Page MenuHomePhorge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
This document is not UTF8. It was detected as ISO-8859-1 (Latin 1) and converted to UTF8 for display.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..654a07f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,45 @@
+This is the source code of ActiveSync Service for Kolab.
+
+
+INTALLATION PROCEDURE
+=====================
+
+This package uses [Composer][1] to install and maintain required PHP libraries
+as well as the Roundcube framework. The requirements are basically the same as
+for Roundcube so please read the INSTALLATION section in the Roundcube
+framework's [README][2] file.
+
+1. Install Composer
+
+Execute this in the project root directory:
+
+$ curl -s http://getcomposer.org/installer | php
+
+This will create a file named composer.phar in the project directory.
+
+2. Install Dependencies
+
+$ cp composer.json-dist composer.json
+$ php composer.phar install
+
+3. Import the Roundcube Framework (1.2) and Kolab plugins
+
+3.1. Either copy or symlink the Roundcube framework package into lib/ext/Roundcube
+3.2. Either copy or symlink the roundcubemail-plugins-kolab into lib/plugins
+
+4. Create database tables structure in the Roundcube database (e.g. using bin/initdb.sh
+script from Roundcube). See docs/SQL/.
+
+5. Copy configuration options from config/config.inc.php.dist to Roundcube config file.
+
+6. Give write access for the webserver user to the 'logs' and 'temp' folders:
+
+$ chown <www-user> logs
+$ chown <www-user> temp
+
+7. Configure your webserver to point to the root directory of this
+package as document root as well as the /Microsoft-Server-ActiveSync alias.
+See docs/kolab-syncroton.conf for an example Apache config.
+
+[1]: http://getcomposer.org
+[2]: https://github.com/roundcube/roundcubemail/blob/master/program/lib/Roundcube/README.md)
diff --git a/lib/ext/Roundcube/README.md b/lib/ext/Roundcube/README.md
deleted file mode 100644
index 88f2d07..0000000
--- a/lib/ext/Roundcube/README.md
+++ /dev/null
@@ -1,102 +0,0 @@
-Roundcube Framework
-===================
-
-INTRODUCTION
-------------
-The Roundcube Framework is the basic library used for the Roundcube Webmail
-application. It is an extract of classes providing the core functionality for
-an email system. They can be used individually or as package for the following
-tasks:
-
-- IMAP mailbox access with optional caching
-- MIME message handling
-- Email message creation and sending through SMTP
-- General caching utilities using the local database
-- Database abstraction using PDO
-- VCard parsing and writing
-
-
-INSTALLATION
-------------
-Copy all files of this directory to your project or install it in the default
-include_path directory of your webserver. Some classes of the framework require
-one or multiple of the following [PEAR][pear] libraries:
-
-- Mail_Mime 1.8.1 or newer
-- Mail_mimeDecode 1.5.5 or newer
-- Net_SMTP (latest from https://github.com/pear/Net_SMTP/)
-- Net_IDNA2 0.1.1 or newer
-- Auth_SASL 1.0.6 or newer
-
-
-USAGE
------
-The Roundcube Framework provides a bootstrapping file which registers an
-autoloader and sets up the environment necessary for the Roundcube classes.
-In order to make use of the framework, simply include the bootstrap.php file
-from this directory in your application and start using the classes by simply
-instantiating them.
-
-If you wanna use more complex functionality like IMAP access with database
-caching or plugins, the rcube singleton helps you loading the necessary files:
-
-```php
-<?php
-
-define('RCUBE_CONFIG_DIR', '<path-to-config-directory>');
-define('RCUBE_PLUGINS_DIR', '<path-to-roundcube-plugins-directory');
-
-require_once '<path-to-roundcube-framework/bootstrap.php';
-
-$rcube = rcube::get_instance(rcube::INIT_WITH_DB | rcube::INIT_WITH_PLUGINS);
-$imap = $rcube->get_storage();
-
-// do cool stuff here...
-
-?>
-```
-
-LICENSE
--------
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License (**with exceptions
-for plugins**) as published by the Free Software Foundation, either
-version 3 of the License, or (at your option) any later version.
-
-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, see [www.gnu.org/licenses/][gpl].
-
-This file forms part of the Roundcube Webmail Framework for which the
-following exception is added: Plugins which merely make function calls to the
-Roundcube Webmail Framework, and for that purpose include it by reference
-shall not be considered modifications of the software.
-
-If you wish to use this file in another project or create a modified
-version that will not be part of the Roundcube Webmail Framework, you
-may remove the exception above and use this source code under the
-original version of the license.
-
-For more details about licensing and the exceptions for skins and plugins
-see [roundcube.net/license][license]
-
-
-CONTACT
--------
-For any bug reports or feature requests please refer to the tracking system
-at [trac.roundcube.net][tracreport] or subscribe to our mailing list.
-See [roundcube.net/support][support] for details.
-
-You're always welcome to send a message to the project admins:
-hello(at)roundcube(dot)net
-
-
-[pear]: http://pear.php.net
-[gpl]: http://www.gnu.org/licenses/
-[license]: http://roundcube.net/license
-[support]: http://roundcube.net/support
-[tracreport]: http://trac.roundcube.net/wiki/Howto_ReportIssues
\ No newline at end of file
diff --git a/lib/ext/Roundcube/bootstrap.php b/lib/ext/Roundcube/bootstrap.php
deleted file mode 100644
index fe9c389..0000000
--- a/lib/ext/Roundcube/bootstrap.php
+++ /dev/null
@@ -1,497 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube PHP suite |
- | Copyright (C) 2005-2014, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | CONTENTS: |
- | Roundcube Framework Initialization |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-
-/**
- * Roundcube Framework Initialization
- *
- * @package Framework
- * @subpackage Core
- */
-
-$config = array(
- 'error_reporting' => E_ALL & ~E_NOTICE & ~E_STRICT,
- // Some users are not using Installer, so we'll check some
- // critical PHP settings here. Only these, which doesn't provide
- // an error/warning in the logs later. See (#1486307).
- 'mbstring.func_overload' => 0,
- 'magic_quotes_runtime' => false,
- 'magic_quotes_sybase' => false, // #1488506
-);
-
-// check these additional ini settings if not called via CLI
-if (php_sapi_name() != 'cli') {
- $config += array(
- 'suhosin.session.encrypt' => false,
- 'file_uploads' => true,
- );
-}
-
-foreach ($config as $optname => $optval) {
- $ini_optval = filter_var(ini_get($optname), is_bool($optval) ? FILTER_VALIDATE_BOOLEAN : FILTER_VALIDATE_INT);
- if ($optval != $ini_optval && @ini_set($optname, $optval) === false) {
- $error = "ERROR: Wrong '$optname' option value and it wasn't possible to set it to required value ($optval).\n"
- . "Check your PHP configuration (including php_admin_flag).";
- if (defined('STDERR')) fwrite(STDERR, $error); else echo $error;
- exit(1);
- }
-}
-
-// framework constants
-define('RCUBE_VERSION', '1.1-git');
-define('RCUBE_CHARSET', 'UTF-8');
-
-if (!defined('RCUBE_LIB_DIR')) {
- define('RCUBE_LIB_DIR', __DIR__ . '/');
-}
-
-if (!defined('RCUBE_INSTALL_PATH')) {
- define('RCUBE_INSTALL_PATH', RCUBE_LIB_DIR);
-}
-
-if (!defined('RCUBE_CONFIG_DIR')) {
- define('RCUBE_CONFIG_DIR', RCUBE_INSTALL_PATH . 'config/');
-}
-
-if (!defined('RCUBE_PLUGINS_DIR')) {
- define('RCUBE_PLUGINS_DIR', RCUBE_INSTALL_PATH . 'plugins/');
-}
-
-if (!defined('RCUBE_LOCALIZATION_DIR')) {
- define('RCUBE_LOCALIZATION_DIR', RCUBE_INSTALL_PATH . 'localization/');
-}
-
-// set internal encoding for mbstring extension
-if (extension_loaded('mbstring')) {
- mb_internal_encoding(RCUBE_CHARSET);
- @mb_regex_encoding(RCUBE_CHARSET);
-}
-
-// make sure the Roundcube lib directory is in the include_path
-$rcube_path = realpath(RCUBE_LIB_DIR . '..');
-$sep = PATH_SEPARATOR;
-$regexp = "!(^|$sep)" . preg_quote($rcube_path, '!') . "($sep|\$)!";
-$path = ini_get('include_path');
-
-if (!preg_match($regexp, $path)) {
- set_include_path($path . PATH_SEPARATOR . $rcube_path);
-}
-
-// Register autoloader
-spl_autoload_register('rcube_autoload');
-
-// set PEAR error handling (will also load the PEAR main class)
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error');
-
-
-
-/**
- * Similar function as in_array() but case-insensitive
- *
- * @param string $needle Needle value
- * @param array $heystack Array to search in
- *
- * @return boolean True if found, False if not
- */
-function in_array_nocase($needle, $haystack)
-{
- $needle = mb_strtolower($needle);
- foreach ((array)$haystack as $value) {
- if ($needle === mb_strtolower($value)) {
- return true;
- }
- }
-
- return false;
-}
-
-
-/**
- * Parse a human readable string for a number of bytes.
- *
- * @param string $str Input string
- *
- * @return float Number of bytes
- */
-function parse_bytes($str)
-{
- if (is_numeric($str)) {
- return floatval($str);
- }
-
- if (preg_match('/([0-9\.]+)\s*([a-z]*)/i', $str, $regs)) {
- $bytes = floatval($regs[1]);
- switch (strtolower($regs[2])) {
- case 'g':
- case 'gb':
- $bytes *= 1073741824;
- break;
- case 'm':
- case 'mb':
- $bytes *= 1048576;
- break;
- case 'k':
- case 'kb':
- $bytes *= 1024;
- break;
- }
- }
-
- return floatval($bytes);
-}
-
-
-/**
- * Make sure the string ends with a slash
- */
-function slashify($str)
-{
- return unslashify($str).'/';
-}
-
-
-/**
- * Remove slashes at the end of the string
- */
-function unslashify($str)
-{
- return preg_replace('/\/+$/', '', $str);
-}
-
-
-/**
- * Returns number of seconds for a specified offset string.
- *
- * @param string $str String representation of the offset (e.g. 20min, 5h, 2days, 1week)
- *
- * @return int Number of seconds
- */
-function get_offset_sec($str)
-{
- if (preg_match('/^([0-9]+)\s*([smhdw])/i', $str, $regs)) {
- $amount = (int) $regs[1];
- $unit = strtolower($regs[2]);
- }
- else {
- $amount = (int) $str;
- $unit = 's';
- }
-
- switch ($unit) {
- case 'w':
- $amount *= 7;
- case 'd':
- $amount *= 24;
- case 'h':
- $amount *= 60;
- case 'm':
- $amount *= 60;
- }
-
- return $amount;
-}
-
-
-/**
- * Create a unix timestamp with a specified offset from now.
- *
- * @param string $offset_str String representation of the offset (e.g. 20min, 5h, 2days)
- * @param int $factor Factor to multiply with the offset
- *
- * @return int Unix timestamp
- */
-function get_offset_time($offset_str, $factor=1)
-{
- return time() + get_offset_sec($offset_str) * $factor;
-}
-
-
-/**
- * Truncate string if it is longer than the allowed length.
- * Replace the middle or the ending part of a string with a placeholder.
- *
- * @param string $str Input string
- * @param int $maxlength Max. length
- * @param string $placeholder Replace removed chars with this
- * @param bool $ending Set to True if string should be truncated from the end
- *
- * @return string Abbreviated string
- */
-function abbreviate_string($str, $maxlength, $placeholder='...', $ending=false)
-{
- $length = mb_strlen($str);
-
- if ($length > $maxlength) {
- if ($ending) {
- return mb_substr($str, 0, $maxlength) . $placeholder;
- }
-
- $placeholder_length = mb_strlen($placeholder);
- $first_part_length = floor(($maxlength - $placeholder_length)/2);
- $second_starting_location = $length - $maxlength + $first_part_length + $placeholder_length;
-
- $str = mb_substr($str, 0, $first_part_length) . $placeholder . mb_substr($str, $second_starting_location);
- }
-
- return $str;
-}
-
-
-/**
- * Get all keys from array (recursive).
- *
- * @param array $array Input array
- *
- * @return array List of array keys
- */
-function array_keys_recursive($array)
-{
- $keys = array();
-
- if (!empty($array) && is_array($array)) {
- foreach ($array as $key => $child) {
- $keys[] = $key;
- foreach (array_keys_recursive($child) as $val) {
- $keys[] = $val;
- }
- }
- }
-
- return $keys;
-}
-
-
-/**
- * Remove all non-ascii and non-word chars except ., -, _
- */
-function asciiwords($str, $css_id = false, $replace_with = '')
-{
- $allowed = 'a-z0-9\_\-' . (!$css_id ? '\.' : '');
- return preg_replace("/[^$allowed]/i", $replace_with, $str);
-}
-
-
-/**
- * Check if a string contains only ascii characters
- *
- * @param string $str String to check
- * @param bool $control_chars Includes control characters
- *
- * @return bool
- */
-function is_ascii($str, $control_chars = true)
-{
- $regexp = $control_chars ? '/[^\x00-\x7F]/' : '/[^\x20-\x7E]/';
- return preg_match($regexp, $str) ? false : true;
-}
-
-
-/**
- * Compose a valid representation of name and e-mail address
- *
- * @param string $email E-mail address
- * @param string $name Person name
- *
- * @return string Formatted string
- */
-function format_email_recipient($email, $name = '')
-{
- $email = trim($email);
-
- if ($name && $name != $email) {
- // Special chars as defined by RFC 822 need to in quoted string (or escaped).
- if (preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name)) {
- $name = '"'.addcslashes($name, '"').'"';
- }
-
- return "$name <$email>";
- }
-
- return $email;
-}
-
-
-/**
- * Format e-mail address
- *
- * @param string $email E-mail address
- *
- * @return string Formatted e-mail address
- */
-function format_email($email)
-{
- $email = trim($email);
- $parts = explode('@', $email);
- $count = count($parts);
-
- if ($count > 1) {
- $parts[$count-1] = mb_strtolower($parts[$count-1]);
-
- $email = implode('@', $parts);
- }
-
- return $email;
-}
-
-
-/**
- * Fix version number so it can be used correctly in version_compare()
- *
- * @param string $version Version number string
- *
- * @param return Version number string
- */
-function version_parse($version)
-{
- return str_replace(
- array('-stable', '-git'),
- array('.0', '.99'),
- $version);
-}
-
-
-/**
- * mbstring replacement functions
- */
-if (!extension_loaded('mbstring'))
-{
- function mb_strlen($str)
- {
- return strlen($str);
- }
-
- function mb_strtolower($str)
- {
- return strtolower($str);
- }
-
- function mb_strtoupper($str)
- {
- return strtoupper($str);
- }
-
- function mb_substr($str, $start, $len=null)
- {
- return substr($str, $start, $len);
- }
-
- function mb_strpos($haystack, $needle, $offset=0)
- {
- return strpos($haystack, $needle, $offset);
- }
-
- function mb_strrpos($haystack, $needle, $offset=0)
- {
- return strrpos($haystack, $needle, $offset);
- }
-}
-
-/**
- * intl replacement functions
- */
-
-if (!function_exists('idn_to_utf8'))
-{
- function idn_to_utf8($domain, $flags=null)
- {
- static $idn, $loaded;
-
- if (!$loaded) {
- $idn = new Net_IDNA2();
- $loaded = true;
- }
-
- if ($idn && $domain && preg_match('/(^|\.)xn--/i', $domain)) {
- try {
- $domain = $idn->decode($domain);
- }
- catch (Exception $e) {
- }
- }
- return $domain;
- }
-}
-
-if (!function_exists('idn_to_ascii'))
-{
- function idn_to_ascii($domain, $flags=null)
- {
- static $idn, $loaded;
-
- if (!$loaded) {
- $idn = new Net_IDNA2();
- $loaded = true;
- }
-
- if ($idn && $domain && preg_match('/[^\x20-\x7E]/', $domain)) {
- try {
- $domain = $idn->encode($domain);
- }
- catch (Exception $e) {
- }
- }
- return $domain;
- }
-}
-
-/**
- * Use PHP5 autoload for dynamic class loading
- *
- * @todo Make Zend, PEAR etc play with this
- * @todo Make our classes conform to a more straight forward CS.
- */
-function rcube_autoload($classname)
-{
- $filename = preg_replace(
- array(
- '/Mail_(.+)/',
- '/Net_(.+)/',
- '/Auth_(.+)/',
- '/^html_.+/',
- '/^rcube(.*)/'
- ),
- array(
- 'Mail/\\1',
- 'Net/\\1',
- 'Auth/\\1',
- 'Roundcube/html',
- 'Roundcube/rcube\\1'
- ),
- $classname
- );
-
- if ($fp = @fopen("$filename.php", 'r', true)) {
- fclose($fp);
- include_once "$filename.php";
- return true;
- }
-
- return false;
-}
-
-/**
- * Local callback function for PEAR errors
- */
-function rcube_pear_error($err)
-{
- error_log(sprintf("%s (%s): %s",
- $err->getMessage(),
- $err->getCode(),
- $err->getUserinfo()), 0);
-}
diff --git a/lib/ext/Roundcube/html.php b/lib/ext/Roundcube/html.php
deleted file mode 100644
index f18cad0..0000000
--- a/lib/ext/Roundcube/html.php
+++ /dev/null
@@ -1,914 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Helper class to create valid XHTML code |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-
-/**
- * Class for HTML code creation
- *
- * @package Framework
- * @subpackage View
- */
-class html
-{
- protected $tagname;
- protected $attrib = array();
- protected $allowed = array();
- protected $content;
-
- public static $doctype = 'xhtml';
- public static $lc_tags = true;
- public static $common_attrib = array('id','class','style','title','align','unselectable','tabindex','role');
- public static $containers = array('iframe','div','span','p','h1','h2','h3','ul','form','textarea','table','thead','tbody','tr','th','td','style','script');
-
-
- /**
- * Constructor
- *
- * @param array $attrib Hash array with tag attributes
- */
- public function __construct($attrib = array())
- {
- if (is_array($attrib)) {
- $this->attrib = $attrib;
- }
- }
-
- /**
- * Return the tag code
- *
- * @return string The finally composed HTML tag
- */
- public function show()
- {
- return self::tag($this->tagname, $this->attrib, $this->content, array_merge(self::$common_attrib, $this->allowed));
- }
-
- /****** STATIC METHODS *******/
-
- /**
- * Generic method to create a HTML tag
- *
- * @param string $tagname Tag name
- * @param array $attrib Tag attributes as key/value pairs
- * @param string $content Optinal Tag content (creates a container tag)
- * @param array $allowed_attrib List with allowed attributes, omit to allow all
- * @return string The XHTML tag
- */
- public static function tag($tagname, $attrib = array(), $content = null, $allowed_attrib = null)
- {
- if (is_string($attrib))
- $attrib = array('class' => $attrib);
-
- $inline_tags = array('a','span','img');
- $suffix = $attrib['nl'] || ($content && $attrib['nl'] !== false && !in_array($tagname, $inline_tags)) ? "\n" : '';
-
- $tagname = self::$lc_tags ? strtolower($tagname) : $tagname;
- if (isset($content) || in_array($tagname, self::$containers)) {
- $suffix = $attrib['noclose'] ? $suffix : '</' . $tagname . '>' . $suffix;
- unset($attrib['noclose'], $attrib['nl']);
- return '<' . $tagname . self::attrib_string($attrib, $allowed_attrib) . '>' . $content . $suffix;
- }
- else {
- return '<' . $tagname . self::attrib_string($attrib, $allowed_attrib) . '>' . $suffix;
- }
- }
-
- /**
- *
- */
- public static function doctype($type)
- {
- $doctypes = array(
- 'html5' => '<!DOCTYPE html>',
- 'xhtml' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
- 'xhtml-trans' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
- 'xhtml-strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
- );
-
- if ($doctypes[$type]) {
- self::$doctype = preg_replace('/-\w+$/', '', $type);
- return $doctypes[$type];
- }
-
- return '';
- }
-
- /**
- * Derrived method for <div> containers
- *
- * @param mixed $attr Hash array with tag attributes or string with class name
- * @param string $cont Div content
- * @return string HTML code
- * @see html::tag()
- */
- public static function div($attr = null, $cont = null)
- {
- if (is_string($attr)) {
- $attr = array('class' => $attr);
- }
- return self::tag('div', $attr, $cont, array_merge(self::$common_attrib, array('onclick')));
- }
-
- /**
- * Derrived method for <p> blocks
- *
- * @param mixed $attr Hash array with tag attributes or string with class name
- * @param string $cont Paragraph content
- * @return string HTML code
- * @see html::tag()
- */
- public static function p($attr = null, $cont = null)
- {
- if (is_string($attr)) {
- $attr = array('class' => $attr);
- }
- return self::tag('p', $attr, $cont, self::$common_attrib);
- }
-
- /**
- * Derrived method to create <img />
- *
- * @param mixed $attr Hash array with tag attributes or string with image source (src)
- * @return string HTML code
- * @see html::tag()
- */
- public static function img($attr = null)
- {
- if (is_string($attr)) {
- $attr = array('src' => $attr);
- }
- return self::tag('img', $attr + array('alt' => ''), null, array_merge(self::$common_attrib,
- array('src','alt','width','height','border','usemap','onclick','onerror')));
- }
-
- /**
- * Derrived method for link tags
- *
- * @param mixed $attr Hash array with tag attributes or string with link location (href)
- * @param string $cont Link content
- * @return string HTML code
- * @see html::tag()
- */
- public static function a($attr, $cont)
- {
- if (is_string($attr)) {
- $attr = array('href' => $attr);
- }
- return self::tag('a', $attr, $cont, array_merge(self::$common_attrib,
- array('href','target','name','rel','onclick','onmouseover','onmouseout','onmousedown','onmouseup')));
- }
-
- /**
- * Derrived method for inline span tags
- *
- * @param mixed $attr Hash array with tag attributes or string with class name
- * @param string $cont Tag content
- * @return string HTML code
- * @see html::tag()
- */
- public static function span($attr, $cont)
- {
- if (is_string($attr)) {
- $attr = array('class' => $attr);
- }
- return self::tag('span', $attr, $cont, self::$common_attrib);
- }
-
- /**
- * Derrived method for form element labels
- *
- * @param mixed $attr Hash array with tag attributes or string with 'for' attrib
- * @param string $cont Tag content
- * @return string HTML code
- * @see html::tag()
- */
- public static function label($attr, $cont)
- {
- if (is_string($attr)) {
- $attr = array('for' => $attr);
- }
- return self::tag('label', $attr, $cont, array_merge(self::$common_attrib, array('for')));
- }
-
- /**
- * Derrived method to create <iframe></iframe>
- *
- * @param mixed $attr Hash array with tag attributes or string with frame source (src)
- * @return string HTML code
- * @see html::tag()
- */
- public static function iframe($attr = null, $cont = null)
- {
- if (is_string($attr)) {
- $attr = array('src' => $attr);
- }
- return self::tag('iframe', $attr, $cont, array_merge(self::$common_attrib,
- array('src','name','width','height','border','frameborder','onload','allowfullscreen')));
- }
-
- /**
- * Derrived method to create <script> tags
- *
- * @param mixed $attr Hash array with tag attributes or string with script source (src)
- * @param string $cont Javascript code to be placed as tag content
- * @return string HTML code
- * @see html::tag()
- */
- public static function script($attr, $cont = null)
- {
- if (is_string($attr)) {
- $attr = array('src' => $attr);
- }
- if ($cont) {
- if (self::$doctype == 'xhtml')
- $cont = "\n/* <![CDATA[ */\n" . $cont . "\n/* ]]> */\n";
- else
- $cont = "\n" . $cont . "\n";
- }
-
- return self::tag('script', $attr + array('type' => 'text/javascript', 'nl' => true),
- $cont, array_merge(self::$common_attrib, array('src','type','charset')));
- }
-
- /**
- * Derrived method for line breaks
- *
- * @return string HTML code
- * @see html::tag()
- */
- public static function br($attrib = array())
- {
- return self::tag('br', $attrib);
- }
-
- /**
- * Create string with attributes
- *
- * @param array $attrib Associative arry with tag attributes
- * @param array $allowed List of allowed attributes
- * @return string Valid attribute string
- */
- public static function attrib_string($attrib = array(), $allowed = null)
- {
- if (empty($attrib)) {
- return '';
- }
-
- $allowed_f = array_flip((array)$allowed);
- $attrib_arr = array();
-
- foreach ($attrib as $key => $value) {
- // skip size if not numeric
- if ($key == 'size' && !is_numeric($value)) {
- continue;
- }
-
- // ignore "internal" or empty attributes
- if ($key == 'nl' || $value === null) {
- continue;
- }
-
- // ignore not allowed attributes, except aria-* and data-*
- if (!empty($allowed)) {
- $is_data_attr = @substr_compare($key, 'data-', 0, 5) === 0;
- $is_aria_attr = @substr_compare($key, 'aria-', 0, 5) === 0;
- if (!$is_aria_attr && !$is_data_attr && !isset($allowed_f[$key])) {
- continue;
- }
- }
-
- // skip empty eventhandlers
- if (preg_match('/^on[a-z]+/', $key) && !$value) {
- continue;
- }
-
- // attributes with no value
- if (in_array($key, array('checked', 'multiple', 'disabled', 'selected', 'autofocus'))) {
- if ($value) {
- $attrib_arr[] = $key . '="' . $key . '"';
- }
- }
- else {
- $attrib_arr[] = $key . '="' . self::quote($value) . '"';
- }
- }
-
- return count($attrib_arr) ? ' '.implode(' ', $attrib_arr) : '';
- }
-
- /**
- * Convert a HTML attribute string attributes to an associative array (name => value)
- *
- * @param string Input string
- * @return array Key-value pairs of parsed attributes
- */
- public static function parse_attrib_string($str)
- {
- $attrib = array();
- $regexp = '/\s*([-_a-z]+)=(["\'])??(?(2)([^\2]*)\2|(\S+?))/Ui';
-
- preg_match_all($regexp, stripslashes($str), $regs, PREG_SET_ORDER);
-
- // convert attributes to an associative array (name => value)
- if ($regs) {
- foreach ($regs as $attr) {
- $attrib[strtolower($attr[1])] = html_entity_decode($attr[3] . $attr[4]);
- }
- }
-
- return $attrib;
- }
-
- /**
- * Replacing specials characters in html attribute value
- *
- * @param string $str Input string
- *
- * @return string The quoted string
- */
- public static function quote($str)
- {
- static $flags;
-
- if (!$flags) {
- $flags = ENT_COMPAT;
- if (defined('ENT_SUBSTITUTE')) {
- $flags |= ENT_SUBSTITUTE;
- }
- }
-
- return @htmlspecialchars($str, $flags, RCUBE_CHARSET);
- }
-}
-
-
-/**
- * Class to create an HTML input field
- *
- * @package Framework
- * @subpackage View
- */
-class html_inputfield extends html
-{
- protected $tagname = 'input';
- protected $type = 'text';
- protected $allowed = array(
- 'type','name','value','size','tabindex','autocapitalize','required',
- 'autocomplete','checked','onchange','onclick','disabled','readonly',
- 'spellcheck','results','maxlength','src','multiple','accept',
- 'placeholder','autofocus',
- );
-
- /**
- * Object constructor
- *
- * @param array $attrib Associative array with tag attributes
- */
- public function __construct($attrib = array())
- {
- if (is_array($attrib)) {
- $this->attrib = $attrib;
- }
-
- if ($attrib['type']) {
- $this->type = $attrib['type'];
- }
- }
-
- /**
- * Compose input tag
- *
- * @param string $value Field value
- * @param array $attrib Additional attributes to override
- * @return string HTML output
- */
- public function show($value = null, $attrib = null)
- {
- // overwrite object attributes
- if (is_array($attrib)) {
- $this->attrib = array_merge($this->attrib, $attrib);
- }
-
- // set value attribute
- if ($value !== null) {
- $this->attrib['value'] = $value;
- }
- // set type
- $this->attrib['type'] = $this->type;
- return parent::show();
- }
-}
-
-/**
- * Class to create an HTML password field
- *
- * @package Framework
- * @subpackage View
- */
-class html_passwordfield extends html_inputfield
-{
- protected $type = 'password';
-}
-
-/**
- * Class to create an hidden HTML input field
- *
- * @package Framework
- * @subpackage View
- */
-class html_hiddenfield extends html
-{
- protected $tagname = 'input';
- protected $type = 'hidden';
- protected $fields_arr = array();
- protected $allowed = array('type','name','value','onchange','disabled','readonly');
-
- /**
- * Constructor
- *
- * @param array $attrib Named tag attributes
- */
- public function __construct($attrib = null)
- {
- if (is_array($attrib)) {
- $this->add($attrib);
- }
- }
-
- /**
- * Add a hidden field to this instance
- *
- * @param array $attrib Named tag attributes
- */
- public function add($attrib)
- {
- $this->fields_arr[] = $attrib;
- }
-
- /**
- * Create HTML code for the hidden fields
- *
- * @return string Final HTML code
- */
- public function show()
- {
- $out = '';
- foreach ($this->fields_arr as $attrib) {
- $out .= self::tag($this->tagname, array('type' => $this->type) + $attrib);
- }
- return $out;
- }
-}
-
-/**
- * Class to create HTML radio buttons
- *
- * @package Framework
- * @subpackage View
- */
-class html_radiobutton extends html_inputfield
-{
- protected $type = 'radio';
-
- /**
- * Get HTML code for this object
- *
- * @param string $value Value of the checked field
- * @param array $attrib Additional attributes to override
- * @return string HTML output
- */
- public function show($value = '', $attrib = null)
- {
- // overwrite object attributes
- if (is_array($attrib)) {
- $this->attrib = array_merge($this->attrib, $attrib);
- }
-
- // set value attribute
- $this->attrib['checked'] = ((string)$value == (string)$this->attrib['value']);
-
- return parent::show();
- }
-}
-
-/**
- * Class to create HTML checkboxes
- *
- * @package Framework
- * @subpackage View
- */
-class html_checkbox extends html_inputfield
-{
- protected $type = 'checkbox';
-
- /**
- * Get HTML code for this object
- *
- * @param string $value Value of the checked field
- * @param array $attrib Additional attributes to override
- * @return string HTML output
- */
- public function show($value = '', $attrib = null)
- {
- // overwrite object attributes
- if (is_array($attrib)) {
- $this->attrib = array_merge($this->attrib, $attrib);
- }
-
- // set value attribute
- $this->attrib['checked'] = ((string)$value == (string)$this->attrib['value']);
-
- return parent::show();
- }
-}
-
-/**
- * Class to create an HTML textarea
- *
- * @package Framework
- * @subpackage View
- */
-class html_textarea extends html
-{
- protected $tagname = 'textarea';
- protected $allowed = array('name','rows','cols','wrap','tabindex',
- 'onchange','disabled','readonly','spellcheck');
-
- /**
- * Get HTML code for this object
- *
- * @param string $value Textbox value
- * @param array $attrib Additional attributes to override
- * @return string HTML output
- */
- public function show($value = '', $attrib = null)
- {
- // overwrite object attributes
- if (is_array($attrib)) {
- $this->attrib = array_merge($this->attrib, $attrib);
- }
-
- // take value attribute as content
- if (empty($value) && !empty($this->attrib['value'])) {
- $value = $this->attrib['value'];
- }
-
- // make shure we don't print the value attribute
- if (isset($this->attrib['value'])) {
- unset($this->attrib['value']);
- }
-
- if (!empty($value) && empty($this->attrib['is_escaped'])) {
- $value = self::quote($value);
- }
-
- return self::tag($this->tagname, $this->attrib, $value,
- array_merge(self::$common_attrib, $this->allowed));
- }
-}
-
-/**
- * Builder for HTML drop-down menus
- * Syntax:<pre>
- * // create instance. arguments are used to set attributes of select-tag
- * $select = new html_select(array('name' => 'fieldname'));
- *
- * // add one option
- * $select->add('Switzerland', 'CH');
- *
- * // add multiple options
- * $select->add(array('Switzerland','Germany'), array('CH','DE'));
- *
- * // generate pulldown with selection 'Switzerland' and return html-code
- * // as second argument the same attributes available to instanciate can be used
- * print $select->show('CH');
- * </pre>
- *
- * @package Framework
- * @subpackage View
- */
-class html_select extends html
-{
- protected $tagname = 'select';
- protected $options = array();
- protected $allowed = array('name','size','tabindex','autocomplete',
- 'multiple','onchange','disabled','rel');
-
- /**
- * Add a new option to this drop-down
- *
- * @param mixed $names Option name or array with option names
- * @param mixed $values Option value or array with option values
- * @param array $attrib Additional attributes for the option entry
- */
- public function add($names, $values = null, $attrib = array())
- {
- if (is_array($names)) {
- foreach ($names as $i => $text) {
- $this->options[] = array('text' => $text, 'value' => $values[$i]) + $attrib;
- }
- }
- else {
- $this->options[] = array('text' => $names, 'value' => $values) + $attrib;
- }
- }
-
- /**
- * Get HTML code for this object
- *
- * @param string $select Value of the selection option
- * @param array $attrib Additional attributes to override
- * @return string HTML output
- */
- public function show($select = array(), $attrib = null)
- {
- // overwrite object attributes
- if (is_array($attrib)) {
- $this->attrib = array_merge($this->attrib, $attrib);
- }
-
- $this->content = "\n";
- $select = (array)$select;
- foreach ($this->options as $option) {
- $attr = array(
- 'value' => $option['value'],
- 'selected' => (in_array($option['value'], $select, true) ||
- in_array($option['text'], $select, true)) ? 1 : null);
-
- $option_content = $option['text'];
- if (empty($this->attrib['is_escaped'])) {
- $option_content = self::quote($option_content);
- }
-
- $this->content .= self::tag('option', $attr + $option, $option_content, array('value','label','class','style','title','disabled','selected'));
- }
-
- return parent::show();
- }
-}
-
-
-/**
- * Class to build an HTML table
- *
- * @package Framework
- * @subpackage View
- */
-class html_table extends html
-{
- protected $tagname = 'table';
- protected $allowed = array('id','class','style','width','summary',
- 'cellpadding','cellspacing','border');
-
- private $header = array();
- private $rows = array();
- private $rowindex = 0;
- private $colindex = 0;
-
- /**
- * Constructor
- *
- * @param array $attrib Named tag attributes
- */
- public function __construct($attrib = array())
- {
- $default_attrib = self::$doctype == 'xhtml' ? array('summary' => '', 'border' => '0') : array();
- $this->attrib = array_merge($attrib, $default_attrib);
-
- if (!empty($attrib['tagname']) && $attrib['tagname'] != 'table') {
- $this->tagname = $attrib['tagname'];
- $this->allowed = self::$common_attrib;
- }
- }
-
- /**
- * Add a table cell
- *
- * @param array $attr Cell attributes
- * @param string $cont Cell content
- */
- public function add($attr, $cont)
- {
- if (is_string($attr)) {
- $attr = array('class' => $attr);
- }
-
- $cell = new stdClass;
- $cell->attrib = $attr;
- $cell->content = $cont;
-
- $this->rows[$this->rowindex]->cells[$this->colindex] = $cell;
- $this->colindex += max(1, intval($attr['colspan']));
-
- if ($this->attrib['cols'] && $this->colindex >= $this->attrib['cols']) {
- $this->add_row();
- }
- }
-
- /**
- * Add a table header cell
- *
- * @param array $attr Cell attributes
- * @param string $cont Cell content
- */
- public function add_header($attr, $cont)
- {
- if (is_string($attr)) {
- $attr = array('class' => $attr);
- }
-
- $cell = new stdClass;
- $cell->attrib = $attr;
- $cell->content = $cont;
- $this->header[] = $cell;
- }
-
- /**
- * Remove a column from a table
- * Useful for plugins making alterations
- *
- * @param string $class
- */
- public function remove_column($class)
- {
- // Remove the header
- foreach ($this->header as $index=>$header){
- if ($header->attrib['class'] == $class){
- unset($this->header[$index]);
- break;
- }
- }
-
- // Remove cells from rows
- foreach ($this->rows as $i=>$row){
- foreach ($row->cells as $j=>$cell){
- if ($cell->attrib['class'] == $class){
- unset($this->rows[$i]->cells[$j]);
- break;
- }
- }
- }
- }
-
- /**
- * Jump to next row
- *
- * @param array $attr Row attributes
- */
- public function add_row($attr = array())
- {
- $this->rowindex++;
- $this->colindex = 0;
- $this->rows[$this->rowindex] = new stdClass;
- $this->rows[$this->rowindex]->attrib = $attr;
- $this->rows[$this->rowindex]->cells = array();
- }
-
- /**
- * Set row attributes
- *
- * @param array $attr Row attributes
- * @param int $index Optional row index (default current row index)
- */
- public function set_row_attribs($attr = array(), $index = null)
- {
- if (is_string($attr)) {
- $attr = array('class' => $attr);
- }
-
- if ($index === null) {
- $index = $this->rowindex;
- }
-
- // make sure row object exists (#1489094)
- if (!$this->rows[$index]) {
- $this->rows[$index] = new stdClass;
- }
-
- $this->rows[$index]->attrib = $attr;
- }
-
- /**
- * Get row attributes
- *
- * @param int $index Row index
- *
- * @return array Row attributes
- */
- public function get_row_attribs($index = null)
- {
- if ($index === null) {
- $index = $this->rowindex;
- }
-
- return $this->rows[$index] ? $this->rows[$index]->attrib : null;
- }
-
- /**
- * Build HTML output of the table data
- *
- * @param array $attrib Table attributes
- * @return string The final table HTML code
- */
- public function show($attrib = null)
- {
- if (is_array($attrib)) {
- $this->attrib = array_merge($this->attrib, $attrib);
- }
-
- $thead = $tbody = "";
-
- // include <thead>
- if (!empty($this->header)) {
- $rowcontent = '';
- foreach ($this->header as $c => $col) {
- $rowcontent .= self::tag($this->_head_tagname(), $col->attrib, $col->content);
- }
- $thead = $this->tagname == 'table' ? self::tag('thead', null, self::tag('tr', null, $rowcontent, parent::$common_attrib)) :
- self::tag($this->_row_tagname(), array('class' => 'thead'), $rowcontent, parent::$common_attrib);
- }
-
- foreach ($this->rows as $r => $row) {
- $rowcontent = '';
- foreach ($row->cells as $c => $col) {
- $rowcontent .= self::tag($this->_col_tagname(), $col->attrib, $col->content);
- }
-
- if ($r < $this->rowindex || count($row->cells)) {
- $tbody .= self::tag($this->_row_tagname(), $row->attrib, $rowcontent, parent::$common_attrib);
- }
- }
-
- if ($this->attrib['rowsonly']) {
- return $tbody;
- }
-
- // add <tbody>
- $this->content = $thead . ($this->tagname == 'table' ? self::tag('tbody', null, $tbody) : $tbody);
-
- unset($this->attrib['cols'], $this->attrib['rowsonly']);
- return parent::show();
- }
-
- /**
- * Count number of rows
- *
- * @return The number of rows
- */
- public function size()
- {
- return count($this->rows);
- }
-
- /**
- * Remove table body (all rows)
- */
- public function remove_body()
- {
- $this->rows = array();
- $this->rowindex = 0;
- }
-
- /**
- * Getter for the corresponding tag name for table row elements
- */
- private function _row_tagname()
- {
- static $row_tagnames = array('table' => 'tr', 'ul' => 'li', '*' => 'div');
- return $row_tagnames[$this->tagname] ?: $row_tagnames['*'];
- }
-
- /**
- * Getter for the corresponding tag name for table row elements
- */
- private function _head_tagname()
- {
- static $head_tagnames = array('table' => 'th', '*' => 'span');
- return $head_tagnames[$this->tagname] ?: $head_tagnames['*'];
- }
-
- /**
- * Getter for the corresponding tag name for table cell elements
- */
- private function _col_tagname()
- {
- static $col_tagnames = array('table' => 'td', '*' => 'span');
- return $col_tagnames[$this->tagname] ?: $col_tagnames['*'];
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube.php b/lib/ext/Roundcube/rcube.php
deleted file mode 100644
index feb9233..0000000
--- a/lib/ext/Roundcube/rcube.php
+++ /dev/null
@@ -1,1748 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2014, The Roundcube Dev Team |
- | Copyright (C) 2011-2014, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Framework base class providing core functions and holding |
- | instances of all 'global' objects like db- and storage-connections |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-
-/**
- * Base class of the Roundcube Framework
- * implemented as singleton
- *
- * @package Framework
- * @subpackage Core
- */
-class rcube
-{
- const INIT_WITH_DB = 1;
- const INIT_WITH_PLUGINS = 2;
-
- /**
- * Singleton instace of rcube
- *
- * @var rcube
- */
- static protected $instance;
-
- /**
- * Stores instance of rcube_config.
- *
- * @var rcube_config
- */
- public $config;
-
- /**
- * Instace of database class.
- *
- * @var rcube_db
- */
- public $db;
-
- /**
- * Instace of Memcache class.
- *
- * @var Memcache
- */
- 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_storage class.
- *
- * @var rcube_storage
- */
- public $storage;
-
- /**
- * Instance of rcube_output class.
- *
- * @var rcube_output
- */
- public $output;
-
- /**
- * Instance of rcube_plugin_api.
- *
- * @var rcube_plugin_api
- */
- public $plugins;
-
- /**
- * Instance of rcube_user class.
- *
- * @var rcube_user
- */
- public $user;
-
-
- /* private/protected vars */
- protected $texts;
- protected $caches = array();
- protected $shutdown_functions = array();
-
-
- /**
- * This implements the 'singleton' design pattern
- *
- * @param integer Options to initialize with this instance. See rcube::INIT_WITH_* constants
- * @param string Environment name to run (e.g. live, dev, test)
- *
- * @return rcube The one and only instance
- */
- static function get_instance($mode = 0, $env = '')
- {
- if (!self::$instance) {
- self::$instance = new rcube($env);
- self::$instance->init($mode);
- }
-
- return self::$instance;
- }
-
-
- /**
- * Private constructor
- */
- protected function __construct($env = '')
- {
- // load configuration
- $this->config = new rcube_config($env);
- $this->plugins = new rcube_dummy_plugin_api;
-
- register_shutdown_function(array($this, 'shutdown'));
- }
-
-
- /**
- * Initial startup function
- */
- protected function init($mode = 0)
- {
- // 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
- if ($mode & self::INIT_WITH_DB) {
- $this->get_dbh();
- }
-
- // create plugin API and load plugins
- if ($mode & self::INIT_WITH_PLUGINS) {
- $this->plugins = rcube_plugin_api::get_instance();
- }
- }
-
-
- /**
- * Get the current database connection
- *
- * @return rcube_db Database object
- */
- public function get_dbh()
- {
- if (!$this->db) {
- $this->db = rcube_db::factory(
- $this->config->get('db_dsnw'),
- $this->config->get('db_dsnr'),
- $this->config->get('db_persistent')
- );
-
- $this->db->set_debug((bool)$this->config->get('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->memcache_init();
-
- // 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;
- }
-
-
- /**
- * Get global handle for memcache access
- *
- * @return object Memcache
- */
- protected function memcache_init()
- {
- $this->mc_available = 0;
-
- // add all configured hosts to pool
- $pconnect = $this->config->get('memcache_pconnect', true);
- foreach ($this->config->get('memcache_hosts', array()) as $host) {
- if (substr($host, 0, 7) != 'unix://') {
- list($host, $port) = explode(':', $host);
- if (!$port) $port = 11211;
- }
- else {
- $port = 0;
- }
-
- $this->mc_available += intval($this->memcache->addServer(
- $host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure')));
- }
- }
-
- /**
- * Callback for memcache failure
- */
- public function memcache_failure($host, $port)
- {
- static $seen = array();
-
- // only report once
- if (!$seen["$host:$port"]++) {
- $this->mc_available--;
- self::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 string $ttl Expiration time for cache items
- * @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]) && ($userid = $this->get_user_id())) {
- $this->caches[$name] = new rcube_cache($type, $userid, $name, $ttl, $packed);
- }
-
- return $this->caches[$name];
- }
-
-
- /**
- * Initialize and get shared cache object
- *
- * @param string $name Cache identifier
- * @param bool $packed Enables/disables data serialization
- *
- * @return rcube_cache_shared Cache object
- */
- public function get_cache_shared($name, $packed=true)
- {
- $shared_name = "shared_$name";
-
- if (!array_key_exists($shared_name, $this->caches)) {
- $opt = strtolower($name) . '_cache';
- $type = $this->config->get($opt);
- $ttl = $this->config->get($opt . '_ttl');
-
- if (!$type) {
- // cache is disabled
- return $this->caches[$shared_name] = null;
- }
-
- if ($ttl === null) {
- $ttl = $this->config->get('shared_cache_ttl', '10d');
- }
-
- $this->caches[$shared_name] = new rcube_cache_shared($type, $name, $ttl, $packed);
- }
-
- return $this->caches[$shared_name];
- }
-
-
- /**
- * Create SMTP object and connect to server
- *
- * @param boolean True if connection should be established
- */
- public function smtp_init($connect = false)
- {
- $this->smtp = new rcube_smtp();
-
- if ($connect) {
- $this->smtp->connect();
- }
- }
-
-
- /**
- * Initialize and get storage object
- *
- * @return rcube_storage Storage object
- */
- public function get_storage()
- {
- // already initialized
- if (!is_object($this->storage)) {
- $this->storage_init();
- }
-
- return $this->storage;
- }
-
-
- /**
- * Initialize storage object
- */
- public function storage_init()
- {
- // already initialized
- if (is_object($this->storage)) {
- return;
- }
-
- $driver = $this->config->get('storage_driver', 'imap');
- $driver_class = "rcube_{$driver}";
-
- if (!class_exists($driver_class)) {
- self::raise_error(array(
- 'code' => 700, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Storage driver class ($driver) not found!"),
- true, true);
- }
-
- // Initialize storage object
- $this->storage = new $driver_class;
-
- // for backward compat. (deprecated, will be removed)
- $this->imap = $this->storage;
-
- // set class options
- $options = array(
- 'auth_type' => $this->config->get("{$driver}_auth_type", 'check'),
- 'auth_cid' => $this->config->get("{$driver}_auth_cid"),
- 'auth_pw' => $this->config->get("{$driver}_auth_pw"),
- 'debug' => (bool) $this->config->get("{$driver}_debug"),
- 'force_caps' => (bool) $this->config->get("{$driver}_force_caps"),
- 'disabled_caps' => $this->config->get("{$driver}_disabled_caps"),
- 'socket_options' => $this->config->get("{$driver}_conn_options"),
- 'timeout' => (int) $this->config->get("{$driver}_timeout"),
- 'skip_deleted' => (bool) $this->config->get('skip_deleted'),
- 'driver' => $driver,
- );
-
- if (!empty($_SESSION['storage_host'])) {
- $options['host'] = $_SESSION['storage_host'];
- $options['user'] = $_SESSION['username'];
- $options['port'] = $_SESSION['storage_port'];
- $options['ssl'] = $_SESSION['storage_ssl'];
- $options['password'] = $this->decrypt($_SESSION['password']);
- $_SESSION[$driver.'_host'] = $_SESSION['storage_host'];
- }
-
- $options = $this->plugins->exec_hook("storage_init", $options);
-
- // for backward compat. (deprecated, to be removed)
- $options = $this->plugins->exec_hook("imap_init", $options);
-
- $this->storage->set_options($options);
- $this->set_storage_prop();
-
- // subscribe to 'storage_connected' hook for session logging
- if ($this->config->get('imap_log_session', false)) {
- $this->plugins->register_hook('storage_connected', array($this, 'storage_log_session'));
- }
- }
-
- /**
- * Set storage parameters.
- */
- protected function set_storage_prop()
- {
- $storage = $this->get_storage();
-
- // set pagesize from config
- $pagesize = $this->config->get('mail_pagesize');
- if (!$pagesize) {
- $pagesize = $this->config->get('pagesize', 50);
- }
-
- $storage->set_pagesize($pagesize);
- $storage->set_charset($this->config->get('default_charset', RCUBE_CHARSET));
-
- // enable caching of mail data
- $driver = $this->config->get('storage_driver', 'imap');
- $storage_cache = $this->config->get("{$driver}_cache");
- $messages_cache = $this->config->get('messages_cache');
- // for backward compatybility
- if ($storage_cache === null && $messages_cache === null && $this->config->get('enable_caching')) {
- $storage_cache = 'db';
- $messages_cache = true;
- }
-
- if ($storage_cache) {
- $storage->set_caching($storage_cache);
- }
- if ($messages_cache) {
- $storage->set_messages_caching(true);
- }
- }
-
-
- /**
- * Set special folders type association.
- * This must be done AFTER connecting to the server!
- */
- protected function set_special_folders()
- {
- $storage = $this->get_storage();
- $folders = $storage->get_special_folders(true);
- $prefs = array();
-
- // check SPECIAL-USE flags on IMAP folders
- foreach ($folders as $type => $folder) {
- $idx = $type . '_mbox';
- if ($folder !== $this->config->get($idx)) {
- $prefs[$idx] = $folder;
- }
- }
-
- // Some special folders differ, update user preferences
- if (!empty($prefs) && $this->user) {
- $this->user->save_prefs($prefs);
- }
-
- // create default folders (on login)
- if ($this->config->get('create_default_folders')) {
- $storage->create_default_folders();
- }
- }
-
-
- /**
- * Callback for IMAP connection events to log session identifiers
- */
- public function storage_log_session($args)
- {
- if (!empty($args['session']) && session_id()) {
- $this->write_log('imap_session', $args['session']);
- }
- }
-
- /**
- * 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');
- $sess_path = $this->config->get('session_path');
- $lifetime = $this->config->get('session_lifetime', 0) * 60;
- $is_secure = $this->config->get('use_https') || rcube_utils::https_check();
-
- // set session domain
- if ($sess_domain) {
- ini_set('session.cookie_domain', $sess_domain);
- }
- // set session path
- if ($sess_path) {
- ini_set('session.cookie_path', $sess_path);
- }
- // set session garbage collecting time according to session_lifetime
- if ($lifetime) {
- ini_set('session.gc_maxlifetime', $lifetime * 2);
- }
-
- ini_set('session.cookie_secure', $is_secure);
- 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.cookie_httponly', 1);
-
- // use database for storing session data
- $this->session = new rcube_session($this->get_dbh(), $this->config);
-
- $this->session->register_gc_handler(array($this, 'gc'));
- $this->session->set_secret($this->config->get('des_key') . dirname($_SERVER['SCRIPT_NAME']));
- $this->session->set_ip_check($this->config->get('ip_check'));
-
- if ($this->config->get('session_auth_name')) {
- $this->session->set_cookiename($this->config->get('session_auth_name'));
- }
-
- // start PHP session (if not in CLI mode)
- if ($_SERVER['REMOTE_ADDR']) {
- $this->session->start();
- }
- }
-
-
- /**
- * Garbage collector - cache/temp cleaner
- */
- public function gc()
- {
- rcube_cache::gc();
- rcube_cache_shared::gc();
- $this->get_storage()->cache_gc();
-
- $this->gc_temp();
- }
-
-
- /**
- * Garbage collector function for temp files.
- * Remove temp files older than two days
- */
- public function gc_temp()
- {
- $tmp = unslashify($this->config->get('temp_dir'));
-
- // expire in 48 hours by default
- $temp_dir_ttl = $this->config->get('temp_dir_ttl', '48h');
- $temp_dir_ttl = get_offset_sec($temp_dir_ttl);
- if ($temp_dir_ttl < 6*3600)
- $temp_dir_ttl = 6*3600; // 6 hours sensible lower bound.
-
- $expire = time() - $temp_dir_ttl;
-
- if ($tmp && ($dir = opendir($tmp))) {
- while (($fname = readdir($dir)) !== false) {
- if ($fname[0] == '.') {
- continue;
- }
-
- if (@filemtime($tmp.'/'.$fname) < $expire) {
- @unlink($tmp.'/'.$fname);
- }
- }
-
- closedir($dir);
- }
- }
-
-
- /**
- * Runs garbage collector with probability based on
- * session settings. This is intended for environments
- * without a session.
- */
- public function gc_run()
- {
- $probability = (int) ini_get('session.gc_probability');
- $divisor = (int) ini_get('session.gc_divisor');
-
- if ($divisor > 0 && $probability > 0) {
- $random = mt_rand(1, $divisor);
- if ($random <= $probability) {
- $this->gc();
- }
- }
- }
-
-
- /**
- * 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);
- }
-
- $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 = $this->texts[$domain.'.'.$name])) {
- }
- // text does not exist
- else if (!($text = $this->texts[$name])) {
- return "[$name]";
- }
-
- // 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 strtr($text, array('\n' => "\n"));
- }
-
-
- /**
- * 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 $lang Language ID
- * @param array $add Additional text labels/messages
- * @param array $merge Additional text labels/messages to merge
- */
- public function load_language($lang = null, $add = array(), $merge = 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(RCUBE_LOCALIZATION_DIR . 'en_US/labels.inc');
- @include(RCUBE_LOCALIZATION_DIR . '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' && $lang != 'en_US' && is_dir(RCUBE_LOCALIZATION_DIR . $lang)) {
- include_once(RCUBE_LOCALIZATION_DIR . $lang . '/labels.inc');
- include_once(RCUBE_LOCALIZATION_DIR . $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;
- }
-
- // merge additional texts (from plugin)
- if (is_array($merge) && !empty($merge)) {
- $this->texts = array_merge($this->texts, $merge);
- }
- }
-
-
- /**
- * Check the given string and return a valid language code
- *
- * @param string Language code
- *
- * @return string Valid language code
- */
- protected 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 = $accept_langs[0];
-
- if (preg_match('/^([a-z]+)[_-]([a-z]+)$/i', $lang, $m)) {
- $lang = $m[1] . '_' . strtoupper($m[2]);
- }
- }
-
- if (empty($rcube_languages)) {
- @include(RCUBE_LOCALIZATION_DIR . '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(RCUBE_LOCALIZATION_DIR . $lang)) {
- $lang = 'en_US';
- }
-
- return $lang;
- }
-
-
- /**
- * 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(RCUBE_LOCALIZATION_DIR . 'index.inc');
-
- if ($dh = @opendir(RCUBE_LOCALIZATION_DIR)) {
- while (($name = readdir($dh)) !== false) {
- if ($name[0] == '.' || !is_dir(RCUBE_LOCALIZATION_DIR . $name)) {
- continue;
- }
-
- if ($label = $rcube_languages[$name]) {
- $sa_languages[$name] = $label;
- }
- }
- closedir($dh);
- }
- }
-
- return $sa_languages;
- }
-
-
- /**
- * 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");
- $ckey = $this->config->get_crypto_key($key);
-
- if (function_exists('openssl_encrypt')) {
- $method = 'DES-EDE3-CBC';
- $opts = defined('OPENSSL_RAW_DATA') ? OPENSSL_RAW_DATA : true;
- $iv = $this->create_iv(openssl_cipher_iv_length($method));
- $cipher = $iv . openssl_encrypt($clear, $method, $ckey, $opts, $iv);
- }
- else 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, $ckey, $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($ckey, $clear, 1, 1, $iv);
- }
- else {
- self::raise_error(array(
- 'code' => 500, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Could not perform encryption; make sure OpenSSL or Mcrypt 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;
- $ckey = $this->config->get_crypto_key($key);
-
- if (function_exists('openssl_decrypt')) {
- $method = 'DES-EDE3-CBC';
- $opts = defined('OPENSSL_RAW_DATA') ? OPENSSL_RAW_DATA : true;
- $iv_size = openssl_cipher_iv_length($method);
- $iv = substr($cipher, 0, $iv_size);
-
- // session corruption? (#1485970)
- if (strlen($iv) < $iv_size) {
- return '';
- }
-
- $cipher = substr($cipher, $iv_size);
- $clear = openssl_decrypt($cipher, $method, $ckey, $opts, $iv);
- }
- else 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, $ckey, $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($ckey, $cipher, 0, 1, $iv);
- }
- else {
- self::raise_error(array(
- 'code' => 500, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Could not perform decryption; make sure OpenSSL or Mcrypt or lib/des.inc is available"
- ), true, true);
- }
- }
-
- /*-
- * Trim PHP's padding and the canary byte; see note in
- * rcube::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)
- {
- // STUB: should be overloaded by the application
- return '';
- }
-
-
- /**
- * 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);
- }
-
- // write session data as soon as possible and before
- // closing database connection, don't do this before
- // registered shutdown functions, they may need the session
- // Note: this will run registered gc handlers (ie. cache gc)
- if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) {
- $this->session->write_close();
- }
-
- if (is_object($this->smtp)) {
- $this->smtp->disconnect();
- }
-
- foreach ($this->caches as $cache) {
- if (is_object($cache)) {
- $cache->close();
- }
- }
-
- if (is_object($this->storage)) {
- $this->storage->close();
- }
- }
-
-
- /**
- * 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;
- }
-
-
- /**
- * When you're going to sleep the script execution for a longer time
- * it is good to close all external connections (sql, memcache, SMTP, IMAP).
- *
- * No action is required on wake up, all connections will be
- * re-established automatically.
- */
- public function sleep()
- {
- foreach ($this->caches as $cache) {
- if (is_object($cache)) {
- $cache->close();
- }
- }
-
- if ($this->storage) {
- $this->storage->close();
- }
-
- if ($this->db) {
- $this->db->closeConnection();
- }
-
- if ($this->memcache) {
- $this->memcache->close();
- // after close() need to re-init memcache
- $this->memcache_init();
- }
-
- if ($this->smtp) {
- $this->smtp->disconnect();
- }
- }
-
- /**
- * Quote a given string.
- * Shortcut function for rcube_utils::rep_specialchars_output()
- *
- * @return string HTML-quoted string
- */
- public static function Q($str, $mode = 'strict', $newlines = true)
- {
- return rcube_utils::rep_specialchars_output($str, 'html', $mode, $newlines);
- }
-
-
- /**
- * Quote a given string for javascript output.
- * Shortcut function for rcube_utils::rep_specialchars_output()
- *
- * @return string JS-quoted string
- */
- public static function JQ($str)
- {
- return rcube_utils::rep_specialchars_output($str, 'js');
- }
-
-
- /**
- * 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);
- }
-
-
- /**
- * Print or write debug messages
- *
- * @param mixed Debug message or data
- */
- public static function console()
- {
- $args = func_get_args();
-
- if (class_exists('rcube', false)) {
- $rcube = self::get_instance();
- $plugin = $rcube->plugins->exec_hook('console', array('args' => $args));
- if ($plugin['abort']) {
- return;
- }
- $args = $plugin['args'];
- }
-
- $msg = array();
- foreach ($args as $arg) {
- $msg[] = !is_string($arg) ? var_export($arg, true) : $arg;
- }
-
- self::write_log('console', join(";\n", $msg));
- }
-
-
- /**
- * Append a line to a logfile in the logs directory.
- * Date will be added automatically to the line.
- *
- * @param $name name of log file
- * @param line Line to append
- */
- public static function write_log($name, $line)
- {
- if (!is_string($line)) {
- $line = var_export($line, true);
- }
-
- $date_format = $log_driver = $session_key = null;
- if (self::$instance) {
- $date_format = self::$instance->config->get('log_date_format');
- $log_driver = self::$instance->config->get('log_driver');
- $session_key = intval(self::$instance->config->get('log_session_id', 8));
- }
-
- if (empty($date_format)) {
- $date_format = 'd-M-Y H:i:s O';
- }
-
- $date = date($date_format);
-
- // trigger logging hook
- if (is_object(self::$instance) && is_object(self::$instance->plugins)) {
- $log = self::$instance->plugins->exec_hook('write_log', array('name' => $name, 'date' => $date, 'line' => $line));
- $name = $log['name'];
- $line = $log['line'];
- $date = $log['date'];
- if ($log['abort'])
- return true;
- }
-
- // add session ID to the log
- if ($session_key > 0 && ($sess = session_id())) {
- $line = '<' . substr($sess, 0, $session_key) . '> ' . $line;
- }
-
- if ($log_driver == 'syslog') {
- $prio = $name == 'errors' ? LOG_ERR : LOG_INFO;
- syslog($prio, $line);
- return true;
- }
-
- // log_driver == 'file' is assumed here
-
- $line = sprintf("[%s]: %s\n", $date, $line);
- $log_dir = null;
-
- // per-user logging is activated
- if (self::$instance && self::$instance->config->get('per_user_logging', false) && self::$instance->get_user_id()) {
- $log_dir = self::$instance->get_user_log_dir();
- if (empty($log_dir))
- return false;
- }
- else if (!empty($log['dir'])) {
- $log_dir = $log['dir'];
- }
- else if (self::$instance) {
- $log_dir = self::$instance->config->get('log_dir');
- }
-
- if (empty($log_dir)) {
- $log_dir = RCUBE_INSTALL_PATH . 'logs';
- }
-
- // try to open specific log file for writing
- $logfile = $log_dir.'/'.$name;
-
- if ($fp = @fopen($logfile, 'a')) {
- fwrite($fp, $line);
- fflush($fp);
- fclose($fp);
- return true;
- }
-
- trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING);
- return false;
- }
-
-
- /**
- * Throw system error (and show error page).
- *
- * @param array Named parameters
- * - code: Error code (required)
- * - type: Error type [php|db|imap|javascript] (required)
- * - message: Error message
- * - file: File where error occurred
- * - line: Line where error occurred
- * @param boolean True to log the error
- * @param boolean Terminate script execution
- */
- public static function raise_error($arg = array(), $log = false, $terminate = false)
- {
- // handle PHP exceptions
- if (is_object($arg) && is_a($arg, 'Exception')) {
- $arg = array(
- 'code' => $arg->getCode(),
- 'line' => $arg->getLine(),
- 'file' => $arg->getFile(),
- 'message' => $arg->getMessage(),
- );
- }
- else if (is_string($arg)) {
- $arg = array('message' => $arg);
- }
-
- if (empty($arg['code'])) {
- $arg['code'] = 500;
- }
-
- // installer
- if (class_exists('rcmail_install', false)) {
- $rci = rcmail_install::get_instance();
- $rci->raise_error($arg);
- return;
- }
-
- $cli = php_sapi_name() == 'cli';
-
- if (($log || $terminate) && !$cli && $arg['message']) {
- $arg['fatal'] = $terminate;
- self::log_bug($arg);
- }
-
- // terminate script
- if ($terminate) {
- // display error page
- if (is_object(self::$instance->output)) {
- self::$instance->output->raise_error($arg['code'], $arg['message']);
- }
- else if ($cli) {
- fwrite(STDERR, 'ERROR: ' . $arg['message']);
- }
-
- exit(1);
- }
- else if ($cli) {
- fwrite(STDERR, 'ERROR: ' . $arg['message']);
- }
- }
-
-
- /**
- * Report error according to configured debug_level
- *
- * @param array Named parameters
- * @see self::raise_error()
- */
- public static function log_bug($arg_arr)
- {
- $program = strtoupper(!empty($arg_arr['type']) ? $arg_arr['type'] : 'php');
- $level = self::get_instance()->config->get('debug_level');
-
- // disable errors for ajax requests, write to log instead (#1487831)
- if (($level & 4) && !empty($_REQUEST['_remote'])) {
- $level = ($level ^ 4) | 1;
- }
-
- // write error to local log file
- if (($level & 1) || !empty($arg_arr['fatal'])) {
- if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- $post_query = '?_task='.urlencode($_POST['_task']).'&_action='.urlencode($_POST['_action']);
- }
- else {
- $post_query = '';
- }
-
- $log_entry = sprintf("%s Error: %s%s (%s %s)",
- $program,
- $arg_arr['message'],
- $arg_arr['file'] ? sprintf(' in %s on line %d', $arg_arr['file'], $arg_arr['line']) : '',
- $_SERVER['REQUEST_METHOD'],
- $_SERVER['REQUEST_URI'] . $post_query);
-
- if (!self::write_log('errors', $log_entry)) {
- // send error to PHPs error handler if write_log didn't succeed
- trigger_error($arg_arr['message'], E_USER_WARNING);
- }
- }
-
- // report the bug to the global bug reporting system
- if ($level & 2) {
- // TODO: Send error via HTTP
- }
-
- // show error if debug_mode is on
- if ($level & 4) {
- print "<b>$program Error";
-
- if (!empty($arg_arr['file']) && !empty($arg_arr['line'])) {
- print " in $arg_arr[file] ($arg_arr[line])";
- }
-
- print ':</b>&nbsp;';
- print nl2br($arg_arr['message']);
- print '<br />';
- flush();
- }
- }
-
-
- /**
- * Returns current time (with microseconds).
- *
- * @return float Current time in seconds since the Unix
- */
- public static function timer()
- {
- return microtime(true);
- }
-
-
- /**
- * Logs time difference according to provided timer
- *
- * @param float $timer Timer (self::timer() result)
- * @param string $label Log line prefix
- * @param string $dest Log file name
- *
- * @see self::timer()
- */
- public static function print_timer($timer, $label = 'Timer', $dest = 'console')
- {
- static $print_count = 0;
-
- $print_count++;
- $now = self::timer();
- $diff = $now - $timer;
-
- if (empty($label)) {
- $label = 'Timer '.$print_count;
- }
-
- self::write_log($dest, sprintf("%s: %0.4f sec", $label, $diff));
- }
-
- /**
- * Setter for system user object
- *
- * @param rcube_user Current user instance
- */
- public function set_user($user)
- {
- if (is_object($user)) {
- $this->user = $user;
-
- // overwrite config with user preferences
- $this->config->set_user_prefs((array)$this->user->get_prefs());
- }
- }
-
- /**
- * Getter for logged user ID.
- *
- * @return mixed User identifier
- */
- public function get_user_id()
- {
- if (is_object($this->user)) {
- return $this->user->ID;
- }
- else if (isset($_SESSION['user_id'])) {
- return $_SESSION['user_id'];
- }
-
- return null;
- }
-
-
- /**
- * Getter for logged user name.
- *
- * @return string User name
- */
- public function get_user_name()
- {
- if (is_object($this->user)) {
- return $this->user->get_username();
- }
- else if (isset($_SESSION['username'])) {
- return $_SESSION['username'];
- }
- }
-
-
- /**
- * Getter for logged user email (derived from user name not identity).
- *
- * @return string User email address
- */
- public function get_user_email()
- {
- if (is_object($this->user)) {
- return $this->user->get_username('mail');
- }
- }
-
-
- /**
- * Getter for logged user password.
- *
- * @return string User password
- */
- public function get_user_password()
- {
- if ($this->password) {
- return $this->password;
- }
- else if ($_SESSION['password']) {
- return $this->decrypt($_SESSION['password']);
- }
- }
-
- /**
- * Get the per-user log directory
- */
- protected function get_user_log_dir()
- {
- $log_dir = $this->config->get('log_dir', RCUBE_INSTALL_PATH . 'logs');
- $user_name = $this->get_user_name();
- $user_log_dir = $log_dir . '/' . $user_name;
-
- return !empty($user_name) && is_writable($user_log_dir) ? $user_log_dir : false;
- }
-
- /**
- * Getter for logged user language code.
- *
- * @return string User language code
- */
- public function get_user_language()
- {
- if (is_object($this->user)) {
- return $this->user->language;
- }
- else if (isset($_SESSION['language'])) {
- return $_SESSION['language'];
- }
- }
-
- /**
- * Unique Message-ID generator.
- *
- * @return string Message-ID
- */
- public function gen_message_id()
- {
- $local_part = md5(uniqid('rcube'.mt_rand(), true));
- $domain_part = $this->user->get_username('domain');
-
- // Try to find FQDN, some spamfilters doesn't like 'localhost' (#1486924)
- if (!preg_match('/\.[a-z]+$/i', $domain_part)) {
- foreach (array($_SERVER['HTTP_HOST'], $_SERVER['SERVER_NAME']) as $host) {
- $host = preg_replace('/:[0-9]+$/', '', $host);
- if ($host && preg_match('/\.[a-z]+$/i', $host)) {
- $domain_part = $host;
- }
- }
- }
-
- return sprintf('<%s@%s>', $local_part, $domain_part);
- }
-
- /**
- * Send the given message using the configured method.
- *
- * @param object $message Reference to Mail_MIME object
- * @param string $from Sender address string
- * @param array $mailto Array of recipient address strings
- * @param array $error SMTP error array (reference)
- * @param string $body_file Location of file with saved message body (reference),
- * used when delay_file_io is enabled
- * @param array $options SMTP options (e.g. DSN request)
- *
- * @return boolean Send status.
- */
- public function deliver_message(&$message, $from, $mailto, &$error, &$body_file = null, $options = null)
- {
- $plugin = $this->plugins->exec_hook('message_before_send', array(
- 'message' => $message,
- 'from' => $from,
- 'mailto' => $mailto,
- 'options' => $options,
- ));
-
- if ($plugin['abort']) {
- if (!empty($plugin['error'])) {
- $error = $plugin['error'];
- }
- if (!empty($plugin['body_file'])) {
- $body_file = $plugin['body_file'];
- }
-
- return isset($plugin['result']) ? $plugin['result'] : false;
- }
-
- $from = $plugin['from'];
- $mailto = $plugin['mailto'];
- $options = $plugin['options'];
- $message = $plugin['message'];
- $headers = $message->headers();
-
- // send thru SMTP server using custom SMTP library
- if ($this->config->get('smtp_server')) {
- // generate list of recipients
- $a_recipients = array($mailto);
-
- if (strlen($headers['Cc']))
- $a_recipients[] = $headers['Cc'];
- if (strlen($headers['Bcc']))
- $a_recipients[] = $headers['Bcc'];
-
- // clean Bcc from header for recipients
- $send_headers = $headers;
- unset($send_headers['Bcc']);
- // here too, it because txtHeaders() below use $message->_headers not only $send_headers
- unset($message->_headers['Bcc']);
-
- $smtp_headers = $message->txtHeaders($send_headers, true);
-
- if ($message->getParam('delay_file_io')) {
- // use common temp dir
- $temp_dir = $this->config->get('temp_dir');
- $body_file = tempnam($temp_dir, 'rcmMsg');
- if (PEAR::isError($mime_result = $message->saveMessageBody($body_file))) {
- self::raise_error(array('code' => 650, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Could not create message: ".$mime_result->getMessage()),
- TRUE, FALSE);
- return false;
- }
- $msg_body = fopen($body_file, 'r');
- }
- else {
- $msg_body = $message->get();
- }
-
- // send message
- if (!is_object($this->smtp)) {
- $this->smtp_init(true);
- }
-
- $sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $options);
- $response = $this->smtp->get_response();
- $error = $this->smtp->get_error();
-
- // log error
- if (!$sent) {
- self::raise_error(array('code' => 800, 'type' => 'smtp',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => "SMTP error: ".join("\n", $response)), TRUE, FALSE);
- }
- }
- // send mail using PHP's mail() function
- else {
- // unset some headers because they will be added by the mail() function
- $headers_enc = $message->headers($headers);
- $headers_php = $message->_headers;
- unset($headers_php['To'], $headers_php['Subject']);
-
- // reset stored headers and overwrite
- $message->_headers = array();
- $header_str = $message->txtHeaders($headers_php);
-
- // #1485779
- if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
- if (preg_match_all('/<([^@]+@[^>]+)>/', $headers_enc['To'], $m)) {
- $headers_enc['To'] = implode(', ', $m[1]);
- }
- }
-
- $msg_body = $message->get();
-
- if (PEAR::isError($msg_body)) {
- self::raise_error(array('code' => 650, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Could not create message: ".$msg_body->getMessage()),
- TRUE, FALSE);
- }
- else {
- $delim = $this->config->header_delimiter();
- $to = $headers_enc['To'];
- $subject = $headers_enc['Subject'];
- $header_str = rtrim($header_str);
-
- if ($delim != "\r\n") {
- $header_str = str_replace("\r\n", $delim, $header_str);
- $msg_body = str_replace("\r\n", $delim, $msg_body);
- $to = str_replace("\r\n", $delim, $to);
- $subject = str_replace("\r\n", $delim, $subject);
- }
-
- if (filter_var(ini_get('safe_mode'), FILTER_VALIDATE_BOOLEAN))
- $sent = mail($to, $subject, $msg_body, $header_str);
- else
- $sent = mail($to, $subject, $msg_body, $header_str, "-f$from");
- }
- }
-
- if ($sent) {
- $this->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body));
-
- // remove MDN headers after sending
- unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']);
-
- // get all recipients
- if ($headers['Cc'])
- $mailto .= $headers['Cc'];
- if ($headers['Bcc'])
- $mailto .= $headers['Bcc'];
- if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m))
- $mailto = implode(', ', array_unique($m[1]));
-
- if ($this->config->get('smtp_log')) {
- self::write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s",
- $this->user->get_username(),
- $_SERVER['REMOTE_ADDR'],
- $mailto,
- !empty($response) ? join('; ', $response) : ''));
- }
- }
- else {
- // allow plugins to catch sending errors with the same parameters as in 'message_before_send'
- $this->plugins->exec_hook('message_send_error', $plugin + array('error' => $error));
- }
-
- if (is_resource($msg_body)) {
- fclose($msg_body);
- }
-
- $message->_headers = array();
- $message->headers($headers);
-
- return $sent;
- }
-
-}
-
-
-/**
- * Lightweight plugin API class serving as a dummy if plugins are not enabled
- *
- * @package Framework
- * @subpackage Core
- */
-class rcube_dummy_plugin_api
-{
- /**
- * Triggers a plugin hook.
- * @see rcube_plugin_api::exec_hook()
- */
- public function exec_hook($hook, $args = array())
- {
- return $args;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_addressbook.php b/lib/ext/Roundcube/rcube_addressbook.php
deleted file mode 100644
index 69027b0..0000000
--- a/lib/ext/Roundcube/rcube_addressbook.php
+++ /dev/null
@@ -1,676 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2006-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Interface to the local address book database |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-
-/**
- * Abstract skeleton of an address book/repository
- *
- * @package Framework
- * @subpackage Addressbook
- */
-abstract class rcube_addressbook
-{
- /** constants for error reporting **/
- const ERROR_READ_ONLY = 1;
- const ERROR_NO_CONNECTION = 2;
- const ERROR_VALIDATE = 3;
- const ERROR_SAVING = 4;
- const ERROR_SEARCH = 5;
-
- /** public properties (mandatory) */
- public $primary_key;
- public $groups = false;
- public $export_groups = true;
- public $readonly = true;
- public $searchonly = false;
- public $undelete = false;
- public $ready = false;
- public $group_id = null;
- public $list_page = 1;
- public $page_size = 10;
- public $sort_col = 'name';
- public $sort_order = 'ASC';
- public $coltypes = array('name' => array('limit'=>1), 'firstname' => array('limit'=>1), 'surname' => array('limit'=>1), 'email' => array('limit'=>1));
- public $date_cols = array();
-
- protected $error;
-
- /**
- * Returns addressbook name (e.g. for addressbooks listing)
- */
- abstract function get_name();
-
- /**
- * Save a search string for future listings
- *
- * @param mixed Search params to use in listing method, obtained by get_search_set()
- */
- abstract function set_search_set($filter);
-
- /**
- * Getter for saved search properties
- *
- * @return mixed Search properties used by this class
- */
- abstract function get_search_set();
-
- /**
- * Reset saved results and search parameters
- */
- abstract function reset();
-
- /**
- * Refresh saved search set after data has changed
- *
- * @return mixed New search set
- */
- function refresh_search()
- {
- return $this->get_search_set();
- }
-
- /**
- * List the current set of contact records
- *
- * @param array List of cols to show
- * @param int Only return this number of records, use negative values for tail
- * @return array Indexed list of contact records, each a hash array
- */
- abstract function list_records($cols=null, $subset=0);
-
- /**
- * Search records
- *
- * @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, $mode=0, $select=true, $nocount=false, $required=array());
-
- /**
- * Count number of available contacts in database
- *
- * @return rcube_result_set Result set with values for 'count' and 'first'
- */
- abstract function count();
-
- /**
- * Return the last result set
- *
- * @return rcube_result_set Current result set or NULL if nothing selected yet
- */
- abstract function get_result();
-
- /**
- * Get a specific contact record
- *
- * @param mixed record identifier(s)
- * @param boolean True to return record as associative array, otherwise a result set is returned
- *
- * @return mixed Result object with all record fields or False if not found
- */
- abstract function get_record($id, $assoc=false);
-
- /**
- * Returns the last error occurred (e.g. when updating/inserting failed)
- *
- * @return array Hash array with the following fields: type, message
- */
- function get_error()
- {
- return $this->error;
- }
-
- /**
- * Setter for errors for internal use
- *
- * @param int Error type (one of this class' error constants)
- * @param string Error message (name of a text label)
- */
- protected function set_error($type, $message)
- {
- $this->error = array('type' => $type, 'message' => $message);
- }
-
- /**
- * Close connection to source
- * Called on script shutdown
- */
- function close() { }
-
- /**
- * Set internal list page
- *
- * @param number Page number to list
- * @access public
- */
- function set_page($page)
- {
- $this->list_page = (int)$page;
- }
-
- /**
- * Set internal page size
- *
- * @param number Number of messages to display on one page
- * @access public
- */
- function set_pagesize($size)
- {
- $this->page_size = (int)$size;
- }
-
- /**
- * Set internal sort settings
- *
- * @param string $sort_col Sort column
- * @param string $sort_order Sort order
- */
- function set_sort_order($sort_col, $sort_order = null)
- {
- if ($sort_col != null && ($this->coltypes[$sort_col] || in_array($sort_col, $this->coltypes))) {
- $this->sort_col = $sort_col;
- }
- if ($sort_order != null) {
- $this->sort_order = strtoupper($sort_order) == 'DESC' ? 'DESC' : 'ASC';
- }
- }
-
- /**
- * Check the given data before saving.
- * 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, $autofix = false)
- {
- $rcube = rcube::get_instance();
- $valid = true;
-
- // check validity of email addresses
- foreach ($this->get_col_values('email', $save_data, true) as $email) {
- if (strlen($email)) {
- if (!rcube_utils::check_email(rcube_utils::idn_to_ascii($email))) {
- $error = $rcube->gettext(array('name' => 'emailformaterror', 'vars' => array('email' => $email)));
- $this->set_error(self::ERROR_VALIDATE, $error);
- $valid = false;
- break;
- }
- }
- }
-
- // allow plugins to do contact validation and auto-fixing
- $plugin = $rcube->plugins->exec_hook('contact_validate', array(
- 'record' => $save_data,
- 'autofix' => $autofix,
- 'valid' => $valid,
- ));
-
- if ($valid && !$plugin['valid']) {
- $this->set_error(self::ERROR_VALIDATE, $plugin['error']);
- }
-
- if (is_array($plugin['record'])) {
- $save_data = $plugin['record'];
- }
-
- return $plugin['valid'];
- }
-
- /**
- * Create a new contact record
- *
- * @param array Assoziative array with save data
- * Keys: Field name with optional section in the form FIELD:SECTION
- * Values: Field value. Can be either a string or an array of strings for multiple values
- * @param boolean True to check for duplicates first
- * @return mixed The created record ID on success, False on error
- */
- function insert($save_data, $check=false)
- {
- /* empty for read-only address books */
- }
-
- /**
- * Create new contact records for every item in the record set
- *
- * @param object rcube_result_set Recordset to insert
- * @param boolean True to check for duplicates first
- * @return array List of created record IDs
- */
- function insertMultiple($recset, $check=false)
- {
- $ids = array();
- if (is_object($recset) && is_a($recset, rcube_result_set)) {
- while ($row = $recset->next()) {
- if ($insert = $this->insert($row, $check))
- $ids[] = $insert;
- }
- }
- return $ids;
- }
-
- /**
- * Update a specific contact record
- *
- * @param mixed Record identifier
- * @param array Assoziative array with save data
- * Keys: Field name with optional section in the form FIELD:SECTION
- * Values: Field value. Can be either a string or an array of strings for multiple values
- *
- * @return mixed On success if ID has been changed returns ID, otherwise True, False on error
- */
- function update($id, $save_cols)
- {
- /* empty for read-only address books */
- }
-
- /**
- * Mark one or more contact records as deleted
- *
- * @param array Record identifiers
- * @param bool Remove records irreversible (see self::undelete)
- */
- function delete($ids, $force=true)
- {
- /* empty for read-only address books */
- }
-
- /**
- * Unmark delete flag on contact record(s)
- *
- * @param array Record identifiers
- */
- function undelete($ids)
- {
- /* empty for read-only address books */
- }
-
- /**
- * Mark all records in database as deleted
- *
- * @param bool $with_groups Remove also groups
- */
- function delete_all($with_groups = false)
- {
- /* empty for read-only address books */
- }
-
- /**
- * Setter for the current group
- * (empty, has to be re-implemented by extending class)
- */
- function set_group($gid) { }
-
- /**
- * List all active contact groups of this source
- *
- * @param string Optional search string to match group name
- * @param int Matching mode:
- * 0 - partial (*abc*),
- * 1 - strict (=),
- * 2 - prefix (abc*)
- *
- * @return array Indexed list of contact groups, each a hash array
- */
- function list_groups($search = null, $mode = 0)
- {
- /* empty for address books don't supporting groups */
- 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
- *
- * @param string The group name
- * @return mixed False on error, array with record props in success
- */
- function create_group($name)
- {
- /* empty for address books don't supporting groups */
- return false;
- }
-
- /**
- * Delete the given group and all linked group members
- *
- * @param string Group identifier
- * @return boolean True on success, false if no data was changed
- */
- function delete_group($gid)
- {
- /* empty for address books don't supporting groups */
- return false;
- }
-
- /**
- * Rename a specific contact group
- *
- * @param string Group identifier
- * @param string New name to set for this group
- * @param string New group identifier (if changed, otherwise don't set)
- * @return boolean New name on success, false if no data was changed
- */
- function rename_group($gid, $newname, &$newid)
- {
- /* empty for address books don't supporting groups */
- return false;
- }
-
- /**
- * Add the given contact records the a certain group
- *
- * @param string Group identifier
- * @param array|string List of contact identifiers to be added
- *
- * @return int Number of contacts added
- */
- function add_to_group($group_id, $ids)
- {
- /* empty for address books don't supporting groups */
- return 0;
- }
-
- /**
- * Remove the given contact records from a certain group
- *
- * @param string Group identifier
- * @param array|string List of contact identifiers to be removed
- *
- * @return int Number of deleted group members
- */
- function remove_from_group($group_id, $ids)
- {
- /* empty for address books don't supporting groups */
- return 0;
- }
-
- /**
- * Get group assignments of a specific contact record
- *
- * @param mixed Record identifier
- *
- * @return array List of assigned groups as ID=>Name pairs
- * @since 0.5-beta
- */
- function get_record_groups($id)
- {
- /* empty for address books don't supporting groups */
- return array();
- }
-
- /**
- * Utility function to return all values of a certain data column
- * either as flat list or grouped by subtype
- *
- * @param string Col name
- * @param array Record data array as used for saving
- * @param boolean True to return one array with all values, False for hash array with values grouped by type
- * @return array List of column values
- */
- public static function get_col_values($col, $data, $flat = false)
- {
- $out = array();
- foreach ((array)$data as $c => $values) {
- if ($c === $col || strpos($c, $col.':') === 0) {
- if ($flat) {
- $out = array_merge($out, (array)$values);
- }
- else {
- list(, $type) = explode(':', $c);
- $out[$type] = array_merge((array)$out[$type], (array)$values);
- }
- }
- }
-
- // remove duplicates
- if ($flat && !empty($out)) {
- $out = array_unique($out);
- }
-
- return $out;
- }
-
- /**
- * Normalize the given string for fulltext search.
- * Currently only optimized for Latin-1 characters; to be extended
- *
- * @param string Input string (UTF-8)
- * @return string Normalized string
- * @deprecated since 0.9-beta
- */
- protected static function normalize_string($str)
- {
- return rcube_utils::normalize_string($str);
- }
-
- /**
- * Compose a valid display name from the given structured contact data
- *
- * @param array Hash array with contact data as key-value pairs
- * @param bool Don't attempt to extract components from the email address
- *
- * @return string Display name
- */
- public static function compose_display_name($contact, $full_email = false)
- {
- $contact = rcube::get_instance()->plugins->exec_hook('contact_displayname', $contact);
- $fn = $contact['name'];
-
- if (!$fn) // default display name composition according to vcard standard
- $fn = trim(join(' ', array_filter(array($contact['prefix'], $contact['firstname'], $contact['middlename'], $contact['surname'], $contact['suffix']))));
-
- // use email address part for name
- $email = self::get_col_values('email', $contact, true);
- $email = $email[0];
-
- if ($email && (empty($fn) || $fn == $email)) {
- // return full email
- if ($full_email)
- return $email;
-
- list($emailname) = explode('@', $email);
- if (preg_match('/(.*)[\.\-\_](.*)/', $emailname, $match))
- $fn = trim(ucfirst($match[1]).' '.ucfirst($match[2]));
- else
- $fn = ucfirst($emailname);
- }
-
- return $fn;
- }
-
- /**
- * Compose the name to display in the contacts list for the given contact record.
- * This respects the settings parameter how to list conacts.
- *
- * @param array Hash array with contact data as key-value pairs
- * @return string List name
- */
- public static function compose_list_name($contact)
- {
- static $compose_mode;
-
- if (!isset($compose_mode)) // cache this
- $compose_mode = rcube::get_instance()->config->get('addressbook_name_listing', 0);
-
- if ($compose_mode == 3)
- $fn = join(' ', array($contact['surname'] . ',', $contact['firstname'], $contact['middlename']));
- else if ($compose_mode == 2)
- $fn = join(' ', array($contact['surname'], $contact['firstname'], $contact['middlename']));
- else if ($compose_mode == 1)
- $fn = join(' ', array($contact['firstname'], $contact['middlename'], $contact['surname']));
- else if ($compose_mode == 0)
- $fn = !empty($contact['name']) ? $contact['name'] : join(' ', array($contact['prefix'], $contact['firstname'], $contact['middlename'], $contact['surname'], $contact['suffix']));
- else {
- $plugin = rcube::get_instance()->plugins->exec_hook('contact_listname', array('contact' => $contact));
- $fn = $plugin['fn'];
- }
-
- $fn = trim($fn, ', ');
-
- // fallback to display name
- if (empty($fn) && $contact['name'])
- $fn = $contact['name'];
-
- // fallback to email address
- if (empty($fn) && ($email = self::get_col_values('email', $contact, true)) && !empty($email)) {
- return $email[0];
- }
-
- return $fn;
- }
-
- /**
- * Build contact display name for autocomplete listing
- *
- * @param array Hash array with contact data as key-value pairs
- * @param string Optional email address
- * @param string Optional name (self::compose_list_name() result)
- * @param string Optional template to use (defaults to the 'contact_search_name' config option)
- *
- * @return string Display name
- */
- public static function compose_search_name($contact, $email = null, $name = null, $templ = null)
- {
- static $template;
-
- if (empty($templ) && !isset($template)) { // cache this
- $template = rcube::get_instance()->config->get('contact_search_name');
- if (empty($template)) {
- $template = '{name} <{email}>';
- }
- }
-
- $result = $templ ?: $template;
-
- if (preg_match_all('/\{[a-z]+\}/', $result, $matches)) {
- foreach ($matches[0] as $key) {
- $key = trim($key, '{}');
- $value = '';
-
- switch ($key) {
- case 'name':
- $value = $name ?: self::compose_list_name($contact);
- break;
-
- case 'email':
- $value = $email;
- break;
- }
-
- if (empty($value)) {
- $value = strpos($key, ':') ? $contact[$key] : self::get_col_values($key, $contact, true);
- if (is_array($value)) {
- $value = $value[0];
- }
- }
-
- $result = str_replace('{' . $key . '}', $value, $result);
- }
- }
-
- $result = preg_replace('/\s+/', ' ', $result);
- $result = preg_replace('/\s*(<>|\(\)|\[\])/', '', $result);
- $result = trim($result, '/ ');
-
- return $result;
- }
-
- /**
- * Create a unique key for sorting contacts
- */
- public static function compose_contact_key($contact, $sort_col)
- {
- $key = $contact[$sort_col] . ':' . $contact['sourceid'];
-
- // add email to a key to not skip contacts with the same name (#1488375)
- if (($email = self::get_col_values('email', $contact, true)) && !empty($email)) {
- $key .= ':' . implode(':', (array)$email);
- }
-
- return $key;
- }
-
- /**
- * Compare search value with contact data
- *
- * @param string $colname Data name
- * @param string|array $value Data value
- * @param string $search Search value
- * @param int $mode Search mode
- *
- * @return bool Comparision result
- */
- protected function compare_search_value($colname, $value, $search, $mode)
- {
- // The value is a date string, for date we'll
- // use only strict comparison (mode = 1)
- // @TODO: partial search, e.g. match only day and month
- if (in_array($colname, $this->date_cols)) {
- return (($value = rcube_utils::anytodatetime($value))
- && ($search = rcube_utils::anytodatetime($search))
- && $value->format('Ymd') == $search->format('Ymd'));
- }
-
- // composite field, e.g. address
- 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);
- }
-
- if ($got) {
- return true;
- }
- }
-
- return false;
- }
-
-}
-
diff --git a/lib/ext/Roundcube/rcube_base_replacer.php b/lib/ext/Roundcube/rcube_base_replacer.php
deleted file mode 100644
index fa67647..0000000
--- a/lib/ext/Roundcube/rcube_base_replacer.php
+++ /dev/null
@@ -1,105 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Provide basic functions for base URL replacement |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Helper class to turn relative urls into absolute ones
- * using a predefined base
- *
- * @package Framework
- * @subpackage Utils
- * @author Thomas Bruederli <roundcube@gmail.com>
- */
-class rcube_base_replacer
-{
- private $base_url;
-
-
- public function __construct($base)
- {
- $this->base_url = $base;
- }
-
-
- public function callback($matches)
- {
- return $matches[1] . '="' . self::absolute_url($matches[3], $this->base_url) . '"';
- }
-
-
- public function replace($body)
- {
- return preg_replace_callback(array(
- '/(src|background|href)=(["\']?)([^"\'\s>]+)(\2|\s|>)/i',
- '/(url\s*\()(["\']?)([^"\'\)\s]+)(\2)\)/i',
- ),
- array($this, 'callback'), $body);
- }
-
-
- /**
- * Convert paths like ../xxx to an absolute path using a base url
- *
- * @param string $path Relative path
- * @param string $base_url Base URL
- *
- * @return string Absolute URL
- */
- public static function absolute_url($path, $base_url)
- {
- $host_url = $base_url;
- $abs_path = $path;
-
- // check if path is an absolute URL
- if (preg_match('/^[fhtps]+:\/\//', $path)) {
- return $path;
- }
-
- // check if path is a content-id scheme
- if (strpos($path, 'cid:') === 0) {
- return $path;
- }
-
- // cut base_url to the last directory
- if (strrpos($base_url, '/') > 7) {
- $host_url = substr($base_url, 0, strpos($base_url, '/', 7));
- $base_url = substr($base_url, 0, strrpos($base_url, '/'));
- }
-
- // $path is absolute
- if ($path[0] == '/') {
- $abs_path = $host_url.$path;
- }
- else {
- // strip './' because its the same as ''
- $path = preg_replace('/^\.\//', '', $path);
-
- if (preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER)) {
- foreach ($matches as $a_match) {
- if ($pos = strrpos($base_url, '/')) {
- $base_url = substr($base_url, 0, $pos);
- }
- $path = substr($path, 3);
- }
- }
-
- $abs_path = $base_url.'/'.$path;
- }
-
- return $abs_path;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_browser.php b/lib/ext/Roundcube/rcube_browser.php
deleted file mode 100644
index b9642d8..0000000
--- a/lib/ext/Roundcube/rcube_browser.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2007-2009, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Class representing the client browser's properties |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Provide details about the client's browser based on the User-Agent header
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_browser
-{
- function __construct()
- {
- $HTTP_USER_AGENT = strtolower($_SERVER['HTTP_USER_AGENT']);
-
- $this->ver = 0;
- $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->webkit = strpos($HTTP_USER_AGENT, 'applewebkit') !== false;
- $this->opera = strpos($HTTP_USER_AGENT, 'opera') !== false || ($this->webkit && strpos($HTTP_USER_AGENT, 'opr/') !== false);
- $this->ns = strpos($HTTP_USER_AGENT, 'netscape') !== false;
- $this->chrome = !$this->opera && strpos($HTTP_USER_AGENT, 'chrome') !== false;
- $this->ie = !$this->opera && (strpos($HTTP_USER_AGENT, 'compatible; msie') !== false || strpos($HTTP_USER_AGENT, 'trident/') !== false);
- $this->safari = !$this->opera && !$this->chrome && ($this->webkit || strpos($HTTP_USER_AGENT, 'safari') !== false);
- $this->mz = !$this->ie && !$this->safari && !$this->chrome && !$this->ns && !$this->opera && strpos($HTTP_USER_AGENT, 'mozilla') !== false;
-
- if ($this->opera) {
- if (preg_match('/(opera|opr)\/([0-9.]+)/', $HTTP_USER_AGENT, $regs)) {
- $this->ver = (float) $regs[2];
- }
- }
- else if (preg_match('/(chrome|msie|version|khtml)(\s*|\/)([0-9.]+)/', $HTTP_USER_AGENT, $regs)) {
- $this->ver = (float) $regs[3];
- }
- else if (preg_match('/rv:([0-9.]+)/', $HTTP_USER_AGENT, $regs)) {
- $this->ver = (float) $regs[1];
- }
-
- if (preg_match('/ ([a-z]{2})-([a-z]{2})/', $HTTP_USER_AGENT, $regs))
- $this->lang = $regs[1];
- else
- $this->lang = 'en';
-
- $this->dom = $this->mz || $this->safari || ($this->ie && $this->ver>=5) || ($this->opera && $this->ver>=7);
- $this->pngalpha = $this->mz || $this->safari || ($this->ie && $this->ver>=5.5) ||
- ($this->ie && $this->ver>=5 && $this->mac) || ($this->opera && $this->ver>=7) ? true : false;
- $this->imgdata = !$this->ie;
- }
-}
-
diff --git a/lib/ext/Roundcube/rcube_cache.php b/lib/ext/Roundcube/rcube_cache.php
deleted file mode 100644
index 2f3ca6f..0000000
--- a/lib/ext/Roundcube/rcube_cache.php
+++ /dev/null
@@ -1,631 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2011, The Roundcube Dev Team |
- | Copyright (C) 2011, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Caching engine |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-
-/**
- * Interface class for accessing Roundcube cache
- *
- * @package Framework
- * @subpackage Cache
- * @author Thomas Bruederli <roundcube@gmail.com>
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_cache
-{
- /**
- * Instance of database handler
- *
- * @var rcube_db|Memcache|bool
- */
- private $db;
- private $type;
- private $userid;
- private $prefix;
- private $table;
- private $ttl;
- private $packed;
- private $index;
- private $cache = array();
- private $cache_changes = array();
- private $cache_sums = array();
- private $max_packet = -1;
-
-
- /**
- * Object constructor.
- *
- * @param string $type Engine type ('db' or 'memcache' or 'apc')
- * @param int $userid User identifier
- * @param string $prefix Key name prefix
- * @param string $ttl Expiration time of memcache/apc items
- * @param bool $packed Enables/disabled data serialization.
- * It's possible to disable data serialization if you're sure
- * stored data will be always a safe string
- */
- function __construct($type, $userid, $prefix='', $ttl=0, $packed=true)
- {
- $rcube = rcube::get_instance();
- $type = strtolower($type);
-
- if ($type == 'memcache') {
- $this->type = 'memcache';
- $this->db = $rcube->get_memcache();
- }
- else if ($type == 'apc') {
- $this->type = 'apc';
- $this->db = function_exists('apc_exists'); // APC 3.1.4 required
- }
- else {
- $this->type = 'db';
- $this->db = $rcube->get_dbh();
- $this->table = $this->db->table_name('cache', true);
- }
-
- // convert ttl string to seconds
- $ttl = get_offset_sec($ttl);
- if ($ttl > 2592000) $ttl = 2592000;
-
- $this->userid = (int) $userid;
- $this->ttl = $ttl;
- $this->packed = $packed;
- $this->prefix = $prefix;
- }
-
-
- /**
- * Returns cached value.
- *
- * @param string $key Cache key name
- *
- * @return mixed Cached value
- */
- function get($key)
- {
- if (!array_key_exists($key, $this->cache)) {
- return $this->read_record($key);
- }
-
- return $this->cache[$key];
- }
-
-
- /**
- * Sets (add/update) value in cache.
- *
- * @param string $key Cache key name
- * @param mixed $data Cache data
- */
- function set($key, $data)
- {
- $this->cache[$key] = $data;
- $this->cache_changed = true;
- $this->cache_changes[$key] = true;
- }
-
-
- /**
- * Returns cached value without storing it in internal memory.
- *
- * @param string $key Cache key name
- *
- * @return mixed Cached value
- */
- function read($key)
- {
- if (array_key_exists($key, $this->cache)) {
- return $this->cache[$key];
- }
-
- return $this->read_record($key, true);
- }
-
-
- /**
- * Sets (add/update) value in cache and immediately saves
- * it in the backend, no internal memory will be used.
- *
- * @param string $key Cache key name
- * @param mixed $data Cache data
- *
- * @param boolean True on success, False on failure
- */
- function write($key, $data)
- {
- return $this->write_record($key, $this->serialize($data));
- }
-
-
- /**
- * Clears the cache.
- *
- * @param string $key Cache key name or pattern
- * @param boolean $prefix_mode Enable it to clear all keys starting
- * with prefix specified in $key
- */
- function remove($key=null, $prefix_mode=false)
- {
- // Remove all keys
- if ($key === null) {
- $this->cache = array();
- $this->cache_changed = false;
- $this->cache_changes = array();
- $this->cache_sums = array();
- }
- // Remove keys by name prefix
- else if ($prefix_mode) {
- foreach (array_keys($this->cache) as $k) {
- if (strpos($k, $key) === 0) {
- $this->cache[$k] = null;
- $this->cache_changes[$k] = false;
- unset($this->cache_sums[$k]);
- }
- }
- }
- // Remove one key by name
- else {
- $this->cache[$key] = null;
- $this->cache_changes[$key] = false;
- unset($this->cache_sums[$key]);
- }
-
- // Remove record(s) from the backend
- $this->remove_record($key, $prefix_mode);
- }
-
-
- /**
- * Remove cache records older than ttl
- */
- function expunge()
- {
- if ($this->type == 'db' && $this->db && $this->ttl) {
- $this->db->query(
- "DELETE FROM {$this->table}".
- " WHERE `user_id` = ?".
- " AND `cache_key` LIKE ?".
- " AND `expires` < " . $this->db->now(),
- $this->userid,
- $this->prefix.'.%');
- }
- }
-
-
- /**
- * Remove expired records of all caches
- */
- static function gc()
- {
- $rcube = rcube::get_instance();
- $db = $rcube->get_dbh();
-
- $db->query("DELETE FROM " . $db->table_name('cache', true) . " WHERE `expires` < " . $db->now());
- }
-
-
- /**
- * Writes the cache back to the DB.
- */
- function close()
- {
- if (!$this->cache_changed) {
- return;
- }
-
- foreach ($this->cache as $key => $data) {
- // The key has been used
- if ($this->cache_changes[$key]) {
- // Make sure we're not going to write unchanged data
- // by comparing current md5 sum with the sum calculated on DB read
- $data = $this->serialize($data);
-
- if (!$this->cache_sums[$key] || $this->cache_sums[$key] != md5($data)) {
- $this->write_record($key, $data);
- }
- }
- }
-
- $this->write_index();
-
- $this->index = null;
- $this->cache = array();
- $this->cache_sums = array();
- $this->cache_changes = array();
- }
-
-
- /**
- * Reads cache entry.
- *
- * @param string $key Cache key name
- * @param boolean $nostore Enable to skip in-memory store
- *
- * @return mixed Cached value
- */
- private function read_record($key, $nostore=false)
- {
- if (!$this->db) {
- return null;
- }
-
- 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->unserialize($data);
-
- if ($nostore) {
- return $data;
- }
-
- $this->cache_sums[$key] = $md5sum;
- $this->cache[$key] = $data;
- }
- else {
- $this->cache[$key] = null;
- }
- }
- else {
- $sql_result = $this->db->limitquery(
- "SELECT `data`, `cache_key`".
- " FROM {$this->table}".
- " WHERE `user_id` = ? AND `cache_key` = ?".
- // for better performance we allow more records for one key
- // get the newer one
- " ORDER BY `created` DESC",
- 0, 1, $this->userid, $this->prefix.'.'.$key);
-
- if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
- $key = substr($sql_arr['cache_key'], strlen($this->prefix)+1);
- $md5sum = $sql_arr['data'] ? md5($sql_arr['data']) : null;
- if ($sql_arr['data']) {
- $data = $this->unserialize($sql_arr['data']);
- }
-
- if ($nostore) {
- return $data;
- }
-
- $this->cache[$key] = $data;
- $this->cache_sums[$key] = $md5sum;
- }
- else {
- $this->cache[$key] = null;
- }
- }
-
- return $this->cache[$key];
- }
-
-
- /**
- * Writes single cache record into DB.
- *
- * @param string $key Cache key name
- * @param mixed $data Serialized cache data
- *
- * @param boolean True on success, False on failure
- */
- private function write_record($key, $data)
- {
- if (!$this->db) {
- return false;
- }
-
- // don't attempt to write too big data sets
- if (strlen($data) > $this->max_packet_size()) {
- trigger_error("rcube_cache: max_packet_size ($this->max_packet) exceeded for key $key. Tried to write " . strlen($data) . " bytes", E_USER_WARNING);
- return false;
- }
-
- if ($this->type == 'memcache' || $this->type == 'apc') {
- return $this->add_record($this->ckey($key), $data);
- }
-
- $key_exists = array_key_exists($key, $this->cache_sums);
- $key = $this->prefix . '.' . $key;
-
- // Remove NULL rows (here we don't need to check if the record exist)
- if ($data == 'N;') {
- $this->db->query(
- "DELETE FROM {$this->table}".
- " WHERE `user_id` = ? AND `cache_key` = ?",
- $this->userid, $key);
-
- return true;
- }
-
- // update existing cache record
- if ($key_exists) {
- $result = $this->db->query(
- "UPDATE {$this->table}".
- " SET `created` = " . $this->db->now().
- ", `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL').
- ", `data` = ?".
- " WHERE `user_id` = ?".
- " AND `cache_key` = ?",
- $data, $this->userid, $key);
- }
- // add new cache record
- else {
- // for better performance we allow more records for one key
- // so, no need to check if record exist (see rcube_cache::read_record())
- $result = $this->db->query(
- "INSERT INTO {$this->table}".
- " (`created`, `expires`, `user_id`, `cache_key`, `data`)".
- " VALUES (" . $this->db->now() . ", " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?, ?, ?)",
- $this->userid, $key, $data);
- }
-
- return $this->db->affected_rows($result);
- }
-
-
- /**
- * Deletes the cache record(s).
- *
- * @param string $key Cache key name or pattern
- * @param boolean $prefix_mode Enable it to clear all keys starting
- * with prefix specified in $key
- */
- private function remove_record($key=null, $prefix_mode=false)
- {
- if (!$this->db) {
- return;
- }
-
- if ($this->type != 'db') {
- $this->load_index();
-
- // Remove all keys
- if ($key === null) {
- foreach ($this->index as $key) {
- $this->delete_record($key, false);
- }
- $this->index = array();
- }
- // Remove keys by name prefix
- else if ($prefix_mode) {
- foreach ($this->index as $k) {
- if (strpos($k, $key) === 0) {
- $this->delete_record($k);
- }
- }
- }
- // Remove one key by name
- else {
- $this->delete_record($key);
- }
-
- return;
- }
-
- // Remove all keys (in specified cache)
- if ($key === null) {
- $where = " AND `cache_key` LIKE " . $this->db->quote($this->prefix.'.%');
- }
- // Remove keys by name prefix
- else if ($prefix_mode) {
- $where = " AND `cache_key` LIKE " . $this->db->quote($this->prefix.'.'.$key.'%');
- }
- // Remove one key by name
- else {
- $where = " AND `cache_key` = " . $this->db->quote($this->prefix.'.'.$key);
- }
-
- $this->db->query(
- "DELETE FROM {$this->table} WHERE `user_id` = ?" . $where,
- $this->userid);
- }
-
-
- /**
- * Adds entry into memcache/apc DB.
- *
- * @param string $key Cache key name
- * @param mxied $data Serialized cache data
- * @param bollean $index Enables immediate index update
- *
- * @param boolean True on success, False on failure
- */
- private function add_record($key, $data, $index=false)
- {
- if ($this->type == 'memcache') {
- $result = $this->db->replace($key, $data, MEMCACHE_COMPRESSED, $this->ttl);
- if (!$result)
- $result = $this->db->set($key, $data, MEMCACHE_COMPRESSED, $this->ttl);
- }
- else if ($this->type == 'apc') {
- if (apc_exists($key))
- apc_delete($key);
- $result = apc_store($key, $data, $this->ttl);
- }
-
- // Update index
- if ($index && $result) {
- $this->load_index();
-
- if (array_search($key, $this->index) === false) {
- $this->index[] = $key;
- $data = serialize($this->index);
- $this->add_record($this->ikey(), $data);
- }
- }
-
- return $result;
- }
-
-
- /**
- * Deletes entry from memcache/apc DB.
- */
- private function delete_record($key, $index=true)
- {
- if ($this->type == 'memcache') {
- // #1488592: use 2nd argument
- $this->db->delete($this->ckey($key), 0);
- }
- else {
- apc_delete($this->ckey($key));
- }
-
- if ($index) {
- if (($idx = array_search($key, $this->index)) !== false) {
- unset($this->index[$idx]);
- }
- }
- }
-
-
- /**
- * Writes the index entry into memcache/apc DB.
- */
- private function write_index()
- {
- if (!$this->db) {
- return;
- }
-
- if ($this->type == 'db') {
- return;
- }
-
- $this->load_index();
-
- // Make sure index contains new keys
- foreach ($this->cache as $key => $value) {
- if ($value !== null) {
- if (array_search($key, $this->index) === false) {
- $this->index[] = $key;
- }
- }
- }
-
- $data = serialize($this->index);
- $this->add_record($this->ikey(), $data);
- }
-
-
- /**
- * Gets the index entry from memcache/apc DB.
- */
- private function load_index()
- {
- if (!$this->db) {
- return;
- }
-
- if ($this->index !== null) {
- return;
- }
-
- $index_key = $this->ikey();
- if ($this->type == 'memcache') {
- $data = $this->db->get($index_key);
- }
- else if ($this->type == 'apc') {
- $data = apc_fetch($index_key);
- }
-
- $this->index = $data ? unserialize($data) : array();
- }
-
-
- /**
- * Creates per-user cache key name (for memcache and apc)
- *
- * @param string $key Cache key name
- *
- * @return string Cache key
- */
- private function ckey($key)
- {
- return sprintf('%d:%s:%s', $this->userid, $this->prefix, $key);
- }
-
-
- /**
- * Creates per-user index cache key name (for memcache and apc)
- *
- * @return string Cache key
- */
- private function ikey()
- {
- // This way each cache will have its own index
- return sprintf('%d:%s%s', $this->userid, $this->prefix, 'INDEX');
- }
-
- /**
- * Serializes data for storing
- */
- private function serialize($data)
- {
- if ($this->type == 'db') {
- return $this->db->encode($data, $this->packed);
- }
-
- return $this->packed ? serialize($data) : $data;
- }
-
- /**
- * Unserializes serialized data
- */
- private function unserialize($data)
- {
- if ($this->type == 'db') {
- return $this->db->decode($data, $this->packed);
- }
-
- return $this->packed ? @unserialize($data) : $data;
- }
-
- /**
- * Determine the maximum size for cache data to be written
- */
- private function max_packet_size()
- {
- if ($this->max_packet < 0) {
- $this->max_packet = 2097152; // default/max is 2 MB
-
- if ($this->type == 'db') {
- $value = $this->db->get_variable('max_allowed_packet', 1048500);
- $this->max_packet = min($value, $this->max_packet) - 2000;
- }
- else if ($this->type == 'memcache') {
- if ($stats = $this->db->getStats()) {
- $remaining = $stats['limit_maxbytes'] - $stats['bytes'];
- $this->max_packet = min($remaining / 5, $this->max_packet);
- }
- }
- else if ($this->type == 'apc' && function_exists('apc_sma_info')) {
- if ($stats = apc_sma_info()) {
- $this->max_packet = min($stats['avail_mem'] / 5, $this->max_packet);
- }
- }
- }
-
- return $this->max_packet;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_cache_shared.php b/lib/ext/Roundcube/rcube_cache_shared.php
deleted file mode 100644
index 3c7c94f..0000000
--- a/lib/ext/Roundcube/rcube_cache_shared.php
+++ /dev/null
@@ -1,586 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2011-2013, The Roundcube Dev Team |
- | Copyright (C) 2011-2013, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Shared (cross-user) caching engine |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-
-/**
- * Interface class for accessing Roundcube shared cache
- *
- * @package Framework
- * @subpackage Cache
- * @author Thomas Bruederli <roundcube@gmail.com>
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_cache_shared
-{
- /**
- * Instance of database handler
- *
- * @var rcube_db|Memcache|bool
- */
- private $db;
- private $type;
- private $prefix;
- private $ttl;
- private $packed;
- private $index;
- private $table;
- private $cache = array();
- private $cache_changes = array();
- private $cache_sums = array();
-
-
- /**
- * Object constructor.
- *
- * @param string $type Engine type ('db' or 'memcache' or 'apc')
- * @param string $prefix Key name prefix
- * @param string $ttl Expiration time of memcache/apc items
- * @param bool $packed Enables/disabled data serialization.
- * It's possible to disable data serialization if you're sure
- * stored data will be always a safe string
- */
- function __construct($type, $prefix='', $ttl=0, $packed=true)
- {
- $rcube = rcube::get_instance();
- $type = strtolower($type);
-
- if ($type == 'memcache') {
- $this->type = 'memcache';
- $this->db = $rcube->get_memcache();
- }
- else if ($type == 'apc') {
- $this->type = 'apc';
- $this->db = function_exists('apc_exists'); // APC 3.1.4 required
- }
- else {
- $this->type = 'db';
- $this->db = $rcube->get_dbh();
- $this->table = $this->db->table_name('cache_shared', true);
- }
-
- // convert ttl string to seconds
- $ttl = get_offset_sec($ttl);
- if ($ttl > 2592000) $ttl = 2592000;
-
- $this->ttl = $ttl;
- $this->packed = $packed;
- $this->prefix = $prefix;
- }
-
-
- /**
- * Returns cached value.
- *
- * @param string $key Cache key name
- *
- * @return mixed Cached value
- */
- function get($key)
- {
- if (!array_key_exists($key, $this->cache)) {
- return $this->read_record($key);
- }
-
- return $this->cache[$key];
- }
-
-
- /**
- * Sets (add/update) value in cache.
- *
- * @param string $key Cache key name
- * @param mixed $data Cache data
- */
- function set($key, $data)
- {
- $this->cache[$key] = $data;
- $this->cache_changed = true;
- $this->cache_changes[$key] = true;
- }
-
-
- /**
- * Returns cached value without storing it in internal memory.
- *
- * @param string $key Cache key name
- *
- * @return mixed Cached value
- */
- function read($key)
- {
- if (array_key_exists($key, $this->cache)) {
- return $this->cache[$key];
- }
-
- return $this->read_record($key, true);
- }
-
-
- /**
- * Sets (add/update) value in cache and immediately saves
- * it in the backend, no internal memory will be used.
- *
- * @param string $key Cache key name
- * @param mixed $data Cache data
- *
- * @param boolean True on success, False on failure
- */
- function write($key, $data)
- {
- return $this->write_record($key, $this->serialize($data));
- }
-
-
- /**
- * Clears the cache.
- *
- * @param string $key Cache key name or pattern
- * @param boolean $prefix_mode Enable it to clear all keys starting
- * with prefix specified in $key
- */
- function remove($key=null, $prefix_mode=false)
- {
- // Remove all keys
- if ($key === null) {
- $this->cache = array();
- $this->cache_changed = false;
- $this->cache_changes = array();
- $this->cache_sums = array();
- }
- // Remove keys by name prefix
- else if ($prefix_mode) {
- foreach (array_keys($this->cache) as $k) {
- if (strpos($k, $key) === 0) {
- $this->cache[$k] = null;
- $this->cache_changes[$k] = false;
- unset($this->cache_sums[$k]);
- }
- }
- }
- // Remove one key by name
- else {
- $this->cache[$key] = null;
- $this->cache_changes[$key] = false;
- unset($this->cache_sums[$key]);
- }
-
- // Remove record(s) from the backend
- $this->remove_record($key, $prefix_mode);
- }
-
-
- /**
- * Remove cache records older than ttl
- */
- function expunge()
- {
- if ($this->type == 'db' && $this->db && $this->ttl) {
- $this->db->query(
- "DELETE FROM {$this->table}"
- . " WHERE `cache_key` LIKE ?"
- . " AND `expires` < " . $this->db->now(),
- $this->prefix . '.%');
- }
- }
-
-
- /**
- * Remove expired records of all caches
- */
- static function gc()
- {
- $rcube = rcube::get_instance();
- $db = $rcube->get_dbh();
-
- $db->query("DELETE FROM " . $db->table_name('cache_shared', true) . " WHERE `expires` < " . $db->now());
- }
-
-
- /**
- * Writes the cache back to the DB.
- */
- function close()
- {
- if (!$this->cache_changed) {
- return;
- }
-
- foreach ($this->cache as $key => $data) {
- // The key has been used
- if ($this->cache_changes[$key]) {
- // Make sure we're not going to write unchanged data
- // by comparing current md5 sum with the sum calculated on DB read
- $data = $this->serialize($data);
-
- if (!$this->cache_sums[$key] || $this->cache_sums[$key] != md5($data)) {
- $this->write_record($key, $data);
- }
- }
- }
-
- $this->write_index();
-
- $this->index = null;
- $this->cache = array();
- $this->cache_sums = array();
- $this->cache_changes = array();
- }
-
-
- /**
- * Reads cache entry.
- *
- * @param string $key Cache key name
- * @param boolean $nostore Enable to skip in-memory store
- *
- * @return mixed Cached value
- */
- private function read_record($key, $nostore=false)
- {
- if (!$this->db) {
- return null;
- }
-
- 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->unserialize($data);
-
- if ($nostore) {
- return $data;
- }
-
- $this->cache_sums[$key] = $md5sum;
- $this->cache[$key] = $data;
- }
- else {
- $this->cache[$key] = null;
- }
- }
- else {
- $sql_result = $this->db->limitquery(
- "SELECT `data`, `cache_key`".
- " FROM {$this->table}" .
- " WHERE `cache_key` = ?".
- // for better performance we allow more records for one key
- // get the newer one
- " ORDER BY `created` DESC",
- 0, 1, $this->prefix . '.' . $key);
-
- if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
- $md5sum = $sql_arr['data'] ? md5($sql_arr['data']) : null;
- if ($sql_arr['data']) {
- $data = $this->unserialize($sql_arr['data']);
- }
-
- if ($nostore) {
- return $data;
- }
-
- $this->cache[$key] = $data;
- $this->cache_sums[$key] = $md5sum;
- }
- else {
- $this->cache[$key] = null;
- }
- }
-
- return $this->cache[$key];
- }
-
-
- /**
- * Writes single cache record into DB.
- *
- * @param string $key Cache key name
- * @param mxied $data Serialized cache data
- *
- * @param boolean True on success, False on failure
- */
- private function write_record($key, $data)
- {
- if (!$this->db) {
- return false;
- }
-
- if ($this->type == 'memcache' || $this->type == 'apc') {
- return $this->add_record($this->ckey($key), $data);
- }
-
- $key_exists = array_key_exists($key, $this->cache_sums);
- $key = $this->prefix . '.' . $key;
-
- // Remove NULL rows (here we don't need to check if the record exist)
- if ($data == 'N;') {
- $this->db->query("DELETE FROM {$this->table} WHERE `cache_key` = ?", $key);
- return true;
- }
-
- // update existing cache record
- if ($key_exists) {
- $result = $this->db->query(
- "UPDATE {$this->table}" .
- " SET `created` = " . $this->db->now() .
- ", `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') .
- ", `data` = ?".
- " WHERE `cache_key` = ?",
- $data, $key);
- }
- // add new cache record
- else {
- // for better performance we allow more records for one key
- // so, no need to check if record exist (see rcube_cache::read_record())
- $result = $this->db->query(
- "INSERT INTO {$this->table}".
- " (`created`, `expires`, `cache_key`, `data`)".
- " VALUES (".$this->db->now().", " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?, ?)",
- $key, $data);
- }
-
- return $this->db->affected_rows($result);
- }
-
-
- /**
- * Deletes the cache record(s).
- *
- * @param string $key Cache key name or pattern
- * @param boolean $prefix_mode Enable it to clear all keys starting
- * with prefix specified in $key
- */
- private function remove_record($key=null, $prefix_mode=false)
- {
- if (!$this->db) {
- return;
- }
-
- if ($this->type != 'db') {
- $this->load_index();
-
- // Remove all keys
- if ($key === null) {
- foreach ($this->index as $key) {
- $this->delete_record($key, false);
- }
- $this->index = array();
- }
- // Remove keys by name prefix
- else if ($prefix_mode) {
- foreach ($this->index as $k) {
- if (strpos($k, $key) === 0) {
- $this->delete_record($k);
- }
- }
- }
- // Remove one key by name
- else {
- $this->delete_record($key);
- }
-
- return;
- }
-
- // Remove all keys (in specified cache)
- if ($key === null) {
- $where = " WHERE `cache_key` LIKE " . $this->db->quote($this->prefix.'.%');
- }
- // Remove keys by name prefix
- else if ($prefix_mode) {
- $where = " WHERE `cache_key` LIKE " . $this->db->quote($this->prefix.'.'.$key.'%');
- }
- // Remove one key by name
- else {
- $where = " WHERE `cache_key` = " . $this->db->quote($this->prefix.'.'.$key);
- }
-
- $this->db->query("DELETE FROM " . $this->table . $where);
- }
-
-
- /**
- * Adds entry into memcache/apc DB.
- *
- * @param string $key Cache key name
- * @param mxied $data Serialized cache data
- * @param bollean $index Enables immediate index update
- *
- * @param boolean True on success, False on failure
- */
- private function add_record($key, $data, $index=false)
- {
- if ($this->type == 'memcache') {
- $result = $this->db->replace($key, $data, MEMCACHE_COMPRESSED, $this->ttl);
- if (!$result) {
- $result = $this->db->set($key, $data, MEMCACHE_COMPRESSED, $this->ttl);
- }
- }
- else if ($this->type == 'apc') {
- if (apc_exists($key)) {
- apc_delete($key);
- }
- $result = apc_store($key, $data, $this->ttl);
- }
-
- // Update index
- if ($index && $result) {
- $this->load_index();
-
- if (array_search($key, $this->index) === false) {
- $this->index[] = $key;
- $data = serialize($this->index);
- $this->add_record($this->ikey(), $data);
- }
- }
-
- return $result;
- }
-
-
- /**
- * Deletes entry from memcache/apc DB.
- */
- private function delete_record($key, $index=true)
- {
- if ($this->type == 'memcache') {
- // #1488592: use 2nd argument
- $this->db->delete($this->ckey($key), 0);
- }
- else {
- apc_delete($this->ckey($key));
- }
-
- if ($index) {
- if (($idx = array_search($key, $this->index)) !== false) {
- unset($this->index[$idx]);
- }
- }
- }
-
-
- /**
- * Writes the index entry into memcache/apc DB.
- */
- private function write_index()
- {
- if (!$this->db) {
- return;
- }
-
- if ($this->type == 'db') {
- return;
- }
-
- $this->load_index();
-
- // Make sure index contains new keys
- foreach ($this->cache as $key => $value) {
- if ($value !== null) {
- if (array_search($key, $this->index) === false) {
- $this->index[] = $key;
- }
- }
- }
-
- $data = serialize($this->index);
- $this->add_record($this->ikey(), $data);
- }
-
-
- /**
- * Gets the index entry from memcache/apc DB.
- */
- private function load_index()
- {
- if (!$this->db) {
- return;
- }
-
- if ($this->index !== null) {
- return;
- }
-
- $index_key = $this->ikey();
-
- if ($this->type == 'memcache') {
- $data = $this->db->get($index_key);
- }
- else if ($this->type == 'apc') {
- $data = apc_fetch($index_key);
- }
-
- $this->index = $data ? unserialize($data) : array();
- }
-
-
- /**
- * Creates cache key name (for memcache and apc)
- *
- * @param string $key Cache key name
- *
- * @return string Cache key
- */
- private function ckey($key)
- {
- return $this->prefix . ':' . $key;
- }
-
-
- /**
- * Creates index cache key name (for memcache and apc)
- *
- * @return string Cache key
- */
- private function ikey()
- {
- // This way each cache will have its own index
- return $this->prefix . 'INDEX';
- }
-
- /**
- * Serializes data for storing
- */
- private function serialize($data)
- {
- if ($this->type == 'db') {
- return $this->db->encode($data, $this->packed);
- }
-
- return $this->packed ? serialize($data) : $data;
- }
-
- /**
- * Unserializes serialized data
- */
- private function unserialize($data)
- {
- if ($this->type == 'db') {
- return $this->db->decode($data, $this->packed);
- }
-
- return $this->packed ? @unserialize($data) : $data;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_charset.php b/lib/ext/Roundcube/rcube_charset.php
deleted file mode 100644
index d6ca3c0..0000000
--- a/lib/ext/Roundcube/rcube_charset.php
+++ /dev/null
@@ -1,810 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | Copyright (C) 2011-2012, Kolab Systems AG |
- | Copyright (C) 2000 Edmund Grimley Evans <edmundo@rano.org> |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Provide charset conversion functionality |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Character sets conversion functionality
- *
- * @package Framework
- * @subpackage Core
- * @author Thomas Bruederli <roundcube@gmail.com>
- * @author Aleksander Machniak <alec@alec.pl>
- * @author Edmund Grimley Evans <edmundo@rano.org>
- */
-class rcube_charset
-{
- // Aliases: some of them from HTML5 spec.
- static public $aliases = array(
- 'USASCII' => 'WINDOWS-1252',
- 'ANSIX31101983' => 'WINDOWS-1252',
- 'ANSIX341968' => 'WINDOWS-1252',
- 'UNKNOWN8BIT' => 'ISO-8859-15',
- 'UNKNOWN' => 'ISO-8859-15',
- 'USERDEFINED' => 'ISO-8859-15',
- 'KSC56011987' => 'EUC-KR',
- 'GB2312' => 'GBK',
- 'GB231280' => 'GBK',
- 'UNICODE' => 'UTF-8',
- 'UTF7IMAP' => 'UTF7-IMAP',
- 'TIS620' => 'WINDOWS-874',
- 'ISO88599' => 'WINDOWS-1254',
- 'ISO885911' => 'WINDOWS-874',
- 'MACROMAN' => 'MACINTOSH',
- '77' => 'MAC',
- '128' => 'SHIFT-JIS',
- '129' => 'CP949',
- '130' => 'CP1361',
- '134' => 'GBK',
- '136' => 'BIG5',
- '161' => 'WINDOWS-1253',
- '162' => 'WINDOWS-1254',
- '163' => 'WINDOWS-1258',
- '177' => 'WINDOWS-1255',
- '178' => 'WINDOWS-1256',
- '186' => 'WINDOWS-1257',
- '204' => 'WINDOWS-1251',
- '222' => 'WINDOWS-874',
- '238' => 'WINDOWS-1250',
- 'MS950' => 'CP950',
- 'WINDOWS949' => 'UHC',
- );
-
-
- /**
- * Catch an error and throw an exception.
- *
- * @param int Level of the error
- * @param string Error message
- */
- public static function error_handler($errno, $errstr)
- {
- throw new ErrorException($errstr, 0, $errno);
- }
-
-
- /**
- * Parse and validate charset name string (see #1485758).
- * Sometimes charset string is malformed, there are also charset aliases
- * but we need strict names for charset conversion (specially utf8 class)
- *
- * @param string $input Input charset name
- *
- * @return string The validated charset name
- */
- public static function parse_charset($input)
- {
- static $charsets = array();
- $charset = strtoupper($input);
-
- if (isset($charsets[$input])) {
- return $charsets[$input];
- }
-
- $charset = preg_replace(array(
- '/^[^0-9A-Z]+/', // e.g. _ISO-8859-JP$SIO
- '/\$.*$/', // e.g. _ISO-8859-JP$SIO
- '/UNICODE-1-1-*/', // RFC1641/1642
- '/^X-/', // X- prefix (e.g. X-ROMAN8 => ROMAN8)
- ), '', $charset);
-
- if ($charset == 'BINARY') {
- return $charsets[$input] = null;
- }
-
- // allow A-Z and 0-9 only
- $str = preg_replace('/[^A-Z0-9]/', '', $charset);
-
- if (isset(self::$aliases[$str])) {
- $result = self::$aliases[$str];
- }
- // UTF
- else if (preg_match('/U[A-Z][A-Z](7|8|16|32)(BE|LE)*/', $str, $m)) {
- $result = 'UTF-' . $m[1] . $m[2];
- }
- // ISO-8859
- else if (preg_match('/ISO8859([0-9]{0,2})/', $str, $m)) {
- $iso = 'ISO-8859-' . ($m[1] ? $m[1] : 1);
- // some clients sends windows-1252 text as latin1,
- // it is safe to use windows-1252 for all latin1
- $result = $iso == 'ISO-8859-1' ? 'WINDOWS-1252' : $iso;
- }
- // handle broken charset names e.g. WINDOWS-1250HTTP-EQUIVCONTENT-TYPE
- else if (preg_match('/(WIN|WINDOWS)([0-9]+)/', $str, $m)) {
- $result = 'WINDOWS-' . $m[2];
- }
- // LATIN
- else if (preg_match('/LATIN(.*)/', $str, $m)) {
- $aliases = array('2' => 2, '3' => 3, '4' => 4, '5' => 9, '6' => 10,
- '7' => 13, '8' => 14, '9' => 15, '10' => 16,
- 'ARABIC' => 6, 'CYRILLIC' => 5, 'GREEK' => 7, 'GREEK1' => 7, 'HEBREW' => 8
- );
-
- // some clients sends windows-1252 text as latin1,
- // it is safe to use windows-1252 for all latin1
- if ($m[1] == 1) {
- $result = 'WINDOWS-1252';
- }
- // if iconv is not supported we need ISO labels, it's also safe for iconv
- else if (!empty($aliases[$m[1]])) {
- $result = 'ISO-8859-'.$aliases[$m[1]];
- }
- // iconv requires convertion of e.g. LATIN-1 to LATIN1
- else {
- $result = $str;
- }
- }
- else {
- $result = $charset;
- }
-
- $charsets[$input] = $result;
-
- return $result;
- }
-
-
- /**
- * Convert a string from one charset to another.
- * Uses mbstring and iconv functions if possible
- *
- * @param string Input string
- * @param string Suspected charset of the input string
- * @param string Target charset to convert to; defaults to RCUBE_CHARSET
- *
- * @return string Converted string
- */
- public static function convert($str, $from, $to = null)
- {
- static $iconv_options = null;
- static $mbstring_list = null;
- static $mbstring_sch = null;
- static $conv = null;
-
- $to = empty($to) ? RCUBE_CHARSET : $to;
- $from = self::parse_charset($from);
-
- // It is a common case when UTF-16 charset is used with US-ASCII content (#1488654)
- // In that case we can just skip the conversion (use UTF-8)
- if ($from == 'UTF-16' && !preg_match('/[^\x00-\x7F]/', $str)) {
- $from = 'UTF-8';
- }
-
- if ($from == $to || empty($str) || empty($from)) {
- return $str;
- }
-
- if ($iconv_options === null) {
- if (function_exists('iconv')) {
- // ignore characters not available in output charset
- $iconv_options = '//IGNORE';
- if (iconv('', $iconv_options, '') === false) {
- // iconv implementation does not support options
- $iconv_options = '';
- }
- }
- else {
- $iconv_options = false;
- }
- }
-
- // convert charset using iconv module
- if ($iconv_options !== false && $from != 'UTF7-IMAP' && $to != 'UTF7-IMAP') {
- // throw an exception if iconv reports an illegal character in input
- // it means that input string has been truncated
- set_error_handler(array('rcube_charset', 'error_handler'), E_NOTICE);
- try {
- $_iconv = iconv($from, $to . $iconv_options, $str);
- } catch (ErrorException $e) {
- $_iconv = false;
- }
- restore_error_handler();
-
- if ($_iconv !== false) {
- return $_iconv;
- }
- }
-
- if ($mbstring_list === null) {
- if (extension_loaded('mbstring')) {
- $mbstring_sch = mb_substitute_character();
- $mbstring_list = mb_list_encodings();
- $mbstring_list = array_map('strtoupper', $mbstring_list);
- }
- else {
- $mbstring_list = false;
- }
- }
-
- // convert charset using mbstring module
- if ($mbstring_list !== false) {
- $aliases['WINDOWS-1257'] = 'ISO-8859-13';
- // it happens that mbstring supports ASCII but not US-ASCII
- if (($from == 'US-ASCII' || $to == 'US-ASCII') && !in_array('US-ASCII', $mbstring_list)) {
- $aliases['US-ASCII'] = 'ASCII';
- }
-
- $mb_from = $aliases[$from] ? $aliases[$from] : $from;
- $mb_to = $aliases[$to] ? $aliases[$to] : $to;
-
- // return if encoding found, string matches encoding and convert succeeded
- if (in_array($mb_from, $mbstring_list) && in_array($mb_to, $mbstring_list)) {
- if (mb_check_encoding($str, $mb_from)) {
- // Do the same as //IGNORE with iconv
- mb_substitute_character('none');
- $out = mb_convert_encoding($str, $mb_to, $mb_from);
- mb_substitute_character($mbstring_sch);
-
- if ($out !== false) {
- return $out;
- }
- }
- }
- }
-
- // convert charset using bundled classes/functions
- if ($to == 'UTF-8') {
- if ($from == 'UTF7-IMAP') {
- if ($_str = self::utf7imap_to_utf8($str)) {
- return $_str;
- }
- }
- else if ($from == 'UTF-7') {
- if ($_str = self::utf7_to_utf8($str)) {
- return $_str;
- }
- }
- else if ($from == 'ISO-8859-1' && function_exists('utf8_encode')) {
- return utf8_encode($str);
- }
- else {
- user_error("No suitable function found for UTF-8 encoding", E_USER_WARNING);
- }
- }
-
- // encode string for output
- if ($from == 'UTF-8') {
- // @TODO: we need a function for UTF-7 (RFC2152) conversion
- if ($to == 'UTF7-IMAP' || $to == 'UTF-7') {
- if ($_str = self::utf8_to_utf7imap($str)) {
- return $_str;
- }
- }
- else if ($to == 'ISO-8859-1' && function_exists('utf8_decode')) {
- return utf8_decode($str);
- }
- else {
- user_error("No suitable function found for UTF-8 decoding", E_USER_WARNING);
- }
- }
-
- // return original string
- return $str;
- }
-
-
- /**
- * Converts string from standard UTF-7 (RFC 2152) to UTF-8.
- *
- * @param string Input string (UTF-7)
- *
- * @return string Converted string (UTF-8)
- */
- public static function utf7_to_utf8($str)
- {
- $Index_64 = array(
- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0,
- 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,
- 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
- 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
- 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
- 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
- );
-
- $u7len = strlen($str);
- $str = strval($str);
- $res = '';
-
- for ($i=0; $u7len > 0; $i++, $u7len--) {
- $u7 = $str[$i];
- if ($u7 == '+') {
- $i++;
- $u7len--;
- $ch = '';
-
- for (; $u7len > 0; $i++, $u7len--) {
- $u7 = $str[$i];
-
- if (!$Index_64[ord($u7)]) {
- break;
- }
-
- $ch .= $u7;
- }
-
- if ($ch == '') {
- if ($u7 == '-') {
- $res .= '+';
- }
-
- continue;
- }
-
- $res .= self::utf16_to_utf8(base64_decode($ch));
- }
- else {
- $res .= $u7;
- }
- }
-
- return $res;
- }
-
-
- /**
- * Converts string from UTF-16 to UTF-8 (helper for utf-7 to utf-8 conversion)
- *
- * @param string Input string
- *
- * @return string The converted string
- */
- public static function utf16_to_utf8($str)
- {
- $len = strlen($str);
- $dec = '';
-
- for ($i = 0; $i < $len; $i += 2) {
- $c = ord($str[$i]) << 8 | ord($str[$i + 1]);
- if ($c >= 0x0001 && $c <= 0x007F) {
- $dec .= chr($c);
- }
- else if ($c > 0x07FF) {
- $dec .= chr(0xE0 | (($c >> 12) & 0x0F));
- $dec .= chr(0x80 | (($c >> 6) & 0x3F));
- $dec .= chr(0x80 | (($c >> 0) & 0x3F));
- }
- else {
- $dec .= chr(0xC0 | (($c >> 6) & 0x1F));
- $dec .= chr(0x80 | (($c >> 0) & 0x3F));
- }
- }
-
- return $dec;
- }
-
-
- /**
- * Convert the data ($str) from RFC 2060's UTF-7 to UTF-8.
- * If input data is invalid, return the original input string.
- * RFC 2060 obviously intends the encoding to be unique (see
- * point 5 in section 5.1.3), so we reject any non-canonical
- * form, such as &ACY- (instead of &-) or &AMA-&AMA- (instead
- * of &AMAAwA-).
- *
- * Translated from C to PHP by Thomas Bruederli <roundcube@gmail.com>
- *
- * @param string $str Input string (UTF7-IMAP)
- *
- * @return string Output string (UTF-8)
- */
- public static function utf7imap_to_utf8($str)
- {
- $Index_64 = array(
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, 63,-1,-1,-1,
- 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
- 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
- -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
- 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
- );
-
- $u7len = strlen($str);
- $str = strval($str);
- $p = '';
- $err = '';
-
- for ($i=0; $u7len > 0; $i++, $u7len--) {
- $u7 = $str[$i];
- if ($u7 == '&') {
- $i++;
- $u7len--;
- $u7 = $str[$i];
-
- if ($u7len && $u7 == '-') {
- $p .= '&';
- continue;
- }
-
- $ch = 0;
- $k = 10;
- for (; $u7len > 0; $i++, $u7len--) {
- $u7 = $str[$i];
-
- if ((ord($u7) & 0x80) || ($b = $Index_64[ord($u7)]) == -1) {
- break;
- }
-
- if ($k > 0) {
- $ch |= $b << $k;
- $k -= 6;
- }
- else {
- $ch |= $b >> (-$k);
- if ($ch < 0x80) {
- // Printable US-ASCII
- if (0x20 <= $ch && $ch < 0x7f) {
- return $err;
- }
- $p .= chr($ch);
- }
- else if ($ch < 0x800) {
- $p .= chr(0xc0 | ($ch >> 6));
- $p .= chr(0x80 | ($ch & 0x3f));
- }
- else {
- $p .= chr(0xe0 | ($ch >> 12));
- $p .= chr(0x80 | (($ch >> 6) & 0x3f));
- $p .= chr(0x80 | ($ch & 0x3f));
- }
-
- $ch = ($b << (16 + $k)) & 0xffff;
- $k += 10;
- }
- }
-
- // Non-zero or too many extra bits
- if ($ch || $k < 6) {
- return $err;
- }
-
- // BASE64 not properly terminated
- if (!$u7len || $u7 != '-') {
- return $err;
- }
-
- // Adjacent BASE64 sections
- if ($u7len > 2 && $str[$i+1] == '&' && $str[$i+2] != '-') {
- return $err;
- }
- }
- // Not printable US-ASCII
- else if (ord($u7) < 0x20 || ord($u7) >= 0x7f) {
- return $err;
- }
- else {
- $p .= $u7;
- }
- }
-
- return $p;
- }
-
-
- /**
- * Convert the data ($str) from UTF-8 to RFC 2060's UTF-7.
- * Unicode characters above U+FFFF are replaced by U+FFFE.
- * If input data is invalid, return an empty string.
- *
- * Translated from C to PHP by Thomas Bruederli <roundcube@gmail.com>
- *
- * @param string $str Input string (UTF-8)
- *
- * @return string Output string (UTF7-IMAP)
- */
- public static function utf8_to_utf7imap($str)
- {
- $B64Chars = array(
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
- 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
- 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', '+', ','
- );
-
- $u8len = strlen($str);
- $base64 = 0;
- $i = 0;
- $p = '';
- $err = '';
-
- while ($u8len) {
- $u8 = $str[$i];
- $c = ord($u8);
-
- if ($c < 0x80) {
- $ch = $c;
- $n = 0;
- }
- else if ($c < 0xc2) {
- return $err;
- }
- else if ($c < 0xe0) {
- $ch = $c & 0x1f;
- $n = 1;
- }
- else if ($c < 0xf0) {
- $ch = $c & 0x0f;
- $n = 2;
- }
- else if ($c < 0xf8) {
- $ch = $c & 0x07;
- $n = 3;
- }
- else if ($c < 0xfc) {
- $ch = $c & 0x03;
- $n = 4;
- }
- else if ($c < 0xfe) {
- $ch = $c & 0x01;
- $n = 5;
- }
- else {
- return $err;
- }
-
- $i++;
- $u8len--;
-
- if ($n > $u8len) {
- return $err;
- }
-
- for ($j=0; $j < $n; $j++) {
- $o = ord($str[$i+$j]);
- if (($o & 0xc0) != 0x80) {
- return $err;
- }
- $ch = ($ch << 6) | ($o & 0x3f);
- }
-
- if ($n > 1 && !($ch >> ($n * 5 + 1))) {
- return $err;
- }
-
- $i += $n;
- $u8len -= $n;
-
- if ($ch < 0x20 || $ch >= 0x7f) {
- if (!$base64) {
- $p .= '&';
- $base64 = 1;
- $b = 0;
- $k = 10;
- }
- if ($ch & ~0xffff) {
- $ch = 0xfffe;
- }
-
- $p .= $B64Chars[($b | $ch >> $k)];
- $k -= 6;
- for (; $k >= 0; $k -= 6) {
- $p .= $B64Chars[(($ch >> $k) & 0x3f)];
- }
-
- $b = ($ch << (-$k)) & 0x3f;
- $k += 16;
- }
- else {
- if ($base64) {
- if ($k > 10) {
- $p .= $B64Chars[$b];
- }
- $p .= '-';
- $base64 = 0;
- }
-
- $p .= chr($ch);
- if (chr($ch) == '&') {
- $p .= '-';
- }
- }
- }
-
- if ($base64) {
- if ($k > 10) {
- $p .= $B64Chars[$b];
- }
- $p .= '-';
- }
-
- return $p;
- }
-
-
- /**
- * A method to guess character set of a string.
- *
- * @param string $string String
- * @param string $failover Default result for failover
- * @param string $language User language
- *
- * @return string Charset name
- */
- public static function detect($string, $failover = null, $language = null)
- {
- if (substr($string, 0, 4) == "\0\0\xFE\xFF") return 'UTF-32BE'; // Big Endian
- if (substr($string, 0, 4) == "\xFF\xFE\0\0") return 'UTF-32LE'; // Little Endian
- if (substr($string, 0, 2) == "\xFE\xFF") return 'UTF-16BE'; // Big Endian
- if (substr($string, 0, 2) == "\xFF\xFE") return 'UTF-16LE'; // Little Endian
- if (substr($string, 0, 3) == "\xEF\xBB\xBF") return 'UTF-8';
-
- // heuristics
- if ($string[0] == "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-32BE';
- if ($string[0] != "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] == "\0") return 'UTF-32LE';
- if ($string[0] == "\0" && $string[1] != "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-16BE';
- if ($string[0] != "\0" && $string[1] == "\0" && $string[2] != "\0" && $string[3] == "\0") return 'UTF-16LE';
-
- if (function_exists('mb_detect_encoding')) {
- if (empty($language)) {
- $rcube = rcube::get_instance();
- $language = $rcube->get_user_language();
- }
-
- // Prioritize charsets according to current language (#1485669)
- switch ($language) {
- case 'ja_JP':
- $prio = array('ISO-2022-JP', 'JIS', 'UTF-8', 'EUC-JP', 'eucJP-win', 'SJIS', 'SJIS-win');
- break;
-
- case 'zh_CN':
- case 'zh_TW':
- $prio = array('UTF-8', 'BIG-5', 'GB2312', 'EUC-TW');
- break;
-
- case 'ko_KR':
- $prio = array('UTF-8', 'EUC-KR', 'ISO-2022-KR');
- break;
-
- case 'ru_RU':
- $prio = array('UTF-8', 'WINDOWS-1251', 'KOI8-R');
- break;
-
- case 'tr_TR':
- $prio = array('UTF-8', 'ISO-8859-9', 'WINDOWS-1254');
- break;
-
- default:
- $prio = array('UTF-8', 'SJIS', 'GB2312',
- 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4',
- 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9',
- 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16',
- 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', 'BIG-5',
- 'ISO-2022-KR', 'ISO-2022-JP',
- );
- }
-
- $encodings = array_unique(array_merge($prio, mb_list_encodings()));
-
- return mb_detect_encoding($string, $encodings);
- }
-
- // No match, check for UTF-8
- // from http://w3.org/International/questions/qa-forms-utf-8.html
- if (preg_match('/\A(
- [\x09\x0A\x0D\x20-\x7E]
- | [\xC2-\xDF][\x80-\xBF]
- | \xE0[\xA0-\xBF][\x80-\xBF]
- | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}
- | \xED[\x80-\x9F][\x80-\xBF]
- | \xF0[\x90-\xBF][\x80-\xBF]{2}
- | [\xF1-\xF3][\x80-\xBF]{3}
- | \xF4[\x80-\x8F][\x80-\xBF]{2}
- )*\z/xs', substr($string, 0, 2048))
- ) {
- return 'UTF-8';
- }
-
- return $failover;
- }
-
-
- /**
- * Removes non-unicode characters from input.
- *
- * @param mixed $input String or array.
- *
- * @return mixed String or array
- */
- public static function clean($input)
- {
- // handle input of type array
- if (is_array($input)) {
- foreach ($input as $idx => $val) {
- $input[$idx] = self::clean($val);
- }
- return $input;
- }
-
- if (!is_string($input) || $input == '') {
- return $input;
- }
-
- // iconv/mbstring are much faster (especially with long strings)
- if (function_exists('mb_convert_encoding')) {
- $msch = mb_substitute_character('none');
- mb_substitute_character('none');
- $res = mb_convert_encoding($input, 'UTF-8', 'UTF-8');
- mb_substitute_character($msch);
-
- if ($res !== false) {
- return $res;
- }
- }
-
- if (function_exists('iconv')) {
- if (($res = @iconv('UTF-8', 'UTF-8//IGNORE', $input)) !== false) {
- return $res;
- }
- }
-
- $seq = '';
- $out = '';
- $regexp = '/^('.
-// '[\x00-\x7F]'. // UTF8-1
- '|[\xC2-\xDF][\x80-\xBF]'. // UTF8-2
- '|\xE0[\xA0-\xBF][\x80-\xBF]'. // UTF8-3
- '|[\xE1-\xEC][\x80-\xBF][\x80-\xBF]'. // UTF8-3
- '|\xED[\x80-\x9F][\x80-\xBF]'. // UTF8-3
- '|[\xEE-\xEF][\x80-\xBF][\x80-\xBF]'. // UTF8-3
- '|\xF0[\x90-\xBF][\x80-\xBF][\x80-\xBF]'. // UTF8-4
- '|[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]'.// UTF8-4
- '|\xF4[\x80-\x8F][\x80-\xBF][\x80-\xBF]'. // UTF8-4
- ')$/';
-
- for ($i = 0, $len = strlen($input); $i < $len; $i++) {
- $chr = $input[$i];
- $ord = ord($chr);
-
- // 1-byte character
- if ($ord <= 0x7F) {
- if ($seq) {
- $out .= preg_match($regexp, $seq) ? $seq : '';
- }
- $seq = '';
- $out .= $chr;
- }
- // first (or second) byte of multibyte sequence
- else if ($ord >= 0xC0) {
- if (strlen($seq) > 1) {
- $out .= preg_match($regexp, $seq) ? $seq : '';
- $seq = '';
- }
- else if ($seq && ord($seq) < 0xC0) {
- $seq = '';
- }
- $seq .= $chr;
- }
- // next byte of multibyte sequence
- else if ($seq) {
- $seq .= $chr;
- }
- }
-
- if ($seq) {
- $out .= preg_match($regexp, $seq) ? $seq : '';
- }
-
- return $out;
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_config.php b/lib/ext/Roundcube/rcube_config.php
deleted file mode 100644
index afe13e8..0000000
--- a/lib/ext/Roundcube/rcube_config.php
+++ /dev/null
@@ -1,608 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Class to read configuration settings |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Configuration class for Roundcube
- *
- * @package Framework
- * @subpackage Core
- */
-class rcube_config
-{
- const DEFAULT_SKIN = 'larry';
-
- private $env = '';
- private $paths = array();
- private $prop = array();
- private $errors = array();
- private $userprefs = array();
-
- /**
- * Renamed options
- *
- * @var array
- */
- private $legacy_props = array(
- // new name => old name
- 'default_folders' => 'default_imap_folders',
- 'mail_pagesize' => 'pagesize',
- 'addressbook_pagesize' => 'pagesize',
- 'reply_mode' => 'top_posting',
- 'refresh_interval' => 'keep_alive',
- 'min_refresh_interval' => 'min_keep_alive',
- 'messages_cache_ttl' => 'message_cache_lifetime',
- 'redundant_attachments_cache_ttl' => 'redundant_attachments_memcache_ttl',
- );
-
-
- /**
- * Object constructor
- *
- * @param string Environment suffix for config files to load
- */
- public function __construct($env = '')
- {
- $this->env = $env;
-
- if ($paths = getenv('RCUBE_CONFIG_PATH')) {
- $this->paths = explode(PATH_SEPARATOR, $paths);
- // make all paths absolute
- foreach ($this->paths as $i => $path) {
- if (!rcube_utils::is_absolute_path($path)) {
- if ($realpath = realpath(RCUBE_INSTALL_PATH . $path)) {
- $this->paths[$i] = unslashify($realpath) . '/';
- }
- else {
- unset($this->paths[$i]);
- }
- }
- else {
- $this->paths[$i] = unslashify($path) . '/';
- }
- }
- }
-
- if (defined('RCUBE_CONFIG_DIR') && !in_array(RCUBE_CONFIG_DIR, $this->paths)) {
- $this->paths[] = RCUBE_CONFIG_DIR;
- }
-
- if (empty($this->paths)) {
- $this->paths[] = RCUBE_INSTALL_PATH . 'config/';
- }
-
- $this->load();
-
- // Defaults, that we do not require you to configure,
- // but contain information that is used in various
- // locations in the code:
- $this->set('contactlist_fields', array('name', 'firstname', 'surname', 'email'));
- }
-
-
- /**
- * Load config from local config file
- *
- * @todo Remove global $CONFIG
- */
- private function load()
- {
- // Load default settings
- if (!$this->load_from_file('defaults.inc.php')) {
- $this->errors[] = 'defaults.inc.php was not found.';
- }
-
- // load main config file
- if (!$this->load_from_file('config.inc.php')) {
- // Old configuration files
- if (!$this->load_from_file('main.inc.php') ||
- !$this->load_from_file('db.inc.php')) {
- $this->errors[] = 'config.inc.php was not found.';
- }
- else if (rand(1,100) == 10) { // log warning on every 100th request (average)
- trigger_error("config.inc.php was not found. Please migrate your config by running bin/update.sh", E_USER_WARNING);
- }
- }
-
- // load host-specific configuration
- $this->load_host_config();
-
- // set skin (with fallback to old 'skin_path' property)
- if (empty($this->prop['skin'])) {
- if (!empty($this->prop['skin_path'])) {
- $this->prop['skin'] = str_replace('skins/', '', unslashify($this->prop['skin_path']));
- }
- else {
- $this->prop['skin'] = self::DEFAULT_SKIN;
- }
- }
-
- // larry is the new default skin :-)
- if ($this->prop['skin'] == 'default')
- $this->prop['skin'] = self::DEFAULT_SKIN;
-
- // fix paths
- $this->prop['log_dir'] = $this->prop['log_dir'] ? realpath(unslashify($this->prop['log_dir'])) : RCUBE_INSTALL_PATH . 'logs';
- $this->prop['temp_dir'] = $this->prop['temp_dir'] ? realpath(unslashify($this->prop['temp_dir'])) : RCUBE_INSTALL_PATH . 'temp';
-
- // fix default imap folders encoding
- foreach (array('drafts_mbox', 'junk_mbox', 'sent_mbox', 'trash_mbox') as $folder)
- $this->prop[$folder] = rcube_charset::convert($this->prop[$folder], RCUBE_CHARSET, 'UTF7-IMAP');
-
- if (!empty($this->prop['default_folders']))
- foreach ($this->prop['default_folders'] as $n => $folder)
- $this->prop['default_folders'][$n] = rcube_charset::convert($folder, RCUBE_CHARSET, 'UTF7-IMAP');
-
- // set PHP error logging according to config
- if ($this->prop['debug_level'] & 1) {
- ini_set('log_errors', 1);
-
- if ($this->prop['log_driver'] == 'syslog') {
- ini_set('error_log', 'syslog');
- }
- else {
- ini_set('error_log', $this->prop['log_dir'].'/errors');
- }
- }
-
- // enable display_errors in 'show' level, but not for ajax requests
- ini_set('display_errors', intval(empty($_REQUEST['_remote']) && ($this->prop['debug_level'] & 4)));
-
- // remove deprecated properties
- unset($this->prop['dst_active']);
-
- // export config data
- $GLOBALS['CONFIG'] = &$this->prop;
- }
-
- /**
- * Load a host-specific config file if configured
- * This will merge the host specific configuration with the given one
- */
- private function load_host_config()
- {
- if (empty($this->prop['include_host_config'])) {
- return;
- }
-
- foreach (array('HTTP_HOST', 'SERVER_NAME', 'SERVER_ADDR') as $key) {
- $fname = null;
- $name = $_SERVER[$key];
-
- if (!$name) {
- continue;
- }
-
- if (is_array($this->prop['include_host_config'])) {
- $fname = $this->prop['include_host_config'][$name];
- }
- else {
- $fname = preg_replace('/[^a-z0-9\.\-_]/i', '', $name) . '.inc.php';
- }
-
- if ($fname && $this->load_from_file($fname)) {
- return;
- }
- }
- }
-
- /**
- * Read configuration from a file
- * and merge with the already stored config values
- *
- * @param string $file Name of the config file to be loaded
- * @return booelan True on success, false on failure
- */
- public function load_from_file($file)
- {
- $success = false;
-
- foreach ($this->resolve_paths($file) as $fpath) {
- if ($fpath && is_file($fpath) && is_readable($fpath)) {
- // use output buffering, we don't need any output here
- ob_start();
- include($fpath);
- ob_end_clean();
-
- if (is_array($config)) {
- $this->merge($config);
- $success = true;
- }
- // deprecated name of config variable
- if (is_array($rcmail_config)) {
- $this->merge($rcmail_config);
- $success = true;
- }
- }
- }
-
- return $success;
- }
-
- /**
- * Helper method to resolve absolute paths to the given config file.
- * This also takes the 'env' property into account.
- *
- * @param string Filename or absolute file path
- * @param boolean Return -$env file path if exists
- * @return array List of candidates in config dir path(s)
- */
- public function resolve_paths($file, $use_env = true)
- {
- $files = array();
- $abs_path = rcube_utils::is_absolute_path($file);
-
- foreach ($this->paths as $basepath) {
- $realpath = $abs_path ? $file : realpath($basepath . '/' . $file);
-
- // check if <file>-env.ini exists
- if ($realpath && $use_env && !empty($this->env)) {
- $envfile = preg_replace('/\.(inc.php)$/', '-' . $this->env . '.\\1', $realpath);
- if (is_file($envfile))
- $realpath = $envfile;
- }
-
- if ($realpath) {
- $files[] = $realpath;
-
- // no need to continue the loop if an absolute file path is given
- if ($abs_path) {
- break;
- }
- }
- }
-
- return $files;
- }
-
- /**
- * Getter for a specific config parameter
- *
- * @param string $name Parameter name
- * @param mixed $def Default value if not set
- * @return mixed The requested config value
- */
- public function get($name, $def = null)
- {
- if (isset($this->prop[$name])) {
- $result = $this->prop[$name];
- }
- else {
- $result = $def;
- }
-
- $rcube = rcube::get_instance();
-
- if ($name == 'timezone') {
- if (empty($result) || $result == 'auto') {
- $result = $this->client_timezone();
- }
- }
- else if ($name == 'client_mimetypes') {
- if ($result == null && $def == null)
- $result = 'text/plain,text/html,text/xml,image/jpeg,image/gif,image/png,image/bmp,image/tiff,application/x-javascript,application/pdf,application/x-shockwave-flash';
- if ($result && is_string($result))
- $result = explode(',', $result);
- }
-
- $plugin = $rcube->plugins->exec_hook('config_get', array(
- 'name' => $name, 'default' => $def, 'result' => $result));
-
- return $plugin['result'];
- }
-
-
- /**
- * Setter for a config parameter
- *
- * @param string $name Parameter name
- * @param mixed $value Parameter value
- */
- public function set($name, $value)
- {
- $this->prop[$name] = $value;
- }
-
-
- /**
- * Override config options with the given values (eg. user prefs)
- *
- * @param array $prefs Hash array with config props to merge over
- */
- public function merge($prefs)
- {
- $prefs = $this->fix_legacy_props($prefs);
- $this->prop = array_merge($this->prop, $prefs, $this->userprefs);
- }
-
-
- /**
- * Merge the given prefs over the current config
- * and make sure that they survive further merging.
- *
- * @param array $prefs Hash array with user prefs
- */
- public function set_user_prefs($prefs)
- {
- $prefs = $this->fix_legacy_props($prefs);
-
- // Honor the dont_override setting for any existing user preferences
- $dont_override = $this->get('dont_override');
- if (is_array($dont_override) && !empty($dont_override)) {
- foreach ($dont_override as $key) {
- unset($prefs[$key]);
- }
- }
-
- // larry is the new default skin :-)
- if ($prefs['skin'] == 'default') {
- $prefs['skin'] = self::DEFAULT_SKIN;
- }
-
- $this->userprefs = $prefs;
- $this->prop = array_merge($this->prop, $prefs);
- }
-
-
- /**
- * Getter for all config options
- *
- * @return array Hash array containing all config properties
- */
- public function all()
- {
- $rcube = rcube::get_instance();
- $plugin = $rcube->plugins->exec_hook('config_get', array(
- 'name' => '*', 'result' => $this->prop));
-
- return $plugin['result'];
- }
-
- /**
- * Special getter for user's timezone offset including DST
- *
- * @return float Timezone offset (in hours)
- * @deprecated
- */
- public function get_timezone()
- {
- if ($tz = $this->get('timezone')) {
- try {
- $tz = new DateTimeZone($tz);
- return $tz->getOffset(new DateTime('now')) / 3600;
- }
- catch (Exception $e) {
- }
- }
-
- return 0;
- }
-
- /**
- * Return requested DES crypto key.
- *
- * @param string $key Crypto key name
- * @return string Crypto key
- */
- public function get_crypto_key($key)
- {
- // Bomb out if the requested key does not exist
- if (!array_key_exists($key, $this->prop)) {
- rcube::raise_error(array(
- 'code' => 500, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Request for unconfigured crypto key \"$key\""
- ), true, true);
- }
-
- $key = $this->prop[$key];
-
- // Bomb out if the configured key is not exactly 24 bytes long
- if (strlen($key) != 24) {
- rcube::raise_error(array(
- 'code' => 500, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Configured crypto key '$key' is not exactly 24 bytes long"
- ), true, true);
- }
-
- return $key;
- }
-
-
- /**
- * Try to autodetect operating system and find the correct line endings
- *
- * @return string The appropriate mail header delimiter
- */
- public function header_delimiter()
- {
- // use the configured delimiter for headers
- if (!empty($this->prop['mail_header_delimiter'])) {
- $delim = $this->prop['mail_header_delimiter'];
- if ($delim == "\n" || $delim == "\r\n")
- return $delim;
- else
- rcube::raise_error(array(
- 'code' => 500, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Invalid mail_header_delimiter setting"
- ), true, false);
- }
-
- $php_os = strtolower(substr(PHP_OS, 0, 3));
-
- if ($php_os == 'win')
- return "\r\n";
-
- if ($php_os == 'mac')
- return "\r\n";
-
- return "\n";
- }
-
-
- /**
- * Return the mail domain configured for the given host
- *
- * @param string $host IMAP host
- * @param boolean $encode If true, domain name will be converted to IDN ASCII
- * @return string Resolved SMTP host
- */
- public function mail_domain($host, $encode=true)
- {
- $domain = $host;
-
- if (is_array($this->prop['mail_domain'])) {
- if (isset($this->prop['mail_domain'][$host]))
- $domain = $this->prop['mail_domain'][$host];
- }
- else if (!empty($this->prop['mail_domain'])) {
- $domain = rcube_utils::parse_host($this->prop['mail_domain']);
- }
-
- if ($encode) {
- $domain = rcube_utils::idn_to_ascii($domain);
- }
-
- return $domain;
- }
-
-
- /**
- * Getter for error state
- *
- * @return mixed Error message on error, False if no errors
- */
- public function get_error()
- {
- return empty($this->errors) ? false : join("\n", $this->errors);
- }
-
-
- /**
- * Internal getter for client's (browser) timezone identifier
- */
- private function client_timezone()
- {
- // @TODO: remove this legacy timezone handling in the future
- $props = $this->fix_legacy_props(array('timezone' => $_SESSION['timezone']));
-
- if (!empty($props['timezone'])) {
- try {
- $tz = new DateTimeZone($props['timezone']);
- return $tz->getName();
- }
- catch (Exception $e) { /* gracefully ignore */ }
- }
-
- // fallback to server's timezone
- return date_default_timezone_get();
- }
-
- /**
- * Convert legacy options into new ones
- *
- * @param array $props Hash array with config props
- *
- * @return array Converted config props
- */
- private function fix_legacy_props($props)
- {
- foreach ($this->legacy_props as $new => $old) {
- if (isset($props[$old])) {
- if (!isset($props[$new])) {
- $props[$new] = $props[$old];
- }
- unset($props[$old]);
- }
- }
-
- // convert deprecated numeric timezone value
- if (isset($props['timezone']) && is_numeric($props['timezone'])) {
- if ($tz = self::timezone_name_from_abbr($props['timezone'])) {
- $props['timezone'] = $tz;
- }
- else {
- unset($props['timezone']);
- }
- }
-
- return $props;
- }
-
- /**
- * timezone_name_from_abbr() replacement. Converts timezone offset
- * into timezone name abbreviation.
- *
- * @param float $offset Timezone offset (in hours)
- *
- * @return string Timezone abbreviation
- */
- static public function timezone_name_from_abbr($offset)
- {
- // List of timezones here is not complete - https://bugs.php.net/bug.php?id=44780
- if ($tz = timezone_name_from_abbr('', $offset * 3600, 0)) {
- return $tz;
- }
-
- // try with more complete list (#1489261)
- $timezones = array(
- '-660' => "Pacific/Apia",
- '-600' => "Pacific/Honolulu",
- '-570' => "Pacific/Marquesas",
- '-540' => "America/Anchorage",
- '-480' => "America/Los_Angeles",
- '-420' => "America/Denver",
- '-360' => "America/Chicago",
- '-300' => "America/New_York",
- '-270' => "America/Caracas",
- '-240' => "America/Halifax",
- '-210' => "Canada/Newfoundland",
- '-180' => "America/Sao_Paulo",
- '-60' => "Atlantic/Azores",
- '0' => "Europe/London",
- '60' => "Europe/Paris",
- '120' => "Europe/Helsinki",
- '180' => "Europe/Moscow",
- '210' => "Asia/Tehran",
- '240' => "Asia/Dubai",
- '300' => "Asia/Karachi",
- '270' => "Asia/Kabul",
- '300' => "Asia/Karachi",
- '330' => "Asia/Kolkata",
- '345' => "Asia/Katmandu",
- '360' => "Asia/Yekaterinburg",
- '390' => "Asia/Rangoon",
- '420' => "Asia/Krasnoyarsk",
- '480' => "Asia/Shanghai",
- '525' => "Australia/Eucla",
- '540' => "Asia/Tokyo",
- '570' => "Australia/Adelaide",
- '600' => "Australia/Melbourne",
- '630' => "Australia/Lord_Howe",
- '660' => "Asia/Vladivostok",
- '690' => "Pacific/Norfolk",
- '720' => "Pacific/Auckland",
- '765' => "Pacific/Chatham",
- '780' => "Pacific/Enderbury",
- '840' => "Pacific/Kiritimati",
- );
-
- return $timezones[(string) intval($offset * 60)];
- }
-}
diff --git a/lib/ext/Roundcube/rcube_contacts.php b/lib/ext/Roundcube/rcube_contacts.php
deleted file mode 100644
index bd3a3f8..0000000
--- a/lib/ext/Roundcube/rcube_contacts.php
+++ /dev/null
@@ -1,1018 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2006-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Interface to the local address book database |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-
-/**
- * Model class for the local address book database
- *
- * @package Framework
- * @subpackage Addressbook
- */
-class rcube_contacts extends rcube_addressbook
-{
- // protected for backward compat. with some plugins
- protected $db_name = 'contacts';
- protected $db_groups = 'contactgroups';
- protected $db_groupmembers = 'contactgroupmembers';
- protected $vcard_fieldmap = array();
-
- /**
- * Store database connection.
- *
- * @var rcube_db
- */
- private $db = null;
- private $user_id = 0;
- private $filter = null;
- private $result = null;
- private $cache;
- private $table_cols = array('name', 'email', 'firstname', 'surname');
- private $fulltext_cols = array('name', 'firstname', 'surname', 'middlename', 'nickname',
- 'jobtitle', 'organization', 'department', 'maidenname', 'email', 'phone',
- 'address', 'street', 'locality', 'zipcode', 'region', 'country', 'website', 'im', 'notes');
-
- // public properties
- public $primary_key = 'contact_id';
- public $name;
- public $readonly = false;
- public $groups = true;
- public $undelete = true;
- public $list_page = 1;
- public $page_size = 10;
- public $group_id = 0;
- public $ready = false;
- public $coltypes = array('name', 'firstname', 'surname', 'middlename', 'prefix', 'suffix', 'nickname',
- 'jobtitle', 'organization', 'department', 'assistant', 'manager',
- 'gender', 'maidenname', 'spouse', 'email', 'phone', 'address',
- 'birthday', 'anniversary', 'website', 'im', 'notes', 'photo');
- public $date_cols = array('birthday', 'anniversary');
-
- const SEPARATOR = ',';
-
-
- /**
- * Object constructor
- *
- * @param object Instance of the rcube_db class
- * @param integer User-ID
- */
- function __construct($dbconn, $user)
- {
- $this->db = $dbconn;
- $this->user_id = $user;
- $this->ready = $this->db && !$this->db->is_error();
- }
-
-
- /**
- * Returns addressbook name
- */
- function get_name()
- {
- return $this->name;
- }
-
-
- /**
- * Save a search string for future listings
- *
- * @param string SQL params to use in listing method
- */
- function set_search_set($filter)
- {
- $this->filter = $filter;
- $this->cache = null;
- }
-
-
- /**
- * Getter for saved search properties
- *
- * @return mixed Search properties used by this class
- */
- function get_search_set()
- {
- return $this->filter;
- }
-
-
- /**
- * Setter for the current group
- * (empty, has to be re-implemented by extending class)
- */
- function set_group($gid)
- {
- $this->group_id = $gid;
- $this->cache = null;
- }
-
-
- /**
- * Reset all saved results and search parameters
- */
- function reset()
- {
- $this->result = null;
- $this->filter = null;
- $this->cache = null;
- }
-
-
- /**
- * List all active contact groups of this source
- *
- * @param string Search string to match group name
- * @param int Matching mode:
- * 0 - partial (*abc*),
- * 1 - strict (=),
- * 2 - prefix (abc*)
- *
- * @return array Indexed list of contact groups, each a hash array
- */
- function list_groups($search = null, $mode = 0)
- {
- $results = array();
-
- if (!$this->groups)
- return $results;
-
- if ($search) {
- switch (intval($mode)) {
- case 1:
- $sql_filter = $this->db->ilike('name', $search);
- break;
- case 2:
- $sql_filter = $this->db->ilike('name', $search . '%');
- break;
- default:
- $sql_filter = $this->db->ilike('name', '%' . $search . '%');
- }
-
- $sql_filter = " AND $sql_filter";
- }
-
- $sql_result = $this->db->query(
- "SELECT * FROM " . $this->db->table_name($this->db_groups, true)
- . " WHERE `del` <> 1 AND `user_id` = ?" . $sql_filter
- . " ORDER BY `name`",
- $this->user_id);
-
- while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) {
- $sql_arr['ID'] = $sql_arr['contactgroup_id'];
- $results[] = $sql_arr;
- }
-
- return $results;
- }
-
-
- /**
- * 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 " . $this->db->table_name($this->db_groups, true)
- . " 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 array List of cols to show, Null means all
- * @param int Only return this number of records, use negative values for tail
- * @param boolean True to skip the count query (select only)
- * @return array Indexed list of contact records, each a hash array
- */
- function list_records($cols=null, $subset=0, $nocount=false)
- {
- if ($nocount || $this->list_page <= 1) {
- // create dummy result, we don't need a count now
- $this->result = new rcube_result_set();
- } else {
- // count all records
- $this->result = $this->count();
- }
-
- $start_row = $subset < 0 ? $this->result->first + $this->page_size + $subset : $this->result->first;
- $length = $subset != 0 ? abs($subset) : $this->page_size;
-
- if ($this->group_id)
- $join = " LEFT JOIN " . $this->db->table_name($this->db_groupmembers, true) . " AS m".
- " ON (m.`contact_id` = c.`".$this->primary_key."`)";
-
- $order_col = (in_array($this->sort_col, $this->table_cols) ? $this->sort_col : 'name');
- $order_cols = array("c.`$order_col`");
- if ($order_col == 'firstname')
- $order_cols[] = 'c.`surname`';
- else if ($order_col == 'surname')
- $order_cols[] = 'c.`firstname`';
- if ($order_col != 'name')
- $order_cols[] = 'c.`name`';
- $order_cols[] = 'c.`email`';
-
- $sql_result = $this->db->limitquery(
- "SELECT * FROM " . $this->db->table_name($this->db_name, true) . " AS c" .
- $join .
- " WHERE c.`del` <> 1" .
- " AND c.`user_id` = ?" .
- ($this->group_id ? " AND m.`contactgroup_id` = ?" : "").
- ($this->filter ? " AND (".$this->filter.")" : "") .
- " ORDER BY ". $this->db->concat($order_cols) .
- " " . $this->sort_order,
- $start_row,
- $length,
- $this->user_id,
- $this->group_id);
-
- // determine whether we have to parse the vcard or if only db cols are requested
- $read_vcard = !$cols || count(array_intersect($cols, $this->table_cols)) < count($cols);
-
- while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) {
- $sql_arr['ID'] = $sql_arr[$this->primary_key];
-
- if ($read_vcard)
- $sql_arr = $this->convert_db_data($sql_arr);
- else {
- $sql_arr['email'] = $sql_arr['email'] ? explode(self::SEPARATOR, $sql_arr['email']) : array();
- $sql_arr['email'] = array_map('trim', $sql_arr['email']);
- }
-
- $this->result->add($sql_arr);
- }
-
- $cnt = count($this->result->records);
-
- // update counter
- if ($nocount)
- $this->result->count = $cnt;
- else if ($this->list_page <= 1) {
- if ($cnt < $this->page_size && $subset == 0)
- $this->result->count = $cnt;
- else if (isset($this->cache['count']))
- $this->result->count = $this->cache['count'];
- else
- $this->result->count = $this->_count();
- }
-
- return $this->result;
- }
-
-
- /**
- * Search contacts
- *
- * @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 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, $mode=0, $select=true, $nocount=false, $required=array())
- {
- if (!is_array($fields))
- $fields = array($fields);
- if (!is_array($required) && !empty($required))
- $required = array($required);
-
- $where = $and_where = array();
- $mode = intval($mode);
- $WS = ' ';
- $AS = self::SEPARATOR;
-
- foreach ($fields as $idx => $col) {
- // direct ID search
- if ($col == 'ID' || $col == $this->primary_key) {
- $ids = !is_array($value) ? explode(self::SEPARATOR, $value) : $value;
- $ids = $this->db->array2list($ids, 'integer');
- $where[] = 'c.' . $this->primary_key.' IN ('.$ids.')';
- continue;
- }
- // fulltext search in all fields
- else if ($col == '*') {
- $words = array();
- foreach (explode($WS, rcube_utils::normalize_string($value)) as $word) {
- switch ($mode) {
- case 1: // strict
- $words[] = '(' . $this->db->ilike('words', $word . '%')
- . ' OR ' . $this->db->ilike('words', '%' . $WS . $word . $WS . '%')
- . ' OR ' . $this->db->ilike('words', '%' . $WS . $word) . ')';
- break;
- case 2: // prefix
- $words[] = '(' . $this->db->ilike('words', $word . '%')
- . ' OR ' . $this->db->ilike('words', '%' . $WS . $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)) {
- switch ($mode) {
- case 1: // strict
- $where[] = '(' . $this->db->quote_identifier($col) . ' = ' . $this->db->quote($val)
- . ' OR ' . $this->db->ilike($col, $val . $AS . '%')
- . ' OR ' . $this->db->ilike($col, '%' . $AS . $val . $AS . '%')
- . ' OR ' . $this->db->ilike($col, '%' . $AS . $val) . ')';
- break;
- case 2: // prefix
- $where[] = '(' . $this->db->ilike($col, $val . '%')
- . ' OR ' . $this->db->ilike($col, $AS . $val . '%') . ')';
- break;
- default: // partial
- $where[] = $this->db->ilike($col, '%' . $val . '%');
- }
- }
- // vCard field
- else {
- if (in_array($col, $this->fulltext_cols)) {
- foreach (rcube_utils::normalize_string($val, true) as $word) {
- switch ($mode) {
- case 1: // strict
- $words[] = '(' . $this->db->ilike('words', $word . $WS . '%')
- . ' OR ' . $this->db->ilike('words', '%' . $AS . $word . $WS .'%')
- . ' OR ' . $this->db->ilike('words', '%' . $AS . $word) . ')';
- break;
- case 2: // prefix
- $words[] = '(' . $this->db->ilike('words', $word . '%')
- . ' OR ' . $this->db->ilike('words', $AS . $word . '%') . ')';
- break;
- default: // partial
- $words[] = $this->db->ilike('words', '%' . $word . '%');
- }
- }
- $where[] = '(' . join(' AND ', $words) . ')';
- }
- if (is_array($value))
- $post_search[$col] = mb_strtolower($val);
- }
- }
- }
-
- foreach (array_intersect($required, $this->table_cols) as $col) {
- $and_where[] = $this->db->quote_identifier($col).' <> '.$this->db->quote('');
- }
-
- if (!empty($where)) {
- // use AND operator for advanced searches
- $where = join(is_array($value) ? ' AND ' : ' OR ', $where);
- }
-
- if (!empty($and_where))
- $where = ($where ? "($where) AND " : '') . join(' AND ', $and_where);
-
- // Post-searching in vCard data fields
- // we will search in all records and then build a where clause for their IDs
- if (!empty($post_search)) {
- $ids = array(0);
- // build key name regexp
- $regexp = '/^(' . implode(array_keys($post_search), '|') . ')(?:.*)$/';
- // use initial WHERE clause, to limit records number if possible
- if (!empty($where))
- $this->set_search_set($where);
-
- // count result pages
- $cnt = $this->count();
- $pages = ceil($cnt / $this->page_size);
- $scnt = count($post_search);
-
- // get (paged) result
- for ($i=0; $i<$pages; $i++) {
- $this->list_records(null, $i, true);
- while ($row = $this->result->next()) {
- $id = $row[$this->primary_key];
- $found = array();
- foreach (preg_grep($regexp, array_keys($row)) as $col) {
- $pos = strpos($col, ':');
- $colname = $pos ? substr($col, 0, $pos) : $col;
- $search = $post_search[$colname];
- foreach ((array)$row[$col] as $value) {
- if ($this->compare_search_value($colname, $value, $search, $mode)) {
- $found[$colname] = true;
- break 2;
- }
- }
- }
- // all fields match
- if (count($found) >= $scnt) {
- $ids[] = $id;
- }
- }
- }
-
- // build WHERE clause
- $ids = $this->db->array2list($ids, 'integer');
- $where = 'c.`' . $this->primary_key.'` IN ('.$ids.')';
- // reset counter
- unset($this->cache['count']);
-
- // when we know we have an empty result
- if ($ids == '0') {
- $this->set_search_set($where);
- return ($this->result = new rcube_result_set(0, 0));
- }
- }
-
- if (!empty($where)) {
- $this->set_search_set($where);
- if ($select)
- $this->list_records(null, 0, $nocount);
- else
- $this->result = $this->count();
- }
-
- return $this->result;
- }
-
-
- /**
- * Count number of available contacts in database
- *
- * @return rcube_result_set Result object
- */
- function count()
- {
- $count = isset($this->cache['count']) ? $this->cache['count'] : $this->_count();
-
- return new rcube_result_set($count, ($this->list_page-1) * $this->page_size);
- }
-
-
- /**
- * Count number of available contacts in database
- *
- * @return int Contacts count
- */
- private function _count()
- {
- if ($this->group_id)
- $join = " LEFT JOIN " . $this->db->table_name($this->db_groupmembers, true) . " AS m".
- " ON (m.`contact_id` = c.`".$this->primary_key."`)";
-
- // count contacts for this user
- $sql_result = $this->db->query(
- "SELECT COUNT(c.`contact_id`) AS rows".
- " FROM " . $this->db->table_name($this->db_name, true) . " AS c".
- $join.
- " WHERE c.`del` <> 1".
- " AND c.`user_id` = ?".
- ($this->group_id ? " AND m.`contactgroup_id` = ?" : "").
- ($this->filter ? " AND (".$this->filter.")" : ""),
- $this->user_id,
- $this->group_id
- );
-
- $sql_arr = $this->db->fetch_assoc($sql_result);
-
- $this->cache['count'] = (int) $sql_arr['rows'];
-
- return $this->cache['count'];
- }
-
-
- /**
- * Return the last result set
- *
- * @return mixed Result array or NULL if nothing selected yet
- */
- function get_result()
- {
- return $this->result;
- }
-
-
- /**
- * Get a specific contact record
- *
- * @param mixed record identifier(s)
- * @return mixed Result object with all record fields or False if not found
- */
- function get_record($id, $assoc=false)
- {
- // return cached result
- if ($this->result && ($first = $this->result->first()) && $first[$this->primary_key] == $id)
- return $assoc ? $first : $this->result;
-
- $this->db->query(
- "SELECT * FROM " . $this->db->table_name($this->db_name, true).
- " WHERE `contact_id` = ?".
- " AND `user_id` = ?".
- " AND `del` <> 1",
- $id,
- $this->user_id
- );
-
- if ($sql_arr = $this->db->fetch_assoc()) {
- $record = $this->convert_db_data($sql_arr);
- $this->result = new rcube_result_set(1);
- $this->result->add($record);
- }
-
- return $assoc && $record ? $record : $this->result;
- }
-
-
- /**
- * Get group assignments of a specific contact record
- *
- * @param mixed Record identifier
- * @return array List of assigned groups as ID=>Name pairs
- */
- function get_record_groups($id)
- {
- $results = array();
-
- if (!$this->groups)
- return $results;
-
- $sql_result = $this->db->query(
- "SELECT cgm.`contactgroup_id`, cg.`name` "
- . " FROM " . $this->db->table_name($this->db_groupmembers, true) . " AS cgm"
- . " LEFT JOIN " . $this->db->table_name($this->db_groups, true) . " AS cg"
- . " ON (cgm.`contactgroup_id` = cg.`contactgroup_id` AND cg.`del` <> 1)"
- . " WHERE cgm.`contact_id` = ?",
- $id
- );
- while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) {
- $results[$sql_arr['contactgroup_id']] = $sql_arr['name'];
- }
-
- return $results;
- }
-
-
- /**
- * Check the given data before saving.
- * 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, $autofix = false)
- {
- // validate e-mail addresses
- $valid = parent::validate($save_data, $autofix);
-
- // require at least one email address or a name
- if ($valid && !strlen($save_data['firstname'].$save_data['surname'].$save_data['name']) && !array_filter($this->get_col_values('email', $save_data, true))) {
- $this->set_error(self::ERROR_VALIDATE, 'noemailwarning');
- $valid = false;
- }
-
- return $valid;
- }
-
-
- /**
- * Create a new contact record
- *
- * @param array Associative array with save data
- * @return integer|boolean The created record ID on success, False on error
- */
- function insert($save_data, $check=false)
- {
- if (!is_array($save_data))
- return false;
-
- $insert_id = $existing = false;
-
- if ($check) {
- foreach ($save_data as $col => $values) {
- if (strpos($col, 'email') === 0) {
- foreach ((array)$values as $email) {
- if ($existing = $this->search('email', $email, false, false))
- break 2;
- }
- }
- }
- }
-
- $save_data = $this->convert_save_data($save_data);
- $a_insert_cols = $a_insert_values = array();
-
- foreach ($save_data as $col => $value) {
- $a_insert_cols[] = $this->db->quote_identifier($col);
- $a_insert_values[] = $this->db->quote($value);
- }
-
- if (!$existing->count && !empty($a_insert_cols)) {
- $this->db->query(
- "INSERT INTO " . $this->db->table_name($this->db_name, true).
- " (`user_id`, `changed`, `del`, ".join(', ', $a_insert_cols).")".
- " VALUES (".intval($this->user_id).", ".$this->db->now().", 0, ".join(', ', $a_insert_values).")"
- );
-
- $insert_id = $this->db->insert_id($this->db_name);
- }
-
- $this->cache = null;
-
- return $insert_id;
- }
-
-
- /**
- * Update a specific contact record
- *
- * @param mixed Record identifier
- * @param array Assoziative array with save data
- *
- * @return boolean True on success, False on error
- */
- function update($id, $save_cols)
- {
- $updated = false;
- $write_sql = array();
- $record = $this->get_record($id, true);
- $save_cols = $this->convert_save_data($save_cols, $record);
-
- foreach ($save_cols as $col => $value) {
- $write_sql[] = sprintf("%s=%s", $this->db->quote_identifier($col), $this->db->quote($value));
- }
-
- if (!empty($write_sql)) {
- $this->db->query(
- "UPDATE " . $this->db->table_name($this->db_name, true).
- " SET `changed` = ".$this->db->now().", ".join(', ', $write_sql).
- " WHERE `contact_id` = ?".
- " AND `user_id` = ?".
- " AND `del` <> 1",
- $id,
- $this->user_id
- );
-
- $updated = $this->db->affected_rows();
- $this->result = null; // clear current result (from get_record())
- }
-
- return $updated ? true : false;
- }
-
-
- private function convert_db_data($sql_arr)
- {
- $record = array();
- $record['ID'] = $sql_arr[$this->primary_key];
-
- if ($sql_arr['vcard']) {
- unset($sql_arr['email']);
- $vcard = new rcube_vcard($sql_arr['vcard'], RCUBE_CHARSET, false, $this->vcard_fieldmap);
- $record += $vcard->get_assoc() + $sql_arr;
- }
- else {
- $record += $sql_arr;
- $record['email'] = explode(self::SEPARATOR, $record['email']);
- $record['email'] = array_map('trim', $record['email']);
- }
-
- return $record;
- }
-
-
- private function convert_save_data($save_data, $record = array())
- {
- $out = array();
- $words = '';
-
- // copy values into vcard object
- $vcard = new rcube_vcard($record['vcard'] ? $record['vcard'] : $save_data['vcard'], RCUBE_CHARSET, false, $this->vcard_fieldmap);
- $vcard->reset();
- foreach ($save_data as $key => $values) {
- list($field, $section) = explode(':', $key);
- $fulltext = in_array($field, $this->fulltext_cols);
- // avoid casting DateTime objects to array
- if (is_object($values) && is_a($values, 'DateTime')) {
- $values = array(0 => $values);
- }
- foreach ((array)$values as $value) {
- if (isset($value))
- $vcard->set($field, $value, $section);
- if ($fulltext && is_array($value))
- $words .= ' ' . rcube_utils::normalize_string(join(" ", $value));
- else if ($fulltext && strlen($value) >= 3)
- $words .= ' ' . rcube_utils::normalize_string($value);
- }
- }
- $out['vcard'] = $vcard->export(false);
-
- foreach ($this->table_cols as $col) {
- $key = $col;
- if (!isset($save_data[$key]))
- $key .= ':home';
- if (isset($save_data[$key])) {
- if (is_array($save_data[$key]))
- $out[$col] = join(self::SEPARATOR, $save_data[$key]);
- else
- $out[$col] = $save_data[$key];
- }
- }
-
- // save all e-mails in database column
- $out['email'] = join(self::SEPARATOR, $vcard->email);
-
- // join words for fulltext search
- $out['words'] = join(" ", array_unique(explode(" ", $words)));
-
- return $out;
- }
-
-
- /**
- * Mark one or more contact records as deleted
- *
- * @param array Record identifiers
- * @param boolean Remove record(s) irreversible (unsupported)
- */
- function delete($ids, $force=true)
- {
- if (!is_array($ids))
- $ids = explode(self::SEPARATOR, $ids);
-
- $ids = $this->db->array2list($ids, 'integer');
-
- // flag record as deleted (always)
- $this->db->query(
- "UPDATE " . $this->db->table_name($this->db_name, true).
- " SET `del` = 1, `changed` = ".$this->db->now().
- " WHERE `user_id` = ?".
- " AND `contact_id` IN ($ids)",
- $this->user_id
- );
-
- $this->cache = null;
-
- return $this->db->affected_rows();
- }
-
-
- /**
- * Undelete one or more contact records
- *
- * @param array Record identifiers
- */
- function undelete($ids)
- {
- if (!is_array($ids))
- $ids = explode(self::SEPARATOR, $ids);
-
- $ids = $this->db->array2list($ids, 'integer');
-
- // clear deleted flag
- $this->db->query(
- "UPDATE " . $this->db->table_name($this->db_name, true).
- " SET `del` = 0, `changed` = ".$this->db->now().
- " WHERE `user_id` = ?".
- " AND `contact_id` IN ($ids)",
- $this->user_id
- );
-
- $this->cache = null;
-
- return $this->db->affected_rows();
- }
-
-
- /**
- * Remove all records from the database
- *
- * @param bool $with_groups Remove also groups
- *
- * @return int Number of removed records
- */
- function delete_all($with_groups = false)
- {
- $this->cache = null;
-
- $now = $this->db->now();
-
- $this->db->query("UPDATE " . $this->db->table_name($this->db_name, true)
- . " SET `del` = 1, `changed` = $now"
- . " WHERE `user_id` = ?", $this->user_id);
-
- $count = $this->db->affected_rows();
-
- if ($with_groups) {
- $this->db->query("UPDATE " . $this->db->table_name($this->db_groups, true)
- . " SET `del` = 1, `changed` = $now"
- . " WHERE `user_id` = ?", $this->user_id);
-
- $count += $this->db->affected_rows();
- }
-
- return $count;
- }
-
-
- /**
- * Create a contact group with the given name
- *
- * @param string The group name
- * @return mixed False on error, array with record props in success
- */
- function create_group($name)
- {
- $result = false;
-
- // make sure we have a unique name
- $name = $this->unique_groupname($name);
-
- $this->db->query(
- "INSERT INTO " . $this->db->table_name($this->db_groups, true).
- " (`user_id`, `changed`, `name`)".
- " VALUES (".intval($this->user_id).", ".$this->db->now().", ".$this->db->quote($name).")"
- );
-
- if ($insert_id = $this->db->insert_id($this->db_groups)) {
- $result = array('id' => $insert_id, 'name' => $name);
- }
-
- return $result;
- }
-
-
- /**
- * Delete the given group (and all linked group members)
- *
- * @param string Group identifier
- * @return boolean True on success, false if no data was changed
- */
- function delete_group($gid)
- {
- // flag group record as deleted
- $this->db->query(
- "UPDATE " . $this->db->table_name($this->db_groups, true)
- . " SET `del` = 1, `changed` = " . $this->db->now()
- . " WHERE `contactgroup_id` = ?"
- . " AND `user_id` = ?",
- $gid, $this->user_id
- );
-
- $this->cache = null;
-
- return $this->db->affected_rows();
- }
-
- /**
- * Rename a specific contact group
- *
- * @param string Group identifier
- * @param string New name to set for this group
- * @return boolean New name on success, false if no data was changed
- */
- function rename_group($gid, $newname, &$new_gid)
- {
- // make sure we have a unique name
- $name = $this->unique_groupname($newname);
-
- $sql_result = $this->db->query(
- "UPDATE " . $this->db->table_name($this->db_groups, true).
- " SET `name` = ?, `changed` = ".$this->db->now().
- " WHERE `contactgroup_id` = ?".
- " AND `user_id` = ?",
- $name, $gid, $this->user_id
- );
-
- return $this->db->affected_rows() ? $name : false;
- }
-
-
- /**
- * Add the given contact records the a certain group
- *
- * @param string Group identifier
- * @param array|string List of contact identifiers to be added
- *
- * @return int Number of contacts added
- */
- function add_to_group($group_id, $ids)
- {
- if (!is_array($ids))
- $ids = explode(self::SEPARATOR, $ids);
-
- $added = 0;
- $exists = array();
-
- // get existing assignments ...
- $sql_result = $this->db->query(
- "SELECT `contact_id` FROM " . $this->db->table_name($this->db_groupmembers, true).
- " WHERE `contactgroup_id` = ?".
- " AND `contact_id` IN (".$this->db->array2list($ids, 'integer').")",
- $group_id
- );
- while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) {
- $exists[] = $sql_arr['contact_id'];
- }
- // ... and remove them from the list
- $ids = array_diff($ids, $exists);
-
- foreach ($ids as $contact_id) {
- $this->db->query(
- "INSERT INTO " . $this->db->table_name($this->db_groupmembers, true).
- " (`contactgroup_id`, `contact_id`, `created`)".
- " VALUES (?, ?, ".$this->db->now().")",
- $group_id,
- $contact_id
- );
-
- if ($error = $this->db->is_error())
- $this->set_error(self::ERROR_SAVING, $error);
- else
- $added++;
- }
-
- return $added;
- }
-
-
- /**
- * Remove the given contact records from a certain group
- *
- * @param string Group identifier
- * @param array|string List of contact identifiers to be removed
- *
- * @return int Number of deleted group members
- */
- function remove_from_group($group_id, $ids)
- {
- if (!is_array($ids))
- $ids = explode(self::SEPARATOR, $ids);
-
- $ids = $this->db->array2list($ids, 'integer');
-
- $sql_result = $this->db->query(
- "DELETE FROM " . $this->db->table_name($this->db_groupmembers, true).
- " WHERE `contactgroup_id` = ?".
- " AND `contact_id` IN ($ids)",
- $group_id
- );
-
- return $this->db->affected_rows();
- }
-
-
- /**
- * Check for existing groups with the same name
- *
- * @param string Name to check
- * @return string A group name which is unique for the current use
- */
- private function unique_groupname($name)
- {
- $checkname = $name;
- $num = 2; $hit = false;
-
- do {
- $sql_result = $this->db->query(
- "SELECT 1 FROM " . $this->db->table_name($this->db_groups, true).
- " WHERE `del` <> 1".
- " AND `user_id` = ?".
- " AND `name` = ?",
- $this->user_id,
- $checkname);
-
- // append number to make name unique
- if ($hit = $this->db->fetch_array($sql_result)) {
- $checkname = $name . ' ' . $num++;
- }
- } while ($hit);
-
- return $checkname;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_content_filter.php b/lib/ext/Roundcube/rcube_content_filter.php
deleted file mode 100644
index ae6617d..0000000
--- a/lib/ext/Roundcube/rcube_content_filter.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2011, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | PHP stream filter to detect evil content in mail attachments |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * PHP stream filter to detect html/javascript code in attachments
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_content_filter extends php_user_filter
-{
- private $buffer = '';
- private $cutoff = 2048;
-
- function onCreate()
- {
- $this->cutoff = rand(2048, 3027);
- return true;
- }
-
- function filter($in, $out, &$consumed, $closing)
- {
- while ($bucket = stream_bucket_make_writeable($in)) {
- $this->buffer .= $bucket->data;
-
- // check for evil content and abort
- if (preg_match('/<(script|iframe|object)/i', $this->buffer)) {
- return PSFS_ERR_FATAL;
- }
-
- // keep buffer small enough
- if (strlen($this->buffer) > 4096) {
- $this->buffer = substr($this->buffer, $this->cutoff);
- }
-
- $consumed += $bucket->datalen;
- stream_bucket_append($out, $bucket);
- }
-
- return PSFS_PASS_ON;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_csv2vcard.php b/lib/ext/Roundcube/rcube_csv2vcard.php
deleted file mode 100644
index b7d1591..0000000
--- a/lib/ext/Roundcube/rcube_csv2vcard.php
+++ /dev/null
@@ -1,630 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | CSV to vCard data conversion |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * CSV to vCard data converter
- *
- * @package Framework
- * @subpackage Addressbook
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_csv2vcard
-{
- /**
- * CSV to vCard fields mapping
- *
- * @var array
- */
- protected $csv2vcard_map = array(
- // MS Outlook 2010
- 'anniversary' => 'anniversary',
- 'assistants_name' => 'assistant',
- 'assistants_phone' => 'phone:assistant',
- 'birthday' => 'birthday',
- 'business_city' => 'locality:work',
- 'business_countryregion' => 'country:work',
- 'business_fax' => 'phone:work,fax',
- 'business_phone' => 'phone:work',
- 'business_phone_2' => 'phone:work2',
- 'business_postal_code' => 'zipcode:work',
- 'business_state' => 'region:work',
- 'business_street' => 'street:work',
- //'business_street_2' => '',
- //'business_street_3' => '',
- 'car_phone' => 'phone:car',
- 'categories' => 'groups',
- //'children' => '',
- 'company' => 'organization',
- //'company_main_phone' => '',
- 'department' => 'department',
- //'email_2_address' => '', //@TODO
- //'email_2_type' => '',
- //'email_3_address' => '', //@TODO
- //'email_3_type' => '',
- 'email_address' => 'email:pref',
- //'email_type' => '',
- 'first_name' => 'firstname',
- 'gender' => 'gender',
- 'home_city' => 'locality:home',
- 'home_countryregion' => 'country:home',
- 'home_fax' => 'phone:home,fax',
- 'home_phone' => 'phone:home',
- 'home_phone_2' => 'phone:home2',
- 'home_postal_code' => 'zipcode:home',
- 'home_state' => 'region:home',
- 'home_street' => 'street:home',
- //'home_street_2' => '',
- //'home_street_3' => '',
- //'initials' => '',
- //'isdn' => '',
- 'job_title' => 'jobtitle',
- //'keywords' => '',
- //'language' => '',
- 'last_name' => 'surname',
- //'location' => '',
- 'managers_name' => 'manager',
- 'middle_name' => 'middlename',
- //'mileage' => '',
- 'mobile_phone' => 'phone:cell',
- 'notes' => 'notes',
- //'office_location' => '',
- 'other_city' => 'locality:other',
- 'other_countryregion' => 'country:other',
- 'other_fax' => 'phone:other,fax',
- 'other_phone' => 'phone:other',
- 'other_postal_code' => 'zipcode:other',
- 'other_state' => 'region:other',
- 'other_street' => 'street:other',
- //'other_street_2' => '',
- //'other_street_3' => '',
- 'pager' => 'phone:pager',
- 'primary_phone' => 'phone:pref',
- //'profession' => '',
- //'radio_phone' => '',
- 'spouse' => 'spouse',
- 'suffix' => 'suffix',
- 'title' => 'title',
- 'web_page' => 'website:homepage',
-
- // Thunderbird
- 'birth_day' => 'birthday-d',
- 'birth_month' => 'birthday-m',
- 'birth_year' => 'birthday-y',
- 'display_name' => 'displayname',
- 'fax_number' => 'phone:fax',
- 'home_address' => 'street:home',
- //'home_address_2' => '',
- 'home_country' => 'country:home',
- 'home_zipcode' => 'zipcode:home',
- 'mobile_number' => 'phone:cell',
- 'nickname' => 'nickname',
- 'organization' => 'organization',
- 'pager_number' => 'phone:pager',
- 'primary_email' => 'email:pref',
- 'secondary_email' => 'email:other',
- 'web_page_1' => 'website:homepage',
- 'web_page_2' => 'website:other',
- 'work_phone' => 'phone:work',
- 'work_address' => 'street:work',
- //'work_address_2' => '',
- 'work_country' => 'country:work',
- 'work_zipcode' => 'zipcode:work',
- 'last' => 'surname',
- 'first' => 'firstname',
- 'work_city' => 'locality:work',
- 'work_state' => 'region:work',
- 'home_city_short' => 'locality:home',
- 'home_state_short' => 'region:home',
-
- // Atmail
- 'date_of_birth' => 'birthday',
- 'email' => 'email:pref',
- 'home_mobile' => 'phone:cell',
- 'home_zip' => 'zipcode:home',
- 'info' => 'notes',
- 'user_photo' => 'photo',
- 'url' => 'website:homepage',
- 'work_company' => 'organization',
- 'work_dept' => 'departament',
- 'work_fax' => 'phone:work,fax',
- 'work_mobile' => 'phone:work,cell',
- 'work_title' => 'jobtitle',
- 'work_zip' => 'zipcode:work',
- 'group' => 'groups',
-
- // GMail
- 'groups' => 'groups',
- 'group_membership' => 'groups',
- 'given_name' => 'firstname',
- 'additional_name' => 'middlename',
- 'family_name' => 'surname',
- 'name' => 'displayname',
- 'name_prefix' => 'prefix',
- 'name_suffix' => 'suffix',
- );
-
- /**
- * CSV label to text mapping for English
- *
- * @var array
- */
- protected $label_map = array(
- // MS Outlook 2010
- 'anniversary' => "Anniversary",
- 'assistants_name' => "Assistant's Name",
- 'assistants_phone' => "Assistant's Phone",
- 'birthday' => "Birthday",
- 'business_city' => "Business City",
- 'business_countryregion' => "Business Country/Region",
- 'business_fax' => "Business Fax",
- 'business_phone' => "Business Phone",
- 'business_phone_2' => "Business Phone 2",
- 'business_postal_code' => "Business Postal Code",
- 'business_state' => "Business State",
- 'business_street' => "Business Street",
- //'business_street_2' => "Business Street 2",
- //'business_street_3' => "Business Street 3",
- 'car_phone' => "Car Phone",
- 'categories' => "Categories",
- //'children' => "Children",
- 'company' => "Company",
- //'company_main_phone' => "Company Main Phone",
- 'department' => "Department",
- //'directory_server' => "Directory Server",
- //'email_2_address' => "E-mail 2 Address",
- //'email_2_type' => "E-mail 2 Type",
- //'email_3_address' => "E-mail 3 Address",
- //'email_3_type' => "E-mail 3 Type",
- 'email_address' => "E-mail Address",
- //'email_type' => "E-mail Type",
- 'first_name' => "First Name",
- 'gender' => "Gender",
- 'home_city' => "Home City",
- 'home_countryregion' => "Home Country/Region",
- 'home_fax' => "Home Fax",
- 'home_phone' => "Home Phone",
- 'home_phone_2' => "Home Phone 2",
- 'home_postal_code' => "Home Postal Code",
- 'home_state' => "Home State",
- 'home_street' => "Home Street",
- //'home_street_2' => "Home Street 2",
- //'home_street_3' => "Home Street 3",
- //'initials' => "Initials",
- //'isdn' => "ISDN",
- 'job_title' => "Job Title",
- //'keywords' => "Keywords",
- //'language' => "Language",
- 'last_name' => "Last Name",
- //'location' => "Location",
- 'managers_name' => "Manager's Name",
- 'middle_name' => "Middle Name",
- //'mileage' => "Mileage",
- 'mobile_phone' => "Mobile Phone",
- 'notes' => "Notes",
- //'office_location' => "Office Location",
- 'other_city' => "Other City",
- 'other_countryregion' => "Other Country/Region",
- 'other_fax' => "Other Fax",
- 'other_phone' => "Other Phone",
- 'other_postal_code' => "Other Postal Code",
- 'other_state' => "Other State",
- 'other_street' => "Other Street",
- //'other_street_2' => "Other Street 2",
- //'other_street_3' => "Other Street 3",
- 'pager' => "Pager",
- 'primary_phone' => "Primary Phone",
- //'profession' => "Profession",
- //'radio_phone' => "Radio Phone",
- 'spouse' => "Spouse",
- 'suffix' => "Suffix",
- 'title' => "Title",
- 'web_page' => "Web Page",
-
- // Thunderbird
- 'birth_day' => "Birth Day",
- 'birth_month' => "Birth Month",
- 'birth_year' => "Birth Year",
- 'display_name' => "Display Name",
- 'fax_number' => "Fax Number",
- 'home_address' => "Home Address",
- //'home_address_2' => "Home Address 2",
- 'home_country' => "Home Country",
- 'home_zipcode' => "Home ZipCode",
- 'mobile_number' => "Mobile Number",
- 'nickname' => "Nickname",
- 'organization' => "Organization",
- 'pager_number' => "Pager Namber",
- 'primary_email' => "Primary Email",
- 'secondary_email' => "Secondary Email",
- 'web_page_1' => "Web Page 1",
- 'web_page_2' => "Web Page 2",
- 'work_phone' => "Work Phone",
- 'work_address' => "Work Address",
- //'work_address_2' => "Work Address 2",
- 'work_city' => "Work City",
- 'work_country' => "Work Country",
- 'work_state' => "Work State",
- 'work_zipcode' => "Work ZipCode",
-
- // Atmail
- 'date_of_birth' => "Date of Birth",
- 'email' => "Email",
- //'email_2' => "Email2",
- //'email_3' => "Email3",
- //'email_4' => "Email4",
- //'email_5' => "Email5",
- 'home_mobile' => "Home Mobile",
- 'home_zip' => "Home Zip",
- 'info' => "Info",
- 'user_photo' => "User Photo",
- 'url' => "URL",
- 'work_company' => "Work Company",
- 'work_dept' => "Work Dept",
- 'work_fax' => "Work Fax",
- 'work_mobile' => "Work Mobile",
- 'work_title' => "Work Title",
- 'work_zip' => "Work Zip",
- 'group' => "Group",
-
- // GMail
- 'groups' => "Groups",
- 'group_membership' => "Group Membership",
- 'given_name' => "Given Name",
- 'additional_name' => "Additional Name",
- 'family_name' => "Family Name",
- 'name' => "Name",
- 'name_prefix' => "Name Prefix",
- 'name_suffix' => "Name Suffix",
- );
-
- /**
- * Special fields map for GMail format
- *
- * @var array
- */
- protected $gmail_label_map = array(
- 'E-mail' => array(
- 'Value' => array(
- 'home' => 'email:home',
- 'work' => 'email:work',
- ),
- ),
- 'Phone' => array(
- 'Value' => array(
- 'home' => 'phone:home',
- 'homefax' => 'phone:homefax',
- 'main' => 'phone:pref',
- 'pager' => 'phone:pager',
- 'mobile' => 'phone:cell',
- 'work' => 'phone:work',
- 'workfax' => 'phone:workfax',
- ),
- ),
- 'Relation' => array(
- 'Value' => array(
- 'spouse' => 'spouse',
- ),
- ),
- 'Website' => array(
- 'Value' => array(
- 'profile' => 'website:profile',
- 'blog' => 'website:blog',
- 'homepage' => 'website:homepage',
- 'work' => 'website:work',
- ),
- ),
- 'Address' => array(
- 'Street' => array(
- 'home' => 'street:home',
- 'work' => 'street:work',
- ),
- 'City' => array(
- 'home' => 'locality:home',
- 'work' => 'locality:work',
- ),
- 'Region' => array(
- 'home' => 'region:home',
- 'work' => 'region:work',
- ),
- 'Postal Code' => array(
- 'home' => 'zipcode:home',
- 'work' => 'zipcode:work',
- ),
- 'Country' => array(
- 'home' => 'country:home',
- 'work' => 'country:work',
- ),
- ),
- 'Organization' => array(
- 'Name' => array(
- '' => 'organization',
- ),
- 'Title' => array(
- '' => 'jobtitle',
- ),
- 'Department' => array(
- '' => 'department',
- ),
- ),
- );
-
-
- protected $local_label_map = array();
- protected $vcards = array();
- protected $map = array();
- protected $gmail_map = array();
-
-
- /**
- * Class constructor
- *
- * @param string $lang File language
- */
- public function __construct($lang = 'en_US')
- {
- // Localize fields map
- if ($lang && $lang != 'en_US') {
- if (file_exists(RCUBE_LOCALIZATION_DIR . "$lang/csv2vcard.inc")) {
- include RCUBE_LOCALIZATION_DIR . "$lang/csv2vcard.inc";
- }
-
- if (!empty($map)) {
- $this->local_label_map = array_merge($this->label_map, $map);
- }
- }
-
- $this->label_map = array_flip($this->label_map);
- $this->local_label_map = array_flip($this->local_label_map);
- }
-
- /**
- *
- */
- public function import($csv)
- {
- // convert to UTF-8
- $head = substr($csv, 0, 4096);
- $charset = rcube_charset::detect($head, RCUBE_CHARSET);
- $csv = rcube_charset::convert($csv, $charset);
- $csv = preg_replace(array('/^[\xFE\xFF]{2}/', '/^\xEF\xBB\xBF/', '/^\x00+/'), '', $csv); // also remove BOM
- $head = '';
- $prev_line = false;
-
- $this->map = array();
- $this->gmail_map = array();
-
- // Parse file
- foreach (preg_split("/[\r\n]+/", $csv) as $line) {
- if (!empty($prev_line)) {
- $line = '"' . $line;
- }
-
- $elements = $this->parse_line($line);
-
- if (empty($elements)) {
- continue;
- }
-
- // Parse header
- if (empty($this->map)) {
- $this->parse_header($elements);
- if (empty($this->map)) {
- break;
- }
- }
- // Parse data row
- else {
- // handle multiline elements (e.g. Gmail)
- if (!empty($prev_line)) {
- $first = array_shift($elements);
-
- if ($first[0] == '"') {
- $prev_line[count($prev_line)-1] = '"' . $prev_line[count($prev_line)-1] . "\n" . substr($first, 1);
- }
- else {
- $prev_line[count($prev_line)-1] .= "\n" . $first;
- }
-
- $elements = array_merge($prev_line, $elements);
- }
-
- $last_element = $elements[count($elements)-1];
- if ($last_element[0] == '"') {
- $elements[count($elements)-1] = substr($last_element, 1);
- $prev_line = $elements;
- continue;
- }
- $this->csv_to_vcard($elements);
- $prev_line = false;
- }
- }
- }
-
- /**
- * @return array rcube_vcard List of vcards
- */
- public function export()
- {
- return $this->vcards;
- }
-
- /**
- * Parse CSV file line
- */
- protected function parse_line($line)
- {
- $line = trim($line);
- if (empty($line)) {
- return null;
- }
-
- $fields = rcube_utils::explode_quoted_string(',', $line);
-
- // remove quotes if needed
- if (!empty($fields)) {
- foreach ($fields as $idx => $value) {
- if (($len = strlen($value)) > 1 && $value[0] == '"' && $value[$len-1] == '"') {
- // remove surrounding quotes
- $value = substr($value, 1, -1);
- // replace doubled quotes inside the string with single quote
- $value = str_replace('""', '"', $value);
-
- $fields[$idx] = $value;
- }
- }
- }
-
- return $fields;
- }
-
- /**
- * Parse CSV header line, detect fields mapping
- */
- protected function parse_header($elements)
- {
- $map1 = array();
- $map2 = array();
- $size = count($elements);
-
- // check English labels
- for ($i = 0; $i < $size; $i++) {
- $label = $this->label_map[$elements[$i]];
- if ($label && !empty($this->csv2vcard_map[$label])) {
- $map1[$i] = $this->csv2vcard_map[$label];
- }
- }
-
- // check localized labels
- if (!empty($this->local_label_map)) {
- for ($i = 0; $i < $size; $i++) {
- $label = $this->local_label_map[$elements[$i]];
-
- // special localization label
- if ($label && $label[0] == '_') {
- $label = substr($label, 1);
- }
-
- if ($label && !empty($this->csv2vcard_map[$label])) {
- $map2[$i] = $this->csv2vcard_map[$label];
- }
- }
- }
-
- $this->map = count($map1) >= count($map2) ? $map1 : $map2;
-
- // support special Gmail format
- foreach ($this->gmail_label_map as $key => $items) {
- $num = 1;
- while (($_key = "$key $num - Type") && ($found = array_search($_key, $elements)) !== false) {
- $this->gmail_map["$key:$num"] = array('_key' => $key, '_idx' => $found);
- foreach (array_keys($items) as $item_key) {
- $_key = "$key $num - $item_key";
- if (($found = array_search($_key, $elements)) !== false) {
- $this->gmail_map["$key:$num"][$item_key] = $found;
- }
- }
-
- $num++;
- }
- }
- }
-
- /**
- * Convert CSV data row to vCard
- */
- protected function csv_to_vcard($data)
- {
- $contact = array();
- foreach ($this->map as $idx => $name) {
- $value = $data[$idx];
- if ($value !== null && $value !== '') {
- $contact[$name] = $value;
- }
- }
-
- // Gmail format support
- foreach ($this->gmail_map as $idx => $item) {
- $type = preg_replace('/[^a-z]/', '', strtolower($data[$item['_idx']]));
- $key = $item['_key'];
-
- unset($item['_idx']);
- unset($item['_key']);
-
- foreach ($item as $item_key => $item_idx) {
- $value = $data[$item_idx];
- if ($value !== null && $value !== '' && ($data_idx = $this->gmail_label_map[$key][$item_key][$type])) {
- $contact[$data_idx] = $value;
- }
- }
- }
-
- if (empty($contact)) {
- return;
- }
-
- // Handle special values
- if (!empty($contact['birthday-d']) && !empty($contact['birthday-m']) && !empty($contact['birthday-y'])) {
- $contact['birthday'] = $contact['birthday-y'] .'-' .$contact['birthday-m'] . '-' . $contact['birthday-d'];
- }
-
- if (!empty($contact['groups'])) {
- // categories/groups separator in vCard is ',' not ';'
- $contact['groups'] = str_replace(';', ',', $contact['groups']);
-
- // remove "* " added by GMail
- if (!empty($this->gmail_map)) {
- $contact['groups'] = str_replace('* ', '', $contact['groups']);
- }
- }
-
- // Empty dates, e.g. "0/0/00", "0000-00-00 00:00:00"
- foreach (array('birthday', 'anniversary') as $key) {
- if (!empty($contact[$key])) {
- $date = preg_replace('/[0[:^word:]]/', '', $contact[$key]);
- if (empty($date)) {
- unset($contact[$key]);
- }
- }
- }
-
- if (!empty($contact['gender']) && ($gender = strtolower($contact['gender']))) {
- if (!in_array($gender, array('male', 'female'))) {
- unset($contact['gender']);
- }
- }
-
- // Convert address(es) to rcube_vcard data
- foreach ($contact as $idx => $value) {
- $name = explode(':', $idx);
- if (in_array($name[0], array('street', 'locality', 'region', 'zipcode', 'country'))) {
- $contact['address:'.$name[1]][$name[0]] = $value;
- unset($contact[$idx]);
- }
- }
-
- // Create vcard object
- $vcard = new rcube_vcard();
- foreach ($contact as $name => $value) {
- $name = explode(':', $name);
- $vcard->set($name[0], $value, $name[1]);
- }
-
- // add to the list
- $this->vcards[] = $vcard;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_db.php b/lib/ext/Roundcube/rcube_db.php
deleted file mode 100644
index 3f372c2..0000000
--- a/lib/ext/Roundcube/rcube_db.php
+++ /dev/null
@@ -1,1348 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Database wrapper class that implements PHP PDO functions |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Database independent query interface.
- * This is a wrapper for the PHP PDO.
- *
- * @package Framework
- * @subpackage Database
- */
-class rcube_db
-{
- public $db_provider;
-
- protected $db_dsnw; // DSN for write operations
- protected $db_dsnr; // DSN for read operations
- protected $db_connected = false; // Already connected ?
- protected $db_mode; // Connection mode
- protected $dbh; // Connection handle
- protected $dbhs = array();
- protected $table_connections = array();
-
- protected $db_error = false;
- protected $db_error_msg = '';
- protected $conn_failure = false;
- protected $db_index = 0;
- protected $last_result;
- protected $tables;
- protected $variables;
-
- protected $options = array(
- // column/table quotes
- 'identifier_start' => '"',
- 'identifier_end' => '"',
- );
-
- const DEBUG_LINE_LENGTH = 4096;
- const DEFAULT_QUOTE = '`';
-
- /**
- * Factory, returns driver-specific instance of the class
- *
- * @param string $db_dsnw DSN for read/write operations
- * @param string $db_dsnr Optional DSN for read only operations
- * @param bool $pconn Enables persistent connections
- *
- * @return rcube_db Object instance
- */
- public static function factory($db_dsnw, $db_dsnr = '', $pconn = false)
- {
- $driver = strtolower(substr($db_dsnw, 0, strpos($db_dsnw, ':')));
- $driver_map = array(
- 'sqlite2' => 'sqlite',
- 'sybase' => 'mssql',
- 'dblib' => 'mssql',
- 'mysqli' => 'mysql',
- 'oci' => 'oracle',
- 'oci8' => 'oracle',
- );
-
- $driver = isset($driver_map[$driver]) ? $driver_map[$driver] : $driver;
- $class = "rcube_db_$driver";
-
- if (!$driver || !class_exists($class)) {
- rcube::raise_error(array('code' => 600, 'type' => 'db',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => "Configuration error. Unsupported database driver: $driver"),
- true, true);
- }
-
- return new $class($db_dsnw, $db_dsnr, $pconn);
- }
-
- /**
- * Object constructor
- *
- * @param string $db_dsnw DSN for read/write operations
- * @param string $db_dsnr Optional DSN for read only operations
- * @param bool $pconn Enables persistent connections
- */
- public function __construct($db_dsnw, $db_dsnr = '', $pconn = false)
- {
- if (empty($db_dsnr)) {
- $db_dsnr = $db_dsnw;
- }
-
- $this->db_dsnw = $db_dsnw;
- $this->db_dsnr = $db_dsnr;
- $this->db_pconn = $pconn;
-
- $this->db_dsnw_array = self::parse_dsn($db_dsnw);
- $this->db_dsnr_array = self::parse_dsn($db_dsnr);
-
- $config = rcube::get_instance()->config;
-
- $this->options['table_prefix'] = $config->get('db_prefix');
- $this->options['dsnw_noread'] = $config->get('db_dsnw_noread', false);
- $this->options['table_dsn_map'] = array_map(array($this, 'table_name'), $config->get('db_table_dsn', array()));
- }
-
- /**
- * Connect to specific database
- *
- * @param array $dsn DSN for DB connections
- * @param string $mode Connection mode (r|w)
- */
- protected function dsn_connect($dsn, $mode)
- {
- $this->db_error = false;
- $this->db_error_msg = null;
-
- // return existing handle
- if ($this->dbhs[$mode]) {
- $this->dbh = $this->dbhs[$mode];
- $this->db_mode = $mode;
- return $this->dbh;
- }
-
- // connect to database
- if ($dbh = $this->conn_create($dsn)) {
- $this->dbh = $dbh;
- $this->dbhs[$mode] = $dbh;
- $this->db_mode = $mode;
- $this->db_connected = true;
- }
- }
-
- /**
- * Create PDO connection
- */
- protected function conn_create($dsn)
- {
- // Get database specific connection options
- $dsn_string = $this->dsn_string($dsn);
- $dsn_options = $this->dsn_options($dsn);
-
- if ($this->db_pconn) {
- $dsn_options[PDO::ATTR_PERSISTENT] = true;
- }
-
- // Connect
- try {
- // with this check we skip fatal error on PDO object creation
- if (!class_exists('PDO', false)) {
- throw new Exception('PDO extension not loaded. See http://php.net/manual/en/intro.pdo.php');
- }
-
- $this->conn_prepare($dsn);
-
- $dbh = new PDO($dsn_string, $dsn['username'], $dsn['password'], $dsn_options);
-
- // don't throw exceptions or warnings
- $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
-
- $this->conn_configure($dsn, $dbh);
- }
- catch (Exception $e) {
- $this->db_error = true;
- $this->db_error_msg = $e->getMessage();
-
- rcube::raise_error(array('code' => 500, 'type' => 'db',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $this->db_error_msg), true, false);
-
- return null;
- }
-
- return $dbh;
- }
-
- /**
- * Driver-specific preparation of database connection
- *
- * @param array $dsn DSN for DB connections
- */
- protected function conn_prepare($dsn)
- {
- }
-
- /**
- * Driver-specific configuration of database connection
- *
- * @param array $dsn DSN for DB connections
- * @param PDO $dbh Connection handler
- */
- protected function conn_configure($dsn, $dbh)
- {
- }
-
- /**
- * Connect to appropriate database depending on the operation
- *
- * @param string $mode Connection mode (r|w)
- * @param boolean $force Enforce using the given mode
- */
- public function db_connect($mode, $force = false)
- {
- // 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 db with the same or "higher" mode (if allowed)
- if ($this->db_mode == $mode || $this->db_mode == 'w' && !$force && !$this->options['dsnw_noread']) {
- return;
- }
- }
-
- $dsn = ($mode == 'r') ? $this->db_dsnr_array : $this->db_dsnw_array;
- $this->dsn_connect($dsn, $mode);
-
- // use write-master when read-only fails
- if (!$this->db_connected && $mode == 'r' && $this->is_replicated()) {
- $this->dsn_connect($this->db_dsnw_array, 'w');
- }
-
- $this->conn_failure = !$this->db_connected;
- }
-
- /**
- * Analyze the given SQL statement and select the appropriate connection to use
- */
- protected function dsn_select($query)
- {
- // no replication
- if ($this->db_dsnw == $this->db_dsnr) {
- return 'w';
- }
-
- // Read or write ?
- $mode = preg_match('/^(select|show|set)/i', $query) ? 'r' : 'w';
-
- $start = '[' . $this->options['identifier_start'] . self::DEFAULT_QUOTE . ']';
- $end = '[' . $this->options['identifier_end'] . self::DEFAULT_QUOTE . ']';
- $regex = '/(?:^|\s)(from|update|into|join)\s+'.$start.'?([a-z0-9._]+)'.$end.'?\s+/i';
-
- // find tables involved in this query
- if (preg_match_all($regex, $query, $matches, PREG_SET_ORDER)) {
- foreach ($matches as $m) {
- $table = $m[2];
-
- // always use direct mapping
- if ($this->options['table_dsn_map'][$table]) {
- $mode = $this->options['table_dsn_map'][$table];
- break; // primary table rules
- }
- else if ($mode == 'r') {
- // connected to db with the same or "higher" mode for this table
- $db_mode = $this->table_connections[$table];
- if ($db_mode == 'w' && !$this->options['dsnw_noread']) {
- $mode = $db_mode;
- }
- }
- }
-
- // remember mode chosen (for primary table)
- $table = $matches[0][2];
- $this->table_connections[$table] = $mode;
- }
-
- return $mode;
- }
-
- /**
- * Activate/deactivate debug mode
- *
- * @param boolean $dbg True if SQL queries should be logged
- */
- public function set_debug($dbg = true)
- {
- $this->options['debug_mode'] = $dbg;
- }
-
- /**
- * Writes debug information/query to 'sql' log file
- *
- * @param string $query SQL query
- */
- protected function debug($query)
- {
- if ($this->options['debug_mode']) {
- if (($len = strlen($query)) > self::DEBUG_LINE_LENGTH) {
- $diff = $len - self::DEBUG_LINE_LENGTH;
- $query = substr($query, 0, self::DEBUG_LINE_LENGTH)
- . "... [truncated $diff bytes]";
- }
- rcube::write_log('sql', '[' . (++$this->db_index) . '] ' . $query . ';');
- }
- }
-
- /**
- * Getter for error state
- *
- * @param mixed $result Optional query result
- *
- * @return string Error message
- */
- public function is_error($result = null)
- {
- if ($result !== null) {
- return $result === false ? $this->db_error_msg : null;
- }
-
- return $this->db_error ? $this->db_error_msg : null;
- }
-
- /**
- * Connection state checker
- *
- * @return boolean True if in connected state
- */
- public function is_connected()
- {
- return !is_object($this->dbh) ? false : $this->db_connected;
- }
-
- /**
- * Is database replication configured?
- *
- * @return bool Returns true if dsnw != dsnr
- */
- public function is_replicated()
- {
- return !empty($this->db_dsnr) && $this->db_dsnw != $this->db_dsnr;
- }
-
- /**
- * Get database runtime variables
- *
- * @param string $varname Variable name
- * @param mixed $default Default value if variable is not set
- *
- * @return mixed Variable value or default
- */
- public function get_variable($varname, $default = null)
- {
- // to be implemented by driver class
- return $default;
- }
-
- /**
- * Execute a SQL query
- *
- * @param string SQL query to execute
- * @param mixed Values to be inserted in query
- *
- * @return number Query handle identifier
- */
- public function query()
- {
- $params = func_get_args();
- $query = array_shift($params);
-
- // Support one argument of type array, instead of n arguments
- if (count($params) == 1 && is_array($params[0])) {
- $params = $params[0];
- }
-
- return $this->_query($query, 0, 0, $params);
- }
-
- /**
- * Execute a SQL query with limits
- *
- * @param string SQL query to execute
- * @param int Offset for LIMIT statement
- * @param int Number of rows for LIMIT statement
- * @param mixed Values to be inserted in query
- *
- * @return PDOStatement|bool Query handle or False on error
- */
- public function limitquery()
- {
- $params = func_get_args();
- $query = array_shift($params);
- $offset = array_shift($params);
- $numrows = array_shift($params);
-
- return $this->_query($query, $offset, $numrows, $params);
- }
-
- /**
- * Execute a SQL query with limits
- *
- * @param string $query SQL query to execute
- * @param int $offset Offset for LIMIT statement
- * @param int $numrows Number of rows for LIMIT statement
- * @param array $params Values to be inserted in query
- *
- * @return PDOStatement|bool Query handle or False on error
- */
- protected function _query($query, $offset, $numrows, $params)
- {
- $query = ltrim($query);
-
- $this->db_connect($this->dsn_select($query), true);
-
- // check connection before proceeding
- if (!$this->is_connected()) {
- return $this->last_result = false;
- }
-
- if ($numrows || $offset) {
- $query = $this->set_limit($query, $numrows, $offset);
- }
-
- // replace self::DEFAULT_QUOTE with driver-specific quoting
- $query = $this->query_parse($query);
-
- // Because in Roundcube we mostly use queries that are
- // executed only once, we will not use prepared queries
- $pos = 0;
- $idx = 0;
-
- if (count($params)) {
- while ($pos = strpos($query, '?', $pos)) {
- if ($query[$pos+1] == '?') { // skip escaped '?'
- $pos += 2;
- }
- else {
- $val = $this->quote($params[$idx++]);
- unset($params[$idx-1]);
- $query = substr_replace($query, $val, $pos, 1);
- $pos += strlen($val);
- }
- }
- }
-
- // replace escaped '?' back to normal, see self::quote()
- $query = str_replace('??', '?', $query);
- $query = rtrim($query, " \t\n\r\0\x0B;");
-
- // log query
- $this->debug($query);
-
- return $this->query_execute($query);
- }
-
- /**
- * Query execution
- */
- protected function query_execute($query)
- {
- // destroy reference to previous result, required for SQLite driver (#1488874)
- $this->last_result = null;
- $this->db_error_msg = null;
-
- // send query
- $result = $this->dbh->query($query);
-
- if ($result === false) {
- $result = $this->handle_error($query);
- }
-
- return $this->last_result = $result;
- }
-
- /**
- * Parse SQL query and replace identifier quoting
- *
- * @param string $query SQL query
- *
- * @return string SQL query
- */
- protected function query_parse($query)
- {
- $start = $this->options['identifier_start'];
- $end = $this->options['identifier_end'];
- $quote = self::DEFAULT_QUOTE;
-
- if ($start == $quote) {
- return $query;
- }
-
- $pos = 0;
- $in = false;
-
- while ($pos = strpos($query, $quote, $pos)) {
- if ($query[$pos+1] == $quote) { // skip escaped quote
- $pos += 2;
- }
- else {
- if ($in) {
- $q = $end;
- $in = false;
- }
- else {
- $q = $start;
- $in = true;
- }
-
- $query = substr_replace($query, $q, $pos, 1);
- $pos++;
- }
- }
-
- // replace escaped quote back to normal, see self::quote()
- $query = str_replace($quote.$quote, $quote, $query);
-
- return $query;
- }
-
- /**
- * Helper method to handle DB errors.
- * This by default logs the error but could be overriden by a driver implementation
- *
- * @param string Query that triggered the error
- * @return mixed Result to be stored and returned
- */
- protected function handle_error($query)
- {
- $error = $this->dbh->errorInfo();
-
- if (empty($this->options['ignore_key_errors']) || !in_array($error[0], array('23000', '23505'))) {
- $this->db_error = true;
- $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]);
-
- rcube::raise_error(array('code' => 500, 'type' => 'db',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $this->db_error_msg . " (SQL Query: $query)"
- ), true, false);
- }
-
- return false;
- }
-
- /**
- * Get number of affected rows for the last query
- *
- * @param mixed $result Optional query handle
- *
- * @return int Number of (matching) rows
- */
- public function affected_rows($result = null)
- {
- if ($result || ($result === null && ($result = $this->last_result))) {
- if ($result !== true) {
- return $result->rowCount();
- }
- }
-
- return 0;
- }
-
- /**
- * Get number of rows for a SQL query
- * If no query handle is specified, the last query will be taken as reference
- *
- * @param mixed $result Optional query handle
- * @return mixed Number of rows or false on failure
- * @deprecated This method shows very poor performance and should be avoided.
- */
- public function num_rows($result = null)
- {
- if (($result || ($result === null && ($result = $this->last_result))) && $result !== true) {
- // repeat query with SELECT COUNT(*) ...
- if (preg_match('/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/ims', $result->queryString, $m)) {
- $query = $this->dbh->query('SELECT COUNT(*) FROM ' . $m[1], PDO::FETCH_NUM);
- return $query ? intval($query->fetchColumn(0)) : false;
- }
- else {
- $num = count($result->fetchAll());
- $result->execute(); // re-execute query because there's no seek(0)
- return $num;
- }
- }
-
- return false;
- }
-
- /**
- * Get last inserted record ID
- *
- * @param string $table Table name (to find the incremented sequence)
- *
- * @return mixed ID or false on failure
- */
- public function insert_id($table = '')
- {
- if (!$this->db_connected || $this->db_mode == 'r') {
- return false;
- }
-
- if ($table) {
- // resolve table name
- $table = $this->table_name($table);
- }
-
- $id = $this->dbh->lastInsertId($table);
-
- return $id;
- }
-
- /**
- * Get an associative array for one row
- * If no query handle is specified, the last query will be taken as reference
- *
- * @param mixed $result Optional query handle
- *
- * @return mixed Array with col values or false on failure
- */
- public function fetch_assoc($result = null)
- {
- return $this->_fetch_row($result, PDO::FETCH_ASSOC);
- }
-
- /**
- * Get an index array for one row
- * If no query handle is specified, the last query will be taken as reference
- *
- * @param mixed $result Optional query handle
- *
- * @return mixed Array with col values or false on failure
- */
- public function fetch_array($result = null)
- {
- return $this->_fetch_row($result, PDO::FETCH_NUM);
- }
-
- /**
- * Get col values for a result row
- *
- * @param mixed $result Optional query handle
- * @param int $mode Fetch mode identifier
- *
- * @return mixed Array with col values or false on failure
- */
- protected function _fetch_row($result, $mode)
- {
- if ($result || ($result === null && ($result = $this->last_result))) {
- if ($result !== true) {
- return $result->fetch($mode);
- }
- }
-
- return false;
- }
-
- /**
- * Adds LIMIT,OFFSET clauses to the query
- *
- * @param string $query SQL query
- * @param int $limit Number of rows
- * @param int $offset Offset
- *
- * @return string SQL query
- */
- protected function set_limit($query, $limit = 0, $offset = 0)
- {
- if ($limit) {
- $query .= ' LIMIT ' . intval($limit);
- }
-
- if ($offset) {
- $query .= ' OFFSET ' . intval($offset);
- }
-
- return $query;
- }
-
- /**
- * Returns list of tables in a database
- *
- * @return array List of all tables of the current database
- */
- public function list_tables()
- {
- // get tables if not cached
- if ($this->tables === null) {
- $q = $this->query('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES ORDER BY TABLE_NAME');
-
- if ($q) {
- $this->tables = $q->fetchAll(PDO::FETCH_COLUMN, 0);
- }
- else {
- $this->tables = array();
- }
- }
-
- return $this->tables;
- }
-
- /**
- * Returns list of columns in database table
- *
- * @param string $table Table name
- *
- * @return array List of table cols
- */
- public function list_cols($table)
- {
- $q = $this->query('SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ?',
- array($table));
-
- if ($q) {
- return $q->fetchAll(PDO::FETCH_COLUMN, 0);
- }
-
- return array();
- }
-
- /**
- * Start transaction
- *
- * @return bool True on success, False on failure
- */
- public function startTransaction()
- {
- $this->db_connect('w', true);
-
- // check connection before proceeding
- if (!$this->is_connected()) {
- return $this->last_result = false;
- }
-
- $this->debug('BEGIN TRANSACTION');
-
- return $this->last_result = $this->dbh->beginTransaction();
- }
-
- /**
- * Commit transaction
- *
- * @return bool True on success, False on failure
- */
- public function endTransaction()
- {
- $this->db_connect('w', true);
-
- // check connection before proceeding
- if (!$this->is_connected()) {
- return $this->last_result = false;
- }
-
- $this->debug('COMMIT TRANSACTION');
-
- return $this->last_result = $this->dbh->commit();
- }
-
- /**
- * Rollback transaction
- *
- * @return bool True on success, False on failure
- */
- public function rollbackTransaction()
- {
- $this->db_connect('w', true);
-
- // check connection before proceeding
- if (!$this->is_connected()) {
- return $this->last_result = false;
- }
-
- $this->debug('ROLLBACK TRANSACTION');
-
- return $this->last_result = $this->dbh->rollBack();
- }
-
- /**
- * Terminate database connection.
- */
- public function closeConnection()
- {
- $this->db_connected = false;
- $this->db_index = 0;
-
- // release statement and connection resources
- $this->last_result = null;
- $this->dbh = null;
- $this->dbhs = array();
- }
-
- /**
- * Formats input so it can be safely used in a query
- *
- * @param mixed $input Value to quote
- * @param string $type Type of data (integer, bool, ident)
- *
- * @return string Quoted/converted string for use in query
- */
- public function quote($input, $type = null)
- {
- // handle int directly for better performance
- if ($type == 'integer' || $type == 'int') {
- return intval($input);
- }
-
- if (is_null($input)) {
- return 'NULL';
- }
-
- if ($type == 'ident') {
- return $this->quote_identifier($input);
- }
-
- // create DB handle if not available
- if (!$this->dbh) {
- $this->db_connect('r');
- }
-
- if ($this->dbh) {
- $map = array(
- 'bool' => PDO::PARAM_BOOL,
- 'integer' => PDO::PARAM_INT,
- );
-
- $type = isset($map[$type]) ? $map[$type] : PDO::PARAM_STR;
-
- return strtr($this->dbh->quote($input, $type),
- // escape ? and `
- array('?' => '??', self::DEFAULT_QUOTE => self::DEFAULT_QUOTE.self::DEFAULT_QUOTE)
- );
- }
-
- return 'NULL';
- }
-
- /**
- * Escapes a string so it can be safely used in a query
- *
- * @param string $str A string to escape
- *
- * @return string Escaped string for use in a query
- */
- public function escape($str)
- {
- if (is_null($str)) {
- return 'NULL';
- }
-
- return substr($this->quote($str), 1, -1);
- }
-
- /**
- * Quotes a string so it can be safely used as a table or column name
- *
- * @param string $str Value to quote
- *
- * @return string Quoted string for use in query
- * @deprecated Replaced by rcube_db::quote_identifier
- * @see rcube_db::quote_identifier
- */
- public function quoteIdentifier($str)
- {
- return $this->quote_identifier($str);
- }
-
- /**
- * Escapes a string so it can be safely used in a query
- *
- * @param string $str A string to escape
- *
- * @return string Escaped string for use in a query
- * @deprecated Replaced by rcube_db::escape
- * @see rcube_db::escape
- */
- public function escapeSimple($str)
- {
- return $this->escape($str);
- }
-
- /**
- * Quotes a string so it can be safely used as a table or column name
- *
- * @param string $str Value to quote
- *
- * @return string Quoted string for use in query
- */
- public function quote_identifier($str)
- {
- $start = $this->options['identifier_start'];
- $end = $this->options['identifier_end'];
- $name = array();
-
- foreach (explode('.', $str) as $elem) {
- $elem = str_replace(array($start, $end), '', $elem);
- $name[] = $start . $elem . $end;
- }
-
- return implode($name, '.');
- }
-
- /**
- * Return SQL function for current time and date
- *
- * @param int $interval Optional interval (in seconds) to add/subtract
- *
- * @return string SQL function to use in query
- */
- public function now($interval = 0)
- {
- if ($interval) {
- $add = ' ' . ($interval > 0 ? '+' : '-') . ' INTERVAL ';
- $add .= $interval > 0 ? intval($interval) : intval($interval) * -1;
- $add .= ' SECOND';
- }
-
- return "now()" . $add;
- }
-
- /**
- * Return list of elements for use with SQL's IN clause
- *
- * @param array $arr Input array
- * @param string $type Type of data (integer, bool, ident)
- *
- * @return string Comma-separated list of quoted values for use in query
- */
- public function array2list($arr, $type = null)
- {
- if (!is_array($arr)) {
- return $this->quote($arr, $type);
- }
-
- foreach ($arr as $idx => $item) {
- $arr[$idx] = $this->quote($item, $type);
- }
-
- return implode(',', $arr);
- }
-
- /**
- * Return SQL statement to convert a field value into a unix timestamp
- *
- * This method is deprecated and should not be used anymore due to limitations
- * of timestamp functions in Mysql (year 2038 problem)
- *
- * @param string $field Field name
- *
- * @return string SQL statement to use in query
- * @deprecated
- */
- public function unixtimestamp($field)
- {
- return "UNIX_TIMESTAMP($field)";
- }
-
- /**
- * Return SQL statement to convert from a unix timestamp
- *
- * @param int $timestamp Unix timestamp
- *
- * @return string Date string in db-specific format
- */
- public function fromunixtime($timestamp)
- {
- return date("'Y-m-d H:i:s'", $timestamp);
- }
-
- /**
- * Return SQL statement for case insensitive LIKE
- *
- * @param string $column Field name
- * @param string $value Search value
- *
- * @return string SQL statement to use in query
- */
- public function ilike($column, $value)
- {
- return $this->quote_identifier($column).' LIKE '.$this->quote($value);
- }
-
- /**
- * Abstract SQL statement for value concatenation
- *
- * @return string SQL statement to be used in query
- */
- public function concat(/* col1, col2, ... */)
- {
- $args = func_get_args();
- if (is_array($args[0])) {
- $args = $args[0];
- }
-
- return '(' . join(' || ', $args) . ')';
- }
-
- /**
- * Encodes non-UTF-8 characters in string/array/object (recursive)
- *
- * @param mixed $input Data to fix
- * @param bool $serialized Enable serialization
- *
- * @return mixed Properly UTF-8 encoded data
- */
- public static function encode($input, $serialized = false)
- {
- // use Base64 encoding to workaround issues with invalid
- // or null characters in serialized string (#1489142)
- if ($serialized) {
- return base64_encode(serialize($input));
- }
-
- if (is_object($input)) {
- foreach (get_object_vars($input) as $idx => $value) {
- $input->$idx = self::encode($value);
- }
- return $input;
- }
- else if (is_array($input)) {
- foreach ($input as $idx => $value) {
- $input[$idx] = self::encode($value);
- }
-
- return $input;
- }
-
- return utf8_encode($input);
- }
-
- /**
- * Decodes encoded UTF-8 string/object/array (recursive)
- *
- * @param mixed $input Input data
- * @param bool $serialized Enable serialization
- *
- * @return mixed Decoded data
- */
- public static function decode($input, $serialized = false)
- {
- // use Base64 encoding to workaround issues with invalid
- // or null characters in serialized string (#1489142)
- if ($serialized) {
- // Keep backward compatybility where base64 wasn't used
- if (strpos(substr($input, 0, 16), ':') !== false) {
- return self::decode(@unserialize($input));
- }
-
- return @unserialize(base64_decode($input));
- }
-
- if (is_object($input)) {
- foreach (get_object_vars($input) as $idx => $value) {
- $input->$idx = self::decode($value);
- }
- return $input;
- }
- else if (is_array($input)) {
- foreach ($input as $idx => $value) {
- $input[$idx] = self::decode($value);
- }
- return $input;
- }
-
- return utf8_decode($input);
- }
-
- /**
- * Return correct name for a specific database table
- *
- * @param string $table Table name
- * @param bool $quoted Quote table identifier
- *
- * @return string Translated table name
- */
- public function table_name($table, $quoted = false)
- {
- // let plugins alter the table name (#1489837)
- $plugin = rcube::get_instance()->plugins->exec_hook('db_table_name', array('table' => $table));
- $table = $plugin['table'];
-
- // add prefix to the table name if configured
- if (($prefix = $this->options['table_prefix']) && strpos($table, $prefix) !== 0) {
- $table = $prefix . $table;
- }
-
- if ($quoted) {
- $table = $this->quote_identifier($table);
- }
-
- return $table;
- }
-
- /**
- * Set class option value
- *
- * @param string $name Option name
- * @param mixed $value Option value
- */
- public function set_option($name, $value)
- {
- $this->options[$name] = $value;
- }
-
- /**
- * Set DSN connection to be used for the given table
- *
- * @param string Table name
- * @param string DSN connection ('r' or 'w') to be used
- */
- public function set_table_dsn($table, $mode)
- {
- $this->options['table_dsn_map'][$this->table_name($table)] = $mode;
- }
-
- /**
- * MDB2 DSN string parser
- *
- * @param string $sequence Secuence name
- *
- * @return array DSN parameters
- */
- public static function parse_dsn($dsn)
- {
- if (empty($dsn)) {
- return null;
- }
-
- // Find phptype and dbsyntax
- if (($pos = strpos($dsn, '://')) !== false) {
- $str = substr($dsn, 0, $pos);
- $dsn = substr($dsn, $pos + 3);
- }
- else {
- $str = $dsn;
- $dsn = null;
- }
-
- // Get phptype and dbsyntax
- // $str => phptype(dbsyntax)
- if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
- $parsed['phptype'] = $arr[1];
- $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2];
- }
- else {
- $parsed['phptype'] = $str;
- $parsed['dbsyntax'] = $str;
- }
-
- if (empty($dsn)) {
- return $parsed;
- }
-
- // Get (if found): username and password
- // $dsn => username:password@protocol+hostspec/database
- if (($at = strrpos($dsn,'@')) !== false) {
- $str = substr($dsn, 0, $at);
- $dsn = substr($dsn, $at + 1);
- if (($pos = strpos($str, ':')) !== false) {
- $parsed['username'] = rawurldecode(substr($str, 0, $pos));
- $parsed['password'] = rawurldecode(substr($str, $pos + 1));
- }
- else {
- $parsed['username'] = rawurldecode($str);
- }
- }
-
- // Find protocol and hostspec
-
- // $dsn => proto(proto_opts)/database
- if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) {
- $proto = $match[1];
- $proto_opts = $match[2] ? $match[2] : false;
- $dsn = $match[3];
- }
- // $dsn => protocol+hostspec/database (old format)
- else {
- if (strpos($dsn, '+') !== false) {
- list($proto, $dsn) = explode('+', $dsn, 2);
- }
- if ( strpos($dsn, '//') === 0
- && strpos($dsn, '/', 2) !== false
- && $parsed['phptype'] == 'oci8'
- ) {
- //oracle's "Easy Connect" syntax:
- //"username/password@[//]host[:port][/service_name]"
- //e.g. "scott/tiger@//mymachine:1521/oracle"
- $proto_opts = $dsn;
- $pos = strrpos($proto_opts, '/');
- $dsn = substr($proto_opts, $pos + 1);
- $proto_opts = substr($proto_opts, 0, $pos);
- }
- else if (strpos($dsn, '/') !== false) {
- list($proto_opts, $dsn) = explode('/', $dsn, 2);
- }
- else {
- $proto_opts = $dsn;
- $dsn = null;
- }
- }
-
- // process the different protocol options
- $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp';
- $proto_opts = rawurldecode($proto_opts);
- if (strpos($proto_opts, ':') !== false) {
- list($proto_opts, $parsed['port']) = explode(':', $proto_opts);
- }
- if ($parsed['protocol'] == 'tcp') {
- $parsed['hostspec'] = $proto_opts;
- }
- else if ($parsed['protocol'] == 'unix') {
- $parsed['socket'] = $proto_opts;
- }
-
- // Get dabase if any
- // $dsn => database
- if ($dsn) {
- // /database
- if (($pos = strpos($dsn, '?')) === false) {
- $parsed['database'] = rawurldecode($dsn);
- // /database?param1=value1&param2=value2
- }
- else {
- $parsed['database'] = rawurldecode(substr($dsn, 0, $pos));
- $dsn = substr($dsn, $pos + 1);
- if (strpos($dsn, '&') !== false) {
- $opts = explode('&', $dsn);
- }
- else { // database?param1=value1
- $opts = array($dsn);
- }
- foreach ($opts as $opt) {
- list($key, $value) = explode('=', $opt);
- if (!array_key_exists($key, $parsed) || false === $parsed[$key]) {
- // don't allow params overwrite
- $parsed[$key] = rawurldecode($value);
- }
- }
- }
- }
-
- return $parsed;
- }
-
- /**
- * Returns PDO DSN string from DSN array
- *
- * @param array $dsn DSN parameters
- *
- * @return string DSN string
- */
- protected function dsn_string($dsn)
- {
- $params = array();
- $result = $dsn['phptype'] . ':';
-
- if ($dsn['hostspec']) {
- $params[] = 'host=' . $dsn['hostspec'];
- }
-
- if ($dsn['port']) {
- $params[] = 'port=' . $dsn['port'];
- }
-
- if ($dsn['database']) {
- $params[] = 'dbname=' . $dsn['database'];
- }
-
- if (!empty($params)) {
- $result .= implode(';', $params);
- }
-
- return $result;
- }
-
- /**
- * Returns driver-specific connection options
- *
- * @param array $dsn DSN parameters
- *
- * @return array Connection options
- */
- protected function dsn_options($dsn)
- {
- $result = array();
-
- return $result;
- }
-
- /**
- * Execute the given SQL script
- *
- * @param string SQL queries to execute
- *
- * @return boolen True on success, False on error
- */
- public function exec_script($sql)
- {
- $sql = $this->fix_table_names($sql);
- $buff = '';
-
- foreach (explode("\n", $sql) as $line) {
- if (preg_match('/^--/', $line) || trim($line) == '')
- continue;
-
- $buff .= $line . "\n";
- if (preg_match('/(;|^GO)$/', trim($line))) {
- $this->query($buff);
- $buff = '';
- if ($this->db_error) {
- break;
- }
- }
- }
-
- return !$this->db_error;
- }
-
- /**
- * Parse SQL file and fix table names according to table prefix
- */
- protected function fix_table_names($sql)
- {
- if (!$this->options['table_prefix']) {
- return $sql;
- }
-
- $sql = preg_replace_callback(
- '/((TABLE|TRUNCATE|(?<!ON )UPDATE|INSERT INTO|FROM'
- . '| ON(?! (DELETE|UPDATE))|REFERENCES|CONSTRAINT|FOREIGN KEY|INDEX)'
- . '\s+(IF (NOT )?EXISTS )?[`"]*)([^`"\( \r\n]+)/',
- array($this, 'fix_table_names_callback'),
- $sql
- );
-
- return $sql;
- }
-
- /**
- * Preg_replace callback for fix_table_names()
- */
- protected function fix_table_names_callback($matches)
- {
- return $matches[1] . $this->options['table_prefix'] . $matches[count($matches)-1];
- }
-}
diff --git a/lib/ext/Roundcube/rcube_db_mssql.php b/lib/ext/Roundcube/rcube_db_mssql.php
deleted file mode 100644
index 4138b14..0000000
--- a/lib/ext/Roundcube/rcube_db_mssql.php
+++ /dev/null
@@ -1,190 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Database wrapper class that implements PHP PDO functions |
- | for MS SQL Server database |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Database independent query interface
- * This is a wrapper for the PHP PDO
- *
- * @package Framework
- * @subpackage Database
- */
-class rcube_db_mssql extends rcube_db
-{
- public $db_provider = 'mssql';
-
- /**
- * Object constructor
- *
- * @param string $db_dsnw DSN for read/write operations
- * @param string $db_dsnr Optional DSN for read only operations
- * @param bool $pconn Enables persistent connections
- */
- public function __construct($db_dsnw, $db_dsnr = '', $pconn = false)
- {
- parent::__construct($db_dsnw, $db_dsnr, $pconn);
-
- $this->options['identifier_start'] = '[';
- $this->options['identifier_end'] = ']';
- }
-
- /**
- * Driver-specific configuration of database connection
- *
- * @param array $dsn DSN for DB connections
- * @param PDO $dbh Connection handler
- */
- protected function conn_configure($dsn, $dbh)
- {
- // Set date format in case of non-default language (#1488918)
- $dbh->query("SET DATEFORMAT ymd");
- }
-
- /**
- * Return SQL function for current time and date
- *
- * @param int $interval Optional interval (in seconds) to add/subtract
- *
- * @return string SQL function to use in query
- */
- public function now($interval = 0)
- {
- if ($interval) {
- $interval = intval($interval);
- return "dateadd(second, $interval, getdate())";
- }
-
- return "getdate()";
- }
-
- /**
- * Return SQL statement to convert a field value into a unix timestamp
- *
- * @param string $field Field name
- *
- * @return string SQL statement to use in query
- * @deprecated
- */
- public function unixtimestamp($field)
- {
- return "DATEDIFF(second, '19700101', $field) + DATEDIFF(second, GETDATE(), GETUTCDATE())";
- }
-
- /**
- * Abstract SQL statement for value concatenation
- *
- * @return string SQL statement to be used in query
- */
- public function concat(/* col1, col2, ... */)
- {
- $args = func_get_args();
-
- if (is_array($args[0])) {
- $args = $args[0];
- }
-
- return '(' . join('+', $args) . ')';
- }
-
- /**
- * Adds TOP (LIMIT,OFFSET) clause to the query
- *
- * @param string $query SQL query
- * @param int $limit Number of rows
- * @param int $offset Offset
- *
- * @return string SQL query
- */
- protected function set_limit($query, $limit = 0, $offset = 0)
- {
- $limit = intval($limit);
- $offset = intval($offset);
- $end = $offset + $limit;
-
- // query without OFFSET
- if (!$offset) {
- $query = preg_replace('/^SELECT\s/i', "SELECT TOP $limit ", $query);
- return $query;
- }
-
- $orderby = stristr($query, 'ORDER BY');
- $offset += 1;
-
- if ($orderby !== false) {
- $query = trim(substr($query, 0, -1 * strlen($orderby)));
- }
- else {
- // it shouldn't happen, paging without sorting has not much sense
- // @FIXME: I don't know how to build paging query without ORDER BY
- $orderby = "ORDER BY 1";
- }
-
- $query = preg_replace('/^SELECT\s/i', '', $query);
- $query = "WITH paging AS (SELECT ROW_NUMBER() OVER ($orderby) AS [RowNumber], $query)"
- . " SELECT * FROM paging WHERE [RowNumber] BETWEEN $offset AND $end ORDER BY [RowNumber]";
-
- return $query;
- }
-
- /**
- * Returns PDO DSN string from DSN array
- */
- protected function dsn_string($dsn)
- {
- $params = array();
- $result = $dsn['phptype'] . ':';
-
- if ($dsn['hostspec']) {
- $host = $dsn['hostspec'];
- if ($dsn['port']) {
- $host .= ',' . $dsn['port'];
- }
- $params[] = 'host=' . $host;
- }
-
- if ($dsn['database']) {
- $params[] = 'dbname=' . $dsn['database'];
- }
-
- if (!empty($params)) {
- $result .= implode(';', $params);
- }
-
- return $result;
- }
-
- /**
- * Parse SQL file and fix table names according to table prefix
- */
- protected function fix_table_names($sql)
- {
- if (!$this->options['table_prefix']) {
- return $sql;
- }
-
- // replace sequence names, and other postgres-specific commands
- $sql = preg_replace_callback(
- '/((TABLE|(?<!ON )UPDATE|INSERT INTO|FROM(?! deleted)| ON(?! (DELETE|UPDATE|\[PRIMARY\]))'
- . '|REFERENCES|CONSTRAINT|TRIGGER|INDEX)\s+(\[dbo\]\.)?[\[\]]*)([^\[\]\( \r\n]+)/',
- array($this, 'fix_table_names_callback'),
- $sql
- );
-
- return $sql;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_db_mysql.php b/lib/ext/Roundcube/rcube_db_mysql.php
deleted file mode 100644
index 400813d..0000000
--- a/lib/ext/Roundcube/rcube_db_mysql.php
+++ /dev/null
@@ -1,200 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Database wrapper class that implements PHP PDO functions |
- | for MySQL database |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Database independent query interface
- *
- * This is a wrapper for the PHP PDO
- *
- * @package Framework
- * @subpackage Database
- */
-class rcube_db_mysql extends rcube_db
-{
- public $db_provider = 'mysql';
-
- /**
- * Object constructor
- *
- * @param string $db_dsnw DSN for read/write operations
- * @param string $db_dsnr Optional DSN for read only operations
- * @param bool $pconn Enables persistent connections
- */
- public function __construct($db_dsnw, $db_dsnr = '', $pconn = false)
- {
- parent::__construct($db_dsnw, $db_dsnr, $pconn);
-
- // SQL identifiers quoting
- $this->options['identifier_start'] = '`';
- $this->options['identifier_end'] = '`';
- }
-
- /**
- * Driver-specific configuration of database connection
- *
- * @param array $dsn DSN for DB connections
- * @param PDO $dbh Connection handler
- */
- protected function conn_configure($dsn, $dbh)
- {
- $dbh->query("SET NAMES 'utf8'");
- }
-
- /**
- * Abstract SQL statement for value concatenation
- *
- * @return string SQL statement to be used in query
- */
- public function concat(/* col1, col2, ... */)
- {
- $args = func_get_args();
-
- if (is_array($args[0])) {
- $args = $args[0];
- }
-
- return 'CONCAT(' . join(', ', $args) . ')';
- }
-
- /**
- * Returns PDO DSN string from DSN array
- *
- * @param array $dsn DSN parameters
- *
- * @return string Connection string
- */
- protected function dsn_string($dsn)
- {
- $params = array();
- $result = 'mysql:';
-
- if ($dsn['database']) {
- $params[] = 'dbname=' . $dsn['database'];
- }
-
- if ($dsn['hostspec']) {
- $params[] = 'host=' . $dsn['hostspec'];
- }
-
- if ($dsn['port']) {
- $params[] = 'port=' . $dsn['port'];
- }
-
- if ($dsn['socket']) {
- $params[] = 'unix_socket=' . $dsn['socket'];
- }
-
- $params[] = 'charset=utf8';
-
- if (!empty($params)) {
- $result .= implode(';', $params);
- }
-
- return $result;
- }
-
- /**
- * Returns driver-specific connection options
- *
- * @param array $dsn DSN parameters
- *
- * @return array Connection options
- */
- protected function dsn_options($dsn)
- {
- $result = array();
-
- if (!empty($dsn['key'])) {
- $result[PDO::MYSQL_ATTR_SSL_KEY] = $dsn['key'];
- }
-
- if (!empty($dsn['cipher'])) {
- $result[PDO::MYSQL_ATTR_SSL_CIPHER] = $dsn['cipher'];
- }
-
- if (!empty($dsn['cert'])) {
- $result[PDO::MYSQL_ATTR_SSL_CERT] = $dsn['cert'];
- }
-
- if (!empty($dsn['capath'])) {
- $result[PDO::MYSQL_ATTR_SSL_CAPATH] = $dsn['capath'];
- }
-
- if (!empty($dsn['ca'])) {
- $result[PDO::MYSQL_ATTR_SSL_CA] = $dsn['ca'];
- }
-
- // Always return matching (not affected only) rows count
- $result[PDO::MYSQL_ATTR_FOUND_ROWS] = true;
-
- // Enable AUTOCOMMIT mode (#1488902)
- $result[PDO::ATTR_AUTOCOMMIT] = true;
-
- return $result;
- }
-
- /**
- * Get database runtime variables
- *
- * @param string $varname Variable name
- * @param mixed $default Default value if variable is not set
- *
- * @return mixed Variable value or default
- */
- public function get_variable($varname, $default = null)
- {
- if (!isset($this->variables)) {
- $this->variables = array();
-
- $result = $this->query('SHOW VARIABLES');
-
- while ($row = $this->fetch_array($result)) {
- $this->variables[$row[0]] = $row[1];
- }
- }
-
- return isset($this->variables[$varname]) ? $this->variables[$varname] : $default;
- }
-
- /**
- * Handle DB errors, re-issue the query on deadlock errors from InnoDB row-level locking
- *
- * @param string Query that triggered the error
- * @return mixed Result to be stored and returned
- */
- protected function handle_error($query)
- {
- $error = $this->dbh->errorInfo();
-
- // retry after "Deadlock found when trying to get lock" errors
- $retries = 2;
- while ($error[1] == 1213 && $retries >= 0) {
- usleep(50000); // wait 50 ms
- $result = $this->dbh->query($query);
- if ($result !== false) {
- return $result;
- }
- $error = $this->dbh->errorInfo();
- $retries--;
- }
-
- return parent::handle_error($query);
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_db_oracle.php b/lib/ext/Roundcube/rcube_db_oracle.php
deleted file mode 100644
index 35d5083..0000000
--- a/lib/ext/Roundcube/rcube_db_oracle.php
+++ /dev/null
@@ -1,613 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2011-2014, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Database wrapper class that implements database functions |
- | for Oracle database using OCI8 extension |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <machniak@kolabsys.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Database independent query interface
- *
- * @package Framework
- * @subpackage Database
- */
-class rcube_db_oracle extends rcube_db
-{
- public $db_provider = 'oracle';
-
-
- /**
- * Create connection instance
- */
- protected function conn_create($dsn)
- {
- // Get database specific connection options
- $dsn_options = $this->dsn_options($dsn);
-
- $function = $this->db_pconn ? 'oci_pconnect' : 'oci_connect';
-
- if (!function_exists($function)) {
- $this->db_error = true;
- $this->db_error_msg = 'OCI8 extension not loaded. See http://php.net/manual/en/book.oci8.php';
-
- rcube::raise_error(array('code' => 500, 'type' => 'db',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $this->db_error_msg), true, false);
-
- return;
- }
-
- // connect
- $dbh = @$function($dsn['username'], $dsn['password'], $dsn_options['database'], $dsn_options['charset']);
-
- if (!$dbh) {
- $error = oci_error();
- $this->db_error = true;
- $this->db_error_msg = $error['message'];
-
- rcube::raise_error(array('code' => 500, 'type' => 'db',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $this->db_error_msg), true, false);
-
- return;
- }
-
- // configure session
- $this->conn_configure($dsn, $dbh);
-
- return $dbh;
- }
-
- /**
- * Driver-specific configuration of database connection
- *
- * @param array $dsn DSN for DB connections
- * @param PDO $dbh Connection handler
- */
- protected function conn_configure($dsn, $dbh)
- {
- $init_queries = array(
- "ALTER SESSION SET nls_date_format = 'YYYY-MM-DD'",
- "ALTER SESSION SET nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'",
- );
-
- foreach ($init_queries as $query) {
- $stmt = oci_parse($dbh, $query);
- oci_execute($stmt);
- }
- }
-
- /**
- * Connection state checker
- *
- * @return boolean True if in connected state
- */
- public function is_connected()
- {
- return empty($this->dbh) ? false : $this->db_connected;
- }
-
- /**
- * Execute a SQL query with limits
- *
- * @param string $query SQL query to execute
- * @param int $offset Offset for LIMIT statement
- * @param int $numrows Number of rows for LIMIT statement
- * @param array $params Values to be inserted in query
- *
- * @return PDOStatement|bool Query handle or False on error
- */
- protected function _query($query, $offset, $numrows, $params)
- {
- $query = ltrim($query);
-
- $this->db_connect($this->dsn_select($query), true);
-
- // check connection before proceeding
- if (!$this->is_connected()) {
- return $this->last_result = false;
- }
-
- if ($numrows || $offset) {
- $query = $this->set_limit($query, $numrows, $offset);
- }
-
- // replace self::DEFAULT_QUOTE with driver-specific quoting
- $query = $this->query_parse($query);
-
- // Because in Roundcube we mostly use queries that are
- // executed only once, we will not use prepared queries
- $pos = 0;
- $idx = 0;
- $args = array();
-
- if (count($params)) {
- while ($pos = strpos($query, '?', $pos)) {
- if ($query[$pos+1] == '?') { // skip escaped '?'
- $pos += 2;
- }
- else {
- $val = $this->quote($params[$idx++]);
-
- // long strings are not allowed inline, need to be parametrized
- if (strlen($val) > 4000) {
- $key = ':param' . (count($args) + 1);
- $args[$key] = $params[$idx-1];
- $val = $key;
- }
-
- unset($params[$idx-1]);
- $query = substr_replace($query, $val, $pos, 1);
- $pos += strlen($val);
- }
- }
- }
-
- // replace escaped '?' back to normal, see self::quote()
- $query = str_replace('??', '?', $query);
- $query = rtrim($query, " \t\n\r\0\x0B;");
-
- // log query
- $this->debug($query);
-
- // destroy reference to previous result
- $this->last_result = null;
- $this->db_error_msg = null;
-
- // prepare query
- $result = @oci_parse($this->dbh, $query);
- $mode = $this->in_transaction ? OCI_NO_AUTO_COMMIT : OCI_COMMIT_ON_SUCCESS;
-
- if ($result) {
- foreach ($args as $param => $arg) {
- oci_bind_by_name($result, $param, $args[$param], -1, SQLT_LNG);
- }
- }
-
- // execute query
- if (!$result || !@oci_execute($result, $mode)) {
- $result = $this->handle_error($query, $result);
- }
-
- return $this->last_result = $result;
- }
-
- /**
- * Helper method to handle DB errors.
- * This by default logs the error but could be overriden by a driver implementation
- *
- * @param string Query that triggered the error
- * @return mixed Result to be stored and returned
- */
- protected function handle_error($query, $result = null)
- {
- $error = oci_error(is_resource($result) ? $result : $this->dbh);
-
- // @TODO: Find error codes for key errors
- if (empty($this->options['ignore_key_errors']) || !in_array($error['code'], array('23000', '23505'))) {
- $this->db_error = true;
- $this->db_error_msg = sprintf('[%s] %s', $error['code'], $error['message']);
-
- rcube::raise_error(array('code' => 500, 'type' => 'db',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $this->db_error_msg . " (SQL Query: $query)"
- ), true, false);
- }
-
- return false;
- }
-
- /**
- * Get last inserted record ID
- *
- * @param string $table Table name (to find the incremented sequence)
- *
- * @return mixed ID or false on failure
- */
- public function insert_id($table = null)
- {
- if (!$this->db_connected || $this->db_mode == 'r' || empty($table)) {
- return false;
- }
-
- $sequence = $this->quote_identifier($this->sequence_name($table));
- $result = $this->query("SELECT $sequence.currval FROM dual");
- $result = $this->fetch_array($result);
-
- return $result[0] ?: false;
- }
-
- /**
- * Get number of affected rows for the last query
- *
- * @param mixed $result Optional query handle
- *
- * @return int Number of (matching) rows
- */
- public function affected_rows($result = null)
- {
- if ($result || ($result === null && ($result = $this->last_result))) {
- return oci_num_rows($result);
- }
-
- return 0;
- }
-
- /**
- * Get number of rows for a SQL query
- * If no query handle is specified, the last query will be taken as reference
- *
- * @param mixed $result Optional query handle
- * @return mixed Number of rows or false on failure
- * @deprecated This method shows very poor performance and should be avoided.
- */
- public function num_rows($result = null)
- {
- // not implemented
- return false;
- }
-
- /**
- * Get an associative array for one row
- * If no query handle is specified, the last query will be taken as reference
- *
- * @param mixed $result Optional query handle
- *
- * @return mixed Array with col values or false on failure
- */
- public function fetch_assoc($result = null)
- {
- return $this->_fetch_row($result, OCI_ASSOC);
- }
-
- /**
- * Get an index array for one row
- * If no query handle is specified, the last query will be taken as reference
- *
- * @param mixed $result Optional query handle
- *
- * @return mixed Array with col values or false on failure
- */
- public function fetch_array($result = null)
- {
- return $this->_fetch_row($result, OCI_NUM);
- }
-
- /**
- * Get col values for a result row
- *
- * @param mixed $result Optional query handle
- * @param int $mode Fetch mode identifier
- *
- * @return mixed Array with col values or false on failure
- */
- protected function _fetch_row($result, $mode)
- {
- if ($result || ($result === null && ($result = $this->last_result))) {
- return oci_fetch_array($result, $mode + OCI_RETURN_NULLS + OCI_RETURN_LOBS);
- }
-
- return false;
- }
-
- /**
- * Formats input so it can be safely used in a query
- * PDO_OCI does not implement quote() method
- *
- * @param mixed $input Value to quote
- * @param string $type Type of data (integer, bool, ident)
- *
- * @return string Quoted/converted string for use in query
- */
- public function quote($input, $type = null)
- {
- // handle int directly for better performance
- if ($type == 'integer' || $type == 'int') {
- return intval($input);
- }
-
- if (is_null($input)) {
- return 'NULL';
- }
-
- if ($type == 'ident') {
- return $this->quote_identifier($input);
- }
-
- switch ($type) {
- case 'bool':
- case 'integer':
- return intval($input);
- default:
- return "'" . strtr($input, array(
- '?' => '??',
- "'" => "''",
- rcube_db::DEFAULT_QUOTE => rcube_db::DEFAULT_QUOTE . rcube_db::DEFAULT_QUOTE
- )) . "'";
- }
- }
-
- /**
- * Return correct name for a specific database sequence
- *
- * @param string $table Table name
- *
- * @return string Translated sequence name
- */
- protected function sequence_name($table)
- {
- // Note: we support only one sequence per table
- // Note: The sequence name must be <table_name>_seq
- $sequence = $table . '_seq';
-
- // modify sequence name if prefix is configured
- if ($prefix = $this->options['table_prefix']) {
- return $prefix . $sequence;
- }
-
- return $sequence;
- }
-
- /**
- * Return SQL statement for case insensitive LIKE
- *
- * @param string $column Field name
- * @param string $value Search value
- *
- * @return string SQL statement to use in query
- */
- public function ilike($column, $value)
- {
- return 'UPPER(' . $this->quote_identifier($column) . ') LIKE UPPER(' . $this->quote($value) . ')';
- }
-
- /**
- * Return SQL function for current time and date
- *
- * @param int $interval Optional interval (in seconds) to add/subtract
- *
- * @return string SQL function to use in query
- */
- public function now($interval = 0)
- {
- if ($interval) {
- $interval = intval($interval);
- return "current_timestamp + INTERVAL '$interval' SECOND";
- }
-
- return "current_timestamp";
- }
-
- /**
- * Return SQL statement to convert a field value into a unix timestamp
- *
- * @param string $field Field name
- *
- * @return string SQL statement to use in query
- * @deprecated
- */
- public function unixtimestamp($field)
- {
- return "(($field - to_date('1970-01-01','YYYY-MM-DD')) * 60 * 60 * 24)";
- }
-
- /**
- * Adds TOP (LIMIT,OFFSET) clause to the query
- *
- * @param string $query SQL query
- * @param int $limit Number of rows
- * @param int $offset Offset
- *
- * @return string SQL query
- */
- protected function set_limit($query, $limit = 0, $offset = 0)
- {
- $limit = intval($limit);
- $offset = intval($offset);
- $end = $offset + $limit;
-
- // @TODO: Oracle 12g has better OFFSET support
-
- if (!$offset) {
- $query = "SELECT * FROM ($query) a WHERE rownum <= $end";
- }
- else {
- $query = "SELECT * FROM (SELECT a.*, rownum as rn FROM ($query) a WHERE rownum <= $end) b WHERE rn > $offset";
- }
-
- return $query;
- }
-
- /**
- * Parse SQL file and fix table names according to table prefix
- */
- protected function fix_table_names($sql)
- {
- if (!$this->options['table_prefix']) {
- return $sql;
- }
-
- $sql = parent::fix_table_names($sql);
-
- // replace sequence names, and other Oracle-specific commands
- $sql = preg_replace_callback('/((SEQUENCE ["]?)([^" \r\n]+)/',
- array($this, 'fix_table_names_callback'),
- $sql
- );
-
- $sql = preg_replace_callback(
- '/([ \r\n]+["]?)([^"\' \r\n\.]+)(["]?\.nextval)/',
- array($this, 'fix_table_names_seq_callback'),
- $sql
- );
-
- return $sql;
- }
-
- /**
- * Preg_replace callback for fix_table_names()
- */
- protected function fix_table_names_seq_callback($matches)
- {
- return $matches[1] . $this->options['table_prefix'] . $matches[2] . $matches[3];
- }
-
- /**
- * Returns connection options from DSN array
- */
- protected function dsn_options($dsn)
- {
- $params = array();
-
- if ($dsn['hostspec']) {
- $host = $dsn['hostspec'];
- if ($dsn['port']) {
- $host .= ':' . $dsn['port'];
- }
-
- $params['database'] = $host . '/' . $dsn['database'];
- }
-
- $params['charset'] = 'UTF8';
-
- return $params;
- }
-
- /**
- * Execute the given SQL script
- *
- * @param string SQL queries to execute
- *
- * @return boolen True on success, False on error
- */
- public function exec_script($sql)
- {
- $sql = $this->fix_table_names($sql);
- $buff = '';
- $body = false;
-
- foreach (explode("\n", $sql) as $line) {
- $tok = strtolower(trim($line));
- if (preg_match('/^--/', $line) || $tok == '' || $tok == '/') {
- continue;
- }
-
- $buff .= $line . "\n";
-
- // detect PL/SQL function bodies, don't break on semicolon
- if ($body && $tok == 'end;') {
- $body = false;
- }
- else if (!$body && $tok == 'begin') {
- $body = true;
- }
-
- if (!$body && substr($tok, -1) == ';') {
- $this->query($buff);
- $buff = '';
- if ($this->db_error) {
- break;
- }
- }
- }
-
- return !$this->db_error;
- }
-
- /**
- * Start transaction
- *
- * @return bool True on success, False on failure
- */
- public function startTransaction()
- {
- $this->db_connect('w', true);
-
- // check connection before proceeding
- if (!$this->is_connected()) {
- return $this->last_result = false;
- }
-
- $this->debug('BEGIN TRANSACTION');
-
- return $this->last_result = $this->in_transaction = true;
- }
-
- /**
- * Commit transaction
- *
- * @return bool True on success, False on failure
- */
- public function endTransaction()
- {
- $this->db_connect('w', true);
-
- // check connection before proceeding
- if (!$this->is_connected()) {
- return $this->last_result = false;
- }
-
- $this->debug('COMMIT TRANSACTION');
-
- if ($result = @oci_commit($this->dbh)) {
- $this->in_transaction = true;
- }
- else {
- $this->handle_error('COMMIT');
- }
-
- return $this->last_result = $result;
- }
-
- /**
- * Rollback transaction
- *
- * @return bool True on success, False on failure
- */
- public function rollbackTransaction()
- {
- $this->db_connect('w', true);
-
- // check connection before proceeding
- if (!$this->is_connected()) {
- return $this->last_result = false;
- }
-
- $this->debug('ROLLBACK TRANSACTION');
-
- if ($result = @oci_rollback($this->dbh)) {
- $this->in_transaction = false;
- }
- else {
- $this->handle_error('ROLLBACK');
- }
-
- return $this->last_result = $this->dbh->rollBack();
- }
-
- /**
- * Terminate database connection.
- */
- public function closeConnection()
- {
- // release statement and close connection(s)
- $this->last_result = null;
- foreach ($this->dbhs as $dbh) {
- oci_close($dbh);
- }
-
- parent::closeConnection();
- }
-}
diff --git a/lib/ext/Roundcube/rcube_db_pgsql.php b/lib/ext/Roundcube/rcube_db_pgsql.php
deleted file mode 100644
index a92d3cf..0000000
--- a/lib/ext/Roundcube/rcube_db_pgsql.php
+++ /dev/null
@@ -1,212 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Database wrapper class that implements PHP PDO functions |
- | for PostgreSQL database |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Database independent query interface
- * This is a wrapper for the PHP PDO
- *
- * @package Framework
- * @subpackage Database
- */
-class rcube_db_pgsql extends rcube_db
-{
- public $db_provider = 'postgres';
-
- /**
- * Driver-specific configuration of database connection
- *
- * @param array $dsn DSN for DB connections
- * @param PDO $dbh Connection handler
- */
- protected function conn_configure($dsn, $dbh)
- {
- $dbh->query("SET NAMES 'utf8'");
- }
-
- /**
- * Get last inserted record ID
- *
- * @param string $table Table name (to find the incremented sequence)
- *
- * @return mixed ID or false on failure
- */
- public function insert_id($table = null)
- {
- if (!$this->db_connected || $this->db_mode == 'r') {
- return false;
- }
-
- if ($table) {
- $table = $this->sequence_name($table);
- }
-
- $id = $this->dbh->lastInsertId($table);
-
- return $id;
- }
-
- /**
- * Return correct name for a specific database sequence
- *
- * @param string $table Table name
- *
- * @return string Translated sequence name
- */
- protected function sequence_name($table)
- {
- // Note: we support only one sequence per table
- // Note: The sequence name must be <table_name>_seq
- $sequence = $table . '_seq';
-
- // modify sequence name if prefix is configured
- if ($prefix = $this->options['table_prefix']) {
- return $prefix . $sequence;
- }
-
- return $sequence;
- }
-
- /**
- * Return SQL statement to convert a field value into a unix timestamp
- *
- * @param string $field Field name
- *
- * @return string SQL statement to use in query
- * @deprecated
- */
- public function unixtimestamp($field)
- {
- return "EXTRACT (EPOCH FROM $field)";
- }
-
- /**
- * Return SQL function for current time and date
- *
- * @param int $interval Optional interval (in seconds) to add/subtract
- *
- * @return string SQL function to use in query
- */
- public function now($interval = 0)
- {
- if ($interval) {
- $add = ' ' . ($interval > 0 ? '+' : '-') . " interval '";
- $add .= $interval > 0 ? intval($interval) : intval($interval) * -1;
- $add .= " seconds'";
- }
-
- return "now()" . $add;
- }
-
- /**
- * Return SQL statement for case insensitive LIKE
- *
- * @param string $column Field name
- * @param string $value Search value
- *
- * @return string SQL statement to use in query
- */
- public function ilike($column, $value)
- {
- return $this->quote_identifier($column) . ' ILIKE ' . $this->quote($value);
- }
-
- /**
- * Get database runtime variables
- *
- * @param string $varname Variable name
- * @param mixed $default Default value if variable is not set
- *
- * @return mixed Variable value or default
- */
- public function get_variable($varname, $default = null)
- {
- // There's a known case when max_allowed_packet is queried
- // PostgreSQL doesn't have such limit, return immediately
- if ($varname == 'max_allowed_packet') {
- return $default;
- }
-
- if (!isset($this->variables)) {
- $this->variables = array();
-
- $result = $this->query('SHOW ALL');
-
- while ($row = $this->fetch_array($result)) {
- $this->variables[$row[0]] = $row[1];
- }
- }
-
- return isset($this->variables[$varname]) ? $this->variables[$varname] : $default;
- }
-
- /**
- * Returns PDO DSN string from DSN array
- *
- * @param array $dsn DSN parameters
- *
- * @return string DSN string
- */
- protected function dsn_string($dsn)
- {
- $params = array();
- $result = 'pgsql:';
-
- if ($dsn['hostspec']) {
- $params[] = 'host=' . $dsn['hostspec'];
- }
- else if ($dsn['socket']) {
- $params[] = 'host=' . $dsn['socket'];
- }
-
- if ($dsn['port']) {
- $params[] = 'port=' . $dsn['port'];
- }
-
- if ($dsn['database']) {
- $params[] = 'dbname=' . $dsn['database'];
- }
-
- if (!empty($params)) {
- $result .= implode(';', $params);
- }
-
- return $result;
- }
-
- /**
- * Parse SQL file and fix table names according to table prefix
- */
- protected function fix_table_names($sql)
- {
- if (!$this->options['table_prefix']) {
- return $sql;
- }
-
- $sql = parent::fix_table_names($sql);
-
- // replace sequence names, and other postgres-specific commands
- $sql = preg_replace_callback(
- '/((SEQUENCE |RENAME TO |nextval\()["\']*)([^"\' \r\n]+)/',
- array($this, 'fix_table_names_callback'),
- $sql
- );
-
- return $sql;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_db_sqlite.php b/lib/ext/Roundcube/rcube_db_sqlite.php
deleted file mode 100644
index b66c560..0000000
--- a/lib/ext/Roundcube/rcube_db_sqlite.php
+++ /dev/null
@@ -1,161 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Database wrapper class that implements PHP PDO functions |
- | for SQLite database |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Database independent query interface
- * This is a wrapper for the PHP PDO
- *
- * @package Framework
- * @subpackage Database
- */
-class rcube_db_sqlite extends rcube_db
-{
- public $db_provider = 'sqlite';
-
- /**
- * Prepare connection
- */
- protected function conn_prepare($dsn)
- {
- // Create database file, required by PDO to exist on connection
- if (!empty($dsn['database']) && !file_exists($dsn['database'])) {
- $created = touch($dsn['database']);
-
- // File mode setting, for compat. with MDB2
- if (!empty($dsn['mode']) && $created) {
- chmod($dsn['database'], octdec($dsn['mode']));
- }
- }
- }
-
- /**
- * Configure connection, create database if not exists
- */
- protected function conn_configure($dsn, $dbh)
- {
- // Initialize database structure in file is empty
- if (!empty($dsn['database']) && !filesize($dsn['database'])) {
- $data = file_get_contents(RCUBE_INSTALL_PATH . 'SQL/sqlite.initial.sql');
-
- if (strlen($data)) {
- $this->debug('INITIALIZE DATABASE');
-
- $q = $dbh->exec($data);
-
- if ($q === false) {
- $error = $dbh->errorInfo();
- $this->db_error = true;
- $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]);
-
- rcube::raise_error(array('code' => 500, 'type' => 'db',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $this->db_error_msg), true, false);
- }
- }
- }
- }
-
- /**
- * Return SQL statement to convert a field value into a unix timestamp
- *
- * @param string $field Field name
- *
- * @return string SQL statement to use in query
- * @deprecated
- */
- public function unixtimestamp($field)
- {
- return "strftime('%s', $field)";
- }
-
- /**
- * Return SQL function for current time and date
- *
- * @param int $interval Optional interval (in seconds) to add/subtract
- *
- * @return string SQL function to use in query
- */
- public function now($interval = 0)
- {
- if ($interval) {
- $add = ($interval > 0 ? '+' : '') . intval($interval) . ' seconds';
- }
-
- return "datetime('now'" . ($add ? ",'$add'" : "") . ")";
- }
-
- /**
- * Returns list of tables in database
- *
- * @return array List of all tables of the current database
- */
- public function list_tables()
- {
- if ($this->tables === null) {
- $q = $this->query('SELECT name FROM sqlite_master'
- .' WHERE type = \'table\' ORDER BY name');
-
- $this->tables = $q ? $q->fetchAll(PDO::FETCH_COLUMN, 0) : array();
- }
-
- return $this->tables;
- }
-
- /**
- * Returns list of columns in database table
- *
- * @param string $table Table name
- *
- * @return array List of table cols
- */
- public function list_cols($table)
- {
- $q = $this->query('SELECT sql FROM sqlite_master WHERE type = ? AND name = ?',
- array('table', $table));
-
- $columns = array();
-
- if ($sql = $this->fetch_array($q)) {
- $sql = $sql[0];
- $start_pos = strpos($sql, '(');
- $end_pos = strrpos($sql, ')');
- $sql = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
- $lines = explode(',', $sql);
-
- foreach ($lines as $line) {
- $line = explode(' ', trim($line));
-
- if ($line[0] && strpos($line[0], '--') !== 0) {
- $column = $line[0];
- $columns[] = trim($column, '"');
- }
- }
- }
-
- return $columns;
- }
-
- /**
- * Build DSN string for PDO constructor
- */
- protected function dsn_string($dsn)
- {
- return $dsn['phptype'] . ':' . $dsn['database'];
- }
-}
diff --git a/lib/ext/Roundcube/rcube_db_sqlsrv.php b/lib/ext/Roundcube/rcube_db_sqlsrv.php
deleted file mode 100644
index 7b64cce..0000000
--- a/lib/ext/Roundcube/rcube_db_sqlsrv.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Database wrapper class that implements PHP PDO functions |
- | for MS SQL Server database |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Database independent query interface
- * This is a wrapper for the PHP PDO
- *
- * @package Framework
- * @subpackage Database
- */
-class rcube_db_sqlsrv extends rcube_db_mssql
-{
- /**
- * Returns PDO DSN string from DSN array
- */
- protected function dsn_string($dsn)
- {
- $params = array();
- $result = 'sqlsrv:';
-
- if ($dsn['hostspec']) {
- $host = $dsn['hostspec'];
-
- if ($dsn['port']) {
- $host .= ',' . $dsn['port'];
- }
-
- $params[] = 'Server=' . $host;
- }
-
- if ($dsn['database']) {
- $params[] = 'Database=' . $dsn['database'];
- }
-
- if (!empty($params)) {
- $result .= implode(';', $params);
- }
-
- return $result;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_enriched.php b/lib/ext/Roundcube/rcube_enriched.php
deleted file mode 100644
index 12deb33..0000000
--- a/lib/ext/Roundcube/rcube_enriched.php
+++ /dev/null
@@ -1,143 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Helper class to convert Enriched to HTML format (RFC 1523, 1896) |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <alec@alec.pl> |
- | Author: Ryo Chijiiwa (IlohaMail) |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class for Enriched to HTML conversion
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_enriched
-{
- protected static function convert_newlines($body)
- {
- // remove single newlines, convert N newlines to N-1
- $body = str_replace("\r\n", "\n", $body);
- $len = strlen($body);
- $nl = 0;
- $out = '';
-
- for ($i=0; $i<$len; $i++) {
- $c = $body[$i];
- if (ord($c) == 10)
- $nl++;
- if ($nl && ord($c) != 10)
- $nl = 0;
- if ($nl != 1)
- $out .= $c;
- else
- $out .= ' ';
- }
-
- return $out;
- }
-
- protected static function convert_formatting($body)
- {
- $replace = array(
- '<bold>' => '<b>', '</bold>' => '</b>',
- '<italic>' => '<i>', '</italic>' => '</i>',
- '<fixed>' => '<tt>', '</fixed>' => '</tt>',
- '<smaller>' => '<font size=-1>', '</smaller>'=> '</font>',
- '<bigger>' => '<font size=+1>', '</bigger>' => '</font>',
- '<underline>' => '<span style="text-decoration: underline">', '</underline>' => '</span>',
- '<flushleft>' => '<span style="text-align: left">', '</flushleft>' => '</span>',
- '<flushright>' => '<span style="text-align: right">', '</flushright>' => '</span>',
- '<flushboth>' => '<span style="text-align: justified">', '</flushboth>' => '</span>',
- '<indent>' => '<span style="padding-left: 20px">', '</indent>' => '</span>',
- '<indentright>' => '<span style="padding-right: 20px">', '</indentright>' => '</span>',
- );
-
- return str_ireplace(array_keys($replace), array_values($replace), $body);
- }
-
- protected static function convert_font($body)
- {
- $pattern = '/(.*)\<fontfamily\>\<param\>(.*)\<\/param\>(.*)\<\/fontfamily\>(.*)/ims';
-
- while (preg_match($pattern, $body, $a)) {
- if (count($a) != 5)
- continue;
-
- $body = $a[1].'<span style="font-family: '.$a[2].'">'.$a[3].'</span>'.$a[4];
- }
-
- return $body;
- }
-
- protected static function convert_color($body)
- {
- $pattern = '/(.*)\<color\>\<param\>(.*)\<\/param\>(.*)\<\/color\>(.*)/ims';
-
- while (preg_match($pattern, $body, $a)) {
- if (count($a) != 5)
- continue;
-
- // extract color (either by name, or ####,####,####)
- if (strpos($a[2],',')) {
- $rgb = explode(',',$a[2]);
- $color = '#';
- for ($i=0; $i<3; $i++)
- $color .= substr($rgb[$i], 0, 2); // just take first 2 bytes
- }
- else {
- $color = $a[2];
- }
-
- // put it all together
- $body = $a[1].'<span style="color: '.$color.'">'.$a[3].'</span>'.$a[4];
- }
-
- return $body;
- }
-
- protected static function convert_excerpt($body)
- {
- $pattern = '/(.*)\<excerpt\>(.*)\<\/excerpt\>(.*)/i';
-
- while (preg_match($pattern, $body, $a)) {
- if (count($a) != 4)
- continue;
-
- $quoted = '';
- $lines = explode('<br>', $a[2]);
-
- foreach ($lines as $line)
- $quoted .= '&gt;'.$line.'<br>';
-
- $body = $a[1].'<span class="quotes">'.$quoted.'</span>'.$a[3];
- }
-
- return $body;
- }
-
- public static function to_html($body)
- {
- $body = str_replace('<<','&lt;',$body);
- $body = self::convert_newlines($body);
- $body = str_replace("\n", '<br>', $body);
- $body = self::convert_formatting($body);
- $body = self::convert_color($body);
- $body = self::convert_font($body);
- $body = self::convert_excerpt($body);
- //$body = nl2br($body);
-
- return $body;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_html2text.php b/lib/ext/Roundcube/rcube_html2text.php
deleted file mode 100644
index 499c4b0..0000000
--- a/lib/ext/Roundcube/rcube_html2text.php
+++ /dev/null
@@ -1,711 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2012, The Roundcube Dev Team |
- | Copyright (c) 2005-2007, Jon Abernathy <jon@chuggnutt.com> |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Converts HTML to formatted plain text (based on html2text class) |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- | Author: Jon Abernathy <jon@chuggnutt.com> |
- +-----------------------------------------------------------------------+
- */
-
-/**
- * Takes HTML and converts it to formatted, plain text.
- *
- * Thanks to Alexander Krug (http://www.krugar.de/) to pointing out and
- * correcting an error in the regexp search array. Fixed 7/30/03.
- *
- * Updated set_html() function's file reading mechanism, 9/25/03.
- *
- * Thanks to Joss Sanglier (http://www.dancingbear.co.uk/) for adding
- * several more HTML entity codes to the $search and $replace arrays.
- * Updated 11/7/03.
- *
- * Thanks to Darius Kasperavicius (http://www.dar.dar.lt/) for
- * suggesting the addition of $allowed_tags and its supporting function
- * (which I slightly modified). Updated 3/12/04.
- *
- * Thanks to Justin Dearing for pointing out that a replacement for the
- * <TH> tag was missing, and suggesting an appropriate fix.
- * Updated 8/25/04.
- *
- * Thanks to Mathieu Collas (http://www.myefarm.com/) for finding a
- * display/formatting bug in the _build_link_list() function: email
- * readers would show the left bracket and number ("[1") as part of the
- * rendered email address.
- * Updated 12/16/04.
- *
- * Thanks to Wojciech Bajon (http://histeria.pl/) for submitting code
- * to handle relative links, which I hadn't considered. I modified his
- * code a bit to handle normal HTTP links and MAILTO links. Also for
- * suggesting three additional HTML entity codes to search for.
- * Updated 03/02/05.
- *
- * Thanks to Jacob Chandler for pointing out another link condition
- * for the _build_link_list() function: "https".
- * Updated 04/06/05.
- *
- * Thanks to Marc Bertrand (http://www.dresdensky.com/) for
- * suggesting a revision to the word wrapping functionality; if you
- * specify a $width of 0 or less, word wrapping will be ignored.
- * Updated 11/02/06.
- *
- * *** Big housecleaning updates below:
- *
- * Thanks to Colin Brown (http://www.sparkdriver.co.uk/) for
- * suggesting the fix to handle </li> and blank lines (whitespace).
- * Christian Basedau (http://www.movetheweb.de/) also suggested the
- * blank lines fix.
- *
- * Special thanks to Marcus Bointon (http://www.synchromedia.co.uk/),
- * Christian Basedau, Norbert Laposa (http://ln5.co.uk/),
- * Bas van de Weijer, and Marijn van Butselaar
- * for pointing out my glaring error in the <th> handling. Marcus also
- * supplied a host of fixes.
- *
- * Thanks to Jeffrey Silverman (http://www.newtnotes.com/) for pointing
- * out that extra spaces should be compressed--a problem addressed with
- * Marcus Bointon's fixes but that I had not yet incorporated.
- *
- * Thanks to Daniel Schledermann (http://www.typoconsult.dk/) for
- * suggesting a valuable fix with <a> tag handling.
- *
- * Thanks to Wojciech Bajon (again!) for suggesting fixes and additions,
- * including the <a> tag handling that Daniel Schledermann pointed
- * out but that I had not yet incorporated. I haven't (yet)
- * incorporated all of Wojciech's changes, though I may at some
- * future time.
- *
- * *** End of the housecleaning updates. Updated 08/08/07.
- */
-
-/**
- * Converts HTML to formatted plain text
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_html2text
-{
- /**
- * Contains the HTML content to convert.
- *
- * @var string $html
- */
- protected $html;
-
- /**
- * Contains the converted, formatted text.
- *
- * @var string $text
- */
- protected $text;
-
- /**
- * Maximum width of the formatted text, in columns.
- *
- * Set this value to 0 (or less) to ignore word wrapping
- * and not constrain text to a fixed-width column.
- *
- * @var integer $width
- */
- protected $width = 70;
-
- /**
- * Target character encoding for output text
- *
- * @var string $charset
- */
- protected $charset = 'UTF-8';
-
- /**
- * List of preg* regular expression patterns to search for,
- * used in conjunction with $replace.
- *
- * @var array $search
- * @see $replace
- */
- protected $search = array(
- "/\r/", // Non-legal carriage return
- "/[\n\t]+/", // Newlines and tabs
- '/<head[^>]*>.*?<\/head>/i', // <head>
- '/<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>
- '/<br[^>]*>/i', // <br>
- '/<i[^>]*>(.*?)<\/i>/i', // <i>
- '/<em[^>]*>(.*?)<\/em>/i', // <em>
- '/(<ul[^>]*>|<\/ul>)/i', // <ul> and </ul>
- '/(<ol[^>]*>|<\/ol>)/i', // <ol> and </ol>
- '/<li[^>]*>(.*?)<\/li>/i', // <li> and </li>
- '/<li[^>]*>/i', // <li>
- '/<hr[^>]*>/i', // <hr>
- '/<div[^>]*>/i', // <div>
- '/(<table[^>]*>|<\/table>)/i', // <table> and </table>
- '/(<tr[^>]*>|<\/tr>)/i', // <tr> and </tr>
- '/<td[^>]*>(.*?)<\/td>/i', // <td> and </td>
- );
-
- /**
- * List of pattern replacements corresponding to patterns searched.
- *
- * @var array $replace
- * @see $search
- */
- protected $replace = array(
- '', // Non-legal carriage return
- ' ', // Newlines and tabs
- '', // <head>
- '', // <script>s -- which strip_tags supposedly has problems with
- '', // <style>s -- which strip_tags supposedly has problems with
- "\n\n", // <P>
- "\n", // <br>
- '_\\1_', // <i>
- '_\\1_', // <em>
- "\n\n", // <ul> and </ul>
- "\n\n", // <ol> and </ol>
- "\t* \\1\n", // <li> and </li>
- "\n\t* ", // <li>
- "\n-------------------------\n", // <hr>
- "<div>\n", // <div>
- "\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
- * @see $ent_replace
- */
- protected $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
- '/&gt;/i', // Greater-than
- '/&lt;/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
- * @see $ent_search
- */
- protected $ent_replace = array(
- ' ', // Non-breaking space
- '"', // Double quotes
- "'", // Single quotes
- '>',
- '<',
- '(c)',
- '(tm)',
- '(R)',
- '--',
- '-',
- '*',
- '£',
- 'EUR', // Euro sign. € ?
- '|+|amp|+|', // Ampersand: see _converter()
- ' ', // Runs of spaces, post-handling
- );
-
- /**
- * List of preg* regular expression patterns to search for
- * and replace using callback function.
- *
- * @var array $callback_search
- */
- protected $callback_search = array(
- '/<(a) [^>]*href=("|\')([^"\']+)\2[^>]*>(.*?)<\/a>/i', // <a href="">
- '/<(h)[123456]( [^>]*)?>(.*?)<\/h[123456]>/i', // h1 - h6
- '/<(b)( [^>]*)?>(.*?)<\/b>/i', // <b>
- '/<(strong)( [^>]*)?>(.*?)<\/strong>/i', // <strong>
- '/<(th)( [^>]*)?>(.*?)<\/th>/i', // <th> and </th>
- );
-
- /**
- * List of preg* regular expression patterns to search for in PRE body,
- * used in conjunction with $pre_replace.
- *
- * @var array $pre_search
- * @see $pre_replace
- */
- protected $pre_search = array(
- "/\n/",
- "/\t/",
- '/ /',
- '/<pre[^>]*>/',
- '/<\/pre>/'
- );
-
- /**
- * List of pattern replacements corresponding to patterns searched for PRE body.
- *
- * @var array $pre_replace
- * @see $pre_search
- */
- protected $pre_replace = array(
- '<br>',
- '&nbsp;&nbsp;&nbsp;&nbsp;',
- '&nbsp;',
- '',
- ''
- );
-
- /**
- * Contains a list of HTML tags to allow in the resulting text.
- *
- * @var string $allowed_tags
- * @see set_allowed_tags()
- */
- protected $allowed_tags = '';
-
- /**
- * Contains the base URL that relative links should resolve to.
- *
- * @var string $url
- */
- protected $url;
-
- /**
- * Indicates whether content in the $html variable has been converted yet.
- *
- * @var boolean $_converted
- * @see $html, $text
- */
- protected $_converted = false;
-
- /**
- * Contains URL addresses from links to be rendered in plain text.
- *
- * @var array $_link_list
- * @see _build_link_list()
- */
- protected $_link_list = array();
-
- /**
- * Boolean flag, true if a table of link URLs should be listed after the text.
- *
- * @var boolean $_do_links
- * @see __construct()
- */
- protected $_do_links = true;
-
- /**
- * Constructor.
- *
- * If the HTML source string (or file) is supplied, the class
- * will instantiate with that source propagated, all that has
- * to be done it to call get_text().
- *
- * @param string $source HTML content
- * @param boolean $from_file Indicates $source is a file to pull content from
- * @param boolean $do_links Indicate whether a table of link URLs is desired
- * @param integer $width Maximum width of the formatted text, 0 for no limit
- */
- function __construct($source = '', $from_file = false, $do_links = true, $width = 75, $charset = 'UTF-8')
- {
- if (!empty($source)) {
- $this->set_html($source, $from_file);
- }
-
- $this->set_base_url();
-
- $this->_do_links = $do_links;
- $this->width = $width;
- $this->charset = $charset;
- }
-
- /**
- * Loads source HTML into memory, either from $source string or a file.
- *
- * @param string $source HTML content
- * @param boolean $from_file Indicates $source is a file to pull content from
- */
- function set_html($source, $from_file = false)
- {
- if ($from_file && file_exists($source)) {
- $this->html = file_get_contents($source);
- }
- else {
- $this->html = $source;
- }
-
- $this->_converted = false;
- }
-
- /**
- * Returns the text, converted from HTML.
- *
- * @return string Plain text
- */
- function get_text()
- {
- if (!$this->_converted) {
- $this->_convert();
- }
-
- return $this->text;
- }
-
- /**
- * Prints the text, converted from HTML.
- */
- function print_text()
- {
- print $this->get_text();
- }
-
- /**
- * Sets the allowed HTML tags to pass through to the resulting text.
- *
- * Tags should be in the form "<p>", with no corresponding closing tag.
- */
- function set_allowed_tags($allowed_tags = '')
- {
- if (!empty($allowed_tags)) {
- $this->allowed_tags = $allowed_tags;
- }
- }
-
- /**
- * Sets a base URL to handle relative links.
- */
- function set_base_url($url = '')
- {
- if (empty($url)) {
- if (!empty($_SERVER['HTTP_HOST'])) {
- $this->url = 'http://' . $_SERVER['HTTP_HOST'];
- }
- else {
- $this->url = '';
- }
- }
- else {
- // Strip any trailing slashes for consistency (relative
- // URLs may already start with a slash like "/file.html")
- if (substr($url, -1) == '/') {
- $url = substr($url, 0, -1);
- }
- $this->url = $url;
- }
- }
-
- /**
- * Workhorse function that does actual conversion (calls _converter() method).
- */
- protected function _convert()
- {
- // Variables used for building the link list
- $this->_link_list = array();
-
- $text = $this->html;
-
- // Convert HTML to TXT
- $this->_converter($text);
-
- // Add link list
- if (!empty($this->_link_list)) {
- $text .= "\n\nLinks:\n------\n";
- foreach ($this->_link_list as $idx => $url) {
- $text .= '[' . ($idx+1) . '] ' . $url . "\n";
- }
- }
-
- $this->text = $text;
- $this->_converted = true;
- }
-
- /**
- * Workhorse function that does actual conversion.
- *
- * First performs custom tag replacement specified by $search and
- * $replace arrays. Then strips any remaining HTML tags, reduces whitespace
- * and newlines to a readable format, and word wraps the text to
- * $width characters.
- *
- * @param string Reference to HTML content string
- */
- protected function _converter(&$text)
- {
- // Convert <BLOCKQUOTE> (before PRE!)
- $this->_convert_blockquotes($text);
-
- // Convert <PRE>
- $this->_convert_pre($text);
-
- // 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($this, 'tags_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_QUOTES, $this->charset);
-
- // Replace unicode nbsp to regular spaces
- $text = preg_replace('/\xC2\xA0/', ' ', $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);
-
- // Convert "|+|amp|+|" into "&", need to be done after handling of unknown entities
- // This properly handles situation of "&amp;quot;" in input string
- $text = str_replace('|+|amp|+|', '&', $text);
-
- // 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 = ltrim($text, "\n");
-
- // Wrap the text to a readable format
- // for PHP versions >= 4.0.2. Default width is 75
- // If width is 0 or less, don't wrap the text.
- if ( $this->width > 0 ) {
- $text = wordwrap($text, $this->width);
- }
- }
-
- /**
- * Helper function called by preg_replace() on link replacement.
- *
- * Maintains an internal list of links to be displayed at the end of the
- * text, with numeric indices to the original point in the text they
- * appeared. Also makes an effort at identifying and handling absolute
- * and relative links.
- *
- * @param string $link URL of the link
- * @param string $display Part of the text to associate number with
- */
- protected function _build_link_list( $link, $display )
- {
- if (!$this->_do_links || empty($link)) {
- return $display;
- }
-
- // Ignored link types
- if (preg_match('!^(javascript:|mailto:|#)!i', $link)) {
- return $display;
- }
-
- if (preg_match('!^([a-z][a-z0-9.+-]+:)!i', $link)) {
- $url = $link;
- }
- else {
- $url = $this->url;
- if (substr($link, 0, 1) != '/') {
- $url .= '/';
- }
- $url .= "$link";
- }
-
- if (($index = array_search($url, $this->_link_list)) === false) {
- $index = count($this->_link_list);
- $this->_link_list[] = $url;
- }
-
- return $display . ' [' . ($index+1) . ']';
- }
-
- /**
- * Helper function for PRE body conversion.
- *
- * @param string HTML content
- */
- protected function _convert_pre(&$text)
- {
- // get the content of PRE element
- while (preg_match('/<pre[^>]*>(.*)<\/pre>/ismU', $text, $matches)) {
- $this->pre_content = $matches[1];
-
- // Run our defined tags search-and-replace with callback
- $this->pre_content = preg_replace_callback($this->callback_search,
- array($this, 'tags_preg_callback'), $this->pre_content);
-
- // convert the content
- $this->pre_content = sprintf('<div><br>%s<br></div>',
- preg_replace($this->pre_search, $this->pre_replace, $this->pre_content));
-
- // replace the content (use callback because content can contain $0 variable)
- $text = preg_replace_callback('/<pre[^>]*>.*<\/pre>/ismU',
- array($this, 'pre_preg_callback'), $text, 1);
-
- // free memory
- $this->pre_content = '';
- }
- }
-
- /**
- * Helper function for BLOCKQUOTE body conversion.
- *
- * @param string HTML content
- */
- protected function _convert_blockquotes(&$text)
- {
- $level = 0;
- $offset = 0;
- while (($start = strpos($text, '<blockquote', $offset)) !== false) {
- $offset = $start + 12;
- do {
- $end = strpos($text, '</blockquote>', $offset);
- $next = strpos($text, '<blockquote', $offset);
-
- // nested <blockquote>, skip
- if ($next !== false && $next < $end) {
- $offset = $next + 12;
- $level++;
- }
- // nested </blockquote> tag
- if ($end !== false && $level > 0) {
- $offset = $end + 12;
- $level--;
- }
- // found matching end tag
- else if ($end !== false && $level == 0) {
- $taglen = strpos($text, '>', $start) - $start;
- $startpos = $start + $taglen + 1;
-
- // get blockquote content
- $body = trim(substr($text, $startpos, $end - $startpos));
-
- // adjust text wrapping width
- $p_width = $this->width;
- if ($this->width > 0) $this->width -= 2;
-
- // replace content with inner blockquotes
- $this->_converter($body);
-
- // resore text width
- $this->width = $p_width;
-
- // Add citation markers and create <pre> block
- $body = preg_replace_callback('/((?:^|\n)>*)([^\n]*)/', array($this, 'blockquote_citation_callback'), trim($body));
- $body = '<pre>' . htmlspecialchars($body) . '</pre>';
-
- $text = substr_replace($text, $body . "\n", $start, $end + 13 - $start);
- $offset = 0;
-
- break;
- }
- // abort on invalid tag structure (e.g. no closing tag found)
- else {
- break;
- }
- }
- while ($end || $next);
- }
- }
-
- /**
- * Callback function to correctly add citation markers for blockquote contents
- */
- public function blockquote_citation_callback($m)
- {
- $line = ltrim($m[2]);
- $space = $line[0] == '>' ? '' : ' ';
-
- return $m[1] . '>' . $space . $line;
- }
-
- /**
- * Callback function for preg_replace_callback use.
- *
- * @param array PREG matches
- * @return string
- */
- public function tags_preg_callback($matches)
- {
- switch (strtolower($matches[1])) {
- case 'b':
- case 'strong':
- return $this->_toupper($matches[3]);
- case 'th':
- return $this->_toupper("\t\t". $matches[3] ."\n");
- case 'h':
- return $this->_toupper("\n\n". $matches[3] ."\n\n");
- case 'a':
- // Remove spaces in URL (#1487805)
- $url = str_replace(' ', '', $matches[3]);
- return $this->_build_link_list($url, $matches[4]);
- }
- }
-
- /**
- * Callback function for preg_replace_callback use in PRE content handler.
- *
- * @param array PREG matches
- * @return string
- */
- public function pre_preg_callback($matches)
- {
- return $this->pre_content;
- }
-
- /**
- * Strtoupper function with HTML tags and entities handling.
- *
- * @param string $str Text to convert
- * @return string Converted text
- */
- private function _toupper($str)
- {
- // string can containg HTML tags
- $chunks = preg_split('/(<[^>]*>)/', $str, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
-
- // convert toupper only the text between HTML tags
- foreach ($chunks as $idx => $chunk) {
- if ($chunk[0] != '<') {
- $chunks[$idx] = $this->_strtoupper($chunk);
- }
- }
-
- return implode($chunks);
- }
-
- /**
- * Strtoupper multibyte wrapper function with HTML entities handling.
- *
- * @param string $str Text to convert
- * @return string Converted text
- */
- private function _strtoupper($str)
- {
- $str = html_entity_decode($str, ENT_COMPAT, $this->charset);
- $str = mb_strtoupper($str);
- $str = htmlspecialchars($str, ENT_COMPAT, $this->charset);
-
- return $str;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_image.php b/lib/ext/Roundcube/rcube_image.php
deleted file mode 100644
index 9c9f08b..0000000
--- a/lib/ext/Roundcube/rcube_image.php
+++ /dev/null
@@ -1,443 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | Copyright (C) 2011-2012, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Image resizer and converter |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Image resizer and converter
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_image
-{
- private $image_file;
-
- const TYPE_GIF = 1;
- const TYPE_JPG = 2;
- const TYPE_PNG = 3;
- const TYPE_TIF = 4;
-
- public static $extensions = array(
- self::TYPE_GIF => 'gif',
- self::TYPE_JPG => 'jpg',
- self::TYPE_PNG => 'png',
- self::TYPE_TIF => 'tif',
- );
-
-
- function __construct($filename)
- {
- $this->image_file = $filename;
- }
-
- /**
- * Get image properties.
- *
- * @return mixed Hash array with image props like type, width, height
- */
- public function props()
- {
- // use GD extension
- if (function_exists('getimagesize') && ($imsize = @getimagesize($this->image_file))) {
- $width = $imsize[0];
- $height = $imsize[1];
- $gd_type = $imsize['2'];
- $type = image_type_to_extension($imsize['2'], false);
- $channels = $imsize['channels'];
- }
-
- // use ImageMagick
- if (!$type && ($data = $this->identify())) {
- list($type, $width, $height) = $data;
- $channels = null;
- }
-
- if ($type) {
- return array(
- 'type' => $type,
- 'gd_type' => $gd_type,
- 'width' => $width,
- 'height' => $height,
- 'channels' => $channels,
- );
- }
-
- return null;
- }
-
- /**
- * Resize image to a given size. Use only to shrink an image.
- * If an image is smaller than specified size it will be not resized.
- *
- * @param int $size Max width/height size
- * @param string $filename Output filename
- * @param boolean $browser_compat Convert to image type displayable by any browser
- *
- * @return mixed Output type on success, False on failure
- */
- public function resize($size, $filename = null, $browser_compat = false)
- {
- $result = false;
- $rcube = rcube::get_instance();
- $convert = $rcube->config->get('im_convert_path', false);
- $props = $this->props();
-
- if (empty($props)) {
- return false;
- }
-
- if (!$filename) {
- $filename = $this->image_file;
- }
-
- // use Imagemagick
- if ($convert || class_exists('Imagick', false)) {
- $p['out'] = $filename;
- $p['in'] = $this->image_file;
- $type = $props['type'];
-
- if (!$type && ($data = $this->identify())) {
- $type = $data[0];
- }
-
- $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps"));
- $p['intype'] = $type;
-
- // convert to an image format every browser can display
- if ($browser_compat && !in_array($type, array('jpg','gif','png'))) {
- $type = 'jpg';
- }
-
- // If only one dimension is greater than the limit convert doesn't
- // work as expected, we need to calculate new dimensions
- $scale = $size / max($props['width'], $props['height']);
-
- // if file is smaller than the limit, we do nothing
- // but copy original file to destination file
- if ($scale >= 1 && $p['intype'] == $type) {
- $result = ($this->image_file == $filename || copy($this->image_file, $filename)) ? '' : false;
- }
- else {
- $valid_types = "bmp,eps,gif,jp2,jpg,png,svg,tif";
-
- if (in_array($type, explode(',', $valid_types))) { // Valid type?
- if ($scale >= 1) {
- $width = $props['width'];
- $height = $props['height'];
- }
- else {
- $width = intval($props['width'] * $scale);
- $height = intval($props['height'] * $scale);
- }
-
- // use ImageMagick in command line
- if ($convert) {
- $p += array(
- 'type' => $type,
- 'quality' => 75,
- 'size' => $width . 'x' . $height,
- );
-
- $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace sRGB -strip'
- . ' -quality {quality} -resize {size} {intype}:{in} {type}:{out}', $p);
- }
- // use PHP's Imagick class
- else {
- try {
- $image = new Imagick($this->image_file);
- $image = $image->flattenImages();
-
- $image->setImageColorspace(Imagick::COLORSPACE_SRGB);
- $image->setImageCompressionQuality(75);
- $image->setImageFormat($type);
- $image->stripImage();
- $image->scaleImage($width, $height);
-
- if ($image->writeImage($filename)) {
- $result = '';
- }
- }
- catch (Exception $e) {
- rcube::raise_error($e, true, false);
- }
- }
- }
- }
-
- if ($result === '') {
- @chmod($filename, 0600);
- return $type;
- }
- }
-
- // do we have enough memory? (#1489937)
- if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && !$this->mem_check($props)) {
- return false;
- }
-
- // use GD extension
- if ($props['gd_type']) {
- if ($props['gd_type'] == IMAGETYPE_JPEG && function_exists('imagecreatefromjpeg')) {
- $image = imagecreatefromjpeg($this->image_file);
- $type = 'jpg';
- }
- else if($props['gd_type'] == IMAGETYPE_GIF && function_exists('imagecreatefromgif')) {
- $image = imagecreatefromgif($this->image_file);
- $type = 'gif';
- }
- else if($props['gd_type'] == IMAGETYPE_PNG && function_exists('imagecreatefrompng')) {
- $image = imagecreatefrompng($this->image_file);
- $type = 'png';
- }
- else {
- // @TODO: print error to the log?
- return false;
- }
-
- if ($image === false) {
- return false;
- }
-
- $scale = $size / max($props['width'], $props['height']);
-
- // Imagemagick resize is implemented in shrinking mode (see -resize argument above)
- // we do the same here, if an image is smaller than specified size
- // we do nothing but copy original file to destination file
- if ($scale >= 1) {
- $result = $this->image_file == $filename || copy($this->image_file, $filename);
- }
- else {
- $width = intval($props['width'] * $scale);
- $height = intval($props['height'] * $scale);
- $new_image = imagecreatetruecolor($width, $height);
-
- // Fix transparency of gif/png image
- if ($props['gd_type'] != IMAGETYPE_JPEG) {
- imagealphablending($new_image, false);
- imagesavealpha($new_image, true);
- $transparent = imagecolorallocatealpha($new_image, 255, 255, 255, 127);
- imagefilledrectangle($new_image, 0, 0, $width, $height, $transparent);
- }
-
- imagecopyresampled($new_image, $image, 0, 0, 0, 0, $width, $height, $props['width'], $props['height']);
- $image = $new_image;
-
- // fix rotation of image if EXIF data exists and specifies rotation (GD strips the EXIF data)
- if ($this->image_file && $type == 'jpg' && function_exists('exif_read_data')) {
- $exif = exif_read_data($this->image_file);
- if ($exif && $exif['Orientation']) {
- switch ($exif['Orientation']) {
- case 3:
- $image = imagerotate($image, 180, 0);
- break;
- case 6:
- $image = imagerotate($image, -90, 0);
- break;
- case 8:
- $image = imagerotate($image, 90, 0);
- break;
- }
- }
- }
-
- if ($props['gd_type'] == IMAGETYPE_JPEG) {
- $result = imagejpeg($image, $filename, 75);
- }
- elseif($props['gd_type'] == IMAGETYPE_GIF) {
- $result = imagegif($image, $filename);
- }
- elseif($props['gd_type'] == IMAGETYPE_PNG) {
- $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS);
- }
- }
-
- if ($result) {
- @chmod($filename, 0600);
- return $type;
- }
- }
-
- // @TODO: print error to the log?
- return false;
- }
-
- /**
- * Convert image to a given type
- *
- * @param int $type Destination file type (see class constants)
- * @param string $filename Output filename (if empty, original file will be used
- * and filename extension will be modified)
- *
- * @return bool True on success, False on failure
- */
- public function convert($type, $filename = null)
- {
- $rcube = rcube::get_instance();
- $convert = $rcube->config->get('im_convert_path', false);
-
- if (!$filename) {
- $filename = $this->image_file;
-
- // modify extension
- if ($extension = self::$extensions[$type]) {
- $filename = preg_replace('/\.[^.]+$/', '', $filename) . '.' . $extension;
- }
- }
-
- // use ImageMagick in command line
- if ($convert) {
- $p['in'] = $this->image_file;
- $p['out'] = $filename;
- $p['type'] = self::$extensions[$type];
-
- $result = rcube::exec($convert . ' 2>&1 -colorspace sRGB -strip -quality 75 {in} {type}:{out}', $p);
-
- if ($result === '') {
- chmod($filename, 0600);
- return true;
- }
- }
-
- // use PHP's Imagick class
- if (class_exists('Imagick', false)) {
- try {
- $image = new Imagick($this->image_file);
-
- $image->setImageColorspace(Imagick::COLORSPACE_SRGB);
- $image->setImageCompressionQuality(75);
- $image->setImageFormat(self::$extensions[$type]);
- $image->stripImage();
-
- if ($image->writeImage($filename)) {
- @chmod($filename, 0600);
- return true;
- }
- }
- catch (Exception $e) {
- rcube::raise_error($e, true, false);
- }
- }
-
- // use GD extension (TIFF isn't supported)
- $props = $this->props();
-
- // do we have enough memory? (#1489937)
- if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && !$this->mem_check($props)) {
- return false;
- }
-
-
- if ($props['gd_type']) {
- if ($props['gd_type'] == IMAGETYPE_JPEG && function_exists('imagecreatefromjpeg')) {
- $image = imagecreatefromjpeg($this->image_file);
- }
- else if ($props['gd_type'] == IMAGETYPE_GIF && function_exists('imagecreatefromgif')) {
- $image = imagecreatefromgif($this->image_file);
- }
- else if ($props['gd_type'] == IMAGETYPE_PNG && function_exists('imagecreatefrompng')) {
- $image = imagecreatefrompng($this->image_file);
- }
- else {
- // @TODO: print error to the log?
- return false;
- }
-
- if ($type == self::TYPE_JPG) {
- $result = imagejpeg($image, $filename, 75);
- }
- else if ($type == self::TYPE_GIF) {
- $result = imagegif($image, $filename);
- }
- else if ($type == self::TYPE_PNG) {
- $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS);
- }
-
- if ($result) {
- @chmod($filename, 0600);
- return true;
- }
- }
-
- // @TODO: print error to the log?
- return false;
- }
-
- /**
- * Checks if image format conversion is supported
- *
- * @return boolean True if specified format can be converted to another format
- */
- public static function is_convertable($mimetype = null)
- {
- $rcube = rcube::get_instance();
-
- // @TODO: check if specified mimetype is really supported
- return class_exists('Imagick', false) || $rcube->config->get('im_convert_path');
- }
-
- /**
- * ImageMagick based image properties read.
- */
- private function identify()
- {
- $rcube = rcube::get_instance();
-
- // use ImageMagick in command line
- if ($cmd = $rcube->config->get('im_identify_path')) {
- $args = array('in' => $this->image_file, 'format' => "%m %[fx:w] %[fx:h]");
- $id = rcube::exec($cmd. ' 2>/dev/null -format {format} {in}', $args);
-
- if ($id) {
- return explode(' ', strtolower($id));
- }
- }
-
- // use PHP's Imagick class
- if (class_exists('Imagick', false)) {
- try {
- $image = new Imagick($this->image_file);
-
- return array(
- strtolower($image->getImageFormat()),
- $image->getImageWidth(),
- $image->getImageHeight(),
- );
- }
- catch (Exception $e) {}
- }
- }
-
- /**
- * Check if we have enough memory to load specified image
- */
- private function mem_check($props)
- {
- // image size is unknown, we can't calculate required memory
- if (!$props['width']) {
- return true;
- }
-
- // channels: CMYK - 4, RGB - 3
- $multip = ($props['channels'] ?: 3) + 1;
-
- // calculate image size in memory (in bytes)
- $size = $props['width'] * $props['height'] * $multip;
- return rcube_utils::mem_check($size);
- }
-}
diff --git a/lib/ext/Roundcube/rcube_imap.php b/lib/ext/Roundcube/rcube_imap.php
deleted file mode 100644
index b5695f3..0000000
--- a/lib/ext/Roundcube/rcube_imap.php
+++ /dev/null
@@ -1,4543 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | Copyright (C) 2011-2012, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | IMAP Storage Engine |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Interface class for accessing an IMAP server
- *
- * @package Framework
- * @subpackage Storage
- * @author Thomas Bruederli <roundcube@gmail.com>
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_imap extends rcube_storage
-{
- /**
- * Instance of rcube_imap_generic
- *
- * @var rcube_imap_generic
- */
- public $conn;
-
- /**
- * Instance of rcube_imap_cache
- *
- * @var rcube_imap_cache
- */
- protected $mcache;
-
- /**
- * Instance of rcube_cache
- *
- * @var rcube_cache
- */
- protected $cache;
-
- /**
- * Internal (in-memory) cache
- *
- * @var array
- */
- protected $icache = array();
-
- protected $plugins;
- protected $list_page = 1;
- protected $delimiter;
- protected $namespace;
- protected $sort_field = '';
- protected $sort_order = 'DESC';
- protected $struct_charset;
- protected $uid_id_map = array();
- protected $msg_headers = array();
- protected $search_set;
- protected $search_string = '';
- protected $search_charset = '';
- protected $search_sort_field = '';
- protected $search_threads = false;
- protected $search_sorted = false;
- protected $options = array('auth_type' => 'check');
- protected $caching = false;
- protected $messages_caching = false;
- protected $threading = false;
-
-
- /**
- * Object constructor.
- */
- public function __construct()
- {
- $this->conn = new rcube_imap_generic();
- $this->plugins = rcube::get_instance()->plugins;
-
- // Set namespace and delimiter from session,
- // so some methods would work before connection
- if (isset($_SESSION['imap_namespace'])) {
- $this->namespace = $_SESSION['imap_namespace'];
- }
- if (isset($_SESSION['imap_delimiter'])) {
- $this->delimiter = $_SESSION['imap_delimiter'];
- }
- }
-
-
- /**
- * Magic getter for backward compat.
- *
- * @deprecated.
- */
- public function __get($name)
- {
- if (isset($this->{$name})) {
- return $this->{$name};
- }
- }
-
-
- /**
- * Connect to an IMAP server
- *
- * @param string $host Host to connect
- * @param string $user Username for IMAP account
- * @param string $pass Password for IMAP account
- * @param integer $port Port to connect to
- * @param string $use_ssl SSL schema (either ssl or tls) or null if plain connection
- *
- * @return boolean True on success, False on failure
- */
- public function connect($host, $user, $pass, $port=143, $use_ssl=null)
- {
- // check for OpenSSL support in PHP build
- if ($use_ssl && extension_loaded('openssl')) {
- $this->options['ssl_mode'] = $use_ssl == 'imaps' ? 'ssl' : $use_ssl;
- }
- else if ($use_ssl) {
- rcube::raise_error(array('code' => 403, 'type' => 'imap',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "OpenSSL not available"), true, false);
- $port = 143;
- }
-
- $this->options['port'] = $port;
-
- if ($this->options['debug']) {
- $this->set_debug(true);
-
- $this->options['ident'] = array(
- 'name' => 'Roundcube',
- 'version' => RCUBE_VERSION,
- 'php' => PHP_VERSION,
- 'os' => PHP_OS,
- 'command' => $_SERVER['REQUEST_URI'],
- );
- }
-
- $attempt = 0;
- do {
- $data = $this->plugins->exec_hook('storage_connect',
- 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, $data);
- } while(!$this->conn->connected() && $data['retry']);
-
- $config = array(
- 'host' => $data['host'],
- 'user' => $data['user'],
- 'password' => $pass,
- 'port' => $port,
- 'ssl' => $use_ssl,
- );
-
- $this->options = array_merge($this->options, $config);
- $this->connect_done = true;
-
- if ($this->conn->connected()) {
- // check for session identifier
- $session = null;
- if (preg_match('/\s+SESSIONID=([^=\s]+)/', $this->conn->result, $m)) {
- $session = $m[1];
- }
-
- // get namespace and delimiter
- $this->set_env();
-
- // trigger post-connect hook
- $this->plugins->exec_hook('storage_connected', array(
- 'host' => $host, 'user' => $user, 'session' => $session
- ));
-
- return true;
- }
- // write error log
- else if ($this->conn->error) {
- if ($pass && $user) {
- $message = sprintf("Login failed for %s from %s. %s",
- $user, rcube_utils::remote_ip(), $this->conn->error);
-
- rcube::raise_error(array('code' => 403, 'type' => 'imap',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => $message), true, false);
- }
- }
-
- return false;
- }
-
-
- /**
- * Close IMAP connection.
- * Usually done on script shutdown
- */
- public function close()
- {
- $this->connect_done = false;
- $this->conn->closeConnection();
-
- if ($this->mcache) {
- $this->mcache->close();
- }
- }
-
-
- /**
- * Check connection state, connect if not connected.
- *
- * @return bool Connection state.
- */
- public function check_connection()
- {
- // Establish connection if it wasn't done yet
- if (!$this->connect_done && !empty($this->options['user'])) {
- return $this->connect(
- $this->options['host'],
- $this->options['user'],
- $this->options['password'],
- $this->options['port'],
- $this->options['ssl']
- );
- }
-
- return $this->is_connected();
- }
-
-
- /**
- * Checks IMAP connection.
- *
- * @return boolean TRUE on success, FALSE on failure
- */
- public function is_connected()
- {
- return $this->conn->connected();
- }
-
-
- /**
- * Returns code of last error
- *
- * @return int Error code
- */
- public function get_error_code()
- {
- return $this->conn->errornum;
- }
-
-
- /**
- * Returns text of last error
- *
- * @return string Error string
- */
- public function get_error_str()
- {
- return $this->conn->error;
- }
-
-
- /**
- * Returns code of last command response
- *
- * @return int Response code
- */
- public function get_response_code()
- {
- switch ($this->conn->resultcode) {
- case 'NOPERM':
- return self::NOPERM;
- case 'READ-ONLY':
- return self::READONLY;
- case 'TRYCREATE':
- return self::TRYCREATE;
- case 'INUSE':
- return self::INUSE;
- case 'OVERQUOTA':
- return self::OVERQUOTA;
- case 'ALREADYEXISTS':
- return self::ALREADYEXISTS;
- case 'NONEXISTENT':
- return self::NONEXISTENT;
- case 'CONTACTADMIN':
- return self::CONTACTADMIN;
- default:
- return self::UNKNOWN;
- }
- }
-
-
- /**
- * Activate/deactivate debug mode
- *
- * @param boolean $dbg True if IMAP conversation should be logged
- */
- public function set_debug($dbg = true)
- {
- $this->options['debug'] = $dbg;
- $this->conn->setDebug($dbg, array($this, 'debug_handler'));
- }
-
-
- /**
- * Set internal folder reference.
- * All operations will be perfomed on this folder.
- *
- * @param string $folder Folder name
- */
- public function set_folder($folder)
- {
- $this->folder = $folder;
- }
-
-
- /**
- * Save a search result for future message listing methods
- *
- * @param array $set Search set, result from rcube_imap::get_search_set():
- * 0 - searching criteria, string
- * 1 - search result, rcube_result_index|rcube_result_thread
- * 2 - searching character set, string
- * 3 - sorting field, string
- * 4 - true if sorted, bool
- */
- public function set_search_set($set)
- {
- $set = (array)$set;
-
- $this->search_string = $set[0];
- $this->search_set = $set[1];
- $this->search_charset = $set[2];
- $this->search_sort_field = $set[3];
- $this->search_sorted = $set[4];
- $this->search_threads = is_a($this->search_set, 'rcube_result_thread');
-
- if (is_a($this->search_set, 'rcube_result_multifolder')) {
- $this->set_threading(false);
- }
- }
-
-
- /**
- * Return the saved search set as hash array
- *
- * @return array Search set
- */
- public function get_search_set()
- {
- if (empty($this->search_set)) {
- return null;
- }
-
- return array(
- $this->search_string,
- $this->search_set,
- $this->search_charset,
- $this->search_sort_field,
- $this->search_sorted,
- );
- }
-
-
- /**
- * Returns the IMAP server's capability.
- *
- * @param string $cap Capability name
- *
- * @return mixed Capability value or TRUE if supported, FALSE if not
- */
- public function get_capability($cap)
- {
- $cap = strtoupper($cap);
- $sess_key = "STORAGE_$cap";
-
- if (!isset($_SESSION[$sess_key])) {
- if (!$this->check_connection()) {
- return false;
- }
-
- $_SESSION[$sess_key] = $this->conn->getCapability($cap);
- }
-
- return $_SESSION[$sess_key];
- }
-
-
- /**
- * Checks the PERMANENTFLAGS capability of the current folder
- * and returns true if the given flag is supported by the IMAP server
- *
- * @param string $flag Permanentflag name
- *
- * @return boolean True if this flag is supported
- */
- public function check_permflag($flag)
- {
- $flag = strtoupper($flag);
- $perm_flags = $this->get_permflags($this->folder);
- $imap_flag = $this->conn->flags[$flag];
-
- return $imap_flag && !empty($perm_flags) && in_array_nocase($imap_flag, $perm_flags);
- }
-
-
- /**
- * Returns PERMANENTFLAGS of the specified folder
- *
- * @param string $folder Folder name
- *
- * @return array Flags
- */
- public function get_permflags($folder)
- {
- if (!strlen($folder)) {
- return array();
- }
-
- if (!$this->check_connection()) {
- return array();
- }
-
- if ($this->conn->select($folder)) {
- $permflags = $this->conn->data['PERMANENTFLAGS'];
- }
- else {
- return array();
- }
-
- if (!is_array($permflags)) {
- $permflags = array();
- }
-
- return $permflags;
- }
-
-
- /**
- * Returns the delimiter that is used by the IMAP server for folder separation
- *
- * @return string Delimiter string
- * @access public
- */
- public function get_hierarchy_delimiter()
- {
- return $this->delimiter;
- }
-
-
- /**
- * Get namespace
- *
- * @param string $name Namespace array index: personal, other, shared, prefix
- *
- * @return array Namespace data
- */
- public function get_namespace($name = null)
- {
- $ns = $this->namespace;
-
- if ($name) {
- return isset($ns[$name]) ? $ns[$name] : null;
- }
-
- unset($ns['prefix']);
- return $ns;
- }
-
-
- /**
- * Sets delimiter and namespaces
- */
- protected function set_env()
- {
- if ($this->delimiter !== null && $this->namespace !== null) {
- return;
- }
-
- $config = rcube::get_instance()->config;
- $imap_personal = $config->get('imap_ns_personal');
- $imap_other = $config->get('imap_ns_other');
- $imap_shared = $config->get('imap_ns_shared');
- $imap_delimiter = $config->get('imap_delimiter');
-
- if (!$this->check_connection()) {
- return;
- }
-
- $ns = $this->conn->getNamespace();
-
- // Set namespaces (NAMESPACE supported)
- if (is_array($ns)) {
- $this->namespace = $ns;
- }
- else {
- $this->namespace = array(
- 'personal' => NULL,
- 'other' => NULL,
- 'shared' => NULL,
- );
- }
-
- if ($imap_delimiter) {
- $this->delimiter = $imap_delimiter;
- }
- if (empty($this->delimiter)) {
- $this->delimiter = $this->namespace['personal'][0][1];
- }
- if (empty($this->delimiter)) {
- $this->delimiter = $this->conn->getHierarchyDelimiter();
- }
- if (empty($this->delimiter)) {
- $this->delimiter = '/';
- }
-
- // Overwrite namespaces
- if ($imap_personal !== null) {
- $this->namespace['personal'] = NULL;
- foreach ((array)$imap_personal as $dir) {
- $this->namespace['personal'][] = array($dir, $this->delimiter);
- }
- }
- if ($imap_other !== null) {
- $this->namespace['other'] = NULL;
- foreach ((array)$imap_other as $dir) {
- if ($dir) {
- $this->namespace['other'][] = array($dir, $this->delimiter);
- }
- }
- }
- if ($imap_shared !== null) {
- $this->namespace['shared'] = NULL;
- foreach ((array)$imap_shared as $dir) {
- if ($dir) {
- $this->namespace['shared'][] = array($dir, $this->delimiter);
- }
- }
- }
-
- // Find personal namespace prefix for mod_folder()
- // Prefix can be removed when there is only one personal namespace
- if (is_array($this->namespace['personal']) && count($this->namespace['personal']) == 1) {
- $this->namespace['prefix'] = $this->namespace['personal'][0][0];
- }
-
- $_SESSION['imap_namespace'] = $this->namespace;
- $_SESSION['imap_delimiter'] = $this->delimiter;
- }
-
-
- /**
- * Get message count for a specific folder
- *
- * @param string $folder Folder name
- * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT|EXISTS]
- * @param boolean $force Force reading from server and update cache
- * @param boolean $status Enables storing folder status info (max UID/count),
- * required for folder_status()
- *
- * @return int Number of messages
- */
- public function count($folder='', $mode='ALL', $force=false, $status=true)
- {
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- return $this->countmessages($folder, $mode, $force, $status);
- }
-
-
- /**
- * protected method for getting nr of messages
- *
- * @param string $folder Folder name
- * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT|EXISTS]
- * @param boolean $force Force reading from server and update cache
- * @param boolean $status Enables storing folder status info (max UID/count),
- * required for folder_status()
- *
- * @return int Number of messages
- * @see rcube_imap::count()
- */
- protected function countmessages($folder, $mode='ALL', $force=false, $status=true)
- {
- $mode = strtoupper($mode);
-
- // count search set, assume search set is always up-to-date (don't check $force flag)
- if ($this->search_string && $folder == $this->folder && ($mode == 'ALL' || $mode == 'THREADS')) {
- if ($mode == 'ALL') {
- return $this->search_set->count_messages();
- }
- else {
- return $this->search_set->count();
- }
- }
-
- // EXISTS is a special alias for ALL, it allows to get the number
- // of all messages in a folder also when search is active and with
- // any skip_deleted setting
-
- $a_folder_cache = $this->get_cache('messagecount');
-
- // return cached value
- if (!$force && is_array($a_folder_cache[$folder]) && isset($a_folder_cache[$folder][$mode])) {
- return $a_folder_cache[$folder][$mode];
- }
-
- if (!is_array($a_folder_cache[$folder])) {
- $a_folder_cache[$folder] = array();
- }
-
- if ($mode == 'THREADS') {
- $res = $this->threads($folder);
- $count = $res->count();
-
- if ($status) {
- $msg_count = $res->count_messages();
- $this->set_folder_stats($folder, 'cnt', $msg_count);
- $this->set_folder_stats($folder, 'maxuid', $msg_count ? $this->id2uid($msg_count, $folder) : 0);
- }
- }
- // Need connection here
- else if (!$this->check_connection()) {
- return 0;
- }
- // RECENT count is fetched a bit different
- else if ($mode == 'RECENT') {
- $count = $this->conn->countRecent($folder);
- }
- // use SEARCH for message counting
- else if ($mode != 'EXISTS' && !empty($this->options['skip_deleted'])) {
- $search_str = "ALL UNDELETED";
- $keys = array('COUNT');
-
- if ($mode == 'UNSEEN') {
- $search_str .= " UNSEEN";
- }
- else {
- if ($this->messages_caching) {
- $keys[] = 'ALL';
- }
- if ($status) {
- $keys[] = 'MAX';
- }
- }
-
- // @TODO: if $mode == 'ALL' we could try to use cache index here
-
- // get message count using (E)SEARCH
- // not very performant but more precise (using UNDELETED)
- $index = $this->conn->search($folder, $search_str, true, $keys);
- $count = $index->count();
-
- if ($mode == 'ALL') {
- // Cache index data, will be used in index_direct()
- $this->icache['undeleted_idx'] = $index;
-
- if ($status) {
- $this->set_folder_stats($folder, 'cnt', $count);
- $this->set_folder_stats($folder, 'maxuid', $index->max());
- }
- }
- }
- else {
- if ($mode == 'UNSEEN') {
- $count = $this->conn->countUnseen($folder);
- }
- else {
- $count = $this->conn->countMessages($folder);
- if ($status && $mode == 'ALL') {
- $this->set_folder_stats($folder, 'cnt', $count);
- $this->set_folder_stats($folder, 'maxuid', $count ? $this->id2uid($count, $folder) : 0);
- }
- }
- }
-
- $a_folder_cache[$folder][$mode] = (int)$count;
-
- // write back to cache
- $this->update_cache('messagecount', $a_folder_cache);
-
- return (int)$count;
- }
-
-
- /**
- * Public method for listing message flags
- *
- * @param string $folder Folder name
- * @param array $uids Message UIDs
- * @param int $mod_seq Optional MODSEQ value (of last flag update)
- *
- * @return array Indexed array with message flags
- */
- public function list_flags($folder, $uids, $mod_seq = null)
- {
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- if (!$this->check_connection()) {
- return array();
- }
-
- // @TODO: when cache was synchronized in this request
- // we might already have asked for flag updates, use it.
-
- $flags = $this->conn->fetch($folder, $uids, true, array('FLAGS'), $mod_seq);
- $result = array();
-
- if (!empty($flags)) {
- foreach ($flags as $message) {
- $result[$message->uid] = $message->flags;
- }
- }
-
- return $result;
- }
-
-
- /**
- * Public method for listing headers
- *
- * @param string $folder Folder name
- * @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 int $slice Number of slice items to extract from result array
- *
- * @return array Indexed array with message header objects
- */
- public function list_messages($folder='', $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0)
- {
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- return $this->_list_messages($folder, $page, $sort_field, $sort_order, $slice);
- }
-
-
- /**
- * protected method for listing message headers
- *
- * @param string $folder Folder name
- * @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 int $slice Number of slice items to extract from result array
- *
- * @return array Indexed array with message header objects
- * @see rcube_imap::list_messages
- */
- protected function _list_messages($folder='', $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0)
- {
- if (!strlen($folder)) {
- return array();
- }
-
- $this->set_sort_order($sort_field, $sort_order);
- $page = $page ? $page : $this->list_page;
-
- // use saved message set
- if ($this->search_string) {
- return $this->list_search_messages($folder, $page, $slice);
- }
-
- if ($this->threading) {
- return $this->list_thread_messages($folder, $page, $slice);
- }
-
- // get UIDs of all messages in the folder, sorted
- $index = $this->index($folder, $this->sort_field, $this->sort_order);
-
- if ($index->is_empty()) {
- return array();
- }
-
- $from = ($page-1) * $this->page_size;
- $to = $from + $this->page_size;
-
- $index->slice($from, $to - $from);
-
- if ($slice) {
- $index->slice(-$slice, $slice);
- }
-
- // fetch reqested messages headers
- $a_index = $index->get();
- $a_msg_headers = $this->fetch_headers($folder, $a_index);
-
- return array_values($a_msg_headers);
- }
-
-
- /**
- * protected method for listing message headers using threads
- *
- * @param string $folder Folder name
- * @param int $page Current page to list
- * @param int $slice Number of slice items to extract from result array
- *
- * @return array Indexed array with message header objects
- * @see rcube_imap::list_messages
- */
- protected function list_thread_messages($folder, $page, $slice=0)
- {
- // get all threads (not sorted)
- if ($mcache = $this->get_mcache_engine()) {
- $threads = $mcache->get_thread($folder);
- }
- else {
- $threads = $this->threads($folder);
- }
-
- return $this->fetch_thread_headers($folder, $threads, $page, $slice);
- }
-
- /**
- * Method for fetching threads data
- *
- * @param string $folder Folder name
- *
- * @return rcube_imap_thread Thread data object
- */
- function threads($folder)
- {
- if ($mcache = $this->get_mcache_engine()) {
- // don't store in self's internal cache, cache has it's own internal cache
- return $mcache->get_thread($folder);
- }
-
- if (!empty($this->icache['threads'])) {
- if ($this->icache['threads']->get_parameters('MAILBOX') == $folder) {
- return $this->icache['threads'];
- }
- }
-
- // get all threads
- $result = $this->threads_direct($folder);
-
- // add to internal (fast) cache
- return $this->icache['threads'] = $result;
- }
-
-
- /**
- * Method for direct fetching of threads data
- *
- * @param string $folder Folder name
- *
- * @return rcube_imap_thread Thread data object
- */
- function threads_direct($folder)
- {
- if (!$this->check_connection()) {
- return new rcube_result_thread();
- }
-
- // get all threads
- return $this->conn->thread($folder, $this->threading,
- $this->options['skip_deleted'] ? 'UNDELETED' : '', true);
- }
-
-
- /**
- * protected method for fetching threaded messages headers
- *
- * @param string $folder Folder name
- * @param rcube_result_thread $threads Threads data object
- * @param int $page List page number
- * @param int $slice Number of threads to slice
- *
- * @return array Messages headers
- */
- protected function fetch_thread_headers($folder, $threads, $page, $slice=0)
- {
- // Sort thread structure
- $this->sort_threads($threads);
-
- $from = ($page-1) * $this->page_size;
- $to = $from + $this->page_size;
-
- $threads->slice($from, $to - $from);
-
- if ($slice) {
- $threads->slice(-$slice, $slice);
- }
-
- // Get UIDs of all messages in all threads
- $a_index = $threads->get();
-
- // fetch reqested headers from server
- $a_msg_headers = $this->fetch_headers($folder, $a_index);
-
- unset($a_index);
-
- // Set depth, has_children and unread_children fields in headers
- $this->set_thread_flags($a_msg_headers, $threads);
-
- return array_values($a_msg_headers);
- }
-
-
- /**
- * protected method for setting threaded messages flags:
- * depth, has_children and unread_children
- *
- * @param array $headers Reference to headers array indexed by message UID
- * @param rcube_result_thread $threads Threads data object
- *
- * @return array Message headers array indexed by message UID
- */
- protected function set_thread_flags(&$headers, $threads)
- {
- $parents = array();
-
- list ($msg_depth, $msg_children) = $threads->get_thread_data();
-
- foreach ($headers as $uid => $header) {
- $depth = $msg_depth[$uid];
- $parents = array_slice($parents, 0, $depth);
-
- if (!empty($parents)) {
- $headers[$uid]->parent_uid = end($parents);
- if (empty($header->flags['SEEN']))
- $headers[$parents[0]]->unread_children++;
- }
- array_push($parents, $uid);
-
- $headers[$uid]->depth = $depth;
- $headers[$uid]->has_children = $msg_children[$uid];
- }
- }
-
-
- /**
- * protected method for listing a set of message headers (search results)
- *
- * @param string $folder Folder name
- * @param int $page Current page to list
- * @param int $slice Number of slice items to extract from result array
- *
- * @return array Indexed array with message header objects
- */
- protected function list_search_messages($folder, $page, $slice=0)
- {
- if (!strlen($folder) || empty($this->search_set) || $this->search_set->is_empty()) {
- return array();
- }
-
- // gather messages from a multi-folder search
- if ($this->search_set->multi) {
- $page_size = $this->page_size;
- $sort_field = $this->sort_field;
- $search_set = $this->search_set;
-
- // prepare paging
- $cnt = $search_set->count();
- $from = ($page-1) * $page_size;
- $to = $from + $page_size;
- $slice_length = min($page_size, $cnt - $from);
-
- // fetch resultset headers, sort and slice them
- if (!empty($sort_field)) {
- $this->sort_field = null;
- $this->page_size = 1000; // fetch up to 1000 matching messages per folder
- $this->threading = false;
-
- $a_msg_headers = array();
- foreach ($search_set->sets as $resultset) {
- if (!$resultset->is_empty()) {
- $this->search_set = $resultset;
- $this->search_threads = $resultset instanceof rcube_result_thread;
- $a_msg_headers = array_merge($a_msg_headers, $this->list_search_messages($resultset->get_parameters('MAILBOX'), 1));
- }
- }
-
- // sort headers
- if (!empty($a_msg_headers)) {
- $a_msg_headers = $this->conn->sortHeaders($a_msg_headers, $sort_field, $this->sort_order);
- }
-
- // store (sorted) message index
- $search_set->set_message_index($a_msg_headers, $sort_field, $this->sort_order);
-
- // only return the requested part of the set
- $a_msg_headers = array_slice(array_values($a_msg_headers), $from, $slice_length);
- }
- else {
- if ($this->sort_order != $search_set->get_parameters('ORDER')) {
- $search_set->revert();
- }
-
- // slice resultset first...
- $fetch = array();
- foreach (array_slice($search_set->get(), $from, $slice_length) as $msg_id) {
- list($uid, $folder) = explode('-', $msg_id, 2);
- $fetch[$folder][] = $uid;
- }
-
- // ... and fetch the requested set of headers
- $a_msg_headers = array();
- foreach ($fetch as $folder => $a_index) {
- $a_msg_headers = array_merge($a_msg_headers, array_values($this->fetch_headers($folder, $a_index)));
- }
- }
-
- if ($slice) {
- $a_msg_headers = array_slice($a_msg_headers, -$slice, $slice);
- }
-
- // restore members
- $this->sort_field = $sort_field;
- $this->page_size = $page_size;
- $this->search_set = $search_set;
-
- return $a_msg_headers;
- }
-
- // use saved messages from searching
- if ($this->threading) {
- return $this->list_search_thread_messages($folder, $page, $slice);
- }
-
- // search set is threaded, we need a new one
- if ($this->search_threads) {
- $this->search('', $this->search_string, $this->search_charset, $this->sort_field);
- }
-
- $index = clone $this->search_set;
- $from = ($page-1) * $this->page_size;
- $to = $from + $this->page_size;
-
- // return empty array if no messages found
- if ($index->is_empty()) {
- return array();
- }
-
- // quickest method (default sorting)
- if (!$this->search_sort_field && !$this->sort_field) {
- $got_index = true;
- }
- // sorted messages, so we can first slice array and then fetch only wanted headers
- else if ($this->search_sorted) { // SORT searching result
- $got_index = true;
- // reset search set if sorting field has been changed
- if ($this->sort_field && $this->search_sort_field != $this->sort_field) {
- $this->search('', $this->search_string, $this->search_charset, $this->sort_field);
-
- $index = clone $this->search_set;
-
- // return empty array if no messages found
- if ($index->is_empty()) {
- return array();
- }
- }
- }
-
- if ($got_index) {
- if ($this->sort_order != $index->get_parameters('ORDER')) {
- $index->revert();
- }
-
- // get messages uids for one page
- $index->slice($from, $to-$from);
-
- if ($slice) {
- $index->slice(-$slice, $slice);
- }
-
- // fetch headers
- $a_index = $index->get();
- $a_msg_headers = $this->fetch_headers($folder, $a_index);
-
- return array_values($a_msg_headers);
- }
-
- // SEARCH result, need sorting
- $cnt = $index->count();
-
- // 300: experimantal value for best result
- if (($cnt > 300 && $cnt > $this->page_size) || !$this->sort_field) {
- // use memory less expensive (and quick) method for big result set
- $index = clone $this->index('', $this->sort_field, $this->sort_order);
- // get messages uids for one page...
- $index->slice($from, min($cnt-$from, $this->page_size));
-
- if ($slice) {
- $index->slice(-$slice, $slice);
- }
-
- // ...and fetch headers
- $a_index = $index->get();
- $a_msg_headers = $this->fetch_headers($folder, $a_index);
-
- return array_values($a_msg_headers);
- }
- else {
- // for small result set we can fetch all messages headers
- $a_index = $index->get();
- $a_msg_headers = $this->fetch_headers($folder, $a_index, false);
-
- // return empty array if no messages found
- if (!is_array($a_msg_headers) || empty($a_msg_headers)) {
- return array();
- }
-
- if (!$this->check_connection()) {
- return array();
- }
-
- // if not already sorted
- $a_msg_headers = $this->conn->sortHeaders(
- $a_msg_headers, $this->sort_field, $this->sort_order);
-
- // only return the requested part of the set
- $slice_length = min($this->page_size, $cnt - ($to > $cnt ? $from : $to));
- $a_msg_headers = array_slice(array_values($a_msg_headers), $from, $slice_length);
-
- if ($slice) {
- $a_msg_headers = array_slice($a_msg_headers, -$slice, $slice);
- }
-
- return $a_msg_headers;
- }
- }
-
-
- /**
- * protected method for listing a set of threaded message headers (search results)
- *
- * @param string $folder Folder name
- * @param int $page Current page to list
- * @param int $slice Number of slice items to extract from result array
- *
- * @return array Indexed array with message header objects
- * @see rcube_imap::list_search_messages()
- */
- protected function list_search_thread_messages($folder, $page, $slice=0)
- {
- // update search_set if previous data was fetched with disabled threading
- if (!$this->search_threads) {
- if ($this->search_set->is_empty()) {
- return array();
- }
- $this->search('', $this->search_string, $this->search_charset, $this->sort_field);
- }
-
- return $this->fetch_thread_headers($folder, clone $this->search_set, $page, $slice);
- }
-
-
- /**
- * Fetches messages headers (by UID)
- *
- * @param string $folder Folder name
- * @param array $msgs Message UIDs
- * @param bool $sort Enables result sorting by $msgs
- * @param bool $force Disables cache use
- *
- * @return array Messages headers indexed by UID
- */
- function fetch_headers($folder, $msgs, $sort = true, $force = false)
- {
- if (empty($msgs)) {
- return array();
- }
-
- if (!$force && ($mcache = $this->get_mcache_engine())) {
- $headers = $mcache->get_messages($folder, $msgs);
- }
- else if (!$this->check_connection()) {
- return array();
- }
- else {
- // fetch reqested headers from server
- $headers = $this->conn->fetchHeaders(
- $folder, $msgs, true, false, $this->get_fetch_headers());
- }
-
- if (empty($headers)) {
- return array();
- }
-
- foreach ($headers as $h) {
- $h->folder = $folder;
- $a_msg_headers[$h->uid] = $h;
- }
-
- if ($sort) {
- // use this class for message sorting
- $sorter = new rcube_message_header_sorter();
- $sorter->set_index($msgs);
- $sorter->sort_headers($a_msg_headers);
- }
-
- return $a_msg_headers;
- }
-
-
- /**
- * Returns current status of a folder (compared to the last time use)
- *
- * We compare the maximum UID to determine the number of
- * new messages because the RECENT flag is not reliable.
- *
- * @param string $folder Folder name
- * @param array $diff Difference data
- *
- * @return int Folder status
- */
- public function folder_status($folder = null, &$diff = array())
- {
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
- $old = $this->get_folder_stats($folder);
-
- // refresh message count -> will update
- $this->countmessages($folder, 'ALL', true);
-
- $result = 0;
-
- if (empty($old)) {
- return $result;
- }
-
- $new = $this->get_folder_stats($folder);
-
- // got new messages
- if ($new['maxuid'] > $old['maxuid']) {
- $result += 1;
- // get new message UIDs range, that can be used for example
- // to get the data of these messages
- $diff['new'] = ($old['maxuid'] + 1 < $new['maxuid'] ? ($old['maxuid']+1).':' : '') . $new['maxuid'];
- }
- // some messages has been deleted
- if ($new['cnt'] < $old['cnt']) {
- $result += 2;
- }
-
- // @TODO: optional checking for messages flags changes (?)
- // @TODO: UIDVALIDITY checking
-
- return $result;
- }
-
-
- /**
- * Stores folder statistic data in session
- * @TODO: move to separate DB table (cache?)
- *
- * @param string $folder Folder name
- * @param string $name Data name
- * @param mixed $data Data value
- */
- protected function set_folder_stats($folder, $name, $data)
- {
- $_SESSION['folders'][$folder][$name] = $data;
- }
-
-
- /**
- * Gets folder statistic data
- *
- * @param string $folder Folder name
- *
- * @return array Stats data
- */
- protected function get_folder_stats($folder)
- {
- if ($_SESSION['folders'][$folder]) {
- return (array) $_SESSION['folders'][$folder];
- }
-
- return array();
- }
-
-
- /**
- * Return sorted list of message UIDs
- *
- * @param string $folder Folder to get index from
- * @param string $sort_field Sort column
- * @param string $sort_order Sort order [ASC, DESC]
- * @param bool $no_threads Get not threaded index
- * @param bool $no_search Get index not limited to search result (optionally)
- *
- * @return rcube_result_index|rcube_result_thread List of messages (UIDs)
- */
- public function index($folder = '', $sort_field = NULL, $sort_order = NULL,
- $no_threads = false, $no_search = false
- ) {
- if (!$no_threads && $this->threading) {
- return $this->thread_index($folder, $sort_field, $sort_order);
- }
-
- $this->set_sort_order($sort_field, $sort_order);
-
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- // we have a saved search result, get index from there
- if ($this->search_string) {
- if ($this->search_set->is_empty()) {
- return new rcube_result_index($folder, '* SORT');
- }
-
- if ($this->search_set instanceof rcube_result_multifolder) {
- $index = $this->search_set;
- $index->folder = $folder;
- // TODO: handle changed sorting
- }
- // search result is an index with the same sorting?
- else if (($this->search_set instanceof rcube_result_index)
- && ((!$this->sort_field && !$this->search_sorted) ||
- ($this->search_sorted && $this->search_sort_field == $this->sort_field))
- ) {
- $index = $this->search_set;
- }
- // $no_search is enabled when we are not interested in
- // fetching index for search result, e.g. to sort
- // threaded search result we can use full mailbox index.
- // This makes possible to use index from cache
- else if (!$no_search) {
- if (!$this->sort_field) {
- // No sorting needed, just build index from the search result
- // @TODO: do we need to sort by UID here?
- $search = $this->search_set->get_compressed();
- $index = new rcube_result_index($folder, '* ESEARCH ALL ' . $search);
- }
- else {
- $index = $this->index_direct($folder, $this->search_charset,
- $this->sort_field, $this->search_set);
- }
- }
-
- if (isset($index)) {
- if ($this->sort_order != $index->get_parameters('ORDER')) {
- $index->revert();
- }
-
- return $index;
- }
- }
-
- // check local cache
- if ($mcache = $this->get_mcache_engine()) {
- return $mcache->get_index($folder, $this->sort_field, $this->sort_order);
- }
-
- // fetch from IMAP server
- return $this->index_direct($folder, $this->sort_field, $this->sort_order);
- }
-
-
- /**
- * Return sorted list of message UIDs ignoring current search settings.
- * Doesn't uses cache by default.
- *
- * @param string $folder Folder to get index from
- * @param string $sort_field Sort column
- * @param string $sort_order Sort order [ASC, DESC]
- * @param rcube_result_* $search Optional messages set to limit the result
- *
- * @return rcube_result_index Sorted list of message UIDs
- */
- public function index_direct($folder, $sort_field = null, $sort_order = null, $search = null)
- {
- if (!empty($search)) {
- $search = $search->get_compressed();
- }
-
- // use message index sort as default sorting
- if (!$sort_field) {
- // use search result from count() if possible
- if (empty($search) && $this->options['skip_deleted']
- && !empty($this->icache['undeleted_idx'])
- && $this->icache['undeleted_idx']->get_parameters('ALL') !== null
- && $this->icache['undeleted_idx']->get_parameters('MAILBOX') == $folder
- ) {
- $index = $this->icache['undeleted_idx'];
- }
- else if (!$this->check_connection()) {
- return new rcube_result_index();
- }
- else {
- $query = $this->options['skip_deleted'] ? 'UNDELETED' : '';
- if ($search) {
- $query = trim($query . ' UID ' . $search);
- }
-
- $index = $this->conn->search($folder, $query, true);
- }
- }
- else if (!$this->check_connection()) {
- return new rcube_result_index();
- }
- // fetch complete message index
- else {
- if ($this->get_capability('SORT')) {
- $query = $this->options['skip_deleted'] ? 'UNDELETED' : '';
- if ($search) {
- $query = trim($query . ' UID ' . $search);
- }
-
- $index = $this->conn->sort($folder, $sort_field, $query, true);
- }
-
- if (empty($index) || $index->is_error()) {
- $index = $this->conn->index($folder, $search ? $search : "1:*",
- $sort_field, $this->options['skip_deleted'],
- $search ? true : false, true);
- }
- }
-
- if ($sort_order != $index->get_parameters('ORDER')) {
- $index->revert();
- }
-
- return $index;
- }
-
-
- /**
- * Return index of threaded message UIDs
- *
- * @param string $folder Folder to get index from
- * @param string $sort_field Sort column
- * @param string $sort_order Sort order [ASC, DESC]
- *
- * @return rcube_result_thread Message UIDs
- */
- public function thread_index($folder='', $sort_field=NULL, $sort_order=NULL)
- {
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- // we have a saved search result, get index from there
- if ($this->search_string && $this->search_threads && $folder == $this->folder) {
- $threads = $this->search_set;
- }
- else {
- // get all threads (default sort order)
- $threads = $this->threads($folder);
- }
-
- $this->set_sort_order($sort_field, $sort_order);
- $this->sort_threads($threads);
-
- return $threads;
- }
-
-
- /**
- * Sort threaded result, using THREAD=REFS method if available.
- * If not, use any method and re-sort the result in THREAD=REFS way.
- *
- * @param rcube_result_thread $threads Threads result set
- */
- protected function sort_threads($threads)
- {
- if ($threads->is_empty()) {
- return;
- }
-
- // 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
-
- if ($this->threading != 'REFS' || ($this->sort_field && $this->sort_field != 'date')) {
- $sortby = $this->sort_field ? $this->sort_field : 'date';
- $index = $this->index($this->folder, $sortby, $this->sort_order, true, true);
-
- if (!$index->is_empty()) {
- $threads->sort($index);
- }
- }
- else if ($this->sort_order != $threads->get_parameters('ORDER')) {
- $threads->revert();
- }
- }
-
-
- /**
- * Invoke search request to IMAP server
- *
- * @param string $folder Folder name to search in
- * @param string $search Search criteria
- * @param string $charset Search charset
- * @param string $sort_field Header field to sort by
- *
- * @return rcube_result_index Search result object
- * @todo: Search criteria should be provided in non-IMAP format, eg. array
- */
- public function search($folder = '', $search = 'ALL', $charset = null, $sort_field = null)
- {
- if (!$search) {
- $search = 'ALL';
- }
-
- if ((is_array($folder) && empty($folder)) || (!is_array($folder) && !strlen($folder))) {
- $folder = $this->folder;
- }
-
- $plugin = $this->plugins->exec_hook('imap_search_before', array(
- 'folder' => $folder,
- 'search' => $search,
- 'charset' => $charset,
- 'sort_field' => $sort_field,
- 'threading' => $this->threading,
- ));
-
- $folder = $plugin['folder'];
- $search = $plugin['search'];
- $charset = $plugin['charset'];
- $sort_field = $plugin['sort_field'];
- $results = $plugin['result'];
-
- // multi-folder search
- if (!$results && is_array($folder) && count($folder) > 1 && $search != 'ALL') {
- // connect IMAP to have all the required classes and settings loaded
- $this->check_connection();
-
- // disable threading
- $this->threading = false;
-
- $searcher = new rcube_imap_search($this->options, $this->conn);
-
- // set limit to not exceed the client's request timeout
- $searcher->set_timelimit(60);
-
- // continue existing incomplete search
- if (!empty($this->search_set) && $this->search_set->incomplete && $search == $this->search_string) {
- $searcher->set_results($this->search_set);
- }
-
- // execute the search
- $results = $searcher->exec(
- $folder,
- $search,
- $charset ? $charset : $this->default_charset,
- $sort_field && $this->get_capability('SORT') ? $sort_field : null,
- $this->threading
- );
- }
- else if (!$results) {
- $folder = is_array($folder) ? $folder[0] : $folder;
- $search = is_array($search) ? $search[$folder] : $search;
- $results = $this->search_index($folder, $search, $charset, $sort_field);
- }
-
- $sorted = $this->threading || $this->search_sorted || $plugin['search_sorted'] ? true : false;
-
- $this->set_search_set(array($search, $results, $charset, $sort_field, $sorted));
-
- return $results;
- }
-
-
- /**
- * Direct (real and simple) SEARCH request (without result sorting and caching).
- *
- * @param string $mailbox Mailbox name to search in
- * @param string $str Search string
- *
- * @return rcube_result_index Search result (UIDs)
- */
- public function search_once($folder = null, $str = 'ALL')
- {
- if (!$this->check_connection()) {
- return new rcube_result_index();
- }
-
- if (!$str) {
- $str = 'ALL';
- }
-
- // multi-folder search
- if (is_array($folder) && count($folder) > 1) {
- $searcher = new rcube_imap_search($this->options, $this->conn);
- $index = $searcher->exec($folder, $str, $this->default_charset);
- }
- else {
- $folder = is_array($folder) ? $folder[0] : $folder;
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
- $index = $this->conn->search($folder, $str, true);
- }
-
- return $index;
- }
-
-
- /**
- * protected search method
- *
- * @param string $folder Folder name
- * @param string $criteria Search criteria
- * @param string $charset Charset
- * @param string $sort_field Sorting field
- *
- * @return rcube_result_index|rcube_result_thread Search results (UIDs)
- * @see rcube_imap::search()
- */
- protected function search_index($folder, $criteria='ALL', $charset=NULL, $sort_field=NULL)
- {
- if (!$this->check_connection()) {
- if ($this->threading) {
- return new rcube_result_thread();
- }
- else {
- return new rcube_result_index();
- }
- }
-
- if ($this->options['skip_deleted'] && !preg_match('/UNDELETED/', $criteria)) {
- $criteria = 'UNDELETED '.$criteria;
- }
-
- // unset CHARSET if criteria string is ASCII, this way
- // SEARCH won't be re-sent after "unsupported charset" response
- if ($charset && $charset != 'US-ASCII' && is_ascii($criteria)) {
- $charset = 'US-ASCII';
- }
-
- if ($this->threading) {
- $threads = $this->conn->thread($folder, $this->threading, $criteria, true, $charset);
-
- // 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)
- if ($threads->is_error() && $charset && $charset != 'US-ASCII') {
- $threads = $this->conn->thread($folder, $this->threading,
- self::convert_criteria($criteria, $charset), true, 'US-ASCII');
- }
-
- return $threads;
- }
-
- if ($sort_field && $this->get_capability('SORT')) {
- $charset = $charset ? $charset : $this->default_charset;
- $messages = $this->conn->sort($folder, $sort_field, $criteria, true, $charset);
-
- // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8,
- // but I've seen Courier with disabled UTF-8 support)
- if ($messages->is_error() && $charset && $charset != 'US-ASCII') {
- $messages = $this->conn->sort($folder, $sort_field,
- self::convert_criteria($criteria, $charset), true, 'US-ASCII');
- }
-
- if (!$messages->is_error()) {
- $this->search_sorted = true;
- return $messages;
- }
- }
-
- $messages = $this->conn->search($folder,
- ($charset && $charset != 'US-ASCII' ? "CHARSET $charset " : '') . $criteria, true);
-
- // Error, try with US-ASCII (some servers may support only US-ASCII)
- if ($messages->is_error() && $charset && $charset != 'US-ASCII') {
- $messages = $this->conn->search($folder,
- self::convert_criteria($criteria, $charset), true);
- }
-
- $this->search_sorted = false;
-
- return $messages;
- }
-
-
- /**
- * Converts charset of search criteria string
- *
- * @param string $str Search string
- * @param string $charset Original charset
- * @param string $dest_charset Destination charset (default US-ASCII)
- *
- * @return string Search string
- */
- public static function convert_criteria($str, $charset, $dest_charset='US-ASCII')
- {
- // convert strings to US_ASCII
- if (preg_match_all('/\{([0-9]+)\}\r\n/', $str, $matches, PREG_OFFSET_CAPTURE)) {
- $last = 0; $res = '';
- foreach ($matches[1] as $m) {
- $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 === false || !strlen($string)) {
- continue;
- }
-
- $res .= substr($str, $last, $m[1] - $last - 1) . rcube_imap_generic::escape($string);
- $last = $m[0] + $string_offset - 1;
- }
-
- if ($last < strlen($str)) {
- $res .= substr($str, $last, strlen($str)-$last);
- }
- }
- // strings for conversion not found
- else {
- $res = $str;
- }
-
- return $res;
- }
-
-
- /**
- * Refresh saved search set
- *
- * @return array Current search set
- */
- public function refresh_search()
- {
- if (!empty($this->search_string)) {
- $this->search(
- is_object($this->search_set) ? $this->search_set->get_parameters('MAILBOX') : '',
- $this->search_string,
- $this->search_charset,
- $this->search_sort_field
- );
- }
-
- return $this->get_search_set();
- }
-
- /**
- * Flag certain result subsets as 'incomplete'.
- * For subsequent refresh_search() calls to only refresh the updated parts.
- */
- protected function set_search_dirty($folder)
- {
- if ($this->search_set && is_a($this->search_set, 'rcube_result_multifolder')) {
- if ($subset = $this->search_set->get_set($folder)) {
- $subset->incomplete = $this->search_set->incomplete = true;
- }
- }
- }
-
-
- /**
- * Return message headers object of a specific message
- *
- * @param int $id Message UID
- * @param string $folder Folder to read from
- * @param bool $force True to skip cache
- *
- * @return rcube_message_header Message headers
- */
- public function get_message_headers($uid, $folder = null, $force = false)
- {
- // decode combined UID-folder identifier
- if (preg_match('/^\d+-.+/', $uid)) {
- list($uid, $folder) = explode('-', $uid, 2);
- }
-
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- // get cached headers
- if (!$force && $uid && ($mcache = $this->get_mcache_engine())) {
- $headers = $mcache->get_message($folder, $uid);
- }
- else if (!$this->check_connection()) {
- $headers = false;
- }
- else {
- $headers = $this->conn->fetchHeader(
- $folder, $uid, true, true, $this->get_fetch_headers());
-
- if (is_object($headers))
- $headers->folder = $folder;
- }
-
- return $headers;
- }
-
-
- /**
- * 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 $folder Folder to read from
- *
- * @return object rcube_message_header Message data
- */
- public function get_message($uid, $folder = null)
- {
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- // decode combined UID-folder identifier
- if (preg_match('/^\d+-.+/', $uid)) {
- list($uid, $folder) = explode('-', $uid, 2);
- }
-
- // Check internal cache
- if (!empty($this->icache['message'])) {
- if (($headers = $this->icache['message']) && $headers->uid == $uid) {
- return $headers;
- }
- }
-
- $headers = $this->get_message_headers($uid, $folder);
-
- // message doesn't exist?
- if (empty($headers)) {
- return null;
- }
-
- // structure might be cached
- if (!empty($headers->structure)) {
- return $headers;
- }
-
- $this->msg_uid = $uid;
-
- if (!$this->check_connection()) {
- return $headers;
- }
-
- if (empty($headers->bodystructure)) {
- $headers->bodystructure = $this->conn->getStructure($folder, $uid, true);
- }
-
- $structure = $headers->bodystructure;
-
- if (empty($structure)) {
- return $headers;
- }
-
- // set message charset from message headers
- if ($headers->charset) {
- $this->struct_charset = $headers->charset;
- }
- else {
- $this->struct_charset = $this->structure_charset($structure);
- }
-
- $headers->ctype = @strtolower($headers->ctype);
-
- // Here we can recognize malformed BODYSTRUCTURE and
- // 1. [@TODO] parse the message in other way to create our own message structure
- // 2. or just show the raw message body.
- // Example of structure for malformed MIME message:
- // ("text" "plain" NIL NIL NIL "7bit" 2154 70 NIL NIL NIL)
- if ($headers->ctype && !is_array($structure[0]) && $headers->ctype != 'text/plain'
- && strtolower($structure[0].'/'.$structure[1]) == 'text/plain'
- ) {
- // A special known case "Content-type: text" (#1488968)
- if ($headers->ctype == 'text') {
- $structure[1] = 'plain';
- $headers->ctype = 'text/plain';
- }
- // we can handle single-part messages, by simple fix in structure (#1486898)
- else if (preg_match('/^(text|application)\/(.*)/', $headers->ctype, $m)) {
- $structure[0] = $m[1];
- $structure[1] = $m[2];
- }
- else {
- // Try to parse the message using Mail_mimeDecode package
- // We need a better solution, Mail_mimeDecode parses message
- // in memory, which wouldn't work for very big messages,
- // (it uses up to 10x more memory than the message size)
- // it's also buggy and not actively developed
- if ($headers->size && rcube_utils::mem_check($headers->size * 10)) {
- $raw_msg = $this->get_raw_body($uid);
- $struct = rcube_mime::parse_message($raw_msg);
- }
- else {
- return $headers;
- }
- }
- }
-
- if (empty($struct)) {
- $struct = $this->structure_part($structure, 0, '', $headers);
- }
-
- // some workarounds on simple messages...
- if (empty($struct->parts)) {
- // ...don't trust given content-type
- if (!empty($headers->ctype)) {
- $struct->mime_id = '1';
- $struct->mimetype = strtolower($headers->ctype);
- list($struct->ctype_primary, $struct->ctype_secondary) = explode('/', $struct->mimetype);
- }
-
- // ...and charset (there's a case described in #1488968 where invalid content-type
- // results in invalid charset in BODYSTRUCTURE)
- if (!empty($headers->charset) && $headers->charset != $struct->ctype_parameters['charset']) {
- $struct->charset = $headers->charset;
- $struct->ctype_parameters['charset'] = $headers->charset;
- }
- }
-
- $headers->structure = $struct;
-
- return $this->icache['message'] = $headers;
- }
-
-
- /**
- * Build message part object
- *
- * @param array $part
- * @param int $count
- * @param string $parent
- */
- protected function structure_part($part, $count=0, $parent='', $mime_headers=null)
- {
- $struct = new rcube_message_part;
- $struct->mime_id = empty($parent) ? (string)$count : "$parent.$count";
-
- // multipart
- if (is_array($part[0])) {
- $struct->ctype_primary = 'multipart';
-
- /* RFC3501: BODYSTRUCTURE fields of multipart part
- part1 array
- part2 array
- part3 array
- ....
- 1. subtype
- 2. parameters (optional)
- 3. description (optional)
- 4. language (optional)
- 5. location (optional)
- */
-
- // find first non-array entry
- for ($i=1; $i<count($part); $i++) {
- if (!is_array($part[$i])) {
- $struct->ctype_secondary = strtolower($part[$i]);
- break;
- }
- }
-
- $struct->mimetype = 'multipart/'.$struct->ctype_secondary;
-
- // build parts list for headers pre-fetching
- for ($i=0; $i<count($part); $i++) {
- if (!is_array($part[$i])) {
- break;
- }
- // fetch message headers if message/rfc822
- // or named part (could contain Content-Location header)
- if (!is_array($part[$i][0])) {
- $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
- if (strtolower($part[$i][0]) == 'message' && strtolower($part[$i][1]) == 'rfc822') {
- $mime_part_headers[] = $tmp_part_id;
- }
- else if (in_array('name', (array)$part[$i][2]) && empty($part[$i][3])) {
- $mime_part_headers[] = $tmp_part_id;
- }
- }
- }
-
- // pre-fetch headers of all parts (in one command for better performance)
- // @TODO: we could do this before _structure_part() call, to fetch
- // headers for parts on all levels
- if ($mime_part_headers) {
- $mime_part_headers = $this->conn->fetchMIMEHeaders($this->folder,
- $this->msg_uid, $mime_part_headers);
- }
-
- $struct->parts = array();
- for ($i=0, $count=0; $i<count($part); $i++) {
- if (!is_array($part[$i])) {
- break;
- }
- $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
- $struct->parts[] = $this->structure_part($part[$i], ++$count, $struct->mime_id,
- $mime_part_headers[$tmp_part_id]);
- }
-
- return $struct;
- }
-
- /* RFC3501: BODYSTRUCTURE fields of non-multipart part
- 0. type
- 1. subtype
- 2. parameters
- 3. id
- 4. description
- 5. encoding
- 6. size
- -- text
- 7. lines
- -- message/rfc822
- 7. envelope structure
- 8. body structure
- 9. lines
- --
- x. md5 (optional)
- x. disposition (optional)
- x. language (optional)
- x. location (optional)
- */
-
- // regular part
- $struct->ctype_primary = strtolower($part[0]);
- $struct->ctype_secondary = strtolower($part[1]);
- $struct->mimetype = $struct->ctype_primary.'/'.$struct->ctype_secondary;
-
- // read content type parameters
- if (is_array($part[2])) {
- $struct->ctype_parameters = array();
- for ($i=0; $i<count($part[2]); $i+=2) {
- $struct->ctype_parameters[strtolower($part[2][$i])] = $part[2][$i+1];
- }
-
- if (isset($struct->ctype_parameters['charset'])) {
- $struct->charset = $struct->ctype_parameters['charset'];
- }
- }
-
- // #1487700: workaround for lack of charset in malformed structure
- if (empty($struct->charset) && !empty($mime_headers) && $mime_headers->charset) {
- $struct->charset = $mime_headers->charset;
- }
-
- // read content encoding
- if (!empty($part[5])) {
- $struct->encoding = strtolower($part[5]);
- $struct->headers['content-transfer-encoding'] = $struct->encoding;
- }
-
- // get part size
- if (!empty($part[6])) {
- $struct->size = intval($part[6]);
- }
-
- // read part disposition
- $di = 8;
- if ($struct->ctype_primary == 'text') {
- $di += 1;
- }
- else if ($struct->mimetype == 'message/rfc822') {
- $di += 3;
- }
-
- if (is_array($part[$di]) && count($part[$di]) == 2) {
- $struct->disposition = strtolower($part[$di][0]);
-
- if (is_array($part[$di][1])) {
- for ($n=0; $n<count($part[$di][1]); $n+=2) {
- $struct->d_parameters[strtolower($part[$di][1][$n])] = $part[$di][1][$n+1];
- }
- }
- }
-
- // get message/rfc822's child-parts
- if (is_array($part[8]) && $di != 8) {
- $struct->parts = array();
- for ($i=0, $count=0; $i<count($part[8]); $i++) {
- if (!is_array($part[8][$i])) {
- break;
- }
- $struct->parts[] = $this->structure_part($part[8][$i], ++$count, $struct->mime_id);
- }
- }
-
- // get part ID
- if (!empty($part[3])) {
- $struct->content_id = $part[3];
- $struct->headers['content-id'] = $part[3];
-
- if (empty($struct->disposition)) {
- $struct->disposition = 'inline';
- }
- }
-
- // fetch message headers if message/rfc822 or named part (could contain Content-Location header)
- if ($struct->ctype_primary == 'message' || ($struct->ctype_parameters['name'] && !$struct->content_id)) {
- if (empty($mime_headers)) {
- $mime_headers = $this->conn->fetchPartHeader(
- $this->folder, $this->msg_uid, true, $struct->mime_id);
- }
-
- if (is_string($mime_headers)) {
- $struct->headers = rcube_mime::parse_headers($mime_headers) + $struct->headers;
- }
- else if (is_object($mime_headers)) {
- $struct->headers = get_object_vars($mime_headers) + $struct->headers;
- }
-
- // get real content-type of message/rfc822
- if ($struct->mimetype == 'message/rfc822') {
- // single-part
- if (!is_array($part[8][0])) {
- $struct->real_mimetype = strtolower($part[8][0] . '/' . $part[8][1]);
- }
- // multi-part
- else {
- for ($n=0; $n<count($part[8]); $n++) {
- if (!is_array($part[8][$n])) {
- break;
- }
- }
- $struct->real_mimetype = 'multipart/' . strtolower($part[8][$n]);
- }
- }
-
- if ($struct->ctype_primary == 'message' && empty($struct->parts)) {
- if (is_array($part[8]) && $di != 8) {
- $struct->parts[] = $this->structure_part($part[8], ++$count, $struct->mime_id);
- }
- }
- }
-
- // normalize filename property
- $this->set_part_filename($struct, $mime_headers);
-
- return $struct;
- }
-
-
- /**
- * Set attachment filename from message part structure
- *
- * @param rcube_message_part $part Part object
- * @param string $headers Part's raw headers
- */
- protected function set_part_filename(&$part, $headers=null)
- {
- if (!empty($part->d_parameters['filename'])) {
- $filename_mime = $part->d_parameters['filename'];
- }
- else if (!empty($part->d_parameters['filename*'])) {
- $filename_encoded = $part->d_parameters['filename*'];
- }
- else if (!empty($part->ctype_parameters['name*'])) {
- $filename_encoded = $part->ctype_parameters['name*'];
- }
- // RFC2231 value continuations
- // TODO: this should be rewrited to support RFC2231 4.1 combinations
- else if (!empty($part->d_parameters['filename*0'])) {
- $i = 0;
- while (isset($part->d_parameters['filename*'.$i])) {
- $filename_mime .= $part->d_parameters['filename*'.$i];
- $i++;
- }
- // some servers (eg. dovecot-1.x) have no support for parameter value continuations
- // we must fetch and parse headers "manually"
- if ($i<2) {
- if (!$headers) {
- $headers = $this->conn->fetchPartHeader(
- $this->folder, $this->msg_uid, true, $part->mime_id);
- }
- $filename_mime = '';
- $i = 0;
- while (preg_match('/filename\*'.$i.'\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) {
- $filename_mime .= $matches[1];
- $i++;
- }
- }
- }
- else if (!empty($part->d_parameters['filename*0*'])) {
- $i = 0;
- while (isset($part->d_parameters['filename*'.$i.'*'])) {
- $filename_encoded .= $part->d_parameters['filename*'.$i.'*'];
- $i++;
- }
- if ($i<2) {
- if (!$headers) {
- $headers = $this->conn->fetchPartHeader(
- $this->folder, $this->msg_uid, true, $part->mime_id);
- }
- $filename_encoded = '';
- $i = 0; $matches = array();
- while (preg_match('/filename\*'.$i.'\*\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) {
- $filename_encoded .= $matches[1];
- $i++;
- }
- }
- }
- else if (!empty($part->ctype_parameters['name*0'])) {
- $i = 0;
- while (isset($part->ctype_parameters['name*'.$i])) {
- $filename_mime .= $part->ctype_parameters['name*'.$i];
- $i++;
- }
- if ($i<2) {
- if (!$headers) {
- $headers = $this->conn->fetchPartHeader(
- $this->folder, $this->msg_uid, true, $part->mime_id);
- }
- $filename_mime = '';
- $i = 0; $matches = array();
- while (preg_match('/\s+name\*'.$i.'\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) {
- $filename_mime .= $matches[1];
- $i++;
- }
- }
- }
- else if (!empty($part->ctype_parameters['name*0*'])) {
- $i = 0;
- while (isset($part->ctype_parameters['name*'.$i.'*'])) {
- $filename_encoded .= $part->ctype_parameters['name*'.$i.'*'];
- $i++;
- }
- if ($i<2) {
- if (!$headers) {
- $headers = $this->conn->fetchPartHeader(
- $this->folder, $this->msg_uid, true, $part->mime_id);
- }
- $filename_encoded = '';
- $i = 0; $matches = array();
- while (preg_match('/\s+name\*'.$i.'\*\s*=\s*"*([^"\n;]+)[";]*/', $headers, $matches)) {
- $filename_encoded .= $matches[1];
- $i++;
- }
- }
- }
- // read 'name' after rfc2231 parameters as it may contains truncated filename (from Thunderbird)
- else if (!empty($part->ctype_parameters['name'])) {
- $filename_mime = $part->ctype_parameters['name'];
- }
- // Content-Disposition
- else if (!empty($part->headers['content-description'])) {
- $filename_mime = $part->headers['content-description'];
- }
- else {
- return;
- }
-
- // decode filename
- if (!empty($filename_mime)) {
- if (!empty($part->charset)) {
- $charset = $part->charset;
- }
- else if (!empty($this->struct_charset)) {
- $charset = $this->struct_charset;
- }
- else {
- $charset = rcube_charset::detect($filename_mime, $this->default_charset);
- }
-
- $part->filename = rcube_mime::decode_mime_string($filename_mime, $charset);
- }
- else if (!empty($filename_encoded)) {
- // decode filename according to RFC 2231, Section 4
- if (preg_match("/^([^']*)'[^']*'(.*)$/", $filename_encoded, $fmatches)) {
- $filename_charset = $fmatches[1];
- $filename_encoded = $fmatches[2];
- }
-
- $part->filename = rcube_charset::convert(urldecode($filename_encoded), $filename_charset);
- }
- }
-
-
- /**
- * Get charset name from message structure (first part)
- *
- * @param array $structure Message structure
- *
- * @return string Charset name
- */
- protected function structure_charset($structure)
- {
- while (is_array($structure)) {
- if (is_array($structure[2]) && $structure[2][0] == 'charset') {
- return $structure[2][1];
- }
- $structure = $structure[0];
- }
- }
-
-
- /**
- * Fetch message body of a specific message from the server
- *
- * @param int Message UID
- * @param string Part number
- * @param rcube_message_part Part object created by get_structure()
- * @param mixed True to print part, resource to write part contents in
- * @param resource File pointer to save the message part
- * @param boolean Disables charset conversion
- * @param int Only read this number of bytes
- * @param boolean Enables formatting of text/* parts bodies
- *
- * @return string Message/part body if not printed
- */
- public function get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL, $skip_charset_conv=false, $max_bytes=0, $formatted=true)
- {
- if (!$this->check_connection()) {
- return null;
- }
-
- // get part data if not provided
- if (!is_object($o_part)) {
- $structure = $this->conn->getStructure($this->folder, $uid, true);
- $part_data = rcube_imap_generic::getStructurePartData($structure, $part);
-
- $o_part = new rcube_message_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'];
- }
-
- if ($o_part && $o_part->size) {
- $formatted = $formatted && $o_part->ctype_primary == 'text';
- $body = $this->conn->handlePartBody($this->folder, $uid, true,
- $part ? $part : 'TEXT', $o_part->encoding, $print, $fp, $formatted, $max_bytes);
- }
-
- if ($fp || $print) {
- return true;
- }
-
- // convert charset (if text or message part)
- if ($body && preg_match('/^(text|message)$/', $o_part->ctype_primary)) {
- // Remove NULL characters if any (#1486189)
- if ($formatted && strpos($body, "\x00") !== false) {
- $body = str_replace("\x00", '', $body);
- }
-
- if (!$skip_charset_conv) {
- if (!$o_part->charset || strtoupper($o_part->charset) == 'US-ASCII') {
- // 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);
- }
- }
-
- return $body;
- }
-
-
- /**
- * Returns the whole message source as string (or saves to a file)
- *
- * @param int $uid Message UID
- * @param resource $fp File pointer to save the message
- *
- * @return string Message source string
- */
- public function get_raw_body($uid, $fp=null)
- {
- if (!$this->check_connection()) {
- return null;
- }
-
- return $this->conn->handlePartBody($this->folder, $uid,
- true, null, null, false, $fp);
- }
-
-
- /**
- * Returns the message headers as string
- *
- * @param int $uid Message UID
- *
- * @return string Message headers string
- */
- public function get_raw_headers($uid)
- {
- if (!$this->check_connection()) {
- return null;
- }
-
- return $this->conn->fetchPartHeader($this->folder, $uid, true);
- }
-
-
- /**
- * Sends the whole message source to stdout
- *
- * @param int $uid Message UID
- * @param bool $formatted Enables line-ending formatting
- */
- public function print_raw_body($uid, $formatted = true)
- {
- if (!$this->check_connection()) {
- return;
- }
-
- $this->conn->handlePartBody($this->folder, $uid, true, null, null, true, null, $formatted);
- }
-
-
- /**
- * Set message flag to one or several messages
- *
- * @param mixed $uids Message UIDs as array or comma-separated string, or '*'
- * @param string $flag Flag to set: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT, MDNSENT
- * @param string $folder Folder name
- * @param boolean $skip_cache True to skip message cache clean up
- *
- * @return boolean Operation status
- */
- public function set_flag($uids, $flag, $folder=null, $skip_cache=false)
- {
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- if (!$this->check_connection()) {
- return false;
- }
-
- $flag = strtoupper($flag);
- list($uids, $all_mode) = $this->parse_uids($uids);
-
- if (strpos($flag, 'UN') === 0) {
- $result = $this->conn->unflag($folder, $uids, substr($flag, 2));
- }
- else {
- $result = $this->conn->flag($folder, $uids, $flag);
- }
-
- if ($result && !$skip_cache) {
- // reload message headers if cached
- // update flags instead removing from cache
- if ($mcache = $this->get_mcache_engine()) {
- $status = strpos($flag, 'UN') !== 0;
- $mflag = preg_replace('/^UN/', '', $flag);
- $mcache->change_flag($folder, $all_mode ? null : explode(',', $uids),
- $mflag, $status);
- }
-
- // clear cached counters
- if ($flag == 'SEEN' || $flag == 'UNSEEN') {
- $this->clear_messagecount($folder, 'SEEN');
- $this->clear_messagecount($folder, 'UNSEEN');
- }
- else if ($flag == 'DELETED' || $flag == 'UNDELETED') {
- $this->clear_messagecount($folder, 'DELETED');
- // remove cached messages
- if ($this->options['skip_deleted']) {
- $this->clear_message_cache($folder, $all_mode ? null : explode(',', $uids));
- }
- }
-
- $this->set_search_dirty($folder);
- }
-
- return $result;
- }
-
-
- /**
- * Append a mail message (source) to a specific folder
- *
- * @param string $folder Target folder
- * @param string|array $message The message source string or filename
- * or array (of strings and file pointers)
- * @param string $headers Headers string if $message contains only the body
- * @param boolean $is_file True if $message is a filename
- * @param array $flags Message flags
- * @param mixed $date Message internal date
- * @param bool $binary Enables BINARY append
- *
- * @return int|bool Appended message UID or True on success, False on error
- */
- public function save_message($folder, &$message, $headers='', $is_file=false, $flags = array(), $date = null, $binary = false)
- {
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- if (!$this->check_connection()) {
- return false;
- }
-
- // make sure folder exists
- if (!$this->folder_exists($folder)) {
- return false;
- }
-
- $date = $this->date_format($date);
-
- if ($is_file) {
- $saved = $this->conn->appendFromFile($folder, $message, $headers, $flags, $date, $binary);
- }
- else {
- $saved = $this->conn->append($folder, $message, $flags, $date, $binary);
- }
-
- if ($saved) {
- // increase messagecount of the target folder
- $this->set_messagecount($folder, 'ALL', 1);
-
- $this->plugins->exec_hook('message_saved', array(
- 'folder' => $folder,
- 'message' => $message,
- 'headers' => $headers,
- 'is_file' => $is_file,
- 'flags' => $flags,
- 'date' => $date,
- 'binary' => $binary,
- 'result' => $saved,
- ));
- }
-
- return $saved;
- }
-
-
- /**
- * Move a message from one folder to another
- *
- * @param mixed $uids Message UIDs as array or comma-separated string, or '*'
- * @param string $to_mbox Target folder
- * @param string $from_mbox Source folder
- *
- * @return boolean True on success, False on error
- */
- public function move_message($uids, $to_mbox, $from_mbox='')
- {
- if (!strlen($from_mbox)) {
- $from_mbox = $this->folder;
- }
-
- if ($to_mbox === $from_mbox) {
- return false;
- }
-
- list($uids, $all_mode) = $this->parse_uids($uids);
-
- // exit if no message uids are specified
- if (empty($uids)) {
- return false;
- }
-
- if (!$this->check_connection()) {
- return false;
- }
-
- $config = rcube::get_instance()->config;
- $to_trash = $to_mbox == $config->get('trash_mbox');
-
- // flag messages as read before moving them
- if ($to_trash && $config->get('read_when_deleted')) {
- // don't flush cache (4th argument)
- $this->set_flag($uids, 'SEEN', $from_mbox, true);
- }
-
- // move messages
- $moved = $this->conn->move($uids, $from_mbox, $to_mbox);
-
- if ($moved) {
- $this->clear_messagecount($from_mbox);
- $this->clear_messagecount($to_mbox);
-
- $this->set_search_dirty($from_mbox);
- $this->set_search_dirty($to_mbox);
- }
- // moving failed
- else if ($to_trash && $config->get('delete_always', false)) {
- $moved = $this->delete_message($uids, $from_mbox);
- }
-
- if ($moved) {
- // unset threads internal cache
- unset($this->icache['threads']);
-
- // remove message ids from search set
- if ($this->search_set && $from_mbox == $this->folder) {
- // threads are too complicated to just remove messages from set
- if ($this->search_threads || $all_mode) {
- $this->refresh_search();
- }
- else if (!$this->search_set->incomplete) {
- $this->search_set->filter(explode(',', $uids), $this->folder);
- }
- }
-
- // remove cached messages
- // @TODO: do cache update instead of clearing it
- $this->clear_message_cache($from_mbox, $all_mode ? null : explode(',', $uids));
- }
-
- return $moved;
- }
-
-
- /**
- * Copy a message from one folder to another
- *
- * @param mixed $uids Message UIDs as array or comma-separated string, or '*'
- * @param string $to_mbox Target folder
- * @param string $from_mbox Source folder
- *
- * @return boolean True on success, False on error
- */
- public function copy_message($uids, $to_mbox, $from_mbox='')
- {
- if (!strlen($from_mbox)) {
- $from_mbox = $this->folder;
- }
-
- list($uids, $all_mode) = $this->parse_uids($uids);
-
- // exit if no message uids are specified
- if (empty($uids)) {
- return false;
- }
-
- if (!$this->check_connection()) {
- return false;
- }
-
- // copy messages
- $copied = $this->conn->copy($uids, $from_mbox, $to_mbox);
-
- if ($copied) {
- $this->clear_messagecount($to_mbox);
- }
-
- return $copied;
- }
-
-
- /**
- * Mark messages as deleted and expunge them
- *
- * @param mixed $uids Message UIDs as array or comma-separated string, or '*'
- * @param string $folder Source folder
- *
- * @return boolean True on success, False on error
- */
- public function delete_message($uids, $folder='')
- {
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- list($uids, $all_mode) = $this->parse_uids($uids);
-
- // exit if no message uids are specified
- if (empty($uids)) {
- return false;
- }
-
- if (!$this->check_connection()) {
- return false;
- }
-
- $deleted = $this->conn->flag($folder, $uids, 'DELETED');
-
- if ($deleted) {
- // send expunge command in order to have the deleted message
- // really deleted from the folder
- $this->expunge_message($uids, $folder, false);
- $this->clear_messagecount($folder);
- unset($this->uid_id_map[$folder]);
-
- // unset threads internal cache
- unset($this->icache['threads']);
-
- $this->set_search_dirty($folder);
-
- // remove message ids from search set
- if ($this->search_set && $folder == $this->folder) {
- // threads are too complicated to just remove messages from set
- if ($this->search_threads || $all_mode) {
- $this->refresh_search();
- }
- else if (!$this->search_set->incomplete) {
- $this->search_set->filter(explode(',', $uids));
- }
- }
-
- // remove cached messages
- $this->clear_message_cache($folder, $all_mode ? null : explode(',', $uids));
- }
-
- return $deleted;
- }
-
-
- /**
- * Send IMAP expunge command and clear cache
- *
- * @param mixed $uids Message UIDs as array or comma-separated string, or '*'
- * @param string $folder Folder name
- * @param boolean $clear_cache False if cache should not be cleared
- *
- * @return boolean True on success, False on failure
- */
- public function expunge_message($uids, $folder = null, $clear_cache = true)
- {
- if ($uids && $this->get_capability('UIDPLUS')) {
- list($uids, $all_mode) = $this->parse_uids($uids);
- }
- else {
- $uids = null;
- }
-
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- if (!$this->check_connection()) {
- return false;
- }
-
- // force folder selection and check if folder is writeable
- // to prevent a situation when CLOSE is executed on closed
- // or EXPUNGE on read-only folder
- $result = $this->conn->select($folder);
- if (!$result) {
- return false;
- }
-
- if (!$this->conn->data['READ-WRITE']) {
- $this->conn->setError(rcube_imap_generic::ERROR_READONLY, "Folder is read-only");
- return false;
- }
-
- // CLOSE(+SELECT) should be faster than EXPUNGE
- if (empty($uids) || $all_mode) {
- $result = $this->conn->close();
- }
- else {
- $result = $this->conn->expunge($folder, $uids);
- }
-
- if ($result && $clear_cache) {
- $this->clear_message_cache($folder, $all_mode ? null : explode(',', $uids));
- $this->clear_messagecount($folder);
- }
-
- return $result;
- }
-
-
- /* --------------------------------
- * folder managment
- * --------------------------------*/
-
- /**
- * 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 $rights Optional ACL requirements
- * @param bool $skip_sort Enable to return unsorted list (for better performance)
- *
- * @return array List of folders
- */
- public function list_folders_subscribed($root='', $name='*', $filter=null, $rights=null, $skip_sort=false)
- {
- $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;
- }
-
- // Give plugins a chance to provide a list of folders
- $data = $this->plugins->exec_hook('storage_folders',
- array('root' => $root, 'name' => $name, 'filter' => $filter, 'mode' => 'LSUB'));
-
- if (isset($data['folders'])) {
- $a_mboxes = $data['folders'];
- }
- else {
- $a_mboxes = $this->list_folders_subscribed_direct($root, $name);
- }
-
- 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 folders (always sort for cache)
- if (!$skip_sort || $this->cache) {
- $a_mboxes = $this->sort_folder_list($a_mboxes);
- }
-
- // write folders list to cache
- $this->update_cache($cache_key, $a_mboxes);
-
- return $a_mboxes;
- }
-
-
- /**
- * Method for direct folders listing (LSUB)
- *
- * @param string $root Optional root folder
- * @param string $name Optional name pattern
- *
- * @return array List of subscribed folders
- * @see rcube_imap::list_folders_subscribed()
- */
- public function list_folders_subscribed_direct($root='', $name='*')
- {
- if (!$this->check_connection()) {
- return null;
- }
-
- $config = rcube::get_instance()->config;
-
- // Server supports LIST-EXTENDED, we can use selection options
- // #1486225: Some dovecot versions returns wrong result using LIST-EXTENDED
- $list_extended = !$config->get('imap_force_lsub') && $this->get_capability('LIST-EXTENDED');
- if ($list_extended) {
- // This will also set folder options, LSUB doesn't do that
- $a_folders = $this->conn->listMailboxes($root, $name,
- NULL, array('SUBSCRIBED'));
- }
- else {
- // retrieve list of folders from IMAP server using LSUB
- $a_folders = $this->conn->listSubscribed($root, $name);
- }
-
- if (!is_array($a_folders)) {
- return array();
- }
-
- // #1486796: some server configurations doesn't return folders in all namespaces
- if ($root == '' && $name == '*' && $config->get('imap_force_ns')) {
- $this->list_folders_update($a_folders, ($list_extended ? 'ext-' : '') . 'subscribed');
- }
-
- if ($list_extended) {
- // unsubscribe non-existent folders, remove from the list
- if (is_array($a_folders) && $name == '*' && !empty($this->conn->data['LIST'])) {
- foreach ($a_folders as $idx => $folder) {
- if (($opts = $this->conn->data['LIST'][$folder])
- && in_array('\\NonExistent', $opts)
- ) {
- $this->conn->unsubscribe($folder);
- unset($a_folders[$idx]);
- }
- }
- }
- }
- else {
- // unsubscribe non-existent folders, remove them from the list
- if (is_array($a_folders) && !empty($a_folders) && $name == '*') {
- $existing = $this->list_folders($root, $name);
- $nonexisting = array_diff($a_folders, $existing);
- $a_folders = array_diff($a_folders, $nonexisting);
-
- foreach ($nonexisting as $folder) {
- $this->conn->unsubscribe($folder);
- }
- }
- }
-
- return $a_folders;
- }
-
-
- /**
- * Get a list of all folders available on the server
- *
- * @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
- */
- public function list_folders($root='', $name='*', $filter=null, $rights=null, $skip_sort=false)
- {
- $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 folders
- $data = $this->plugins->exec_hook('storage_folders',
- array('root' => $root, 'name' => $name, 'filter' => $filter, 'mode' => 'LIST'));
-
- if (isset($data['folders'])) {
- $a_mboxes = $data['folders'];
- }
- else {
- // retrieve list of folders from IMAP server
- $a_mboxes = $this->list_folders_direct($root, $name);
- }
-
- if (!is_array($a_mboxes)) {
- $a_mboxes = array();
- }
-
- // INBOX should always be available
- if ((!$filter || $filter == 'mail') && !in_array('INBOX', $a_mboxes)) {
- array_unshift($a_mboxes, 'INBOX');
- }
-
- // cache folder attributes
- if ($root == '' && $name == '*' && empty($filter) && !empty($this->conn->data)) {
- $this->update_cache('mailboxes.attributes', $this->conn->data['LIST']);
- }
-
- // filter folders list according to rights requirements
- if ($rights && $this->get_capability('ACL')) {
- $a_mboxes = $this->filter_rights($a_mboxes, $rights);
- }
-
- // filter folders and sort them
- if (!$skip_sort) {
- $a_mboxes = $this->sort_folder_list($a_mboxes);
- }
-
- // write folders list to cache
- $this->update_cache($cache_key, $a_mboxes);
-
- return $a_mboxes;
- }
-
-
- /**
- * Method for direct folders listing (LIST)
- *
- * @param string $root Optional root folder
- * @param string $name Optional name pattern
- *
- * @return array List of folders
- * @see rcube_imap::list_folders()
- */
- public function list_folders_direct($root='', $name='*')
- {
- if (!$this->check_connection()) {
- return null;
- }
-
- $result = $this->conn->listMailboxes($root, $name);
-
- if (!is_array($result)) {
- return array();
- }
-
- $config = rcube::get_instance()->config;
-
- // #1486796: some server configurations doesn't return folders in all namespaces
- if ($root == '' && $name == '*' && $config->get('imap_force_ns')) {
- $this->list_folders_update($result);
- }
-
- return $result;
- }
-
-
- /**
- * Fix folders list by adding folders from other namespaces.
- * Needed on some servers eg. Courier IMAP
- *
- * @param array $result Reference to folders list
- * @param string $type Listing type (ext-subscribed, subscribed or all)
- */
- protected function list_folders_update(&$result, $type = null)
- {
- $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) {
- if ($type == 'ext-subscribed') {
- $list = $this->conn->listMailboxes('', $prefix . '*', null, array('SUBSCRIBED'));
- }
- else if ($type == 'subscribed') {
- $list = $this->conn->listSubscribed('', $prefix . '*');
- }
- else {
- $list = $this->conn->listMailboxes('', $prefix . '*');
- }
-
- if (!empty($list)) {
- $result = array_merge($result, $list);
- }
- }
- }
- }
-
-
- /**
- * Filter the given list of folders according to access rights
- *
- * For performance reasons we assume user has full rights
- * on all personal folders.
- */
- protected function filter_rights($a_folders, $rights)
- {
- $regex = '/('.$rights.')/';
-
- foreach ($a_folders as $idx => $folder) {
- if ($this->folder_namespace($folder) == 'personal') {
- continue;
- }
-
- $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
- *
- * @param string $folder Folder name
- *
- * @return mixed Quota info or False if not supported
- */
- public function get_quota($folder = null)
- {
- if ($this->get_capability('QUOTA') && $this->check_connection()) {
- return $this->conn->getQuota($folder);
- }
-
- return false;
- }
-
-
- /**
- * Get folder size (size of all messages in a folder)
- *
- * @param string $folder Folder name
- *
- * @return int Folder size in bytes, False on error
- */
- public function folder_size($folder)
- {
- if (!$this->check_connection()) {
- return 0;
- }
-
- // @TODO: could we try to use QUOTA here?
- $result = $this->conn->fetchHeaderIndex($folder, '1:*', 'SIZE', false);
-
- if (is_array($result)) {
- $result = array_sum($result);
- }
-
- return $result;
- }
-
-
- /**
- * Subscribe to a specific folder(s)
- *
- * @param array $folders Folder name(s)
- *
- * @return boolean True on success
- */
- public function subscribe($folders)
- {
- // let this common function do the main work
- return $this->change_subscription($folders, 'subscribe');
- }
-
-
- /**
- * Unsubscribe folder(s)
- *
- * @param array $a_mboxes Folder name(s)
- *
- * @return boolean True on success
- */
- public function unsubscribe($folders)
- {
- // let this common function do the main work
- return $this->change_subscription($folders, 'unsubscribe');
- }
-
-
- /**
- * Create a new folder on the server and register it in local cache
- *
- * @param string $folder New folder name
- * @param boolean $subscribe True if the new folder should be subscribed
- * @param string $type Optional folder type (junk, trash, drafts, sent, archive)
- *
- * @return boolean True on success
- */
- public function create_folder($folder, $subscribe = false, $type = null)
- {
- if (!$this->check_connection()) {
- return false;
- }
-
- $result = $this->conn->createFolder($folder, $type ? array("\\" . ucfirst($type)) : null);
-
- // it's quite often situation that we're trying to create and subscribe
- // a folder that already exist, but is unsubscribed
- if (!$result) {
- if ($this->get_response_code() == rcube_storage::ALREADYEXISTS
- || preg_match('/already exists/i', $this->get_error_str())
- ) {
- $result = true;
- }
- }
-
- // try to subscribe it
- if ($result) {
- // clear cache
- $this->clear_cache('mailboxes', true);
-
- if ($subscribe) {
- $this->subscribe($folder);
- }
- }
-
- return $result;
- }
-
-
- /**
- * Set a new name to an existing folder
- *
- * @param string $folder Folder to rename
- * @param string $new_name New folder name
- *
- * @return boolean True on success
- */
- public function rename_folder($folder, $new_name)
- {
- if (!strlen($new_name)) {
- return false;
- }
-
- if (!$this->check_connection()) {
- return false;
- }
-
- $delm = $this->get_hierarchy_delimiter();
-
- // get list of subscribed folders
- if ((strpos($folder, '%') === false) && (strpos($folder, '*') === false)) {
- $a_subscribed = $this->list_folders_subscribed('', $folder . $delm . '*');
- $subscribed = $this->folder_exists($folder, true);
- }
- else {
- $a_subscribed = $this->list_folders_subscribed();
- $subscribed = in_array($folder, $a_subscribed);
- }
-
- $result = $this->conn->renameFolder($folder, $new_name);
-
- if ($result) {
- // unsubscribe the old folder, subscribe the new one
- if ($subscribed) {
- $this->conn->unsubscribe($folder);
- $this->conn->subscribe($new_name);
- }
-
- // check if folder children are subscribed
- foreach ($a_subscribed as $c_subscribed) {
- if (strpos($c_subscribed, $folder.$delm) === 0) {
- $this->conn->unsubscribe($c_subscribed);
- $this->conn->subscribe(preg_replace('/^'.preg_quote($folder, '/').'/',
- $new_name, $c_subscribed));
-
- // clear cache
- $this->clear_message_cache($c_subscribed);
- }
- }
-
- // clear cache
- $this->clear_message_cache($folder);
- $this->clear_cache('mailboxes', true);
- }
-
- return $result;
- }
-
-
- /**
- * Remove folder from server
- *
- * @param string $folder Folder name
- *
- * @return boolean True on success
- */
- function delete_folder($folder)
- {
- $delm = $this->get_hierarchy_delimiter();
-
- if (!$this->check_connection()) {
- return false;
- }
-
- // get list of folders
- if ((strpos($folder, '%') === false) && (strpos($folder, '*') === false)) {
- $sub_mboxes = $this->list_folders('', $folder . $delm . '*');
- }
- else {
- $sub_mboxes = $this->list_folders();
- }
-
- // send delete command to server
- $result = $this->conn->deleteFolder($folder);
-
- if ($result) {
- // unsubscribe folder
- $this->conn->unsubscribe($folder);
-
- foreach ($sub_mboxes as $c_mbox) {
- if (strpos($c_mbox, $folder.$delm) === 0) {
- $this->conn->unsubscribe($c_mbox);
- if ($this->conn->deleteFolder($c_mbox)) {
- $this->clear_message_cache($c_mbox);
- }
- }
- }
-
- // clear folder-related cache
- $this->clear_message_cache($folder);
- $this->clear_cache('mailboxes', true);
- }
-
- return $result;
- }
-
-
- /**
- * Detect special folder associations stored in storage backend
- */
- public function get_special_folders($forced = false)
- {
- $result = parent::get_special_folders();
-
- if (isset($this->icache['special-use'])) {
- return array_merge($result, $this->icache['special-use']);
- }
-
- if (!$forced || !$this->get_capability('SPECIAL-USE')) {
- return $result;
- }
-
- if (!$this->check_connection()) {
- return $result;
- }
-
- $types = array_map(function($value) { return "\\" . ucfirst($value); }, rcube_storage::$folder_types);
- $special = array();
-
- // request \Subscribed flag in LIST response as performance improvement for folder_exists()
- $folders = $this->conn->listMailboxes('', '*', array('SUBSCRIBED'), array('SPECIAL-USE'));
-
- if (!empty($folders)) {
- foreach ($folders as $folder) {
- if ($flags = $this->conn->data['LIST'][$folder]) {
- foreach ($types as $type) {
- if (in_array($type, $flags)) {
- $type = strtolower(substr($type, 1));
- $special[$type] = $folder;
- }
- }
- }
- }
- }
-
- $this->icache['special-use'] = $special;
- unset($this->icache['special-folders']);
-
- return array_merge($result, $special);
- }
-
-
- /**
- * Set special folder associations stored in storage backend
- */
- public function set_special_folders($specials)
- {
- if (!$this->get_capability('SPECIAL-USE') || !$this->get_capability('METADATA')) {
- return false;
- }
-
- if (!$this->check_connection()) {
- return false;
- }
-
- $folders = $this->get_special_folders(true);
- $old = (array) $this->icache['special-use'];
-
- foreach ($specials as $type => $folder) {
- if (in_array($type, rcube_storage::$folder_types)) {
- $old_folder = $old[$type];
- if ($old_folder !== $folder) {
- // unset old-folder metadata
- if ($old_folder !== null) {
- $this->delete_metadata($old_folder, array('/private/specialuse'));
- }
- // set new folder metadata
- if ($folder) {
- $this->set_metadata($folder, array('/private/specialuse' => "\\" . ucfirst($type)));
- }
- }
- }
- }
-
- $this->icache['special-use'] = $specials;
- unset($this->icache['special-folders']);
-
- return true;
- }
-
-
- /**
- * Checks if folder exists and is subscribed
- *
- * @param string $folder Folder name
- * @param boolean $subscription Enable subscription checking
- *
- * @return boolean TRUE or FALSE
- */
- public function folder_exists($folder, $subscription = false)
- {
- if ($folder == 'INBOX') {
- return true;
- }
-
- $key = $subscription ? 'subscribed' : 'existing';
-
- if (is_array($this->icache[$key]) && in_array($folder, $this->icache[$key])) {
- return true;
- }
-
- if (!$this->check_connection()) {
- return false;
- }
-
- if ($subscription) {
- // It's possible we already called LIST command, check LIST data
- if (!empty($this->conn->data['LIST']) && !empty($this->conn->data['LIST'][$folder])
- && in_array('\\Subscribed', $this->conn->data['LIST'][$folder])
- ) {
- $a_folders = array($folder);
- }
- else {
- $a_folders = $this->conn->listSubscribed('', $folder);
- }
- }
- else {
- // It's possible we already called LIST command, check LIST data
- if (!empty($this->conn->data['LIST']) && isset($this->conn->data['LIST'][$folder])) {
- $a_folders = array($folder);
- }
- else {
- $a_folders = $this->conn->listMailboxes('', $folder);
- }
- }
-
- if (is_array($a_folders) && in_array($folder, $a_folders)) {
- $this->icache[$key][] = $folder;
- return true;
- }
-
- return false;
- }
-
-
- /**
- * Returns the namespace where the folder is in
- *
- * @param string $folder Folder name
- *
- * @return string One of 'personal', 'other' or 'shared'
- */
- public function folder_namespace($folder)
- {
- if ($folder == 'INBOX') {
- return 'personal';
- }
-
- foreach ($this->namespace as $type => $namespace) {
- if (is_array($namespace)) {
- foreach ($namespace as $ns) {
- if ($len = strlen($ns[0])) {
- if (($len > 1 && $folder == substr($ns[0], 0, -1))
- || strpos($folder, $ns[0]) === 0
- ) {
- return $type;
- }
- }
- }
- }
- }
-
- return 'personal';
- }
-
-
- /**
- * Modify folder name according to namespace.
- * For output it removes prefix of the personal namespace if it's possible.
- * For input it adds the prefix. Use it before creating a folder in root
- * of the folders tree.
- *
- * @param string $folder Folder name
- * @param string $mode Mode name (out/in)
- *
- * @return string Folder name
- */
- public function mod_folder($folder, $mode = 'out')
- {
- if (!strlen($folder)) {
- return $folder;
- }
-
- $prefix = $this->namespace['prefix']; // see set_env()
- $prefix_len = strlen($prefix);
-
- if (!$prefix_len) {
- return $folder;
- }
-
- // remove prefix for output
- if ($mode == 'out') {
- if (substr($folder, 0, $prefix_len) === $prefix) {
- return substr($folder, $prefix_len);
- }
- }
- // add prefix for input (e.g. folder creation)
- else {
- return $prefix . $folder;
- }
-
- return $folder;
- }
-
-
- /**
- * Gets folder attributes from LIST response, e.g. \Noselect, \Noinferiors
- *
- * @param string $folder Folder name
- * @param bool $force Set to True if attributes should be refreshed
- *
- * @return array Options list
- */
- public function folder_attributes($folder, $force=false)
- {
- // get attributes directly from LIST command
- if (!empty($this->conn->data['LIST']) && is_array($this->conn->data['LIST'][$folder])) {
- $opts = $this->conn->data['LIST'][$folder];
- }
- // get cached folder attributes
- else if (!$force) {
- $opts = $this->get_cache('mailboxes.attributes');
- $opts = $opts[$folder];
- }
-
- if (!is_array($opts)) {
- if (!$this->check_connection()) {
- return array();
- }
-
- $this->conn->listMailboxes('', $folder);
- $opts = $this->conn->data['LIST'][$folder];
- }
-
- return is_array($opts) ? $opts : array();
- }
-
-
- /**
- * Gets connection (and current folder) data: UIDVALIDITY, EXISTS, RECENT,
- * PERMANENTFLAGS, UIDNEXT, UNSEEN
- *
- * @param string $folder Folder name
- *
- * @return array Data
- */
- public function folder_data($folder)
- {
- if (!strlen($folder)) {
- $folder = $this->folder !== null ? $this->folder : 'INBOX';
- }
-
- if ($this->conn->selected != $folder) {
- if (!$this->check_connection()) {
- return array();
- }
-
- if ($this->conn->select($folder)) {
- $this->folder = $folder;
- }
- 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']->get_parameters('MAILBOX') == $folder
- ) {
- $data['UNDELETED'] = $this->icache['undeleted_idx'];
- }
-
- return $data;
- }
-
-
- /**
- * Returns extended information about the folder
- *
- * @param string $folder Folder name
- *
- * @return array Data
- */
- public function folder_info($folder)
- {
- if ($this->icache['options'] && $this->icache['options']['name'] == $folder) {
- return $this->icache['options'];
- }
-
- // get cached metadata
- $cache_key = 'mailboxes.folder-info.' . $folder;
- $cached = $this->get_cache($cache_key);
-
- if (is_array($cached)) {
- return $cached;
- }
-
- $acl = $this->get_capability('ACL');
- $namespace = $this->get_namespace();
- $options = array();
-
- // check if the folder is a namespace prefix
- if (!empty($namespace)) {
- $mbox = $folder . $this->delimiter;
- foreach ($namespace as $ns) {
- if (!empty($ns)) {
- foreach ($ns as $item) {
- if ($item[0] === $mbox) {
- $options['is_root'] = true;
- break 2;
- }
- }
- }
- }
- }
- // check if the folder is other user virtual-root
- if (!$options['is_root'] && !empty($namespace) && !empty($namespace['other'])) {
- $parts = explode($this->delimiter, $folder);
- if (count($parts) == 2) {
- $mbox = $parts[0] . $this->delimiter;
- foreach ($namespace['other'] as $item) {
- if ($item[0] === $mbox) {
- $options['is_root'] = true;
- break;
- }
- }
- }
- }
-
- $options['name'] = $folder;
- $options['attributes'] = $this->folder_attributes($folder, true);
- $options['namespace'] = $this->folder_namespace($folder);
- $options['special'] = $this->is_special_folder($folder);
-
- // Set 'noselect' flag
- if (is_array($options['attributes'])) {
- foreach ($options['attributes'] as $attrib) {
- $attrib = strtolower($attrib);
- if ($attrib == '\noselect' || $attrib == '\nonexistent') {
- $options['noselect'] = true;
- }
- }
- }
- else {
- $options['noselect'] = true;
- }
-
- // Get folder rights (MYRIGHTS)
- if ($acl && ($rights = $this->my_rights($folder))) {
- $options['rights'] = $rights;
- }
-
- // Set 'norename' flag
- if (!empty($options['rights'])) {
- $options['norename'] = !in_array('x', $options['rights']) && !in_array('d', $options['rights']);
-
- if (!$options['noselect']) {
- $options['noselect'] = !in_array('r', $options['rights']);
- }
- }
- else {
- $options['norename'] = $options['is_root'] || $options['namespace'] != 'personal';
- }
-
- // update caches
- $this->icache['options'] = $options;
- $this->update_cache($cache_key, $options);
-
- return $options;
- }
-
-
- /**
- * Synchronizes messages cache.
- *
- * @param string $folder Folder name
- */
- public function folder_sync($folder)
- {
- if ($mcache = $this->get_mcache_engine()) {
- $mcache->synchronize($folder);
- }
- }
-
-
- /**
- * Get message header names for rcube_imap_generic::fetchHeader(s)
- *
- * @return string Space-separated list of header names
- */
- protected function get_fetch_headers()
- {
- if (!empty($this->options['fetch_headers'])) {
- $headers = explode(' ', $this->options['fetch_headers']);
- }
- else {
- $headers = array();
- }
-
- if ($this->messages_caching || $this->options['all_headers']) {
- $headers = array_merge($headers, $this->all_headers);
- }
-
- return $headers;
- }
-
-
- /* -----------------------------------------
- * ACL and METADATA/ANNOTATEMORE methods
- * ----------------------------------------*/
-
- /**
- * Changes the ACL on the specified folder (SETACL)
- *
- * @param string $folder Folder name
- * @param string $user User name
- * @param string $acl ACL string
- *
- * @return boolean True on success, False on failure
- * @since 0.5-beta
- */
- public function set_acl($folder, $user, $acl)
- {
- if (!$this->get_capability('ACL')) {
- return false;
- }
-
- if (!$this->check_connection()) {
- return false;
- }
-
- $this->clear_cache('mailboxes.folder-info.' . $folder);
-
- return $this->conn->setACL($folder, $user, $acl);
- }
-
-
- /**
- * Removes any <identifier,rights> pair for the
- * specified user from the ACL for the specified
- * folder (DELETEACL)
- *
- * @param string $folder Folder name
- * @param string $user User name
- *
- * @return boolean True on success, False on failure
- * @since 0.5-beta
- */
- public function delete_acl($folder, $user)
- {
- if (!$this->get_capability('ACL')) {
- return false;
- }
-
- if (!$this->check_connection()) {
- return false;
- }
-
- return $this->conn->deleteACL($folder, $user);
- }
-
-
- /**
- * Returns the access control list for folder (GETACL)
- *
- * @param string $folder Folder name
- *
- * @return array User-rights array on success, NULL on error
- * @since 0.5-beta
- */
- public function get_acl($folder)
- {
- if (!$this->get_capability('ACL')) {
- return null;
- }
-
- if (!$this->check_connection()) {
- return null;
- }
-
- return $this->conn->getACL($folder);
- }
-
-
- /**
- * Returns information about what rights can be granted to the
- * user (identifier) in the ACL for the folder (LISTRIGHTS)
- *
- * @param string $folder Folder name
- * @param string $user User name
- *
- * @return array List of user rights
- * @since 0.5-beta
- */
- public function list_rights($folder, $user)
- {
- if (!$this->get_capability('ACL')) {
- return null;
- }
-
- if (!$this->check_connection()) {
- return null;
- }
-
- return $this->conn->listRights($folder, $user);
- }
-
-
- /**
- * Returns the set of rights that the current user has to
- * folder (MYRIGHTS)
- *
- * @param string $folder Folder name
- *
- * @return array MYRIGHTS response on success, NULL on error
- * @since 0.5-beta
- */
- public function my_rights($folder)
- {
- if (!$this->get_capability('ACL')) {
- return null;
- }
-
- if (!$this->check_connection()) {
- return null;
- }
-
- return $this->conn->myRights($folder);
- }
-
-
- /**
- * Sets IMAP metadata/annotations (SETMETADATA/SETANNOTATION)
- *
- * @param string $folder Folder name (empty for server metadata)
- * @param array $entries Entry-value array (use NULL value as NIL)
- *
- * @return boolean True on success, False on failure
- * @since 0.5-beta
- */
- public function set_metadata($folder, $entries)
- {
- if (!$this->check_connection()) {
- return false;
- }
-
- $this->clear_cache('mailboxes.metadata.', true);
-
- if ($this->get_capability('METADATA') ||
- (!strlen($folder) && $this->get_capability('METADATA-SERVER'))
- ) {
- return $this->conn->setMetadata($folder, $entries);
- }
- else if ($this->get_capability('ANNOTATEMORE') || $this->get_capability('ANNOTATEMORE2')) {
- foreach ((array)$entries as $entry => $value) {
- list($ent, $attr) = $this->md2annotate($entry);
- $entries[$entry] = array($ent, $attr, $value);
- }
- return $this->conn->setAnnotation($folder, $entries);
- }
-
- return false;
- }
-
-
- /**
- * Unsets IMAP metadata/annotations (SETMETADATA/SETANNOTATION)
- *
- * @param string $folder Folder name (empty for server metadata)
- * @param array $entries Entry names array
- *
- * @return boolean True on success, False on failure
- * @since 0.5-beta
- */
- public function delete_metadata($folder, $entries)
- {
- if (!$this->check_connection()) {
- return false;
- }
-
- $this->clear_cache('mailboxes.metadata.', true);
-
- if ($this->get_capability('METADATA') ||
- (!strlen($folder) && $this->get_capability('METADATA-SERVER'))
- ) {
- return $this->conn->deleteMetadata($folder, $entries);
- }
- else if ($this->get_capability('ANNOTATEMORE') || $this->get_capability('ANNOTATEMORE2')) {
- foreach ((array)$entries as $idx => $entry) {
- list($ent, $attr) = $this->md2annotate($entry);
- $entries[$idx] = array($ent, $attr, NULL);
- }
- return $this->conn->setAnnotation($folder, $entries);
- }
-
- return false;
- }
-
-
- /**
- * Returns IMAP metadata/annotations (GETMETADATA/GETANNOTATION)
- *
- * @param string $folder Folder name (empty for server metadata)
- * @param array $entries Entries
- * @param array $options Command options (with MAXSIZE and DEPTH keys)
- *
- * @return array Metadata entry-value hash array on success, NULL on error
- * @since 0.5-beta
- */
- public function get_metadata($folder, $entries, $options=array())
- {
- $entries = (array)$entries;
-
- // create cache key
- // @TODO: this is the simplest solution, but we do the same with folders list
- // maybe we should store data per-entry and merge on request
- sort($options);
- sort($entries);
- $cache_key = 'mailboxes.metadata.' . $folder;
- $cache_key .= '.' . md5(serialize($options).serialize($entries));
-
- // get cached data
- $cached_data = $this->get_cache($cache_key);
-
- if (is_array($cached_data)) {
- return $cached_data;
- }
-
- if (!$this->check_connection()) {
- return null;
- }
-
- if ($this->get_capability('METADATA') ||
- (!strlen($folder) && $this->get_capability('METADATA-SERVER'))
- ) {
- $res = $this->conn->getMetadata($folder, $entries, $options);
- }
- else if ($this->get_capability('ANNOTATEMORE') || $this->get_capability('ANNOTATEMORE2')) {
- $queries = array();
- $res = array();
-
- // Convert entry names
- foreach ($entries as $entry) {
- list($ent, $attr) = $this->md2annotate($entry);
- $queries[$attr][] = $ent;
- }
-
- // @TODO: Honor MAXSIZE and DEPTH options
- foreach ($queries as $attrib => $entry) {
- if ($result = $this->conn->getAnnotation($folder, $entry, $attrib)) {
- foreach ($result as $fldr => $data) {
- $res[$fldr] = array_merge((array) $res[$fldr], $data);
- }
- }
- }
- }
-
- if (isset($res)) {
- $this->update_cache($cache_key, $res);
- return $res;
- }
-
- return null;
- }
-
-
- /**
- * Converts the METADATA extension entry name into the correct
- * entry-attrib names for older ANNOTATEMORE version.
- *
- * @param string $entry Entry name
- *
- * @return array Entry-attribute list, NULL if not supported (?)
- */
- protected function md2annotate($entry)
- {
- if (substr($entry, 0, 7) == '/shared') {
- return array(substr($entry, 7), 'value.shared');
- }
- else if (substr($entry, 0, 8) == '/private') {
- return array(substr($entry, 8), 'value.priv');
- }
-
- // @TODO: log error
- return null;
- }
-
-
- /* --------------------------------
- * internal caching methods
- * --------------------------------*/
-
- /**
- * Enable or disable indexes caching
- *
- * @param string $type Cache type (@see rcube::get_cache)
- */
- public function set_caching($type)
- {
- if ($type) {
- $this->caching = $type;
- }
- else {
- if ($this->cache) {
- $this->cache->close();
- }
- $this->cache = null;
- $this->caching = false;
- }
- }
-
- /**
- * Getter for IMAP cache object
- */
- protected function get_cache_engine()
- {
- if ($this->caching && !$this->cache) {
- $rcube = rcube::get_instance();
- $ttl = $rcube->config->get('imap_cache_ttl', '10d');
- $this->cache = $rcube->get_cache('IMAP', $this->caching, $ttl);
- }
-
- return $this->cache;
- }
-
- /**
- * Returns cached value
- *
- * @param string $key Cache key
- *
- * @return mixed
- */
- public function get_cache($key)
- {
- if ($cache = $this->get_cache_engine()) {
- return $cache->get($key);
- }
- }
-
- /**
- * Update cache
- *
- * @param string $key Cache key
- * @param mixed $data Data
- */
- public function update_cache($key, $data)
- {
- if ($cache = $this->get_cache_engine()) {
- $cache->set($key, $data);
- }
- }
-
- /**
- * Clears the cache.
- *
- * @param string $key Cache key name or pattern
- * @param boolean $prefix_mode Enable it to clear all keys starting
- * with prefix specified in $key
- */
- public function clear_cache($key = null, $prefix_mode = false)
- {
- if ($cache = $this->get_cache_engine()) {
- $cache->remove($key, $prefix_mode);
- }
- }
-
-
- /* --------------------------------
- * message caching methods
- * --------------------------------*/
-
- /**
- * Enable or disable messages caching
- *
- * @param boolean $set Flag
- * @param int $mode Cache mode
- */
- public function set_messages_caching($set, $mode = null)
- {
- if ($set) {
- $this->messages_caching = true;
-
- if ($mode && ($cache = $this->get_mcache_engine())) {
- $cache->set_mode($mode);
- }
- }
- else {
- if ($this->mcache) {
- $this->mcache->close();
- }
- $this->mcache = null;
- $this->messages_caching = false;
- }
- }
-
-
- /**
- * Getter for messages cache object
- */
- protected function get_mcache_engine()
- {
- if ($this->messages_caching && !$this->mcache) {
- $rcube = rcube::get_instance();
- if (($dbh = $rcube->get_dbh()) && ($userid = $rcube->get_user_id())) {
- $ttl = $rcube->config->get('messages_cache_ttl', '10d');
- $threshold = $rcube->config->get('messages_cache_threshold', 50);
- $this->mcache = new rcube_imap_cache(
- $dbh, $this, $userid, $this->options['skip_deleted'], $ttl, $threshold);
- }
- }
-
- return $this->mcache;
- }
-
-
- /**
- * Clears the messages cache.
- *
- * @param string $folder Folder name
- * @param array $uids Optional message UIDs to remove from cache
- */
- protected function clear_message_cache($folder = null, $uids = null)
- {
- if ($mcache = $this->get_mcache_engine()) {
- $mcache->clear($folder, $uids);
- }
- }
-
-
- /**
- * Delete outdated cache entries
- */
- function cache_gc()
- {
- rcube_imap_cache::gc();
- }
-
-
- /* --------------------------------
- * protected methods
- * --------------------------------*/
-
- /**
- * Validate the given input and save to local properties
- *
- * @param string $sort_field Sort column
- * @param string $sort_order Sort order
- */
- protected function set_sort_order($sort_field, $sort_order)
- {
- if ($sort_field != null) {
- $this->sort_field = asciiwords($sort_field);
- }
- if ($sort_order != null) {
- $this->sort_order = strtoupper($sort_order) == 'DESC' ? 'DESC' : 'ASC';
- }
- }
-
-
- /**
- * Sort folders first by default folders and then in alphabethical order
- *
- * @param array $a_folders Folders list
- * @param bool $skip_default Skip default folders handling
- *
- * @return array Sorted list
- */
- public function sort_folder_list($a_folders, $skip_default = false)
- {
- $specials = array_merge(array('INBOX'), array_values($this->get_special_folders()));
- $folders = array();
-
- // convert names to UTF-8 and skip folders starting with '.'
- foreach ($a_folders as $folder) {
- if ($folder[0] != '.') {
- // for better performance skip encoding conversion
- // if the string does not look like UTF7-IMAP
- $folders[$folder] = strpos($folder, '&') === false ? $folder : rcube_charset::convert($folder, 'UTF7-IMAP');
- }
- }
-
- // sort folders
- // asort($folders, SORT_LOCALE_STRING) is not properly sorting case sensitive names
- uasort($folders, array($this, 'sort_folder_comparator'));
-
- $folders = array_keys($folders);
-
- if ($skip_default) {
- return $folders;
- }
-
- // force the type of folder name variable (#1485527)
- $folders = array_map('strval', $folders);
- $out = array();
-
- // finally we must put special folders on top and rebuild the list
- // to move their subfolders where they belong...
- $specials = array_unique(array_intersect($specials, $folders));
- $folders = array_merge($specials, array_diff($folders, $specials));
-
- $this->sort_folder_specials(null, $folders, $specials, $out);
-
- return $out;
- }
-
- /**
- * Recursive function to put subfolders of special folders in place
- */
- protected function sort_folder_specials($folder, &$list, &$specials, &$out)
- {
- while (list($key, $name) = each($list)) {
- if ($folder === null || strpos($name, $folder.$this->delimiter) === 0) {
- $out[] = $name;
- unset($list[$key]);
-
- if (!empty($specials) && ($found = array_search($name, $specials)) !== false) {
- unset($specials[$found]);
- $this->sort_folder_specials($name, $list, $specials, $out);
- }
- }
- }
-
- reset($list);
- }
-
- /**
- * Callback for uasort() that implements correct
- * locale-aware case-sensitive sorting
- */
- protected function sort_folder_comparator($str1, $str2)
- {
- $path1 = explode($this->delimiter, $str1);
- $path2 = explode($this->delimiter, $str2);
-
- foreach ($path1 as $idx => $folder1) {
- $folder2 = $path2[$idx];
-
- if ($folder1 === $folder2) {
- continue;
- }
-
- return strcoll($folder1, $folder2);
- }
- }
-
-
- /**
- * Find UID of the specified message sequence ID
- *
- * @param int $id Message (sequence) ID
- * @param string $folder Folder name
- *
- * @return int Message UID
- */
- public function id2uid($id, $folder = null)
- {
- if (!strlen($folder)) {
- $folder = $this->folder;
- }
-
- if ($uid = array_search($id, (array)$this->uid_id_map[$folder])) {
- return $uid;
- }
-
- if (!$this->check_connection()) {
- return null;
- }
-
- $uid = $this->conn->ID2UID($folder, $id);
-
- $this->uid_id_map[$folder][$uid] = $id;
-
- return $uid;
- }
-
-
- /**
- * Subscribe/unsubscribe a list of folders and update local cache
- */
- protected function change_subscription($folders, $mode)
- {
- $updated = false;
-
- if (!empty($folders)) {
- if (!$this->check_connection()) {
- return false;
- }
-
- foreach ((array)$folders as $i => $folder) {
- $folders[$i] = $folder;
-
- if ($mode == 'subscribe') {
- $updated = $this->conn->subscribe($folder);
- }
- else if ($mode == 'unsubscribe') {
- $updated = $this->conn->unsubscribe($folder);
- }
- }
- }
-
- // clear cached folders list(s)
- if ($updated) {
- $this->clear_cache('mailboxes', true);
- }
-
- return $updated;
- }
-
-
- /**
- * Increde/decrese messagecount for a specific folder
- */
- protected function set_messagecount($folder, $mode, $increment)
- {
- if (!is_numeric($increment)) {
- return false;
- }
-
- $mode = strtoupper($mode);
- $a_folder_cache = $this->get_cache('messagecount');
-
- if (!is_array($a_folder_cache[$folder]) || !isset($a_folder_cache[$folder][$mode])) {
- return false;
- }
-
- // add incremental value to messagecount
- $a_folder_cache[$folder][$mode] += $increment;
-
- // there's something wrong, delete from cache
- if ($a_folder_cache[$folder][$mode] < 0) {
- unset($a_folder_cache[$folder][$mode]);
- }
-
- // write back to cache
- $this->update_cache('messagecount', $a_folder_cache);
-
- return true;
- }
-
-
- /**
- * Remove messagecount of a specific folder from cache
- */
- protected function clear_messagecount($folder, $mode=null)
- {
- $a_folder_cache = $this->get_cache('messagecount');
-
- if (is_array($a_folder_cache[$folder])) {
- if ($mode) {
- unset($a_folder_cache[$folder][$mode]);
- }
- else {
- unset($a_folder_cache[$folder]);
- }
- $this->update_cache('messagecount', $a_folder_cache);
- }
- }
-
-
- /**
- * Converts date string/object into IMAP date/time format
- */
- protected function date_format($date)
- {
- if (empty($date)) {
- return null;
- }
-
- if (!is_object($date) || !is_a($date, 'DateTime')) {
- try {
- $timestamp = rcube_utils::strtotime($date);
- $date = new DateTime("@".$timestamp);
- }
- catch (Exception $e) {
- return null;
- }
- }
-
- return $date->format('d-M-Y H:i:s O');
- }
-
-
- /**
- * This is our own debug handler for the IMAP connection
- * @access public
- */
- public function debug_handler(&$imap, $message)
- {
- rcube::write_log('imap', $message);
- }
-
-
- /**
- * Deprecated methods (to be removed)
- */
-
- public function decode_address_list($input, $max = null, $decode = true, $fallback = null)
- {
- return rcube_mime::decode_address_list($input, $max, $decode, $fallback);
- }
-
- public function decode_header($input, $fallback = null)
- {
- return rcube_mime::decode_mime_string((string)$input, $fallback);
- }
-
- public static function decode_mime_string($input, $fallback = null)
- {
- return rcube_mime::decode_mime_string($input, $fallback);
- }
-
- public function mime_decode($input, $encoding = '7bit')
- {
- return rcube_mime::decode($input, $encoding);
- }
-
- public static function explode_header_string($separator, $str, $remove_comments = false)
- {
- return rcube_mime::explode_header_string($separator, $str, $remove_comments);
- }
-
- public function select_mailbox($mailbox)
- {
- // do nothing
- }
-
- public function set_mailbox($folder)
- {
- $this->set_folder($folder);
- }
-
- public function get_mailbox_name()
- {
- return $this->get_folder();
- }
-
- public function list_headers($folder='', $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0)
- {
- return $this->list_messages($folder, $page, $sort_field, $sort_order, $slice);
- }
-
- public function get_headers($uid, $folder = null, $force = false)
- {
- return $this->get_message_headers($uid, $folder, $force);
- }
-
- public function mailbox_status($folder = null)
- {
- return $this->folder_status($folder);
- }
-
- public function message_index($folder = '', $sort_field = NULL, $sort_order = NULL)
- {
- return $this->index($folder, $sort_field, $sort_order);
- }
-
- public function message_index_direct($folder, $sort_field = null, $sort_order = null)
- {
- return $this->index_direct($folder, $sort_field, $sort_order);
- }
-
- public function list_mailboxes($root='', $name='*', $filter=null, $rights=null, $skip_sort=false)
- {
- return $this->list_folders_subscribed($root, $name, $filter, $rights, $skip_sort);
- }
-
- public function list_unsubscribed($root='', $name='*', $filter=null, $rights=null, $skip_sort=false)
- {
- return $this->list_folders($root, $name, $filter, $rights, $skip_sort);
- }
-
- public function get_mailbox_size($folder)
- {
- return $this->folder_size($folder);
- }
-
- public function create_mailbox($folder, $subscribe=false)
- {
- return $this->create_folder($folder, $subscribe);
- }
-
- public function rename_mailbox($folder, $new_name)
- {
- return $this->rename_folder($folder, $new_name);
- }
-
- function delete_mailbox($folder)
- {
- return $this->delete_folder($folder);
- }
-
- function clear_mailbox($folder = null)
- {
- return $this->clear_folder($folder);
- }
-
- public function mailbox_exists($folder, $subscription=false)
- {
- return $this->folder_exists($folder, $subscription);
- }
-
- public function mailbox_namespace($folder)
- {
- return $this->folder_namespace($folder);
- }
-
- public function mod_mailbox($folder, $mode = 'out')
- {
- return $this->mod_folder($folder, $mode);
- }
-
- public function mailbox_attributes($folder, $force=false)
- {
- return $this->folder_attributes($folder, $force);
- }
-
- public function mailbox_data($folder)
- {
- return $this->folder_data($folder);
- }
-
- public function mailbox_info($folder)
- {
- return $this->folder_info($folder);
- }
-
- public function mailbox_sync($folder)
- {
- return $this->folder_sync($folder);
- }
-
- public function expunge($folder='', $clear_cache=true)
- {
- return $this->expunge_folder($folder, $clear_cache);
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_imap_cache.php b/lib/ext/Roundcube/rcube_imap_cache.php
deleted file mode 100644
index 81df076..0000000
--- a/lib/ext/Roundcube/rcube_imap_cache.php
+++ /dev/null
@@ -1,1321 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Caching of IMAP folder contents (messages and index) |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Interface class for accessing Roundcube messages cache
- *
- * @package Framework
- * @subpackage Storage
- * @author Thomas Bruederli <roundcube@gmail.com>
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_imap_cache
-{
- const MODE_INDEX = 1;
- const MODE_MESSAGE = 2;
-
- /**
- * Instance of rcube_imap
- *
- * @var rcube_imap
- */
- private $imap;
-
- /**
- * Instance of rcube_db
- *
- * @var rcube_db
- */
- private $db;
-
- /**
- * User ID
- *
- * @var int
- */
- private $userid;
-
- /**
- * Expiration time in seconds
- *
- * @var int
- */
- private $ttl;
-
- /**
- * Maximum cached message size
- *
- * @var int
- */
- private $threshold;
-
- /**
- * Internal (in-memory) cache
- *
- * @var array
- */
- private $icache = array();
-
- private $skip_deleted = false;
- private $mode;
-
- /**
- * 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.
- *
- * @param rcube_db $db DB handler
- * @param rcube_imap $imap IMAP handler
- * @param int $userid User identifier
- * @param bool $skip_deleted skip_deleted flag
- * @param string $ttl Expiration time of memcache/apc items
- * @param int $threshold Maximum cached message size
- */
- function __construct($db, $imap, $userid, $skip_deleted, $ttl=0, $threshold=0)
- {
- // convert ttl string to seconds
- $ttl = get_offset_sec($ttl);
- if ($ttl > 2592000) $ttl = 2592000;
-
- $this->db = $db;
- $this->imap = $imap;
- $this->userid = $userid;
- $this->skip_deleted = $skip_deleted;
- $this->ttl = $ttl;
- $this->threshold = $threshold;
-
- // cache all possible information by default
- $this->mode = self::MODE_INDEX | self::MODE_MESSAGE;
-
- // database tables
- $this->index_table = $db->table_name('cache_index', true);
- $this->thread_table = $db->table_name('cache_thread', true);
- $this->messages_table = $db->table_name('cache_messages', true);
- }
-
-
- /**
- * Cleanup actions (on shutdown).
- */
- public function close()
- {
- $this->save_icache();
- $this->icache = null;
- }
-
-
- /**
- * Set cache mode
- *
- * @param int $mode Cache mode
- */
- public function set_mode($mode)
- {
- $this->mode = $mode;
- }
-
-
- /**
- * Return (sorted) messages index (UIDs).
- * 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 (empty($this->icache[$mailbox]['index']['validated'])) {
- $index = $this->icache[$mailbox]['index'];
- }
- // We've got a valid index
- else if ($sort_field == 'ANY' || $this->icache[$mailbox]['index']['sort_field'] == $sort_field) {
- $result = $this->icache[$mailbox]['index']['object'];
- if ($result->get_parameters('ORDER') != $sort_order) {
- $result->revert();
- }
- return $result;
- }
- }
-
- // 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) {
- $data = $index['object'];
- // revert the order if needed
- if ($data->get_parameters('ORDER') != $sort_order) {
- $data->revert();
- }
- }
- }
- 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->folder_data($mailbox);
- $data = $this->get_index_data($mailbox, $sort_field, $sort_order, $mbox_data);
-
- // insert/update
- $this->add_index_row($mailbox, $sort_field, $data, $mbox_data, $exists, $index['modseq']);
- }
-
- $this->icache[$mailbox]['index'] = array(
- 'validated' => true,
- 'object' => $data,
- 'sort_field' => $sort_field,
- '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
- *
- * @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 $this->icache[$mailbox]['thread']['object'];
- }
-
- // 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;
- }
-
- // 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->folder_data($mailbox);
- // Get THREADS result
- $index['object'] = $this->get_thread_data($mailbox, $mbox_data);
-
- // insert/update
- $this->add_thread_row($mailbox, $index['object'], $mbox_data, $exists);
- }
-
- $this->icache[$mailbox]['thread'] = $index;
-
- return $index['object'];
- }
-
-
- /**
- * Returns list of messages (headers). See rcube_imap::fetch_headers().
- *
- * @param string $mailbox Folder name
- * @param array $msgs Message UIDs
- *
- * @return array The list of messages (rcube_message_header) indexed by UID
- */
- function get_messages($mailbox, $msgs = array())
- {
- if (empty($msgs)) {
- return array();
- }
-
- $result = array();
-
- if ($this->mode & self::MODE_MESSAGE) {
- // Fetch messages from cache
- $sql_result = $this->db->query(
- "SELECT `uid`, `data`, `flags`"
- ." FROM {$this->messages_table}"
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?"
- ." AND `uid` IN (".$this->db->array2list($msgs, 'integer').")",
- $this->userid, $mailbox);
-
- $msgs = array_flip($msgs);
-
- while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
- $uid = intval($sql_arr['uid']);
- $result[$uid] = $this->build_message($sql_arr);
-
- if (!empty($result[$uid])) {
- // save memory, we don't need message body here (?)
- $result[$uid]->body = null;
-
- unset($msgs[$uid]);
- }
- }
-
- $msgs = array_flip($msgs);
- }
-
- // Fetch not found messages from IMAP server
- if (!empty($msgs)) {
- $messages = $this->imap->fetch_headers($mailbox, $msgs, false, true);
-
- // Insert to DB and add to result list
- if (!empty($messages)) {
- foreach ($messages as $msg) {
- if ($this->mode & self::MODE_MESSAGE) {
- $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_message_header Message data
- */
- function get_message($mailbox, $uid, $update = true, $cache = true)
- {
- // Check internal cache
- if ($this->icache['__message']
- && $this->icache['__message']['mailbox'] == $mailbox
- && $this->icache['__message']['object']->uid == $uid
- ) {
- return $this->icache['__message']['object'];
- }
-
- if ($this->mode & self::MODE_MESSAGE) {
- $sql_result = $this->db->query(
- "SELECT `flags`, `data`"
- ." FROM {$this->messages_table}"
- ." 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;
- }
- }
-
- // Get the message from IMAP server
- if (empty($message) && $update) {
- $message = $this->imap->get_message_headers($uid, $mailbox, true);
- // cache will be updated in close(), see below
- }
-
- if (!($this->mode & self::MODE_MESSAGE)) {
- return $message;
- }
-
- // 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_message_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;
- }
-
- if (!($this->mode & self::MODE_MESSAGE)) {
- return;
- }
-
- $flags = 0;
- $msg = clone $message;
-
- if (!empty($message->flags)) {
- foreach ($this->flags as $idx => $flag) {
- if (!empty($message->flags[$flag])) {
- $flags += $idx;
- }
- }
- }
-
- unset($msg->flags);
- $msg = $this->db->encode($msg, true);
-
- // 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 {$this->messages_table}"
- ." SET `flags` = ?, `data` = ?, `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?"
- ." AND `uid` = ?",
- $flags, $msg, $this->userid, $mailbox, (int) $message->uid);
-
- if ($this->db->affected_rows($res)) {
- return;
- }
- }
-
- $this->db->set_option('ignore_key_errors', true);
-
- // insert new record
- $res = $this->db->query(
- "INSERT INTO {$this->messages_table}"
- ." (`user_id`, `mailbox`, `uid`, `flags`, `expires`, `data`)"
- ." VALUES (?, ?, ?, ?, ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?)",
- $this->userid, $mailbox, (int) $message->uid, $flags, $msg);
-
- // race-condition, insert failed so try update (#1489146)
- // thanks to ignore_key_errors "duplicate row" errors will be ignored
- if ($force && !$res && !$this->db->is_error($res)) {
- $this->db->query(
- "UPDATE {$this->messages_table}"
- ." SET `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
- .", `flags` = ?, `data` = ?"
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?"
- ." AND `uid` = ?",
- $flags, $msg, $this->userid, $mailbox, (int) $message->uid);
- }
-
- $this->db->set_option('ignore_key_errors', false);
- }
-
-
- /**
- * 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)
- {
- if (empty($uids)) {
- return;
- }
-
- if (!($this->mode & self::MODE_MESSAGE)) {
- return;
- }
-
- $flag = strtoupper($flag);
- $idx = (int) array_search($flag, $this->flags);
- $uids = (array) $uids;
-
- if (!$idx) {
- return;
- }
-
- // Internal cache update
- if (($message = $this->icache['__message'])
- && $message['mailbox'] === $mailbox
- && in_array($message['object']->uid, $uids)
- ) {
- $message['object']->flags[$flag] = $enabled;
-
- if (count($uids) == 1) {
- return;
- }
- }
-
- $binary_check = $this->db->db_provider == 'oracle' ? "BITAND(`flags`, %d)" : "(`flags` & %d)";
-
- $this->db->query(
- "UPDATE {$this->messages_table}"
- ." SET `expires` = ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
- .", `flags` = `flags` ".($enabled ? "+ $idx" : "- $idx")
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?"
- .(!empty($uids) ? " AND `uid` IN (".$this->db->array2list($uids, 'integer').")" : "")
- ." AND " . sprintf($binary_check, $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 (!($this->mode & self::MODE_MESSAGE)) {
- return;
- }
-
- if (!strlen($mailbox)) {
- $this->db->query(
- "DELETE FROM {$this->messages_table}"
- ." WHERE `user_id` = ?",
- $this->userid);
- }
- else {
- // Remove the message from internal cache
- if (!empty($uids) && ($message = $this->icache['__message'])
- && $message['mailbox'] === $mailbox
- && in_array($message['object']->uid, (array)$uids)
- ) {
- $this->icache['__message'] = null;
- }
-
- $this->db->query(
- "DELETE FROM {$this->messages_table}"
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?"
- .($uids !== null ? " AND `uid` IN (".$this->db->array2list((array)$uids, 'integer').")" : ""),
- $this->userid, $mailbox);
- }
- }
-
-
- /**
- * 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 {$this->index_table}"
- ." WHERE `user_id` = ?"
- .(strlen($mailbox) ? " AND `mailbox` = ".$this->db->quote($mailbox) : ""),
- $this->userid
- );
- }
- else {
- $this->db->query(
- "UPDATE {$this->index_table}"
- ." SET `valid` = 0"
- ." WHERE `user_id` = ?"
- .(strlen($mailbox) ? " AND `mailbox` = ".$this->db->quote($mailbox) : ""),
- $this->userid
- );
- }
-
- 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 {$this->thread_table}"
- ." WHERE `user_id` = ?"
- .(strlen($mailbox) ? " AND `mailbox` = ".$this->db->quote($mailbox) : ""),
- $this->userid
- );
-
- 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);
- }
-
-
- /**
- * Delete expired cache entries
- */
- static function gc()
- {
- $rcube = rcube::get_instance();
- $db = $rcube->get_dbh();
- $now = $db->now();
-
- $db->query("DELETE FROM " . $db->table_name('cache_messages', true)
- ." WHERE `expires` < $now");
-
- $db->query("DELETE FROM " . $db->table_name('cache_index', true)
- ." WHERE `expires` < $now");
-
- $db->query("DELETE FROM ".$db->table_name('cache_thread', true)
- ." WHERE `expires` < $now");
- }
-
-
- /**
- * Fetches index data from database
- */
- private function get_index_row($mailbox)
- {
- // Get index from DB
- $sql_result = $this->db->query(
- "SELECT `data`, `valid`"
- ." FROM {$this->index_table}"
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?",
- $this->userid, $mailbox);
-
- if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
- $data = explode('@', $sql_arr['data']);
- $index = $this->db->decode($data[0], true);
- unset($data[0]);
-
- if (empty($index)) {
- $index = new rcube_result_index($mailbox);
- }
-
- return array(
- 'valid' => $sql_arr['valid'],
- 'object' => $index,
- 'sort_field' => $data[1],
- 'deleted' => $data[2],
- 'validity' => $data[3],
- 'uidnext' => $data[4],
- 'modseq' => $data[5],
- );
- }
-
- 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 {$this->thread_table}"
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?",
- $this->userid, $mailbox);
-
- if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
- $data = explode('@', $sql_arr['data']);
- $thread = $this->db->decode($data[0], true);
- unset($data[0]);
-
- if (empty($thread)) {
- $thread = new rcube_result_thread($mailbox);
- }
-
- return array(
- 'object' => $thread,
- 'deleted' => $data[1],
- 'validity' => $data[2],
- 'uidnext' => $data[3],
- );
- }
-
- return null;
- }
-
-
- /**
- * Saves index data into database
- */
- private function add_index_row($mailbox, $sort_field,
- $data, $mbox_data = array(), $exists = false, $modseq = null)
- {
- $data = array(
- $this->db->encode($data, true),
- $sort_field,
- (int) $this->skip_deleted,
- (int) $mbox_data['UIDVALIDITY'],
- (int) $mbox_data['UIDNEXT'],
- $modseq ? $modseq : $mbox_data['HIGHESTMODSEQ'],
- );
-
- $data = implode('@', $data);
- $expires = $this->ttl ? $this->db->now($this->ttl) : 'NULL';
-
- if ($exists) {
- $res = $this->db->query(
- "UPDATE {$this->index_table}"
- ." SET `data` = ?, `valid` = 1, `expires` = $expires"
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?",
- $data, $this->userid, $mailbox);
-
- if ($this->db->affected_rows($res)) {
- return;
- }
- }
-
- $this->db->set_option('ignore_key_errors', true);
-
- $res = $this->db->query(
- "INSERT INTO {$this->index_table}"
- ." (`user_id`, `mailbox`, `valid`, `expires`, `data`)"
- ." VALUES (?, ?, 1, $expires, ?)",
- $this->userid, $mailbox, $data);
-
- // race-condition, insert failed so try update (#1489146)
- // thanks to ignore_key_errors "duplicate row" errors will be ignored
- if (!$exists && !$res && !$this->db->is_error($res)) {
- $res = $this->db->query(
- "UPDATE {$this->index_table}"
- ." SET `data` = ?, `valid` = 1, `expires` = $expires"
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?",
- $data, $this->userid, $mailbox);
- }
-
- $this->db->set_option('ignore_key_errors', false);
- }
-
-
- /**
- * Saves thread data into database
- */
- private function add_thread_row($mailbox, $data, $mbox_data = array(), $exists = false)
- {
- $data = array(
- $this->db->encode($data, true),
- (int) $this->skip_deleted,
- (int) $mbox_data['UIDVALIDITY'],
- (int) $mbox_data['UIDNEXT'],
- );
-
- $data = implode('@', $data);
- $expires = $this->ttl ? $this->db->now($this->ttl) : 'NULL';
-
- if ($exists) {
- $res = $this->db->query(
- "UPDATE {$this->thread_table}"
- ." SET `data` = ?, `expires` = $expires"
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?",
- $data, $this->userid, $mailbox);
-
- if ($this->db->affected_rows($res)) {
- return;
- }
- }
-
- $this->db->set_option('ignore_key_errors', true);
-
- $res = $this->db->query(
- "INSERT INTO {$this->thread_table}"
- ." (`user_id`, `mailbox`, `expires`, `data`)"
- ." VALUES (?, ?, $expires, ?)",
- $this->userid, $mailbox, $data);
-
- // race-condition, insert failed so try update (#1489146)
- // thanks to ignore_key_errors "duplicate row" errors will be ignored
- if (!$exists && !$res && !$this->db->is_error($res)) {
- $this->db->query(
- "UPDATE {$this->thread_table}"
- ." SET `expires` = $expires, `data` = ?"
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?",
- $data, $this->userid, $mailbox);
- }
-
- $this->db->set_option('ignore_key_errors', false);
- }
-
-
- /**
- * Checks index/thread validity
- */
- private function validate($mailbox, $index, &$exists = true)
- {
- $object = $index['object'];
- $is_thread = is_a($object, 'rcube_result_thread');
-
- // sanity check
- if (empty($object)) {
- return false;
- }
-
- $index['validated'] = true;
-
- // Get mailbox data (UIDVALIDITY, counters, etc.) for status check
- $mbox_data = $this->imap->folder_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 (!$object->is_empty()) {
- $this->clear($mailbox);
- $exists = false;
- return false;
- }
- }
- // Folder is not empty but cache is
- else if ($object->is_empty()) {
- unset($this->icache[$mailbox][$is_thread ? 'thread' : 'index']);
- return false;
- }
-
- // Validation flag
- if (!$is_thread && empty($index['valid'])) {
- unset($this->icache[$mailbox]['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'] != $object->count_messages()) {
- return false;
- }
- return true;
- }
-
- // The rest of checks, more expensive
- if (!empty($this->skip_deleted)) {
- // compare counts if available
- if (!empty($mbox_data['UNDELETED'])
- && $mbox_data['UNDELETED']->count() != $object->count()
- ) {
- return false;
- }
- // compare UID sets
- if (!empty($mbox_data['UNDELETED'])) {
- $uids_new = $mbox_data['UNDELETED']->get();
- $uids_old = $object->get();
-
- 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($object->get()));
-
- if (!$ids->is_empty()) {
- return false;
- }
- }
- }
- else {
- // check messages number...
- if ($mbox_data['EXISTS'] != $object->count()) {
- return false;
- }
- // ... and max UID
- if ($object->max() != $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;
- }
-
- if (!$this->imap->check_connection()) {
- return;
- }
-
- // Enable QRESYNC
- $res = $this->imap->conn->enable($qresync ? 'QRESYNC' : 'CONDSTORE');
- if ($res === false) {
- return;
- }
-
- // Close mailbox if already selected to get most recent data
- if ($this->imap->conn->selected == $mailbox) {
- $this->imap->conn->close();
- }
-
- // Get mailbox data (UIDVALIDITY, HIGHESTMODSEQ, counters, etc.)
- $mbox_data = $this->imap->folder_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;
- }
-
- $uids = array();
- $removed = array();
-
- // Get known UIDs
- if ($this->mode & self::MODE_MESSAGE) {
- $sql_result = $this->db->query(
- "SELECT `uid`"
- ." FROM {$this->messages_table}"
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?",
- $this->userid, $mailbox);
-
- while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
- $uids[] = $sql_arr['uid'];
- }
- }
-
- // Synchronize messages data
- if (!empty($uids)) {
- // Get modified flags and vanished messages
- // UID FETCH 1:* (FLAGS) (CHANGEDSINCE 0123456789 VANISHED)
- $result = $this->imap->conn->fetch($mailbox,
- $uids, true, array('FLAGS'), $index['modseq'], $qresync);
-
- if (!empty($result)) {
- foreach ($result as $msg) {
- $uid = $msg->uid;
- // Remove deleted message
- if ($this->skip_deleted && !empty($msg->flags['DELETED'])) {
- $removed[] = $uid;
- // 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 {$this->messages_table}"
- ." SET `flags` = ?, `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
- ." WHERE `user_id` = ?"
- ." AND `mailbox` = ?"
- ." AND `uid` = ?"
- ." AND `flags` <> ?",
- $flags, $this->userid, $mailbox, $uid, $flags);
- }
- }
-
- // VANISHED found?
- if ($qresync) {
- $mbox_data = $this->imap->folder_data($mailbox);
-
- // Removed messages found
- $uids = rcube_imap_generic::uncompressMessageSet($mbox_data['VANISHED']);
- if (!empty($uids)) {
- $removed = array_merge($removed, $uids);
- // Invalidate index
- $index['valid'] = false;
- }
- }
-
- // remove messages from database
- if (!empty($removed)) {
- $this->remove_message($mailbox, $removed);
- }
- }
-
- $sort_field = $index['sort_field'];
- $sort_order = $index['object']->get_parameters('ORDER');
- $exists = true;
-
- // Validate index
- if (!$this->validate($mailbox, $index, $exists)) {
- // Invalidate (remove) thread index
- // if $exists=false it was already removed in validate()
- if ($exists) {
- $this->remove_thread($mailbox);
- }
-
- // Update index
- $data = $this->get_index_data($mailbox, $sort_field, $sort_order, $mbox_data);
- }
- else {
- $data = $index['object'];
- }
-
- // update index and/or HIGHESTMODSEQ value
- $this->add_index_row($mailbox, $sort_field, $data, $mbox_data, $exists);
-
- // update internal cache for get_index()
- $this->icache[$mailbox]['index']['object'] = $data;
- }
-
-
- /**
- * Converts cache row into message object.
- *
- * @param array $sql_arr Message row data
- *
- * @return rcube_message_header Message object
- */
- private function build_message($sql_arr)
- {
- $message = $this->db->decode($sql_arr['data'], true);
-
- if ($message) {
- $message->flags = array();
- foreach ($this->flags as $idx => $flag) {
- if (($sql_arr['flags'] & $idx) == $idx) {
- $message->flags[$flag] = true;
- }
- }
- }
-
- return $message;
- }
-
-
- /**
- * 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
- $this->message_object_prepare($message['object']);
-
- // calculate current md5 sum
- $md5sum = md5(serialize($message['object']));
-
- if ($message['md5sum'] != $md5sum) {
- $this->add_message($message['mailbox'], $message['object'], !$message['exists']);
- }
-
- $this->icache['__message']['md5sum'] = $md5sum;
- }
- }
-
-
- /**
- * Prepares message object to be stored in database.
- *
- * @param rcube_message_header|rcube_message_part
- */
- private function message_object_prepare(&$msg, &$size = 0)
- {
- // Remove body too big
- if (isset($msg->body)) {
- $length = strlen($msg->body);
-
- if ($msg->body_modified || $size + $length > $this->threshold * 1024) {
- unset($msg->body);
- }
- else {
- $size += $length;
- }
- }
-
- // 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);
- }
-
- unset($msg->replaces);
-
- if (is_object($msg->structure)) {
- $this->message_object_prepare($msg->structure, $size);
- }
-
- if (is_array($msg->parts)) {
- foreach ($msg->parts as $part) {
- $this->message_object_prepare($part, $size);
- }
- }
- }
-
-
- /**
- * Fetches index data from IMAP server
- */
- private function get_index_data($mailbox, $sort_field, $sort_order, $mbox_data = array())
- {
- if (empty($mbox_data)) {
- $mbox_data = $this->imap->folder_data($mailbox);
- }
-
- if ($mbox_data['EXISTS']) {
- // fetch sorted sequence numbers
- $index = $this->imap->index_direct($mailbox, $sort_field, $sort_order);
- }
- else {
- $index = new rcube_result_index($mailbox, '* SORT');
- }
-
- return $index;
- }
-
-
- /**
- * Fetches thread data from IMAP server
- */
- private function get_thread_data($mailbox, $mbox_data = array())
- {
- if (empty($mbox_data)) {
- $mbox_data = $this->imap->folder_data($mailbox);
- }
-
- if ($mbox_data['EXISTS']) {
- // get all threads (default sort order)
- return $this->imap->threads_direct($mailbox);
- }
-
- return new rcube_result_thread($mailbox, '* THREAD');
- }
-
-}
-
-// for backward compat.
-class rcube_mail_header extends rcube_message_header { }
diff --git a/lib/ext/Roundcube/rcube_imap_generic.php b/lib/ext/Roundcube/rcube_imap_generic.php
deleted file mode 100644
index d78b526..0000000
--- a/lib/ext/Roundcube/rcube_imap_generic.php
+++ /dev/null
@@ -1,3925 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | Copyright (C) 2011-2012, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Provide alternative IMAP library that doesn't rely on the standard |
- | C-Client based version. This allows to function regardless |
- | of whether or not the PHP build it's running on has IMAP |
- | functionality built-in. |
- | |
- | Based on Iloha IMAP Library. See http://ilohamail.org/ for details |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <alec@alec.pl> |
- | Author: Ryo Chijiiwa <Ryo@IlohaMail.org> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * PHP based wrapper class to connect to an IMAP server
- *
- * @package Framework
- * @subpackage Storage
- */
-class rcube_imap_generic
-{
- public $error;
- public $errornum;
- public $result;
- public $resultcode;
- public $selected;
- public $data = array();
- public $flags = array(
- 'SEEN' => '\\Seen',
- 'DELETED' => '\\Deleted',
- 'ANSWERED' => '\\Answered',
- 'DRAFT' => '\\Draft',
- 'FLAGGED' => '\\Flagged',
- 'FORWARDED' => '$Forwarded',
- 'MDNSENT' => '$MDNSent',
- '*' => '\\*',
- );
-
- public static $mupdate;
-
- protected $fp;
- protected $host;
- protected $logged = false;
- protected $capability = array();
- protected $capability_readed = false;
- protected $prefs;
- protected $cmd_tag;
- protected $cmd_num = 0;
- protected $resourceid;
- protected $_debug = false;
- protected $_debug_handler = false;
-
- const ERROR_OK = 0;
- const ERROR_NO = -1;
- const ERROR_BAD = -2;
- const ERROR_BYE = -3;
- const ERROR_UNKNOWN = -4;
- const ERROR_COMMAND = -5;
- const ERROR_READONLY = -6;
-
- const COMMAND_NORESPONSE = 1;
- const COMMAND_CAPABILITY = 2;
- const COMMAND_LASTLINE = 4;
- const COMMAND_ANONYMIZED = 8;
-
- const DEBUG_LINE_LENGTH = 4098; // 4KB + 2B for \r\n
-
- /**
- * Object constructor
- */
- function __construct()
- {
- }
-
- /**
- * Send simple (one line) command to the connection stream
- *
- * @param string $string Command string
- * @param bool $endln True if CRLF need to be added at the end of command
- * @param bool $anonymized Don't write the given data to log but a placeholder
- *
- * @param int Number of bytes sent, False on error
- */
- function putLine($string, $endln=true, $anonymized=false)
- {
- if (!$this->fp)
- return false;
-
- if ($this->_debug) {
- // anonymize the sent command for logging
- $cut = $endln ? 2 : 0;
- if ($anonymized && preg_match('/^(A\d+ (?:[A-Z]+ )+)(.+)/', $string, $m)) {
- $log = $m[1] . sprintf('****** [%d]', strlen($m[2]) - $cut);
- }
- else if ($anonymized) {
- $log = sprintf('****** [%d]', strlen($string) - $cut);
- }
- else {
- $log = rtrim($string);
- }
- $this->debug('C: ' . $log);
- }
-
- $res = fwrite($this->fp, $string . ($endln ? "\r\n" : ''));
-
- if ($res === false) {
- @fclose($this->fp);
- $this->fp = null;
- }
-
- return $res;
- }
-
- /**
- * Send command to the connection stream with Command Continuation
- * Requests (RFC3501 7.5) and LITERAL+ (RFC2088) support
- *
- * @param string $string Command string
- * @param bool $endln True if CRLF need to be added at the end of command
- * @param bool $anonymized Don't write the given data to log but a placeholder
- *
- * @return int|bool Number of bytes sent, False on error
- */
- function putLineC($string, $endln=true, $anonymized=false)
- {
- if (!$this->fp) {
- return false;
- }
-
- if ($endln) {
- $string .= "\r\n";
- }
-
- $res = 0;
- if ($parts = preg_split('/(\{[0-9]+\}\r\n)/m', $string, -1, PREG_SPLIT_DELIM_CAPTURE)) {
- for ($i=0, $cnt=count($parts); $i<$cnt; $i++) {
- if (preg_match('/^\{([0-9]+)\}\r\n$/', $parts[$i+1], $matches)) {
- // LITERAL+ support
- if ($this->prefs['literal+']) {
- $parts[$i+1] = sprintf("{%d+}\r\n", $matches[1]);
- }
-
- $bytes = $this->putLine($parts[$i].$parts[$i+1], false, $anonymized);
- if ($bytes === false)
- return false;
- $res += $bytes;
-
- // don't wait if server supports LITERAL+ capability
- if (!$this->prefs['literal+']) {
- $line = $this->readLine(1000);
- // handle error in command
- if ($line[0] != '+')
- return false;
- }
- $i++;
- }
- else {
- $bytes = $this->putLine($parts[$i], false, $anonymized);
- if ($bytes === false)
- return false;
- $res += $bytes;
- }
- }
- }
- return $res;
- }
-
- /**
- * Reads line from the connection stream
- *
- * @param int $size Buffer size
- *
- * @return string Line of text response
- */
- function readLine($size=1024)
- {
- $line = '';
-
- if (!$size) {
- $size = 1024;
- }
-
- do {
- if ($this->eof()) {
- return $line ? $line : NULL;
- }
-
- $buffer = fgets($this->fp, $size);
-
- if ($buffer === false) {
- $this->closeSocket();
- break;
- }
- if ($this->_debug) {
- $this->debug('S: '. rtrim($buffer));
- }
- $line .= $buffer;
- } while (substr($buffer, -1) != "\n");
-
- return $line;
- }
-
- /**
- * Reads more data from the connection stream when provided
- * data contain string literal
- *
- * @param string $line Response text
- * @param bool $escape Enables escaping
- *
- * @return string Line of text response
- */
- function multLine($line, $escape = false)
- {
- $line = rtrim($line);
- if (preg_match('/\{([0-9]+)\}$/', $line, $m)) {
- $out = '';
- $str = substr($line, 0, -strlen($m[0]));
- $bytes = $m[1];
-
- while (strlen($out) < $bytes) {
- $line = $this->readBytes($bytes);
- if ($line === NULL)
- break;
- $out .= $line;
- }
-
- $line = $str . ($escape ? $this->escape($out) : $out);
- }
-
- return $line;
- }
-
- /**
- * Reads specified number of bytes from the connection stream
- *
- * @param int $bytes Number of bytes to get
- *
- * @return string Response text
- */
- function readBytes($bytes)
- {
- $data = '';
- $len = 0;
- while ($len < $bytes && !$this->eof())
- {
- $d = fread($this->fp, $bytes-$len);
- if ($this->_debug) {
- $this->debug('S: '. $d);
- }
- $data .= $d;
- $data_len = strlen($data);
- if ($len == $data_len) {
- break; // nothing was read -> exit to avoid apache lockups
- }
- $len = $data_len;
- }
-
- return $data;
- }
-
- /**
- * Reads complete response to the IMAP command
- *
- * @param array $untagged Will be filled with untagged response lines
- *
- * @return string Response text
- */
- function readReply(&$untagged=null)
- {
- do {
- $line = trim($this->readLine(1024));
- // store untagged response lines
- if ($line[0] == '*')
- $untagged[] = $line;
- } while ($line[0] == '*');
-
- if ($untagged)
- $untagged = join("\n", $untagged);
-
- return $line;
- }
-
- /**
- * Response parser.
- *
- * @param string $string Response text
- * @param string $err_prefix Error message prefix
- *
- * @return int Response status
- */
- function parseResult($string, $err_prefix='')
- {
- if (preg_match('/^[a-z0-9*]+ (OK|NO|BAD|BYE)(.*)$/i', trim($string), $matches)) {
- $res = strtoupper($matches[1]);
- $str = trim($matches[2]);
-
- if ($res == 'OK') {
- $this->errornum = self::ERROR_OK;
- } else if ($res == 'NO') {
- $this->errornum = self::ERROR_NO;
- } else if ($res == 'BAD') {
- $this->errornum = self::ERROR_BAD;
- } else if ($res == 'BYE') {
- $this->closeSocket();
- $this->errornum = self::ERROR_BYE;
- }
-
- if ($str) {
- $str = trim($str);
- // get response string and code (RFC5530)
- if (preg_match("/^\[([a-z-]+)\]/i", $str, $m)) {
- $this->resultcode = strtoupper($m[1]);
- $str = trim(substr($str, strlen($m[1]) + 2));
- }
- 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];
- }
- // parse response for [COPYUID 1204196876 3456:3457 123:124]
- else if (preg_match("/^\[COPYUID [0-9]+ ([0-9,:]+) ([0-9,:]+)\]/i", $str, $m)) {
- $this->data['COPYUID'] = array($m[1], $m[2]);
- }
- }
- $this->result = $str;
-
- if ($this->errornum != self::ERROR_OK) {
- $this->error = $err_prefix ? $err_prefix.$str : $str;
- }
- }
-
- return $this->errornum;
- }
- return self::ERROR_UNKNOWN;
- }
-
- /**
- * Checks connection stream state.
- *
- * @return bool True if connection is closed
- */
- protected function eof()
- {
- if (!is_resource($this->fp)) {
- return true;
- }
-
- // If a connection opened by fsockopen() wasn't closed
- // by the server, feof() will hang.
- $start = microtime(true);
-
- if (feof($this->fp) ||
- ($this->prefs['timeout'] && (microtime(true) - $start > $this->prefs['timeout']))
- ) {
- $this->closeSocket();
- return true;
- }
-
- return false;
- }
-
- /**
- * Closes connection stream.
- */
- protected function closeSocket()
- {
- @fclose($this->fp);
- $this->fp = null;
- }
-
- /**
- * Error code/message setter.
- */
- function setError($code, $msg='')
- {
- $this->errornum = $code;
- $this->error = $msg;
- }
-
- /**
- * Checks response status.
- * Checks if command response line starts with specified prefix (or * BYE/BAD)
- *
- * @param string $string Response text
- * @param string $match Prefix to match with (case-sensitive)
- * @param bool $error Enables BYE/BAD checking
- * @param bool $nonempty Enables empty response checking
- *
- * @return bool True any check is true or connection is closed.
- */
- function startsWith($string, $match, $error=false, $nonempty=false)
- {
- if (!$this->fp) {
- return true;
- }
- if (strncmp($string, $match, strlen($match)) == 0) {
- return true;
- }
- if ($error && preg_match('/^\* (BYE|BAD) /i', $string, $m)) {
- if (strtoupper($m[1]) == 'BYE') {
- $this->closeSocket();
- }
- return true;
- }
- if ($nonempty && !strlen($string)) {
- return true;
- }
- return false;
- }
-
- protected function hasCapability($name)
- {
- if (empty($this->capability) || $name == '') {
- return false;
- }
-
- if (in_array($name, $this->capability)) {
- return true;
- }
- else if (strpos($name, '=')) {
- return false;
- }
-
- $result = array();
- foreach ($this->capability as $cap) {
- $entry = explode('=', $cap);
- if ($entry[0] == $name) {
- $result[] = $entry[1];
- }
- }
-
- return !empty($result) ? $result : false;
- }
-
- /**
- * Capabilities checker
- *
- * @param string $name Capability name
- *
- * @return mixed Capability values array for key=value pairs, true/false for others
- */
- function getCapability($name)
- {
- $result = $this->hasCapability($name);
-
- if (!empty($result)) {
- return $result;
- }
- else if ($this->capability_readed) {
- return false;
- }
-
- // get capabilities (only once) because initial
- // optional CAPABILITY response may differ
- $result = $this->execute('CAPABILITY');
-
- if ($result[0] == self::ERROR_OK) {
- $this->parseCapability($result[1]);
- }
-
- $this->capability_readed = true;
-
- return $this->hasCapability($name);
- }
-
- function clearCapability()
- {
- $this->capability = array();
- $this->capability_readed = false;
- }
-
- /**
- * DIGEST-MD5/CRAM-MD5/PLAIN Authentication
- *
- * @param string $user
- * @param string $pass
- * @param string $type Authentication type (PLAIN/CRAM-MD5/DIGEST-MD5)
- *
- * @return resource Connection resourse on success, error code on error
- */
- function authenticate($user, $pass, $type='PLAIN')
- {
- if ($type == 'CRAM-MD5' || $type == 'DIGEST-MD5') {
- if ($type == 'DIGEST-MD5' && !class_exists('Auth_SASL')) {
- $this->setError(self::ERROR_BYE,
- "The Auth_SASL package is required for DIGEST-MD5 authentication");
- return self::ERROR_BAD;
- }
-
- $this->putLine($this->nextTag() . " AUTHENTICATE $type");
- $line = trim($this->readReply());
-
- if ($line[0] == '+') {
- $challenge = substr($line, 2);
- }
- else {
- return $this->parseResult($line);
- }
-
- if ($type == 'CRAM-MD5') {
- // RFC2195: CRAM-MD5
- $ipad = '';
- $opad = '';
-
- // initialize ipad, opad
- for ($i=0; $i<64; $i++) {
- $ipad .= chr(0x36);
- $opad .= chr(0x5C);
- }
-
- // pad $pass so it's 64 bytes
- $padLen = 64 - strlen($pass);
- for ($i=0; $i<$padLen; $i++) {
- $pass .= chr(0);
- }
-
- // generate hash
- $hash = md5($this->_xor($pass, $opad) . pack("H*",
- md5($this->_xor($pass, $ipad) . base64_decode($challenge))));
- $reply = base64_encode($user . ' ' . $hash);
-
- // send result
- $this->putLine($reply, true, true);
- }
- else {
- // RFC2831: DIGEST-MD5
- // proxy authorization
- if (!empty($this->prefs['auth_cid'])) {
- $authc = $this->prefs['auth_cid'];
- $pass = $this->prefs['auth_pw'];
- }
- else {
- $authc = $user;
- $user = '';
- }
- $auth_sasl = Auth_SASL::factory('digestmd5');
- $reply = base64_encode($auth_sasl->getResponse($authc, $pass,
- base64_decode($challenge), $this->host, 'imap', $user));
-
- // send result
- $this->putLine($reply, true, true);
- $line = trim($this->readReply());
-
- if ($line[0] == '+') {
- $challenge = substr($line, 2);
- }
- else {
- return $this->parseResult($line);
- }
-
- // check response
- $challenge = base64_decode($challenge);
- if (strpos($challenge, 'rspauth=') === false) {
- $this->setError(self::ERROR_BAD,
- "Unexpected response from server to DIGEST-MD5 response");
- return self::ERROR_BAD;
- }
-
- $this->putLine('');
- }
-
- $line = $this->readReply();
- $result = $this->parseResult($line);
- }
- else { // PLAIN
- // proxy authorization
- if (!empty($this->prefs['auth_cid'])) {
- $authc = $this->prefs['auth_cid'];
- $pass = $this->prefs['auth_pw'];
- }
- else {
- $authc = $user;
- $user = '';
- }
-
- $reply = base64_encode($user . chr(0) . $authc . chr(0) . $pass);
-
- // RFC 4959 (SASL-IR): save one round trip
- if ($this->getCapability('SASL-IR')) {
- list($result, $line) = $this->execute("AUTHENTICATE PLAIN", array($reply),
- self::COMMAND_LASTLINE | self::COMMAND_CAPABILITY | self::COMMAND_ANONYMIZED);
- }
- else {
- $this->putLine($this->nextTag() . " AUTHENTICATE PLAIN");
- $line = trim($this->readReply());
-
- if ($line[0] != '+') {
- return $this->parseResult($line);
- }
-
- // send result, get reply and process it
- $this->putLine($reply, true, true);
- $line = $this->readReply();
- $result = $this->parseResult($line);
- }
- }
-
- if ($result == self::ERROR_OK) {
- // optional CAPABILITY response
- if ($line && preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) {
- $this->parseCapability($matches[1], true);
- }
- return $this->fp;
- }
- else {
- $this->setError($result, "AUTHENTICATE $type: $line");
- }
-
- return $result;
- }
-
- /**
- * LOGIN Authentication
- *
- * @param string $user
- * @param string $pass
- *
- * @return resource Connection resourse on success, error code on error
- */
- function login($user, $password)
- {
- list($code, $response) = $this->execute('LOGIN', array(
- $this->escape($user), $this->escape($password)), self::COMMAND_CAPABILITY | self::COMMAND_ANONYMIZED);
-
- // re-set capabilities list if untagged CAPABILITY response provided
- if (preg_match('/\* CAPABILITY (.+)/i', $response, $matches)) {
- $this->parseCapability($matches[1], true);
- }
-
- if ($code == self::ERROR_OK) {
- return $this->fp;
- }
-
- return $code;
- }
-
- /**
- * Detects hierarchy delimiter
- *
- * @return string The delimiter
- */
- function getHierarchyDelimiter()
- {
- if ($this->prefs['delimiter']) {
- return $this->prefs['delimiter'];
- }
-
- // try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8)
- list($code, $response) = $this->execute('LIST',
- array($this->escape(''), $this->escape('')));
-
- if ($code == self::ERROR_OK) {
- $args = $this->tokenizeResponse($response, 4);
- $delimiter = $args[3];
-
- if (strlen($delimiter) > 0) {
- return ($this->prefs['delimiter'] = $delimiter);
- }
- }
-
- return NULL;
- }
-
- /**
- * NAMESPACE handler (RFC 2342)
- *
- * @return array Namespace data hash (personal, other, shared)
- */
- function getNamespace()
- {
- if (array_key_exists('namespace', $this->prefs)) {
- return $this->prefs['namespace'];
- }
-
- if (!$this->getCapability('NAMESPACE')) {
- return self::ERROR_BAD;
- }
-
- list($code, $response) = $this->execute('NAMESPACE');
-
- if ($code == self::ERROR_OK && preg_match('/^\* NAMESPACE /', $response)) {
- $data = $this->tokenizeResponse(substr($response, 11));
- }
-
- if (!is_array($data)) {
- return $code;
- }
-
- $this->prefs['namespace'] = array(
- 'personal' => $data[0],
- 'other' => $data[1],
- 'shared' => $data[2],
- );
-
- return $this->prefs['namespace'];
- }
-
- /**
- * Connects to IMAP server and authenticates.
- *
- * @param string $host Server hostname or IP
- * @param string $user User name
- * @param string $password Password
- * @param array $options Connection and class options
- *
- * @return bool True on success, False on failure
- */
- function connect($host, $user, $password, $options=null)
- {
- // configure
- $this->set_prefs($options);
-
- $this->host = $host;
- $this->user = $user;
- $this->logged = false;
- $this->selected = null;
-
- // check input
- if (empty($host)) {
- $this->setError(self::ERROR_BAD, "Empty host");
- return false;
- }
-
- if (empty($user)) {
- $this->setError(self::ERROR_NO, "Empty user");
- return false;
- }
-
- if (empty($password)) {
- $this->setError(self::ERROR_NO, "Empty password");
- return false;
- }
-
- // Connect
- if (!$this->_connect($host)) {
- return false;
- }
-
- // Send ID info
- if (!empty($this->prefs['ident']) && $this->getCapability('ID')) {
- $this->id($this->prefs['ident']);
- }
-
- $auth_method = $this->prefs['auth_type'];
- $auth_methods = array();
- $result = null;
-
- // check for supported auth methods
- if ($auth_method == 'CHECK') {
- if ($auth_caps = $this->getCapability('AUTH')) {
- $auth_methods = $auth_caps;
- }
- // RFC 2595 (LOGINDISABLED) LOGIN disabled when connection is not secure
- $login_disabled = $this->getCapability('LOGINDISABLED');
- if (($key = array_search('LOGIN', $auth_methods)) !== false) {
- if ($login_disabled) {
- unset($auth_methods[$key]);
- }
- }
- else if (!$login_disabled) {
- $auth_methods[] = 'LOGIN';
- }
-
- // Use best (for security) supported authentication method
- foreach (array('DIGEST-MD5', 'CRAM-MD5', 'CRAM_MD5', 'PLAIN', 'LOGIN') as $auth_method) {
- if (in_array($auth_method, $auth_methods)) {
- break;
- }
- }
- }
- else {
- // Prevent from sending credentials in plain text when connection is not secure
- if ($auth_method == 'LOGIN' && $this->getCapability('LOGINDISABLED')) {
- $this->setError(self::ERROR_BAD, "Login disabled by IMAP server");
- $this->closeConnection();
- return false;
- }
- // replace AUTH with CRAM-MD5 for backward compat.
- if ($auth_method == 'AUTH') {
- $auth_method = 'CRAM-MD5';
- }
- }
-
- // pre-login capabilities can be not complete
- $this->capability_readed = false;
-
- // Authenticate
- switch ($auth_method) {
- case 'CRAM_MD5':
- $auth_method = 'CRAM-MD5';
- case 'CRAM-MD5':
- case 'DIGEST-MD5':
- case 'PLAIN':
- $result = $this->authenticate($user, $password, $auth_method);
- break;
- case 'LOGIN':
- $result = $this->login($user, $password);
- break;
- default:
- $this->setError(self::ERROR_BAD, "Configuration error. Unknown auth method: $auth_method");
- }
-
- // Connected and authenticated
- if (is_resource($result)) {
- if ($this->prefs['force_caps']) {
- $this->clearCapability();
- }
- $this->logged = true;
-
- return true;
- }
-
- $this->closeConnection();
-
- return false;
- }
-
- /**
- * Connects to IMAP server.
- *
- * @param string $host Server hostname or IP
- *
- * @return bool True on success, False on failure
- */
- protected function _connect($host)
- {
- // initialize connection
- $this->error = '';
- $this->errornum = self::ERROR_OK;
-
- if (!$this->prefs['port']) {
- $this->prefs['port'] = 143;
- }
-
- // check for SSL
- if ($this->prefs['ssl_mode'] && $this->prefs['ssl_mode'] != 'tls') {
- $host = $this->prefs['ssl_mode'] . '://' . $host;
- }
-
- if ($this->prefs['timeout'] <= 0) {
- $this->prefs['timeout'] = max(0, intval(ini_get('default_socket_timeout')));
- }
-
- if (!empty($this->prefs['socket_options'])) {
- $context = stream_context_create($this->prefs['socket_options']);
- $this->fp = stream_socket_client($host . ':' . $this->prefs['port'], $errno, $errstr,
- $this->prefs['timeout'], STREAM_CLIENT_CONNECT, $context);
- }
- else {
- $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']);
- }
-
- if (!$this->fp) {
- $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s",
- $host, $this->prefs['port'], $errstr ?: "Unknown reason"));
-
- return false;
- }
-
- if ($this->prefs['timeout'] > 0) {
- stream_set_timeout($this->fp, $this->prefs['timeout']);
- }
-
- $line = trim(fgets($this->fp, 8192));
-
- if ($this->_debug) {
- // set connection identifier for debug output
- preg_match('/#([0-9]+)/', (string) $this->fp, $m);
- $this->resourceid = strtoupper(substr(md5($m[1].$this->user.microtime()), 0, 4));
-
- if ($line) {
- $this->debug('S: '. $line);
- }
- }
-
- // Connected to wrong port or connection error?
- if (!preg_match('/^\* (OK|PREAUTH)/i', $line)) {
- if ($line)
- $error = sprintf("Wrong startup greeting (%s:%d): %s", $host, $this->prefs['port'], $line);
- else
- $error = sprintf("Empty startup greeting (%s:%d)", $host, $this->prefs['port']);
-
- $this->setError(self::ERROR_BAD, $error);
- $this->closeConnection();
- return false;
- }
-
- // RFC3501 [7.1] optional CAPABILITY response
- if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) {
- $this->parseCapability($matches[1], true);
- }
-
- // TLS connection
- if ($this->prefs['ssl_mode'] == 'tls' && $this->getCapability('STARTTLS')) {
- $res = $this->execute('STARTTLS');
-
- if ($res[0] != self::ERROR_OK) {
- $this->closeConnection();
- return false;
- }
-
- if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
- $this->setError(self::ERROR_BAD, "Unable to negotiate TLS");
- $this->closeConnection();
- return false;
- }
-
- // Now we're secure, capabilities need to be reread
- $this->clearCapability();
- }
-
- return true;
- }
-
- /**
- * Initializes environment
- */
- protected function set_prefs($prefs)
- {
- // set preferences
- if (is_array($prefs)) {
- $this->prefs = $prefs;
- }
-
- // set auth method
- if (!empty($this->prefs['auth_type'])) {
- $this->prefs['auth_type'] = strtoupper($this->prefs['auth_type']);
- }
- else {
- $this->prefs['auth_type'] = 'CHECK';
- }
-
- // disabled capabilities
- if (!empty($this->prefs['disabled_caps'])) {
- $this->prefs['disabled_caps'] = array_map('strtoupper', (array)$this->prefs['disabled_caps']);
- }
-
- // additional message flags
- if (!empty($this->prefs['message_flags'])) {
- $this->flags = array_merge($this->flags, $this->prefs['message_flags']);
- unset($this->prefs['message_flags']);
- }
- }
-
- /**
- * Checks connection status
- *
- * @return bool True if connection is active and user is logged in, False otherwise.
- */
- function connected()
- {
- return ($this->fp && $this->logged) ? true : false;
- }
-
- /**
- * Closes connection with logout.
- */
- function closeConnection()
- {
- if ($this->logged && $this->putLine($this->nextTag() . ' LOGOUT')) {
- $this->readReply();
- }
-
- $this->closeSocket();
- }
-
- /**
- * Executes SELECT command (if mailbox is already not in selected state)
- *
- * @param string $mailbox Mailbox name
- * @param array $qresync_data QRESYNC data (RFC5162)
- *
- * @return boolean True on success, false on error
- */
- function select($mailbox, $qresync_data = null)
- {
- if (!strlen($mailbox)) {
- return false;
- }
-
- if ($this->selected === $mailbox) {
- return true;
- }
-/*
- Temporary commented out because Courier returns \Noselect for INBOX
- Requires more investigation
-
- if (is_array($this->data['LIST']) && is_array($opts = $this->data['LIST'][$mailbox])) {
- if (in_array('\\Noselect', $opts)) {
- return false;
- }
- }
-*/
- $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);
- foreach ($response as $line) {
- if (preg_match('/^\* ([0-9]+) (EXISTS|RECENT)$/i', $line, $m)) {
- $this->data[strtoupper($m[2])] = (int) $m[1];
- }
- 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;
- }
- // 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;
- }
- }
-
- $this->data['READ-WRITE'] = $this->resultcode != 'READ-ONLY';
-
- $this->selected = $mailbox;
- return true;
- }
-
- return false;
- }
-
- /**
- * Executes STATUS command
- *
- * @param string $mailbox Mailbox name
- * @param array $items Additional requested item names. By default
- * MESSAGES and UNSEEN are requested. Other defined
- * in RFC3501: UIDNEXT, UIDVALIDITY, RECENT
- *
- * @return array Status item-value hash
- * @since 0.5-beta
- */
- function status($mailbox, $items=array())
- {
- if (!strlen($mailbox)) {
- return false;
- }
-
- if (!in_array('MESSAGES', $items)) {
- $items[] = 'MESSAGES';
- }
- if (!in_array('UNSEEN', $items)) {
- $items[] = 'UNSEEN';
- }
-
- list($code, $response) = $this->execute('STATUS', array($this->escape($mailbox),
- '(' . implode(' ', (array) $items) . ')'));
-
- if ($code == self::ERROR_OK && preg_match('/\* STATUS /i', $response)) {
- $result = array();
- $response = substr($response, 9); // remove prefix "* STATUS "
-
- list($mbox, $items) = $this->tokenizeResponse($response, 2);
-
- // Fix for #1487859. Some buggy server returns not quoted
- // folder name with spaces. Let's try to handle this situation
- if (!is_array($items) && ($pos = strpos($response, '(')) !== false) {
- $response = substr($response, $pos);
- $items = $this->tokenizeResponse($response, 1);
- if (!is_array($items)) {
- return $result;
- }
- }
-
- for ($i=0, $len=count($items); $i<$len; $i += 2) {
- $result[$items[$i]] = $items[$i+1];
- }
-
- $this->data['STATUS:'.$mailbox] = $result;
-
- return $result;
- }
-
- return false;
- }
-
- /**
- * Executes EXPUNGE command
- *
- * @param string $mailbox Mailbox name
- * @param string|array $messages Message UIDs to expunge
- *
- * @return boolean True on success, False on error
- */
- function expunge($mailbox, $messages=NULL)
- {
- if (!$this->select($mailbox)) {
- return false;
- }
-
- if (!$this->data['READ-WRITE']) {
- $this->setError(self::ERROR_READONLY, "Mailbox is read-only");
- return false;
- }
-
- // Clear internal status cache
- unset($this->data['STATUS:'.$mailbox]);
-
- if (!empty($messages) && $messages != '*' && $this->hasCapability('UIDPLUS')) {
- $messages = self::compressMessageSet($messages);
- $result = $this->execute('UID EXPUNGE', array($messages), self::COMMAND_NORESPONSE);
- }
- else {
- $result = $this->execute('EXPUNGE', null, self::COMMAND_NORESPONSE);
- }
-
- if ($result == self::ERROR_OK) {
- $this->selected = null; // state has changed, need to reselect
- return true;
- }
-
- return false;
- }
-
- /**
- * Executes CLOSE command
- *
- * @return boolean True on success, False on error
- * @since 0.5
- */
- function close()
- {
- $result = $this->execute('CLOSE', NULL, self::COMMAND_NORESPONSE);
-
- if ($result == self::ERROR_OK) {
- $this->selected = null;
- return true;
- }
-
- return false;
- }
-
- /**
- * Folder subscription (SUBSCRIBE)
- *
- * @param string $mailbox Mailbox name
- *
- * @return boolean True on success, False on error
- */
- function subscribe($mailbox)
- {
- $result = $this->execute('SUBSCRIBE', array($this->escape($mailbox)),
- self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- /**
- * Folder unsubscription (UNSUBSCRIBE)
- *
- * @param string $mailbox Mailbox name
- *
- * @return boolean True on success, False on error
- */
- function unsubscribe($mailbox)
- {
- $result = $this->execute('UNSUBSCRIBE', array($this->escape($mailbox)),
- self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- /**
- * Folder creation (CREATE)
- *
- * @param string $mailbox Mailbox name
- * @param array $types Optional folder types (RFC 6154)
- *
- * @return bool True on success, False on error
- */
- function createFolder($mailbox, $types = null)
- {
- $args = array($this->escape($mailbox));
-
- // RFC 6154: CREATE-SPECIAL-USE
- if (!empty($types) && $this->getCapability('CREATE-SPECIAL-USE')) {
- $args[] = '(USE (' . implode(' ', $types) . '))';
- }
-
- $result = $this->execute('CREATE', $args, self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- /**
- * Folder renaming (RENAME)
- *
- * @param string $mailbox Mailbox name
- *
- * @return bool True on success, False on error
- */
- function renameFolder($from, $to)
- {
- $result = $this->execute('RENAME', array($this->escape($from), $this->escape($to)),
- self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- /**
- * Executes DELETE command
- *
- * @param string $mailbox Mailbox name
- *
- * @return boolean True on success, False on error
- */
- function deleteFolder($mailbox)
- {
- $result = $this->execute('DELETE', array($this->escape($mailbox)),
- self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- /**
- * Removes all messages in a folder
- *
- * @param string $mailbox Mailbox name
- *
- * @return boolean True on success, False on error
- */
- function clearFolder($mailbox)
- {
- $num_in_trash = $this->countMessages($mailbox);
- if ($num_in_trash > 0) {
- $res = $this->flag($mailbox, '1:*', 'DELETED');
- }
-
- if ($res) {
- if ($this->selected === $mailbox)
- $res = $this->close();
- else
- $res = $this->expunge($mailbox);
- }
-
- return $res;
- }
-
- /**
- * Returns list of mailboxes
- *
- * @param string $ref Reference name
- * @param string $mailbox Mailbox name
- * @param array $return_opts (see self::_listMailboxes)
- * @param array $select_opts (see self::_listMailboxes)
- *
- * @return array|bool List of mailboxes or hash of options if STATUS/MYROGHTS response
- * is requested, False on error.
- */
- function listMailboxes($ref, $mailbox, $return_opts=array(), $select_opts=array())
- {
- return $this->_listMailboxes($ref, $mailbox, false, $return_opts, $select_opts);
- }
-
- /**
- * Returns list of subscribed mailboxes
- *
- * @param string $ref Reference name
- * @param string $mailbox Mailbox name
- * @param array $return_opts (see self::_listMailboxes)
- *
- * @return array|bool List of mailboxes or hash of options if STATUS/MYROGHTS response
- * is requested, False on error.
- */
- function listSubscribed($ref, $mailbox, $return_opts=array())
- {
- return $this->_listMailboxes($ref, $mailbox, true, $return_opts, NULL);
- }
-
- /**
- * IMAP LIST/LSUB command
- *
- * @param string $ref Reference name
- * @param string $mailbox Mailbox name
- * @param bool $subscribed Enables returning subscribed mailboxes only
- * @param array $return_opts List of RETURN options (RFC5819: LIST-STATUS, RFC5258: LIST-EXTENDED)
- * Possible: MESSAGES, RECENT, UIDNEXT, UIDVALIDITY, UNSEEN,
- * MYRIGHTS, SUBSCRIBED, CHILDREN
- * @param array $select_opts List of selection options (RFC5258: LIST-EXTENDED)
- * Possible: SUBSCRIBED, RECURSIVEMATCH, REMOTE,
- * SPECIAL-USE (RFC6154)
- *
- * @return array|bool List of mailboxes or hash of options if STATUS/MYROGHTS response
- * is requested, False on error.
- */
- protected function _listMailboxes($ref, $mailbox, $subscribed=false,
- $return_opts=array(), $select_opts=array())
- {
- if (!strlen($mailbox)) {
- $mailbox = '*';
- }
-
- $args = array();
- $rets = array();
-
- if (!empty($select_opts) && $this->getCapability('LIST-EXTENDED')) {
- $select_opts = (array) $select_opts;
-
- $args[] = '(' . implode(' ', $select_opts) . ')';
- }
-
- $args[] = $this->escape($ref);
- $args[] = $this->escape($mailbox);
-
- if (!empty($return_opts) && $this->getCapability('LIST-EXTENDED')) {
- $ext_opts = array('SUBSCRIBED', 'CHILDREN');
- $rets = array_intersect($return_opts, $ext_opts);
- $return_opts = array_diff($return_opts, $rets);
- }
-
- if (!empty($return_opts) && $this->getCapability('LIST-STATUS')) {
- $lstatus = true;
- $status_opts = array('MESSAGES', 'RECENT', 'UIDNEXT', 'UIDVALIDITY', 'UNSEEN');
- $opts = array_diff($return_opts, $status_opts);
- $status_opts = array_diff($return_opts, $opts);
-
- if (!empty($status_opts)) {
- $rets[] = 'STATUS (' . implode(' ', $status_opts) . ')';
- }
-
- if (!empty($opts)) {
- $rets = array_merge($rets, $opts);
- }
- }
-
- if (!empty($rets)) {
- $args[] = 'RETURN (' . implode(' ', $rets) . ')';
- }
-
- list($code, $response) = $this->execute($subscribed ? 'LSUB' : 'LIST', $args);
-
- if ($code == self::ERROR_OK) {
- $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|MYRIGHTS) /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($line, 3);
-
- // Remove redundant separator at the end of folder name, UW-IMAP bug? (#1488879)
- if ($delim) {
- $mailbox = rtrim($mailbox, $delim);
- }
-
- // Add to result array
- if (!$lstatus) {
- $folders[] = $mailbox;
- }
- else {
- $folders[$mailbox] = array();
- }
-
- // store folder options
- if ($cmd == 'LIST') {
- // Add to options array
- 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));
- }
- }
- else if ($lstatus) {
- // * STATUS <mailbox> (<result>)
- if ($cmd == 'STATUS') {
- 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;
- }
- }
- // * MYRIGHTS <mailbox> <acl>
- else if ($cmd == 'MYRIGHTS') {
- list($mailbox, $acl) = $this->tokenizeResponse($line, 2);
- $folders[$mailbox]['MYRIGHTS'] = $acl;
- }
- }
- }
-
- return $folders;
- }
-
- return false;
- }
-
- /**
- * Returns count of all messages in a folder
- *
- * @param string $mailbox Mailbox name
- *
- * @return int Number of messages, False on error
- */
- function countMessages($mailbox, $refresh = false)
- {
- if ($refresh) {
- $this->selected = null;
- }
-
- if ($this->selected === $mailbox) {
- return $this->data['EXISTS'];
- }
-
- // Check internal cache
- $cache = $this->data['STATUS:'.$mailbox];
- if (!empty($cache) && isset($cache['MESSAGES'])) {
- return (int) $cache['MESSAGES'];
- }
-
- // Try STATUS (should be faster than SELECT)
- $counts = $this->status($mailbox);
- if (is_array($counts)) {
- return (int) $counts['MESSAGES'];
- }
-
- return false;
- }
-
- /**
- * Returns count of messages with \Recent flag in a folder
- *
- * @param string $mailbox Mailbox name
- *
- * @return int Number of messages, False on error
- */
- function countRecent($mailbox)
- {
- if (!strlen($mailbox)) {
- $mailbox = 'INBOX';
- }
-
- $this->select($mailbox);
-
- if ($this->selected === $mailbox) {
- return $this->data['RECENT'];
- }
-
- return false;
- }
-
- /**
- * Returns count of messages without \Seen flag in a specified folder
- *
- * @param string $mailbox Mailbox name
- *
- * @return int Number of messages, False on error
- */
- function countUnseen($mailbox)
- {
- // Check internal cache
- $cache = $this->data['STATUS:'.$mailbox];
- if (!empty($cache) && isset($cache['UNSEEN'])) {
- return (int) $cache['UNSEEN'];
- }
-
- // Try STATUS (should be faster than SELECT+SEARCH)
- $counts = $this->status($mailbox);
- if (is_array($counts)) {
- return (int) $counts['UNSEEN'];
- }
-
- // Invoke SEARCH as a fallback
- $index = $this->search($mailbox, 'ALL UNSEEN', false, array('COUNT'));
- if (!$index->is_error()) {
- return $index->count();
- }
-
- return false;
- }
-
- /**
- * Executes ID command (RFC2971)
- *
- * @param array $items Client identification information key/value hash
- *
- * @return array Server identification information key/value hash
- * @since 0.6
- */
- function id($items=array())
- {
- if (is_array($items) && !empty($items)) {
- foreach ($items as $key => $value) {
- $args[] = $this->escape($key, true);
- $args[] = $this->escape($value, true);
- }
- }
-
- list($code, $response) = $this->execute('ID', array(
- !empty($args) ? '(' . implode(' ', (array) $args) . ')' : $this->escape(null)
- ));
-
-
- if ($code == self::ERROR_OK && preg_match('/\* ID /i', $response)) {
- $response = substr($response, 5); // remove prefix "* ID "
- $items = $this->tokenizeResponse($response, 1);
- $result = null;
-
- for ($i=0, $len=count($items); $i<$len; $i += 2) {
- $result[$items[$i]] = $items[$i+1];
- }
-
- return $result;
- }
-
- 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);
- }
-
- if (!empty($this->extensions_enabled)) {
- // check if all extensions are already enabled
- $diff = array_diff($extension, $this->extensions_enabled);
-
- if (empty($diff)) {
- return $extension;
- }
-
- // Make sure the mailbox isn't selected, before enabling extension(s)
- if ($this->selected !== null) {
- $this->close();
- }
- }
-
- 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);
-
- $this->extensions_enabled = array_unique(array_merge((array)$this->extensions_enabled, $result));
-
- return $this->extensions_enabled;
- }
-
- return false;
- }
-
- /**
- * Executes SORT command
- *
- * @param string $mailbox Mailbox name
- * @param string $field Field to sort by (ARRIVAL, CC, DATE, FROM, SIZE, SUBJECT, TO)
- * @param string $criteria Searching criteria
- * @param bool $return_uid Enables UID SORT usage
- * @param string $encoding Character set
- *
- * @return rcube_result_index Response data
- */
- function sort($mailbox, $field = 'ARRIVAL', $criteria = '', $return_uid = false, $encoding = 'US-ASCII')
- {
- $old_sel = $this->selected;
- $supported = array('ARRIVAL', 'CC', 'DATE', 'FROM', 'SIZE', 'SUBJECT', 'TO');
- $field = strtoupper($field);
-
- if ($field == 'INTERNALDATE') {
- $field = 'ARRIVAL';
- }
-
- if (!in_array($field, $supported)) {
- return new rcube_result_index($mailbox);
- }
-
- if (!$this->select($mailbox)) {
- return new rcube_result_index($mailbox);
- }
-
- // return empty result when folder is empty and we're just after SELECT
- if ($old_sel != $mailbox && !$this->data['EXISTS']) {
- return new rcube_result_index($mailbox, '* SORT');
- }
-
- // RFC 5957: SORT=DISPLAY
- if (($field == 'FROM' || $field == 'TO') && $this->getCapability('SORT=DISPLAY')) {
- $field = 'DISPLAY' . $field;
- }
-
- $encoding = $encoding ? trim($encoding) : 'US-ASCII';
- $criteria = $criteria ? 'ALL ' . trim($criteria) : 'ALL';
-
- list($code, $response) = $this->execute($return_uid ? 'UID SORT' : 'SORT',
- array("($field)", $encoding, $criteria));
-
- if ($code != self::ERROR_OK) {
- $response = null;
- }
-
- return new rcube_result_index($mailbox, $response);
- }
-
- /**
- * Executes THREAD command
- *
- * @param string $mailbox Mailbox name
- * @param string $algorithm Threading algorithm (ORDEREDSUBJECT, REFERENCES, REFS)
- * @param string $criteria Searching criteria
- * @param bool $return_uid Enables UIDs in result instead of sequence numbers
- * @param string $encoding Character set
- *
- * @return rcube_result_thread Thread data
- */
- function thread($mailbox, $algorithm='REFERENCES', $criteria='', $return_uid=false, $encoding='US-ASCII')
- {
- $old_sel = $this->selected;
-
- if (!$this->select($mailbox)) {
- return new rcube_result_thread($mailbox);
- }
-
- // return empty result when folder is empty and we're just after SELECT
- if ($old_sel != $mailbox && !$this->data['EXISTS']) {
- return new rcube_result_thread($mailbox, '* THREAD');
- }
-
- $encoding = $encoding ? trim($encoding) : 'US-ASCII';
- $algorithm = $algorithm ? trim($algorithm) : 'REFERENCES';
- $criteria = $criteria ? 'ALL '.trim($criteria) : 'ALL';
- $data = '';
-
- list($code, $response) = $this->execute($return_uid ? 'UID THREAD' : 'THREAD',
- array($algorithm, $encoding, $criteria));
-
- if ($code != self::ERROR_OK) {
- $response = null;
- }
-
- return new rcube_result_thread($mailbox, $response);
- }
-
- /**
- * Executes SEARCH command
- *
- * @param string $mailbox Mailbox name
- * @param string $criteria Searching criteria
- * @param bool $return_uid Enable UID in result instead of sequence ID
- * @param array $items Return items (MIN, MAX, COUNT, ALL)
- *
- * @return rcube_result_index Result data
- */
- function search($mailbox, $criteria, $return_uid=false, $items=array())
- {
- $old_sel = $this->selected;
-
- if (!$this->select($mailbox)) {
- return new rcube_result_index($mailbox);
- }
-
- // return empty result when folder is empty and we're just after SELECT
- if ($old_sel != $mailbox && !$this->data['EXISTS']) {
- return new rcube_result_index($mailbox, '* SEARCH');
- }
-
- // If ESEARCH is supported always use ALL
- // but not when items are specified or using simple id2uid search
- if (empty($items) && preg_match('/[^0-9]/', $criteria)) {
- $items = array('ALL');
- }
-
- $esearch = empty($items) ? false : $this->getCapability('ESEARCH');
- $criteria = trim($criteria);
- $params = '';
-
- // RFC4731: ESEARCH
- if (!empty($items) && $esearch) {
- $params .= 'RETURN (' . implode(' ', $items) . ')';
- }
-
- if (!empty($criteria)) {
- $params .= ($params ? ' ' : '') . $criteria;
- }
- else {
- $params .= 'ALL';
- }
-
- list($code, $response) = $this->execute($return_uid ? 'UID SEARCH' : 'SEARCH',
- array($params));
-
- if ($code != self::ERROR_OK) {
- $response = null;
- }
-
- return new rcube_result_index($mailbox, $response);
- }
-
- /**
- * Simulates SORT command by using FETCH and sorting.
- *
- * @param string $mailbox Mailbox name
- * @param string|array $message_set Searching criteria (list of messages to return)
- * @param string $index_field Field to sort by (ARRIVAL, CC, DATE, FROM, SIZE, SUBJECT, TO)
- * @param bool $skip_deleted Makes that DELETED messages will be skipped
- * @param bool $uidfetch Enables UID FETCH usage
- * @param bool $return_uid Enables returning UIDs instead of IDs
- *
- * @return rcube_result_index Response data
- */
- function index($mailbox, $message_set, $index_field='', $skip_deleted=true,
- $uidfetch=false, $return_uid=false)
- {
- $msg_index = $this->fetchHeaderIndex($mailbox, $message_set,
- $index_field, $skip_deleted, $uidfetch, $return_uid);
-
- if (!empty($msg_index)) {
- asort($msg_index); // ASC
- $msg_index = array_keys($msg_index);
- $msg_index = '* SEARCH ' . implode(' ', $msg_index);
- }
- else {
- $msg_index = is_array($msg_index) ? '* SEARCH' : null;
- }
-
- return new rcube_result_index($mailbox, $msg_index);
- }
-
- function fetchHeaderIndex($mailbox, $message_set, $index_field='', $skip_deleted=true,
- $uidfetch=false, $return_uid=false)
- {
- if (is_array($message_set)) {
- if (!($message_set = $this->compressMessageSet($message_set)))
- return false;
- } else {
- list($from_idx, $to_idx) = explode(':', $message_set);
- if (empty($message_set) ||
- (isset($to_idx) && $to_idx != '*' && (int)$from_idx > (int)$to_idx)) {
- return false;
- }
- }
-
- $index_field = empty($index_field) ? 'DATE' : strtoupper($index_field);
-
- $fields_a['DATE'] = 1;
- $fields_a['INTERNALDATE'] = 4;
- $fields_a['ARRIVAL'] = 4;
- $fields_a['FROM'] = 1;
- $fields_a['REPLY-TO'] = 1;
- $fields_a['SENDER'] = 1;
- $fields_a['TO'] = 1;
- $fields_a['CC'] = 1;
- $fields_a['SUBJECT'] = 1;
- $fields_a['UID'] = 2;
- $fields_a['SIZE'] = 2;
- $fields_a['SEEN'] = 3;
- $fields_a['RECENT'] = 3;
- $fields_a['DELETED'] = 3;
-
- if (!($mode = $fields_a[$index_field])) {
- return false;
- }
-
- /* Do "SELECT" command */
- if (!$this->select($mailbox)) {
- return false;
- }
-
- // build FETCH command string
- $key = $this->nextTag();
- $cmd = $uidfetch ? 'UID FETCH' : 'FETCH';
- $fields = array();
-
- if ($return_uid)
- $fields[] = 'UID';
- if ($skip_deleted)
- $fields[] = 'FLAGS';
-
- if ($mode == 1) {
- if ($index_field == 'DATE')
- $fields[] = 'INTERNALDATE';
- $fields[] = "BODY.PEEK[HEADER.FIELDS ($index_field)]";
- }
- else if ($mode == 2) {
- if ($index_field == 'SIZE')
- $fields[] = 'RFC822.SIZE';
- else if (!$return_uid || $index_field != 'UID')
- $fields[] = $index_field;
- }
- else if ($mode == 3 && !$skip_deleted)
- $fields[] = 'FLAGS';
- else if ($mode == 4)
- $fields[] = 'INTERNALDATE';
-
- $request = "$key $cmd $message_set (" . implode(' ', $fields) . ")";
-
- if (!$this->putLine($request)) {
- $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
- return false;
- }
-
- $result = array();
-
- do {
- $line = rtrim($this->readLine(200));
- $line = $this->multLine($line);
-
- if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) {
- $id = $m[1];
- $flags = NULL;
-
- if ($return_uid) {
- if (preg_match('/UID ([0-9]+)/', $line, $matches))
- $id = (int) $matches[1];
- else
- continue;
- }
- if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) {
- $flags = explode(' ', strtoupper($matches[1]));
- if (in_array('\\DELETED', $flags)) {
- continue;
- }
- }
-
- if ($mode == 1 && $index_field == 'DATE') {
- if (preg_match('/BODY\[HEADER\.FIELDS \("*DATE"*\)\] (.*)/', $line, $matches)) {
- $value = preg_replace(array('/^"*[a-z]+:/i'), '', $matches[1]);
- $value = trim($value);
- $result[$id] = $this->strToTime($value);
- }
- // non-existent/empty Date: header, use INTERNALDATE
- if (empty($result[$id])) {
- if (preg_match('/INTERNALDATE "([^"]+)"/', $line, $matches))
- $result[$id] = $this->strToTime($matches[1]);
- else
- $result[$id] = 0;
- }
- } else if ($mode == 1) {
- if (preg_match('/BODY\[HEADER\.FIELDS \("?(FROM|REPLY-TO|SENDER|TO|SUBJECT)"?\)\] (.*)/', $line, $matches)) {
- $value = preg_replace(array('/^"*[a-z]+:/i', '/\s+$/sm'), array('', ''), $matches[2]);
- $result[$id] = trim($value);
- } else {
- $result[$id] = '';
- }
- } else if ($mode == 2) {
- if (preg_match('/' . $index_field . ' ([0-9]+)/', $line, $matches)) {
- $result[$id] = trim($matches[1]);
- } else {
- $result[$id] = 0;
- }
- } else if ($mode == 3) {
- if (!$flags && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) {
- $flags = explode(' ', $matches[1]);
- }
- $result[$id] = in_array('\\'.$index_field, $flags) ? 1 : 0;
- } else if ($mode == 4) {
- if (preg_match('/INTERNALDATE "([^"]+)"/', $line, $matches)) {
- $result[$id] = $this->strToTime($matches[1]);
- } else {
- $result[$id] = 0;
- }
- }
- }
- } while (!$this->startsWith($line, $key, true, true));
-
- return $result;
- }
-
- /**
- * Returns message sequence identifier
- *
- * @param string $mailbox Mailbox name
- * @param int $uid Message unique identifier (UID)
- *
- * @return int Message sequence identifier
- */
- function UID2ID($mailbox, $uid)
- {
- if ($uid > 0) {
- $index = $this->search($mailbox, "UID $uid");
-
- if ($index->count() == 1) {
- $arr = $index->get();
- return (int) $arr[0];
- }
- }
- return null;
- }
-
- /**
- * Returns message unique identifier (UID)
- *
- * @param string $mailbox Mailbox name
- * @param int $uid Message sequence identifier
- *
- * @return int Message unique identifier
- */
- function ID2UID($mailbox, $id)
- {
- if (empty($id) || $id < 0) {
- return null;
- }
-
- if (!$this->select($mailbox)) {
- return null;
- }
-
- $index = $this->search($mailbox, $id, true);
-
- if ($index->count() == 1) {
- $arr = $index->get();
- return (int) $arr[0];
- }
-
- return null;
- }
-
- /**
- * Sets flag of the message(s)
- *
- * @param string $mailbox Mailbox name
- * @param string|array $messages Message UID(s)
- * @param string $flag Flag name
- *
- * @return bool True on success, False on failure
- */
- function flag($mailbox, $messages, $flag) {
- return $this->modFlag($mailbox, $messages, $flag, '+');
- }
-
- /**
- * Unsets flag of the message(s)
- *
- * @param string $mailbox Mailbox name
- * @param string|array $messages Message UID(s)
- * @param string $flag Flag name
- *
- * @return bool True on success, False on failure
- */
- function unflag($mailbox, $messages, $flag) {
- return $this->modFlag($mailbox, $messages, $flag, '-');
- }
-
- /**
- * Changes flag of the message(s)
- *
- * @param string $mailbox Mailbox name
- * @param string|array $messages Message UID(s)
- * @param string $flag Flag name
- * @param string $mod Modifier [+|-]. Default: "+".
- *
- * @return bool True on success, False on failure
- */
- protected function modFlag($mailbox, $messages, $flag, $mod = '+')
- {
- if (!$this->select($mailbox)) {
- return false;
- }
-
- if (!$this->data['READ-WRITE']) {
- $this->setError(self::ERROR_READONLY, "Mailbox is read-only");
- return false;
- }
-
- if ($this->flags[strtoupper($flag)]) {
- $flag = $this->flags[strtoupper($flag)];
- }
-
- if (!$flag) {
- return false;
- }
-
- // if PERMANENTFLAGS is not specified all flags are allowed
- if (!empty($this->data['PERMANENTFLAGS'])
- && !in_array($flag, (array) $this->data['PERMANENTFLAGS'])
- && !in_array('\\*', (array) $this->data['PERMANENTFLAGS'])
- ) {
- return false;
- }
-
- // Clear internal status cache
- if ($flag == 'SEEN') {
- unset($this->data['STATUS:'.$mailbox]['UNSEEN']);
- }
-
- if ($mod != '+' && $mod != '-') {
- $mod = '+';
- }
-
- $result = $this->execute('UID STORE', array(
- $this->compressMessageSet($messages), $mod . 'FLAGS.SILENT', "($flag)"),
- self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- /**
- * Copies message(s) from one folder to another
- *
- * @param string|array $messages Message UID(s)
- * @param string $from Mailbox name
- * @param string $to Destination mailbox name
- *
- * @return bool True on success, False on failure
- */
- function copy($messages, $from, $to)
- {
- // Clear last COPYUID data
- unset($this->data['COPYUID']);
-
- if (!$this->select($from)) {
- return false;
- }
-
- // Clear internal status cache
- unset($this->data['STATUS:'.$to]);
-
- $result = $this->execute('UID COPY', array(
- $this->compressMessageSet($messages), $this->escape($to)),
- self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- /**
- * Moves message(s) from one folder to another.
- *
- * @param string|array $messages Message UID(s)
- * @param string $from Mailbox name
- * @param string $to Destination mailbox name
- *
- * @return bool True on success, False on failure
- */
- function move($messages, $from, $to)
- {
- if (!$this->select($from)) {
- return false;
- }
-
- if (!$this->data['READ-WRITE']) {
- $this->setError(self::ERROR_READONLY, "Mailbox is read-only");
- return false;
- }
-
- // use MOVE command (RFC 6851)
- if ($this->hasCapability('MOVE')) {
- // Clear last COPYUID data
- unset($this->data['COPYUID']);
-
- // Clear internal status cache
- unset($this->data['STATUS:'.$to]);
- unset($this->data['STATUS:'.$from]);
-
- $result = $this->execute('UID MOVE', array(
- $this->compressMessageSet($messages), $this->escape($to)),
- self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- // use COPY + STORE +FLAGS.SILENT \Deleted + EXPUNGE
- $result = $this->copy($messages, $from, $to);
-
- if ($result) {
- // Clear internal status cache
- unset($this->data['STATUS:'.$from]);
-
- $result = $this->flag($from, $messages, 'DELETED');
-
- if ($messages == '*') {
- // CLOSE+SELECT should be faster than EXPUNGE
- $this->close();
- }
- else {
- $this->expunge($from, $messages);
- }
- }
-
- return $result;
- }
-
- /**
- * 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_message_header elements, False on error
- * @since 0.6
- */
- function fetch($mailbox, $message_set, $is_uid = false, $query_items = array(),
- $mod_seq = null, $vanished = false)
- {
- if (!$this->select($mailbox)) {
- return false;
- }
-
- $message_set = $this->compressMessageSet($message_set);
- $result = array();
-
- $key = $this->nextTag();
- $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);
-
- 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] = new rcube_message_header;
- $result[$id]->id = $id;
- $result[$id]->subject = '';
- $result[$id]->messageID = 'mid:' . $id;
-
- $headers = null;
- $lines = array();
- $line = substr($line, strlen($m[0]) + 2);
- $ln = 0;
-
- // get complete entry
- while (preg_match('/\{([0-9]+)\}\r\n$/', $line, $m)) {
- $bytes = $m[1];
- $out = '';
-
- while (strlen($out) < $bytes) {
- $out = $this->readBytes($bytes);
- if ($out === NULL)
- break;
- $line .= $out;
- }
-
- $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);
-
- $result[$id]->flags[$flag] = true;
- }
- }
- }
- else if ($name == 'MODSEQ') {
- $result[$id]->modseq = $value[0];
- }
- else if ($name == 'ENVELOPE') {
- $result[$id]->envelope = $value;
- }
- 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;
- }
- else if ($name == 'RFC822') {
- $result[$id]->body = $value;
- }
- else if (stripos($name, 'BODY[') === 0) {
- $name = str_replace(']', '', substr($name, 5));
-
- if ($name == 'HEADER.FIELDS') {
- // skip ']' after headers list
- $this->tokenizeResponse($line, 1);
- $headers = $this->tokenizeResponse($line, 1);
- }
- else if (strlen($name))
- $result[$id]->bodypart[$name] = $value;
- else
- $result[$id]->body = $value;
- }
- }
-
- // create array with header field:data
- if (!empty($headers)) {
- $headers = explode("\n", trim($headers));
- foreach ($headers as $resln) {
- if (ord($resln[0]) <= 32) {
- $lines[$ln] .= (empty($lines[$ln]) ? '' : "\n") . trim($resln);
- } else {
- $lines[++$ln] = trim($resln);
- }
- }
-
- foreach ($lines as $str) {
- list($field, $string) = explode(':', $str, 2);
-
- $field = strtolower($field);
- $string = preg_replace('/\n[\t\s]*/', ' ', trim($string));
-
- switch ($field) {
- case 'date';
- $result[$id]->date = $string;
- $result[$id]->timestamp = $this->strToTime($string);
- break;
- case 'from':
- $result[$id]->from = $string;
- break;
- case 'to':
- $result[$id]->to = preg_replace('/undisclosed-recipients:[;,]*/', '', $string);
- break;
- case 'subject':
- $result[$id]->subject = $string;
- break;
- case 'reply-to':
- $result[$id]->replyto = $string;
- break;
- case 'cc':
- $result[$id]->cc = $string;
- break;
- case 'bcc':
- $result[$id]->bcc = $string;
- break;
- case 'content-transfer-encoding':
- $result[$id]->encoding = $string;
- break;
- case 'content-type':
- $ctype_parts = preg_split('/[; ]+/', $string);
- $result[$id]->ctype = strtolower(array_shift($ctype_parts));
- if (preg_match('/charset\s*=\s*"?([a-z0-9\-\.\_]+)"?/i', $string, $regs)) {
- $result[$id]->charset = $regs[1];
- }
- break;
- case 'in-reply-to':
- $result[$id]->in_reply_to = str_replace(array("\n", '<', '>'), '', $string);
- break;
- case 'references':
- $result[$id]->references = $string;
- break;
- case 'return-receipt-to':
- case 'disposition-notification-to':
- case 'x-confirm-reading-to':
- $result[$id]->mdn_to = $string;
- break;
- case 'message-id':
- $result[$id]->messageID = $string;
- break;
- case 'x-priority':
- if (preg_match('/^(\d+)/', $string, $matches)) {
- $result[$id]->priority = intval($matches[1]);
- }
- break;
- default:
- if (strlen($field) < 3) {
- break;
- }
- if ($result[$id]->others[$field]) {
- $string = array_merge((array)$result[$id]->others[$field], (array)$string);
- }
- $result[$id]->others[$field] = $string;
- }
- }
- }
- }
-
- // 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;
- }
-
- /**
- * Returns message(s) data (flags, headers, etc.)
- *
- * @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 bool $bodystr Enable to add BODYSTRUCTURE data to the result
- * @param array $add_headers List of additional headers
- *
- * @return bool|array List of rcube_message_header elements, False on error
- */
- function fetchHeaders($mailbox, $message_set, $is_uid = false, $bodystr = false, $add_headers = array())
- {
- $query_items = array('UID', 'RFC822.SIZE', 'FLAGS', 'INTERNALDATE');
- $headers = array('DATE', 'FROM', 'TO', 'SUBJECT', 'CONTENT-TYPE', 'CC', 'REPLY-TO',
- 'LIST-POST', 'DISPOSITION-NOTIFICATION-TO', 'X-PRIORITY');
-
- if (!empty($add_headers)) {
- $add_headers = array_map('strtoupper', $add_headers);
- $headers = array_unique(array_merge($headers, $add_headers));
- }
-
- if ($bodystr) {
- $query_items[] = 'BODYSTRUCTURE';
- }
-
- $query_items[] = 'BODY.PEEK[HEADER.FIELDS (' . implode(' ', $headers) . ')]';
-
- $result = $this->fetch($mailbox, $message_set, $is_uid, $query_items);
-
- return $result;
- }
-
- /**
- * Returns message data (flags, headers, etc.)
- *
- * @param string $mailbox Mailbox name
- * @param int $id Message sequence identifier or UID
- * @param bool $is_uid True if $id is an UID
- * @param bool $bodystr Enable to add BODYSTRUCTURE data to the result
- * @param array $add_headers List of additional headers
- *
- * @return bool|rcube_message_header Message data, False on error
- */
- function fetchHeader($mailbox, $id, $is_uid = false, $bodystr = false, $add_headers = array())
- {
- $a = $this->fetchHeaders($mailbox, $id, $is_uid, $bodystr, $add_headers);
- if (is_array($a)) {
- return array_shift($a);
- }
- return false;
- }
-
- function sortHeaders($a, $field, $flag)
- {
- if (empty($field)) {
- $field = 'uid';
- }
- else {
- $field = strtolower($field);
- }
-
- if ($field == 'date' || $field == 'internaldate') {
- $field = 'timestamp';
- }
-
- if (empty($flag)) {
- $flag = 'ASC';
- } else {
- $flag = strtoupper($flag);
- }
-
- $c = count($a);
- if ($c > 0) {
- // Strategy:
- // First, we'll create an "index" array.
- // Then, we'll use sort() on that array,
- // and use that to sort the main array.
-
- // create "index" array
- $index = array();
- reset($a);
- while (list($key, $val) = each($a)) {
- if ($field == 'timestamp') {
- $data = $this->strToTime($val->date);
- if (!$data) {
- $data = $val->timestamp;
- }
- } else {
- $data = $val->$field;
- if (is_string($data)) {
- $data = str_replace('"', '', $data);
- if ($field == 'subject') {
- $data = preg_replace('/^(Re: \s*|Fwd:\s*|Fw:\s*)+/i', '', $data);
- }
- $data = strtoupper($data);
- }
- }
- $index[$key] = $data;
- }
-
- // sort index
- if ($flag == 'ASC') {
- asort($index);
- } else {
- arsort($index);
- }
-
- // form new array based on index
- $result = array();
- reset($index);
- while (list($key, $val) = each($index)) {
- $result[$key] = $a[$key];
- }
- }
-
- return $result;
- }
-
- function fetchMIMEHeaders($mailbox, $uid, $parts, $mime=true)
- {
- if (!$this->select($mailbox)) {
- return false;
- }
-
- $result = false;
- $parts = (array) $parts;
- $key = $this->nextTag();
- $peeks = array();
- $type = $mime ? 'MIME' : 'HEADER';
-
- // format request
- foreach ($parts as $part) {
- $peeks[] = "BODY.PEEK[$part.$type]";
- }
-
- $request = "$key UID FETCH $uid (" . implode(' ', $peeks) . ')';
-
- // send request
- if (!$this->putLine($request)) {
- $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
- return false;
- }
-
- do {
- $line = $this->readLine(1024);
-
- 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));
-
- return $result;
- }
-
- function fetchPartHeader($mailbox, $id, $is_uid=false, $part=NULL)
- {
- $part = empty($part) ? 'HEADER' : $part.'.MIME';
-
- return $this->handlePartBody($mailbox, $id, $is_uid, $part);
- }
-
- function handlePartBody($mailbox, $id, $is_uid=false, $part='', $encoding=NULL, $print=NULL, $file=NULL, $formatted=false, $max_bytes=0)
- {
- if (!$this->select($mailbox)) {
- return false;
- }
-
- $binary = true;
-
- do {
- if (!$initiated) {
- switch ($encoding) {
- case 'base64':
- $mode = 1;
- break;
- case 'quoted-printable':
- $mode = 2;
- break;
- case 'x-uuencode':
- case 'x-uue':
- case 'uue':
- case 'uuencode':
- $mode = 3;
- break;
- default:
- $mode = 0;
- }
-
- // Use BINARY extension when possible (and safe)
- $binary = $binary && $mode && preg_match('/^[0-9.]+$/', $part) && $this->hasCapability('BINARY');
- $fetch_mode = $binary ? 'BINARY' : 'BODY';
- $partial = $max_bytes ? sprintf('<0.%d>', $max_bytes) : '';
-
- // format request
- $key = $this->nextTag();
- $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id ($fetch_mode.PEEK[$part]$partial)";
- $result = false;
- $found = false;
- $initiated = true;
-
- // send request
- if (!$this->putLine($request)) {
- $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
- return false;
- }
-
- if ($binary) {
- // WARNING: Use $formatted argument with care, this may break binary data stream
- $mode = -1;
- }
- }
-
- $line = trim($this->readLine(1024));
-
- if (!$line) {
- break;
- }
-
- // handle UNKNOWN-CTE response - RFC 3516, try again with standard BODY request
- if ($binary && !$found && preg_match('/^' . $key . ' NO \[UNKNOWN-CTE\]/i', $line)) {
- $binary = $initiated = false;
- continue;
- }
-
- // skip irrelevant untagged responses (we have a result already)
- if ($found || !preg_match('/^\* ([0-9]+) FETCH (.*)$/', $line, $m)) {
- continue;
- }
-
- $line = $m[2];
-
- // handle one line response
- if ($line[0] == '(' && substr($line, -1) == ')') {
- // tokenize content inside brackets
- // the content can be e.g.: (UID 9844 BODY[2.4] NIL)
- $tokens = $this->tokenizeResponse(preg_replace('/(^\(|\)$)/', '', $line));
-
- for ($i=0; $i<count($tokens); $i+=2) {
- if (preg_match('/^(BODY|BINARY)/i', $tokens[$i])) {
- $result = $tokens[$i+1];
- $found = true;
- break;
- }
- }
-
- if ($result !== false) {
- if ($mode == 1) {
- $result = base64_decode($result);
- }
- else if ($mode == 2) {
- $result = quoted_printable_decode($result);
- }
- else if ($mode == 3) {
- $result = convert_uudecode($result);
- }
- }
- }
- // response with string literal
- else if (preg_match('/\{([0-9]+)\}$/', $line, $m)) {
- $bytes = (int) $m[1];
- $prev = '';
- $found = true;
-
- // empty body
- if (!$bytes) {
- $result = '';
- }
- else while ($bytes > 0) {
- $line = $this->readLine(8192);
-
- if ($line === NULL) {
- break;
- }
-
- $len = strlen($line);
-
- if ($len > $bytes) {
- $line = substr($line, 0, $bytes);
- $len = strlen($line);
- }
- $bytes -= $len;
-
- // BASE64
- if ($mode == 1) {
- $line = preg_replace('|[^a-zA-Z0-9+=/]|', '', $line);
- // create chunks with proper length for base64 decoding
- $line = $prev.$line;
- $length = strlen($line);
- if ($length % 4) {
- $length = floor($length / 4) * 4;
- $prev = substr($line, $length);
- $line = substr($line, 0, $length);
- }
- else {
- $prev = '';
- }
- $line = base64_decode($line);
- }
- // QUOTED-PRINTABLE
- else if ($mode == 2) {
- $line = rtrim($line, "\t\r\0\x0B");
- $line = quoted_printable_decode($line);
- }
- // UUENCODE
- else if ($mode == 3) {
- $line = rtrim($line, "\t\r\n\0\x0B");
- if ($line == 'end' || preg_match('/^begin\s+[0-7]+\s+.+$/', $line)) {
- continue;
- }
- $line = convert_uudecode($line);
- }
- // default
- else if ($formatted) {
- $line = rtrim($line, "\t\r\n\0\x0B") . "\n";
- }
-
- if ($file) {
- if (fwrite($file, $line) === false) {
- break;
- }
- }
- else if ($print) {
- echo $line;
- }
- else {
- $result .= $line;
- }
- }
- }
- } while (!$this->startsWith($line, $key, true) || !$initiated);
-
- if ($result !== false) {
- if ($file) {
- return fwrite($file, $result);
- }
- else if ($print) {
- echo $result;
- return true;
- }
-
- return $result;
- }
-
- return false;
- }
-
- /**
- * Handler for IMAP APPEND command
- *
- * @param string $mailbox Mailbox name
- * @param string|array $message The message source string or array (of strings and file pointers)
- * @param array $flags Message flags
- * @param string $date Message internal date
- * @param bool $binary Enable BINARY append (RFC3516)
- *
- * @return string|bool On success APPENDUID response (if available) or True, False on failure
- */
- function append($mailbox, &$message, $flags = array(), $date = null, $binary = false)
- {
- unset($this->data['APPENDUID']);
-
- if ($mailbox === null || $mailbox === '') {
- return false;
- }
-
- $binary = $binary && $this->getCapability('BINARY');
- $literal_plus = !$binary && $this->prefs['literal+'];
- $len = 0;
- $msg = is_array($message) ? $message : array(&$message);
- $chunk_size = 512000;
-
- for ($i=0, $cnt=count($msg); $i<$cnt; $i++) {
- if (is_resource($msg[$i])) {
- $stat = fstat($msg[$i]);
- if ($stat === false) {
- return false;
- }
- $len += $stat['size'];
- }
- else {
- if (!$binary) {
- $msg[$i] = str_replace("\r", '', $msg[$i]);
- $msg[$i] = str_replace("\n", "\r\n", $msg[$i]);
- }
-
- $len += strlen($msg[$i]);
- }
- }
-
- if (!$len) {
- return false;
- }
-
- // build APPEND command
- $key = $this->nextTag();
- $request = "$key APPEND " . $this->escape($mailbox) . ' (' . $this->flagsToStr($flags) . ')';
- if (!empty($date)) {
- $request .= ' ' . $this->escape($date);
- }
- $request .= ' ' . ($binary ? '~' : '') . '{' . $len . ($literal_plus ? '+' : '') . '}';
-
- // send APPEND command
- if ($this->putLine($request)) {
- // Do not wait when LITERAL+ is supported
- if (!$literal_plus) {
- $line = $this->readReply();
-
- if ($line[0] != '+') {
- $this->parseResult($line, 'APPEND: ');
- return false;
- }
- }
-
- foreach ($msg as $msg_part) {
- // file pointer
- if (is_resource($msg_part)) {
- rewind($msg_part);
- while (!feof($msg_part) && $this->fp) {
- $buffer = fread($msg_part, $chunk_size);
- $this->putLine($buffer, false);
- }
- fclose($msg_part);
- }
- // string
- else {
- $size = strlen($msg_part);
-
- // Break up the data by sending one chunk (up to 512k) at a time.
- // This approach reduces our peak memory usage
- for ($offset = 0; $offset < $size; $offset += $chunk_size) {
- $chunk = substr($msg_part, $offset, $chunk_size);
- if (!$this->putLine($chunk, false)) {
- return false;
- }
- }
- }
- }
-
- if (!$this->putLine('')) { // \r\n
- return false;
- }
-
- do {
- $line = $this->readLine();
- } while (!$this->startsWith($line, $key, true, true));
-
- // Clear internal status cache
- unset($this->data['STATUS:'.$mailbox]);
-
- if ($this->parseResult($line, 'APPEND: ') != self::ERROR_OK)
- return false;
- else if (!empty($this->data['APPENDUID']))
- return $this->data['APPENDUID'];
- else
- return true;
- }
- else {
- $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
- }
-
- return false;
- }
-
- /**
- * 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
- * @param array $flags Message flags
- * @param string $date Message internal date
- * @param bool $binary Enable BINARY append (RFC3516)
- *
- * @return string|bool On success APPENDUID response (if available) or True, False on failure
- */
- function appendFromFile($mailbox, $path, $headers=null, $flags = array(), $date = null, $binary = false)
- {
- // open message file
- if (file_exists(realpath($path))) {
- $fp = fopen($path, 'r');
- }
-
- if (!$fp) {
- $this->setError(self::ERROR_UNKNOWN, "Couldn't open $path for reading");
- return false;
- }
-
- $message = array();
- if ($headers) {
- $message[] = trim($headers, "\r\n") . "\r\n\r\n";
- }
- $message[] = $fp;
-
- return $this->append($mailbox, $message, $flags, $date, $binary);
- }
-
- /**
- * Returns QUOTA information
- *
- * @param string $mailbox Mailbox name
- *
- * @return array Quota information
- */
- function getQuota($mailbox = null)
- {
- if ($mailbox === null || $mailbox === '') {
- $mailbox = 'INBOX';
- }
-
- // a0001 GETQUOTAROOT INBOX
- // * QUOTAROOT INBOX user/sample
- // * QUOTA user/sample (STORAGE 654 9765)
- // a0001 OK Completed
-
- list($code, $response) = $this->execute('GETQUOTAROOT', array($this->escape($mailbox)));
-
- $result = false;
- $min_free = PHP_INT_MAX;
- $all = array();
-
- if ($code == self::ERROR_OK) {
- foreach (explode("\n", $response) as $line) {
- if (preg_match('/^\* QUOTA /', $line)) {
- list(, , $quota_root) = $this->tokenizeResponse($line, 3);
-
- while ($line) {
- list($type, $used, $total) = $this->tokenizeResponse($line, 1);
- $type = strtolower($type);
-
- if ($type && $total) {
- $all[$quota_root][$type]['used'] = intval($used);
- $all[$quota_root][$type]['total'] = intval($total);
- }
- }
-
- if (empty($all[$quota_root]['storage'])) {
- continue;
- }
-
- $used = $all[$quota_root]['storage']['used'];
- $total = $all[$quota_root]['storage']['total'];
- $free = $total - $used;
-
- // calculate lowest available space from all storage quotas
- if ($free < $min_free) {
- $min_free = $free;
- $result['used'] = $used;
- $result['total'] = $total;
- $result['percent'] = min(100, round(($used/max(1,$total))*100));
- $result['free'] = 100 - $result['percent'];
- }
- }
- }
- }
-
- if (!empty($result)) {
- $result['all'] = $all;
- }
-
- return $result;
- }
-
- /**
- * Send the SETACL command (RFC4314)
- *
- * @param string $mailbox Mailbox name
- * @param string $user User name
- * @param mixed $acl ACL string or array
- *
- * @return boolean True on success, False on failure
- *
- * @since 0.5-beta
- */
- function setACL($mailbox, $user, $acl)
- {
- if (is_array($acl)) {
- $acl = implode('', $acl);
- }
-
- $result = $this->execute('SETACL', array(
- $this->escape($mailbox), $this->escape($user), strtolower($acl)),
- self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- /**
- * Send the DELETEACL command (RFC4314)
- *
- * @param string $mailbox Mailbox name
- * @param string $user User name
- *
- * @return boolean True on success, False on failure
- *
- * @since 0.5-beta
- */
- function deleteACL($mailbox, $user)
- {
- $result = $this->execute('DELETEACL', array(
- $this->escape($mailbox), $this->escape($user)),
- self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- /**
- * Send the GETACL command (RFC4314)
- *
- * @param string $mailbox Mailbox name
- *
- * @return array User-rights array on success, NULL on error
- * @since 0.5-beta
- */
- function getACL($mailbox)
- {
- list($code, $response) = $this->execute('GETACL', array($this->escape($mailbox)));
-
- if ($code == self::ERROR_OK && preg_match('/^\* ACL /i', $response)) {
- // Parse server response (remove "* ACL ")
- $response = substr($response, 6);
- $ret = $this->tokenizeResponse($response);
- $mbox = array_shift($ret);
- $size = count($ret);
-
- // Create user-rights hash array
- // @TODO: consider implementing fixACL() method according to RFC4314.2.1.1
- // so we could return only standard rights defined in RFC4314,
- // excluding 'c' and 'd' defined in RFC2086.
- if ($size % 2 == 0) {
- for ($i=0; $i<$size; $i++) {
- $ret[$ret[$i]] = str_split($ret[++$i]);
- unset($ret[$i-1]);
- unset($ret[$i]);
- }
- return $ret;
- }
-
- $this->setError(self::ERROR_COMMAND, "Incomplete ACL response");
- return NULL;
- }
-
- return NULL;
- }
-
- /**
- * Send the LISTRIGHTS command (RFC4314)
- *
- * @param string $mailbox Mailbox name
- * @param string $user User name
- *
- * @return array List of user rights
- * @since 0.5-beta
- */
- function listRights($mailbox, $user)
- {
- list($code, $response) = $this->execute('LISTRIGHTS', array(
- $this->escape($mailbox), $this->escape($user)));
-
- if ($code == self::ERROR_OK && preg_match('/^\* LISTRIGHTS /i', $response)) {
- // Parse server response (remove "* LISTRIGHTS ")
- $response = substr($response, 13);
-
- $ret_mbox = $this->tokenizeResponse($response, 1);
- $ret_user = $this->tokenizeResponse($response, 1);
- $granted = $this->tokenizeResponse($response, 1);
- $optional = trim($response);
-
- return array(
- 'granted' => str_split($granted),
- 'optional' => explode(' ', $optional),
- );
- }
-
- return NULL;
- }
-
- /**
- * Send the MYRIGHTS command (RFC4314)
- *
- * @param string $mailbox Mailbox name
- *
- * @return array MYRIGHTS response on success, NULL on error
- * @since 0.5-beta
- */
- function myRights($mailbox)
- {
- list($code, $response) = $this->execute('MYRIGHTS', array($this->escape($mailbox)));
-
- if ($code == self::ERROR_OK && preg_match('/^\* MYRIGHTS /i', $response)) {
- // Parse server response (remove "* MYRIGHTS ")
- $response = substr($response, 11);
-
- $ret_mbox = $this->tokenizeResponse($response, 1);
- $rights = $this->tokenizeResponse($response, 1);
-
- return str_split($rights);
- }
-
- return NULL;
- }
-
- /**
- * Send the SETMETADATA command (RFC5464)
- *
- * @param string $mailbox Mailbox name
- * @param array $entries Entry-value array (use NULL value as NIL)
- *
- * @return boolean True on success, False on failure
- * @since 0.5-beta
- */
- function setMetadata($mailbox, $entries)
- {
- if (!is_array($entries) || empty($entries)) {
- $this->setError(self::ERROR_COMMAND, "Wrong argument for SETMETADATA command");
- return false;
- }
-
- foreach ($entries as $name => $value) {
- $entries[$name] = $this->escape($name) . ' ' . $this->escape($value, true);
- }
-
- $entries = implode(' ', $entries);
- $result = $this->execute('SETMETADATA', array(
- $this->escape($mailbox), '(' . $entries . ')'),
- self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- /**
- * Send the SETMETADATA command with NIL values (RFC5464)
- *
- * @param string $mailbox Mailbox name
- * @param array $entries Entry names array
- *
- * @return boolean True on success, False on failure
- *
- * @since 0.5-beta
- */
- function deleteMetadata($mailbox, $entries)
- {
- if (!is_array($entries) && !empty($entries)) {
- $entries = explode(' ', $entries);
- }
-
- if (empty($entries)) {
- $this->setError(self::ERROR_COMMAND, "Wrong argument for SETMETADATA command");
- return false;
- }
-
- foreach ($entries as $entry) {
- $data[$entry] = NULL;
- }
-
- return $this->setMetadata($mailbox, $data);
- }
-
- /**
- * Send the GETMETADATA command (RFC5464)
- *
- * @param string $mailbox Mailbox name
- * @param array $entries Entries
- * @param array $options Command options (with MAXSIZE and DEPTH keys)
- *
- * @return array GETMETADATA result on success, NULL on error
- *
- * @since 0.5-beta
- */
- function getMetadata($mailbox, $entries, $options=array())
- {
- if (!is_array($entries)) {
- $entries = array($entries);
- }
-
- // create entries string
- foreach ($entries as $idx => $name) {
- $entries[$idx] = $this->escape($name);
- }
-
- $optlist = '';
- $entlist = '(' . implode(' ', $entries) . ')';
-
- // create options string
- if (is_array($options)) {
- $options = array_change_key_case($options, CASE_UPPER);
- $opts = array();
-
- if (!empty($options['MAXSIZE'])) {
- $opts[] = 'MAXSIZE '.intval($options['MAXSIZE']);
- }
- if (!empty($options['DEPTH'])) {
- $opts[] = 'DEPTH '.intval($options['DEPTH']);
- }
-
- if ($opts) {
- $optlist = '(' . implode(' ', $opts) . ')';
- }
- }
-
- $optlist .= ($optlist ? ' ' : '') . $entlist;
-
- list($code, $response) = $this->execute('GETMETADATA', array(
- $this->escape($mailbox), $optlist));
-
- if ($code == self::ERROR_OK) {
- $result = array();
- $data = $this->tokenizeResponse($response);
-
- // The METADATA response can contain multiple entries in a single
- // response or multiple responses for each entry or group of entries
- if (!empty($data) && ($size = count($data))) {
- for ($i=0; $i<$size; $i++) {
- if (isset($mbox) && is_array($data[$i])) {
- $size_sub = count($data[$i]);
- for ($x=0; $x<$size_sub; $x+=2) {
- if ($data[$i][$x+1] !== null)
- $result[$mbox][$data[$i][$x]] = $data[$i][$x+1];
- }
- unset($data[$i]);
- }
- else if ($data[$i] == '*') {
- if ($data[$i+1] == 'METADATA') {
- $mbox = $data[$i+2];
- unset($data[$i]); // "*"
- unset($data[++$i]); // "METADATA"
- unset($data[++$i]); // Mailbox
- }
- // get rid of other untagged responses
- else {
- unset($mbox);
- unset($data[$i]);
- }
- }
- else if (isset($mbox)) {
- if ($data[++$i] !== null)
- $result[$mbox][$data[$i-1]] = $data[$i];
- unset($data[$i]);
- unset($data[$i-1]);
- }
- else {
- unset($data[$i]);
- }
- }
- }
-
- return $result;
- }
-
- return NULL;
- }
-
- /**
- * Send the SETANNOTATION command (draft-daboo-imap-annotatemore)
- *
- * @param string $mailbox Mailbox name
- * @param array $data Data array where each item is an array with
- * three elements: entry name, attribute name, value
- *
- * @return boolean True on success, False on failure
- * @since 0.5-beta
- */
- function setAnnotation($mailbox, $data)
- {
- if (!is_array($data) || empty($data)) {
- $this->setError(self::ERROR_COMMAND, "Wrong argument for SETANNOTATION command");
- return false;
- }
-
- foreach ($data as $entry) {
- // Workaround cyrus-murder bug, the entry[2] string needs to be escaped
- if (self::$mupdate) {
- $entry[2] = addcslashes($entry[2], '\\"');
- }
-
- // ANNOTATEMORE drafts before version 08 require quoted parameters
- $entries[] = sprintf('%s (%s %s)', $this->escape($entry[0], true),
- $this->escape($entry[1], true), $this->escape($entry[2], true));
- }
-
- $entries = implode(' ', $entries);
- $result = $this->execute('SETANNOTATION', array(
- $this->escape($mailbox), $entries), self::COMMAND_NORESPONSE);
-
- return ($result == self::ERROR_OK);
- }
-
- /**
- * Send the SETANNOTATION command with NIL values (draft-daboo-imap-annotatemore)
- *
- * @param string $mailbox Mailbox name
- * @param array $data Data array where each item is an array with
- * two elements: entry name and attribute name
- *
- * @return boolean True on success, False on failure
- *
- * @since 0.5-beta
- */
- function deleteAnnotation($mailbox, $data)
- {
- if (!is_array($data) || empty($data)) {
- $this->setError(self::ERROR_COMMAND, "Wrong argument for SETANNOTATION command");
- return false;
- }
-
- return $this->setAnnotation($mailbox, $data);
- }
-
- /**
- * Send the GETANNOTATION command (draft-daboo-imap-annotatemore)
- *
- * @param string $mailbox Mailbox name
- * @param array $entries Entries names
- * @param array $attribs Attribs names
- *
- * @return array Annotations result on success, NULL on error
- *
- * @since 0.5-beta
- */
- function getAnnotation($mailbox, $entries, $attribs)
- {
- if (!is_array($entries)) {
- $entries = array($entries);
- }
- // create entries string
- // ANNOTATEMORE drafts before version 08 require quoted parameters
- foreach ($entries as $idx => $name) {
- $entries[$idx] = $this->escape($name, true);
- }
- $entries = '(' . implode(' ', $entries) . ')';
-
- if (!is_array($attribs)) {
- $attribs = array($attribs);
- }
- // create entries string
- foreach ($attribs as $idx => $name) {
- $attribs[$idx] = $this->escape($name, true);
- }
- $attribs = '(' . implode(' ', $attribs) . ')';
-
- list($code, $response) = $this->execute('GETANNOTATION', array(
- $this->escape($mailbox), $entries, $attribs));
-
- if ($code == self::ERROR_OK) {
- $result = array();
- $data = $this->tokenizeResponse($response);
-
- // Here we returns only data compatible with METADATA result format
- if (!empty($data) && ($size = count($data))) {
- for ($i=0; $i<$size; $i++) {
- $entry = $data[$i];
- if (isset($mbox) && is_array($entry)) {
- $attribs = $entry;
- $entry = $last_entry;
- }
- else if ($entry == '*') {
- if ($data[$i+1] == 'ANNOTATION') {
- $mbox = $data[$i+2];
- unset($data[$i]); // "*"
- unset($data[++$i]); // "ANNOTATION"
- unset($data[++$i]); // Mailbox
- }
- // get rid of other untagged responses
- else {
- unset($mbox);
- unset($data[$i]);
- }
- continue;
- }
- else if (isset($mbox)) {
- $attribs = $data[++$i];
- }
- else {
- unset($data[$i]);
- continue;
- }
-
- if (!empty($attribs)) {
- for ($x=0, $len=count($attribs); $x<$len;) {
- $attr = $attribs[$x++];
- $value = $attribs[$x++];
- if ($attr == 'value.priv' && $value !== null) {
- $result[$mbox]['/private' . $entry] = $value;
- }
- else if ($attr == 'value.shared' && $value !== null) {
- $result[$mbox]['/shared' . $entry] = $value;
- }
- }
- }
- $last_entry = $entry;
- unset($data[$i]);
- }
- }
-
- return $result;
- }
-
- 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 (empty($part)) {
- return $a;
- }
-
- $ctype = is_string($a[0]) && is_string($a[1]) ? $a[0] . '/' . $a[1] : '';
-
- if (strcasecmp($ctype, 'message/rfc822') == 0) {
- $a = $a[8];
- }
-
- if (strpos($part, '.') > 0) {
- $orig_part = $part;
- $pos = strpos($part, '.');
- $rest = substr($orig_part, $pos+1);
- $part = substr($orig_part, 0, $pos);
-
- return self::getStructurePartArray($a[$part-1], $rest);
- }
- else if ($part > 0) {
- return (is_array($a[$part-1])) ? $a[$part-1] : $a;
- }
- }
-
- /**
- * Creates next command identifier (tag)
- *
- * @return string Command identifier
- * @since 0.5-beta
- */
- function nextTag()
- {
- $this->cmd_num++;
- $this->cmd_tag = sprintf('A%04d', $this->cmd_num);
-
- return $this->cmd_tag;
- }
-
- /**
- * Sends IMAP command and parses result
- *
- * @param string $command IMAP command
- * @param array $arguments Command arguments
- * @param int $options Execution options
- *
- * @return mixed Response code or list of response code and data
- * @since 0.5-beta
- */
- function execute($command, $arguments=array(), $options=0)
- {
- $tag = $this->nextTag();
- $query = $tag . ' ' . $command;
- $noresp = ($options & self::COMMAND_NORESPONSE);
- $response = $noresp ? null : '';
-
- if (!empty($arguments)) {
- foreach ($arguments as $arg) {
- $query .= ' ' . self::r_implode($arg);
- }
- }
-
- // Send command
- if (!$this->putLineC($query, true, ($options & self::COMMAND_ANONYMIZED))) {
- $this->setError(self::ERROR_COMMAND, "Unable to send command: $query");
- return $noresp ? self::ERROR_COMMAND : array(self::ERROR_COMMAND, '');
- }
-
- // Parse response
- do {
- $line = $this->readLine(4096);
- if ($response !== null) {
- $response .= $line;
- }
- } while (!$this->startsWith($line, $tag . ' ', true, true));
-
- $code = $this->parseResult($line, $command . ': ');
-
- // Remove last line from response
- if ($response) {
- $line_len = min(strlen($response), strlen($line) + 2);
- $response = substr($response, 0, -$line_len);
- }
-
- // optional CAPABILITY response
- if (($options & self::COMMAND_CAPABILITY) && $code == self::ERROR_OK
- && preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)
- ) {
- $this->parseCapability($matches[1], true);
- }
-
- // return last line only (without command tag, result and response code)
- if ($line && ($options & self::COMMAND_LASTLINE)) {
- $response = preg_replace("/^$tag (OK|NO|BAD|BYE|PREAUTH)?\s*(\[[a-z-]+\])?\s*/i", '', trim($line));
- }
-
- return $noresp ? $code : array($code, $response);
- }
-
- /**
- * Splits IMAP response into string tokens
- *
- * @param string &$str The IMAP's server response
- * @param int $num Number of tokens to return
- *
- * @return mixed Tokens array or string if $num=1
- * @since 0.5-beta
- */
- static function tokenizeResponse(&$str, $num=0)
- {
- $result = array();
-
- while (!$num || count($result) < $num) {
- // remove spaces from the beginning of the string
- $str = ltrim($str);
-
- switch ($str[0]) {
-
- // String literal
- case '{':
- if (($epos = strpos($str, "}\r\n", 1)) == false) {
- // error
- }
- if (!is_numeric(($bytes = substr($str, 1, $epos - 1)))) {
- // error
- }
- $result[] = $bytes ? substr($str, $epos + 3, $bytes) : '';
- // Advance the string
- $str = substr($str, $epos + 3 + $bytes);
- break;
-
- // Quoted string
- case '"':
- $len = strlen($str);
-
- for ($pos=1; $pos<$len; $pos++) {
- if ($str[$pos] == '"') {
- break;
- }
- if ($str[$pos] == "\\") {
- if ($str[$pos + 1] == '"' || $str[$pos + 1] == "\\") {
- $pos++;
- }
- }
- }
- if ($str[$pos] != '"') {
- // error
- }
- // we need to strip slashes for a quoted string
- $result[] = stripslashes(substr($str, 1, $pos - 1));
- $str = substr($str, $pos + 1);
- break;
-
- // Parenthesized list
- case '(':
- $str = substr($str, 1);
- $result[] = self::tokenizeResponse($str);
- break;
- case ')':
- $str = substr($str, 1);
- return $result;
- break;
-
- // String atom, number, astring, NIL, *, %
- default:
- // empty string
- if ($str === '' || $str === null) {
- break 2;
- }
-
- // excluded chars: SP, CTL, ), DEL
- // we do not exclude [ and ] (#1489223)
- if (preg_match('/^([^\x00-\x20\x29\x7F]+)/', $str, $m)) {
- $result[] = $m[1] == 'NIL' ? NULL : $m[1];
- $str = substr($str, strlen($m[1]));
- }
- break;
- }
- }
-
- return $num == 1 ? $result[0] : $result;
- }
-
- static function r_implode($element)
- {
- $string = '';
-
- if (is_array($element)) {
- reset($element);
- foreach ($element as $value) {
- $string .= ' ' . self::r_implode($value);
- }
- }
- else {
- return $element;
- }
-
- return '(' . trim($string) . ')';
- }
-
- /**
- * Converts message identifiers array into sequence-set syntax
- *
- * @param array $messages Message identifiers
- * @param bool $force Forces compression of any size
- *
- * @return string Compressed sequence-set
- */
- static function compressMessageSet($messages, $force=false)
- {
- // given a comma delimited list of independent mid's,
- // compresses by grouping sequences together
-
- if (!is_array($messages)) {
- // if less than 255 bytes long, let's not bother
- if (!$force && strlen($messages)<255) {
- return $messages;
- }
-
- // see if it's already been compressed
- if (strpos($messages, ':') !== false) {
- return $messages;
- }
-
- // separate, then sort
- $messages = explode(',', $messages);
- }
-
- sort($messages);
-
- $result = array();
- $start = $prev = $messages[0];
-
- foreach ($messages as $id) {
- $incr = $id - $prev;
- if ($incr > 1) { // found a gap
- if ($start == $prev) {
- $result[] = $prev; // push single id
- } else {
- $result[] = $start . ':' . $prev; // push sequence as start_id:end_id
- }
- $start = $id; // start of new sequence
- }
- $prev = $id;
- }
-
- // handle the last sequence/id
- if ($start == $prev) {
- $result[] = $prev;
- } else {
- $result[] = $start.':'.$prev;
- }
-
- // return as comma separated string
- return implode(',', $result);
- }
-
- /**
- * Converts message sequence-set into array
- *
- * @param string $messages Message identifiers
- *
- * @return array List of message identifiers
- */
- static function uncompressMessageSet($messages)
- {
- if (empty($messages)) {
- return array();
- }
-
- $result = array();
- $messages = explode(',', $messages);
-
- foreach ($messages as $idx => $part) {
- $items = explode(':', $part);
- $max = max($items[0], $items[1]);
-
- for ($x=$items[0]; $x<=$max; $x++) {
- $result[] = (int)$x;
- }
- unset($messages[$idx]);
- }
-
- return $result;
- }
-
- protected function _xor($string, $string2)
- {
- $result = '';
- $size = strlen($string);
-
- for ($i=0; $i<$size; $i++) {
- $result .= chr(ord($string[$i]) ^ ord($string2[$i]));
- }
-
- return $result;
- }
-
- /**
- * Converts flags array into string for inclusion in IMAP command
- *
- * @param array $flags Flags (see self::flags)
- *
- * @return string Space-separated list of flags
- */
- protected function flagsToStr($flags)
- {
- foreach ((array)$flags as $idx => $flag) {
- if ($flag = $this->flags[strtoupper($flag)]) {
- $flags[$idx] = $flag;
- }
- }
-
- return implode(' ', (array)$flags);
- }
-
- /**
- * Converts datetime string into unix timestamp
- *
- * @param string $date Date string
- *
- * @return int Unix timestamp
- */
- static function strToTime($date)
- {
- // Clean malformed data
- $date = preg_replace(
- array(
- '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal
- '/[^a-z0-9\x20\x09:+-]/i', // remove any invalid characters
- '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names
- ),
- array(
- '\\1',
- '',
- '',
- ), $date);
-
- $date = trim($date);
-
- // if date parsing fails, we have a date in non-rfc format
- // remove token from the end and try again
- while (($ts = intval(@strtotime($date))) <= 0) {
- $d = explode(' ', $date);
- array_pop($d);
- if (empty($d)) {
- break;
- }
- $date = implode(' ', $d);
- }
-
- return $ts < 0 ? 0 : $ts;
- }
-
- /**
- * CAPABILITY response parser
- */
- protected function parseCapability($str, $trusted=false)
- {
- $str = preg_replace('/^\* CAPABILITY /i', '', $str);
-
- $this->capability = explode(' ', strtoupper($str));
-
- if (!empty($this->prefs['disabled_caps'])) {
- $this->capability = array_diff($this->capability, $this->prefs['disabled_caps']);
- }
-
- if (!isset($this->prefs['literal+']) && in_array('LITERAL+', $this->capability)) {
- $this->prefs['literal+'] = true;
- }
-
- if (preg_match('/(\[| )MUPDATE=.*/', $str)) {
- self::$mupdate = true;
- }
-
- if ($trusted) {
- $this->capability_readed = true;
- }
- }
-
- /**
- * Escapes a string when it contains special characters (RFC3501)
- *
- * @param string $string IMAP string
- * @param boolean $force_quotes Forces string quoting (for atoms)
- *
- * @return string String atom, quoted-string or string literal
- * @todo lists
- */
- static function escape($string, $force_quotes=false)
- {
- if ($string === null) {
- return 'NIL';
- }
-
- if ($string === '') {
- return '""';
- }
-
- // atom-string (only safe characters)
- if (!$force_quotes && !preg_match('/[\x00-\x20\x22\x25\x28-\x2A\x5B-\x5D\x7B\x7D\x80-\xFF]/', $string)) {
- return $string;
- }
-
- // quoted-string
- if (!preg_match('/[\r\n\x00\x80-\xFF]/', $string)) {
- return '"' . addcslashes($string, '\\"') . '"';
- }
-
- // literal-string
- return sprintf("{%d}\r\n%s", strlen($string), $string);
- }
-
- /**
- * Set the value of the debugging flag.
- *
- * @param boolean $debug New value for the debugging flag.
- * @param callback $handler Logging handler function
- *
- * @since 0.5-stable
- */
- function setDebug($debug, $handler = null)
- {
- $this->_debug = $debug;
- $this->_debug_handler = $handler;
- }
-
- /**
- * Write the given debug text to the current debug output handler.
- *
- * @param string $message Debug mesage text.
- *
- * @since 0.5-stable
- */
- protected function debug($message)
- {
- if (($len = strlen($message)) > self::DEBUG_LINE_LENGTH) {
- $diff = $len - self::DEBUG_LINE_LENGTH;
- $message = substr($message, 0, self::DEBUG_LINE_LENGTH)
- . "... [truncated $diff bytes]";
- }
-
- if ($this->resourceid) {
- $message = sprintf('[%s] %s', $this->resourceid, $message);
- }
-
- if ($this->_debug_handler) {
- call_user_func_array($this->_debug_handler, array(&$this, $message));
- } else {
- echo "DEBUG: $message\n";
- }
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_imap_search.php b/lib/ext/Roundcube/rcube_imap_search.php
deleted file mode 100644
index 365d78f..0000000
--- a/lib/ext/Roundcube/rcube_imap_search.php
+++ /dev/null
@@ -1,231 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | |
- | Copyright (C) 2013, The Roundcube Dev Team |
- | Copyright (C) 2014, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Execute (multi-threaded) searches in multiple IMAP folders |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class to control search jobs on multiple IMAP folders.
- *
- * @package Framework
- * @subpackage Storage
- * @author Thomas Bruederli <roundcube@gmail.com>
- */
-class rcube_imap_search
-{
- public $options = array();
-
- protected $jobs = array();
- protected $timelimit = 0;
- protected $results;
- protected $conn;
-
- /**
- * Default constructor
- */
- public function __construct($options, $conn)
- {
- $this->options = $options;
- $this->conn = $conn;
- }
-
- /**
- * Invoke search request to IMAP server
- *
- * @param array $folders List of IMAP folders to search in
- * @param string $str Search criteria
- * @param string $charset Search charset
- * @param string $sort_field Header field to sort by
- * @param boolean $threading True if threaded listing is active
- */
- public function exec($folders, $str, $charset = null, $sort_field = null, $threading=null)
- {
- $start = floor(microtime(true));
- $results = new rcube_result_multifolder($folders);
-
- // start a search job for every folder to search in
- foreach ($folders as $folder) {
- // a complete result for this folder already exists
- $result = $this->results ? $this->results->get_set($folder) : false;
- if ($result && !$result->incomplete) {
- $results->add($result);
- }
- else {
- $search = is_array($str) && $str[$folder] ? $str[$folder] : $str;
- $job = new rcube_imap_search_job($folder, $search, $charset, $sort_field, $threading);
- $job->worker = $this;
- $this->jobs[] = $job;
- }
- }
-
- // execute jobs and gather results
- foreach ($this->jobs as $job) {
- // only run search if within the configured time limit
- // TODO: try to estimate the required time based on folder size and previous search performance
- if (!$this->timelimit || floor(microtime(true)) - $start < $this->timelimit) {
- $job->run();
- }
-
- // add result (may have ->incomplete flag set)
- $results->add($job->get_result());
- }
-
- return $results;
- }
-
- /**
- * Setter for timelimt property
- */
- public function set_timelimit($seconds)
- {
- $this->timelimit = $seconds;
- }
-
- /**
- * Setter for previous (potentially incomplete) search results
- */
- public function set_results($res)
- {
- $this->results = $res;
- }
-
- /**
- * Get connection to the IMAP server
- * (used for single-thread mode)
- */
- public function get_imap()
- {
- return $this->conn;
- }
-}
-
-
-/**
- * Stackable item to run the search on a specific IMAP folder
- */
-class rcube_imap_search_job /* extends Stackable */
-{
- private $folder;
- private $search;
- private $charset;
- private $sort_field;
- private $threading;
- private $searchset;
- private $result;
- private $pagesize = 100;
-
- public function __construct($folder, $str, $charset = null, $sort_field = null, $threading=false)
- {
- $this->folder = $folder;
- $this->search = $str;
- $this->charset = $charset;
- $this->sort_field = $sort_field;
- $this->threading = $threading;
-
- $this->result = new rcube_result_index($folder);
- $this->result->incomplete = true;
- }
-
- public function run()
- {
- $this->result = $this->search_index();
- }
-
- /**
- * Copy of rcube_imap::search_index()
- */
- protected function search_index()
- {
- $criteria = $this->search;
- $charset = $this->charset;
- $imap = $this->worker->get_imap();
-
- if (!$imap->connected()) {
- trigger_error("No IMAP connection for $this->folder", E_USER_WARNING);
-
- if ($this->threading) {
- return new rcube_result_thread($this->folder);
- }
- else {
- return new rcube_result_index($this->folder);
- }
- }
-
- if ($this->worker->options['skip_deleted'] && !preg_match('/UNDELETED/', $criteria)) {
- $criteria = 'UNDELETED '.$criteria;
- }
-
- // unset CHARSET if criteria string is ASCII, this way
- // SEARCH won't be re-sent after "unsupported charset" response
- if ($charset && $charset != 'US-ASCII' && is_ascii($criteria)) {
- $charset = 'US-ASCII';
- }
-
- if ($this->threading) {
- $threads = $imap->thread($this->folder, $this->threading, $criteria, true, $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)
- if ($threads->is_error() && $charset && $charset != 'US-ASCII') {
- $threads = $imap->thread($this->folder, $this->threading,
- rcube_imap::convert_criteria($criteria, $charset), true, 'US-ASCII');
- }
-
- return $threads;
- }
-
- if ($this->sort_field) {
- $messages = $imap->sort($this->folder, $this->sort_field, $criteria, true, $charset);
-
- // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8,
- // but I've seen Courier with disabled UTF-8 support)
- if ($messages->is_error() && $charset && $charset != 'US-ASCII') {
- $messages = $imap->sort($this->folder, $this->sort_field,
- rcube_imap::convert_criteria($criteria, $charset), true, 'US-ASCII');
- }
- }
-
- if (!$messages || $messages->is_error()) {
- $messages = $imap->search($this->folder,
- ($charset && $charset != 'US-ASCII' ? "CHARSET $charset " : '') . $criteria, true);
-
- // Error, try with US-ASCII (some servers may support only US-ASCII)
- if ($messages->is_error() && $charset && $charset != 'US-ASCII') {
- $messages = $imap->search($this->folder,
- rcube_imap::convert_criteria($criteria, $charset), true);
- }
- }
-
- return $messages;
- }
-
- public function get_search_set()
- {
- return array(
- $this->search,
- $this->result,
- $this->charset,
- $this->sort_field,
- $this->threading,
- );
- }
-
- public function get_result()
- {
- return $this->result;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_ldap.php b/lib/ext/Roundcube/rcube_ldap.php
deleted file mode 100644
index 6805c49..0000000
--- a/lib/ext/Roundcube/rcube_ldap.php
+++ /dev/null
@@ -1,2061 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2006-2013, The Roundcube Dev Team |
- | Copyright (C) 2011-2013, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Interface to an LDAP address directory |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Andreas Dick <andudi (at) gmx (dot) ch> |
- | Aleksander Machniak <machniak@kolabsys.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Model class to access an LDAP address directory
- *
- * @package Framework
- * @subpackage Addressbook
- */
-class rcube_ldap extends rcube_addressbook
-{
- // public properties
- public $primary_key = 'ID';
- public $groups = false;
- public $readonly = true;
- public $ready = false;
- public $group_id = 0;
- public $coltypes = array();
- public $export_groups = false;
-
- // private properties
- protected $ldap;
- protected $prop = array();
- protected $fieldmap = array();
- protected $filter = '';
- protected $sub_filter;
- protected $result;
- protected $ldap_result;
- protected $mail_domain = '';
- protected $debug = false;
-
- /**
- * Group objectclass (lowercase) to member attribute mapping
- *
- * @var array
- */
- private $group_types = array(
- 'group' => 'member',
- 'groupofnames' => 'member',
- 'kolabgroupofnames' => 'member',
- 'groupofuniquenames' => 'uniqueMember',
- 'kolabgroupofuniquenames' => 'uniqueMember',
- 'univentiongroup' => 'uniqueMember',
- 'groupofurls' => null,
- );
-
- private $base_dn = '';
- private $groups_base_dn = '';
- private $group_url;
- private $group_data;
- private $group_search_cache;
- private $cache;
-
-
- /**
- * Object constructor
- *
- * @param array $p LDAP connection properties
- * @param boolean $debug Enables debug mode
- * @param string $mail_domain Current user mail domain name
- */
- function __construct($p, $debug = false, $mail_domain = null)
- {
- $this->prop = $p;
-
- $fetch_attributes = array('objectClass');
-
- // check if groups are configured
- if (is_array($p['groups']) && count($p['groups'])) {
- $this->groups = true;
- // set member field
- if (!empty($p['groups']['member_attr']))
- $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';
- // extend group objectclass => member attribute mapping
- if (!empty($this->prop['groups']['class_member_attr']))
- $this->group_types = array_merge($this->group_types, $this->prop['groups']['class_member_attr']);
-
- // add group name attrib to the list of attributes to be fetched
- $fetch_attributes[] = $this->prop['groups']['name_attr'];
- }
- if (is_array($p['group_filters'])) {
- $this->groups = $this->groups || count($p['group_filters']);
-
- foreach ($p['group_filters'] as $k => $group_filter) {
- // set default name attribute to cn
- if (empty($group_filter['name_attr']) && empty($this->prop['groups']['name_attr']))
- $this->prop['group_filters'][$k]['name_attr'] = $group_filter['name_attr'] = 'cn';
-
- if ($group_filter['name_attr'])
- $fetch_attributes[] = $group_filter['name_attr'];
- }
- }
-
- // fieldmap property is given
- if (is_array($p['fieldmap'])) {
- foreach ($p['fieldmap'] as $rf => $lf)
- $this->fieldmap[$rf] = $this->_attr_name(strtolower($lf));
- }
- else if (!empty($p)) {
- // read deprecated *_field properties to remain backwards compatible
- foreach ($p as $prop => $value)
- if (preg_match('/^(.+)_field$/', $prop, $matches))
- $this->fieldmap[$matches[1]] = $this->_attr_name(strtolower($value));
- }
-
- // use fieldmap to advertise supported coltypes to the application
- foreach ($this->fieldmap as $colv => $lfv) {
- list($col, $type) = explode(':', $colv);
- list($lf, $limit, $delim) = explode(':', $lfv);
-
- if ($limit == '*') $limit = null;
- else $limit = max(1, intval($limit));
-
- if (!is_array($this->coltypes[$col])) {
- $subtypes = $type ? array($type) : null;
- $this->coltypes[$col] = array('limit' => $limit, 'subtypes' => $subtypes, 'attributes' => array($lf));
- }
- elseif ($type) {
- $this->coltypes[$col]['subtypes'][] = $type;
- $this->coltypes[$col]['attributes'][] = $lf;
- $this->coltypes[$col]['limit'] += $limit;
- }
-
- if ($delim)
- $this->coltypes[$col]['serialized'][$type] = $delim;
-
- $this->fieldmap[$colv] = $lf;
- }
-
- // support for composite address
- if ($this->coltypes['street'] && $this->coltypes['locality']) {
- $this->coltypes['address'] = array(
- 'limit' => max(1, $this->coltypes['locality']['limit'] + $this->coltypes['address']['limit']),
- 'subtypes' => array_merge((array)$this->coltypes['address']['subtypes'], (array)$this->coltypes['locality']['subtypes']),
- 'childs' => array(),
- ) + (array)$this->coltypes['address'];
-
- foreach (array('street','locality','zipcode','region','country') as $childcol) {
- if ($this->coltypes[$childcol]) {
- $this->coltypes['address']['childs'][$childcol] = array('type' => 'text');
- unset($this->coltypes[$childcol]); // remove address child col from global coltypes list
- }
- }
-
- // at least one address type must be specified
- if (empty($this->coltypes['address']['subtypes'])) {
- $this->coltypes['address']['subtypes'] = array('home');
- }
- }
- else if ($this->coltypes['address']) {
- $this->coltypes['address'] += array('type' => 'textarea', 'childs' => null, 'size' => 40);
-
- // 'serialized' means the UI has to present a composite address field
- if ($this->coltypes['address']['serialized']) {
- $childprop = array('type' => 'text');
- $this->coltypes['address']['type'] = 'composite';
- $this->coltypes['address']['childs'] = array('street' => $childprop, 'locality' => $childprop, 'zipcode' => $childprop, 'country' => $childprop);
- }
- }
-
- // make sure 'required_fields' is an array
- if (!is_array($this->prop['required_fields'])) {
- $this->prop['required_fields'] = (array) $this->prop['required_fields'];
- }
-
- // make sure LDAP_rdn field is required
- if (!empty($this->prop['LDAP_rdn']) && !in_array($this->prop['LDAP_rdn'], $this->prop['required_fields'])
- && !in_array($this->prop['LDAP_rdn'], array_keys((array)$this->prop['autovalues']))) {
- $this->prop['required_fields'][] = $this->prop['LDAP_rdn'];
- }
-
- foreach ($this->prop['required_fields'] as $key => $val) {
- $this->prop['required_fields'][$key] = $this->_attr_name(strtolower($val));
- }
-
- // Build sub_fields filter
- if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) {
- $this->sub_filter = '';
- foreach ($this->prop['sub_fields'] as $class) {
- if (!empty($class)) {
- $class = is_array($class) ? array_pop($class) : $class;
- $this->sub_filter .= '(objectClass=' . $class . ')';
- }
- }
- if (count($this->prop['sub_fields']) > 1) {
- $this->sub_filter = '(|' . $this->sub_filter . ')';
- }
- }
-
- $this->sort_col = is_array($p['sort']) ? $p['sort'][0] : $p['sort'];
- $this->debug = $debug;
- $this->mail_domain = $mail_domain;
-
- // initialize cache
- $rcube = rcube::get_instance();
- if ($cache_type = $rcube->config->get('ldap_cache', 'db')) {
- $cache_ttl = $rcube->config->get('ldap_cache_ttl', '10m');
- $cache_name = 'LDAP.' . asciiwords($this->prop['name']);
-
- $this->cache = $rcube->get_cache($cache_name, $cache_type, $cache_ttl);
- }
-
- // determine which attributes to fetch
- $this->prop['list_attributes'] = array_unique($fetch_attributes);
- $this->prop['attributes'] = array_merge(array_values($this->fieldmap), $fetch_attributes);
- foreach ($rcube->config->get('contactlist_fields') as $col) {
- $this->prop['list_attributes'] = array_merge($this->prop['list_attributes'], $this->_map_field($col));
- }
-
- // initialize ldap wrapper object
- $this->ldap = new rcube_ldap_generic($this->prop);
- $this->ldap->config_set(array('cache' => $this->cache, 'debug' => $this->debug));
-
- $this->_connect();
- }
-
-
- /**
- * Establish a connection to the LDAP server
- */
- private function _connect()
- {
- $rcube = rcube::get_instance();
-
- if ($this->ready)
- return true;
-
- if (!is_array($this->prop['hosts']))
- $this->prop['hosts'] = array($this->prop['hosts']);
-
- // try to connect + bind for every host configured
- // with OpenLDAP 2.x ldap_connect() always succeeds but ldap_bind will fail if host isn't reachable
- // see http://www.php.net/manual/en/function.ldap-connect.php
- foreach ($this->prop['hosts'] as $host) {
- // skip host if connection failed
- if (!$this->ldap->connect($host)) {
- continue;
- }
-
- // 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'];
-
- $this->base_dn = $this->prop['base_dn'];
- $this->groups_base_dn = ($this->prop['groups']['base_dn']) ?
- $this->prop['groups']['base_dn'] : $this->base_dn;
-
- // 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 = $rcube->get_user_password();
- }
-
- // Get the pieces needed for variable replacement.
- if ($fu = $rcube->get_user_email())
- list($u, $d) = explode('@', $fu);
- else
- $d = $this->mail_domain;
-
- $dc = 'dc='.strtr($d, array('.' => ',dc=')); // hierarchal domain string
-
- $replaces = array('%dn' => '', '%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u);
-
- // Search for the dn to use to authenticate
- if ($this->prop['search_base_dn'] && $this->prop['search_filter']
- && (strstr($bind_dn, '%dn') || strstr($this->base_dn, '%dn') || strstr($this->groups_base_dn, '%dn'))
- ) {
- $search_attribs = array('uid');
- if ($search_bind_attrib = (array)$this->prop['search_bind_attrib']) {
- foreach ($search_bind_attrib as $r => $attr) {
- $search_attribs[] = $attr;
- $replaces[$r] = '';
- }
- }
-
- $search_bind_dn = strtr($this->prop['search_bind_dn'], $replaces);
- $search_base_dn = strtr($this->prop['search_base_dn'], $replaces);
- $search_filter = strtr($this->prop['search_filter'], $replaces);
-
- $cache_key = 'DN.' . md5("$host:$search_bind_dn:$search_base_dn:$search_filter:"
- .$this->prop['search_bind_pw']);
-
- if ($this->cache && ($dn = $this->cache->get($cache_key))) {
- $replaces['%dn'] = $dn;
- }
- else {
- $ldap = $this->ldap;
- if (!empty($search_bind_dn) && !empty($this->prop['search_bind_pw'])) {
- // To protect from "Critical extension is unavailable" error
- // we need to use a separate LDAP connection
- if (!empty($this->prop['vlv'])) {
- $ldap = new rcube_ldap_generic($this->prop);
- $ldap->config_set(array('cache' => $this->cache, 'debug' => $this->debug));
- if (!$ldap->connect($host)) {
- continue;
- }
- }
-
- if (!$ldap->bind($search_bind_dn, $this->prop['search_bind_pw'])) {
- continue; // bind failed, try next host
- }
- }
-
- $res = $ldap->search($search_base_dn, $search_filter, 'sub', $search_attribs);
- if ($res) {
- $res->rewind();
- $replaces['%dn'] = key($res->entries(TRUE));
-
- // add more replacements from 'search_bind_attrib' config
- if ($search_bind_attrib) {
- $res = $res->current();
- foreach ($search_bind_attrib as $r => $attr) {
- $replaces[$r] = $res[$attr][0];
- }
- }
- }
-
- if ($ldap != $this->ldap) {
- $ldap->close();
- }
- }
-
- // DN not found
- if (empty($replaces['%dn'])) {
- if (!empty($this->prop['search_dn_default']))
- $replaces['%dn'] = $this->prop['search_dn_default'];
- else {
- rcube::raise_error(array(
- 'code' => 100, 'type' => 'ldap',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "DN not found using LDAP search."), true);
- continue;
- }
- }
-
- if ($this->cache && !empty($replaces['%dn'])) {
- $this->cache->set($cache_key, $replaces['%dn']);
- }
- }
-
- // 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);
-
- // replace placeholders in filter settings
- if (!empty($this->prop['filter']))
- $this->prop['filter'] = strtr($this->prop['filter'], $replaces);
-
- foreach (array('base_dn','filter','member_filter') as $k) {
- if (!empty($this->prop['groups'][$k]))
- $this->prop['groups'][$k] = strtr($this->prop['groups'][$k], $replaces);
- }
-
- if (is_array($this->prop['group_filters'])) {
- foreach ($this->prop['group_filters'] as $i => $gf) {
- if (!empty($gf['base_dn']))
- $this->prop['group_filters'][$i]['base_dn'] = strtr($gf['base_dn'], $replaces);
- if (!empty($gf['filter']))
- $this->prop['group_filters'][$i]['filter'] = strtr($gf['filter'], $replaces);
- }
- }
-
- if (empty($bind_user)) {
- $bind_user = $u;
- }
- }
-
- if (empty($bind_pass)) {
- $this->ready = true;
- }
- else {
- if (!empty($bind_dn)) {
- $this->ready = $this->ldap->bind($bind_dn, $bind_pass);
- }
- else if (!empty($this->prop['auth_cid'])) {
- $this->ready = $this->ldap->sasl_bind($this->prop['auth_cid'], $bind_pass, $bind_user);
- }
- else {
- $this->ready = $this->ldap->sasl_bind($bind_user, $bind_pass);
- }
- }
-
- // connection established, we're done here
- if ($this->ready) {
- break;
- }
-
- } // end foreach hosts
-
- if (!is_resource($this->ldap->conn)) {
- rcube::raise_error(array('code' => 100, 'type' => 'ldap',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Could not connect to any LDAP server, last tried $host"), true);
-
- return false;
- }
-
- return $this->ready;
- }
-
-
- /**
- * Close connection to LDAP server
- */
- function close()
- {
- if ($this->ldap) {
- $this->ldap->close();
- }
- }
-
-
- /**
- * Returns address book name
- *
- * @return string Address book name
- */
- function get_name()
- {
- return $this->prop['name'];
- }
-
-
- /**
- * Set internal list page
- *
- * @param number Page number to list
- */
- function set_page($page)
- {
- $this->list_page = (int)$page;
- $this->ldap->set_vlv_page($this->list_page, $this->page_size);
- }
-
- /**
- * Set internal page size
- *
- * @param number Number of records to display on one page
- */
- function set_pagesize($size)
- {
- $this->page_size = (int)$size;
- $this->ldap->set_vlv_page($this->list_page, $this->page_size);
- }
-
-
- /**
- * Set internal sort settings
- *
- * @param string $sort_col Sort column
- * @param string $sort_order Sort order
- */
- function set_sort_order($sort_col, $sort_order = null)
- {
- if ($this->coltypes[$sort_col]['attributes'])
- $this->sort_col = $this->coltypes[$sort_col]['attributes'][0];
- }
-
-
- /**
- * Save a search string for future listings
- *
- * @param string $filter Filter string
- */
- function set_search_set($filter)
- {
- $this->filter = $filter;
- }
-
-
- /**
- * Getter for saved search properties
- *
- * @return mixed Search properties used by this class
- */
- function get_search_set()
- {
- return $this->filter;
- }
-
-
- /**
- * Reset all saved results and search parameters
- */
- function reset()
- {
- $this->result = null;
- $this->ldap_result = null;
- $this->filter = '';
- }
-
-
- /**
- * List the current set of contact records
- *
- * @param array List of cols to show
- * @param int Only return this number of records
- *
- * @return array Indexed list of contact records, each a hash array
- */
- function list_records($cols=null, $subset=0)
- {
- if ($this->prop['searchonly'] && empty($this->filter) && !$this->group_id) {
- $this->result = new rcube_result_set(0);
- $this->result->searchonly = true;
- return $this->result;
- }
-
- // fetch group members recursively
- if ($this->group_id && $this->group_data['dn']) {
- $entries = $this->list_group_members($this->group_data['dn']);
-
- // 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'));
-
- $entries['count'] = count($entries);
- $this->result = new rcube_result_set($entries['count'], ($this->list_page-1) * $this->page_size);
- }
- else {
- $prop = $this->group_id ? $this->group_data : $this->prop;
- $base_dn = $this->group_id ? $prop['base_dn'] : $this->base_dn;
-
- // use global search filter
- if (!empty($this->filter))
- $prop['filter'] = $this->filter;
-
- // exec LDAP search if no result resource is stored
- if ($this->ready && !$this->ldap_result)
- $this->ldap_result = $this->ldap->search($base_dn, $prop['filter'], $prop['scope'], $this->prop['attributes'], $prop);
-
- // count contacts for this user
- $this->result = $this->count();
-
- // we have a search result resource
- if ($this->ldap_result && $this->result->count > 0) {
- // sorting still on the ldap server
- if ($this->sort_col && $prop['scope'] !== 'base' && !$this->ldap->vlv_active)
- $this->ldap_result->sort($this->sort_col);
-
- // get all entries from the ldap server
- $entries = $this->ldap_result->entries();
- }
-
- } // end else
-
- // start and end of the page
- $start_row = $this->ldap->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 boolean Count only
- * @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)) {
- $attribs = array_merge(array('dn','objectClass','memberURL'), array_values($this->group_types));
- $entries = $this->ldap->read_entries($dn, '(objectClass=*)', $attribs);
- if ($entries === false) {
- return $group_members;
- }
- }
-
- for ($i=0; $i < $entries['count']; $i++) {
- $entry = $entries[$i];
- $attrs = array();
-
- foreach ((array)$entry['objectclass'] as $objectclass) {
- if (($member_attr = $this->get_group_member_attr(array($objectclass), ''))
- && ($member_attr = strtolower($member_attr)) && !in_array($member_attr, $attrs)
- ) {
- $members = $this->_list_group_members($dn, $entry, $member_attr, $count);
- $group_members = array_merge($group_members, $members);
- $attrs[] = $member_attr;
- }
- else if (!empty($entry['memberurl'])) {
- $members = $this->_list_group_memberurl($dn, $entry, $count);
- $group_members = array_merge($group_members, $members);
- }
-
- if ($this->prop['sizelimit'] && count($group_members) > $this->prop['sizelimit']) {
- break 2;
- }
- }
- }
-
- return array_filter($group_members);
- }
-
- /**
- * Fetch members of the given group entry from server
- *
- * @param string Group DN
- * @param array Group entry
- * @param string Member attribute to use
- * @param boolean Count only
- * @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','objectClass') : $this->prop['list_attributes'];
- $attrib = array_merge($attrib, array_values($this->group_types));
- $attrib[] = 'memberURL';
-
- $filter = $this->prop['groups']['member_filter'] ? $this->prop['groups']['member_filter'] : '(objectclass=*)';
-
- for ($i=0; $i < $entry[$attr]['count']; $i++) {
- if (empty($entry[$attr][$i]))
- continue;
-
- $members = $this->ldap->read_entries($entry[$attr][$i], $filter, $attrib);
- if ($members == false) {
- $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 $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];
- $attrs = $count ? array('dn','objectClass') : $this->prop['list_attributes'];
- if ($result = $this->ldap->search($m[1], $filter, $m[2], $attrs, $this->group_data)) {
- $entries = $result->entries();
- for ($j = 0; $j < $entries['count']; $j++) {
- if ($this->is_group_entry($entries[$j]) && ($nested_group_members = $this->list_group_members($entries[$j]['dn'], $count)))
- $group_members = array_merge($group_members, $nested_group_members);
- else
- $group_members[] = $entries[$j];
- }
- }
- }
-
- 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]);
- }
-
-
- /**
- * Search contacts
- *
- * @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 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, $mode=0, $select=true, $nocount=false, $required=array())
- {
- $mode = intval($mode);
-
- // special treatment for ID-based search
- if ($fields == 'ID' || $fields == $this->primary_key) {
- $ids = !is_array($value) ? explode(',', $value) : $value;
- $result = new rcube_result_set();
- foreach ($ids as $id) {
- if ($rec = $this->get_record($id, true)) {
- $result->add($rec);
- $result->count++;
- }
- }
- return $result;
- }
-
- // use VLV pseudo-search for autocompletion
- $rcube = rcube::get_instance();
- $list_fields = $rcube->config->get('contactlist_fields');
-
- if ($this->prop['vlv_search'] && $this->ready && join(',', (array)$fields) == join(',', $list_fields)) {
- $this->result = new rcube_result_set(0);
-
- $search_suffix = $this->prop['fuzzy_search'] && $mode != 1 ? '*' : '';
- $ldap_data = $this->ldap->search($this->base_dn, $this->prop['filter'], $this->prop['scope'], $this->prop['attributes'],
- array('search' => $value . $search_suffix /*, 'sort' => $this->prop['sort'] */));
- if ($ldap_data === false) {
- return $this->result;
- }
-
- // get all entries of this page and post-filter those that really match the query
- $search = mb_strtolower($value);
- foreach ($ldap_data as $i => $entry) {
- $rec = $this->_ldap2result($entry);
- foreach ($fields as $f) {
- foreach ((array)$rec[$f] as $val) {
- if ($this->compare_search_value($f, $val, $search, $mode)) {
- $this->result->add($rec);
- $this->result->count++;
- break 2;
- }
- }
- }
- }
-
- return $this->result;
- }
-
- // use AND operator for advanced searches
- $filter = is_array($value) ? '(&' : '(|';
- // set wildcards
- $wp = $ws = '';
- if (!empty($this->prop['fuzzy_search']) && $mode != 1) {
- $ws = '*';
- if (!$mode) {
- $wp = '*';
- }
- }
-
- if ($fields == '*') {
- // search_fields are required for fulltext search
- if (empty($this->prop['search_fields'])) {
- $this->set_error(self::ERROR_SEARCH, 'nofulltextsearch');
- $this->result = new rcube_result_set();
- return $this->result;
- }
- if (is_array($this->prop['search_fields'])) {
- foreach ($this->prop['search_fields'] as $field) {
- $filter .= "($field=$wp" . rcube_ldap_generic::quote_string($value) . "$ws)";
- }
- }
- }
- else {
- foreach ((array)$fields as $idx => $field) {
- $val = is_array($value) ? $value[$idx] : $value;
- if ($attrs = $this->_map_field($field)) {
- if (count($attrs) > 1)
- $filter .= '(|';
- foreach ($attrs as $f)
- $filter .= "($f=$wp" . rcube_ldap_generic::quote_string($val) . "$ws)";
- if (count($attrs) > 1)
- $filter .= ')';
- }
- }
- }
- $filter .= ')';
-
- // add required (non empty) fields filter
- $req_filter = '';
- foreach ((array)$required as $field) {
- if (in_array($field, (array)$fields)) // required field is already in search filter
- continue;
- if ($attrs = $this->_map_field($field)) {
- if (count($attrs) > 1)
- $req_filter .= '(|';
- foreach ($attrs as $f)
- $req_filter .= "($f=*)";
- if (count($attrs) > 1)
- $req_filter .= ')';
- }
- }
-
- if (!empty($req_filter))
- $filter = '(&' . $req_filter . $filter . ')';
-
- // avoid double-wildcard if $value is empty
- $filter = preg_replace('/\*+/', '*', $filter);
-
- // add general filter to query
- if (!empty($this->prop['filter']))
- $filter = '(&(' . preg_replace('/^\(|\)$/', '', $this->prop['filter']) . ')' . $filter . ')';
-
- // set filter string and execute search
- $this->set_search_set($filter);
-
- if ($select)
- $this->list_records();
- else
- $this->result = $this->count();
-
- return $this->result;
- }
-
-
- /**
- * Count number of available contacts in database
- *
- * @return object rcube_result_set Resultset with values for 'count' and 'first'
- */
- function count()
- {
- $count = 0;
- if ($this->ldap_result) {
- $count = $this->ldap_result->count();
- }
- else if ($this->group_id && $this->group_data['dn']) {
- $count = count($this->list_group_members($this->group_data['dn'], true));
- }
- // We have a connection but no result set, attempt to get one.
- else if ($this->ready) {
- $prop = $this->group_id ? $this->group_data : $this->prop;
- $base_dn = $this->group_id ? $this->group_base_dn : $this->base_dn;
-
- if (!empty($this->filter)) { // Use global search filter
- $prop['filter'] = $this->filter;
- }
- $count = $this->ldap->search($base_dn, $prop['filter'], $prop['scope'], array('dn'), $prop, true);
- }
-
- return new rcube_result_set($count, ($this->list_page-1) * $this->page_size);
- }
-
-
- /**
- * Return the last result set
- *
- * @return object rcube_result_set Current resultset or NULL if nothing selected yet
- */
- function get_result()
- {
- return $this->result;
- }
-
- /**
- * Get a specific contact record
- *
- * @param mixed Record identifier
- * @param boolean Return as associative array
- *
- * @return mixed Hash array or rcube_result_set with all record fields
- */
- function get_record($dn, $assoc=false)
- {
- $res = $this->result = null;
-
- if ($this->ready && $dn) {
- $dn = self::dn_decode($dn);
-
- if ($rec = $this->ldap->get_entry($dn)) {
- $rec = array_change_key_case($rec, CASE_LOWER);
- }
-
- // Use ldap_list to get subentries like country (c) attribute (#1488123)
- if (!empty($rec) && $this->sub_filter) {
- if ($entries = $this->ldap->list_entries($dn, $this->sub_filter, array_keys($this->prop['sub_fields']))) {
- foreach ($entries as $entry) {
- $lrec = array_change_key_case($entry, CASE_LOWER);
- $rec = array_merge($lrec, $rec);
- }
- }
- }
-
- if (!empty($rec)) {
- // Add in the dn for the entry.
- $rec['dn'] = $dn;
- $res = $this->_ldap2result($rec);
- $this->result = new rcube_result_set(1);
- $this->result->add($res);
- }
- }
-
- return $assoc ? $res : $this->result;
- }
-
- /**
- * Returns the last error occurred (e.g. when updating/inserting failed)
- *
- * @return array Hash array with the following fields: type, message
- */
- function get_error()
- {
- $err = $this->error;
-
- // check ldap connection for errors
- if (!$err && $this->ldap->get_error()) {
- $err = array(self::ERROR_SEARCH, $this->ldap->get_error());
- }
-
- return $err;
- }
-
-
- /**
- * Check the given data before saving.
- * 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, $autofix = false)
- {
- // validate e-mail addresses
- if (!parent::validate($save_data, $autofix)) {
- return false;
- }
-
- // check for name input
- if (empty($save_data['name'])) {
- $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]) || $ldap_data[$fld] === '') {
- $missing[$fld] = 1;
- }
- }
-
- if ($missing) {
- // try to complete record automatically
- if ($autofix) {
- $sn_field = $this->fieldmap['surname'];
- $fn_field = $this->fieldmap['firstname'];
- $mail_field = $this->fieldmap['email'];
-
- // try to extract surname and firstname from displayname
- $name_parts = preg_split('/[\s,.]+/', $save_data['name']);
-
- if ($sn_field && $missing[$sn_field]) {
- $save_data['surname'] = array_pop($name_parts);
- unset($missing[$sn_field]);
- }
-
- if ($fn_field && $missing[$fn_field]) {
- $save_data['firstname'] = array_shift($name_parts);
- unset($missing[$fn_field]);
- }
-
- // try to fix missing e-mail, very often on import
- // from vCard we have email:other only defined
- if ($mail_field && $missing[$mail_field]) {
- $emails = $this->get_col_values('email', $save_data, true);
- if (!empty($emails) && ($email = array_shift($emails))) {
- $save_data['email'] = $email;
- unset($missing[$mail_field]);
- }
- }
- }
-
- // TODO: generate message saying which fields are missing
- if (!empty($missing)) {
- $this->set_error(self::ERROR_VALIDATE, 'formincomplete');
- return false;
- }
- }
-
- return true;
- }
-
-
- /**
- * Create a new contact record
- *
- * @param array Hash array with save data
- *
- * @return encoded record ID on success, False on error
- */
- function insert($save_cols)
- {
- // Map out the column names to their LDAP ones to build the new entry.
- $newentry = $this->_map_data($save_cols);
- $newentry['objectClass'] = $this->prop['LDAP_Object_Classes'];
-
- // add automatically generated attributes
- $this->add_autovalues($newentry);
-
- // Verify that the required fields are set.
- $missing = null;
- foreach ($this->prop['required_fields'] as $fld) {
- if (!isset($newentry[$fld])) {
- $missing[] = $fld;
- }
- }
-
- // abort process if requiered fields are missing
- // TODO: generate message saying which fields are missing
- if ($missing) {
- $this->set_error(self::ERROR_VALIDATE, 'formincomplete');
- return false;
- }
-
- // Build the new entries DN.
- $dn = $this->prop['LDAP_rdn'].'='.rcube_ldap_generic::quote_string($newentry[$this->prop['LDAP_rdn']], true).','.$this->base_dn;
-
- // Remove attributes that need to be added separately (child objects)
- $xfields = array();
- if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) {
- foreach (array_keys($this->prop['sub_fields']) as $xf) {
- if (!empty($newentry[$xf])) {
- $xfields[$xf] = $newentry[$xf];
- unset($newentry[$xf]);
- }
- }
- }
-
- if (!$this->ldap->add_entry($dn, $newentry)) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return false;
- }
-
- foreach ($xfields as $xidx => $xf) {
- $xdn = $xidx.'='.rcube_ldap_generic::quote_string($xf).','.$dn;
- $xf = array(
- $xidx => $xf,
- 'objectClass' => (array) $this->prop['sub_fields'][$xidx],
- );
-
- $this->ldap->add_entry($xdn, $xf);
- }
-
- $dn = self::dn_encode($dn);
-
- // add new contact to the selected group
- if ($this->group_id)
- $this->add_to_group($this->group_id, $dn);
-
- return $dn;
- }
-
-
- /**
- * Update a specific contact record
- *
- * @param mixed Record identifier
- * @param array Hash array with save data
- *
- * @return boolean True on success, False on error
- */
- function update($id, $save_cols)
- {
- $record = $this->get_record($id, true);
-
- $newdata = array();
- $replacedata = array();
- $deletedata = array();
- $subdata = array();
- $subdeldata = array();
- $subnewdata = array();
-
- $ldap_data = $this->_map_data($save_cols);
- $old_data = $record['_raw_attrib'];
-
- // special handling of photo col
- if ($photo_fld = $this->fieldmap['photo']) {
- // undefined means keep old photo
- if (!array_key_exists('photo', $save_cols)) {
- $ldap_data[$photo_fld] = $record['photo'];
- }
- }
-
- foreach ($this->fieldmap as $fld) {
- if ($fld) {
- $val = $ldap_data[$fld];
- $old = $old_data[$fld];
- // remove empty array values
- if (is_array($val))
- $val = array_filter($val);
- // $this->_map_data() result and _raw_attrib use different format
- // make sure comparing array with one element with a string works as expected
- if (is_array($old) && count($old) == 1 && !is_array($val)) {
- $old = array_pop($old);
- }
- if (is_array($val) && count($val) == 1 && !is_array($old)) {
- $val = array_pop($val);
- }
- // Subentries must be handled separately
- if (!empty($this->prop['sub_fields']) && isset($this->prop['sub_fields'][$fld])) {
- if ($old != $val) {
- if ($old !== null) {
- $subdeldata[$fld] = $old;
- }
- if ($val) {
- $subnewdata[$fld] = $val;
- }
- }
- else if ($old !== null) {
- $subdata[$fld] = $old;
- }
- continue;
- }
-
- // The field does exist compare it to the ldap record.
- if ($old != $val) {
- // Changed, but find out how.
- if ($old === null) {
- // Field was not set prior, need to add it.
- $newdata[$fld] = $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.
- // #1488420: Workaround "ldap_mod_del(): Modify: Inappropriate matching in..."
- // jpegPhoto attribute require an array() here. It looks to me that it works for other attribs too
- $deletedata[$fld] = array();
- //$deletedata[$fld] = $old_data[$fld];
- }
- }
- else {
- // The data was modified, save it out.
- $replacedata[$fld] = $val;
- }
- } // end if
- } // end if
- } // end foreach
-
- // console($old_data, $ldap_data, '----', $newdata, $replacedata, $deletedata, '----', $subdata, $subnewdata, $subdeldata);
-
- $dn = self::dn_decode($id);
-
- // Update the entry as required.
- if (!empty($deletedata)) {
- // Delete the fields.
- if (!$this->ldap->mod_del($dn, $deletedata)) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return false;
- }
- } // end if
-
- if (!empty($replacedata)) {
- // Handle RDN change
- if ($replacedata[$this->prop['LDAP_rdn']]) {
- $newdn = $this->prop['LDAP_rdn'].'='
- .rcube_ldap_generic::quote_string($replacedata[$this->prop['LDAP_rdn']], true)
- .','.$this->base_dn;
- if ($dn != $newdn) {
- $newrdn = $this->prop['LDAP_rdn'].'='
- .rcube_ldap_generic::quote_string($replacedata[$this->prop['LDAP_rdn']], true);
- unset($replacedata[$this->prop['LDAP_rdn']]);
- }
- }
- // Replace the fields.
- if (!empty($replacedata)) {
- if (!$this->ldap->mod_replace($dn, $replacedata)) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return false;
- }
- }
- } // end if
-
- // RDN change, we need to remove all sub-entries
- if (!empty($newrdn)) {
- $subdeldata = array_merge($subdeldata, $subdata);
- $subnewdata = array_merge($subnewdata, $subdata);
- }
-
- // remove sub-entries
- if (!empty($subdeldata)) {
- foreach ($subdeldata as $fld => $val) {
- $subdn = $fld.'='.rcube_ldap_generic::quote_string($val).','.$dn;
- if (!$this->ldap->delete_entry($subdn)) {
- return false;
- }
- }
- }
-
- if (!empty($newdata)) {
- // Add the fields.
- if (!$this->ldap->mod_add($dn, $newdata)) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return false;
- }
- } // end if
-
- // Handle RDN change
- if (!empty($newrdn)) {
- if (!$this->ldap->rename($dn, $newrdn, null, true)) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return false;
- }
-
- $dn = self::dn_encode($dn);
- $newdn = self::dn_encode($newdn);
-
- // change the group membership of the contact
- if ($this->groups) {
- $group_ids = $this->get_record_groups($dn);
- foreach (array_keys($group_ids) as $group_id) {
- $this->remove_from_group($group_id, $dn);
- $this->add_to_group($group_id, $newdn);
- }
- }
-
- $dn = self::dn_decode($newdn);
- }
-
- // add sub-entries
- if (!empty($subnewdata)) {
- foreach ($subnewdata as $fld => $val) {
- $subdn = $fld.'='.rcube_ldap_generic::quote_string($val).','.$dn;
- $xf = array(
- $fld => $val,
- 'objectClass' => (array) $this->prop['sub_fields'][$fld],
- );
- $this->ldap->add_entry($subdn, $xf);
- }
- }
-
- return $newdn ? $newdn : true;
- }
-
-
- /**
- * Mark one or more contact records as deleted
- *
- * @param array Record identifiers
- * @param boolean Remove record(s) irreversible (unsupported)
- *
- * @return boolean True on success, False on error
- */
- function delete($ids, $force=true)
- {
- if (!is_array($ids)) {
- // Not an array, break apart the encoded DNs.
- $ids = explode(',', $ids);
- } // end if
-
- foreach ($ids as $id) {
- $dn = self::dn_decode($id);
-
- // Need to delete all sub-entries first
- if ($this->sub_filter) {
- if ($entries = $this->ldap->list_entries($dn, $this->sub_filter)) {
- foreach ($entries as $entry) {
- if (!$this->ldap->delete_entry($entry['dn'])) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return false;
- }
- }
- }
- }
-
- // Delete the record.
- if (!$this->ldap->delete_entry($dn)) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return false;
- }
-
- // remove contact from all groups where he was a member
- if ($this->groups) {
- $dn = self::dn_encode($dn);
- $group_ids = $this->get_record_groups($dn);
- foreach (array_keys($group_ids) as $group_id) {
- $this->remove_from_group($group_id, $dn);
- }
- }
- } // end foreach
-
- return count($ids);
- }
-
-
- /**
- * Remove all contact records
- *
- * @param bool $with_groups Delete also groups if enabled
- */
- function delete_all($with_groups = false)
- {
- // searching for contact entries
- $dn_list = $this->ldap->list_entries($this->base_dn, $this->prop['filter'] ? $this->prop['filter'] : '(objectclass=*)');
-
- if (!empty($dn_list)) {
- foreach ($dn_list as $idx => $entry) {
- $dn_list[$idx] = self::dn_encode($entry['dn']);
- }
- $this->delete($dn_list);
- }
-
- if ($with_groups && $this->groups && ($groups = $this->_fetch_groups()) && count($groups)) {
- foreach ($groups as $group) {
- $this->ldap->delete_entry($group['dn']);
- }
-
- if ($this->cache) {
- $this->cache->remove('groups');
- }
- }
- }
-
- /**
- * Generate missing attributes as configured
- *
- * @param array LDAP record attributes
- */
- protected function add_autovalues(&$attrs)
- {
- if (empty($this->prop['autovalues'])) {
- return;
- }
-
- $attrvals = array();
- foreach ($attrs as $k => $v) {
- $attrvals['{'.$k.'}'] = is_array($v) ? $v[0] : $v;
- }
-
- foreach ((array)$this->prop['autovalues'] as $lf => $templ) {
- if (empty($attrs[$lf])) {
- if (strpos($templ, '(') !== false) {
- // replace {attr} placeholders with (escaped!) attribute values to be safely eval'd
- $code = preg_replace('/\{\w+\}/', '', strtr($templ, array_map('addslashes', $attrvals)));
- $fn = create_function('', "return ($code);");
- if (!$fn) {
- rcube::raise_error(array(
- 'code' => 505, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Expression parse error on: ($code)"), true, false);
- continue;
- }
-
- $attrs[$lf] = $fn();
- }
- else {
- // replace {attr} placeholders with concrete attribute values
- $attrs[$lf] = preg_replace('/\{\w+\}/', '', strtr($templ, $attrvals));
- }
- }
- }
- }
-
-
- /**
- * Converts LDAP entry into an array
- */
- private function _ldap2result($rec)
- {
- $out = array('_type' => 'person');
- $fieldmap = $this->fieldmap;
-
- if ($rec['dn'])
- $out[$this->primary_key] = self::dn_encode($rec['dn']);
-
- // determine record type
- if ($this->is_group_entry($rec)) {
- $out['_type'] = 'group';
- $out['readonly'] = true;
- $fieldmap['name'] = $this->group_data['name_attr'] ? $this->group_data['name_attr'] : $this->prop['groups']['name_attr'];
- }
-
- // assign object type from object class mapping
- if (!empty($this->prop['class_type_map'])) {
- foreach (array_map('strtolower', (array)$rec['objectclass']) as $objcls) {
- if (!empty($this->prop['class_type_map'][$objcls])) {
- $out['_type'] = $this->prop['class_type_map'][$objcls];
- break;
- }
- }
- }
-
- foreach ($fieldmap as $rf => $lf)
- {
- for ($i=0; $i < $rec[$lf]['count']; $i++) {
- if (!($value = $rec[$lf][$i]))
- continue;
-
- list($col, $subtype) = explode(':', $rf);
- $out['_raw_attrib'][$lf][$i] = $value;
-
- if ($col == 'email' && $this->mail_domain && !strpos($value, '@'))
- $out[$rf][] = sprintf('%s@%s', $value, $this->mail_domain);
- else if (in_array($col, array('street','zipcode','locality','country','region')))
- $out['address'.($subtype?':':'').$subtype][$i][$col] = $value;
- else if ($col == 'address' && strpos($value, '$') !== false) // address data is represented as string separated with $
- list($out[$rf][$i]['street'], $out[$rf][$i]['locality'], $out[$rf][$i]['zipcode'], $out[$rf][$i]['country']) = explode('$', $value);
- else if ($rec[$lf]['count'] > 1)
- $out[$rf][] = $value;
- 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;
- }
-
-
- /**
- * Return LDAP attribute(s) for the given field
- */
- private function _map_field($field)
- {
- return (array)$this->coltypes[$field]['attributes'];
- }
-
-
- /**
- * 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;
- }
- }
- }
- }
-
- // if addresses are to be saved as serialized string, do so
- if (is_array($colprop['serialized'])) {
- foreach ($colprop['serialized'] as $subtype => $delim) {
- $key = $col.':'.$subtype;
- foreach ((array)$save_cols[$key] as $i => $val) {
- $values = array($val['street'], $val['locality'], $val['zipcode'], $val['country']);
- $save_cols[$key][$i] = count(array_filter($values)) ? join($delim, $values) : null;
- }
- }
- }
- }
-
- $ldap_data = array();
- foreach ($this->fieldmap as $rf => $fld) {
- $val = $save_cols[$rf];
-
- // check for value in base field (eg.g email instead of email:foo)
- list($col, $subtype) = explode(':', $rf);
- if (!$val && !empty($save_cols[$col])) {
- $val = $save_cols[$col];
- unset($save_cols[$col]); // only use this value once
- }
- else if (!$val && !$subtype) { // extract values from subtype cols
- $val = $this->get_col_values($col, $save_cols, true);
- }
-
- 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)
- */
- private static function _attr_name($namev)
- {
- // list of known attribute aliases
- static $aliases = array(
- 'gn' => 'givenname',
- 'rfc822mailbox' => 'email',
- 'userid' => 'uid',
- 'emailaddress' => 'email',
- 'pkcs9email' => 'email',
- );
-
- list($name, $limit) = explode(':', $namev, 2);
- $suffix = $limit ? ':'.$limit : '';
-
- return (isset($aliases[$name]) ? $aliases[$name] : $name) . $suffix;
- }
-
- /**
- * Determines whether the given LDAP entry is a group record
- */
- private function is_group_entry($entry)
- {
- $classes = array_map('strtolower', (array)$entry['objectclass']);
-
- return count(array_intersect(array_keys($this->group_types), $classes)) > 0;
- }
-
- /**
- * Prints debug info to the log
- */
- private function _debug($str)
- {
- if ($this->debug) {
- rcube::write_log('ldap', $str);
- }
- }
-
-
- /**
- * Activate/deactivate debug mode
- *
- * @param boolean $dbg True if LDAP commands should be logged
- */
- function set_debug($dbg = true)
- {
- $this->debug = $dbg;
-
- if ($this->ldap) {
- $this->ldap->config_set('debug', $dbg);
- }
- }
-
-
- /**
- * Setter for the current group
- */
- function set_group($group_id)
- {
- if ($group_id) {
- $this->group_id = $group_id;
- $this->group_data = $this->get_group_entry($group_id);
- }
- else {
- $this->group_id = 0;
- $this->group_data = null;
- }
- }
-
- /**
- * List all active contact groups of this source
- *
- * @param string Optional search string to match group name
- * @param int Matching mode:
- * 0 - partial (*abc*),
- * 1 - strict (=),
- * 2 - prefix (abc*)
- *
- * @return array Indexed list of contact groups, each a hash array
- */
- function list_groups($search = null, $mode = 0)
- {
- if (!$this->groups) {
- return array();
- }
-
- $group_cache = $this->_fetch_groups($search, $mode);
- $groups = array();
-
- if ($search) {
- foreach ($group_cache as $group) {
- if ($this->compare_search_value('name', $group['name'], mb_strtolower($search), $mode)) {
- $groups[] = $group;
- }
- }
- }
- else {
- $groups = $group_cache;
- }
-
- return array_values($groups);
- }
-
- /**
- * Fetch groups from server
- */
- private function _fetch_groups($search = null, $mode = 0, $vlv_page = null)
- {
- // reset group search cache
- if ($search !== null && $vlv_page === null) {
- $this->group_search_cache = null;
- }
- // return in-memory cache from previous search results
- else if (is_array($this->group_search_cache) && $vlv_page === null) {
- return $this->group_search_cache;
- }
-
- // special case: list groups from 'group_filters' config
- if ($vlv_page === null && $search === null && is_array($this->prop['group_filters'])) {
- $groups = array();
- $rcube = rcube::get_instance();
-
- // list regular groups configuration as special filter
- if (!empty($this->prop['groups']['filter'])) {
- $id = '__groups__';
- $groups[$id] = array('ID' => $id, 'name' => $rcube->gettext('groups'), 'virtual' => true) + $this->prop['groups'];
- }
-
- foreach ($this->prop['group_filters'] as $id => $prop) {
- $groups[$id] = $prop + array('ID' => $id, 'name' => ucfirst($id), 'virtual' => true, 'base_dn' => $this->base_dn);
- }
-
- return $groups;
- }
-
- if ($this->cache && $search === null && $vlv_page === null && ($groups = $this->cache->get('groups')) !== null) {
- return $groups;
- }
-
- $base_dn = $this->groups_base_dn;
- $filter = $this->prop['groups']['filter'];
- $scope = $this->prop['groups']['scope'];
- $name_attr = $this->prop['groups']['name_attr'];
- $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];
-
- $ldap = $this->ldap;
-
- // use vlv to list groups
- if ($this->prop['groups']['vlv']) {
- $page_size = 200;
- if (!$this->prop['groups']['sort']) {
- $this->prop['groups']['sort'] = $sort_attrs;
- }
-
- $ldap = clone $this->ldap;
- $ldap->config_set($this->prop['groups']);
- $ldap->set_vlv_page($vlv_page+1, $page_size);
- }
-
- $props = array('sort' => $this->prop['groups']['sort']);
- $attrs = array_unique(array('dn', 'objectClass', $name_attr, $email_attr, $sort_attr));
-
- // add search filter
- if ($search !== null) {
- // set wildcards
- $wp = $ws = '';
- if (!empty($this->prop['fuzzy_search']) && $mode != 1) {
- $ws = '*';
- $wp = !$mode ? '*' : '';
- }
- $filter = "(&$filter($name_attr=$wp" . rcube_ldap_generic::quote_string($search) . "$ws))";
- $props['search'] = $wp . $search . $ws;
- }
-
- $ldap_data = $ldap->search($base_dn, $filter, $scope, $attrs, $props);
-
- if ($ldap_data === false) {
- return array();
- }
-
- $groups = array();
- $group_sortnames = array();
- $group_count = $ldap_data->count();
-
- foreach ($ldap_data as $entry) {
- if (!$entry['dn']) // DN is mandatory
- $entry['dn'] = $ldap_data->get_dn();
-
- $group_name = is_array($entry[$name_attr]) ? $entry[$name_attr][0] : $entry[$name_attr];
- $group_id = self::dn_encode($entry['dn']);
- $groups[$group_id]['ID'] = $group_id;
- $groups[$group_id]['dn'] = $entry['dn'];
- $groups[$group_id]['name'] = $group_name;
- $groups[$group_id]['member_attr'] = $this->get_group_member_attr($entry['objectclass']);
-
- // list email attributes of a group
- for ($j=0; $entry[$email_attr] && $j < $entry[$email_attr]['count']; $j++) {
- if (strpos($entry[$email_attr][$j], '@') > 0)
- $groups[$group_id]['email'][] = $entry[$email_attr][$j];
- }
-
- $group_sortnames[] = mb_strtolower($entry[$sort_attr][0]);
- }
-
- // recursive call can exit here
- if ($vlv_page > 0) {
- return $groups;
- }
-
- // call recursively until we have fetched all groups
- while ($this->prop['groups']['vlv'] && $group_count == $page_size) {
- $next_page = $this->_fetch_groups($search, $mode, ++$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
- if ($this->cache && $search === null) {
- $this->cache->set('groups', $groups);
- }
- else if ($search !== null) {
- $this->group_search_cache = $groups;
- }
-
- return $groups;
- }
-
- /**
- * Fetch a group entry from LDAP and save in local cache
- */
- private function get_group_entry($group_id)
- {
- $group_cache = $this->_fetch_groups();
-
- // add group record to cache if it isn't yet there
- if (!isset($group_cache[$group_id])) {
- $name_attr = $this->prop['groups']['name_attr'];
- $dn = self::dn_decode($group_id);
-
- if ($list = $this->ldap->read_entries($dn, '(objectClass=*)', array('dn','objectClass','member','uniqueMember','memberURL',$name_attr,$this->fieldmap['email']))) {
- $entry = $list[0];
- $group_name = is_array($entry[$name_attr]) ? $entry[$name_attr][0] : $entry[$name_attr];
- $group_cache[$group_id]['ID'] = $group_id;
- $group_cache[$group_id]['dn'] = $dn;
- $group_cache[$group_id]['name'] = $group_name;
- $group_cache[$group_id]['member_attr'] = $this->get_group_member_attr($entry['objectclass']);
- }
- else {
- $group_cache[$group_id] = false;
- }
-
- if ($this->cache) {
- $this->cache->set('groups', $group_cache);
- }
- }
-
- return $group_cache[$group_id];
- }
-
- /**
- * Get group properties such as name and email address(es)
- *
- * @param string Group identifier
- * @return array Group properties as hash array
- */
- function get_group($group_id)
- {
- $group_data = $this->get_group_entry($group_id);
- unset($group_data['dn'], $group_data['member_attr']);
-
- return $group_data;
- }
-
- /**
- * Create a contact group with the given name
- *
- * @param string The group name
- * @return mixed False on error, array with record props in success
- */
- function create_group($group_name)
- {
- $new_dn = 'cn=' . rcube_ldap_generic::quote_string($group_name, true) . ',' . $this->groups_base_dn;
- $new_gid = self::dn_encode($new_dn);
- $member_attr = $this->get_group_member_attr();
- $name_attr = $this->prop['groups']['name_attr'] ? $this->prop['groups']['name_attr'] : 'cn';
- $new_entry = array(
- 'objectClass' => $this->prop['groups']['object_classes'],
- $name_attr => $group_name,
- $member_attr => '',
- );
-
- if (!$this->ldap->add_entry($new_dn, $new_entry)) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return false;
- }
-
- if ($this->cache) {
- $this->cache->remove('groups');
- }
-
- return array('id' => $new_gid, 'name' => $group_name);
- }
-
- /**
- * Delete the given group and all linked group members
- *
- * @param string Group identifier
- * @return boolean True on success, false if no data was changed
- */
- function delete_group($group_id)
- {
- $group_cache = $this->_fetch_groups();
- $del_dn = $group_cache[$group_id]['dn'];
-
- if (!$this->ldap->delete_entry($del_dn)) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return false;
- }
-
- if ($this->cache) {
- unset($group_cache[$group_id]);
- $this->cache->set('groups', $group_cache);
- }
-
- return true;
- }
-
- /**
- * Rename a specific contact group
- *
- * @param string Group identifier
- * @param string New name to set for this group
- * @param string New group identifier (if changed, otherwise don't set)
- * @return boolean New name on success, false if no data was changed
- */
- function rename_group($group_id, $new_name, &$new_gid)
- {
- $group_cache = $this->_fetch_groups();
- $old_dn = $group_cache[$group_id]['dn'];
- $new_rdn = "cn=" . rcube_ldap_generic::quote_string($new_name, true);
- $new_gid = self::dn_encode($new_rdn . ',' . $this->groups_base_dn);
-
- if (!$this->ldap->rename($old_dn, $new_rdn, null, true)) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return false;
- }
-
- if ($this->cache) {
- $this->cache->remove('groups');
- }
-
- return $new_name;
- }
-
- /**
- * Add the given contact records the a certain group
- *
- * @param string Group identifier
- * @param array|string List of contact identifiers to be added
- *
- * @return int Number of contacts added
- */
- function add_to_group($group_id, $contact_ids)
- {
- $group_cache = $this->_fetch_groups();
- $member_attr = $group_cache[$group_id]['member_attr'];
- $group_dn = $group_cache[$group_id]['dn'];
- $new_attrs = array();
-
- if (!is_array($contact_ids)) {
- $contact_ids = explode(',', $contact_ids);
- }
-
- foreach ($contact_ids as $id) {
- $new_attrs[$member_attr][] = self::dn_decode($id);
- }
-
- if (!$this->ldap->mod_add($group_dn, $new_attrs)) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return 0;
- }
-
- if ($this->cache) {
- $this->cache->remove('groups');
- }
-
- return count($new_attrs[$member_attr]);
- }
-
- /**
- * Remove the given contact records from a certain group
- *
- * @param string Group identifier
- * @param array|string List of contact identifiers to be removed
- *
- * @return int Number of deleted group members
- */
- function remove_from_group($group_id, $contact_ids)
- {
- $group_cache = $this->_fetch_groups();
- $member_attr = $group_cache[$group_id]['member_attr'];
- $group_dn = $group_cache[$group_id]['dn'];
- $del_attrs = array();
-
- if (!is_array($contact_ids)) {
- $contact_ids = explode(',', $contact_ids);
- }
-
- foreach ($contact_ids as $id) {
- $del_attrs[$member_attr][] = self::dn_decode($id);
- }
-
- if (!$this->ldap->mod_del($group_dn, $del_attrs)) {
- $this->set_error(self::ERROR_SAVING, 'errorsaving');
- return 0;
- }
-
- if ($this->cache) {
- $this->cache->remove('groups');
- }
-
- return count($del_attrs[$member_attr]);
- }
-
- /**
- * Get group assignments of a specific contact record
- *
- * @param mixed Record identifier
- *
- * @return array List of assigned groups as ID=>Name pairs
- * @since 0.5-beta
- */
- function get_record_groups($contact_id)
- {
- if (!$this->groups) {
- return array();
- }
-
- $base_dn = $this->groups_base_dn;
- $contact_dn = self::dn_decode($contact_id);
- $name_attr = $this->prop['groups']['name_attr'] ? $this->prop['groups']['name_attr'] : 'cn';
- $member_attr = $this->get_group_member_attr();
- $add_filter = '';
-
- if ($member_attr != 'member' && $member_attr != 'uniqueMember')
- $add_filter = "($member_attr=$contact_dn)";
- $filter = strtr("(|(member=$contact_dn)(uniqueMember=$contact_dn)$add_filter)", array('\\' => '\\\\'));
-
- $ldap_data = $this->ldap->search($base_dn, $filter, 'sub', array('dn', $name_attr));
- if ($res === false) {
- return array();
- }
-
- $groups = array();
- foreach ($ldap_data as $entry) {
- if (!$entry['dn'])
- $entry['dn'] = $ldap_data->get_dn();
- $group_name = $entry[$name_attr][0];
- $group_id = self::dn_encode($entry['dn']);
- $groups[$group_id] = $group_name;
- }
-
- return $groups;
- }
-
- /**
- * Detects group member attribute name
- */
- private function get_group_member_attr($object_classes = array(), $default = 'member')
- {
- if (empty($object_classes)) {
- $object_classes = $this->prop['groups']['object_classes'];
- }
-
- if (!empty($object_classes)) {
- foreach ((array)$object_classes as $oc) {
- if ($attr = $this->group_types[strtolower($oc)]) {
- return $attr;
- }
- }
- }
-
- if (!empty($this->prop['groups']['member_attr'])) {
- return $this->prop['groups']['member_attr'];
- }
-
- return $default;
- }
-
-
- /**
- * HTML-safe DN string encoding
- *
- * @param string $str DN string
- *
- * @return string Encoded HTML identifier string
- */
- static function dn_encode($str)
- {
- // @TODO: to make output string shorter we could probably
- // remove dc=* items from it
- return rtrim(strtr(base64_encode($str), '+/', '-_'), '=');
- }
-
- /**
- * Decodes DN string encoded with _dn_encode()
- *
- * @param string $str Encoded HTML identifier string
- *
- * @return string DN string
- */
- static function dn_decode($str)
- {
- $str = str_pad(strtr($str, '-_', '+/'), strlen($str) % 4, '=', STR_PAD_RIGHT);
- return base64_decode($str);
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_ldap_generic.php b/lib/ext/Roundcube/rcube_ldap_generic.php
deleted file mode 100644
index a76ad6d..0000000
--- a/lib/ext/Roundcube/rcube_ldap_generic.php
+++ /dev/null
@@ -1,322 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | Roundcube/rcube_ldap_generic.php |
- | |
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2006-2014, The Roundcube Dev Team |
- | Copyright (C) 2012-2014, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Provide basic functionality for accessing LDAP directories |
- | |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Aleksander Machniak <machniak@kolabsys.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Model class to access an LDAP directories
- *
- * @package Framework
- * @subpackage LDAP
- */
-class rcube_ldap_generic extends Net_LDAP3
-{
- /** private properties */
- protected $cache = null;
- protected $attributes = array('dn');
- protected $error;
-
- function __construct($config = null)
- {
- parent::__construct($config);
-
- $this->config_set('log_hook', array($this, 'log'));
- }
-
- /**
- * Establish a connection to the LDAP server
- */
- public function connect($host = null)
- {
- // Net_LDAP3 does not support IDNA yet
- // also parse_host() here is very Roundcube specific
- $host = rcube_utils::idn_to_ascii(rcube_utils::parse_host($host));
-
- return parent::connect($host);
- }
-
- /**
- * Get a specific LDAP entry, identified by its DN
- *
- * @param string $dn Record identifier
- *
- * @return array Hash array
- */
- function get_entry($dn)
- {
- return parent::get_entry($dn, $this->attributes);
- }
-
- /**
- * Prints debug/error info to the log
- */
- public function log($level, $msg)
- {
- $msg = implode("\n", $msg);
-
- switch ($level) {
- case LOG_DEBUG:
- case LOG_INFO:
- case LOG_NOTICE:
- if ($this->config['debug']) {
- rcube::write_log('ldap', $msg);
- }
- break;
-
- case LOG_EMERGE:
- case LOG_ALERT:
- case LOG_CRIT:
- rcube::raise_error($msg, true, true);
- break;
-
- case LOG_ERR:
- case LOG_WARNING:
- $this->error = $msg;
- rcube::raise_error($msg, true, false);
- break;
- }
- }
-
- /**
- * Returns the last LDAP error occurred
- *
- * @return mixed Error message string or null if no error occured
- */
- function get_error()
- {
- return $this->error;
- }
-
- /**
- * @deprecated
- */
- public function set_debug($dbg = true)
- {
- $this->config['debug'] = (bool) $dbg;
- }
-
- /**
- * @deprecated
- */
- public function set_cache($cache_engine)
- {
- $this->config['cache'] = $cache_engine;
- }
-
- /**
- * @deprecated
- */
- public static function scope2func($scope, &$ns_function = null)
- {
- return self::scope_to_function($scope, $ns_function);
- }
-
- /**
- * @deprecated
- */
- public function set_config($opt, $val = null)
- {
- $this->config_set($opt, $val);
- }
-
- /**
- * @deprecated
- */
- public function add($dn, $entry)
- {
- return $this->add_entry($dn, $entry);
- }
-
- /**
- * @deprecated
- */
- public function delete($dn)
- {
- return $this->delete_entry($dn);
- }
-
- /**
- * Wrapper for ldap_mod_replace()
- *
- * @see ldap_mod_replace()
- */
- public function mod_replace($dn, $entry)
- {
- $this->_debug("C: Replace $dn: ".print_r($entry, true));
-
- if (!ldap_mod_replace($this->conn, $dn, $entry)) {
- $this->_error("ldap_mod_replace() failed with " . ldap_error($this->conn));
- return false;
- }
-
- $this->_debug("S: OK");
- return true;
- }
-
- /**
- * Wrapper for ldap_mod_add()
- *
- * @see ldap_mod_add()
- */
- public function mod_add($dn, $entry)
- {
- $this->_debug("C: Add $dn: ".print_r($entry, true));
-
- if (!ldap_mod_add($this->conn, $dn, $entry)) {
- $this->_error("ldap_mod_add() failed with " . ldap_error($this->conn));
- return false;
- }
-
- $this->_debug("S: OK");
- return true;
- }
-
- /**
- * Wrapper for ldap_mod_del()
- *
- * @see ldap_mod_del()
- */
- public function mod_del($dn, $entry)
- {
- $this->_debug("C: Delete $dn: ".print_r($entry, true));
-
- if (!ldap_mod_del($this->conn, $dn, $entry)) {
- $this->_error("ldap_mod_del() failed with " . ldap_error($this->conn));
- return false;
- }
-
- $this->_debug("S: OK");
- return true;
- }
-
- /**
- * Wrapper for ldap_rename()
- *
- * @see ldap_rename()
- */
- public function rename($dn, $newrdn, $newparent = null, $deleteoldrdn = true)
- {
- $this->_debug("C: Rename $dn to $newrdn");
-
- if (!ldap_rename($this->conn, $dn, $newrdn, $newparent, $deleteoldrdn)) {
- $this->_error("ldap_rename() failed with " . ldap_error($this->conn));
- return false;
- }
-
- $this->_debug("S: OK");
- return true;
- }
-
- /**
- * Wrapper for ldap_list() + ldap_get_entries()
- *
- * @see ldap_list()
- * @see ldap_get_entries()
- */
- public function list_entries($dn, $filter, $attributes = array('dn'))
- {
- $list = array();
- $this->_debug("C: List $dn [{$filter}]");
-
- if ($result = ldap_list($this->conn, $dn, $filter, $attributes)) {
- $list = ldap_get_entries($this->conn, $result);
-
- if ($list === false) {
- $this->_error("ldap_get_entries() failed with " . ldap_error($this->conn));
- return array();
- }
-
- $count = $list['count'];
- unset($list['count']);
-
- $this->_debug("S: $count record(s)");
- }
- else {
- $this->_error("ldap_list() failed with " . ldap_error($this->conn));
- }
-
- return $list;
- }
-
- /**
- * Wrapper for ldap_read() + ldap_get_entries()
- *
- * @see ldap_read()
- * @see ldap_get_entries()
- */
- public function read_entries($dn, $filter, $attributes = null)
- {
- $this->_debug("C: Read $dn [{$filter}]");
-
- if ($this->conn && $dn) {
- $result = @ldap_read($this->conn, $dn, $filter, $attributes, 0, (int)$this->config['sizelimit'], (int)$this->config['timelimit']);
- if ($result === false) {
- $this->_error("ldap_read() failed with " . ldap_error($this->conn));
- return false;
- }
-
- $this->_debug("S: OK");
- return ldap_get_entries($this->conn, $result);
- }
-
- return false;
- }
-
- /**
- * Turn an LDAP entry into a regular PHP array with attributes as keys.
- *
- * @param array $entry Attributes array as retrieved from ldap_get_attributes() or ldap_get_entries()
- *
- * @return array Hash array with attributes as keys
- */
- public static function normalize_entry($entry)
- {
- if (!isset($entry['count'])) {
- return $entry;
- }
-
- $rec = array();
-
- for ($i=0; $i < $entry['count']; $i++) {
- $attr = $entry[$i];
- if ($entry[$attr]['count'] == 1) {
- switch ($attr) {
- case 'objectclass':
- $rec[$attr] = array(strtolower($entry[$attr][0]));
- break;
- default:
- $rec[$attr] = $entry[$attr][0];
- break;
- }
- }
- else {
- for ($j=0; $j < $entry[$attr]['count']; $j++) {
- $rec[$attr][$j] = $entry[$attr][$j];
- }
- }
- }
-
- return $rec;
- }
-}
-
-// for backward compat.
-class rcube_ldap_result extends Net_LDAP3_Result {}
diff --git a/lib/ext/Roundcube/rcube_ldap_result.php b/lib/ext/Roundcube/rcube_ldap_result.php
deleted file mode 100644
index efc3331..0000000
--- a/lib/ext/Roundcube/rcube_ldap_result.php
+++ /dev/null
@@ -1,130 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | Roundcube/rcube_ldap_result.php |
- | |
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2006-2013, The Roundcube Dev Team |
- | Copyright (C) 2013, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Model class that represents an LDAP search result |
- | |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-
-/**
- * Model class representing an LDAP search result
- *
- * @package Framework
- * @subpackage LDAP
- */
-class rcube_ldap_result implements Iterator
-{
- public $conn;
- public $ldap;
- public $base_dn;
- public $filter;
-
- private $count = null;
- private $current = null;
- private $iteratorkey = 0;
-
- /**
- * Default constructor
- *
- * @param resource $conn LDAP link identifier
- * @param resource $ldap LDAP result entry identifier
- * @param string $base_dn Base DN used to get this result
- * @param string $filter Filter query used to get this result
- * @param integer $count Record count value (pre-calculated)
- */
- function __construct($conn, $ldap, $base_dn, $filter, $count = null)
- {
- $this->conn = $conn;
- $this->ldap = $ldap;
- $this->base_dn = $base_dn;
- $this->filter = $filter;
- $this->count = $count;
- }
-
- /**
- * Wrapper for ldap_sort()
- */
- public function sort($attr)
- {
- return ldap_sort($this->conn, $this->ldap, $attr);
- }
-
- /**
- * Get entries count
- */
- public function count()
- {
- if (!isset($this->count))
- $this->count = ldap_count_entries($this->conn, $this->ldap);
-
- return $this->count;
- }
-
- /**
- * Wrapper for ldap_get_entries()
- *
- * @param boolean $normalize Optionally normalize the entries to a list of hash arrays
- * @return array List of LDAP entries
- */
- public function entries($normalize = false)
- {
- $entries = ldap_get_entries($this->conn, $this->ldap);
- return $normalize ? rcube_ldap_generic::normalize_result($entries) : $entries;
- }
-
- /**
- * Wrapper for ldap_get_dn() using the current entry pointer
- */
- public function get_dn()
- {
- return $this->current ? ldap_get_dn($this->conn, $this->current) : null;
- }
-
-
- /*** Implements the PHP 5 Iterator interface to make foreach work ***/
-
- function current()
- {
- $attrib = ldap_get_attributes($this->conn, $this->current);
- $attrib['dn'] = ldap_get_dn($this->conn, $this->current);
- return $attrib;
- }
-
- function key()
- {
- return $this->iteratorkey;
- }
-
- function rewind()
- {
- $this->iteratorkey = 0;
- $this->current = ldap_first_entry($this->conn, $this->ldap);
- }
-
- function next()
- {
- $this->iteratorkey++;
- $this->current = ldap_next_entry($this->conn, $this->current);
- }
-
- function valid()
- {
- return (bool)$this->current;
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_message.php b/lib/ext/Roundcube/rcube_message.php
deleted file mode 100644
index 169d00c..0000000
--- a/lib/ext/Roundcube/rcube_message.php
+++ /dev/null
@@ -1,1006 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2014, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Logical representation of a mail message with all its data |
- | and related functions |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Logical representation of a mail message with all its data
- * and related functions
- *
- * @package Framework
- * @subpackage Storage
- * @author Thomas Bruederli <roundcube@gmail.com>
- */
-class rcube_message
-{
- /**
- * Instace of framework class.
- *
- * @var rcube
- */
- private $app;
-
- /**
- * Instance of storage class
- *
- * @var rcube_storage
- */
- private $storage;
-
- /**
- * Instance of mime class
- *
- * @var rcube_mime
- */
- private $mime;
- private $opt = array();
- private $parse_alternative = false;
-
- public $uid;
- public $folder;
- public $headers;
- public $parts = array();
- public $mime_parts = array();
- public $inline_parts = array();
- public $attachments = array();
- public $subject = '';
- public $sender = null;
- public $is_safe = false;
-
- const BODY_MAX_SIZE = 1048576; // 1MB
-
-
- /**
- * __construct
- *
- * Provide a uid, and parse message structure.
- *
- * @param string $uid The message UID.
- * @param string $folder Folder name
- *
- * @see self::$app, self::$storage, self::$opt, self::$parts
- */
- function __construct($uid, $folder = null)
- {
- // decode combined UID-folder identifier
- if (preg_match('/^\d+-.+/', $uid)) {
- list($uid, $folder) = explode('-', $uid, 2);
- }
-
- $this->uid = $uid;
- $this->app = rcube::get_instance();
- $this->storage = $this->app->get_storage();
- $this->folder = strlen($folder) ? $folder : $this->storage->get_folder();
- $this->storage->set_options(array('all_headers' => true));
-
- // Set current folder
- $this->storage->set_folder($this->folder);
-
- $this->headers = $this->storage->get_message($uid);
-
- if (!$this->headers) {
- return;
- }
-
- $this->mime = new rcube_mime($this->headers->charset);
-
- $this->subject = $this->headers->get('subject');
- list(, $this->sender) = each($this->mime->decode_address_list($this->headers->from, 1));
-
- $this->set_safe((intval($_GET['_safe']) || $_SESSION['safe_messages'][$this->folder.':'.$uid]));
- $this->opt = array(
- 'safe' => $this->is_safe,
- 'prefer_html' => $this->app->config->get('prefer_html'),
- 'get_url' => $this->app->url(array(
- 'action' => 'get',
- 'mbox' => $this->storage->get_folder(),
- 'uid' => $uid))
- );
-
- if (!empty($this->headers->structure)) {
- $this->get_mime_numbers($this->headers->structure);
- $this->parse_structure($this->headers->structure);
- }
- else {
- $this->body = $this->storage->get_body($uid);
- }
-
- // notify plugins and let them analyze this structured message object
- $this->app->plugins->exec_hook('message_load', array('object' => $this));
- }
-
-
- /**
- * Return a (decoded) message header
- *
- * @param string $name Header name
- * @param bool $row Don't mime-decode the value
- * @return string Header value
- */
- public function get_header($name, $raw = false)
- {
- if (empty($this->headers)) {
- return null;
- }
-
- return $this->headers->get($name, !$raw);
- }
-
-
- /**
- * Set is_safe var and session data
- *
- * @param bool $safe enable/disable
- */
- public function set_safe($safe = true)
- {
- $_SESSION['safe_messages'][$this->folder.':'.$this->uid] = $this->is_safe = $safe;
- }
-
-
- /**
- * Compose a valid URL for getting a message part
- *
- * @param string $mime_id Part MIME-ID
- * @param mixed $embed Mimetype class for parts to be embedded
- * @return string URL or false if part does not exist
- */
- public function get_part_url($mime_id, $embed = false)
- {
- if ($this->mime_parts[$mime_id])
- return $this->opt['get_url'] . '&_part=' . $mime_id . ($embed ? '&_embed=1&_mimeclass=' . $embed : '');
- else
- return false;
- }
-
-
- /**
- * Get content of a specific part of this message
- *
- * @param string $mime_id Part MIME-ID
- * @param resource $fp File pointer to save the message part
- * @param boolean $skip_charset_conv Disables charset conversion
- * @param int $max_bytes Only read this number of bytes
- * @param boolean $formatted Enables formatting of text/* parts bodies
- *
- * @return string Part content
- * @deprecated
- */
- public function get_part_content($mime_id, $fp = null, $skip_charset_conv = false, $max_bytes = 0, $formatted = true)
- {
- if ($part = $this->mime_parts[$mime_id]) {
- // stored in message structure (winmail/inline-uuencode)
- if (!empty($part->body) || $part->encoding == 'stream') {
- if ($fp) {
- fwrite($fp, $part->body);
- }
- return $fp ? true : $part->body;
- }
-
- // get from IMAP
- $this->storage->set_folder($this->folder);
-
- return $this->storage->get_message_part($this->uid, $mime_id, $part,
- NULL, $fp, $skip_charset_conv, $max_bytes, $formatted);
- }
- }
-
-
- /**
- * Get content of a specific part of this message
- *
- * @param string $mime_id Part ID
- * @param boolean $formatted Enables formatting of text/* parts bodies
- * @param int $max_bytes Only return/read this number of bytes
- * @param mixed $mode NULL to return a string, -1 to print body
- * or file pointer to save the body into
- *
- * @return string|bool Part content or operation status
- */
- public function get_part_body($mime_id, $formatted = false, $max_bytes = 0, $mode = null)
- {
- if (!($part = $this->mime_parts[$mime_id])) {
- return;
- }
-
- // only text parts can be formatted
- $formatted = $formatted && $part->ctype_primary == 'text';
-
- // part body not fetched yet... save in memory if it's small enough
- if ($part->body === null && is_numeric($mime_id) && $part->size < self::BODY_MAX_SIZE) {
- $this->storage->set_folder($this->folder);
- // Warning: body here should be always unformatted
- $part->body = $this->storage->get_message_part($this->uid, $mime_id, $part,
- null, null, true, 0, false);
- }
-
- // body stored in message structure (winmail/inline-uuencode)
- if ($part->body !== null || $part->encoding == 'stream') {
- $body = $part->body;
-
- if ($formatted && $body) {
- $body = self::format_part_body($body, $part, $this->headers->charset);
- }
-
- if ($max_bytes && strlen($body) > $max_bytes) {
- $body = substr($body, 0, $max_bytes);
- }
-
- if (is_resource($mode)) {
- if ($body !== false) {
- fwrite($mode, $body);
- rewind($mode);
- }
-
- return $body !== false;
- }
-
- if ($mode === -1) {
- if ($body !== false) {
- print($body);
- }
-
- return $body !== false;
- }
-
- return $body;
- }
-
- // get the body from IMAP
- $this->storage->set_folder($this->folder);
-
- $body = $this->storage->get_message_part($this->uid, $mime_id, $part,
- $mode === -1, is_resource($mode) ? $mode : null,
- !($mode && $formatted), $max_bytes, $mode && $formatted);
-
- if (is_resource($mode)) {
- rewind($mode);
- return $body !== false;
- }
-
- if (!$mode && $body && $formatted) {
- $body = self::format_part_body($body, $part, $this->headers->charset);
- }
-
- return $body;
- }
-
-
- /**
- * Format text message part for display
- *
- * @param string $body Part body
- * @param rcube_message_part $part Part object
- * @param string $default_charset Fallback charset if part charset is not specified
- *
- * @return string Formatted body
- */
- public static function format_part_body($body, $part, $default_charset = null)
- {
- // remove useless characters
- $body = preg_replace('/[\t\r\0\x0B]+\n/', "\n", $body);
-
- // remove NULL characters if any (#1486189)
- if (strpos($body, "\x00") !== false) {
- $body = str_replace("\x00", '', $body);
- }
-
- // detect charset...
- if (!$part->charset || strtoupper($part->charset) == 'US-ASCII') {
- // try to extract charset information from HTML meta tag (#1488125)
- if ($part->ctype_secondary == 'html' && preg_match('/<meta[^>]+charset=([a-z0-9-_]+)/i', $body, $m)) {
- $part->charset = strtoupper($m[1]);
- }
- else if ($default_charset) {
- $part->charset = $default_charset;
- }
- else {
- $rcube = rcube::get_instance();
- $part->charset = $rcube->config->get('default_charset', RCUBE_CHARSET);
- }
- }
-
- // ..convert charset encoding
- $body = rcube_charset::convert($body, $part->charset);
-
- return $body;
- }
-
-
- /**
- * Determine if the message contains a HTML part. This must to be
- * a real part not an attachment (or its part)
- *
- * @param bool $enriched Enables checking for text/enriched parts too
- *
- * @return bool True if a HTML is available, False if not
- */
- function has_html_part($enriched = false)
- {
- // check all message parts
- foreach ($this->mime_parts as $part) {
- if ($part->mimetype == 'text/html' || ($enriched && $part->mimetype == 'text/enriched')) {
- // Skip if part is an attachment, don't use is_attachment() here
- if ($part->filename) {
- continue;
- }
-
- $level = explode('.', $part->mime_id);
- $depth = count($level);
-
- // Check if the part belongs to higher-level's multipart part
- // this can be alternative/related/signed/encrypted or mixed
- while (array_pop($level) !== null) {
- $parent_depth = count($level);
- if (!$parent_depth) {
- return true;
- }
-
- $parent = $this->mime_parts[join('.', $level)];
- if (!preg_match('/^multipart\/(alternative|related|signed|encrypted|mixed)$/', $parent->mimetype)
- || ($parent->mimetype == 'multipart/mixed' && $parent_depth < $depth - 1)) {
- continue 2;
- }
- }
-
- if ($part->size) {
- return true;
- }
- }
- }
-
- return false;
- }
-
-
- /**
- * Determine if the message contains a text/plain part. This must to be
- * a real part not an attachment (or its part)
- *
- * @return bool True if a plain text part is available, False if not
- */
- function has_text_part()
- {
- // check all message parts
- foreach ($this->mime_parts as $part) {
- if ($part->mimetype == 'text/plain') {
- // Skip if part is an attachment, don't use is_attachment() here
- if ($part->filename) {
- continue;
- }
-
- $level = explode('.', $part->mime_id);
-
- // Check if the part belongs to higher-level's alternative/related
- while (array_pop($level) !== null) {
- if (!count($level)) {
- return true;
- }
-
- $parent = $this->mime_parts[join('.', $level)];
- if ($parent->mimetype != 'multipart/alternative' && $parent->mimetype != 'multipart/related') {
- continue 2;
- }
- }
-
- if ($part->size) {
- return true;
- }
- }
- }
-
- return false;
- }
-
-
- /**
- * Return the first HTML part of this message
- *
- * @return string HTML message part content
- */
- function first_html_part()
- {
- // check all message parts
- foreach ($this->mime_parts as $pid => $part) {
- if ($part->mimetype == 'text/html') {
- return $this->get_part_body($pid, true);
- }
- }
- }
-
-
- /**
- * Return the first text part of this message
- *
- * @param rcube_message_part $part Reference to the part if found
- * @return string Plain text message/part content
- */
- function first_text_part(&$part=null)
- {
- // no message structure, return complete body
- if (empty($this->parts))
- return $this->body;
-
- // check all message parts
- foreach ($this->mime_parts as $mime_id => $part) {
- if ($part->mimetype == 'text/plain') {
- return $this->get_part_body($mime_id, true);
- }
- else if ($part->mimetype == 'text/html') {
- $out = $this->get_part_body($mime_id, true);
-
- // create instance of html2text class
- $txt = new rcube_html2text($out);
- return $txt->get_text();
- }
- }
-
- $part = null;
- return null;
- }
-
-
- /**
- * Checks if part of the message is an attachment (or part of it)
- *
- * @param rcube_message_part $part Message part
- *
- * @return bool True if the part is an attachment part
- */
- public function is_attachment($part)
- {
- foreach ($this->attachments as $att_part) {
- if ($att_part->mime_id == $part->mime_id) {
- return true;
- }
-
- // check if the part is a subpart of another attachment part (message/rfc822)
- if ($att_part->mimetype == 'message/rfc822') {
- if (in_array($part, (array)$att_part->parts)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
-
- /**
- * Read the message structure returend by the IMAP server
- * and build flat lists of content parts and attachments
- *
- * @param rcube_message_part $structure Message structure node
- * @param bool $recursive True when called recursively
- */
- private function parse_structure($structure, $recursive = false)
- {
- // real content-type of message/rfc822 part
- if ($structure->mimetype == 'message/rfc822' && $structure->real_mimetype) {
- $mimetype = $structure->real_mimetype;
-
- // parse headers from message/rfc822 part
- if (!isset($structure->headers['subject']) && !isset($structure->headers['from'])) {
- list($headers, ) = explode("\r\n\r\n", $this->get_part_body($structure->mime_id, false, 32768));
- $structure->headers = rcube_mime::parse_headers($headers);
- }
- }
- else
- $mimetype = $structure->mimetype;
-
- // show message headers
- if ($recursive && is_array($structure->headers) &&
- (isset($structure->headers['subject']) || $structure->headers['from'] || $structure->headers['to'])) {
- $c = new stdClass;
- $c->type = 'headers';
- $c->headers = $structure->headers;
- $this->parts[] = $c;
- }
-
- // Allow plugins to handle message parts
- $plugin = $this->app->plugins->exec_hook('message_part_structure',
- array('object' => $this, 'structure' => $structure,
- 'mimetype' => $mimetype, 'recursive' => $recursive));
-
- if ($plugin['abort'])
- return;
-
- $structure = $plugin['structure'];
- list($message_ctype_primary, $message_ctype_secondary) = explode('/', $plugin['mimetype']);
-
- // print body if message doesn't have multiple parts
- if ($message_ctype_primary == 'text' && !$recursive) {
- // parts with unsupported type add to attachments list
- if (!in_array($message_ctype_secondary, array('plain', 'html', 'enriched'))) {
- $this->attachments[] = $structure;
- return;
- }
-
- $structure->type = 'content';
- $this->parts[] = $structure;
-
- // Parse simple (plain text) message body
- if ($message_ctype_secondary == 'plain') {
- foreach ((array)$this->uu_decode($structure) as $uupart) {
- $this->mime_parts[$uupart->mime_id] = $uupart;
- $this->attachments[] = $uupart;
- }
- }
- }
- // the same for pgp signed messages
- else if ($mimetype == 'application/pgp' && !$recursive) {
- $structure->type = 'content';
- $this->parts[] = $structure;
- }
- // message contains (more than one!) alternative parts
- else if ($mimetype == 'multipart/alternative'
- && is_array($structure->parts) && count($structure->parts) > 1
- ) {
- $plain_part = null;
- $html_part = null;
- $print_part = null;
- $related_part = null;
- $attach_part = null;
-
- // get html/plaintext parts, other add to attachments list
- foreach ($structure->parts as $p => $sub_part) {
- $sub_mimetype = $sub_part->mimetype;
- $is_multipart = preg_match('/^multipart\/(related|relative|mixed|alternative)/', $sub_mimetype);
-
- // skip empty text parts
- if (!$sub_part->size && !$is_multipart) {
- continue;
- }
-
- // We've encountered (malformed) messages with more than
- // one text/plain or text/html part here. There's no way to choose
- // which one is better, so we'll display first of them and add
- // others as attachments (#1489358)
-
- // check if sub part is
- if ($is_multipart)
- $related_part = $p;
- else if ($sub_mimetype == 'text/plain' && !$plain_part)
- $plain_part = $p;
- else if ($sub_mimetype == 'text/html' && !$html_part)
- $html_part = $p;
- else if ($sub_mimetype == 'text/enriched' && !$enriched_part)
- $enriched_part = $p;
- else {
- // add unsupported/unrecognized parts to attachments list
- $this->attachments[] = $sub_part;
- }
- }
-
- // parse related part (alternative part could be in here)
- if ($related_part !== null && !$this->parse_alternative) {
- $this->parse_alternative = true;
- $this->parse_structure($structure->parts[$related_part], true);
- $this->parse_alternative = false;
-
- // if plain part was found, we should unset it if html is preferred
- if ($this->opt['prefer_html'] && count($this->parts))
- $plain_part = null;
- }
-
- // choose html/plain part to print
- if ($html_part !== null && $this->opt['prefer_html']) {
- $print_part = $structure->parts[$html_part];
- }
- else if ($enriched_part !== null) {
- $print_part = $structure->parts[$enriched_part];
- }
- else if ($plain_part !== null) {
- $print_part = $structure->parts[$plain_part];
- }
-
- // add the right message body
- if (is_object($print_part)) {
- $print_part->type = 'content';
- $this->parts[] = $print_part;
- }
- // show plaintext warning
- else if ($html_part !== null && empty($this->parts)) {
- $c = new stdClass;
- $c->type = 'content';
- $c->ctype_primary = 'text';
- $c->ctype_secondary = 'plain';
- $c->mimetype = 'text/plain';
- $c->realtype = 'text/html';
-
- $this->parts[] = $c;
- }
- }
- // this is an ecrypted message -> create a plaintext body with the according message
- else if ($mimetype == 'multipart/encrypted') {
- $p = new stdClass;
- $p->type = 'content';
- $p->ctype_primary = 'text';
- $p->ctype_secondary = 'plain';
- $p->mimetype = 'text/plain';
- $p->realtype = 'multipart/encrypted';
-
- $this->parts[] = $p;
- }
- // this is an S/MIME ecrypted message -> create a plaintext body with the according message
- else if ($mimetype == 'application/pkcs7-mime') {
- $p = new stdClass;
- $p->type = 'content';
- $p->ctype_primary = 'text';
- $p->ctype_secondary = 'plain';
- $p->mimetype = 'text/plain';
- $p->realtype = 'application/pkcs7-mime';
-
- $this->parts[] = $p;
- }
- // message contains multiple parts
- else if (is_array($structure->parts) && !empty($structure->parts)) {
- // iterate over parts
- for ($i=0; $i < count($structure->parts); $i++) {
- $mail_part = &$structure->parts[$i];
- $primary_type = $mail_part->ctype_primary;
- $secondary_type = $mail_part->ctype_secondary;
-
- // real content-type of message/rfc822
- if ($mail_part->real_mimetype) {
- $part_orig_mimetype = $mail_part->mimetype;
- $part_mimetype = $mail_part->real_mimetype;
- list($primary_type, $secondary_type) = explode('/', $part_mimetype);
- }
- else {
- $part_mimetype = $part_orig_mimetype = $mail_part->mimetype;
- }
-
- // multipart/alternative
- if ($primary_type == 'multipart') {
- $this->parse_structure($mail_part, true);
-
- // list message/rfc822 as attachment as well (mostly .eml)
- if ($part_orig_mimetype == 'message/rfc822' && !empty($mail_part->filename))
- $this->attachments[] = $mail_part;
- }
- // part text/[plain|html] or delivery status
- else if ((($part_mimetype == 'text/plain' || $part_mimetype == 'text/html') && $mail_part->disposition != 'attachment') ||
- in_array($part_mimetype, array('message/delivery-status', 'text/rfc822-headers', 'message/disposition-notification'))
- ) {
- // Allow plugins to handle also this part
- $plugin = $this->app->plugins->exec_hook('message_part_structure',
- array('object' => $this, 'structure' => $mail_part,
- 'mimetype' => $part_mimetype, 'recursive' => true));
-
- if ($plugin['abort'])
- continue;
-
- if ($part_mimetype == 'text/html' && $mail_part->size) {
- $got_html_part = true;
- }
-
- $mail_part = $plugin['structure'];
- list($primary_type, $secondary_type) = explode('/', $plugin['mimetype']);
-
- // add text part if it matches the prefs
- if (!$this->parse_alternative ||
- ($secondary_type == 'html' && $this->opt['prefer_html']) ||
- ($secondary_type == 'plain' && !$this->opt['prefer_html'])
- ) {
- $mail_part->type = 'content';
- $this->parts[] = $mail_part;
- }
-
- // list as attachment as well
- if (!empty($mail_part->filename)) {
- $this->attachments[] = $mail_part;
- }
- }
- // part message/*
- else if ($primary_type == 'message') {
- $this->parse_structure($mail_part, true);
-
- // list as attachment as well (mostly .eml)
- if (!empty($mail_part->filename))
- $this->attachments[] = $mail_part;
- }
- // ignore "virtual" protocol parts
- else if ($primary_type == 'protocol') {
- continue;
- }
- // part is Microsoft Outlook TNEF (winmail.dat)
- else if ($part_mimetype == 'application/ms-tnef') {
- foreach ((array)$this->tnef_decode($mail_part) as $tpart) {
- $this->mime_parts[$tpart->mime_id] = $tpart;
- $this->attachments[] = $tpart;
- }
- }
- // part is a file/attachment
- else if (preg_match('/^(inline|attach)/', $mail_part->disposition) ||
- $mail_part->headers['content-id'] ||
- ($mail_part->filename &&
- (empty($mail_part->disposition) || preg_match('/^[a-z0-9!#$&.+^_-]+$/i', $mail_part->disposition)))
- ) {
- // skip apple resource forks
- if ($message_ctype_secondary == 'appledouble' && $secondary_type == 'applefile')
- continue;
-
- // part belongs to a related message and is linked
- if (preg_match('/^multipart\/(related|relative)/', $mimetype)
- && ($mail_part->headers['content-id'] || $mail_part->headers['content-location'])) {
- if ($mail_part->headers['content-id'])
- $mail_part->content_id = preg_replace(array('/^</', '/>$/'), '', $mail_part->headers['content-id']);
- if ($mail_part->headers['content-location'])
- $mail_part->content_location = $mail_part->headers['content-base'] . $mail_part->headers['content-location'];
-
- $this->inline_parts[] = $mail_part;
- }
- // attachment encapsulated within message/rfc822 part needs further decoding (#1486743)
- else if ($part_orig_mimetype == 'message/rfc822') {
- $this->parse_structure($mail_part, true);
-
- // list as attachment as well (mostly .eml)
- if (!empty($mail_part->filename))
- $this->attachments[] = $mail_part;
- }
- // regular attachment with valid content type
- // (content-type name regexp according to RFC4288.4.2)
- else if (preg_match('/^[a-z0-9!#$&.+^_-]+\/[a-z0-9!#$&.+^_-]+$/i', $part_mimetype)) {
- $this->attachments[] = $mail_part;
- }
- // attachment with invalid content type
- // replace malformed content type with application/octet-stream (#1487767)
- else if ($mail_part->filename) {
- $mail_part->ctype_primary = 'application';
- $mail_part->ctype_secondary = 'octet-stream';
- $mail_part->mimetype = 'application/octet-stream';
-
- $this->attachments[] = $mail_part;
- }
- }
- // attachment part as message/rfc822 (#1488026)
- else if ($mail_part->mimetype == 'message/rfc822') {
- $this->parse_structure($mail_part);
- }
- }
-
- // if this was a related part try to resolve references
- if (preg_match('/^multipart\/(related|relative)/', $mimetype) && sizeof($this->inline_parts)) {
- $a_replaces = array();
- $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, $inline_object->ctype_primary);
- if (isset($inline_object->content_id))
- $a_replaces['cid:'.$inline_object->content_id] = $part_url;
- if ($inline_object->content_location) {
- $a_replaces[$inline_object->content_location] = $part_url;
- }
-
- if (!empty($inline_object->filename)) {
- // MS Outlook sends sometimes non-related attachments as related
- // In this case multipart/related message has only one text part
- // We'll add all such attachments to the attachments list
- if (!isset($got_html_part) && empty($inline_object->content_id)) {
- $this->attachments[] = $inline_object;
- }
- // MS Outlook sometimes also adds non-image attachments as related
- // We'll add all such attachments to the attachments list
- // Warning: some browsers support pdf in <img/>
- else if (!preg_match($img_regexp, $inline_object->mimetype)) {
- $this->attachments[] = $inline_object;
- }
- // @TODO: we should fetch HTML body and find attachment's content-id
- // to handle also image attachments without reference in the body
- // @TODO: should we list all image attachments in text mode?
- }
- }
-
- // add replace array to each content part
- // (will be applied later when part body is available)
- foreach ($this->parts as $i => $part) {
- if ($part->type == 'content')
- $this->parts[$i]->replaces = $a_replaces;
- }
- }
- }
- // message is a single part non-text
- else if ($structure->filename) {
- $this->attachments[] = $structure;
- }
- // message is a single part non-text (without filename)
- else if (preg_match('/application\//i', $mimetype)) {
- $this->attachments[] = $structure;
- }
- }
-
-
- /**
- * Fill aflat array with references to all parts, indexed by part numbers
- *
- * @param rcube_message_part $part Message body structure
- */
- private function get_mime_numbers(&$part)
- {
- if (strlen($part->mime_id))
- $this->mime_parts[$part->mime_id] = &$part;
-
- if (is_array($part->parts))
- for ($i=0; $i<count($part->parts); $i++)
- $this->get_mime_numbers($part->parts[$i]);
- }
-
-
- /**
- * Decode a Microsoft Outlook TNEF part (winmail.dat)
- *
- * @param rcube_message_part $part Message part to decode
- * @return array
- */
- function tnef_decode(&$part)
- {
- // @TODO: attachment may be huge, handle body via file
- $body = $this->get_part_body($part->mime_id);
- $tnef = new rcube_tnef_decoder;
- $tnef_arr = $tnef->decompress($body);
- $parts = array();
-
- unset($body);
-
- foreach ($tnef_arr as $pid => $winatt) {
- $tpart = new rcube_message_part;
-
- $tpart->filename = $this->fix_attachment_name(trim($winatt['name']), $part);
- $tpart->encoding = 'stream';
- $tpart->ctype_primary = trim(strtolower($winatt['type']));
- $tpart->ctype_secondary = trim(strtolower($winatt['subtype']));
- $tpart->mimetype = $tpart->ctype_primary . '/' . $tpart->ctype_secondary;
- $tpart->mime_id = 'winmail.' . $part->mime_id . '.' . $pid;
- $tpart->size = $winatt['size'];
- $tpart->body = $winatt['stream'];
-
- $parts[] = $tpart;
- unset($tnef_arr[$pid]);
- }
-
- return $parts;
- }
-
-
- /**
- * Parse message body for UUencoded attachments bodies
- *
- * @param rcube_message_part $part Message part to decode
- * @return array
- */
- function uu_decode(&$part)
- {
- // @TODO: messages may be huge, handle body via file
- $part->body = $this->get_part_body($part->mime_id);
- $parts = array();
- $pid = 0;
-
- // FIXME: line length is max.65?
- $uu_regexp_begin = '/begin [0-7]{3,4} ([^\r\n]+)\r?\n/s';
- $uu_regexp_end = '/`\r?\nend((\r?\n)|($))/s';
-
- while (preg_match($uu_regexp_begin, $part->body, $matches, PREG_OFFSET_CAPTURE)) {
- $startpos = $matches[0][1];
-
- if (!preg_match($uu_regexp_end, $part->body, $m, PREG_OFFSET_CAPTURE, $startpos)) {
- break;
- }
-
- $endpos = $m[0][1];
- $begin_len = strlen($matches[0][0]);
- $end_len = strlen($m[0][0]);
-
- // extract attachment body
- $filebody = substr($part->body, $startpos + $begin_len, $endpos - $startpos - $begin_len - 1);
- $filebody = str_replace("\r\n", "\n", $filebody);
-
- // remove attachment body from the message body
- $part->body = substr_replace($part->body, '', $startpos, $endpos + $end_len - $startpos);
- // mark body as modified so it will not be cached by rcube_imap_cache
- $part->body_modified = true;
-
- // add attachments to the structure
- $uupart = new rcube_message_part;
- $uupart->filename = trim($matches[1][0]);
- $uupart->encoding = 'stream';
- $uupart->body = convert_uudecode($filebody);
- $uupart->size = strlen($uupart->body);
- $uupart->mime_id = 'uu.' . $part->mime_id . '.' . $pid;
-
- $ctype = rcube_mime::file_content_type($uupart->body, $uupart->filename, 'application/octet-stream', true);
- $uupart->mimetype = $ctype;
- list($uupart->ctype_primary, $uupart->ctype_secondary) = explode('/', $ctype);
-
- $parts[] = $uupart;
- $pid++;
- }
-
- return $parts;
- }
-
- /**
- * Fix attachment name encoding if needed/possible
- */
- protected function fix_attachment_name($name, $part)
- {
- if ($name == rcube_charset::clean($name)) {
- return $name;
- }
-
- // find charset from part or its parent(s)
- if ($part->charset) {
- $charsets[] = $part->charset;
- }
- else {
- // check first part (common case)
- $n = strpos($part->mime_id, '.') ? preg_replace('/\.[0-9]+$/', '', $part->mime_id) . '.1' : 1;
- if (($_part = $this->mime_parts[$n]) && $_part->charset) {
- $charsets[] = $_part->charset;
- }
-
- // check parents' charset
- $items = explode('.', $part->mime_id);
- for ($i = count($items)-1; $i > 0; $i--) {
- $last = array_pop($items);
- $parent = $this->mime_parts[join('.', $items)];
-
- if ($parent && $parent->charset) {
- $charsets[] = $parent->charset;
- }
- }
- }
-
- if ($this->headers->charset) {
- $charsets[] = $this->headers->charset;
- }
-
- if (empty($charsets)) {
- $rcube = rcube::get_instance();
- $charsets[] = rcube_charset::detect($name, $rcube->config->get('default_charset', RCUBE_CHARSET));
- }
-
- foreach (array_unique($charsets) as $charset) {
- $_name = rcube_charset::convert($name, $charset);
-
- if ($_name == rcube_charset::clean($_name)) {
- if (!$part->charset) {
- $part->charset = $charset;
- }
-
- return $_name;
- }
- }
-
- return $name;
- }
-
- /**
- * Deprecated methods (to be removed)
- */
-
- public static function unfold_flowed($text)
- {
- return rcube_mime::unfold_flowed($text);
- }
-
- public static function format_flowed($text, $length = 72)
- {
- return rcube_mime::format_flowed($text, $length);
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_message_header.php b/lib/ext/Roundcube/rcube_message_header.php
deleted file mode 100644
index 2b795e5..0000000
--- a/lib/ext/Roundcube/rcube_message_header.php
+++ /dev/null
@@ -1,325 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | Copyright (C) 2011-2012, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | E-mail message headers representation |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Struct representing an e-mail message header
- *
- * @package Framework
- * @subpackage Storage
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_message_header
-{
- /**
- * Message sequence number
- *
- * @var int
- */
- public $id;
-
- /**
- * Message unique identifier
- *
- * @var int
- */
- public $uid;
-
- /**
- * Message subject
- *
- * @var string
- */
- public $subject;
-
- /**
- * Message sender (From)
- *
- * @var string
- */
- public $from;
-
- /**
- * Message recipient (To)
- *
- * @var string
- */
- public $to;
-
- /**
- * Message additional recipients (Cc)
- *
- * @var string
- */
- public $cc;
-
- /**
- * Message Reply-To header
- *
- * @var string
- */
- public $replyto;
-
- /**
- * Message In-Reply-To header
- *
- * @var string
- */
- public $in_reply_to;
-
- /**
- * Message date (Date)
- *
- * @var string
- */
- public $date;
-
- /**
- * Message identifier (Message-ID)
- *
- * @var string
- */
- public $messageID;
-
- /**
- * Message size
- *
- * @var int
- */
- public $size;
-
- /**
- * Message encoding
- *
- * @var string
- */
- public $encoding;
-
- /**
- * Message charset
- *
- * @var string
- */
- public $charset;
-
- /**
- * Message Content-type
- *
- * @var string
- */
- public $ctype;
-
- /**
- * Message timestamp (based on message date)
- *
- * @var int
- */
- public $timestamp;
-
- /**
- * IMAP bodystructure string
- *
- * @var string
- */
- public $bodystructure;
-
- /**
- * IMAP internal date
- *
- * @var string
- */
- public $internaldate;
-
- /**
- * Message References header
- *
- * @var string
- */
- public $references;
-
- /**
- * Message priority (X-Priority)
- *
- * @var int
- */
- public $priority;
-
- /**
- * Message receipt recipient
- *
- * @var string
- */
- public $mdn_to;
-
- /**
- * IMAP folder this message is stored in
- *
- * @var string
- */
- public $folder;
-
- /**
- * Other message headers
- *
- * @var array
- */
- public $others = array();
-
- /**
- * Message flags
- *
- * @var array
- */
- public $flags = array();
-
- // map header to rcube_message_header object property
- private $obj_headers = array(
- 'date' => 'date',
- 'from' => 'from',
- 'to' => 'to',
- 'subject' => 'subject',
- 'reply-to' => 'replyto',
- 'cc' => 'cc',
- 'bcc' => 'bcc',
- 'mbox' => 'folder',
- 'folder' => 'folder',
- 'content-transfer-encoding' => 'encoding',
- 'in-reply-to' => 'in_reply_to',
- 'content-type' => 'ctype',
- 'charset' => 'charset',
- 'references' => 'references',
- 'return-receipt-to' => 'mdn_to',
- 'disposition-notification-to' => 'mdn_to',
- 'x-confirm-reading-to' => 'mdn_to',
- 'message-id' => 'messageID',
- 'x-priority' => 'priority',
- );
-
- /**
- * Returns header value
- */
- public function get($name, $decode = true)
- {
- $name = strtolower($name);
-
- if (isset($this->obj_headers[$name])) {
- $value = $this->{$this->obj_headers[$name]};
- }
- else {
- $value = $this->others[$name];
- }
-
- if ($decode) {
- if (is_array($value)) {
- foreach ($value as $key => $val) {
- $value[$key] = rcube_mime::decode_header($val, $this->charset);
- $value[$key] = rcube_charset::clean($val);
- }
- }
- else {
- $value = rcube_mime::decode_header($value, $this->charset);
- $value = rcube_charset::clean($value);
- }
- }
-
- return $value;
- }
-
- /**
- * Sets header value
- */
- public function set($name, $value)
- {
- $name = strtolower($name);
-
- if (isset($this->obj_headers[$name])) {
- $this->{$this->obj_headers[$name]} = $value;
- }
- else {
- $this->others[$name] = $value;
- }
- }
-
-
- /**
- * Factory method to instantiate headers from a data array
- *
- * @param array Hash array with header values
- * @return object rcube_message_header instance filled with headers values
- */
- public static function from_array($arr)
- {
- $obj = new rcube_message_header;
- foreach ($arr as $k => $v)
- $obj->set($k, $v);
-
- return $obj;
- }
-}
-
-
-/**
- * Class for sorting an array of rcube_message_header objects in a predetermined order.
- *
- * @package Framework
- * @subpackage Storage
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_message_header_sorter
-{
- private $uids = array();
-
-
- /**
- * Set the predetermined sort order.
- *
- * @param array $index Numerically indexed array of IMAP UIDs
- */
- function set_index($index)
- {
- $index = array_flip($index);
-
- $this->uids = $index;
- }
-
- /**
- * Sort the array of header objects
- *
- * @param array $headers Array of rcube_message_header objects indexed by UID
- */
- function sort_headers(&$headers)
- {
- uksort($headers, array($this, "compare_uids"));
- }
-
- /**
- * Sort method called by uksort()
- *
- * @param int $a Array key (UID)
- * @param int $b Array key (UID)
- */
- function compare_uids($a, $b)
- {
- // then find each sequence number in my ordered list
- $posa = isset($this->uids[$a]) ? intval($this->uids[$a]) : -1;
- $posb = isset($this->uids[$b]) ? intval($this->uids[$b]) : -1;
-
- // return the relative position as the comparison value
- return $posa - $posb;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_message_part.php b/lib/ext/Roundcube/rcube_message_part.php
deleted file mode 100644
index 4222ba3..0000000
--- a/lib/ext/Roundcube/rcube_message_part.php
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | Copyright (C) 2011-2012, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Class representing a message part |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class representing a message part
- *
- * @package Framework
- * @subpackage Storage
- * @author Thomas Bruederli <roundcube@gmail.com>
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_message_part
-{
- /**
- * Part MIME identifier
- *
- * @var string
- */
- public $mime_id = '';
-
- /**
- * Content main type
- *
- * @var string
- */
- public $ctype_primary = 'text';
-
- /**
- * Content subtype
- *
- * @var string
- */
- public $ctype_secondary = 'plain';
-
- /**
- * Complete content type
- *
- * @var string
- */
- public $mimetype = 'text/plain';
-
- public $disposition = '';
- public $filename = '';
- public $encoding = '8bit';
- public $charset = '';
-
- /**
- * Part size in bytes
- *
- * @var int
- */
- public $size = 0;
-
- /**
- * Part headers
- *
- * @var array
- */
- public $headers = array();
-
- public $d_parameters = array();
- public $ctype_parameters = array();
-
-
- /**
- * Clone handler.
- */
- function __clone()
- {
- if (isset($this->parts)) {
- foreach ($this->parts as $idx => $part) {
- if (is_object($part)) {
- $this->parts[$idx] = clone $part;
- }
- }
- }
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_mime.php b/lib/ext/Roundcube/rcube_mime.php
deleted file mode 100644
index 3f2fcc3..0000000
--- a/lib/ext/Roundcube/rcube_mime.php
+++ /dev/null
@@ -1,913 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2014, The Roundcube Dev Team |
- | Copyright (C) 2011-2014, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | MIME message parsing utilities |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class for parsing MIME messages
- *
- * @package Framework
- * @subpackage Storage
- * @author Thomas Bruederli <roundcube@gmail.com>
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_mime
-{
- private static $default_charset;
-
-
- /**
- * Object constructor.
- */
- function __construct($default_charset = null)
- {
- self::$default_charset = $default_charset;
- }
-
- /**
- * Returns message/object character set name
- *
- * @return string Characted set name
- */
- public static function get_charset()
- {
- if (self::$default_charset) {
- return self::$default_charset;
- }
-
- if ($charset = rcube::get_instance()->config->get('default_charset')) {
- return $charset;
- }
-
- return RCUBE_CHARSET;
- }
-
- /**
- * Parse the given raw message source and return a structure
- * of rcube_message_part objects.
- *
- * It makes use of the PEAR:Mail_mimeDecode library
- *
- * @param string The message source
- * @return object rcube_message_part The message structure
- */
- public static function parse_message($raw_body)
- {
- $mime = new Mail_mimeDecode($raw_body);
- $struct = $mime->decode(array('include_bodies' => true, 'decode_bodies' => true));
- return self::structure_part($struct);
- }
-
- /**
- * Recursive method to convert a Mail_mimeDecode part into a rcube_message_part object
- *
- * @param object A message part struct
- * @param int Part count
- * @param string Parent MIME ID
- *
- * @return object rcube_message_part
- */
- private static function structure_part($part, $count=0, $parent='')
- {
- $struct = new rcube_message_part;
- $struct->mime_id = $part->mime_id ?: (empty($parent) ? (string)$count : "$parent.$count");
- $struct->headers = $part->headers;
- $struct->mimetype = $part->ctype_primary . '/' . $part->ctype_secondary;
- $struct->ctype_primary = $part->ctype_primary;
- $struct->ctype_secondary = $part->ctype_secondary;
- $struct->ctype_parameters = $part->ctype_parameters;
-
- if ($part->headers['content-transfer-encoding']) {
- $struct->encoding = $part->headers['content-transfer-encoding'];
- }
-
- if ($part->ctype_parameters['charset']) {
- $struct->charset = $part->ctype_parameters['charset'];
- }
-
- $part_charset = $struct->charset ?: self::get_charset();
-
- // determine filename
- if (($filename = $part->d_parameters['filename']) || ($filename = $part->ctype_parameters['name'])) {
- $struct->filename = rcube_mime::decode_mime_string($filename, $part_charset);
- }
-
- $struct->body = $part->body;
- $struct->size = strlen($part->body);
- $struct->disposition = $part->disposition;
-
- foreach ((array)$part->parts as $child_part) {
- $struct->parts[] = self::structure_part($child_part, ++$count, $struct->mime_id);
- }
-
- return $struct;
- }
-
- /**
- * Split an address list into a structured array list
- *
- * @param string $input Input string
- * @param int $max List only this number of addresses
- * @param boolean $decode Decode address strings
- * @param string $fallback Fallback charset if none specified
- * @param boolean $addronly Return flat array with e-mail addresses only
- *
- * @return array Indexed list of addresses
- */
- static function decode_address_list($input, $max = null, $decode = true, $fallback = null, $addronly = false)
- {
- $a = self::parse_address_list($input, $decode, $fallback);
- $out = array();
- $j = 0;
-
- // Special chars as defined by RFC 822 need to in quoted string (or escaped).
- $special_chars = '[\(\)\<\>\\\.\[\]@,;:"]';
-
- if (!is_array($a))
- return $out;
-
- foreach ($a as $val) {
- $j++;
- $address = trim($val['address']);
-
- if ($addronly) {
- $out[$j] = $address;
- }
- else {
- $name = trim($val['name']);
- if ($name && $address && $name != $address)
- $string = sprintf('%s <%s>', preg_match("/$special_chars/", $name) ? '"'.addcslashes($name, '"').'"' : $name, $address);
- else if ($address)
- $string = $address;
- else if ($name)
- $string = $name;
-
- $out[$j] = array('name' => $name, 'mailto' => $address, 'string' => $string);
- }
-
- if ($max && $j==$max)
- break;
- }
-
- return $out;
- }
-
- /**
- * Decode a message header value
- *
- * @param string $input Header value
- * @param string $fallback Fallback charset if none specified
- *
- * @return string Decoded string
- */
- public static function decode_header($input, $fallback = null)
- {
- $str = self::decode_mime_string((string)$input, $fallback);
-
- return $str;
- }
-
- /**
- * Decode a mime-encoded string to internal charset
- *
- * @param string $input Header value
- * @param string $fallback Fallback charset if none specified
- *
- * @return string Decoded string
- */
- public static function decode_mime_string($input, $fallback = null)
- {
- $default_charset = !empty($fallback) ? $fallback : self::get_charset();
-
- // rfc: all line breaks or other characters not found
- // in the Base64 Alphabet must be ignored by decoding software
- // delete all blanks between MIME-lines, differently we can
- // receive unnecessary blanks and broken utf-8 symbols
- $input = preg_replace("/\?=\s+=\?/", '?==?', $input);
-
- // encoded-word regexp
- $re = '/=\?([^?]+)\?([BbQq])\?([^\n]*?)\?=/';
-
- // Find all RFC2047's encoded words
- if (preg_match_all($re, $input, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
- // Initialize variables
- $tmp = array();
- $out = '';
- $start = 0;
-
- foreach ($matches as $idx => $m) {
- $pos = $m[0][1];
- $charset = $m[1][0];
- $encoding = $m[2][0];
- $text = $m[3][0];
- $length = strlen($m[0][0]);
-
- // Append everything that is before the text to be decoded
- if ($start != $pos) {
- $substr = substr($input, $start, $pos-$start);
- $out .= rcube_charset::convert($substr, $default_charset);
- $start = $pos;
- }
- $start += $length;
-
- // Per RFC2047, each string part "MUST represent an integral number
- // of characters . A multi-octet character may not be split across
- // adjacent encoded-words." However, some mailers break this, so we
- // try to handle characters spanned across parts anyway by iterating
- // through and aggregating sequential encoded parts with the same
- // character set and encoding, then perform the decoding on the
- // aggregation as a whole.
-
- $tmp[] = $text;
- if ($next_match = $matches[$idx+1]) {
- if ($next_match[0][1] == $start
- && $next_match[1][0] == $charset
- && $next_match[2][0] == $encoding
- ) {
- continue;
- }
- }
-
- $count = count($tmp);
- $text = '';
-
- // Decode and join encoded-word's chunks
- if ($encoding == 'B' || $encoding == 'b') {
- // base64 must be decoded a segment at a time
- for ($i=0; $i<$count; $i++)
- $text .= base64_decode($tmp[$i]);
- }
- else { //if ($encoding == 'Q' || $encoding == 'q') {
- // quoted printable can be combined and processed at once
- for ($i=0; $i<$count; $i++)
- $text .= $tmp[$i];
-
- $text = str_replace('_', ' ', $text);
- $text = quoted_printable_decode($text);
- }
-
- $out .= rcube_charset::convert($text, $charset);
- $tmp = array();
- }
-
- // add the last part of the input string
- if ($start != strlen($input)) {
- $out .= rcube_charset::convert(substr($input, $start), $default_charset);
- }
-
- // return the results
- return $out;
- }
-
- // no encoding information, use fallback
- return rcube_charset::convert($input, $default_charset);
- }
-
- /**
- * Decode a mime part
- *
- * @param string $input Input string
- * @param string $encoding Part encoding
- *
- * @return string Decoded string
- */
- public static function decode($input, $encoding = '7bit')
- {
- switch (strtolower($encoding)) {
- case 'quoted-printable':
- return quoted_printable_decode($input);
- case 'base64':
- return base64_decode($input);
- case 'x-uuencode':
- case 'x-uue':
- case 'uue':
- case 'uuencode':
- return convert_uudecode($input);
- case '7bit':
- default:
- return $input;
- }
- }
-
- /**
- * Split RFC822 header string into an associative array
- */
- public static function parse_headers($headers)
- {
- $a_headers = array();
- $headers = preg_replace('/\r?\n(\t| )+/', ' ', $headers);
- $lines = explode("\n", $headers);
- $c = count($lines);
-
- for ($i=0; $i<$c; $i++) {
- if ($p = strpos($lines[$i], ': ')) {
- $field = strtolower(substr($lines[$i], 0, $p));
- $value = trim(substr($lines[$i], $p+1));
- if (!empty($value))
- $a_headers[$field] = $value;
- }
- }
-
- return $a_headers;
- }
-
- /**
- * @access private
- */
- private static function parse_address_list($str, $decode = true, $fallback = null)
- {
- // remove any newlines and carriage returns before
- $str = preg_replace('/\r?\n(\s|\t)?/', ' ', $str);
-
- // extract list items, remove comments
- $str = self::explode_header_string(',;', $str, true);
- $result = array();
-
- // simplified regexp, supporting quoted local part
- $email_rx = '(\S+|("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+"))@\S+';
-
- foreach ($str as $key => $val) {
- $name = '';
- $address = '';
- $val = trim($val);
-
- if (preg_match('/(.*)<('.$email_rx.')>$/', $val, $m)) {
- $address = $m[2];
- $name = trim($m[1]);
- }
- else if (preg_match('/^('.$email_rx.')$/', $val, $m)) {
- $address = $m[1];
- $name = '';
- }
- // special case (#1489092)
- else if (preg_match('/(\s*<MAILER-DAEMON>)$/', $val, $m)) {
- $address = 'MAILER-DAEMON';
- $name = substr($val, 0, -strlen($m[1]));
- }
- else if (preg_match('/('.$email_rx.')/', $val, $m)) {
- $name = $m[1];
- }
- else {
- $name = $val;
- }
-
- // dequote and/or decode name
- if ($name) {
- if ($name[0] == '"' && $name[strlen($name)-1] == '"') {
- $name = substr($name, 1, -1);
- $name = stripslashes($name);
- }
- if ($decode) {
- $name = self::decode_header($name, $fallback);
- // some clients encode addressee name with quotes around it
- if ($name[0] == '"' && $name[strlen($name)-1] == '"') {
- $name = substr($name, 1, -1);
- }
- }
- }
-
- if (!$address && $name) {
- $address = $name;
- $name = '';
- }
-
- if ($address) {
- $address = self::fix_email($address);
- $result[$key] = array('name' => $name, 'address' => $address);
- }
- }
-
- return $result;
- }
-
- /**
- * Explodes header (e.g. address-list) string into array of strings
- * using specified separator characters with proper handling
- * of quoted-strings and comments (RFC2822)
- *
- * @param string $separator String containing separator characters
- * @param string $str Header string
- * @param bool $remove_comments Enable to remove comments
- *
- * @return array Header items
- */
- public static function explode_header_string($separator, $str, $remove_comments = false)
- {
- $length = strlen($str);
- $result = array();
- $quoted = false;
- $comment = 0;
- $out = '';
-
- for ($i=0; $i<$length; $i++) {
- // we're inside a quoted string
- if ($quoted) {
- if ($str[$i] == '"') {
- $quoted = false;
- }
- else if ($str[$i] == "\\") {
- if ($comment <= 0) {
- $out .= "\\";
- }
- $i++;
- }
- }
- // we are inside a comment string
- else if ($comment > 0) {
- if ($str[$i] == ')') {
- $comment--;
- }
- else if ($str[$i] == '(') {
- $comment++;
- }
- else if ($str[$i] == "\\") {
- $i++;
- }
- continue;
- }
- // separator, add to result array
- else if (strpos($separator, $str[$i]) !== false) {
- if ($out) {
- $result[] = $out;
- }
- $out = '';
- continue;
- }
- // start of quoted string
- else if ($str[$i] == '"') {
- $quoted = true;
- }
- // start of comment
- else if ($remove_comments && $str[$i] == '(') {
- $comment++;
- }
-
- if ($comment <= 0) {
- $out .= $str[$i];
- }
- }
-
- if ($out && $comment <= 0) {
- $result[] = $out;
- }
-
- return $result;
- }
-
- /**
- * Interpret a format=flowed message body according to RFC 2646
- *
- * @param string $text Raw body formatted as flowed text
- * @param string $mark Mark each flowed line with specified character
- *
- * @return string Interpreted text with unwrapped lines and stuffed space removed
- */
- public static function unfold_flowed($text, $mark = null)
- {
- $text = preg_split('/\r?\n/', $text);
- $last = -1;
- $q_level = 0;
- $marks = array();
-
- foreach ($text as $idx => $line) {
- if (preg_match('/^(>+)/', $line, $m)) {
- // remove quote chars
- $q = strlen($m[1]);
- $line = preg_replace('/^>+/', '', $line);
- // remove (optional) space-staffing
- $line = preg_replace('/^ /', '', $line);
-
- // The same paragraph (We join current line with the previous one) when:
- // - the same level of quoting
- // - previous line was flowed
- // - previous line contains more than only one single space (and quote char(s))
- if ($q == $q_level
- && isset($text[$last]) && $text[$last][strlen($text[$last])-1] == ' '
- && !preg_match('/^>+ {0,1}$/', $text[$last])
- ) {
- $text[$last] .= $line;
- unset($text[$idx]);
-
- if ($mark) {
- $marks[$last] = true;
- }
- }
- else {
- $last = $idx;
- }
- }
- else {
- $q = 0;
- if ($line == '-- ') {
- $last = $idx;
- }
- else {
- // remove space-stuffing
- $line = preg_replace('/^ /', '', $line);
-
- if (isset($text[$last]) && $line
- && $text[$last] != '-- '
- && $text[$last][strlen($text[$last])-1] == ' '
- ) {
- $text[$last] .= $line;
- unset($text[$idx]);
-
- if ($mark) {
- $marks[$last] = true;
- }
- }
- else {
- $text[$idx] = $line;
- $last = $idx;
- }
- }
- }
- $q_level = $q;
- }
-
- if (!empty($marks)) {
- foreach (array_keys($marks) as $mk) {
- $text[$mk] = $mark . $text[$mk];
- }
- }
-
- return implode("\r\n", $text);
- }
-
- /**
- * Wrap the given text to comply with RFC 2646
- *
- * @param string $text Text to wrap
- * @param int $length Length
- * @param string $charset Character encoding of $text
- *
- * @return string Wrapped text
- */
- public static function format_flowed($text, $length = 72, $charset=null)
- {
- $text = preg_split('/\r?\n/', $text);
-
- foreach ($text as $idx => $line) {
- if ($line != '-- ') {
- if (preg_match('/^(>+)/', $line, $m)) {
- // remove quote chars
- $level = strlen($m[1]);
- $line = preg_replace('/^>+/', '', $line);
- // remove (optional) space-staffing and spaces before the line end
- $line = preg_replace('/(^ | +$)/', '', $line);
- $prefix = str_repeat('>', $level) . ' ';
- $line = $prefix . self::wordwrap($line, $length - $level - 2, " \r\n$prefix", false, $charset);
- }
- else if ($line) {
- $line = self::wordwrap(rtrim($line), $length - 2, " \r\n", false, $charset);
- // space-stuffing
- $line = preg_replace('/(^|\r\n)(From| |>)/', '\\1 \\2', $line);
- }
-
- $text[$idx] = $line;
- }
- }
-
- return implode("\r\n", $text);
- }
-
- /**
- * Improved wordwrap function with multibyte support.
- * The code is based on Zend_Text_MultiByte::wordWrap().
- *
- * @param string $string Text to wrap
- * @param int $width Line width
- * @param string $break Line separator
- * @param bool $cut Enable to cut word
- * @param string $charset Charset of $string
- * @param bool $wrap_quoted When enabled quoted lines will not be wrapped
- *
- * @return string Text
- */
- public static function wordwrap($string, $width=75, $break="\n", $cut=false, $charset=null, $wrap_quoted=true)
- {
- // Note: Never try to use iconv instead of mbstring functions here
- // Iconv's substr/strlen are 100x slower (#1489113)
-
- if ($charset && $charset != RCUBE_CHARSET && function_exists('mb_internal_encoding')) {
- mb_internal_encoding($charset);
- }
-
- // Convert \r\n to \n, this is our line-separator
- $string = str_replace("\r\n", "\n", $string);
- $separator = "\n"; // must be 1 character length
- $result = array();
-
- while (($stringLength = mb_strlen($string)) > 0) {
- $breakPos = mb_strpos($string, $separator, 0);
-
- // quoted line (do not wrap)
- if ($wrap_quoted && $string[0] == '>') {
- if ($breakPos === $stringLength - 1 || $breakPos === false) {
- $subString = $string;
- $cutLength = null;
- }
- else {
- $subString = mb_substr($string, 0, $breakPos);
- $cutLength = $breakPos + 1;
- }
- }
- // next line found and current line is shorter than the limit
- else if ($breakPos !== false && $breakPos < $width) {
- if ($breakPos === $stringLength - 1) {
- $subString = $string;
- $cutLength = null;
- }
- else {
- $subString = mb_substr($string, 0, $breakPos);
- $cutLength = $breakPos + 1;
- }
- }
- else {
- $subString = mb_substr($string, 0, $width);
-
- // last line
- if ($breakPos === false && $subString === $string) {
- $cutLength = null;
- }
- else {
- $nextChar = mb_substr($string, $width, 1);
-
- if ($nextChar === ' ' || $nextChar === $separator) {
- $afterNextChar = mb_substr($string, $width + 1, 1);
-
- // Note: mb_substr() does never return False
- if ($afterNextChar === false || $afterNextChar === '') {
- $subString .= $nextChar;
- }
-
- $cutLength = mb_strlen($subString) + 1;
- }
- else {
- $spacePos = mb_strrpos($subString, ' ', 0);
-
- if ($spacePos !== false) {
- $subString = mb_substr($subString, 0, $spacePos);
- $cutLength = $spacePos + 1;
- }
- else if ($cut === false) {
- $spacePos = mb_strpos($string, ' ', 0);
-
- if ($spacePos !== false && ($breakPos === false || $spacePos < $breakPos)) {
- $subString = mb_substr($string, 0, $spacePos);
- $cutLength = $spacePos + 1;
- }
- else if ($breakPos === false) {
- $subString = $string;
- $cutLength = null;
- }
- else {
- $subString = mb_substr($string, 0, $breakPos);
- $cutLength = $breakPos + 1;
- }
- }
- else {
- $cutLength = $width;
- }
- }
- }
- }
-
- $result[] = $subString;
-
- if ($cutLength !== null) {
- $string = mb_substr($string, $cutLength, ($stringLength - $cutLength));
- }
- else {
- break;
- }
- }
-
- if ($charset && $charset != RCUBE_CHARSET && function_exists('mb_internal_encoding')) {
- mb_internal_encoding(RCUBE_CHARSET);
- }
-
- return implode($break, $result);
- }
-
- /**
- * A method to guess the mime_type of an attachment.
- *
- * @param string $path Path to the file or file contents
- * @param string $name File name (with suffix)
- * @param string $failover Mime type supplied for failover
- * @param boolean $is_stream Set to True if $path contains file contents
- * @param boolean $skip_suffix Set to True if the config/mimetypes.php mappig should be ignored
- *
- * @return string
- * @author Till Klampaeckel <till@php.net>
- * @see http://de2.php.net/manual/en/ref.fileinfo.php
- * @see http://de2.php.net/mime_content_type
- */
- public static function file_content_type($path, $name, $failover = 'application/octet-stream', $is_stream = false, $skip_suffix = false)
- {
- static $mime_ext = array();
-
- $mime_type = null;
- $config = rcube::get_instance()->config;
- $mime_magic = $config->get('mime_magic');
-
- if (!$skip_suffix && empty($mime_ext)) {
- foreach ($config->resolve_paths('mimetypes.php') as $fpath) {
- $mime_ext = array_merge($mime_ext, (array) @include($fpath));
- }
- }
-
- // use file name suffix with hard-coded mime-type map
- if (!$skip_suffix && is_array($mime_ext) && $name) {
- if ($suffix = substr($name, strrpos($name, '.')+1)) {
- $mime_type = $mime_ext[strtolower($suffix)];
- }
- }
-
- // try fileinfo extension if available
- if (!$mime_type && function_exists('finfo_open')) {
- // null as a 2nd argument should be the same as no argument
- // this however is not true on all systems/versions
- if ($mime_magic) {
- $finfo = finfo_open(FILEINFO_MIME, $mime_magic);
- }
- else {
- $finfo = finfo_open(FILEINFO_MIME);
- }
-
- if ($finfo) {
- if ($is_stream)
- $mime_type = finfo_buffer($finfo, $path);
- else
- $mime_type = finfo_file($finfo, $path);
- finfo_close($finfo);
- }
- }
-
- // try PHP's mime_content_type
- if (!$mime_type && !$is_stream && function_exists('mime_content_type')) {
- $mime_type = @mime_content_type($path);
- }
-
- // fall back to user-submitted string
- if (!$mime_type) {
- $mime_type = $failover;
- }
- else {
- // Sometimes (PHP-5.3?) content-type contains charset definition,
- // Remove it (#1487122) also "charset=binary" is useless
- $mime_type = array_shift(preg_split('/[; ]/', $mime_type));
- }
-
- return $mime_type;
- }
-
- /**
- * Get mimetype => file extension mapping
- *
- * @param string Mime-Type to get extensions for
- *
- * @return array List of extensions matching the given mimetype or a hash array
- * with ext -> mimetype mappings if $mimetype is not given
- */
- public static function get_mime_extensions($mimetype = null)
- {
- static $mime_types, $mime_extensions;
-
- // return cached data
- if (is_array($mime_types)) {
- return $mimetype ? $mime_types[$mimetype] : $mime_extensions;
- }
-
- // load mapping file
- $file_paths = array();
-
- if ($mime_types = rcube::get_instance()->config->get('mime_types')) {
- $file_paths[] = $mime_types;
- }
-
- // try common locations
- if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
- $file_paths[] = 'C:/xampp/apache/conf/mime.types.';
- }
- else {
- $file_paths[] = '/etc/mime.types';
- $file_paths[] = '/etc/httpd/mime.types';
- $file_paths[] = '/etc/httpd2/mime.types';
- $file_paths[] = '/etc/apache/mime.types';
- $file_paths[] = '/etc/apache2/mime.types';
- $file_paths[] = '/etc/nginx/mime.types';
- $file_paths[] = '/usr/local/etc/httpd/conf/mime.types';
- $file_paths[] = '/usr/local/etc/apache/conf/mime.types';
- }
-
- foreach ($file_paths as $fp) {
- if (@is_readable($fp)) {
- $lines = file($fp, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
- break;
- }
- }
-
- $mime_types = $mime_extensions = array();
- $regex = "/([\w\+\-\.\/]+)\s+([\w\s]+)/i";
- foreach((array)$lines as $line) {
- // skip comments or mime types w/o any extensions
- if ($line[0] == '#' || !preg_match($regex, $line, $matches))
- continue;
-
- $mime = $matches[1];
- foreach (explode(' ', $matches[2]) as $ext) {
- $ext = trim($ext);
- $mime_types[$mime][] = $ext;
- $mime_extensions[$ext] = $mime;
- }
- }
-
- // fallback to some well-known types most important for daily emails
- if (empty($mime_types)) {
- foreach (rcube::get_instance()->config->resolve_paths('mimetypes.php') as $fpath) {
- $mime_extensions = array_merge($mime_extensions, (array) @include($fpath));
- }
-
- foreach ($mime_extensions as $ext => $mime) {
- $mime_types[$mime][] = $ext;
- }
- }
-
- // Add some known aliases that aren't included by some mime.types (#1488891)
- // the order is important here so standard extensions have higher prio
- $aliases = array(
- 'image/gif' => array('gif'),
- 'image/png' => array('png'),
- 'image/x-png' => array('png'),
- 'image/jpeg' => array('jpg', 'jpeg', 'jpe'),
- 'image/jpg' => array('jpg', 'jpeg', 'jpe'),
- 'image/pjpeg' => array('jpg', 'jpeg', 'jpe'),
- 'image/tiff' => array('tif'),
- 'message/rfc822' => array('eml'),
- 'text/x-mail' => array('eml'),
- );
-
- foreach ($aliases as $mime => $exts) {
- $mime_types[$mime] = array_unique(array_merge((array) $mime_types[$mime], $exts));
-
- foreach ($exts as $ext) {
- if (!isset($mime_extensions[$ext])) {
- $mime_extensions[$ext] = $mime;
- }
- }
- }
-
- return $mimetype ? $mime_types[$mimetype] : $mime_extensions;
- }
-
- /**
- * Detect image type of the given binary data by checking magic numbers.
- *
- * @param string $data Binary file content
- *
- * @return string Detected mime-type or jpeg as fallback
- */
- public static function image_content_type($data)
- {
- $type = 'jpeg';
- if (preg_match('/^\x89\x50\x4E\x47/', $data)) $type = 'png';
- else if (preg_match('/^\x47\x49\x46\x38/', $data)) $type = 'gif';
- else if (preg_match('/^\x00\x00\x01\x00/', $data)) $type = 'ico';
- // else if (preg_match('/^\xFF\xD8\xFF\xE0/', $data)) $type = 'jpeg';
-
- return 'image/' . $type;
- }
-
- /**
- * Try to fix invalid email addresses
- */
- public static function fix_email($email)
- {
- $parts = rcube_utils::explode_quoted_string('@', $email);
- foreach ($parts as $idx => $part) {
- // remove redundant quoting (#1490040)
- if ($part[0] == '"' && preg_match('/^"([a-zA-Z0-9._+=-]+)"$/', $part, $m)) {
- $parts[$idx] = $m[1];
- }
- }
-
- return implode('@', $parts);
- }
-}
diff --git a/lib/ext/Roundcube/rcube_output.php b/lib/ext/Roundcube/rcube_output.php
deleted file mode 100644
index 55a38b2..0000000
--- a/lib/ext/Roundcube/rcube_output.php
+++ /dev/null
@@ -1,275 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube PHP suite |
- | Copyright (C) 2005-2014 The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | CONTENTS: |
- | Abstract class for output generation |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class for output generation
- *
- * @package Framework
- * @subpackage View
- */
-abstract class rcube_output
-{
- public $browser;
-
- protected $app;
- protected $config;
- protected $charset = RCUBE_CHARSET;
- protected $env = array();
- protected $skins = array();
-
-
- /**
- * Object constructor
- */
- public function __construct()
- {
- $this->app = rcube::get_instance();
- $this->config = $this->app->config;
- $this->browser = new rcube_browser();
- }
-
- /**
- * Magic getter
- */
- public function __get($var)
- {
- // allow read-only access to some members
- switch ($var) {
- case 'env': return $this->env;
- case 'skins': return $this->skins;
- case 'charset': return $this->charset;
- }
-
- return null;
- }
-
- /**
- * Setter for output charset.
- * To be specified in a meta tag and sent as http-header
- *
- * @param string $charset Charset name
- */
- public function set_charset($charset)
- {
- $this->charset = $charset;
- }
-
- /**
- * Getter for output charset
- *
- * @return string Output charset name
- */
- public function get_charset()
- {
- return $this->charset;
- }
-
- /**
- * Set environment variable
- *
- * @param string $name Property name
- * @param mixed $value Property value
- */
- public function set_env($name, $value)
- {
- $this->env[$name] = $value;
- }
-
- /**
- * Environment variable getter.
- *
- * @param string $name Property name
- *
- * @return mixed Property value
- */
- public function get_env($name)
- {
- return $this->env[$name];
- }
-
- /**
- * Delete all stored env variables and commands
- */
- public function reset()
- {
- $this->env = array();
- }
-
- /**
- * Invoke display_message command
- *
- * @param string $message Message to display
- * @param string $type Message type [notice|confirm|error]
- * @param array $vars Key-value pairs to be replaced in localized text
- * @param boolean $override Override last set message
- * @param int $timeout Message displaying time in seconds
- */
- abstract function show_message($message, $type = 'notice', $vars = null, $override = true, $timeout = 0);
-
- /**
- * Redirect to a certain url.
- *
- * @param mixed $p Either a string with the action or url parameters as key-value pairs
- * @param int $delay Delay in seconds
- */
- abstract function redirect($p = array(), $delay = 1);
-
- /**
- * Send output to the client.
- */
- abstract function send();
-
- /**
- * Send HTTP headers to prevent caching a page
- */
- public function nocacheing_headers()
- {
- if (headers_sent()) {
- return;
- }
-
- header("Expires: ".gmdate("D, d M Y H:i:s")." GMT");
- header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
-
- // We need to set the following headers to make downloads work using IE in HTTPS mode.
- if ($this->browser->ie && rcube_utils::https_check()) {
- header('Pragma: private');
- header("Cache-Control: private, must-revalidate");
- }
- else {
- header("Cache-Control: private, no-cache, no-store, must-revalidate, post-check=0, pre-check=0");
- header("Pragma: no-cache");
- }
- }
-
- /**
- * Send header with expire date 30 days in future
- *
- * @param int Expiration time in seconds
- */
- public function future_expire_header($offset = 2600000)
- {
- if (headers_sent()) {
- return;
- }
-
- header("Expires: " . gmdate("D, d M Y H:i:s", time()+$offset) . " GMT");
- header("Cache-Control: max-age=$offset");
- header("Pragma: ");
- }
-
- /**
- * Send browser compatibility/security/etc. headers
- */
- public function common_headers()
- {
- if (headers_sent()) {
- return;
- }
-
- // Unlock IE compatibility mode
- if ($this->browser->ie) {
- header('X-UA-Compatible: IE=edge');
- }
-
- // Request browser to disable DNS prefetching (CVE-2010-0464)
- header("X-DNS-Prefetch-Control: off");
- }
-
- /**
- * Show error page and terminate script execution
- *
- * @param int $code Error code
- * @param string $message Error message
- */
- public function raise_error($code, $message)
- {
- // STUB: to be overloaded by specific output classes
- fputs(STDERR, "Error $code: $message\n");
- exit(-1);
- }
-
- /**
- * Create an edit field for inclusion on a form
- *
- * @param string col field name
- * @param string value field value
- * @param array attrib HTML element attributes for field
- * @param string type HTML element type (default 'text')
- *
- * @return string HTML field definition
- */
- public static function get_edit_field($col, $value, $attrib, $type = 'text')
- {
- static $colcounts = array();
-
- $fname = '_'.$col;
- $attrib['name'] = $fname . ($attrib['array'] ? '[]' : '');
- $attrib['class'] = trim($attrib['class'] . ' ff_' . $col);
-
- if ($type == 'checkbox') {
- $attrib['value'] = '1';
- $input = new html_checkbox($attrib);
- }
- else if ($type == 'textarea') {
- $attrib['cols'] = $attrib['size'];
- $input = new html_textarea($attrib);
- }
- else if ($type == 'select') {
- $input = new html_select($attrib);
- $input->add('---', '');
- $input->add(array_values($attrib['options']), array_keys($attrib['options']));
- }
- else if ($attrib['type'] == 'password') {
- $input = new html_passwordfield($attrib);
- }
- else {
- if ($attrib['type'] != 'text' && $attrib['type'] != 'hidden') {
- $attrib['type'] = 'text';
- }
- $input = new html_inputfield($attrib);
- }
-
- // use value from post
- if (isset($_POST[$fname])) {
- $postvalue = rcube_utils::get_input_value($fname, rcube_utils::INPUT_POST, true);
- $value = $attrib['array'] ? $postvalue[intval($colcounts[$col]++)] : $postvalue;
- }
-
- $out = $input->show($value);
-
- return $out;
- }
-
- /**
- * Convert a variable into a javascript object notation
- *
- * @param mixed Input value
- *
- * @return string Serialized JSON string
- */
- public static function json_serialize($input)
- {
- $input = rcube_charset::clean($input);
-
- // sometimes even using rcube_charset::clean() the input contains invalid UTF-8 sequences
- // that's why we have @ here
- return @json_encode($input);
- }
-}
diff --git a/lib/ext/Roundcube/rcube_plugin.php b/lib/ext/Roundcube/rcube_plugin.php
deleted file mode 100644
index e240448..0000000
--- a/lib/ext/Roundcube/rcube_plugin.php
+++ /dev/null
@@ -1,451 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2014, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Abstract plugins interface/class |
- | All plugins need to extend this class |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Plugin interface class
- *
- * @package Framework
- * @subpackage PluginAPI
- */
-abstract class rcube_plugin
-{
- /**
- * Class name of the plugin instance
- *
- * @var string
- */
- public $ID;
-
- /**
- * Instance of Plugin API
- *
- * @var rcube_plugin_api
- */
- public $api;
-
- /**
- * Regular expression defining task(s) to bind with
- *
- * @var string
- */
- public $task;
-
- /**
- * Disables plugin in AJAX requests
- *
- * @var boolean
- */
- public $noajax = false;
-
- /**
- * Disables plugin in framed mode
- *
- * @var boolean
- */
- public $noframe = false;
-
- /**
- * A list of config option names that can be modified
- * by the user via user interface (with save-prefs command)
- *
- * @var array
- */
- public $allowed_prefs;
-
- protected $home;
- protected $urlbase;
- private $mytask;
- private $loaded_config = array();
-
-
- /**
- * Default constructor.
- *
- * @param rcube_plugin_api $api Plugin API
- */
- public function __construct($api)
- {
- $this->ID = get_class($this);
- $this->api = $api;
- $this->home = $api->dir . $this->ID;
- $this->urlbase = $api->url . $this->ID . '/';
- }
-
- /**
- * Initialization method, needs to be implemented by the plugin itself
- */
- abstract function init();
-
- /**
- * Provide information about this
- *
- * @return array Meta information about a plugin or false if not implemented:
- * As hash array with the following keys:
- * name: The plugin name
- * vendor: Name of the plugin developer
- * version: Plugin version name
- * license: License name (short form according to http://spdx.org/licenses/)
- * uri: The URL to the plugin homepage or source repository
- * src_uri: Direct download URL to the source code of this plugin
- * require: List of plugins required for this one (as array of plugin names)
- */
- public static function info()
- {
- return false;
- }
-
- /**
- * Attempt to load the given plugin which is required for the current plugin
- *
- * @param string Plugin name
- * @return boolean True on success, false on failure
- */
- public function require_plugin($plugin_name)
- {
- return $this->api->load_plugin($plugin_name, true);
- }
-
- /**
- * Attempt to load the given plugin which is optional for the current plugin
- *
- * @param string Plugin name
- * @return boolean True on success, false on failure
- */
- public function include_plugin($plugin_name)
- {
- return $this->api->load_plugin($plugin_name, true, false);
- }
-
- /**
- * Load local config file from plugins directory.
- * The loaded values are patched over the global configuration.
- *
- * @param string $fname Config file name relative to the plugin's folder
- *
- * @return boolean True on success, false on failure
- */
- public function load_config($fname = 'config.inc.php')
- {
- if (in_array($fname, $this->loaded_config)) {
- return true;
- }
-
- $this->loaded_config[] = $fname;
-
- $fpath = $this->home.'/'.$fname;
- $rcube = rcube::get_instance();
-
- if (($is_local = is_file($fpath)) && !$rcube->config->load_from_file($fpath)) {
- rcube::raise_error(array(
- 'code' => 527, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Failed to load config from $fpath"), true, false);
- return false;
- }
- else if (!$is_local) {
- // Search plugin_name.inc.php file in any configured path
- return $rcube->config->load_from_file($this->ID . '.inc.php');
- }
-
- return true;
- }
-
- /**
- * Register a callback function for a specific (server-side) hook
- *
- * @param string $hook Hook name
- * @param mixed $callback Callback function as string or array
- * with object reference and method name
- */
- public function add_hook($hook, $callback)
- {
- $this->api->register_hook($hook, $callback);
- }
-
- /**
- * Unregister a callback function for a specific (server-side) hook.
- *
- * @param string $hook Hook name
- * @param mixed $callback Callback function as string or array
- * with object reference and method name
- */
- public function remove_hook($hook, $callback)
- {
- $this->api->unregister_hook($hook, $callback);
- }
-
- /**
- * Load localized texts from the plugins dir
- *
- * @param string $dir Directory to search in
- * @param mixed $add2client Make texts also available on the client
- * (array with list or true for all)
- */
- public function add_texts($dir, $add2client = false)
- {
- $domain = $this->ID;
- $lang = $_SESSION['language'];
- $langs = array_unique(array('en_US', $lang));
- $locdir = slashify(realpath(slashify($this->home) . $dir));
- $texts = array();
-
- // Language aliases used to find localization in similar lang, see below
- $aliases = array(
- 'de_CH' => 'de_DE',
- 'es_AR' => 'es_ES',
- 'fa_AF' => 'fa_IR',
- 'nl_BE' => 'nl_NL',
- 'pt_BR' => 'pt_PT',
- 'zh_CN' => 'zh_TW',
- );
-
- // use buffering to handle empty lines/spaces after closing PHP tag
- ob_start();
-
- foreach ($langs as $lng) {
- $fpath = $locdir . $lng . '.inc';
- if (is_file($fpath) && is_readable($fpath)) {
- include $fpath;
- $texts = (array)$labels + (array)$messages + (array)$texts;
- }
- else if ($lng != 'en_US') {
- // Find localization in similar language (#1488401)
- $alias = null;
- if (!empty($aliases[$lng])) {
- $alias = $aliases[$lng];
- }
- else if ($key = array_search($lng, $aliases)) {
- $alias = $key;
- }
-
- if (!empty($alias)) {
- $fpath = $locdir . $alias . '.inc';
- if (is_file($fpath) && is_readable($fpath)) {
- include $fpath;
- $texts = (array)$labels + (array)$messages + (array)$texts;
- }
- }
- }
- }
-
- ob_end_clean();
-
- // prepend domain to text keys and add to the application texts repository
- if (!empty($texts)) {
- $add = array();
- foreach ($texts as $key => $value) {
- $add[$domain.'.'.$key] = $value;
- }
-
- $rcube = rcube::get_instance();
- $rcube->load_language($lang, $add);
-
- // add labels to client
- if ($add2client && method_exists($rcube->output, 'add_label')) {
- if (is_array($add2client)) {
- $js_labels = array_map(array($this, 'label_map_callback'), $add2client);
- }
- else {
- $js_labels = array_keys($add);
- }
- $rcube->output->add_label($js_labels);
- }
- }
- }
-
- /**
- * Wrapper for add_label() adding the plugin ID as domain
- */
- public function add_label()
- {
- $rcube = rcube::get_instance();
-
- if (method_exists($rcube->output, 'add_label')) {
- $args = func_get_args();
- if (count($args) == 1 && is_array($args[0])) {
- $args = $args[0];
- }
-
- $args = array_map(array($this, 'label_map_callback'), $args);
- $rcube->output->add_label($args);
- }
- }
-
- /**
- * Wrapper for rcube::gettext() adding the plugin ID as domain
- *
- * @param string $p Message identifier
- *
- * @return string Localized text
- * @see rcube::gettext()
- */
- public function gettext($p)
- {
- return rcube::get_instance()->gettext($p, $this->ID);
- }
-
- /**
- * Register this plugin to be responsible for a specific task
- *
- * @param string $task Task name (only characters [a-z0-9_-] are allowed)
- */
- public function register_task($task)
- {
- if ($this->api->register_task($task, $this->ID)) {
- $this->mytask = $task;
- }
- }
-
- /**
- * Register a handler for a specific client-request action
- *
- * The callback will be executed upon a request like /?_task=mail&_action=plugin.myaction
- *
- * @param string $action Action name (should be unique)
- * @param mixed $callback Callback function as string
- * or array with object reference and method name
- */
- public function register_action($action, $callback)
- {
- $this->api->register_action($action, $this->ID, $callback, $this->mytask);
- }
-
- /**
- * Register a handler function for a template object
- *
- * When parsing a template for display, tags like <roundcube:object name="plugin.myobject" />
- * will be replaced by the return value if the registered callback function.
- *
- * @param string $name Object name (should be unique and start with 'plugin.')
- * @param mixed $callback Callback function as string or array with object reference
- * and method name
- */
- public function register_handler($name, $callback)
- {
- $this->api->register_handler($name, $this->ID, $callback);
- }
-
- /**
- * Make this javascipt file available on the client
- *
- * @param string $fn File path; absolute or relative to the plugin directory
- */
- public function include_script($fn)
- {
- $this->api->include_script($this->resource_url($fn));
- }
-
- /**
- * Make this stylesheet available on the client
- *
- * @param string $fn File path; absolute or relative to the plugin directory
- */
- public function include_stylesheet($fn)
- {
- $this->api->include_stylesheet($this->resource_url($fn));
- }
-
- /**
- * Append a button to a certain container
- *
- * @param array $p Hash array with named parameters (as used in skin templates)
- * @param string $container Container name where the buttons should be added to
- *
- * @see rcube_remplate::button()
- */
- public function add_button($p, $container)
- {
- if ($this->api->output->type == 'html') {
- // fix relative paths
- foreach (array('imagepas', 'imageact', 'imagesel') as $key) {
- if ($p[$key]) {
- $p[$key] = $this->api->url . $this->resource_url($p[$key]);
- }
- }
-
- $this->api->add_content($this->api->output->button($p), $container);
- }
- }
-
- /**
- * Generate an absolute URL to the given resource within the current
- * plugin directory
- *
- * @param string $fn The file name
- *
- * @return string Absolute URL to the given resource
- */
- public function url($fn)
- {
- return $this->api->url . $this->resource_url($fn);
- }
-
- /**
- * Make the given file name link into the plugin directory
- *
- * @param string $fn Filename
- */
- private function resource_url($fn)
- {
- if ($fn[0] != '/' && !preg_match('|^https?://|i', $fn)) {
- return $this->ID . '/' . $fn;
- }
- else {
- return $fn;
- }
- }
-
- /**
- * Provide path to the currently selected skin folder within the plugin directory
- * with a fallback to the default skin folder.
- *
- * @return string Skin path relative to plugins directory
- */
- public function local_skin_path()
- {
- $rcube = rcube::get_instance();
- $skins = array_keys((array)$rcube->output->skins);
- if (empty($skins)) {
- $skins = (array) $rcube->config->get('skin');
- }
- foreach ($skins as $skin) {
- $skin_path = 'skins/' . $skin;
- if (is_dir(realpath(slashify($this->home) . $skin_path))) {
- break;
- }
- }
-
- return $skin_path;
- }
-
- /**
- * Callback function for array_map
- *
- * @param string $key Array key.
- * @return string
- */
- private function label_map_callback($key)
- {
- if (strpos($key, $this->ID.'.') === 0) {
- return $key;
- }
-
- return $this->ID.'.'.$key;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_plugin_api.php b/lib/ext/Roundcube/rcube_plugin_api.php
deleted file mode 100644
index 92a5636..0000000
--- a/lib/ext/Roundcube/rcube_plugin_api.php
+++ /dev/null
@@ -1,663 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Plugins repository |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-// location where plugins are loade from
-if (!defined('RCUBE_PLUGINS_DIR')) {
- define('RCUBE_PLUGINS_DIR', RCUBE_INSTALL_PATH . 'plugins/');
-}
-
-/**
- * The plugin loader and global API
- *
- * @package Framework
- * @subpackage PluginAPI
- */
-class rcube_plugin_api
-{
- static protected $instance;
-
- public $dir;
- public $url = 'plugins/';
- public $task = '';
- public $output;
- public $handlers = array();
- public $allowed_prefs = array();
- public $allowed_session_prefs = array();
- public $active_plugins = array();
-
- protected $plugins = array();
- protected $tasks = array();
- protected $actions = array();
- protected $actionmap = array();
- protected $objectsmap = array();
- protected $template_contents = array();
- protected $exec_stack = array();
-
- // Deprecated names of hooks, will be removed after 0.5-stable release
- protected $deprecated_hooks = array(
- 'create_user' => 'user_create',
- 'kill_session' => 'session_destroy',
- 'upload_attachment' => 'attachment_upload',
- 'save_attachment' => 'attachment_save',
- 'get_attachment' => 'attachment_get',
- 'cleanup_attachments' => 'attachments_cleanup',
- 'display_attachment' => 'attachment_display',
- 'remove_attachment' => 'attachment_delete',
- 'outgoing_message_headers' => 'message_outgoing_headers',
- 'outgoing_message_body' => 'message_outgoing_body',
- 'address_sources' => 'addressbooks_list',
- 'get_address_book' => 'addressbook_get',
- 'create_contact' => 'contact_create',
- 'save_contact' => 'contact_update',
- 'contact_save' => 'contact_update',
- 'delete_contact' => 'contact_delete',
- 'manage_folders' => 'folders_list',
- 'list_mailboxes' => 'mailboxes_list',
- 'save_preferences' => 'preferences_save',
- 'user_preferences' => 'preferences_list',
- 'list_prefs_sections' => 'preferences_sections_list',
- 'list_identities' => 'identities_list',
- 'create_identity' => 'identity_create',
- 'delete_identity' => 'identity_delete',
- 'save_identity' => 'identity_update',
- 'identity_save' => 'identity_update',
- // to be removed after 0.8
- 'imap_init' => 'storage_init',
- 'mailboxes_list' => 'storage_folders',
- 'imap_connect' => 'storage_connect',
- );
-
- /**
- * This implements the 'singleton' design pattern
- *
- * @return rcube_plugin_api The one and only instance if this class
- */
- static function get_instance()
- {
- if (!self::$instance) {
- self::$instance = new rcube_plugin_api();
- }
-
- return self::$instance;
- }
-
- /**
- * Private constructor
- */
- protected function __construct()
- {
- $this->dir = slashify(RCUBE_PLUGINS_DIR);
- }
-
- /**
- * Initialize plugin engine
- *
- * This has to be done after rcmail::load_gui() or rcmail::json_init()
- * was called because plugins need to have access to rcmail->output
- *
- * @param object rcube Instance of the rcube base class
- * @param string Current application task (used for conditional plugin loading)
- */
- public function init($app, $task = '')
- {
- $this->task = $task;
- $this->output = $app->output;
-
- // register an internal hook
- $this->register_hook('template_container', array($this, 'template_container_hook'));
-
- // maybe also register a shudown function which triggers
- // shutdown functions of all plugin objects
- }
-
- /**
- * Load and init all enabled plugins
- *
- * This has to be done after rcmail::load_gui() or rcmail::json_init()
- * was called because plugins need to have access to rcmail->output
- *
- * @param array List of configured plugins to load
- * @param array List of plugins required by the application
- */
- public function load_plugins($plugins_enabled, $required_plugins = array())
- {
- foreach ($plugins_enabled as $plugin_name) {
- $this->load_plugin($plugin_name);
- }
-
- // check existance of all required core plugins
- foreach ($required_plugins as $plugin_name) {
- $loaded = false;
- foreach ($this->plugins as $plugin) {
- if ($plugin instanceof $plugin_name) {
- $loaded = true;
- break;
- }
- }
-
- // load required core plugin if no derivate was found
- if (!$loaded) {
- $loaded = $this->load_plugin($plugin_name);
- }
-
- // trigger fatal error if still not loaded
- if (!$loaded) {
- rcube::raise_error(array(
- 'code' => 520, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Requried plugin $plugin_name was not loaded"), true, true);
- }
- }
- }
-
- /**
- * Load the specified plugin
- *
- * @param string Plugin name
- * @param boolean Force loading of the plugin even if it doesn't match the filter
- * @param boolean Require loading of the plugin, error if it doesn't exist
- *
- * @return boolean True on success, false if not loaded or failure
- */
- public function load_plugin($plugin_name, $force = false, $require = true)
- {
- static $plugins_dir;
-
- if (!$plugins_dir) {
- $dir = dir($this->dir);
- $plugins_dir = unslashify($dir->path);
- }
-
- // plugin already loaded
- if ($this->plugins[$plugin_name]) {
- return true;
- }
-
- $fn = "$plugins_dir/$plugin_name/$plugin_name.php";
-
- if (is_readable($fn)) {
- if (!class_exists($plugin_name, false)) {
- include $fn;
- }
-
- // instantiate class if exists
- if (class_exists($plugin_name, false)) {
- $plugin = new $plugin_name($this);
- $this->active_plugins[] = $plugin_name;
-
- // check inheritance...
- if (is_subclass_of($plugin, 'rcube_plugin')) {
- // ... task, request type and framed mode
- if (($force || !$plugin->task || preg_match('/^('.$plugin->task.')$/i', $this->task))
- && (!$plugin->noajax || (is_object($this->output) && $this->output->type == 'html'))
- && (!$plugin->noframe || empty($_REQUEST['_framed']))
- ) {
- $plugin->init();
- $this->plugins[$plugin_name] = $plugin;
- }
-
- if (!empty($plugin->allowed_prefs)) {
- $this->allowed_prefs = array_merge($this->allowed_prefs, $plugin->allowed_prefs);
- }
-
- return true;
- }
- }
- else {
- rcube::raise_error(array('code' => 520, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "No plugin class $plugin_name found in $fn"),
- true, false);
- }
- }
- elseif ($require) {
- rcube::raise_error(array('code' => 520, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Failed to load plugin file $fn"), true, false);
- }
-
- return false;
- }
-
- /**
- * Get information about a specific plugin.
- * This is either provided my a plugin's info() method or extracted from a package.xml or a composer.json file
- *
- * @param string Plugin name
- * @return array Meta information about a plugin or False if plugin was not found
- */
- public function get_info($plugin_name)
- {
- static $composer_lock, $license_uris = array(
- 'Apache' => 'http://www.apache.org/licenses/LICENSE-2.0.html',
- 'Apache-2' => 'http://www.apache.org/licenses/LICENSE-2.0.html',
- 'Apache-1' => 'http://www.apache.org/licenses/LICENSE-1.0',
- 'Apache-1.1' => 'http://www.apache.org/licenses/LICENSE-1.1',
- 'GPL' => 'http://www.gnu.org/licenses/gpl.html',
- 'GPLv2' => 'http://www.gnu.org/licenses/gpl-2.0.html',
- 'GPL-2.0' => 'http://www.gnu.org/licenses/gpl-2.0.html',
- 'GPLv3' => 'http://www.gnu.org/licenses/gpl-3.0.html',
- 'GPL-3.0' => 'http://www.gnu.org/licenses/gpl-3.0.html',
- 'GPL-3.0+' => 'http://www.gnu.org/licenses/gpl.html',
- 'GPL-2.0+' => 'http://www.gnu.org/licenses/gpl.html',
- 'AGPLv3' => 'http://www.gnu.org/licenses/agpl.html',
- 'AGPLv3+' => 'http://www.gnu.org/licenses/agpl.html',
- 'AGPL-3.0' => 'http://www.gnu.org/licenses/agpl.html',
- 'LGPL' => 'http://www.gnu.org/licenses/lgpl.html',
- 'LGPLv2' => 'http://www.gnu.org/licenses/lgpl-2.0.html',
- 'LGPLv2.1' => 'http://www.gnu.org/licenses/lgpl-2.1.html',
- 'LGPLv3' => 'http://www.gnu.org/licenses/lgpl.html',
- 'LGPL-2.0' => 'http://www.gnu.org/licenses/lgpl-2.0.html',
- 'LGPL-2.1' => 'http://www.gnu.org/licenses/lgpl-2.1.html',
- 'LGPL-3.0' => 'http://www.gnu.org/licenses/lgpl.html',
- 'LGPL-3.0+' => 'http://www.gnu.org/licenses/lgpl.html',
- 'BSD' => 'http://opensource.org/licenses/bsd-license.html',
- 'BSD-2-Clause' => 'http://opensource.org/licenses/BSD-2-Clause',
- 'BSD-3-Clause' => 'http://opensource.org/licenses/BSD-3-Clause',
- 'FreeBSD' => 'http://opensource.org/licenses/BSD-2-Clause',
- 'MIT' => 'http://www.opensource.org/licenses/mit-license.php',
- 'PHP' => 'http://opensource.org/licenses/PHP-3.0',
- 'PHP-3' => 'http://www.php.net/license/3_01.txt',
- 'PHP-3.0' => 'http://www.php.net/license/3_0.txt',
- 'PHP-3.01' => 'http://www.php.net/license/3_01.txt',
- );
-
- $dir = dir($this->dir);
- $fn = unslashify($dir->path) . "/$plugin_name/$plugin_name.php";
- $info = false;
-
- if (!class_exists($plugin_name, false)) {
- if (is_readable($fn))
- include($fn);
- else
- return false;
- }
-
- if (class_exists($plugin_name))
- $info = $plugin_name::info();
-
- // fall back to composer.json file
- if (!$info) {
- $composer = INSTALL_PATH . "/plugins/$plugin_name/composer.json";
- if (is_readable($composer) && ($json = @json_decode(file_get_contents($composer), true))) {
- list($info['vendor'], $info['name']) = explode('/', $json['name']);
- $info['version'] = $json['version'];
- $info['license'] = $json['license'];
- $info['uri'] = $json['homepage'];
- $info['require'] = array_filter(array_keys((array)$json['require']), function($pname) {
- if (strpos($pname, '/') == false)
- return false;
- list($vendor, $name) = explode('/', $pname);
- return !($name == 'plugin-installer' || $vendor == 'pear-pear');
- });
- }
-
- // read local composer.lock file (once)
- if (!isset($composer_lock)) {
- $composer_lock = @json_decode(@file_get_contents(INSTALL_PATH . "/composer.lock"), true);
- if ($composer_lock['packages']) {
- foreach ($composer_lock['packages'] as $i => $package) {
- $composer_lock['installed'][$package['name']] = $package;
- }
- }
- }
-
- // load additional information from local composer.lock file
- if ($lock = $composer_lock['installed'][$json['name']]) {
- $info['version'] = $lock['version'];
- $info['uri'] = $lock['homepage'] ? $lock['homepage'] : $lock['source']['uri'];
- $info['src_uri'] = $lock['dist']['uri'] ? $lock['dist']['uri'] : $lock['source']['uri'];
- }
- }
-
- // fall back to package.xml file
- if (!$info) {
- $package = INSTALL_PATH . "/plugins/$plugin_name/package.xml";
- if (is_readable($package) && ($file = file_get_contents($package))) {
- $doc = new DOMDocument();
- $doc->loadXML($file);
- $xpath = new DOMXPath($doc);
- $xpath->registerNamespace('rc', "http://pear.php.net/dtd/package-2.0");
-
- // XPaths of plugin metadata elements
- $metadata = array(
- 'name' => 'string(//rc:package/rc:name)',
- 'version' => 'string(//rc:package/rc:version/rc:release)',
- 'license' => 'string(//rc:package/rc:license)',
- 'license_uri' => 'string(//rc:package/rc:license/@uri)',
- 'src_uri' => 'string(//rc:package/rc:srcuri)',
- 'uri' => 'string(//rc:package/rc:uri)',
- );
-
- foreach ($metadata as $key => $path) {
- $info[$key] = $xpath->evaluate($path);
- }
-
- // dependent required plugins (can be used, but not included in config)
- $deps = $xpath->evaluate('//rc:package/rc:dependencies/rc:required/rc:package/rc:name');
- for ($i = 0; $i < $deps->length; $i++) {
- $dn = $deps->item($i)->nodeValue;
- $info['require'][] = $dn;
- }
- }
- }
-
- // At least provide the name
- if (!$info && class_exists($plugin_name)) {
- $info = array('name' => $plugin_name, 'version' => '--');
- }
- else if ($info['license'] && empty($info['license_uri']) && ($license_uri = $license_uris[$info['license']])) {
- $info['license_uri'] = $license_uri;
- }
-
- return $info;
- }
-
- /**
- * Allows a plugin object to register a callback for a certain hook
- *
- * @param string $hook Hook name
- * @param mixed $callback String with global function name or array($obj, 'methodname')
- */
- public function register_hook($hook, $callback)
- {
- if (is_callable($callback)) {
- if (isset($this->deprecated_hooks[$hook])) {
- rcube::raise_error(array('code' => 522, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Deprecated hook name. "
- . $hook . ' -> ' . $this->deprecated_hooks[$hook]), true, false);
- $hook = $this->deprecated_hooks[$hook];
- }
- $this->handlers[$hook][] = $callback;
- }
- else {
- rcube::raise_error(array('code' => 521, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Invalid callback function for $hook"), true, false);
- }
- }
-
- /**
- * Allow a plugin object to unregister a callback.
- *
- * @param string $hook Hook name
- * @param mixed $callback String with global function name or array($obj, 'methodname')
- */
- public function unregister_hook($hook, $callback)
- {
- $callback_id = array_search($callback, $this->handlers[$hook]);
- if ($callback_id !== false) {
- unset($this->handlers[$hook][$callback_id]);
- }
- }
-
- /**
- * Triggers a plugin hook.
- * This is called from the application and executes all registered handlers
- *
- * @param string $hook Hook name
- * @param array $args Named arguments (key->value pairs)
- *
- * @return array The (probably) altered hook arguments
- */
- public function exec_hook($hook, $args = array())
- {
- if (!is_array($args)) {
- $args = array('arg' => $args);
- }
-
- // TODO: avoid recusion by checking in_array($hook, $this->exec_stack) ?
-
- $args += array('abort' => false);
- array_push($this->exec_stack, $hook);
-
- foreach ((array)$this->handlers[$hook] as $callback) {
- $ret = call_user_func($callback, $args);
- if ($ret && is_array($ret)) {
- $args = $ret + $args;
- }
-
- if ($args['break']) {
- break;
- }
- }
-
- array_pop($this->exec_stack);
- return $args;
- }
-
- /**
- * Let a plugin register a handler for a specific request
- *
- * @param string $action Action name (_task=mail&_action=plugin.foo)
- * @param string $owner Plugin name that registers this action
- * @param mixed $callback Callback: string with global function name or array($obj, 'methodname')
- * @param string $task Task name registered by this plugin
- */
- public function register_action($action, $owner, $callback, $task = null)
- {
- // check action name
- if ($task)
- $action = $task.'.'.$action;
- else if (strpos($action, 'plugin.') !== 0)
- $action = 'plugin.'.$action;
-
- // can register action only if it's not taken or registered by myself
- if (!isset($this->actionmap[$action]) || $this->actionmap[$action] == $owner) {
- $this->actions[$action] = $callback;
- $this->actionmap[$action] = $owner;
- }
- else {
- rcube::raise_error(array('code' => 523, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Cannot register action $action;"
- ." already taken by another plugin"), true, false);
- }
- }
-
- /**
- * This method handles requests like _task=mail&_action=plugin.foo
- * It executes the callback function that was registered with the given action.
- *
- * @param string $action Action name
- */
- public function exec_action($action)
- {
- if (isset($this->actions[$action])) {
- call_user_func($this->actions[$action]);
- }
- else if (rcube::get_instance()->action != 'refresh') {
- rcube::raise_error(array('code' => 524, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "No handler found for action $action"), true, true);
- }
- }
-
- /**
- * Register a handler function for template objects
- *
- * @param string $name Object name
- * @param string $owner Plugin name that registers this action
- * @param mixed $callback Callback: string with global function name or array($obj, 'methodname')
- */
- public function register_handler($name, $owner, $callback)
- {
- // check name
- if (strpos($name, 'plugin.') !== 0) {
- $name = 'plugin.' . $name;
- }
-
- // can register handler only if it's not taken or registered by myself
- if (is_object($this->output)
- && (!isset($this->objectsmap[$name]) || $this->objectsmap[$name] == $owner)
- ) {
- $this->output->add_handler($name, $callback);
- $this->objectsmap[$name] = $owner;
- }
- else {
- rcube::raise_error(array('code' => 525, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Cannot register template handler $name;"
- ." already taken by another plugin or no output object available"), true, false);
- }
- }
-
- /**
- * Register this plugin to be responsible for a specific task
- *
- * @param string $task Task name (only characters [a-z0-9_-] are allowed)
- * @param string $owner Plugin name that registers this action
- */
- public function register_task($task, $owner)
- {
- // tasks are irrelevant in framework mode
- if (!class_exists('rcmail', false)) {
- return true;
- }
-
- if ($task != asciiwords($task, true)) {
- rcube::raise_error(array('code' => 526, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Invalid task name: $task."
- ." Only characters [a-z0-9_.-] are allowed"), true, false);
- }
- else if (in_array($task, rcmail::$main_tasks)) {
- rcube::raise_error(array('code' => 526, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Cannot register taks $task;"
- ." already taken by another plugin or the application itself"), true, false);
- }
- else {
- $this->tasks[$task] = $owner;
- rcmail::$main_tasks[] = $task;
- return true;
- }
-
- return false;
- }
-
- /**
- * Checks whether the given task is registered by a plugin
- *
- * @param string $task Task name
- *
- * @return boolean True if registered, otherwise false
- */
- public function is_plugin_task($task)
- {
- return $this->tasks[$task] ? true : false;
- }
-
- /**
- * Check if a plugin hook is currently processing.
- * Mainly used to prevent loops and recursion.
- *
- * @param string $hook Hook to check (optional)
- *
- * @return boolean True if any/the given hook is currently processed, otherwise false
- */
- public function is_processing($hook = null)
- {
- return count($this->exec_stack) > 0 && (!$hook || in_array($hook, $this->exec_stack));
- }
-
- /**
- * Include a plugin script file in the current HTML page
- *
- * @param string $fn Path to script
- */
- public function include_script($fn)
- {
- if (is_object($this->output) && $this->output->type == 'html') {
- $src = $this->resource_url($fn);
- $this->output->add_header(html::tag('script',
- array('type' => "text/javascript", 'src' => $src)));
- }
- }
-
- /**
- * Include a plugin stylesheet in the current HTML page
- *
- * @param string $fn Path to stylesheet
- */
- public function include_stylesheet($fn)
- {
- if (is_object($this->output) && $this->output->type == 'html') {
- $src = $this->resource_url($fn);
- $this->output->include_css($src);
- }
- }
-
- /**
- * Save the given HTML content to be added to a template container
- *
- * @param string $html HTML content
- * @param string $container Template container identifier
- */
- public function add_content($html, $container)
- {
- $this->template_contents[$container] .= $html . "\n";
- }
-
- /**
- * Returns list of loaded plugins names
- *
- * @return array List of plugin names
- */
- public function loaded_plugins()
- {
- return array_keys($this->plugins);
- }
-
- /**
- * Returns loaded plugin
- *
- * @return rcube_plugin Plugin instance
- */
- public function get_plugin($name)
- {
- return $this->plugins[$name];
- }
-
- /**
- * Callback for template_container hooks
- *
- * @param array $attrib
- * @return array
- */
- protected function template_container_hook($attrib)
- {
- $container = $attrib['name'];
- return array('content' => $attrib['content'] . $this->template_contents[$container]);
- }
-
- /**
- * Make the given file name link into the plugins directory
- *
- * @param string $fn Filename
- * @return string
- */
- protected function resource_url($fn)
- {
- if ($fn[0] != '/' && !preg_match('|^https?://|i', $fn))
- return $this->url . $fn;
- else
- return $fn;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_result_index.php b/lib/ext/Roundcube/rcube_result_index.php
deleted file mode 100644
index ffc1ad7..0000000
--- a/lib/ext/Roundcube/rcube_result_index.php
+++ /dev/null
@@ -1,436 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | 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 General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | SORT/SEARCH/ESEARCH response handler |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class for accessing IMAP's SORT/SEARCH/ESEARCH result
- *
- * @package Framework
- * @subpackage Storage
- */
-class rcube_result_index
-{
- public $incomplete = false;
-
- protected $raw_data;
- protected $mailbox;
- protected $meta = array();
- protected $params = array();
- protected $order = 'ASC';
-
- const SEPARATOR_ELEMENT = ' ';
-
-
- /**
- * Object constructor.
- */
- public function __construct($mailbox = null, $data = null)
- {
- $this->mailbox = $mailbox;
- $this->init($data);
- }
-
-
- /**
- * Initializes object with SORT command response
- *
- * @param string $data IMAP response string
- */
- public function init($data = null)
- {
- $this->meta = array();
-
- $data = explode('*', (string)$data);
-
- // ...skip unilateral untagged server responses
- for ($i=0, $len=count($data); $i<$len; $i++) {
- $data_item = &$data[$i];
- if (preg_match('/^ SORT/i', $data_item)) {
- // valid response, initialize raw_data for is_error()
- $this->raw_data = '';
- $data_item = substr($data_item, 5);
- break;
- }
- else if (preg_match('/^ (E?SEARCH)/i', $data_item, $m)) {
- // valid response, initialize raw_data for is_error()
- $this->raw_data = '';
- $data_item = substr($data_item, strlen($m[0]));
-
- if (strtoupper($m[1]) == 'ESEARCH') {
- $data_item = trim($data_item);
- // remove MODSEQ response
- if (preg_match('/\(MODSEQ ([0-9]+)\)$/i', $data_item, $m)) {
- $data_item = substr($data_item, 0, -strlen($m[0]));
- $this->params['MODSEQ'] = $m[1];
- }
- // remove TAG response part
- if (preg_match('/^\(TAG ["a-z0-9]+\)\s*/i', $data_item, $m)) {
- $data_item = substr($data_item, strlen($m[0]));
- }
- // remove UID
- $data_item = preg_replace('/^UID\s*/i', '', $data_item);
-
- // ESEARCH parameters
- while (preg_match('/^([a-z]+) ([0-9:,]+)\s*/i', $data_item, $m)) {
- $param = strtoupper($m[1]);
- $value = $m[2];
-
- $this->params[$param] = $value;
- $data_item = substr($data_item, strlen($m[0]));
-
- if (in_array($param, array('COUNT', 'MIN', 'MAX'))) {
- $this->meta[strtolower($param)] = (int) $value;
- }
- }
-
-// @TODO: Implement compression using compressMessageSet() in __sleep() and __wakeup() ?
-// @TODO: work with compressed result?!
- if (isset($this->params['ALL'])) {
- $data_item = implode(self::SEPARATOR_ELEMENT,
- rcube_imap_generic::uncompressMessageSet($this->params['ALL']));
- }
- }
-
- break;
- }
-
- unset($data[$i]);
- }
-
- $data = array_filter($data);
-
- if (empty($data)) {
- return;
- }
-
- $data = array_shift($data);
- $data = trim($data);
- $data = preg_replace('/[\r\n]/', '', $data);
- $data = preg_replace('/\s+/', ' ', $data);
-
- $this->raw_data = $data;
- }
-
-
- /**
- * Checks the result from IMAP command
- *
- * @return bool True if the result is an error, False otherwise
- */
- public function is_error()
- {
- return $this->raw_data === null ? true : false;
- }
-
-
- /**
- * Checks if the result is empty
- *
- * @return bool True if the result is empty, False otherwise
- */
- public function is_empty()
- {
- return empty($this->raw_data) ? true : false;
- }
-
-
- /**
- * Returns number of elements in the result
- *
- * @return int Number of elements
- */
- public function count()
- {
- if ($this->meta['count'] !== null)
- return $this->meta['count'];
-
- if (empty($this->raw_data)) {
- $this->meta['count'] = 0;
- $this->meta['length'] = 0;
- }
- else {
- $this->meta['count'] = 1 + substr_count($this->raw_data, self::SEPARATOR_ELEMENT);
- }
-
- return $this->meta['count'];
- }
-
-
- /**
- * Returns number of elements in the result.
- * Alias for count() for compatibility with rcube_result_thread
- *
- * @return int Number of elements
- */
- public function count_messages()
- {
- return $this->count();
- }
-
-
- /**
- * Returns maximal message identifier in the result
- *
- * @return int Maximal message identifier
- */
- public function max()
- {
- if (!isset($this->meta['max'])) {
- $this->meta['max'] = (int) @max($this->get());
- }
-
- return $this->meta['max'];
- }
-
-
- /**
- * Returns minimal message identifier in the result
- *
- * @return int Minimal message identifier
- */
- public function min()
- {
- if (!isset($this->meta['min'])) {
- $this->meta['min'] = (int) @min($this->get());
- }
-
- return $this->meta['min'];
- }
-
-
- /**
- * Slices data set.
- *
- * @param $offset Offset (as for PHP's array_slice())
- * @param $length Number of elements (as for PHP's array_slice())
- *
- */
- public function slice($offset, $length)
- {
- $data = $this->get();
- $data = array_slice($data, $offset, $length);
-
- $this->meta = array();
- $this->meta['count'] = count($data);
- $this->raw_data = implode(self::SEPARATOR_ELEMENT, $data);
- }
-
-
- /**
- * Filters data set. Removes elements not listed in $ids list.
- *
- * @param array $ids List of IDs to remove.
- */
- public function filter($ids = array())
- {
- $data = $this->get();
- $data = array_intersect($data, $ids);
-
- $this->meta = array();
- $this->meta['count'] = count($data);
- $this->raw_data = implode(self::SEPARATOR_ELEMENT, $data);
- }
-
-
- /**
- * Reverts order of elements in the result
- */
- public function revert()
- {
- $this->order = $this->order == 'ASC' ? 'DESC' : 'ASC';
-
- if (empty($this->raw_data)) {
- return;
- }
-
- // @TODO: maybe do this in chunks
- $data = $this->get();
- $data = array_reverse($data);
- $this->raw_data = implode(self::SEPARATOR_ELEMENT, $data);
-
- $this->meta['pos'] = array();
- }
-
-
- /**
- * Check if the given message ID exists in the object
- *
- * @param int $msgid Message ID
- * @param bool $get_index When enabled element's index will be returned.
- * Elements are indexed starting with 0
- *
- * @return mixed False if message ID doesn't exist, True if exists or
- * index of the element if $get_index=true
- */
- public function exists($msgid, $get_index = false)
- {
- if (empty($this->raw_data)) {
- return false;
- }
-
- $msgid = (int) $msgid;
- $begin = implode('|', array('^', preg_quote(self::SEPARATOR_ELEMENT, '/')));
- $end = implode('|', array('$', preg_quote(self::SEPARATOR_ELEMENT, '/')));
-
- if (preg_match("/($begin)$msgid($end)/", $this->raw_data, $m,
- $get_index ? PREG_OFFSET_CAPTURE : null)
- ) {
- if ($get_index) {
- $idx = 0;
- if ($m[0][1]) {
- $idx = 1 + substr_count($this->raw_data, self::SEPARATOR_ELEMENT, 0, $m[0][1]);
- }
- // cache position of this element, so we can use it in get_element()
- $this->meta['pos'][$idx] = (int)$m[0][1];
-
- return $idx;
- }
- return true;
- }
-
- return false;
- }
-
-
- /**
- * Return all messages in the result.
- *
- * @return array List of message IDs
- */
- public function get()
- {
- if (empty($this->raw_data)) {
- return array();
- }
-
- return explode(self::SEPARATOR_ELEMENT, $this->raw_data);
- }
-
-
- /**
- * Return all messages in the result.
- *
- * @return array List of message IDs
- */
- public function get_compressed()
- {
- if (empty($this->raw_data)) {
- return '';
- }
-
- return rcube_imap_generic::compressMessageSet($this->get());
- }
-
-
- /**
- * Return result element at specified index
- *
- * @param int|string $index Element's index or "FIRST" or "LAST"
- *
- * @return int Element value
- */
- public function get_element($index)
- {
- $count = $this->count();
-
- if (!$count) {
- return null;
- }
-
- // first element
- if ($index === 0 || $index === '0' || $index === 'FIRST') {
- $pos = strpos($this->raw_data, self::SEPARATOR_ELEMENT);
- if ($pos === false)
- $result = (int) $this->raw_data;
- else
- $result = (int) substr($this->raw_data, 0, $pos);
-
- return $result;
- }
-
- // last element
- if ($index === 'LAST' || $index == $count-1) {
- $pos = strrpos($this->raw_data, self::SEPARATOR_ELEMENT);
- if ($pos === false)
- $result = (int) $this->raw_data;
- else
- $result = (int) substr($this->raw_data, $pos);
-
- return $result;
- }
-
- // do we know the position of the element or the neighbour of it?
- if (!empty($this->meta['pos'])) {
- if (isset($this->meta['pos'][$index]))
- $pos = $this->meta['pos'][$index];
- else if (isset($this->meta['pos'][$index-1]))
- $pos = strpos($this->raw_data, self::SEPARATOR_ELEMENT,
- $this->meta['pos'][$index-1] + 1);
- else if (isset($this->meta['pos'][$index+1]))
- $pos = strrpos($this->raw_data, self::SEPARATOR_ELEMENT,
- $this->meta['pos'][$index+1] - $this->length() - 1);
-
- if (isset($pos) && preg_match('/([0-9]+)/', $this->raw_data, $m, null, $pos)) {
- return (int) $m[1];
- }
- }
-
- // Finally use less effective method
- $data = explode(self::SEPARATOR_ELEMENT, $this->raw_data);
-
- return $data[$index];
- }
-
-
- /**
- * Returns response parameters, e.g. ESEARCH's MIN/MAX/COUNT/ALL/MODSEQ
- * or internal data e.g. MAILBOX, ORDER
- *
- * @param string $param Parameter name
- *
- * @return array|string Response parameters or parameter value
- */
- public function get_parameters($param=null)
- {
- $params = $this->params;
- $params['MAILBOX'] = $this->mailbox;
- $params['ORDER'] = $this->order;
-
- if ($param !== null) {
- return $params[$param];
- }
-
- return $params;
- }
-
-
- /**
- * Returns length of internal data representation
- *
- * @return int Data length
- */
- protected function length()
- {
- if (!isset($this->meta['length'])) {
- $this->meta['length'] = strlen($this->raw_data);
- }
-
- return $this->meta['length'];
- }
-}
diff --git a/lib/ext/Roundcube/rcube_result_multifolder.php b/lib/ext/Roundcube/rcube_result_multifolder.php
deleted file mode 100644
index 786ee85..0000000
--- a/lib/ext/Roundcube/rcube_result_multifolder.php
+++ /dev/null
@@ -1,337 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | 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 General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | SORT/SEARCH/ESEARCH response handler |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class holding a set of rcube_result_index instances that together form a
- * result set of a multi-folder search
- *
- * @package Framework
- * @subpackage Storage
- */
-class rcube_result_multifolder
-{
- public $multi = true;
- public $sets = array();
- public $incomplete = false;
- public $folder;
-
- protected $meta = array();
- protected $index = array();
- protected $folders = array();
- protected $order = 'ASC';
- protected $sorting;
-
-
- /**
- * Object constructor.
- */
- public function __construct($folders = array())
- {
- $this->folders = $folders;
- $this->meta = array('count' => 0);
- }
-
-
- /**
- * Initializes object with SORT command response
- *
- * @param string $data IMAP response string
- */
- public function add($result)
- {
- $this->sets[] = $result;
-
- if ($result->count()) {
- $this->append_result($result);
- }
- else if ($result->incomplete) {
- $this->incomplete = true;
- }
- }
-
- /**
- * Append message UIDs from the given result to our index
- */
- protected function append_result($result)
- {
- $this->meta['count'] += $result->count();
-
- // append UIDs to global index
- $folder = $result->get_parameters('MAILBOX');
- $index = array_map(function($uid) use ($folder) { return $uid . '-' . $folder; }, $result->get());
-
- $this->index = array_merge($this->index, $index);
- }
-
- /**
- * Store a global index of (sorted) message UIDs
- */
- public function set_message_index($headers, $sort_field, $sort_order)
- {
- $this->index = array();
- foreach ($headers as $header) {
- $this->index[] = $header->uid . '-' . $header->folder;
- }
-
- $this->sorting = $sort_field;
- $this->order = $sort_order;
- }
-
- /**
- * Checks the result from IMAP command
- *
- * @return bool True if the result is an error, False otherwise
- */
- public function is_error()
- {
- return false;
- }
-
-
- /**
- * Checks if the result is empty
- *
- * @return bool True if the result is empty, False otherwise
- */
- public function is_empty()
- {
- return empty($this->sets) || $this->meta['count'] == 0;
- }
-
-
- /**
- * Returns number of elements in the result
- *
- * @return int Number of elements
- */
- public function count()
- {
- return $this->meta['count'];
- }
-
-
- /**
- * Returns number of elements in the result.
- * Alias for count() for compatibility with rcube_result_thread
- *
- * @return int Number of elements
- */
- public function count_messages()
- {
- return $this->count();
- }
-
-
- /**
- * Reverts order of elements in the result
- */
- public function revert()
- {
- $this->order = $this->order == 'ASC' ? 'DESC' : 'ASC';
- $this->index = array();
-
- // revert order in all sub-sets
- foreach ($this->sets as $set) {
- if ($this->order != $set->get_parameters('ORDER')) {
- $set->revert();
- }
-
- $folder = $set->get_parameters('MAILBOX');
- $index = array_map(function($uid) use ($folder) { return $uid . '-' . $folder; }, $set->get());
-
- $this->index = array_merge($this->index, $index);
- }
- }
-
-
- /**
- * Check if the given message ID exists in the object
- *
- * @param int $msgid Message ID
- * @param bool $get_index When enabled element's index will be returned.
- * Elements are indexed starting with 0
- * @return mixed False if message ID doesn't exist, True if exists or
- * index of the element if $get_index=true
- */
- public function exists($msgid, $get_index = false)
- {
- if (!empty($this->folder)) {
- $msgid .= '-' . $this->folder;
- }
-
- return array_search($msgid, $this->index);
- }
-
-
- /**
- * Filters data set. Removes elements listed in $ids list.
- *
- * @param array $ids List of IDs to remove.
- * @param string $folder IMAP folder
- */
- public function filter($ids = array(), $folder = null)
- {
- $this->meta['count'] = 0;
- foreach ($this->sets as $set) {
- if ($set->get_parameters('MAILBOX') == $folder) {
- $set->filter($ids);
- }
-
- $this->meta['count'] += $set->count();
- }
- }
-
- /**
- * Slices data set.
- *
- * @param $offset Offset (as for PHP's array_slice())
- * @param $length Number of elements (as for PHP's array_slice())
- *
- */
- public function slice($offset, $length)
- {
- $data = array_slice($this->get(), $offset, $length);
-
- $this->index = $data;
- $this->meta['count'] = count($data);
- }
-
- /**
- * Filters data set. Removes elements not listed in $ids list.
- *
- * @param array $ids List of IDs to keep.
- */
- public function intersect($ids = array())
- {
- // not implemented
- }
-
- /**
- * Return all messages in the result.
- *
- * @return array List of message IDs
- */
- public function get()
- {
- return $this->index;
- }
-
-
- /**
- * Return all messages in the result.
- *
- * @return array List of message IDs
- */
- public function get_compressed()
- {
- return '';
- }
-
-
- /**
- * Return result element at specified index
- *
- * @param int|string $index Element's index or "FIRST" or "LAST"
- *
- * @return int Element value
- */
- public function get_element($idx)
- {
- switch ($idx) {
- case 'FIRST': return $this->index[0];
- case 'LAST': return end($this->index);
- default: return $this->index[$idx];
- }
- }
-
-
- /**
- * Returns response parameters, e.g. ESEARCH's MIN/MAX/COUNT/ALL/MODSEQ
- * or internal data e.g. MAILBOX, ORDER
- *
- * @param string $param Parameter name
- *
- * @return array|string Response parameters or parameter value
- */
- public function get_parameters($param=null)
- {
- $params = array(
- 'SORT' => $this->sorting,
- 'ORDER' => $this->order,
- 'MAILBOX' => $this->folders,
- );
-
- if ($param !== null) {
- return $params[$param];
- }
-
- return $params;
- }
-
- /**
- * Returns the stored result object for a particular folder
- *
- * @param string $folder Folder name
- * @return false|obejct rcube_result_* instance of false if none found
- */
- public function get_set($folder)
- {
- foreach ($this->sets as $set) {
- if ($set->get_parameters('MAILBOX') == $folder) {
- return $set;
- }
- }
-
- return false;
- }
-
- /**
- * Returns length of internal data representation
- *
- * @return int Data length
- */
- protected function length()
- {
- return $this->count();
- }
-
-
- /* Serialize magic methods */
-
- public function __sleep()
- {
- return array('sets','folders','sorting','order');
- }
-
- public function __wakeup()
- {
- // restore index from saved result sets
- $this->meta = array('count' => 0);
-
- foreach ($this->sets as $result) {
- if ($result->count()) {
- $this->append_result($result);
- }
- else if ($result->incomplete) {
- $this->incomplete = true;
- }
- }
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_result_set.php b/lib/ext/Roundcube/rcube_result_set.php
deleted file mode 100644
index 82502ce..0000000
--- a/lib/ext/Roundcube/rcube_result_set.php
+++ /dev/null
@@ -1,119 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2006-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Class representing an address directory result set |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Roundcube result set class
- *
- * Representing an address directory result set.
- * Implenets Iterator and thus be used in foreach() loops.
- *
- * @package Framework
- * @subpackage Addressbook
- */
-class rcube_result_set implements Iterator, ArrayAccess
-{
- public $count = 0;
- public $first = 0;
- public $searchonly = false;
- public $records = array();
-
- private $current = 0;
-
- function __construct($c=0, $f=0)
- {
- $this->count = (int)$c;
- $this->first = (int)$f;
- }
-
- function add($rec)
- {
- $this->records[] = $rec;
- }
-
- function iterate()
- {
- return $this->records[$this->current++];
- }
-
- function first()
- {
- $this->current = 0;
- return $this->records[$this->current];
- }
-
- function seek($i)
- {
- $this->current = $i;
- }
-
- /*** Implement PHP ArrayAccess interface ***/
-
- public function offsetSet($offset, $value)
- {
- if (is_null($offset)) {
- $offset = count($this->records);
- $this->records[] = $value;
- }
- else {
- $this->records[$offset] = $value;
- }
- }
-
- public function offsetExists($offset)
- {
- return isset($this->records[$offset]);
- }
-
- public function offsetUnset($offset)
- {
- unset($this->records[$offset]);
- }
-
- public function offsetGet($offset)
- {
- return $this->records[$offset];
- }
-
- /*** PHP 5 Iterator interface ***/
-
- function rewind()
- {
- $this->current = 0;
- }
-
- function current()
- {
- return $this->records[$this->current];
- }
-
- function key()
- {
- return $this->current;
- }
-
- function next()
- {
- return $this->iterate();
- }
-
- function valid()
- {
- return isset($this->records[$this->current]);
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_result_thread.php b/lib/ext/Roundcube/rcube_result_thread.php
deleted file mode 100644
index 1687616..0000000
--- a/lib/ext/Roundcube/rcube_result_thread.php
+++ /dev/null
@@ -1,681 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | 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 General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | THREAD response handler |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class for accessing IMAP's THREAD result
- *
- * @package Framework
- * @subpackage Storage
- */
-class rcube_result_thread
-{
- public $incomplete = false;
-
- protected $raw_data;
- protected $mailbox;
- protected $meta = array();
- protected $order = 'ASC';
-
- const SEPARATOR_ELEMENT = ' ';
- const SEPARATOR_ITEM = '~';
- const SEPARATOR_LEVEL = ':';
-
-
- /**
- * Object constructor.
- */
- public function __construct($mailbox = null, $data = null)
- {
- $this->mailbox = $mailbox;
- $this->init($data);
- }
-
-
- /**
- * Initializes object with IMAP command response
- *
- * @param string $data IMAP response string
- */
- public function init($data = null)
- {
- $this->meta = array();
-
- $data = explode('*', (string)$data);
-
- // ...skip unilateral untagged server responses
- for ($i=0, $len=count($data); $i<$len; $i++) {
- if (preg_match('/^ THREAD/i', $data[$i])) {
- // valid response, initialize raw_data for is_error()
- $this->raw_data = '';
- $data[$i] = substr($data[$i], 7);
- break;
- }
-
- unset($data[$i]);
- }
-
- if (empty($data)) {
- return;
- }
-
- $data = array_shift($data);
- $data = trim($data);
- $data = preg_replace('/[\r\n]/', '', $data);
- $data = preg_replace('/\s+/', ' ', $data);
-
- $this->raw_data = $this->parse_thread($data);
- }
-
-
- /**
- * Checks the result from IMAP command
- *
- * @return bool True if the result is an error, False otherwise
- */
- public function is_error()
- {
- return $this->raw_data === null ? true : false;
- }
-
-
- /**
- * Checks if the result is empty
- *
- * @return bool True if the result is empty, False otherwise
- */
- public function is_empty()
- {
- return empty($this->raw_data) ? true : false;
- }
-
-
- /**
- * Returns number of elements (threads) in the result
- *
- * @return int Number of elements
- */
- public function count()
- {
- if ($this->meta['count'] !== null)
- return $this->meta['count'];
-
- if (empty($this->raw_data)) {
- $this->meta['count'] = 0;
- }
- else {
- $this->meta['count'] = 1 + substr_count($this->raw_data, self::SEPARATOR_ELEMENT);
- }
-
- if (!$this->meta['count'])
- $this->meta['messages'] = 0;
-
- return $this->meta['count'];
- }
-
-
- /**
- * Returns number of all messages in the result
- *
- * @return int Number of elements
- */
- public function count_messages()
- {
- if ($this->meta['messages'] !== null)
- return $this->meta['messages'];
-
- if (empty($this->raw_data)) {
- $this->meta['messages'] = 0;
- }
- else {
- $this->meta['messages'] = 1
- + substr_count($this->raw_data, self::SEPARATOR_ELEMENT)
- + substr_count($this->raw_data, self::SEPARATOR_ITEM);
- }
-
- if ($this->meta['messages'] == 0 || $this->meta['messages'] == 1)
- $this->meta['count'] = $this->meta['messages'];
-
- return $this->meta['messages'];
- }
-
-
- /**
- * Returns maximum message identifier in the result
- *
- * @return int Maximum message identifier
- */
- public function max()
- {
- if (!isset($this->meta['max'])) {
- $this->meta['max'] = (int) @max($this->get());
- }
- return $this->meta['max'];
- }
-
-
- /**
- * Returns minimum message identifier in the result
- *
- * @return int Minimum message identifier
- */
- public function min()
- {
- if (!isset($this->meta['min'])) {
- $this->meta['min'] = (int) @min($this->get());
- }
- return $this->meta['min'];
- }
-
-
- /**
- * Slices data set.
- *
- * @param $offset Offset (as for PHP's array_slice())
- * @param $length Number of elements (as for PHP's array_slice())
- */
- public function slice($offset, $length)
- {
- $data = explode(self::SEPARATOR_ELEMENT, $this->raw_data);
- $data = array_slice($data, $offset, $length);
-
- $this->meta = array();
- $this->meta['count'] = count($data);
- $this->raw_data = implode(self::SEPARATOR_ELEMENT, $data);
- }
-
-
- /**
- * Filters data set. Removes threads not listed in $roots list.
- *
- * @param array $roots List of IDs of thread roots.
- */
- public function filter($roots)
- {
- $datalen = strlen($this->raw_data);
- $roots = array_flip($roots);
- $result = '';
- $start = 0;
-
- $this->meta = array();
- $this->meta['count'] = 0;
-
- while (($pos = @strpos($this->raw_data, self::SEPARATOR_ELEMENT, $start))
- || ($start < $datalen && ($pos = $datalen))
- ) {
- $len = $pos - $start;
- $elem = substr($this->raw_data, $start, $len);
- $start = $pos + 1;
-
- // extract root message ID
- if ($npos = strpos($elem, self::SEPARATOR_ITEM)) {
- $root = (int) substr($elem, 0, $npos);
- }
- else {
- $root = $elem;
- }
-
- if (isset($roots[$root])) {
- $this->meta['count']++;
- $result .= self::SEPARATOR_ELEMENT . $elem;
- }
- }
-
- $this->raw_data = ltrim($result, self::SEPARATOR_ELEMENT);
- }
-
-
- /**
- * Reverts order of elements in the result
- */
- public function revert()
- {
- $this->order = $this->order == 'ASC' ? 'DESC' : 'ASC';
-
- if (empty($this->raw_data)) {
- return;
- }
-
- $this->meta['pos'] = array();
- $datalen = strlen($this->raw_data);
- $result = '';
- $start = 0;
-
- while (($pos = @strpos($this->raw_data, self::SEPARATOR_ELEMENT, $start))
- || ($start < $datalen && ($pos = $datalen))
- ) {
- $len = $pos - $start;
- $elem = substr($this->raw_data, $start, $len);
- $start = $pos + 1;
-
- $result = $elem . self::SEPARATOR_ELEMENT . $result;
- }
-
- $this->raw_data = rtrim($result, self::SEPARATOR_ELEMENT);
- }
-
-
- /**
- * Check if the given message ID exists in the object
- *
- * @param int $msgid Message ID
- * @param bool $get_index When enabled element's index will be returned.
- * Elements are indexed starting with 0
- *
- * @return boolean True on success, False if message ID doesn't exist
- */
- public function exists($msgid, $get_index = false)
- {
- $msgid = (int) $msgid;
- $begin = implode('|', array(
- '^',
- preg_quote(self::SEPARATOR_ELEMENT, '/'),
- preg_quote(self::SEPARATOR_LEVEL, '/'),
- ));
- $end = implode('|', array(
- '$',
- preg_quote(self::SEPARATOR_ELEMENT, '/'),
- preg_quote(self::SEPARATOR_ITEM, '/'),
- ));
-
- if (preg_match("/($begin)$msgid($end)/", $this->raw_data, $m,
- $get_index ? PREG_OFFSET_CAPTURE : null)
- ) {
- if ($get_index) {
- $idx = 0;
- if ($m[0][1]) {
- $idx = substr_count($this->raw_data, self::SEPARATOR_ELEMENT, 0, $m[0][1]+1)
- + substr_count($this->raw_data, self::SEPARATOR_ITEM, 0, $m[0][1]+1);
- }
- // cache position of this element, so we can use it in get_element()
- $this->meta['pos'][$idx] = (int)$m[0][1];
-
- return $idx;
- }
- return true;
- }
-
- return false;
- }
-
-
- /**
- * Return IDs of all messages in the result. Threaded data will be flattened.
- *
- * @return array List of message identifiers
- */
- public function get()
- {
- if (empty($this->raw_data)) {
- return array();
- }
-
- $regexp = '/(' . preg_quote(self::SEPARATOR_ELEMENT, '/')
- . '|' . preg_quote(self::SEPARATOR_ITEM, '/') . '[0-9]+' . preg_quote(self::SEPARATOR_LEVEL, '/')
- .')/';
-
- return preg_split($regexp, $this->raw_data);
- }
-
-
- /**
- * Return all messages in the result.
- *
- * @return array List of message identifiers
- */
- public function get_compressed()
- {
- if (empty($this->raw_data)) {
- return '';
- }
-
- return rcube_imap_generic::compressMessageSet($this->get());
- }
-
-
- /**
- * Return result element at specified index (all messages, not roots)
- *
- * @param int|string $index Element's index or "FIRST" or "LAST"
- *
- * @return int Element value
- */
- public function get_element($index)
- {
- $count = $this->count();
-
- if (!$count) {
- return null;
- }
-
- // first element
- if ($index === 0 || $index === '0' || $index === 'FIRST') {
- preg_match('/^([0-9]+)/', $this->raw_data, $m);
- $result = (int) $m[1];
- return $result;
- }
-
- // last element
- if ($index === 'LAST' || $index == $count-1) {
- preg_match('/([0-9]+)$/', $this->raw_data, $m);
- $result = (int) $m[1];
- return $result;
- }
-
- // do we know the position of the element or the neighbour of it?
- if (!empty($this->meta['pos'])) {
- $element = preg_quote(self::SEPARATOR_ELEMENT, '/');
- $item = preg_quote(self::SEPARATOR_ITEM, '/') . '[0-9]+' . preg_quote(self::SEPARATOR_LEVEL, '/') .'?';
- $regexp = '(' . $element . '|' . $item . ')';
-
- if (isset($this->meta['pos'][$index])) {
- if (preg_match('/([0-9]+)/', $this->raw_data, $m, null, $this->meta['pos'][$index]))
- $result = $m[1];
- }
- else if (isset($this->meta['pos'][$index-1])) {
- // get chunk of data after previous element
- $data = substr($this->raw_data, $this->meta['pos'][$index-1]+1, 50);
- $data = preg_replace('/^[0-9]+/', '', $data); // remove UID at $index position
- $data = preg_replace("/^$regexp/", '', $data); // remove separator
- if (preg_match('/^([0-9]+)/', $data, $m))
- $result = $m[1];
- }
- else if (isset($this->meta['pos'][$index+1])) {
- // get chunk of data before next element
- $pos = max(0, $this->meta['pos'][$index+1] - 50);
- $len = min(50, $this->meta['pos'][$index+1]);
- $data = substr($this->raw_data, $pos, $len);
- $data = preg_replace("/$regexp\$/", '', $data); // remove separator
-
- if (preg_match('/([0-9]+)$/', $data, $m))
- $result = $m[1];
- }
-
- if (isset($result)) {
- return (int) $result;
- }
- }
-
- // Finally use less effective method
- $data = $this->get();
-
- return $data[$index];
- }
-
-
- /**
- * Returns response parameters e.g. MAILBOX, ORDER
- *
- * @param string $param Parameter name
- *
- * @return array|string Response parameters or parameter value
- */
- public function get_parameters($param=null)
- {
- $params = $this->params;
- $params['MAILBOX'] = $this->mailbox;
- $params['ORDER'] = $this->order;
-
- if ($param !== null) {
- return $params[$param];
- }
-
- return $params;
- }
-
-
- /**
- * THREAD=REFS sorting implementation (based on provided index)
- *
- * @param rcube_result_index $index Sorted message identifiers
- */
- public function sort($index)
- {
- $this->sort_order = $index->get_parameters('ORDER');
-
- if (empty($this->raw_data)) {
- return;
- }
-
- // when sorting search result it's good to make the index smaller
- if ($index->count() != $this->count_messages()) {
- $index->filter($this->get());
- }
-
- $result = array_fill_keys($index->get(), null);
- $datalen = strlen($this->raw_data);
- $start = 0;
-
- // Here we're parsing raw_data twice, we want only one big array
- // in memory at a time
-
- // Assign roots
- while (($pos = @strpos($this->raw_data, self::SEPARATOR_ELEMENT, $start))
- || ($start < $datalen && ($pos = $datalen))
- ) {
- $len = $pos - $start;
- $elem = substr($this->raw_data, $start, $len);
- $start = $pos + 1;
-
- $items = explode(self::SEPARATOR_ITEM, $elem);
- $root = (int) array_shift($items);
-
- if ($root) {
- $result[$root] = $root;
- foreach ($items as $item) {
- list($lv, $id) = explode(self::SEPARATOR_LEVEL, $item);
- $result[$id] = $root;
- }
- }
- }
-
- // get only unique roots
- $result = array_filter($result); // make sure there are no nulls
- $result = array_unique($result);
-
- // Re-sort raw data
- $result = array_fill_keys($result, null);
- $start = 0;
-
- while (($pos = @strpos($this->raw_data, self::SEPARATOR_ELEMENT, $start))
- || ($start < $datalen && ($pos = $datalen))
- ) {
- $len = $pos - $start;
- $elem = substr($this->raw_data, $start, $len);
- $start = $pos + 1;
-
- $npos = strpos($elem, self::SEPARATOR_ITEM);
- $root = (int) ($npos ? substr($elem, 0, $npos) : $elem);
-
- $result[$root] = $elem;
- }
-
- $this->raw_data = implode(self::SEPARATOR_ELEMENT, $result);
- }
-
-
- /**
- * Returns data as tree
- *
- * @return array Data tree
- */
- public function get_tree()
- {
- $datalen = strlen($this->raw_data);
- $result = array();
- $start = 0;
-
- while (($pos = @strpos($this->raw_data, self::SEPARATOR_ELEMENT, $start))
- || ($start < $datalen && ($pos = $datalen))
- ) {
- $len = $pos - $start;
- $elem = substr($this->raw_data, $start, $len);
- $items = explode(self::SEPARATOR_ITEM, $elem);
- $result[array_shift($items)] = $this->build_thread($items);
- $start = $pos + 1;
- }
-
- return $result;
- }
-
-
- /**
- * Returns thread depth and children data
- *
- * @return array Thread data
- */
- public function get_thread_data()
- {
- $data = $this->get_tree();
- $depth = array();
- $children = array();
-
- $this->build_thread_data($data, $depth, $children);
-
- return array($depth, $children);
- }
-
-
- /**
- * Creates 'depth' and 'children' arrays from stored thread 'tree' data.
- */
- protected function build_thread_data($data, &$depth, &$children, $level = 0)
- {
- foreach ((array)$data as $key => $val) {
- $empty = empty($val) || !is_array($val);
- $children[$key] = !$empty;
- $depth[$key] = $level;
- if (!$empty) {
- $this->build_thread_data($val, $depth, $children, $level + 1);
- }
- }
- }
-
-
- /**
- * Converts part of the raw thread into an array
- */
- protected function build_thread($items, $level = 1, &$pos = 0)
- {
- $result = array();
-
- for ($len=count($items); $pos < $len; $pos++) {
- list($lv, $id) = explode(self::SEPARATOR_LEVEL, $items[$pos]);
- if ($level == $lv) {
- $pos++;
- $result[$id] = $this->build_thread($items, $level+1, $pos);
- }
- else {
- $pos--;
- break;
- }
- }
-
- return $result;
- }
-
-
- /**
- * IMAP THREAD response parser
- */
- protected function parse_thread($str, $begin = 0, $end = 0, $depth = 0)
- {
- // Don't be tempted to change $str to pass by reference to speed this up - it will slow it down by about
- // 7 times instead :-) See comments on http://uk2.php.net/references and this article:
- // http://derickrethans.nl/files/phparch-php-variables-article.pdf
- $node = '';
- if (!$end) {
- $end = strlen($str);
- }
-
- // Let's try to store data in max. compacted stracture as a string,
- // arrays handling is much more expensive
- // For the following structure: THREAD (2)(3 6 (4 23)(44 7 96))
- // -- 2
- // -- 3
- // \-- 6
- // |-- 4
- // | \-- 23
- // |
- // \-- 44
- // \-- 7
- // \-- 96
- //
- // The output will be: 2,3^1:6^2:4^3:23^2:44^3:7^4:96
-
- if ($str[$begin] != '(') {
- // find next bracket
- $stop = $begin + strcspn($str, '()', $begin, $end - $begin);
- $messages = explode(' ', trim(substr($str, $begin, $stop - $begin)));
-
- if (empty($messages)) {
- return $node;
- }
-
- foreach ($messages as $msg) {
- if ($msg) {
- $node .= ($depth ? self::SEPARATOR_ITEM.$depth.self::SEPARATOR_LEVEL : '').$msg;
- $this->meta['messages']++;
- $depth++;
- }
- }
-
- if ($stop < $end) {
- $node .= $this->parse_thread($str, $stop, $end, $depth);
- }
- }
- else {
- $off = $begin;
- while ($off < $end) {
- $start = $off;
- $off++;
- $n = 1;
- while ($n > 0) {
- $p = strpos($str, ')', $off);
- if ($p === false) {
- // error, wrong structure, mismatched brackets in IMAP THREAD response
- // @TODO: write error to the log or maybe set $this->raw_data = null;
- return $node;
- }
- $p1 = strpos($str, '(', $off);
- if ($p1 !== false && $p1 < $p) {
- $off = $p1 + 1;
- $n++;
- }
- else {
- $off = $p + 1;
- $n--;
- }
- }
-
- $thread = $this->parse_thread($str, $start + 1, $off - 1, $depth);
- if ($thread) {
- if (!$depth) {
- if ($node) {
- $node .= self::SEPARATOR_ELEMENT;
- }
- }
- $node .= $thread;
- }
- }
- }
-
- return $node;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_session.php b/lib/ext/Roundcube/rcube_session.php
deleted file mode 100644
index 8306a06..0000000
--- a/lib/ext/Roundcube/rcube_session.php
+++ /dev/null
@@ -1,807 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2014, The Roundcube Dev Team |
- | Copyright (C) 2011, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Provide database supported session management |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class to provide database supported session storage
- *
- * @package Framework
- * @subpackage Core
- * @author Thomas Bruederli <roundcube@gmail.com>
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_session
-{
- private $db;
- private $ip;
- private $start;
- private $changed;
- private $time_diff = 0;
- private $reloaded = false;
- private $appends = array();
- private $unsets = array();
- private $gc_handlers = array();
- private $cookiename = 'roundcube_sessauth';
- private $vars;
- private $key;
- private $now;
- private $secret = '';
- private $ip_check = false;
- private $logging = false;
- private $storage;
- private $memcache;
-
- /**
- * Blocks session data from being written to database.
- * Can be used if write-race conditions are to be expected
- * @var boolean
- */
- public $nowrite = false;
-
-
- /**
- * Default constructor
- */
- public function __construct($db, $config)
- {
- $this->db = $db;
- $this->start = microtime(true);
- $this->ip = rcube_utils::remote_addr();
- $this->logging = $config->get('log_session', false);
-
- $lifetime = $config->get('session_lifetime', 1) * 60;
- $this->set_lifetime($lifetime);
-
- // use memcache backend
- $this->storage = $config->get('session_storage', 'db');
- if ($this->storage == 'memcache') {
- $this->memcache = rcube::get_instance()->get_memcache();
-
- // set custom functions for PHP session management if memcache is available
- if ($this->memcache) {
- ini_set('session.serialize_handler', 'php');
-
- session_set_save_handler(
- array($this, 'open'),
- array($this, 'close'),
- array($this, 'mc_read'),
- array($this, 'mc_write'),
- array($this, 'mc_destroy'),
- array($this, 'gc'));
- }
- else {
- rcube::raise_error(array('code' => 604, 'type' => 'db',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => "Failed to connect to memcached. Please check configuration"),
- true, true);
- }
- }
- else if ($this->storage != 'php') {
- ini_set('session.serialize_handler', 'php');
-
- // set custom functions for PHP session management
- session_set_save_handler(
- array($this, 'open'),
- array($this, 'close'),
- array($this, 'db_read'),
- array($this, 'db_write'),
- array($this, 'db_destroy'),
- array($this, 'gc'));
-
- $this->table_name = $this->db->table_name('session', true);
- }
- }
-
-
- /**
- * Wrapper for session_start()
- */
- public function start()
- {
- session_start();
-
- // copy some session properties to object vars
- if ($this->storage == 'php') {
- $this->key = session_id();
- $this->ip = $_SESSION['__IP'];
- $this->changed = $_SESSION['__MTIME'];
- }
- }
-
-
- public function open($save_path, $session_name)
- {
- return true;
- }
-
-
- public function close()
- {
- return true;
- }
-
-
- /**
- * Delete session data for the given key
- *
- * @param string Session ID
- */
- public function destroy($key)
- {
- return $this->memcache ? $this->mc_destroy($key) : $this->db_destroy($key);
- }
-
-
- /**
- * Wrapper for session_write_close()
- */
- public function write_close()
- {
- if ($this->storage == 'php') {
- $_SESSION['__IP'] = $this->ip;
- $_SESSION['__MTIME'] = time();
- }
-
- session_write_close();
-
- // write_close() is called on script shutdown, see rcube::shutdown()
- // execute cleanup functionality if enabled by session gc handler
- // we do this after closing the session for better performance
- $this->gc_shutdown();
- }
-
-
- /**
- * Read session data from database
- *
- * @param string Session ID
- *
- * @return string Session vars
- */
- public function db_read($key)
- {
- $sql_result = $this->db->query(
- "SELECT `vars`, `ip`, `changed`, " . $this->db->now() . " AS ts"
- . " FROM {$this->table_name} WHERE `sess_id` = ?", $key);
-
- if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) {
- $this->time_diff = time() - strtotime($sql_arr['ts']);
- $this->changed = strtotime($sql_arr['changed']);
- $this->ip = $sql_arr['ip'];
- $this->vars = base64_decode($sql_arr['vars']);
- $this->key = $key;
-
- return !empty($this->vars) ? (string) $this->vars : '';
- }
-
- return null;
- }
-
-
- /**
- * Save session data.
- * handler for session_read()
- *
- * @param string Session ID
- * @param string Serialized session vars
- *
- * @return boolean True on success
- */
- public function db_write($key, $vars)
- {
- $now = $this->db->now();
- $ts = microtime(true);
-
- if ($this->nowrite)
- return true;
-
- // no session row in DB (db_read() returns false)
- if (!$this->key) {
- $oldvars = null;
- }
- // use internal data from read() for fast requests (up to 0.5 sec.)
- else if ($key == $this->key && (!$this->vars || $ts - $this->start < 0.5)) {
- $oldvars = $this->vars;
- }
- else { // else read data again from DB
- $oldvars = $this->db_read($key);
- }
-
- if ($oldvars !== null) {
- $newvars = $this->_fixvars($vars, $oldvars);
-
- if ($newvars !== $oldvars) {
- $this->db->query("UPDATE {$this->table_name} "
- . "SET `changed` = $now, `vars` = ? WHERE `sess_id` = ?",
- base64_encode($newvars), $key);
- }
- else if ($ts - $this->changed + $this->time_diff > $this->lifetime / 2) {
- $this->db->query("UPDATE {$this->table_name} SET `changed` = $now"
- . " WHERE `sess_id` = ?", $key);
- }
- }
- else {
- $this->db->query("INSERT INTO {$this->table_name}"
- . " (`sess_id`, `vars`, `ip`, `created`, `changed`)"
- . " VALUES (?, ?, ?, $now, $now)",
- $key, base64_encode($vars), (string)$this->ip);
- }
-
- return true;
- }
-
-
- /**
- * Merge vars with old vars and apply unsets
- */
- private function _fixvars($vars, $oldvars)
- {
- if ($oldvars !== null) {
- $a_oldvars = $this->unserialize($oldvars);
- if (is_array($a_oldvars)) {
- // remove unset keys on oldvars
- foreach ((array)$this->unsets as $var) {
- if (isset($a_oldvars[$var])) {
- unset($a_oldvars[$var]);
- }
- else {
- $path = explode('.', $var);
- $k = array_pop($path);
- $node = &$this->get_node($path, $a_oldvars);
- unset($node[$k]);
- }
- }
-
- $newvars = $this->serialize(array_merge(
- (array)$a_oldvars, (array)$this->unserialize($vars)));
- }
- else {
- $newvars = $vars;
- }
- }
-
- $this->unsets = array();
- return $newvars;
- }
-
-
- /**
- * Handler for session_destroy()
- *
- * @param string Session ID
- *
- * @return boolean True on success
- */
- public function db_destroy($key)
- {
- if ($key) {
- $this->db->query("DELETE FROM {$this->table_name} WHERE `sess_id` = ?", $key);
- }
-
- return true;
- }
-
-
- /**
- * Read session data from memcache
- *
- * @param string Session ID
- * @return string Session vars
- */
- public function mc_read($key)
- {
- if ($value = $this->memcache->get($key)) {
- $arr = unserialize($value);
- $this->changed = $arr['changed'];
- $this->ip = $arr['ip'];
- $this->vars = $arr['vars'];
- $this->key = $key;
-
- return !empty($this->vars) ? (string) $this->vars : '';
- }
-
- return null;
- }
-
-
- /**
- * Save session data.
- * handler for session_read()
- *
- * @param string Session ID
- * @param string Serialized session vars
- *
- * @return boolean True on success
- */
- public function mc_write($key, $vars)
- {
- $ts = microtime(true);
-
- // no session data in cache (mc_read() returns false)
- if (!$this->key)
- $oldvars = null;
- // use internal data for fast requests (up to 0.5 sec.)
- else if ($key == $this->key && (!$this->vars || $ts - $this->start < 0.5))
- $oldvars = $this->vars;
- else // else read data again
- $oldvars = $this->mc_read($key);
-
- $newvars = $oldvars !== null ? $this->_fixvars($vars, $oldvars) : $vars;
-
- if ($newvars !== $oldvars || $ts - $this->changed > $this->lifetime / 3) {
- return $this->memcache->set($key, serialize(array('changed' => time(), 'ip' => $this->ip, 'vars' => $newvars)),
- MEMCACHE_COMPRESSED, $this->lifetime + 60);
- }
-
- return true;
- }
-
-
- /**
- * Handler for session_destroy() with memcache backend
- *
- * @param string Session ID
- *
- * @return boolean True on success
- */
- public function mc_destroy($key)
- {
- if ($key) {
- // #1488592: use 2nd argument
- $this->memcache->delete($key, 0);
- }
-
- return true;
- }
-
-
- /**
- * Execute registered garbage collector routines
- */
- public function gc($maxlifetime)
- {
- // move gc execution to the script shutdown function
- // see rcube::shutdown() and rcube_session::write_close()
- return $this->gc_enabled = $maxlifetime;
- }
-
-
- /**
- * Register additional garbage collector functions
- *
- * @param mixed Callback function
- */
- public function register_gc_handler($func)
- {
- foreach ($this->gc_handlers as $handler) {
- if ($handler == $func) {
- return;
- }
- }
-
- $this->gc_handlers[] = $func;
- }
-
-
- /**
- * Garbage collector handler to run on script shutdown
- */
- protected function gc_shutdown()
- {
- if ($this->gc_enabled) {
- // just delete all expired sessions
- if ($this->storage == 'db') {
- $this->db->query("DELETE FROM {$this->table_name}"
- . " WHERE `changed` < " . $this->db->now(-$this->gc_enabled));
- }
-
- foreach ($this->gc_handlers as $fct) {
- call_user_func($fct);
- }
- }
- }
-
-
- /**
- * Generate and set new session id
- *
- * @param boolean $destroy If enabled the current session will be destroyed
- */
- public function regenerate_id($destroy=true)
- {
- session_regenerate_id($destroy);
-
- $this->vars = null;
- $this->key = session_id();
-
- return true;
- }
-
-
- /**
- * Append the given value to the certain node in the session data array
- *
- * @param string Path denoting the session variable where to append the value
- * @param string Key name under which to append the new value (use null for appending to an indexed list)
- * @param mixed Value to append to the session data array
- */
- public function append($path, $key, $value)
- {
- // re-read session data from DB because it might be outdated
- if (!$this->reloaded && microtime(true) - $this->start > 0.5) {
- $this->reload();
- $this->reloaded = true;
- $this->start = microtime(true);
- }
-
- $node = &$this->get_node(explode('.', $path), $_SESSION);
-
- if ($key !== null) {
- $node[$key] = $value;
- $path .= '.' . $key;
- }
- else {
- $node[] = $value;
- }
-
- $this->appends[] = $path;
-
- // when overwriting a previously unset variable
- if ($this->unsets[$path])
- unset($this->unsets[$path]);
- }
-
-
- /**
- * Unset a session variable
- *
- * @param string Variable name (can be a path denoting a certain node in the session array, e.g. compose.attachments.5)
- * @return boolean True on success
- */
- public function remove($var=null)
- {
- if (empty($var)) {
- return $this->destroy(session_id());
- }
-
- $this->unsets[] = $var;
-
- if (isset($_SESSION[$var])) {
- unset($_SESSION[$var]);
- }
- else {
- $path = explode('.', $var);
- $key = array_pop($path);
- $node = &$this->get_node($path, $_SESSION);
- unset($node[$key]);
- }
-
- return true;
- }
-
-
- /**
- * Kill this session
- */
- public function kill()
- {
- $this->vars = null;
- $this->ip = rcube_utils::remote_addr(); // update IP (might have changed)
- $this->destroy(session_id());
- rcube_utils::setcookie($this->cookiename, '-del-', time() - 60);
- }
-
-
- /**
- * Re-read session data from storage backend
- */
- public function reload()
- {
- // collect updated data from previous appends
- $merge_data = array();
- foreach ((array)$this->appends as $var) {
- $path = explode('.', $var);
- $value = $this->get_node($path, $_SESSION);
- $k = array_pop($path);
- $node = &$this->get_node($path, $merge_data);
- $node[$k] = $value;
- }
-
- 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);
-
- // apply appends and unsets to reloaded data
- $_SESSION = array_merge_recursive($_SESSION, $merge_data);
-
- foreach ((array)$this->unsets as $var) {
- if (isset($_SESSION[$var])) {
- unset($_SESSION[$var]);
- }
- else {
- $path = explode('.', $var);
- $k = array_pop($path);
- $node = &$this->get_node($path, $_SESSION);
- unset($node[$k]);
- }
- }
- }
-
- }
-
- /**
- * Returns a reference to the node in data array referenced by the given path.
- * e.g. ['compose','attachments'] will return $_SESSION['compose']['attachments']
- */
- private function &get_node($path, &$data_arr)
- {
- $node = &$data_arr;
- if (!empty($path)) {
- foreach ((array)$path as $key) {
- if (!isset($node[$key]))
- $node[$key] = array();
- $node = &$node[$key];
- }
- }
-
- return $node;
- }
-
- /**
- * Serialize session data
- */
- private function serialize($vars)
- {
- $data = '';
- if (is_array($vars)) {
- foreach ($vars as $var=>$value)
- $data .= $var.'|'.serialize($value);
- }
- else {
- $data = 'b:0;';
- }
-
- return $data;
- }
-
-
- /**
- * Unserialize session data
- * http://www.php.net/manual/en/function.session-decode.php#56106
- */
- private function unserialize($str)
- {
- $str = (string)$str;
- $endptr = strlen($str);
- $p = 0;
-
- $serialized = '';
- $items = 0;
- $level = 0;
-
- while ($p < $endptr) {
- $q = $p;
- while ($str[$q] != '|')
- if (++$q >= $endptr)
- break 2;
-
- if ($str[$p] == '!') {
- $p++;
- $has_value = false;
- }
- else {
- $has_value = true;
- }
-
- $name = substr($str, $p, $q - $p);
- $q++;
-
- $serialized .= 's:' . strlen($name) . ':"' . $name . '";';
-
- if ($has_value) {
- for (;;) {
- $p = $q;
- switch (strtolower($str[$q])) {
- case 'n': // null
- case 'b': // boolean
- case 'i': // integer
- case 'd': // decimal
- do $q++;
- while ( ($q < $endptr) && ($str[$q] != ';') );
- $q++;
- $serialized .= substr($str, $p, $q - $p);
- if ($level == 0)
- break 2;
- break;
- case 'r': // reference
- $q+= 2;
- for ($id = ''; ($q < $endptr) && ($str[$q] != ';'); $q++)
- $id .= $str[$q];
- $q++;
- // increment pointer because of outer array
- $serialized .= 'R:' . ($id + 1) . ';';
- if ($level == 0)
- break 2;
- break;
- case 's': // string
- $q+=2;
- for ($length=''; ($q < $endptr) && ($str[$q] != ':'); $q++)
- $length .= $str[$q];
- $q+=2;
- $q+= (int)$length + 2;
- $serialized .= substr($str, $p, $q - $p);
- if ($level == 0)
- break 2;
- break;
- case 'a': // array
- case 'o': // object
- do $q++;
- while ($q < $endptr && $str[$q] != '{');
- $q++;
- $level++;
- $serialized .= substr($str, $p, $q - $p);
- break;
- case '}': // end of array|object
- $q++;
- $serialized .= substr($str, $p, $q - $p);
- if (--$level == 0)
- break 2;
- break;
- default:
- return false;
- }
- }
- }
- else {
- $serialized .= 'N;';
- $q += 2;
- }
- $items++;
- $p = $q;
- }
-
- return unserialize( 'a:' . $items . ':{' . $serialized . '}' );
- }
-
-
- /**
- * Setter for session lifetime
- */
- public function set_lifetime($lifetime)
- {
- $this->lifetime = max(120, $lifetime);
-
- // valid time range is now - 1/2 lifetime to now + 1/2 lifetime
- $now = time();
- $this->now = $now - ($now % ($this->lifetime / 2));
- }
-
-
- /**
- * Getter for remote IP saved with this session
- */
- public function get_ip()
- {
- return $this->ip;
- }
-
-
- /**
- * Setter for cookie encryption secret
- */
- function set_secret($secret)
- {
- $this->secret = $secret;
- }
-
-
- /**
- * Enable/disable IP check
- */
- function set_ip_check($check)
- {
- $this->ip_check = $check;
- }
-
-
- /**
- * Setter for the cookie name used for session cookie
- */
- function set_cookiename($cookiename)
- {
- if ($cookiename) {
- $this->cookiename = $cookiename;
- }
- }
-
-
- /**
- * Check session authentication cookie
- *
- * @return boolean True if valid, False if not
- */
- function check_auth()
- {
- $this->cookie = $_COOKIE[$this->cookiename];
- $result = $this->ip_check ? rcube_utils::remote_addr() == $this->ip : true;
-
- if (!$result) {
- $this->log("IP check failed for " . $this->key . "; expected " . $this->ip . "; got " . rcube_utils::remote_addr());
- }
-
- if ($result && $this->_mkcookie($this->now) != $this->cookie) {
- $this->log("Session auth check failed for " . $this->key . "; timeslot = " . date('Y-m-d H:i:s', $this->now));
- $result = false;
-
- // Check if using id from a previous time slot
- for ($i = 1; $i <= 2; $i++) {
- $prev = $this->now - ($this->lifetime / 2) * $i;
- if ($this->_mkcookie($prev) == $this->cookie) {
- $this->log("Send new auth cookie for " . $this->key . ": " . $this->cookie);
- $this->set_auth_cookie();
- $result = true;
- }
- }
- }
-
- if (!$result) {
- $this->log("Session authentication failed for " . $this->key
- . "; invalid auth cookie sent; timeslot = " . date('Y-m-d H:i:s', $prev));
- }
-
- return $result;
- }
-
-
- /**
- * Set session authentication cookie
- */
- function set_auth_cookie()
- {
- $this->cookie = $this->_mkcookie($this->now);
- rcube_utils::setcookie($this->cookiename, $this->cookie, 0);
- $_COOKIE[$this->cookiename] = $this->cookie;
- }
-
-
- /**
- * Create session cookie from session data
- *
- * @param int Time slot to use
- */
- function _mkcookie($timeslot)
- {
- $auth_string = "$this->key,$this->secret,$timeslot";
- return "S" . (function_exists('sha1') ? sha1($auth_string) : md5($auth_string));
- }
-
- /**
- * Writes debug information to the log
- */
- function log($line)
- {
- if ($this->logging) {
- rcube::write_log('session', $line);
- }
- }
-}
diff --git a/lib/ext/Roundcube/rcube_smtp.php b/lib/ext/Roundcube/rcube_smtp.php
deleted file mode 100644
index 70f15dc..0000000
--- a/lib/ext/Roundcube/rcube_smtp.php
+++ /dev/null
@@ -1,470 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Provide SMTP functionality using socket connections |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class to provide SMTP functionality using PEAR Net_SMTP
- *
- * @package Framework
- * @subpackage Mail
- * @author Thomas Bruederli <roundcube@gmail.com>
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_smtp
-{
- private $conn = null;
- private $response;
- private $error;
- private $anonymize_log = 0;
-
- // define headers delimiter
- const SMTP_MIME_CRLF = "\r\n";
-
- const DEBUG_LINE_LENGTH = 4098; // 4KB + 2B for \r\n
-
-
- /**
- * SMTP Connection and authentication
- *
- * @param string Server host
- * @param string Server port
- * @param string User name
- * @param string Password
- *
- * @return bool Returns true on success, or false on error
- */
- public function connect($host=null, $port=null, $user=null, $pass=null)
- {
- $rcube = rcube::get_instance();
-
- // disconnect/destroy $this->conn
- $this->disconnect();
-
- // reset error/response var
- $this->error = $this->response = null;
-
- // let plugins alter smtp connection config
- $CONFIG = $rcube->plugins->exec_hook('smtp_connect', array(
- 'smtp_server' => $host ? $host : $rcube->config->get('smtp_server'),
- 'smtp_port' => $port ? $port : $rcube->config->get('smtp_port', 25),
- 'smtp_user' => $user ? $user : $rcube->config->get('smtp_user'),
- 'smtp_pass' => $pass ? $pass : $rcube->config->get('smtp_pass'),
- 'smtp_auth_cid' => $rcube->config->get('smtp_auth_cid'),
- 'smtp_auth_pw' => $rcube->config->get('smtp_auth_pw'),
- 'smtp_auth_type' => $rcube->config->get('smtp_auth_type'),
- 'smtp_helo_host' => $rcube->config->get('smtp_helo_host'),
- 'smtp_timeout' => $rcube->config->get('smtp_timeout'),
- 'smtp_conn_options' => $rcube->config->get('smtp_conn_options'),
- 'smtp_auth_callbacks' => array(),
- ));
-
- $smtp_host = rcube_utils::parse_host($CONFIG['smtp_server']);
- // when called from Installer it's possible to have empty $smtp_host here
- if (!$smtp_host) $smtp_host = 'localhost';
- $smtp_port = is_numeric($CONFIG['smtp_port']) ? $CONFIG['smtp_port'] : 25;
- $smtp_host_url = parse_url($smtp_host);
-
- // overwrite port
- if (isset($smtp_host_url['host']) && isset($smtp_host_url['port'])) {
- $smtp_host = $smtp_host_url['host'];
- $smtp_port = $smtp_host_url['port'];
- }
-
- // re-write smtp host
- if (isset($smtp_host_url['host']) && isset($smtp_host_url['scheme'])) {
- $smtp_host = sprintf('%s://%s', $smtp_host_url['scheme'], $smtp_host_url['host']);
- }
-
- // remove TLS prefix and set flag for use in Net_SMTP::auth()
- if (preg_match('#^tls://#i', $smtp_host)) {
- $smtp_host = preg_replace('#^tls://#i', '', $smtp_host);
- $use_tls = true;
- }
-
- if (!empty($CONFIG['smtp_helo_host'])) {
- $helo_host = $CONFIG['smtp_helo_host'];
- }
- else if (!empty($_SERVER['SERVER_NAME'])) {
- $helo_host = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']);
- }
- else {
- $helo_host = 'localhost';
- }
-
- // IDNA Support
- $smtp_host = rcube_utils::idn_to_ascii($smtp_host);
-
- $this->conn = new Net_SMTP($smtp_host, $smtp_port, $helo_host, false, 0, $CONFIG['smtp_conn_options']);
-
- if ($rcube->config->get('smtp_debug')) {
- $this->conn->setDebug(true, array($this, 'debug_handler'));
- $this->anonymize_log = 0;
- }
-
- // register authentication methods
- if (!empty($CONFIG['smtp_auth_callbacks']) && method_exists($this->conn, 'setAuthMethod')) {
- foreach ($CONFIG['smtp_auth_callbacks'] as $callback) {
- $this->conn->setAuthMethod($callback['name'], $callback['function'],
- isset($callback['prepend']) ? $callback['prepend'] : true);
- }
- }
-
- // try to connect to server and exit on failure
- $result = $this->conn->connect($CONFIG['smtp_timeout']);
-
- if (PEAR::isError($result)) {
- $this->response[] = "Connection failed: ".$result->getMessage();
- $this->error = array('label' => 'smtpconnerror', 'vars' => array('code' => $this->conn->_code));
- $this->conn = null;
- return false;
- }
-
- // workaround for timeout bug in Net_SMTP 1.5.[0-1] (#1487843)
- if (method_exists($this->conn, 'setTimeout')
- && ($timeout = ini_get('default_socket_timeout'))
- ) {
- $this->conn->setTimeout($timeout);
- }
-
- $smtp_user = str_replace('%u', $rcube->get_user_name(), $CONFIG['smtp_user']);
- $smtp_pass = str_replace('%p', $rcube->get_user_password(), $CONFIG['smtp_pass']);
- $smtp_auth_type = empty($CONFIG['smtp_auth_type']) ? NULL : $CONFIG['smtp_auth_type'];
-
- if (!empty($CONFIG['smtp_auth_cid'])) {
- $smtp_authz = $smtp_user;
- $smtp_user = $CONFIG['smtp_auth_cid'];
- $smtp_pass = $CONFIG['smtp_auth_pw'];
- }
-
- // attempt to authenticate to the SMTP server
- if ($smtp_user && $smtp_pass) {
- // IDNA Support
- if (strpos($smtp_user, '@')) {
- $smtp_user = rcube_utils::idn_to_ascii($smtp_user);
- }
-
- $result = $this->conn->auth($smtp_user, $smtp_pass, $smtp_auth_type, $use_tls, $smtp_authz);
-
- if (PEAR::isError($result)) {
- $this->error = array('label' => 'smtpautherror', 'vars' => array('code' => $this->conn->_code));
- $this->response[] .= 'Authentication failure: ' . $result->getMessage() . ' (Code: ' . $result->getCode() . ')';
- $this->reset();
- $this->disconnect();
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Function for sending mail
- *
- * @param string Sender e-Mail address
- *
- * @param mixed Either a comma-seperated list of recipients
- * (RFC822 compliant), or an array of recipients,
- * each RFC822 valid. This may contain recipients not
- * specified in the headers, for Bcc:, resending
- * messages, etc.
- * @param mixed The message headers to send with the mail
- * Either as an associative array or a finally
- * formatted string
- * @param mixed The full text of the message body, including any Mime parts
- * or file handle
- * @param array Delivery options (e.g. DSN request)
- *
- * @return bool Returns true on success, or false on error
- */
- public function send_mail($from, $recipients, &$headers, &$body, $opts=null)
- {
- if (!is_object($this->conn)) {
- return false;
- }
-
- // prepare message headers as string
- if (is_array($headers)) {
- if (!($headerElements = $this->_prepare_headers($headers))) {
- $this->reset();
- return false;
- }
-
- list($from, $text_headers) = $headerElements;
- }
- else if (is_string($headers)) {
- $text_headers = $headers;
- }
- else {
- $this->reset();
- $this->response[] = "Invalid message headers";
- return false;
- }
-
- // exit if no from address is given
- if (!isset($from)) {
- $this->reset();
- $this->response[] = "No From address has been provided";
- return false;
- }
-
- // RFC3461: Delivery Status Notification
- if ($opts['dsn']) {
- $exts = $this->conn->getServiceExtensions();
-
- if (isset($exts['DSN'])) {
- $from_params = 'RET=HDRS';
- $recipient_params = 'NOTIFY=SUCCESS,FAILURE';
- }
- }
-
- // RFC2298.3: remove envelope sender address
- if (empty($opts['mdn_use_from'])
- && preg_match('/Content-Type: multipart\/report/', $text_headers)
- && preg_match('/report-type=disposition-notification/', $text_headers)
- ) {
- $from = '';
- }
-
- // set From: address
- if (PEAR::isError($this->conn->mailFrom($from, $from_params))) {
- $err = $this->conn->getResponse();
- $this->error = array('label' => 'smtpfromerror', 'vars' => array(
- 'from' => $from, 'code' => $this->conn->_code, 'msg' => $err[1]));
- $this->response[] = "Failed to set sender '$from'";
- $this->reset();
- return false;
- }
-
- // prepare list of recipients
- $recipients = $this->_parse_rfc822($recipients);
- if (PEAR::isError($recipients)) {
- $this->error = array('label' => 'smtprecipientserror');
- $this->reset();
- return false;
- }
-
- // set mail recipients
- foreach ($recipients as $recipient) {
- if (PEAR::isError($this->conn->rcptTo($recipient, $recipient_params))) {
- $err = $this->conn->getResponse();
- $this->error = array('label' => 'smtptoerror', 'vars' => array(
- 'to' => $recipient, 'code' => $this->conn->_code, 'msg' => $err[1]));
- $this->response[] = "Failed to add recipient '$recipient'";
- $this->reset();
- return false;
- }
- }
-
- if (is_resource($body)) {
- // file handle
- $data = $body;
- $text_headers = preg_replace('/[\r\n]+$/', '', $text_headers);
- }
- else {
- // Concatenate headers and body so it can be passed by reference to SMTP_CONN->data
- // so preg_replace in SMTP_CONN->quotedata will store a reference instead of a copy.
- // We are still forced to make another copy here for a couple ticks so we don't really
- // get to save a copy in the method call.
- $data = $text_headers . "\r\n" . $body;
-
- // unset old vars to save data and so we can pass into SMTP_CONN->data by reference.
- unset($text_headers, $body);
- }
-
- // Send the message's headers and the body as SMTP data.
- if (PEAR::isError($result = $this->conn->data($data, $text_headers))) {
- $err = $this->conn->getResponse();
- if (!in_array($err[0], array(354, 250, 221))) {
- $msg = sprintf('[%d] %s', $err[0], $err[1]);
- }
- else {
- $msg = $result->getMessage();
- }
-
- $this->error = array('label' => 'smtperror', 'vars' => array('msg' => $msg));
- $this->response[] = "Failed to send data";
- $this->reset();
- return false;
- }
-
- $this->response[] = join(': ', $this->conn->getResponse());
- return true;
- }
-
- /**
- * Reset the global SMTP connection
- */
- public function reset()
- {
- if (is_object($this->conn)) {
- $this->conn->rset();
- }
- }
-
- /**
- * Disconnect the global SMTP connection
- */
- public function disconnect()
- {
- if (is_object($this->conn)) {
- $this->conn->disconnect();
- $this->conn = null;
- }
- }
-
-
- /**
- * This is our own debug handler for the SMTP connection
- */
- public function debug_handler(&$smtp, $message)
- {
- // catch AUTH commands and set anonymization flag for subsequent sends
- if (preg_match('/^Send: AUTH ([A-Z]+)/', $message, $m)) {
- $this->anonymize_log = $m[1] == 'LOGIN' ? 2 : 1;
- }
- // anonymize this log entry
- else if ($this->anonymize_log > 0 && strpos($message, 'Send:') === 0 && --$this->anonymize_log == 0) {
- $message = sprintf('Send: ****** [%d]', strlen($message) - 8);
- }
-
- if (($len = strlen($message)) > self::DEBUG_LINE_LENGTH) {
- $diff = $len - self::DEBUG_LINE_LENGTH;
- $message = substr($message, 0, self::DEBUG_LINE_LENGTH)
- . "... [truncated $diff bytes]";
- }
-
- rcube::write_log('smtp', preg_replace('/\r\n$/', '', $message));
- }
-
- /**
- * Get error message
- */
- public function get_error()
- {
- return $this->error;
- }
-
- /**
- * Get server response messages array
- */
- public function get_response()
- {
- return $this->response;
- }
-
- /**
- * Take an array of mail headers and return a string containing
- * text usable in sending a message.
- *
- * @param array $headers The array of headers to prepare, in an associative
- * array, where the array key is the header name (ie,
- * 'Subject'), and the array value is the header
- * value (ie, 'test'). The header produced from those
- * values would be 'Subject: test'.
- *
- * @return mixed Returns false if it encounters a bad address,
- * otherwise returns an array containing two
- * elements: Any From: address found in the headers,
- * and the plain text version of the headers.
- */
- private function _prepare_headers($headers)
- {
- $lines = array();
- $from = null;
-
- foreach ($headers as $key => $value) {
- if (strcasecmp($key, 'From') === 0) {
- $addresses = $this->_parse_rfc822($value);
-
- if (is_array($addresses)) {
- $from = $addresses[0];
- }
-
- // Reject envelope From: addresses with spaces.
- if (strpos($from, ' ') !== false) {
- return false;
- }
-
- $lines[] = $key . ': ' . $value;
- }
- else if (strcasecmp($key, 'Received') === 0) {
- $received = array();
- if (is_array($value)) {
- foreach ($value as $line) {
- $received[] = $key . ': ' . $line;
- }
- }
- else {
- $received[] = $key . ': ' . $value;
- }
-
- // Put Received: headers at the top. Spam detectors often
- // flag messages with Received: headers after the Subject:
- // as spam.
- $lines = array_merge($received, $lines);
- }
- else {
- // If $value is an array (i.e., a list of addresses), convert
- // it to a comma-delimited string of its elements (addresses).
- if (is_array($value)) {
- $value = implode(', ', $value);
- }
-
- $lines[] = $key . ': ' . $value;
- }
- }
-
- return array($from, join(self::SMTP_MIME_CRLF, $lines) . self::SMTP_MIME_CRLF);
- }
-
- /**
- * Take a set of recipients and parse them, returning an array of
- * bare addresses (forward paths) that can be passed to sendmail
- * or an smtp server with the rcpt to: command.
- *
- * @param mixed Either a comma-seperated list of recipients
- * (RFC822 compliant), or an array of recipients,
- * each RFC822 valid.
- *
- * @return array An array of forward paths (bare addresses).
- */
- private function _parse_rfc822($recipients)
- {
- // if we're passed an array, assume addresses are valid and implode them before parsing.
- if (is_array($recipients)) {
- $recipients = implode(', ', $recipients);
- }
-
- $addresses = array();
- $recipients = rcube_utils::explode_quoted_string(',', $recipients);
-
- reset($recipients);
- foreach ($recipients as $recipient) {
- $a = rcube_utils::explode_quoted_string(' ', $recipient);
- foreach ($a as $word) {
- if (strpos($word, "@") > 0 && $word[strlen($word)-1] != '"') {
- $word = preg_replace('/^<|>$/', '', trim($word));
- if (in_array($word, $addresses) === false) {
- array_push($addresses, $word);
- }
- }
- }
- }
-
- return $addresses;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_spellcheck_atd.php b/lib/ext/Roundcube/rcube_spellcheck_atd.php
deleted file mode 100644
index 9f073f5..0000000
--- a/lib/ext/Roundcube/rcube_spellcheck_atd.php
+++ /dev/null
@@ -1,204 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | |
- | Copyright (C) 2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Spellchecking backend implementation for afterthedeadline services |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Spellchecking backend implementation to work with an After the Deadline service
- * See http://www.afterthedeadline.com/ for more information
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_spellcheck_atd extends rcube_spellcheck_engine
-{
- const SERVICE_HOST = 'service.afterthedeadline.com';
- const SERVICE_PORT = 80;
-
- private $matches = array();
- private $content;
- private $langhosts = array(
- 'fr' => 'fr.',
- 'de' => 'de.',
- 'pt' => 'pt.',
- 'es' => 'es.',
- );
-
- /**
- * Return a list of languages supported by this backend
- *
- * @see rcube_spellcheck_engine::languages()
- */
- function languages()
- {
- $langs = array_values($this->langhosts);
- $langs[] = 'en';
- return $langs;
- }
-
- /**
- * Set content and check spelling
- *
- * @see rcube_spellcheck_engine::check()
- */
- function check($text)
- {
- $this->content = $text;
-
- // spell check uri is configured
- $rcube = rcube::get_instance();
- $url = $rcube->config->get('spellcheck_uri');
- $key = $rcube->config->get('spellcheck_atd_key');
-
- if ($url) {
- $a_uri = parse_url($url);
- $ssl = ($a_uri['scheme'] == 'https' || $a_uri['scheme'] == 'ssl');
- $port = $a_uri['port'] ? $a_uri['port'] : ($ssl ? 443 : 80);
- $host = ($ssl ? 'ssl://' : '') . $a_uri['host'];
- $path = $a_uri['path'] . ($a_uri['query'] ? '?'.$a_uri['query'] : '') . $this->lang;
- }
- else {
- $host = self::SERVICE_HOST;
- $port = self::SERVICE_PORT;
- $path = '/checkDocument';
-
- // prefix host for other languages than 'en'
- $lang = substr($this->lang, 0, 2);
- if ($this->langhosts[$lang])
- $host = $this->langhosts[$lang] . $host;
- }
-
- $postdata = 'data=' . urlencode($text);
-
- if (!empty($key))
- $postdata .= '&key=' . urlencode($key);
-
- $response = $headers = '';
- $in_header = true;
- if ($fp = fsockopen($host, $port, $errno, $errstr, 30)) {
- $out = "POST $path HTTP/1.0\r\n";
- $out .= "Host: " . str_replace('ssl://', '', $host) . "\r\n";
- $out .= "Content-Length: " . strlen($postdata) . "\r\n";
- $out .= "Content-Type: application/x-www-form-urlencoded\r\n";
- $out .= "Connection: Close\r\n\r\n";
- $out .= $postdata;
- fwrite($fp, $out);
-
- while (!feof($fp)) {
- if ($in_header) {
- $line = fgets($fp, 512);
- $headers .= $line;
- if (trim($line) == '')
- $in_header = false;
- }
- else {
- $response .= fgets($fp, 1024);
- }
- }
- fclose($fp);
- }
-
- // parse HTTP response headers
- if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $headers, $m)) {
- $http_status = $m[1];
- if ($http_status != '200')
- $this->error = 'HTTP ' . $m[1] . $m[2];
- }
-
- if (!$response) {
- $this->error = "Empty result from spelling engine";
- }
-
- try {
- $result = new SimpleXMLElement($response);
- }
- catch (Exception $e) {
- $thid->error = "Unexpected response from server: " . $store;
- return array();
- }
-
- foreach ($result->error as $error) {
- if (strval($error->type) == 'spelling') {
- $word = strval($error->string);
-
- // skip exceptions
- if ($this->dictionary->is_exception($word)) {
- continue;
- }
-
- $prefix = strval($error->precontext);
- $start = $prefix ? mb_strpos($text, $prefix) : 0;
- $pos = mb_strpos($text, $word, $start);
- $len = mb_strlen($word);
- $num = 0;
-
- $match = array($word, $pos, $len, null, array());
- foreach ($error->suggestions->option as $option) {
- $match[4][] = strval($option);
- if (++$num == self::MAX_SUGGESTIONS)
- break;
- }
- $matches[] = $match;
- }
- }
-
- $this->matches = $matches;
- return $matches;
- }
-
- /**
- * Returns suggestions for the specified word
- *
- * @see rcube_spellcheck_engine::get_words()
- */
- function get_suggestions($word)
- {
- $matches = $word ? $this->check($word) : $this->matches;
-
- if ($matches[0][4]) {
- return $matches[0][4];
- }
-
- return array();
- }
-
- /**
- * Returns misspelled words
- *
- * @see rcube_spellcheck_engine::get_suggestions()
- */
- function get_words($text = null)
- {
- if ($text) {
- $matches = $this->check($text);
- }
- else {
- $matches = $this->matches;
- $text = $this->content;
- }
-
- $result = array();
-
- foreach ($matches as $m) {
- $result[] = mb_substr($text, $m[1], $m[2], RCUBE_CHARSET);
- }
-
- return $result;
- }
-
-}
-
diff --git a/lib/ext/Roundcube/rcube_spellcheck_enchant.php b/lib/ext/Roundcube/rcube_spellcheck_enchant.php
deleted file mode 100644
index 14d6fff..0000000
--- a/lib/ext/Roundcube/rcube_spellcheck_enchant.php
+++ /dev/null
@@ -1,182 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | |
- | Copyright (C) 2011-2013, Kolab Systems AG |
- | Copyright (C) 20011-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Spellchecking backend implementation to work with Enchant |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <machniak@kolabsys.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Spellchecking backend implementation to work with Pspell
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_spellcheck_enchant extends rcube_spellcheck_engine
-{
- private $enchant_broker;
- private $enchant_dictionary;
- private $matches = array();
-
- /**
- * Return a list of languages supported by this backend
- *
- * @see rcube_spellcheck_engine::languages()
- */
- function languages()
- {
- $this->init();
-
- $langs = array();
- $dicts = enchant_broker_list_dicts($this->enchant_broker);
- foreach ($dicts as $dict) {
- $langs[] = preg_replace('/-.*$/', '', $dict['lang_tag']);
- }
-
- return array_unique($langs);
- }
-
- /**
- * Initializes Enchant dictionary
- */
- private function init()
- {
- if (!$this->enchant_broker) {
- if (!extension_loaded('enchant')) {
- $this->error = "Enchant extension not available";
- return;
- }
-
- $this->enchant_broker = enchant_broker_init();
- }
-
- if (!enchant_broker_dict_exists($this->enchant_broker, $this->lang)) {
- $this->error = "Unable to load dictionary for selected language using Enchant";
- return;
- }
-
- $this->enchant_dictionary = enchant_broker_request_dict($this->enchant_broker, $this->lang);
- }
-
- /**
- * Set content and check spelling
- *
- * @see rcube_spellcheck_engine::check()
- */
- function check($text)
- {
- $this->init();
-
- if (!$this->enchant_dictionary) {
- return array();
- }
-
- // tokenize
- $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE);
-
- $diff = 0;
- $matches = array();
-
- foreach ($text as $w) {
- $word = trim($w[0]);
- $pos = $w[1] - $diff;
- $len = mb_strlen($word);
-
- // skip exceptions
- if ($this->dictionary->is_exception($word)) {
- }
- else if (!enchant_dict_check($this->enchant_dictionary, $word)) {
- $suggestions = enchant_dict_suggest($this->enchant_dictionary, $word);
-
- if (sizeof($suggestions) > self::MAX_SUGGESTIONS) {
- $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS);
- }
-
- $matches[] = array($word, $pos, $len, null, $suggestions);
- }
-
- $diff += (strlen($word) - $len);
- }
-
- $this->matches = $matches;
- return $matches;
- }
-
- /**
- * Returns suggestions for the specified word
- *
- * @see rcube_spellcheck_engine::get_words()
- */
- function get_suggestions($word)
- {
- $this->init();
-
- if (!$this->enchant_dictionary) {
- return array();
- }
-
- $suggestions = enchant_dict_suggest($this->enchant_dictionary, $word);
-
- if (sizeof($suggestions) > self::MAX_SUGGESTIONS)
- $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS);
-
- return is_array($suggestions) ? $suggestions : array();
- }
-
- /**
- * Returns misspelled words
- *
- * @see rcube_spellcheck_engine::get_suggestions()
- */
- function get_words($text = null)
- {
- $result = array();
-
- if ($text) {
- // init spellchecker
- $this->init();
-
- if (!$this->enchant_dictionary) {
- return array();
- }
-
- // With Enchant we don't need to get suggestions to return misspelled words
- $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE);
-
- foreach ($text as $w) {
- $word = trim($w[0]);
-
- // skip exceptions
- if ($this->dictionary->is_exception($word)) {
- continue;
- }
-
- if (!enchant_dict_check($this->enchant_dictionary, $word)) {
- $result[] = $word;
- }
- }
-
- return $result;
- }
-
- foreach ($this->matches as $m) {
- $result[] = $m[0];
- }
-
- return $result;
- }
-
-}
-
diff --git a/lib/ext/Roundcube/rcube_spellcheck_engine.php b/lib/ext/Roundcube/rcube_spellcheck_engine.php
deleted file mode 100644
index 3cb4ca3..0000000
--- a/lib/ext/Roundcube/rcube_spellcheck_engine.php
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | |
- | Copyright (C) 2011-2013, Kolab Systems AG |
- | Copyright (C) 2008-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Interface class for a spell-checking backend |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Interface class for a spell-checking backend
- *
- * @package Framework
- * @subpackage Utils
- */
-abstract class rcube_spellcheck_engine
-{
- const MAX_SUGGESTIONS = 10;
-
- protected $lang;
- protected $error;
- protected $dictionary;
- protected $separator = '/[\s\r\n\t\(\)\/\[\]{}<>\\"]+|[:;?!,\.](?=\W|$)/';
-
- /**
- * Default constructor
- */
- public function __construct($dict, $lang)
- {
- $this->dictionary = $dict;
- $this->lang = $lang;
- }
-
- /**
- * Return a list of languages supported by this backend
- *
- * @return array Indexed list of language codes
- */
- abstract function languages();
-
- /**
- * Set content and check spelling
- *
- * @param string $text Text content for spellchecking
- *
- * @return bool True when no mispelling found, otherwise false
- */
- abstract function check($text);
-
- /**
- * Returns suggestions for the specified word
- *
- * @param string $word The word
- *
- * @return array Suggestions list
- */
- abstract function get_suggestions($word);
-
- /**
- * Returns misspelled words
- *
- * @param string $text The content for spellchecking. If empty content
- * used for check() method will be used.
- *
- * @return array List of misspelled words
- */
- abstract function get_words($text = null);
-
- /**
- * Returns error message
- *
- * @return string Error message
- */
- public function error()
- {
- return $this->error;
- }
-
-}
-
diff --git a/lib/ext/Roundcube/rcube_spellcheck_googie.php b/lib/ext/Roundcube/rcube_spellcheck_googie.php
deleted file mode 100644
index f9e450f..0000000
--- a/lib/ext/Roundcube/rcube_spellcheck_googie.php
+++ /dev/null
@@ -1,180 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | |
- | Copyright (C) 2008-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Spellchecking backend implementation to work with Googiespell |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <machniak@kolabsys.com> |
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Spellchecking backend implementation to work with a Googiespell service
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_spellcheck_googie extends rcube_spellcheck_engine
-{
- const GOOGIE_HOST = 'ssl://spell.roundcube.net';
- const GOOGIE_PORT = 443;
-
- private $matches = array();
- private $content;
-
- /**
- * Return a list of languages supported by this backend
- *
- * @see rcube_spellcheck_engine::languages()
- */
- function languages()
- {
- return array('am','ar','ar','bg','br','ca','cs','cy','da',
- 'de_CH','de_DE','el','en_GB','en_US',
- 'eo','es','et','eu','fa','fi','fr_FR','ga','gl','gl',
- 'he','hr','hu','hy','is','it','ku','lt','lv','nl',
- 'pl','pt_BR','pt_PT','ro','ru',
- 'sk','sl','sv','uk');
- }
-
- /**
- * Set content and check spelling
- *
- * @see rcube_spellcheck_engine::check()
- */
- function check($text)
- {
- $this->content = $text;
-
- if (empty($text)) {
- return $this->matches = array();
- }
-
- // spell check uri is configured
- $url = rcube::get_instance()->config->get('spellcheck_uri');
-
- if ($url) {
- $a_uri = parse_url($url);
- $ssl = ($a_uri['scheme'] == 'https' || $a_uri['scheme'] == 'ssl');
- $port = $a_uri['port'] ? $a_uri['port'] : ($ssl ? 443 : 80);
- $host = ($ssl ? 'ssl://' : '') . $a_uri['host'];
- $path = $a_uri['path'] . ($a_uri['query'] ? '?'.$a_uri['query'] : '') . $this->lang;
- }
- else {
- $host = self::GOOGIE_HOST;
- $port = self::GOOGIE_PORT;
- $path = '/tbproxy/spell?lang=' . $this->lang;
- }
-
- $path .= sprintf('&key=%06d', $_SESSION['user_id']);
-
- $gtext = '<?xml version="1.0" encoding="utf-8" ?>'
- .'<spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1">'
- .'<text>' . htmlspecialchars($text, ENT_QUOTES, RCUBE_CHARSET) . '</text>'
- .'</spellrequest>';
-
- $store = '';
- if ($fp = fsockopen($host, $port, $errno, $errstr, 30)) {
- $out = "POST $path HTTP/1.0\r\n";
- $out .= "Host: " . str_replace('ssl://', '', $host) . "\r\n";
- $out .= "User-Agent: Roundcube Webmail/" . RCMAIL_VERSION . " (Googiespell Wrapper)\r\n";
- $out .= "Content-Length: " . strlen($gtext) . "\r\n";
- $out .= "Content-Type: text/xml\r\n";
- $out .= "Connection: Close\r\n\r\n";
- $out .= $gtext;
- fwrite($fp, $out);
-
- while (!feof($fp))
- $store .= fgets($fp, 128);
- fclose($fp);
- }
-
- // parse HTTP response
- if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $store, $m)) {
- $http_status = $m[1];
- if ($http_status != '200') {
- $this->error = 'HTTP ' . $m[1] . $m[2];
- $this->error .= "\n" . $store;
- }
- }
-
- if (!$store) {
- $this->error = "Empty result from spelling engine";
- }
- else if (preg_match('/<spellresult error="([^"]+)"/', $store, $m) && $m[1]) {
- $this->error = "Error code $m[1] returned";
- $this->error .= preg_match('/<errortext>([^<]+)/', $store, $m) ? ": " . html_entity_decode($m[1]) : '';
- }
-
- preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $store, $matches, PREG_SET_ORDER);
-
- // skip exceptions (if appropriate options are enabled)
- foreach ($matches as $idx => $m) {
- $word = mb_substr($text, $m[1], $m[2], RCUBE_CHARSET);
- // skip exceptions
- if ($this->dictionary->is_exception($word)) {
- unset($matches[$idx]);
- }
- }
-
- $this->matches = $matches;
- return $matches;
- }
-
- /**
- * Returns suggestions for the specified word
- *
- * @see rcube_spellcheck_engine::get_words()
- */
- function get_suggestions($word)
- {
- $matches = $word ? $this->check($word) : $this->matches;
-
- if ($matches[0][4]) {
- $suggestions = explode("\t", $matches[0][4]);
- if (sizeof($suggestions) > self::MAX_SUGGESTIONS) {
- $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS);
- }
-
- return $suggestions;
- }
-
- return array();
- }
-
- /**
- * Returns misspelled words
- *
- * @see rcube_spellcheck_engine::get_suggestions()
- */
- function get_words($text = null)
- {
- if ($text) {
- $matches = $this->check($text);
- }
- else {
- $matches = $this->matches;
- $text = $this->content;
- }
-
- $result = array();
-
- foreach ($matches as $m) {
- $result[] = mb_substr($text, $m[1], $m[2], RCUBE_CHARSET);
- }
-
- return $result;
- }
-
-}
-
diff --git a/lib/ext/Roundcube/rcube_spellcheck_pspell.php b/lib/ext/Roundcube/rcube_spellcheck_pspell.php
deleted file mode 100644
index b12684e..0000000
--- a/lib/ext/Roundcube/rcube_spellcheck_pspell.php
+++ /dev/null
@@ -1,189 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | |
- | Copyright (C) 2008-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Spellchecking backend implementation to work with Pspell |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <machniak@kolabsys.com> |
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Spellchecking backend implementation to work with Pspell
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_spellcheck_pspell extends rcube_spellcheck_engine
-{
- private $plink;
- private $matches = array();
-
- /**
- * Return a list of languages supported by this backend
- *
- * @see rcube_spellcheck_engine::languages()
- */
- function languages()
- {
- $defaults = array('en');
- $langs = array();
-
- // get aspell dictionaries
- exec('aspell dump dicts', $dicts);
- if (!empty($dicts)) {
- $seen = array();
- foreach ($dicts as $lang) {
- $lang = preg_replace('/-.*$/', '', $lang);
- $langc = strlen($lang) == 2 ? $lang.'_'.strtoupper($lang) : $lang;
- if (!$seen[$langc]++)
- $langs[] = $lang;
- }
- $langs = array_unique($langs);
- }
- else {
- $langs = $defaults;
- }
-
- return $langs;
- }
-
- /**
- * Initializes PSpell dictionary
- */
- private function init()
- {
- if (!$this->plink) {
- if (!extension_loaded('pspell')) {
- $this->error = "Pspell extension not available";
- return;
- }
-
- $this->plink = pspell_new($this->lang, null, null, RCUBE_CHARSET, PSPELL_FAST);
- }
-
- if (!$this->plink) {
- $this->error = "Unable to load Pspell engine for selected language";
- }
- }
-
- /**
- * Set content and check spelling
- *
- * @see rcube_spellcheck_engine::check()
- */
- function check($text)
- {
- $this->init();
-
- if (!$this->plink) {
- return array();
- }
-
- // tokenize
- $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE);
-
- $diff = 0;
- $matches = array();
-
- foreach ($text as $w) {
- $word = trim($w[0]);
- $pos = $w[1] - $diff;
- $len = mb_strlen($word);
-
- // skip exceptions
- if ($this->dictionary->is_exception($word)) {
- }
- else if (!pspell_check($this->plink, $word)) {
- $suggestions = pspell_suggest($this->plink, $word);
-
- if (sizeof($suggestions) > self::MAX_SUGGESTIONS) {
- $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS);
- }
-
- $matches[] = array($word, $pos, $len, null, $suggestions);
- }
-
- $diff += (strlen($word) - $len);
- }
-
- $this->matches = $matches;
- return $matches;
- }
-
- /**
- * Returns suggestions for the specified word
- *
- * @see rcube_spellcheck_engine::get_words()
- */
- function get_suggestions($word)
- {
- $this->init();
-
- if (!$this->plink) {
- return array();
- }
-
- $suggestions = pspell_suggest($this->plink, $word);
-
- if (sizeof($suggestions) > self::MAX_SUGGESTIONS)
- $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS);
-
- return is_array($suggestions) ? $suggestions : array();
- }
-
- /**
- * Returns misspelled words
- *
- * @see rcube_spellcheck_engine::get_suggestions()
- */
- function get_words($text = null)
- {
- $result = array();
-
- if ($text) {
- // init spellchecker
- $this->init();
-
- if (!$this->plink) {
- return array();
- }
-
- // With PSpell we don't need to get suggestions to return misspelled words
- $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE);
-
- foreach ($text as $w) {
- $word = trim($w[0]);
-
- // skip exceptions
- if ($this->dictionary->is_exception($word)) {
- continue;
- }
-
- if (!pspell_check($this->plink, $word)) {
- $result[] = $word;
- }
- }
-
- return $result;
- }
-
- foreach ($this->matches as $m) {
- $result[] = $m[0];
- }
-
- return $result;
- }
-
-}
-
diff --git a/lib/ext/Roundcube/rcube_spellchecker.php b/lib/ext/Roundcube/rcube_spellchecker.php
deleted file mode 100644
index 0627807..0000000
--- a/lib/ext/Roundcube/rcube_spellchecker.php
+++ /dev/null
@@ -1,430 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2011-2013, Kolab Systems AG |
- | Copyright (C) 2008-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Spellchecking using different backends |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <machniak@kolabsys.com> |
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Helper class for spellchecking with Googielspell and PSpell support.
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_spellchecker
-{
- private $matches = array();
- private $engine;
- private $backend;
- private $lang;
- private $rc;
- private $error;
- private $options = array();
- private $dict;
- private $have_dict;
-
-
- /**
- * Constructor
- *
- * @param string $lang Language code
- */
- function __construct($lang = 'en')
- {
- $this->rc = rcube::get_instance();
- $this->engine = $this->rc->config->get('spellcheck_engine', 'googie');
- $this->lang = $lang ? $lang : 'en';
-
- $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'),
- );
-
- $cls = 'rcube_spellcheck_' . $this->engine;
- if (class_exists($cls)) {
- $this->backend = new $cls($this, $this->lang);
- $this->backend->options = $this->options;
- }
- else {
- $this->error = "Unknown spellcheck engine '$this->engine'";
- }
- }
-
- /**
- * Return a list of supported languages
- */
- function languages()
- {
- // trust configuration
- $configured = $this->rc->config->get('spellcheck_languages');
- if (!empty($configured) && is_array($configured) && !$configured[0]) {
- return $configured;
- }
- else if (!empty($configured)) {
- $langs = (array)$configured;
- }
- else if ($this->backend) {
- $langs = $this->backend->languages();
- }
-
- // load index
- @include(RCUBE_LOCALIZATION_DIR . 'index.inc');
-
- // add correct labels
- $languages = array();
- foreach ($langs as $lang) {
- $langc = strtolower(substr($lang, 0, 2));
- $alias = $rcube_language_aliases[$langc];
- if (!$alias) {
- $alias = $langc.'_'.strtoupper($langc);
- }
- if ($rcube_languages[$lang]) {
- $languages[$lang] = $rcube_languages[$lang];
- }
- else if ($rcube_languages[$alias]) {
- $languages[$lang] = $rcube_languages[$alias];
- }
- else {
- $languages[$lang] = ucfirst($lang);
- }
- }
-
- // remove possible duplicates (#1489395)
- $languages = array_unique($languages);
-
- asort($languages);
-
- return $languages;
- }
-
- /**
- * Set content and check spelling
- *
- * @param string $text Text content for spellchecking
- * @param bool $is_html Enables HTML-to-Text conversion
- *
- * @return bool True when no mispelling found, otherwise false
- */
- function check($text, $is_html = false)
- {
- // convert to plain text
- if ($is_html) {
- $this->content = $this->html2text($text);
- }
- else {
- $this->content = $text;
- }
-
- if ($this->backend) {
- $this->matches = $this->backend->check($this->content);
- }
-
- return $this->found() == 0;
- }
-
-
- /**
- * Number of mispellings found (after check)
- *
- * @return int Number of mispellings
- */
- function found()
- {
- return count($this->matches);
- }
-
-
- /**
- * Returns suggestions for the specified word
- *
- * @param string $word The word
- *
- * @return array Suggestions list
- */
- function get_suggestions($word)
- {
- if ($this->backend) {
- return $this->backend->get_suggestions($word);
- }
-
- return array();
- }
-
-
- /**
- * Returns misspelled words
- *
- * @param string $text The content for spellchecking. If empty content
- * used for check() method will be used.
- *
- * @return array List of misspelled words
- */
- function get_words($text = null, $is_html=false)
- {
- if ($is_html) {
- $text = $this->html2text($text);
- }
-
- if ($this->backend) {
- return $this->backend->get_words($text);
- }
-
- return array();
- }
-
-
- /**
- * Returns checking result in XML (Googiespell) format
- *
- * @return string XML content
- */
- function get_xml()
- {
- // send output
- $out = '<?xml version="1.0" encoding="'.RCUBE_CHARSET.'"?><spellresult charschecked="'.mb_strlen($this->content).'">';
-
- foreach ((array)$this->matches as $item) {
- $out .= '<c o="'.$item[1].'" l="'.$item[2].'">';
- $out .= is_array($item[4]) ? implode("\t", $item[4]) : $item[4];
- $out .= '</c>';
- }
-
- $out .= '</spellresult>';
-
- return $out;
- }
-
-
- /**
- * Returns checking result (misspelled words with suggestions)
- *
- * @return array Spellchecking result. An array indexed by word.
- */
- function get()
- {
- $result = array();
-
- foreach ((array)$this->matches as $item) {
- if ($this->engine == 'pspell') {
- $word = $item[0];
- }
- else {
- $word = mb_substr($this->content, $item[1], $item[2], RCUBE_CHARSET);
- }
-
- if (is_array($item[4])) {
- $suggestions = $item[4];
- }
- else if (empty($item[4])) {
- $suggestions = array();
- }
- else {
- $suggestions = explode("\t", $item[4]);
- }
-
- $result[$word] = $suggestions;
- }
-
- return $result;
- }
-
-
- /**
- * Returns error message
- *
- * @return string Error message
- */
- function error()
- {
- return $this->error ? $this->error : ($this->backend ? $this->backend->error() : false);
- }
-
-
- private function html2text($text)
- {
- $h2t = new rcube_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 = $this->rc->get_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 " . $this->rc->db->table_name('dictionary', true)
- ." SET `data` = ?"
- ." WHERE `user_id` " . ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL")
- ." AND `language` = ?",
- implode(' ', $plugin['dictionary']), $plugin['language']);
- }
- // don't store empty dict
- else {
- $this->rc->db->query(
- "DELETE FROM " . $this->rc->db->table_name('dictionary', true)
- ." WHERE `user_id` " . ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL")
- ." AND `language` = ?",
- $plugin['language']);
- }
- }
- else if (!empty($this->dict)) {
- $this->rc->db->query(
- "INSERT INTO " . $this->rc->db->table_name('dictionary', true)
- ." (`user_id`, `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 = $this->rc->get_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();
- $sql_result = $this->rc->db->query(
- "SELECT `data` FROM " . $this->rc->db->table_name('dictionary', true)
- ." WHERE `user_id` ". ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL")
- ." AND `language` = ?",
- $plugin['language']);
-
- if ($sql_arr = $this->rc->db->fetch_assoc($sql_result)) {
- $this->have_dict = true;
- if (!empty($sql_arr['data'])) {
- $dict = explode(' ', $sql_arr['data']);
- }
- }
-
- $plugin['dictionary'] = array_merge((array)$plugin['dictionary'], $dict);
- }
-
- if (!empty($plugin['dictionary']) && is_array($plugin['dictionary'])) {
- $this->dict = $plugin['dictionary'];
- }
- else {
- $this->dict = array();
- }
-
- return $this->dict;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_storage.php b/lib/ext/Roundcube/rcube_storage.php
deleted file mode 100644
index ccb28c6..0000000
--- a/lib/ext/Roundcube/rcube_storage.php
+++ /dev/null
@@ -1,1052 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | Copyright (C) 2012, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Mail Storage Engine |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Abstract class for accessing mail messages storage server
- *
- * @package Framework
- * @subpackage Storage
- * @author Thomas Bruederli <roundcube@gmail.com>
- * @author Aleksander Machniak <alec@alec.pl>
- */
-abstract class rcube_storage
-{
- /**
- * Instance of connection object e.g. rcube_imap_generic
- *
- * @var mixed
- */
- public $conn;
-
- /**
- * List of supported special folder types
- *
- * @var array
- */
- public static $folder_types = array('drafts', 'sent', 'junk', 'trash');
-
- protected $folder = 'INBOX';
- protected $default_charset = 'ISO-8859-1';
- protected $search_set;
- protected $options = array('auth_type' => 'check');
- protected $page_size = 10;
- protected $threading = false;
-
- /**
- * All (additional) headers used (in any way) by Roundcube
- * Not listed here: DATE, FROM, TO, CC, REPLY-TO, SUBJECT, CONTENT-TYPE, LIST-POST
- * (used for messages listing) are hardcoded in rcube_imap_generic::fetchHeaders()
- *
- * @var array
- */
- protected $all_headers = array(
- 'IN-REPLY-TO',
- 'BCC',
- 'SENDER',
- 'MESSAGE-ID',
- 'CONTENT-TRANSFER-ENCODING',
- 'REFERENCES',
- 'X-DRAFT-INFO',
- 'MAIL-FOLLOWUP-TO',
- 'MAIL-REPLY-TO',
- 'RETURN-PATH',
- );
-
- const UNKNOWN = 0;
- const NOPERM = 1;
- const READONLY = 2;
- const TRYCREATE = 3;
- const INUSE = 4;
- const OVERQUOTA = 5;
- const ALREADYEXISTS = 6;
- const NONEXISTENT = 7;
- const CONTACTADMIN = 8;
-
-
- /**
- * Connect to the server
- *
- * @param string $host Host to connect
- * @param string $user Username for IMAP account
- * @param string $pass Password for IMAP account
- * @param integer $port Port to connect to
- * @param string $use_ssl SSL schema (either ssl or tls) or null if plain connection
- *
- * @return boolean TRUE on success, FALSE on failure
- */
- abstract function connect($host, $user, $pass, $port = 143, $use_ssl = null);
-
-
- /**
- * Close connection. Usually done on script shutdown
- */
- abstract function close();
-
-
- /**
- * Checks connection state.
- *
- * @return boolean TRUE on success, FALSE on failure
- */
- abstract function is_connected();
-
-
- /**
- * Check connection state, connect if not connected.
- *
- * @return bool Connection state.
- */
- abstract function check_connection();
-
-
- /**
- * Returns code of last error
- *
- * @return int Error code
- */
- abstract function get_error_code();
-
-
- /**
- * Returns message of last error
- *
- * @return string Error message
- */
- abstract function get_error_str();
-
-
- /**
- * Returns code of last command response
- *
- * @return int Response code (class constant)
- */
- abstract function get_response_code();
-
-
- /**
- * Set connection and class options
- *
- * @param array $opt Options array
- */
- public function set_options($opt)
- {
- $this->options = array_merge($this->options, (array)$opt);
- }
-
-
- /**
- * Get connection/class option
- *
- * @param string $name Option name
- *
- * @param mixed Option value
- */
- public function get_option($name)
- {
- return $this->options[$name];
- }
-
-
- /**
- * Activate/deactivate debug mode.
- *
- * @param boolean $dbg True if conversation with the server should be logged
- */
- abstract function set_debug($dbg = true);
-
-
- /**
- * Set default message charset.
- *
- * This will be used for message decoding if a charset specification is not available
- *
- * @param string $cs Charset string
- */
- public function set_charset($cs)
- {
- $this->default_charset = $cs;
- }
-
-
- /**
- * Set internal folder reference.
- * All operations will be perfomed on this folder.
- *
- * @param string $folder Folder name
- */
- public function set_folder($folder)
- {
- if ($this->folder === $folder) {
- return;
- }
-
- $this->folder = $folder;
- }
-
-
- /**
- * Returns the currently used folder name
- *
- * @return string Name of the folder
- */
- public function get_folder()
- {
- return $this->folder;
- }
-
-
- /**
- * Set internal list page number.
- *
- * @param int $page Page number to list
- */
- public function set_page($page)
- {
- $this->list_page = (int) $page;
- }
-
-
- /**
- * Gets internal list page number.
- *
- * @return int Page number
- */
- public function get_page()
- {
- return $this->list_page;
- }
-
-
- /**
- * Set internal page size
- *
- * @param int $size Number of messages to display on one page
- */
- public function set_pagesize($size)
- {
- $this->page_size = (int) $size;
- }
-
-
- /**
- * Get internal page size
- *
- * @return int Number of messages to display on one page
- */
- public function get_pagesize()
- {
- return $this->page_size;
- }
-
-
- /**
- * Save a search result for future message listing methods.
- *
- * @param mixed $set Search set in driver specific format
- */
- abstract function set_search_set($set);
-
-
- /**
- * Return the saved search set.
- *
- * @return array Search set in driver specific format, NULL if search wasn't initialized
- */
- abstract function get_search_set();
-
-
- /**
- * Returns the storage server's (IMAP) capability
- *
- * @param string $cap Capability name
- *
- * @return mixed Capability value or TRUE if supported, FALSE if not
- */
- abstract function get_capability($cap);
-
-
- /**
- * Sets threading flag to the best supported THREAD algorithm.
- * Enable/Disable threaded mode.
- *
- * @param boolean $enable TRUE to enable and FALSE
- *
- * @return mixed Threading algorithm or False if THREAD is not supported
- */
- public function set_threading($enable = false)
- {
- $this->threading = false;
-
- if ($enable && ($caps = $this->get_capability('THREAD'))) {
- $methods = array('REFS', 'REFERENCES', 'ORDEREDSUBJECT');
- $methods = array_intersect($methods, $caps);
-
- $this->threading = array_shift($methods);
- }
-
- return $this->threading;
- }
-
-
- /**
- * Get current threading flag.
- *
- * @return mixed Threading algorithm or False if THREAD is not supported or disabled
- */
- public function get_threading()
- {
- return $this->threading;
- }
-
-
- /**
- * Checks the PERMANENTFLAGS capability of the current folder
- * and returns true if the given flag is supported by the server.
- *
- * @param string $flag Permanentflag name
- *
- * @return boolean True if this flag is supported
- */
- abstract function check_permflag($flag);
-
-
- /**
- * Returns the delimiter that is used by the server
- * for folder hierarchy separation.
- *
- * @return string Delimiter string
- */
- abstract function get_hierarchy_delimiter();
-
-
- /**
- * Get namespace
- *
- * @param string $name Namespace array index: personal, other, shared, prefix
- *
- * @return array Namespace data
- */
- abstract function get_namespace($name = null);
-
-
- /**
- * Get messages count for a specific folder.
- *
- * @param string $folder Folder name
- * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT|EXISTS]
- * @param boolean $force Force reading from server and update cache
- * @param boolean $status Enables storing folder status info (max UID/count),
- * required for folder_status()
- *
- * @return int Number of messages
- */
- abstract function count($folder = null, $mode = 'ALL', $force = false, $status = true);
-
-
- /**
- * Public method for listing message flags
- *
- * @param string $folder Folder name
- * @param array $uids Message UIDs
- * @param int $mod_seq Optional MODSEQ value
- *
- * @return array Indexed array with message flags
- */
- abstract function list_flags($folder, $uids, $mod_seq = null);
-
-
- /**
- * Public method for listing headers.
- *
- * @param string $folder Folder name
- * @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 int $slice Number of slice items to extract from result array
- *
- * @return array Indexed array with message header objects
- */
- abstract function list_messages($folder = null, $page = null, $sort_field = null, $sort_order = null, $slice = 0);
-
-
- /**
- * Return sorted list of message UIDs
- *
- * @param string $folder Folder to get index from
- * @param string $sort_field Sort column
- * @param string $sort_order Sort order [ASC, DESC]
- *
- * @return rcube_result_index|rcube_result_thread List of messages (UIDs)
- */
- abstract function index($folder = null, $sort_field = null, $sort_order = null);
-
-
- /**
- * Invoke search request to the server.
- *
- * @param string $folder Folder name to search in
- * @param string $str Search criteria
- * @param string $charset Search charset
- * @param string $sort_field Header field to sort by
- *
- * @todo: Search criteria should be provided in non-IMAP format, eg. array
- */
- abstract function search($folder = null, $str = 'ALL', $charset = null, $sort_field = null);
-
-
- /**
- * Direct (real and simple) search request (without result sorting and caching).
- *
- * @param string $folder Folder name to search in
- * @param string $str Search string
- *
- * @return rcube_result_index Search result (UIDs)
- */
- abstract function search_once($folder = null, $str = 'ALL');
-
-
- /**
- * Refresh saved search set
- *
- * @return array Current search set
- */
- abstract function refresh_search();
-
-
- /* --------------------------------
- * messages management
- * --------------------------------*/
-
- /**
- * Fetch message headers and body structure from the server and build
- * an object structure similar to the one generated by PEAR::Mail_mimeDecode
- *
- * @param int $uid Message UID to fetch
- * @param string $folder Folder to read from
- *
- * @return object rcube_message_header Message data
- */
- abstract function get_message($uid, $folder = null);
-
-
- /**
- * Return message headers object of a specific message
- *
- * @param int $id Message sequence ID or UID
- * @param string $folder Folder to read from
- * @param bool $force True to skip cache
- *
- * @return rcube_message_header Message headers
- */
- abstract function get_message_headers($uid, $folder = null, $force = false);
-
-
- /**
- * Fetch message body of a specific message from the server
- *
- * @param int $uid Message UID
- * @param string $part Part number
- * @param rcube_message_part $o_part Part object created by get_structure()
- * @param mixed $print True to print part, ressource to write part contents in
- * @param resource $fp File pointer to save the message part
- * @param boolean $skip_charset_conv Disables charset conversion
- *
- * @return string Message/part body if not printed
- */
- abstract function get_message_part($uid, $part = 1, $o_part = null, $print = null, $fp = null, $skip_charset_conv = false);
-
-
- /**
- * Fetch message body of a specific message from the server
- *
- * @param int $uid Message UID
- *
- * @return string $part Message/part body
- * @see rcube_imap::get_message_part()
- */
- public function get_body($uid, $part = 1)
- {
- $headers = $this->get_message_headers($uid);
- return rcube_charset::convert($this->get_message_part($uid, $part, null),
- $headers->charset ? $headers->charset : $this->default_charset);
- }
-
-
- /**
- * Returns the whole message source as string (or saves to a file)
- *
- * @param int $uid Message UID
- * @param resource $fp File pointer to save the message
- *
- * @return string Message source string
- */
- abstract function get_raw_body($uid, $fp = null);
-
-
- /**
- * Returns the message headers as string
- *
- * @param int $uid Message UID
- *
- * @return string Message headers string
- */
- abstract function get_raw_headers($uid);
-
-
- /**
- * Sends the whole message source to stdout
- *
- * @param int $uid Message UID
- * @param bool $formatted Enables line-ending formatting
- */
- abstract function print_raw_body($uid, $formatted = true);
-
-
- /**
- * Set message flag to one or several messages
- *
- * @param mixed $uids Message UIDs as array or comma-separated string, or '*'
- * @param string $flag Flag to set: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT, MDNSENT
- * @param string $folder Folder name
- * @param boolean $skip_cache True to skip message cache clean up
- *
- * @return bool Operation status
- */
- abstract function set_flag($uids, $flag, $folder = null, $skip_cache = false);
-
-
- /**
- * Remove message flag for one or several messages
- *
- * @param mixed $uids Message UIDs as array or comma-separated string, or '*'
- * @param string $flag Flag to unset: SEEN, DELETED, RECENT, ANSWERED, DRAFT, MDNSENT
- * @param string $folder Folder name
- *
- * @return bool Operation status
- * @see set_flag
- */
- public function unset_flag($uids, $flag, $folder = null)
- {
- return $this->set_flag($uids, 'UN'.$flag, $folder);
- }
-
-
- /**
- * Append a mail message (source) to a specific folder.
- *
- * @param string $folder Target folder
- * @param string|array $message The message source string or filename
- * or array (of strings and file pointers)
- * @param string $headers Headers string if $message contains only the body
- * @param boolean $is_file True if $message is a filename
- * @param array $flags Message flags
- * @param mixed $date Message internal date
- *
- * @return int|bool Appended message UID or True on success, False on error
- */
- abstract function save_message($folder, &$message, $headers = '', $is_file = false, $flags = array(), $date = null);
-
-
- /**
- * Move message(s) from one folder to another.
- *
- * @param mixed $uids Message UIDs as array or comma-separated string, or '*'
- * @param string $to Target folder
- * @param string $from Source folder
- *
- * @return boolean True on success, False on error
- */
- abstract function move_message($uids, $to, $from = null);
-
-
- /**
- * Copy message(s) from one mailbox to another.
- *
- * @param mixed $uids Message UIDs as array or comma-separated string, or '*'
- * @param string $to Target folder
- * @param string $from Source folder
- *
- * @return boolean True on success, False on error
- */
- abstract function copy_message($uids, $to, $from = null);
-
-
- /**
- * Mark message(s) as deleted and expunge.
- *
- * @param mixed $uids Message UIDs as array or comma-separated string, or '*'
- * @param string $folder Source folder
- *
- * @return boolean True on success, False on error
- */
- abstract function delete_message($uids, $folder = null);
-
-
- /**
- * Expunge message(s) and clear the cache.
- *
- * @param mixed $uids Message UIDs as array or comma-separated string, or '*'
- * @param string $folder Folder name
- * @param boolean $clear_cache False if cache should not be cleared
- *
- * @return boolean True on success, False on error
- */
- abstract function expunge_message($uids, $folder = null, $clear_cache = true);
-
-
- /**
- * Parse message UIDs input
- *
- * @param mixed $uids UIDs array or comma-separated list or '*' or '1:*'
- *
- * @return array Two elements array with UIDs converted to list and ALL flag
- */
- protected function parse_uids($uids)
- {
- if ($uids === '*' || $uids === '1:*') {
- if (empty($this->search_set)) {
- $uids = '1:*';
- $all = true;
- }
- // get UIDs from current search set
- else {
- $uids = join(',', $this->search_set->get());
- }
- }
- else {
- if (is_array($uids)) {
- $uids = join(',', $uids);
- }
- else if (strpos($uids, ':')) {
- $uids = join(',', rcube_imap_generic::uncompressMessageSet($uids));
- }
-
- if (preg_match('/[^0-9,]/', $uids)) {
- $uids = '';
- }
- }
-
- return array($uids, (bool) $all);
- }
-
-
- /* --------------------------------
- * folder managment
- * --------------------------------*/
-
- /**
- * Get a list of subscribed folders.
- *
- * @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 folders
- */
- abstract function list_folders_subscribed($root = '', $name = '*', $filter = null, $rights = null, $skip_sort = false);
-
-
- /**
- * Get a list of all folders available on the server.
- *
- * @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
- */
- abstract function list_folders($root = '', $name = '*', $filter = null, $rights = null, $skip_sort = false);
-
-
- /**
- * Subscribe to a specific folder(s)
- *
- * @param array $folders Folder name(s)
- *
- * @return boolean True on success
- */
- abstract function subscribe($folders);
-
-
- /**
- * Unsubscribe folder(s)
- *
- * @param array $folders Folder name(s)
- *
- * @return boolean True on success
- */
- abstract function unsubscribe($folders);
-
-
- /**
- * Create a new folder on the server.
- *
- * @param string $folder New folder name
- * @param boolean $subscribe True if the newvfolder should be subscribed
- *
- * @return boolean True on success, False on error
- */
- abstract function create_folder($folder, $subscribe = false);
-
-
- /**
- * Set a new name to an existing folder
- *
- * @param string $folder Folder to rename
- * @param string $new_name New folder name
- *
- * @return boolean True on success, False on error
- */
- abstract function rename_folder($folder, $new_name);
-
-
- /**
- * Remove a folder from the server.
- *
- * @param string $folder Folder name
- *
- * @return boolean True on success, False on error
- */
- abstract function delete_folder($folder);
-
-
- /**
- * Send expunge command and clear the cache.
- *
- * @param string $folder Folder name
- * @param boolean $clear_cache False if cache should not be cleared
- *
- * @return boolean True on success, False on error
- */
- public function expunge_folder($folder = null, $clear_cache = true)
- {
- return $this->expunge_message('*', $folder, $clear_cache);
- }
-
-
- /**
- * Remove all messages in a folder..
- *
- * @param string $folder Folder name
- *
- * @return boolean True on success, False on error
- */
- public function clear_folder($folder = null)
- {
- return $this->delete_message('*', $folder);
- }
-
-
- /**
- * Checks if folder exists and is subscribed
- *
- * @param string $folder Folder name
- * @param boolean $subscription Enable subscription checking
- *
- * @return boolean True if folder exists, False otherwise
- */
- abstract function folder_exists($folder, $subscription = false);
-
-
- /**
- * Get folder size (size of all messages in a folder)
- *
- * @param string $folder Folder name
- *
- * @return int Folder size in bytes, False on error
- */
- abstract function folder_size($folder);
-
-
- /**
- * Returns the namespace where the folder is in
- *
- * @param string $folder Folder name
- *
- * @return string One of 'personal', 'other' or 'shared'
- */
- abstract function folder_namespace($folder);
-
-
- /**
- * Gets folder attributes (from LIST response, e.g. \Noselect, \Noinferiors).
- *
- * @param string $folder Folder name
- * @param bool $force Set to True if attributes should be refreshed
- *
- * @return array Options list
- */
- abstract function folder_attributes($folder, $force = false);
-
-
- /**
- * Gets connection (and current folder) data: UIDVALIDITY, EXISTS, RECENT,
- * PERMANENTFLAGS, UIDNEXT, UNSEEN
- *
- * @param string $folder Folder name
- *
- * @return array Data
- */
- abstract function folder_data($folder);
-
-
- /**
- * Returns extended information about the folder.
- *
- * @param string $folder Folder name
- *
- * @return array Data
- */
- abstract function folder_info($folder);
-
-
- /**
- * Returns current status of a folder (compared to the last time use)
- *
- * @param string $folder Folder name
- * @param array $diff Difference data
- *
- * @return int Folder status
- */
- abstract function folder_status($folder = null, &$diff = array());
-
-
- /**
- * Synchronizes messages cache.
- *
- * @param string $folder Folder name
- */
- abstract function folder_sync($folder);
-
-
- /**
- * Modify folder name according to namespace.
- * For output it removes prefix of the personal namespace if it's possible.
- * For input it adds the prefix. Use it before creating a folder in root
- * of the folders tree.
- *
- * @param string $folder Folder name
- * @param string $mode Mode name (out/in)
- *
- * @return string Folder name
- */
- abstract function mod_folder($folder, $mode = 'out');
-
-
- /**
- * Create all folders specified as default
- */
- public function create_default_folders()
- {
- $rcube = rcube::get_instance();
-
- // create default folders if they do not exist
- foreach (self::$folder_types as $type) {
- if ($folder = $rcube->config->get($type . '_mbox')) {
- if (!$this->folder_exists($folder)) {
- $this->create_folder($folder, true, $type);
- }
- else if (!$this->folder_exists($folder, true)) {
- $this->subscribe($folder);
- }
- }
- }
- }
-
-
- /**
- * Check if specified folder is a special folder
- */
- public function is_special_folder($name)
- {
- return $name == 'INBOX' || in_array($name, $this->get_special_folders());
- }
-
-
- /**
- * Return configured special folders
- */
- public function get_special_folders($forced = false)
- {
- // getting config might be expensive, store special folders in memory
- if (!isset($this->icache['special-folders'])) {
- $rcube = rcube::get_instance();
- $this->icache['special-folders'] = array();
-
- foreach (self::$folder_types as $type) {
- if ($folder = $rcube->config->get($type . '_mbox')) {
- $this->icache['special-folders'][$type] = $folder;
- }
- }
- }
-
- return $this->icache['special-folders'];
- }
-
-
- /**
- * Set special folder associations stored in backend
- */
- public function set_special_folders($specials)
- {
- // should be overriden by storage class if backend supports special folders (SPECIAL-USE)
- unset($this->icache['special-folders']);
- }
-
-
- /**
- * Get mailbox quota information.
- *
- * @param string $folder Folder name
- *
- * @return mixed Quota info or False if not supported
- */
- abstract function get_quota($folder = null);
-
-
- /* -----------------------------------------
- * ACL and METADATA methods
- * ----------------------------------------*/
-
- /**
- * Changes the ACL on the specified folder (SETACL)
- *
- * @param string $folder Folder name
- * @param string $user User name
- * @param string $acl ACL string
- *
- * @return boolean True on success, False on failure
- */
- abstract function set_acl($folder, $user, $acl);
-
-
- /**
- * Removes any <identifier,rights> pair for the
- * specified user from the ACL for the specified
- * folder (DELETEACL).
- *
- * @param string $folder Folder name
- * @param string $user User name
- *
- * @return boolean True on success, False on failure
- */
- abstract function delete_acl($folder, $user);
-
-
- /**
- * Returns the access control list for a folder (GETACL).
- *
- * @param string $folder Folder name
- *
- * @return array User-rights array on success, NULL on error
- */
- abstract function get_acl($folder);
-
-
- /**
- * Returns information about what rights can be granted to the
- * user (identifier) in the ACL for the folder (LISTRIGHTS).
- *
- * @param string $folder Folder name
- * @param string $user User name
- *
- * @return array List of user rights
- */
- abstract function list_rights($folder, $user);
-
-
- /**
- * Returns the set of rights that the current user has to a folder (MYRIGHTS).
- *
- * @param string $folder Folder name
- *
- * @return array MYRIGHTS response on success, NULL on error
- */
- abstract function my_rights($folder);
-
-
- /**
- * Sets metadata/annotations (SETMETADATA/SETANNOTATION)
- *
- * @param string $folder Folder name (empty for server metadata)
- * @param array $entries Entry-value array (use NULL value as NIL)
- *
- * @return boolean True on success, False on failure
- */
- abstract function set_metadata($folder, $entries);
-
-
- /**
- * Unsets metadata/annotations (SETMETADATA/SETANNOTATION)
- *
- * @param string $folder Folder name (empty for server metadata)
- * @param array $entries Entry names array
- *
- * @return boolean True on success, False on failure
- */
- abstract function delete_metadata($folder, $entries);
-
-
- /**
- * Returns folder metadata/annotations (GETMETADATA/GETANNOTATION).
- *
- * @param string $folder Folder name (empty for server metadata)
- * @param array $entries Entries
- * @param array $options Command options (with MAXSIZE and DEPTH keys)
- *
- * @return array Metadata entry-value hash array on success, NULL on error
- */
- abstract function get_metadata($folder, $entries, $options = array());
-
-
- /* -----------------------------------------
- * Cache related functions
- * ----------------------------------------*/
-
- /**
- * Clears the cache.
- *
- * @param string $key Cache key name or pattern
- * @param boolean $prefix_mode Enable it to clear all keys starting
- * with prefix specified in $key
- */
- abstract function clear_cache($key = null, $prefix_mode = false);
-
-
- /**
- * Returns cached value
- *
- * @param string $key Cache key
- *
- * @return mixed Cached value
- */
- abstract function get_cache($key);
-
-
- /**
- * Delete outdated cache entries
- */
- abstract function cache_gc();
-
-} // end class rcube_storage
diff --git a/lib/ext/Roundcube/rcube_string_replacer.php b/lib/ext/Roundcube/rcube_string_replacer.php
deleted file mode 100644
index ce61e53..0000000
--- a/lib/ext/Roundcube/rcube_string_replacer.php
+++ /dev/null
@@ -1,252 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2009-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Handle string replacements based on preg_replace_callback |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Helper class for string replacements based on preg_replace_callback
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_string_replacer
-{
- public static $pattern = '/##str_replacement_(\d+)##/';
- public $mailto_pattern;
- public $link_pattern;
- public $linkref_index;
- public $linkref_pattern;
-
- private $values = array();
- private $options = array();
- private $linkrefs = array();
- private $urls = array();
-
-
- function __construct($options = array())
- {
- // Simplified domain expression for UTF8 characters handling
- // 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-zA-Z0-9]{2,})';
- $url1 = '.:;,';
- $url2 = 'a-zA-Z0-9%=#$@+?|!&\\/_~\\[\\]\\(\\){}\*\x80-\xFE-';
-
- $this->link_pattern = "/([\w]+:\/\/|\W[Ww][Ww][Ww]\.|^[Ww][Ww][Ww]\.)($utf_domain([$url1]*[$url2]+)*)/";
- $this->mailto_pattern = "/("
- ."[-\w!\#\$%&\'*+~\/^`|{}=]+(?:\.[-\w!\#\$%&\'*+~\/^`|{}=]+)*" // local-part
- ."@$utf_domain" // domain-part
- ."(\?[$url1$url2]+)?" // e.g. ?subject=test...
- .")/";
- $this->linkref_index = '/\[([^\]#]+)\](:?\s*##str_replacement_(\d+)##)/';
- $this->linkref_pattern = '/\[([^\]#]+)\]/';
-
- $this->options = $options;
- }
-
- /**
- * Add a string to the internal list
- *
- * @param string String value
- * @return int Index of value for retrieval
- */
- public function add($str)
- {
- $i = count($this->values);
- $this->values[$i] = $str;
- return $i;
- }
-
- /**
- * Build replacement string
- */
- public function get_replacement($i)
- {
- return '##str_replacement_' . $i . '##';
- }
-
- /**
- * Callback function used to build HTML links around URL strings
- *
- * @param array Matches result from preg_replace_callback
- * @return int Index of saved string value
- */
- public function link_callback($matches)
- {
- $i = -1;
- $scheme = strtolower($matches[1]);
-
- if (preg_match('!^(http|ftp|file)s?://!i', $scheme)) {
- $url = $matches[1] . $matches[2];
- }
- else if (preg_match('/^(\W*)(www\.)$/i', $matches[1], $m)) {
- $url = $m[2] . $matches[2];
- $url_prefix = 'http://';
- $prefix = $m[1];
- }
-
- if ($url) {
- $suffix = $this->parse_url_brackets($url);
- $attrib = (array)$this->options['link_attribs'];
- $attrib['href'] = $url_prefix . $url;
-
- $i = $this->add(html::a($attrib, rcube::Q($url)) . $suffix);
- $this->urls[$i] = $attrib['href'];
- }
-
- // Return valid link for recognized schemes, otherwise
- // return the unmodified string for unrecognized schemes.
- return $i >= 0 ? $prefix . $this->get_replacement($i) : $matches[0];
- }
-
- /**
- * Callback to add an entry to the link index
- */
- public function linkref_addindex($matches)
- {
- $key = $matches[1];
- $this->linkrefs[$key] = $this->urls[$matches[3]];
-
- return $this->get_replacement($this->add('['.$key.']')) . $matches[2];
- }
-
- /**
- * Callback to replace link references with real links
- */
- public function linkref_callback($matches)
- {
- $i = 0;
- if ($url = $this->linkrefs[$matches[1]]) {
- $attrib = (array)$this->options['link_attribs'];
- $attrib['href'] = $url;
- $i = $this->add(html::a($attrib, rcube::Q($matches[1])));
- }
-
- return $i > 0 ? '['.$this->get_replacement($i).']' : $matches[0];
- }
-
- /**
- * Callback function used to build mailto: links around e-mail strings
- *
- * @param array Matches result from preg_replace_callback
- * @return int Index of saved string value
- */
- public function mailto_callback($matches)
- {
- $href = $matches[1];
- $suffix = $this->parse_url_brackets($href);
- $i = $this->add(html::a('mailto:' . $href, rcube::Q($href)) . $suffix);
-
- return $i >= 0 ? $this->get_replacement($i) : '';
- }
-
- /**
- * Look up the index from the preg_replace matches array
- * and return the substitution value.
- *
- * @param array Matches result from preg_replace_callback
- * @return string Value at index $matches[1]
- */
- public function replace_callback($matches)
- {
- return $this->values[$matches[1]];
- }
-
- /**
- * Replace all defined (link|mailto) patterns with replacement string
- *
- * @param string $str Text
- *
- * @return string Text
- */
- public function replace($str)
- {
- // search for patterns like links and e-mail addresses
- $str = preg_replace_callback($this->link_pattern, array($this, 'link_callback'), $str);
- $str = preg_replace_callback($this->mailto_pattern, array($this, 'mailto_callback'), $str);
- // resolve link references
- $str = preg_replace_callback($this->linkref_index, array($this, 'linkref_addindex'), $str);
- $str = preg_replace_callback($this->linkref_pattern, array($this, 'linkref_callback'), $str);
-
- return $str;
- }
-
- /**
- * Replace substituted strings with original values
- */
- public function resolve($str)
- {
- return preg_replace_callback(self::$pattern, array($this, 'replace_callback'), $str);
- }
-
- /**
- * Fixes bracket characters in URL handling
- */
- public static function parse_url_brackets(&$url)
- {
- // #1487672: special handling of square brackets,
- // URL regexp allows [] characters in URL, for example:
- // "http://example.com/?a[b]=c". However we need to handle
- // properly situation when a bracket is placed at the end
- // of the link e.g. "[http://example.com]"
- // Yes, this is not perfect handles correctly only paired characters
- // but it should work for common cases
-
- if (preg_match('/(\\[|\\])/', $url)) {
- $in = false;
- for ($i=0, $len=strlen($url); $i<$len; $i++) {
- if ($url[$i] == '[') {
- if ($in)
- break;
- $in = true;
- }
- else if ($url[$i] == ']') {
- if (!$in)
- break;
- $in = false;
- }
- }
-
- if ($i < $len) {
- $suffix = substr($url, $i);
- $url = substr($url, 0, $i);
- }
- }
-
- // Do the same for parentheses
- if (preg_match('/(\\(|\\))/', $url)) {
- $in = false;
- for ($i=0, $len=strlen($url); $i<$len; $i++) {
- if ($url[$i] == '(') {
- if ($in)
- break;
- $in = true;
- }
- else if ($url[$i] == ')') {
- if (!$in)
- break;
- $in = false;
- }
- }
-
- if ($i < $len) {
- $suffix = substr($url, $i);
- $url = substr($url, 0, $i);
- }
- }
-
- return $suffix;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_text2html.php b/lib/ext/Roundcube/rcube_text2html.php
deleted file mode 100644
index 0afc6d1..0000000
--- a/lib/ext/Roundcube/rcube_text2html.php
+++ /dev/null
@@ -1,309 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2014, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Converts plain text to HTML |
- +-----------------------------------------------------------------------+
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
- */
-
-/**
- * Converts plain text to HTML
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_text2html
-{
- /**
- * Contains the HTML content after conversion.
- *
- * @var string $html
- */
- protected $html;
-
- /**
- * Contains the plain text.
- *
- * @var string $text
- */
- protected $text;
-
- /**
- * Configuration
- *
- * @var array $config
- */
- protected $config = array(
- // non-breaking space
- 'space' => "\xC2\xA0",
- // enables format=flowed parser
- 'flowed' => false,
- // enables wrapping for non-flowed text
- 'wrap' => true,
- // line-break tag
- 'break' => "<br>\n",
- // prefix and suffix (wrapper element)
- 'begin' => '<div class="pre">',
- 'end' => '</div>',
- // enables links replacement
- 'links' => true,
- // string replacer class
- 'replacer' => 'rcube_string_replacer',
- );
-
-
- /**
- * Constructor.
- *
- * If the plain text source string (or file) is supplied, the class
- * will instantiate with that source propagated, all that has
- * to be done it to call get_html().
- *
- * @param string $source Plain text
- * @param boolean $from_file Indicates $source is a file to pull content from
- * @param array $config Class configuration
- */
- function __construct($source = '', $from_file = false, $config = array())
- {
- if (!empty($source)) {
- $this->set_text($source, $from_file);
- }
-
- if (!empty($config) && is_array($config)) {
- $this->config = array_merge($this->config, $config);
- }
- }
-
- /**
- * Loads source text into memory, either from $source string or a file.
- *
- * @param string $source Plain text
- * @param boolean $from_file Indicates $source is a file to pull content from
- */
- function set_text($source, $from_file = false)
- {
- if ($from_file && file_exists($source)) {
- $this->text = file_get_contents($source);
- }
- else {
- $this->text = $source;
- }
-
- $this->_converted = false;
- }
-
- /**
- * Returns the HTML content.
- *
- * @return string HTML content
- */
- function get_html()
- {
- if (!$this->_converted) {
- $this->_convert();
- }
-
- return $this->html;
- }
-
- /**
- * Prints the HTML.
- */
- function print_html()
- {
- print $this->get_html();
- }
-
- /**
- * Workhorse function that does actual conversion (calls _converter() method).
- */
- protected function _convert()
- {
- // Convert TXT to HTML
- $this->html = $this->_converter($this->text);
- $this->_converted = true;
- }
-
- /**
- * Workhorse function that does actual conversion.
- *
- * @param string Plain text
- */
- protected function _converter($text)
- {
- // make links and email-addresses clickable
- $attribs = array('link_attribs' => array('rel' => 'noreferrer', 'target' => '_blank'));
- $replacer = new $this->config['replacer']($attribs);
-
- if ($this->config['flowed']) {
- $flowed_char = 0x01;
- $text = rcube_mime::unfold_flowed($text, chr($flowed_char));
- }
-
- // search for patterns like links and e-mail addresses and replace with tokens
- if ($this->config['links']) {
- $text = $replacer->replace($text);
- }
-
- // split body into single lines
- $text = preg_split('/\r?\n/', $text);
- $quote_level = 0;
- $last = null;
-
- // wrap quoted lines with <blockquote>
- for ($n = 0, $cnt = count($text); $n < $cnt; $n++) {
- $flowed = false;
- if ($this->config['flowed'] && ord($text[$n][0]) == $flowed_char) {
- $flowed = true;
- $text[$n] = substr($text[$n], 1);
- }
-
- if ($text[$n][0] == '>' && preg_match('/^(>+ {0,1})+/', $text[$n], $regs)) {
- $q = substr_count($regs[0], '>');
- $text[$n] = substr($text[$n], strlen($regs[0]));
- $text[$n] = $this->_convert_line($text[$n], $flowed || $this->config['wrap']);
- $_length = strlen(str_replace(' ', '', $text[$n]));
-
- if ($q > $quote_level) {
- if ($last !== null) {
- $text[$last] .= (!$length ? "\n" : '')
- . $replacer->get_replacement($replacer->add(
- str_repeat('<blockquote>', $q - $quote_level)))
- . $text[$n];
-
- unset($text[$n]);
- }
- else {
- $text[$n] = $replacer->get_replacement($replacer->add(
- str_repeat('<blockquote>', $q - $quote_level))) . $text[$n];
-
- $last = $n;
- }
- }
- else if ($q < $quote_level) {
- $text[$last] .= (!$length ? "\n" : '')
- . $replacer->get_replacement($replacer->add(
- str_repeat('</blockquote>', $quote_level - $q)))
- . $text[$n];
-
- unset($text[$n]);
- }
- else {
- $last = $n;
- }
- }
- else {
- $text[$n] = $this->_convert_line($text[$n], $flowed || $this->config['wrap']);
- $q = 0;
- $_length = strlen(str_replace(' ', '', $text[$n]));
-
- if ($quote_level > 0) {
- $text[$last] .= (!$length ? "\n" : '')
- . $replacer->get_replacement($replacer->add(
- str_repeat('</blockquote>', $quote_level)))
- . $text[$n];
-
- unset($text[$n]);
- }
- else {
- $last = $n;
- }
- }
-
- $quote_level = $q;
- $length = $_length;
- }
-
- if ($quote_level > 0) {
- $text[$last] .= $replacer->get_replacement($replacer->add(
- str_repeat('</blockquote>', $quote_level)));
- }
-
- $text = join("\n", $text);
-
- // colorize signature (up to <sig_max_lines> lines)
- $len = strlen($text);
- $sig_sep = "--" . $this->config['space'] . "\n";
- $sig_max_lines = rcube::get_instance()->config->get('sig_max_lines', 15);
-
- while (($sp = strrpos($text, $sig_sep, $sp ? -$len+$sp-1 : 0)) !== false) {
- if ($sp == 0 || $text[$sp-1] == "\n") {
- // do not touch blocks with more that X lines
- if (substr_count($text, "\n", $sp) < $sig_max_lines) {
- $text = substr($text, 0, max(0, $sp))
- .'<span class="sig">'.substr($text, $sp).'</span>';
- }
-
- break;
- }
- }
-
- // insert url/mailto links and citation tags
- $text = $replacer->resolve($text);
-
- // replace line breaks
- $text = str_replace("\n", $this->config['break'], $text);
-
- return $this->config['begin'] . $text . $this->config['end'];
- }
-
- /**
- * Converts spaces in line of text
- */
- protected function _convert_line($text, $is_flowed)
- {
- static $table;
-
- if (empty($table)) {
- $table = get_html_translation_table(HTML_SPECIALCHARS);
- unset($table['?']);
- }
-
- // skip signature separator
- if ($text == '-- ') {
- return '--' . $this->config['space'];
- }
-
- // replace HTML special characters
- $text = strtr($text, $table);
-
- $nbsp = $this->config['space'];
-
- // replace some whitespace characters
- $text = str_replace(array("\r", "\t"), array('', ' '), $text);
-
- // replace spaces with non-breaking spaces
- if ($is_flowed) {
- $pos = 0;
- $diff = 0;
- $len = strlen($nbsp);
- $copy = $text;
-
- while (($pos = strpos($text, ' ', $pos)) !== false) {
- if ($pos == 0 || $text[$pos-1] == ' ') {
- $copy = substr_replace($copy, $nbsp, $pos + $diff, 1);
- $diff += $len - 1;
- }
- $pos++;
- }
-
- $text = $copy;
- }
- else {
- // make the whole line non-breakable
- $text = str_replace(array(' ', '-', '/'), array($nbsp, '-&#8288;', '/&#8288;'), $text);
- }
-
- return $text;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_tnef_decoder.php b/lib/ext/Roundcube/rcube_tnef_decoder.php
deleted file mode 100644
index f047ba0..0000000
--- a/lib/ext/Roundcube/rcube_tnef_decoder.php
+++ /dev/null
@@ -1,341 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2014, The Roundcube Dev Team |
- | Copyright (C) 2002-2010, The Horde Project (http://www.horde.org/) |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | MS-TNEF format decoder |
- +-----------------------------------------------------------------------+
- | Author: Jan Schneider <jan@horde.org> |
- | Author: Michael Slusarz <slusarz@horde.org> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * MS-TNEF format decoder based on code by:
- * Graham Norbury <gnorbury@bondcar.com>
- * Original design by:
- * Thomas Boll <tb@boll.ch>, Mark Simpson <damned@world.std.com>
- *
- * @package Framework
- * @subpackage Storage
- */
-class rcube_tnef_decoder
-{
- const SIGNATURE = 0x223e9f78;
- const LVL_MESSAGE = 0x01;
- const LVL_ATTACHMENT = 0x02;
-
- const ASUBJECT = 0x88004;
- const AMCLASS = 0x78008;
- const ATTACHDATA = 0x6800f;
- const AFILENAME = 0x18010;
- const ARENDDATA = 0x69002;
- const AMAPIATTRS = 0x69005;
- const AVERSION = 0x89006;
-
- const MAPI_NULL = 0x0001;
- const MAPI_SHORT = 0x0002;
- const MAPI_INT = 0x0003;
- const MAPI_FLOAT = 0x0004;
- const MAPI_DOUBLE = 0x0005;
- const MAPI_CURRENCY = 0x0006;
- const MAPI_APPTIME = 0x0007;
- const MAPI_ERROR = 0x000a;
- const MAPI_BOOLEAN = 0x000b;
- const MAPI_OBJECT = 0x000d;
- const MAPI_INT8BYTE = 0x0014;
- const MAPI_STRING = 0x001e;
- const MAPI_UNICODE_STRING = 0x001f;
- const MAPI_SYSTIME = 0x0040;
- const MAPI_CLSID = 0x0048;
- const MAPI_BINARY = 0x0102;
-
- const MAPI_ATTACH_LONG_FILENAME = 0x3707;
- const MAPI_ATTACH_MIME_TAG = 0x370E;
-
- const MAPI_NAMED_TYPE_ID = 0x0000;
- const MAPI_NAMED_TYPE_STRING = 0x0001;
- const MAPI_MV_FLAG = 0x1000;
-
- /**
- * Decompress the data.
- *
- * @param string $data The data to decompress.
- * @param array $params An array of arguments needed to decompress the
- * data.
- *
- * @return mixed The decompressed data.
- */
- public function decompress($data, $params = array())
- {
- $out = array();
-
- if ($this->_geti($data, 32) == self::SIGNATURE) {
- $this->_geti($data, 16);
-
- while (strlen($data) > 0) {
- switch ($this->_geti($data, 8)) {
- case self::LVL_MESSAGE:
- $this->_decodeMessage($data);
- break;
-
- case self::LVL_ATTACHMENT:
- $this->_decodeAttachment($data, $out);
- break;
- }
- }
- }
-
- return array_reverse($out);
- }
-
- /**
- * TODO
- *
- * @param string &$data The data string.
- * @param integer $bits How many bits to retrieve.
- *
- * @return TODO
- */
- protected function _getx(&$data, $bits)
- {
- $value = null;
-
- if (strlen($data) >= $bits) {
- $value = substr($data, 0, $bits);
- $data = substr_replace($data, '', 0, $bits);
- }
-
- return $value;
- }
-
- /**
- * TODO
- *
- * @param string &$data The data string.
- * @param integer $bits How many bits to retrieve.
- *
- * @return TODO
- */
- protected function _geti(&$data, $bits)
- {
- $bytes = $bits / 8;
- $value = null;
-
- if (strlen($data) >= $bytes) {
- $value = ord($data[0]);
- if ($bytes >= 2) {
- $value += (ord($data[1]) << 8);
- }
- if ($bytes >= 4) {
- $value += (ord($data[2]) << 16) + (ord($data[3]) << 24);
- }
- $data = substr_replace($data, '', 0, $bytes);
- }
-
- return $value;
- }
-
- /**
- * TODO
- *
- * @param string &$data The data string.
- * @param string $attribute TODO
- */
- protected function _decodeAttribute(&$data, $attribute)
- {
- /* Data. */
- $this->_getx($data, $this->_geti($data, 32));
-
- /* Checksum. */
- $this->_geti($data, 16);
- }
-
- /**
- * TODO
- *
- * @param string $data The data string.
- * @param array &$attachment_data TODO
- */
- protected function _extractMapiAttributes($data, &$attachment_data)
- {
- /* Number of attributes. */
- $number = $this->_geti($data, 32);
-
- while ((strlen($data) > 0) && $number--) {
- $have_mval = false;
- $num_mval = 1;
- $named_id = $value = null;
- $attr_type = $this->_geti($data, 16);
- $attr_name = $this->_geti($data, 16);
-
- if (($attr_type & self::MAPI_MV_FLAG) != 0) {
- $have_mval = true;
- $attr_type = $attr_type & ~self::MAPI_MV_FLAG;
- }
-
- if (($attr_name >= 0x8000) && ($attr_name < 0xFFFE)) {
- $this->_getx($data, 16);
- $named_type = $this->_geti($data, 32);
-
- switch ($named_type) {
- case self::MAPI_NAMED_TYPE_ID:
- $named_id = $this->_geti($data, 32);
- $attr_name = $named_id;
- break;
-
- case self::MAPI_NAMED_TYPE_STRING:
- $attr_name = 0x9999;
- $idlen = $this->_geti($data, 32);
- $datalen = $idlen + ((4 - ($idlen % 4)) % 4);
- $named_id = substr($this->_getx($data, $datalen), 0, $idlen);
- break;
- }
- }
-
- if ($have_mval) {
- $num_mval = $this->_geti($data, 32);
- }
-
- switch ($attr_type) {
- case self::MAPI_SHORT:
- $value = $this->_geti($data, 16);
- break;
-
- case self::MAPI_INT:
- case self::MAPI_BOOLEAN:
- for ($i = 0; $i < $num_mval; $i++) {
- $value = $this->_geti($data, 32);
- }
- break;
-
- case self::MAPI_FLOAT:
- case self::MAPI_ERROR:
- $value = $this->_getx($data, 4);
- break;
-
- case self::MAPI_DOUBLE:
- case self::MAPI_APPTIME:
- case self::MAPI_CURRENCY:
- case self::MAPI_INT8BYTE:
- case self::MAPI_SYSTIME:
- $value = $this->_getx($data, 8);
- break;
-
- case self::MAPI_STRING:
- case self::MAPI_UNICODE_STRING:
- case self::MAPI_BINARY:
- case self::MAPI_OBJECT:
- $num_vals = ($have_mval) ? $num_mval : $this->_geti($data, 32);
- for ($i = 0; $i < $num_vals; $i++) {
- $length = $this->_geti($data, 32);
-
- /* Pad to next 4 byte boundary. */
- $datalen = $length + ((4 - ($length % 4)) % 4);
-
- if ($attr_type == self::MAPI_STRING) {
- --$length;
- }
-
- /* Read and truncate to length. */
- $value = substr($this->_getx($data, $datalen), 0, $length);
- }
- break;
- }
-
- /* Store any interesting attributes. */
- switch ($attr_name) {
- case self::MAPI_ATTACH_LONG_FILENAME:
- $value = str_replace("\0", '', $value);
- /* Used in preference to AFILENAME value. */
- $attachment_data[0]['name'] = preg_replace('/.*[\/](.*)$/', '\1', $value);
- break;
-
- case self::MAPI_ATTACH_MIME_TAG:
- $value = str_replace("\0", '', $value);
- /* Is this ever set, and what is format? */
- $attachment_data[0]['type'] = preg_replace('/^(.*)\/.*/', '\1', $value);
- $attachment_data[0]['subtype'] = preg_replace('/.*\/(.*)$/', '\1', $value);
- break;
- }
- }
- }
-
- /**
- * TODO
- *
- * @param string &$data The data string.
- */
- protected function _decodeMessage(&$data)
- {
- $this->_decodeAttribute($data, $this->_geti($data, 32));
- }
-
- /**
- * TODO
- *
- * @param string &$data The data string.
- * @param array &$attachment_data TODO
- */
- protected function _decodeAttachment(&$data, &$attachment_data)
- {
- $attribute = $this->_geti($data, 32);
-
- switch ($attribute) {
- case self::ARENDDATA:
- /* Marks start of new attachment. */
- $this->_getx($data, $this->_geti($data, 32));
-
- /* Checksum */
- $this->_geti($data, 16);
-
- /* Add a new default data block to hold details of this
- attachment. Reverse order is easier to handle later! */
- array_unshift($attachment_data, array('type' => 'application',
- 'subtype' => 'octet-stream',
- 'name' => 'unknown',
- 'stream' => ''));
- break;
-
- case self::AFILENAME:
- $value = $this->_getx($data, $this->_geti($data, 32));
- $value = str_replace("\0", '', $value);
- /* Strip path. */
- $attachment_data[0]['name'] = preg_replace('/.*[\/](.*)$/', '\1', $value);
-
- /* Checksum */
- $this->_geti($data, 16);
- break;
-
- case self::ATTACHDATA:
- /* The attachment itself. */
- $length = $this->_geti($data, 32);
- $attachment_data[0]['size'] = $length;
- $attachment_data[0]['stream'] = $this->_getx($data, $length);
-
- /* Checksum */
- $this->_geti($data, 16);
- break;
-
- case self::AMAPIATTRS:
- $length = $this->_geti($data, 32);
- $value = $this->_getx($data, $length);
-
- /* Checksum */
- $this->_geti($data, 16);
- $this->_extractMapiAttributes($value, $attachment_data);
- break;
-
- default:
- $this->_decodeAttribute($data, $attribute);
- }
- }
-}
diff --git a/lib/ext/Roundcube/rcube_user.php b/lib/ext/Roundcube/rcube_user.php
deleted file mode 100644
index b2110df..0000000
--- a/lib/ext/Roundcube/rcube_user.php
+++ /dev/null
@@ -1,746 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | This class represents a system user linked and provides access |
- | to the related database records. |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class representing a system user
- *
- * @package Framework
- * @subpackage Core
- */
-class rcube_user
-{
- public $ID;
- public $data;
- public $language;
-
- /**
- * Holds database connection.
- *
- * @var rcube_db
- */
- private $db;
-
- /**
- * Framework object.
- *
- * @var rcube
- */
- private $rc;
-
- /**
- * Internal identities cache
- *
- * @var array
- */
- private $identities = array();
-
- const SEARCH_ADDRESSBOOK = 1;
- const SEARCH_MAIL = 2;
-
- /**
- * Object constructor
- *
- * @param int $id User id
- * @param array $sql_arr SQL result set
- */
- function __construct($id = null, $sql_arr = null)
- {
- $this->rc = rcube::get_instance();
- $this->db = $this->rc->get_dbh();
-
- if ($id && !$sql_arr) {
- $sql_result = $this->db->query(
- "SELECT * FROM " . $this->db->table_name('users', true)
- . " WHERE `user_id` = ?", $id);
- $sql_arr = $this->db->fetch_assoc($sql_result);
- }
-
- if (!empty($sql_arr)) {
- $this->ID = $sql_arr['user_id'];
- $this->data = $sql_arr;
- $this->language = $sql_arr['language'];
- }
- }
-
-
- /**
- * Build a user name string (as e-mail address)
- *
- * @param string $part Username part (empty or 'local' or 'domain', 'mail')
- * @return string Full user name or its part
- */
- function get_username($part = null)
- {
- if ($this->data['username']) {
- // return real name
- if (!$part) {
- return $this->data['username'];
- }
-
- list($local, $domain) = explode('@', $this->data['username']);
-
- // at least we should always have the local part
- if ($part == 'local') {
- return $local;
- }
- // if no domain was provided...
- if (empty($domain)) {
- $domain = $this->rc->config->mail_domain($this->data['mail_host']);
- }
-
- if ($part == 'domain') {
- return $domain;
- }
-
- if (!empty($domain))
- return $local . '@' . $domain;
- else
- return $local;
- }
-
- return false;
- }
-
-
- /**
- * Get the preferences saved for this user
- *
- * @return array Hash array with prefs
- */
- function get_prefs()
- {
- $prefs = array();
-
- if (!empty($this->language))
- $prefs['language'] = $this->language;
-
- if ($this->ID) {
- // Preferences from session (write-master is unavailable)
- if (!empty($_SESSION['preferences'])) {
- // Check last write attempt time, try to write again (every 5 minutes)
- if ($_SESSION['preferences_time'] < time() - 5 * 60) {
- $saved_prefs = unserialize($_SESSION['preferences']);
- $this->rc->session->remove('preferences');
- $this->rc->session->remove('preferences_time');
- $this->save_prefs($saved_prefs);
- }
- else {
- $this->data['preferences'] = $_SESSION['preferences'];
- }
- }
-
- if ($this->data['preferences']) {
- $prefs += (array)unserialize($this->data['preferences']);
- }
- }
-
- return $prefs;
- }
-
-
- /**
- * Write the given user prefs to the user's record
- *
- * @param array $a_user_prefs User prefs to save
- * @return boolean True on success, False on failure
- */
- function save_prefs($a_user_prefs)
- {
- if (!$this->ID)
- return false;
-
- $plugin = $this->rc->plugins->exec_hook('preferences_update', array(
- 'userid' => $this->ID, 'prefs' => $a_user_prefs, 'old' => (array)$this->get_prefs()));
-
- if (!empty($plugin['abort'])) {
- return;
- }
-
- $a_user_prefs = $plugin['prefs'];
- $old_prefs = $plugin['old'];
- $config = $this->rc->config;
-
- // merge (partial) prefs array with existing settings
- $save_prefs = $a_user_prefs + $old_prefs;
- unset($save_prefs['language']);
-
- // don't save prefs with default values if they haven't been changed yet
- foreach ($a_user_prefs as $key => $value) {
- if ($value === null || (!isset($old_prefs[$key]) && ($value == $config->get($key))))
- unset($save_prefs[$key]);
- }
-
- $save_prefs = serialize($save_prefs);
-
- $this->db->query(
- "UPDATE ".$this->db->table_name('users', true).
- " SET `preferences` = ?, `language` = ?".
- " WHERE `user_id` = ?",
- $save_prefs,
- $_SESSION['language'],
- $this->ID);
-
- $this->language = $_SESSION['language'];
-
- // Update success
- if ($this->db->affected_rows() !== false) {
- $config->set_user_prefs($a_user_prefs);
- $this->data['preferences'] = $save_prefs;
-
- if (isset($_SESSION['preferences'])) {
- $this->rc->session->remove('preferences');
- $this->rc->session->remove('preferences_time');
- }
- return true;
- }
- // Update error, but we are using replication (we have read-only DB connection)
- // and we are storing session not in the SQL database
- // we can store preferences in session and try to write later (see get_prefs())
- else if ($this->db->is_replicated() && $config->get('session_storage', 'db') != 'db') {
- $_SESSION['preferences'] = $save_prefs;
- $_SESSION['preferences_time'] = time();
- $config->set_user_prefs($a_user_prefs);
- $this->data['preferences'] = $save_prefs;
- }
-
- return false;
- }
-
- /**
- * Generate a unique hash to identify this user which
- */
- function get_hash()
- {
- $key = substr($this->rc->config->get('des_key'), 1, 4);
- return md5($this->data['user_id'] . $key . $this->data['username'] . '@' . $this->data['mail_host']);
- }
-
- /**
- * Get default identity of this user
- *
- * @param int $id Identity ID. If empty, the default identity is returned
- * @return array Hash array with all cols of the identity record
- */
- function get_identity($id = null)
- {
- $id = (int)$id;
- // cache identities for better performance
- if (!array_key_exists($id, $this->identities)) {
- $result = $this->list_identities($id ? "AND `identity_id` = $id" : '');
- $this->identities[$id] = $result[0];
- }
-
- return $this->identities[$id];
- }
-
-
- /**
- * Return a list of all identities linked with this user
- *
- * @param string $sql_add Optional WHERE clauses
- * @param bool $formatted Format identity email and name
- *
- * @return array List of identities
- */
- function list_identities($sql_add = '', $formatted = false)
- {
- $result = array();
-
- $sql_result = $this->db->query(
- "SELECT * FROM ".$this->db->table_name('identities', true).
- " WHERE `del` <> 1 AND `user_id` = ?".
- ($sql_add ? " ".$sql_add : "").
- " ORDER BY `standard` DESC, `name` ASC, `email` ASC, `identity_id` ASC",
- $this->ID);
-
- while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
- if ($formatted) {
- $ascii_email = format_email($sql_arr['email']);
- $utf8_email = format_email(rcube_utils::idn_to_utf8($ascii_email));
-
- $sql_arr['email_ascii'] = $ascii_email;
- $sql_arr['email'] = $utf8_email;
- $sql_arr['ident'] = format_email_recipient($ascii_email, $sql_arr['name']);
- }
-
- $result[] = $sql_arr;
- }
-
- return $result;
- }
-
-
- /**
- * Update a specific identity record
- *
- * @param int $iid Identity ID
- * @param array $data Hash array with col->value pairs to save
- * @return boolean True if saved successfully, false if nothing changed
- */
- function update_identity($iid, $data)
- {
- if (!$this->ID)
- return false;
-
- $query_cols = $query_params = array();
-
- foreach ((array)$data as $col => $value) {
- $query_cols[] = $this->db->quote_identifier($col) . ' = ?';
- $query_params[] = $value;
- }
- $query_params[] = $iid;
- $query_params[] = $this->ID;
-
- $sql = "UPDATE ".$this->db->table_name('identities', true).
- " SET `changed` = ".$this->db->now().", ".join(', ', $query_cols).
- " WHERE `identity_id` = ?".
- " AND `user_id` = ?".
- " AND `del` <> 1";
-
- call_user_func_array(array($this->db, 'query'),
- array_merge(array($sql), $query_params));
-
- $this->identities = array();
-
- return $this->db->affected_rows();
- }
-
-
- /**
- * Create a new identity record linked with this user
- *
- * @param array $data Hash array with col->value pairs to save
- * @return int The inserted identity ID or false on error
- */
- function insert_identity($data)
- {
- if (!$this->ID)
- return false;
-
- unset($data['user_id']);
-
- $insert_cols = $insert_values = array();
- foreach ((array)$data as $col => $value) {
- $insert_cols[] = $this->db->quote_identifier($col);
- $insert_values[] = $value;
- }
- $insert_cols[] = $this->db->quote_identifier('user_id');
- $insert_values[] = $this->ID;
-
- $sql = "INSERT INTO ".$this->db->table_name('identities', true).
- " (`changed`, ".join(', ', $insert_cols).")".
- " VALUES (".$this->db->now().", ".join(', ', array_pad(array(), sizeof($insert_values), '?')).")";
-
- call_user_func_array(array($this->db, 'query'),
- array_merge(array($sql), $insert_values));
-
- $this->identities = array();
-
- return $this->db->insert_id('identities');
- }
-
-
- /**
- * Mark the given identity as deleted
- *
- * @param int $iid Identity ID
- * @return boolean True if deleted successfully, false if nothing changed
- */
- function delete_identity($iid)
- {
- if (!$this->ID)
- return false;
-
- $sql_result = $this->db->query(
- "SELECT count(*) AS ident_count FROM ".$this->db->table_name('identities', true).
- " WHERE `user_id` = ? AND `del` <> 1",
- $this->ID);
-
- $sql_arr = $this->db->fetch_assoc($sql_result);
-
- // we'll not delete last identity
- if ($sql_arr['ident_count'] <= 1)
- return -1;
-
- $this->db->query(
- "UPDATE ".$this->db->table_name('identities', true).
- " SET `del` = 1, `changed` = ".$this->db->now().
- " WHERE `user_id` = ?".
- " AND `identity_id` = ?",
- $this->ID,
- $iid);
-
- $this->identities = array();
-
- return $this->db->affected_rows();
- }
-
-
- /**
- * Make this identity the default one for this user
- *
- * @param int $iid The identity ID
- */
- function set_default($iid)
- {
- if ($this->ID && $iid) {
- $this->db->query(
- "UPDATE ".$this->db->table_name('identities', true).
- " SET `standard` = '0'".
- " WHERE `user_id` = ? AND `identity_id` <> ?",
- $this->ID,
- $iid);
-
- unset($this->identities[0]);
- }
- }
-
-
- /**
- * Update user's last_login timestamp
- */
- function touch()
- {
- if ($this->ID) {
- $this->db->query(
- "UPDATE ".$this->db->table_name('users', true).
- " SET `last_login` = ".$this->db->now().
- " WHERE `user_id` = ?",
- $this->ID);
- }
- }
-
-
- /**
- * Clear the saved object state
- */
- function reset()
- {
- $this->ID = null;
- $this->data = null;
- }
-
-
- /**
- * Find a user record matching the given name and host
- *
- * @param string $user IMAP user name
- * @param string $host IMAP host name
- * @return rcube_user New user instance
- */
- static function query($user, $host)
- {
- $dbh = rcube::get_instance()->get_dbh();
- $config = rcube::get_instance()->config;
-
- // query for matching user name
- $sql_result = $dbh->query("SELECT * FROM " . $dbh->table_name('users', true)
- ." WHERE `mail_host` = ? AND `username` = ?", $host, $user);
-
- $sql_arr = $dbh->fetch_assoc($sql_result);
-
- // username not found, try aliases from identities
- if (empty($sql_arr) && $config->get('user_aliases') && strpos($user, '@')) {
- $sql_result = $dbh->limitquery("SELECT u.*"
- ." FROM " . $dbh->table_name('users', true) . " u"
- ." JOIN " . $dbh->table_name('identities', true) . " i ON (i.`user_id` = u.`user_id`)"
- ." WHERE `email` = ? AND `del` <> 1", 0, 1, $user);
-
- $sql_arr = $dbh->fetch_assoc($sql_result);
- }
-
- // user already registered -> overwrite username
- if ($sql_arr)
- return new rcube_user($sql_arr['user_id'], $sql_arr);
- else
- return false;
- }
-
-
- /**
- * Create a new user record and return a rcube_user instance
- *
- * @param string $user IMAP user name
- * @param string $host IMAP host
- * @return rcube_user New user instance
- */
- static function create($user, $host)
- {
- $user_name = '';
- $user_email = '';
- $rcube = rcube::get_instance();
- $dbh = $rcube->get_dbh();
-
- // try to resolve user in virtuser table and file
- if ($email_list = self::user2email($user, false, true)) {
- $user_email = is_array($email_list[0]) ? $email_list[0]['email'] : $email_list[0];
- }
-
- $data = $rcube->plugins->exec_hook('user_create', array(
- 'host' => $host,
- 'user' => $user,
- 'user_name' => $user_name,
- 'user_email' => $user_email,
- 'email_list' => $email_list,
- 'language' => $_SESSION['language'],
- ));
-
- // plugin aborted this operation
- if ($data['abort']) {
- return false;
- }
-
- $dbh->query(
- "INSERT INTO ".$dbh->table_name('users', true).
- " (`created`, `last_login`, `username`, `mail_host`, `language`)".
- " VALUES (".$dbh->now().", ".$dbh->now().", ?, ?, ?)",
- $data['user'],
- $data['host'],
- $data['language']);
-
- if ($user_id = $dbh->insert_id('users')) {
- // create rcube_user instance to make plugin hooks work
- $user_instance = new rcube_user($user_id, array(
- 'user_id' => $user_id,
- 'username' => $data['user'],
- 'mail_host' => $data['host'],
- 'language' => $data['language'],
- ));
- $rcube->user = $user_instance;
- $mail_domain = $rcube->config->mail_domain($data['host']);
- $user_name = $data['user_name'];
- $user_email = $data['user_email'];
- $email_list = $data['email_list'];
-
- if (empty($email_list)) {
- if (empty($user_email)) {
- $user_email = strpos($data['user'], '@') ? $user : sprintf('%s@%s', $data['user'], $mail_domain);
- }
- $email_list[] = $user_email;
- }
- // identities_level check
- else if (count($email_list) > 1 && $rcube->config->get('identities_level', 0) > 1) {
- $email_list = array($email_list[0]);
- }
-
- if (empty($user_name)) {
- $user_name = $data['user'];
- }
-
- // create new identities records
- $standard = 1;
- foreach ($email_list as $row) {
- $record = array();
-
- if (is_array($row)) {
- if (empty($row['email'])) {
- continue;
- }
- $record = $row;
- }
- else {
- $record['email'] = $row;
- }
-
- if (empty($record['name'])) {
- $record['name'] = $user_name != $record['email'] ? $user_name : '';
- }
-
- $record['user_id'] = $user_id;
- $record['standard'] = $standard;
-
- $plugin = $rcube->plugins->exec_hook('identity_create',
- array('login' => true, 'record' => $record));
-
- if (!$plugin['abort'] && $plugin['record']['email']) {
- $rcube->user->insert_identity($plugin['record']);
- }
- $standard = 0;
- }
- }
- else {
- rcube::raise_error(array(
- 'code' => 500,
- 'type' => 'php',
- 'line' => __LINE__,
- 'file' => __FILE__,
- 'message' => "Failed to create new user"), true, false);
- }
-
- return $user_id ? $user_instance : false;
- }
-
-
- /**
- * Resolve username using a virtuser plugins
- *
- * @param string $email E-mail address to resolve
- * @return string Resolved IMAP username
- */
- static function email2user($email)
- {
- $rcube = rcube::get_instance();
- $plugin = $rcube->plugins->exec_hook('email2user',
- array('email' => $email, 'user' => NULL));
-
- return $plugin['user'];
- }
-
-
- /**
- * Resolve e-mail address from virtuser plugins
- *
- * @param string $user User name
- * @param boolean $first If true returns first found entry
- * @param boolean $extended If true returns email as array (email and name for identity)
- * @return mixed Resolved e-mail address string or array of strings
- */
- static function user2email($user, $first=true, $extended=false)
- {
- $rcube = rcube::get_instance();
- $plugin = $rcube->plugins->exec_hook('user2email',
- array('email' => NULL, 'user' => $user,
- 'first' => $first, 'extended' => $extended));
-
- 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, `name`"
- ." FROM ".$this->db->table_name('searches', true)
- ." WHERE `user_id` = ? AND `type` = ?"
- ." ORDER BY `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 `name`, `data`, `type`"
- . " FROM ".$this->db->table_name('searches', true)
- . " 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 ".$this->db->table_name('searches', true)
- ." 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->quote_identifier('type');
- $insert_values[] = (int) $data['type'];
- $insert_cols[] = $this->db->quote_identifier('name');
- $insert_values[] = $data['name'];
- $insert_cols[] = $this->db->quote_identifier('data');
- $insert_values[] = serialize($data['data']);
-
- $sql = "INSERT INTO ".$this->db->table_name('searches', true)
- ." (".join(', ', $insert_cols).")"
- ." VALUES (".join(', ', array_pad(array(), sizeof($insert_values), '?')).")";
-
- call_user_func_array(array($this->db, 'query'),
- array_merge(array($sql), $insert_values));
-
- return $this->db->insert_id('searches');
- }
-}
diff --git a/lib/ext/Roundcube/rcube_utils.php b/lib/ext/Roundcube/rcube_utils.php
deleted file mode 100644
index a51247e..0000000
--- a/lib/ext/Roundcube/rcube_utils.php
+++ /dev/null
@@ -1,1105 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2012, The Roundcube Dev Team |
- | Copyright (C) 2011-2012, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Utility class providing common functions |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Utility class providing common functions
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_utils
-{
- // define constants for input reading
- const INPUT_GET = 0x0101;
- const INPUT_POST = 0x0102;
- const INPUT_GPC = 0x0103;
-
- /**
- * 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();
- $secure = $cookie['secure'] || self::https_check();
-
- setcookie($name, $value, $exp, $cookie['path'], $cookie['domain'], $secure, true);
- }
-
- /**
- * E-mail address validation.
- *
- * @param string $email Email address
- * @param boolean $dns_check True to check dns
- *
- * @return boolean True on success, False if address is invalid
- */
- public static function check_email($email, $dns_check=true)
- {
- // Check for invalid characters
- if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email)) {
- return false;
- }
-
- // Check for length limit specified by RFC 5321 (#1486453)
- if (strlen($email) > 254) {
- return false;
- }
-
- $email_array = explode('@', $email);
-
- // Check that there's one @ symbol
- if (count($email_array) < 2) {
- return false;
- }
-
- $domain_part = array_pop($email_array);
- $local_part = implode('@', $email_array);
-
- // from PEAR::Validate
- $regexp = '&^(?:
- ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")| #1 quoted name
- ([-\w!\#\$%\&\'*+~/^`|{}=]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}=]+)*)) #2 OR dot-atom (RFC5322)
- $&xi';
-
- if (!preg_match($regexp, $local_part)) {
- return false;
- }
-
- // Validate domain part
- if (preg_match('/^\[((IPv6:[0-9a-f:.]+)|([0-9.]+))\]$/i', $domain_part, $matches)) {
- return self::check_ip(preg_replace('/^IPv6:/i', '', $matches[1])); // valid IPv4 or IPv6 address
- }
- else {
- // If not an IP address
- $domain_array = explode('.', $domain_part);
- // Not enough parts to be a valid domain
- if (sizeof($domain_array) < 2) {
- return false;
- }
-
- foreach ($domain_array as $part) {
- if (!preg_match('/^((xn--)?([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $part)) {
- return false;
- }
- }
-
- // last domain part
- $last_part = array_pop($domain_array);
- if (strpos($last_part, 'xn--') !== 0 && preg_match('/[^a-zA-Z]/', $last_part)) {
- return false;
- }
-
- $rcube = rcube::get_instance();
-
- if (!$dns_check || !$rcube->config->get('email_dns_check')) {
- return true;
- }
-
- // find MX record(s)
- if (!function_exists('getmxrr') || getmxrr($domain_part, $mx_records)) {
- return true;
- }
-
- // find any DNS record
- if (!function_exists('checkdnsrr') || checkdnsrr($domain_part, 'ANY')) {
- return true;
- }
- }
-
- return false;
- }
-
-
- /**
- * Validates IPv4 or IPv6 address
- *
- * @param string $ip IP address in v4 or v6 format
- *
- * @return bool True if the address is valid
- */
- public static function check_ip($ip)
- {
- // IPv6, but there's no build-in IPv6 support
- if (strpos($ip, ':') !== false && !defined('AF_INET6')) {
- $parts = explode(':', $ip);
- $count = count($parts);
-
- if ($count > 8 || $count < 2) {
- return false;
- }
-
- foreach ($parts as $idx => $part) {
- $length = strlen($part);
- if (!$length) {
- // there can be only one ::
- if ($found_empty) {
- return false;
- }
- $found_empty = true;
- }
- // last part can be an IPv4 address
- else if ($idx == $count - 1) {
- if (!preg_match('/^[0-9a-f]{1,4}$/i', $part)) {
- return @inet_pton($part) !== false;
- }
- }
- else if (!preg_match('/^[0-9a-f]{1,4}$/i', $part)) {
- return false;
- }
- }
-
- return true;
- }
-
- return @inet_pton($ip) !== false;
- }
-
-
- /**
- * Check whether the HTTP referer matches the current request
- *
- * @return boolean True if referer is the same host+path, false if not
- */
- public static function check_referer()
- {
- $uri = parse_url($_SERVER['REQUEST_URI']);
- $referer = parse_url(self::request_header('Referer'));
- return $referer['host'] == self::request_header('Host') && $referer['path'] == $uri['path'];
- }
-
-
- /**
- * Replacing specials characters to a specific encoding type
- *
- * @param string Input string
- * @param string Encoding type: text|html|xml|js|url
- * @param string Replace mode for tags: show|replace|remove
- * @param boolean Convert newlines
- *
- * @return string The quoted string
- */
- public static function rep_specialchars_output($str, $enctype = '', $mode = '', $newlines = true)
- {
- static $html_encode_arr = false;
- static $js_rep_table = false;
- static $xml_rep_table = false;
-
- if (!is_string($str)) {
- $str = strval($str);
- }
-
- // encode for HTML output
- if ($enctype == 'html') {
- if (!$html_encode_arr) {
- $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS);
- unset($html_encode_arr['?']);
- }
-
- $encode_arr = $html_encode_arr;
-
- // don't replace quotes and html tags
- if ($mode == 'show' || $mode == '') {
- $ltpos = strpos($str, '<');
- if ($ltpos !== false && strpos($str, '>', $ltpos) !== false) {
- unset($encode_arr['"']);
- unset($encode_arr['<']);
- unset($encode_arr['>']);
- unset($encode_arr['&']);
- }
- }
- else if ($mode == 'remove') {
- $str = strip_tags($str);
- }
-
- $out = strtr($str, $encode_arr);
-
- return $newlines ? nl2br($out) : $out;
- }
-
- // if the replace tables for XML and JS are not yet defined
- if ($js_rep_table === false) {
- $js_rep_table = $xml_rep_table = array();
- $xml_rep_table['&'] = '&amp;';
-
- // can be increased to support more charsets
- for ($c=160; $c<256; $c++) {
- $xml_rep_table[chr($c)] = "&#$c;";
- }
-
- $xml_rep_table['"'] = '&quot;';
- $js_rep_table['"'] = '\\"';
- $js_rep_table["'"] = "\\'";
- $js_rep_table["\\"] = "\\\\";
- // Unicode line and paragraph separators (#1486310)
- $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A8))] = '&#8232;';
- $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A9))] = '&#8233;';
- }
-
- // encode for javascript use
- if ($enctype == 'js') {
- return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), strtr($str, $js_rep_table));
- }
-
- // encode for plaintext
- if ($enctype == 'text') {
- return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
- }
-
- if ($enctype == 'url') {
- return rawurlencode($str);
- }
-
- // encode for XML
- if ($enctype == 'xml') {
- return strtr($str, $xml_rep_table);
- }
-
- // no encoding given -> return original string
- return $str;
- }
-
-
- /**
- * Read input value and convert it for internal use
- * Performs stripslashes() and charset conversion if necessary
- *
- * @param string Field name to read
- * @param int Source to get value from (GPC)
- * @param boolean Allow HTML tags in field value
- * @param string Charset to convert into
- *
- * @return string Field value or NULL if not available
- */
- public static function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL)
- {
- $value = NULL;
-
- if ($source == self::INPUT_GET) {
- if (isset($_GET[$fname])) {
- $value = $_GET[$fname];
- }
- }
- else if ($source == self::INPUT_POST) {
- if (isset($_POST[$fname])) {
- $value = $_POST[$fname];
- }
- }
- else if ($source == self::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 self::parse_input_value($value, $allow_html, $charset);
- }
-
-
- /**
- * Parse/validate input value. See self::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
- *
- * @return string Parsed value
- */
- public static function parse_input_value($value, $allow_html=FALSE, $charset=NULL)
- {
- global $OUTPUT;
-
- if (empty($value)) {
- return $value;
- }
-
- if (is_array($value)) {
- foreach ($value as $idx => $val) {
- $value[$idx] = self::parse_input_value($val, $allow_html, $charset);
- }
- return $value;
- }
-
- // strip slashes if magic_quotes enabled
- if (get_magic_quotes_gpc() || get_magic_quotes_runtime()) {
- $value = stripslashes($value);
- }
-
- // 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 = rcube_charset::clean($value);
- }
-
- // convert to internal charset
- if ($charset && $output_charset) {
- $value = rcube_charset::convert($value, $output_charset, $charset);
- }
-
- return $value;
- }
-
-
- /**
- * Convert array of request parameters (prefixed with _)
- * to a regular array with non-prefixed keys.
- *
- * @param int $mode Source to get value from (GPC)
- * @param string $ignore PCRE expression to skip parameters by name
- * @param boolean $allow_html Allow HTML tags in field value
- *
- * @return array Hash array with all request parameters
- */
- public static function request2param($mode = null, $ignore = 'task|action', $allow_html = false)
- {
- $out = array();
- $src = $mode == self::INPUT_GET ? $_GET : ($mode == self::INPUT_POST ? $_POST : $_REQUEST);
-
- foreach (array_keys($src) as $key) {
- $fname = $key[0] == '_' ? substr($key, 1) : $key;
- if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) {
- $out[$fname] = self::get_input_value($key, $mode, $allow_html);
- }
- }
-
- return $out;
- }
-
-
- /**
- * Convert the given string into a valid HTML identifier
- * Same functionality as done in app.js with rcube_webmail.html_identifier()
- */
- public static function html_identifier($str, $encode=false)
- {
- if ($encode) {
- return rtrim(strtr(base64_encode($str), '+/', '-_'), '=');
- }
- else {
- return asciiwords($str, true, '_');
- }
- }
-
-
- /**
- * Replace all css definitions with #container [def]
- * and remove css-inlined scripting
- *
- * @param string CSS source code
- * @param string Container ID to use as prefix
- *
- * @return string Modified CSS source
- */
- public static function 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
- $source = self::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! */';
- }
-
- $strict_url_regexp = '!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims';
-
- // cut out all contents between { and }
- while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) {
- $nested = strpos($source, '{', $pos+1);
- if ($nested && $nested < $pos2) // when dealing with nested blocks (e.g. @media), take the inner one
- $pos = $nested;
- $length = $pos2 - $pos - 1;
- $styles = substr($source, $pos+1, $length);
-
- // 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($strict_url_regexp, $line)) {
- $a_styles = array('/* evil! */');
- break;
- }
- }
-
- $styles = join(";\n", $a_styles);
- }
-
- $key = $replacements->add($styles);
- $repl = $replacements->get_replacement($key);
- $source = substr_replace($source, $repl, $pos+1, $length);
- $last_pos = $pos2 - ($length - strlen($repl));
- }
-
- // remove html comments and add #container to each tag selector.
- // also replace body definition because we also stripped off the <body> tag
- $source = preg_replace(
- array(
- '/(^\s*<\!--)|(-->\s*$)/m',
- '/(^\s*|,\s*|\}\s*)([a-z0-9\._#\*][a-z0-9\.\-_]*)/im',
- '/'.preg_quote($container_id, '/').'\s+body/i',
- ),
- array(
- '',
- "\\1#$container_id \\2",
- $container_id,
- ),
- $source);
-
- // put block contents back in
- $source = $replacements->resolve($source);
-
- return $source;
- }
-
-
- /**
- * Generate CSS classes from mimetype and filename extension
- *
- * @param string $mimetype Mimetype
- * @param string $filename Filename
- *
- * @return string CSS classes separated by space
- */
- public static function file2class($mimetype, $filename)
- {
- $mimetype = strtolower($mimetype);
- $filename = strtolower($filename);
-
- list($primary, $secondary) = explode('/', $mimetype);
-
- $classes = array($primary ? $primary : 'unknown');
-
- if ($secondary) {
- $classes[] = $secondary;
- }
-
- if (preg_match('/\.([a-z0-9]+)$/', $filename, $m)) {
- if (!in_array($m[1], $classes)) {
- $classes[] = $m[1];
- }
- }
-
- return join(" ", $classes);
- }
-
-
- /**
- * Decode escaped entities used by known XSS exploits.
- * See http://downloads.securityfocus.com/vulnerabilities/exploits/26800.eml for examples
- *
- * @param string CSS content to decode
- *
- * @return string Decoded string
- */
- public static function xss_entity_decode($content)
- {
- $out = html_entity_decode(html_entity_decode($content));
- $out = preg_replace_callback('/\\\([0-9a-f]{4})/i',
- array(self, 'xss_entity_decode_callback'), $out);
- $out = preg_replace('#/\*.*\*/#Ums', '', $out);
-
- return $out;
- }
-
-
- /**
- * preg_replace_callback callback for xss_entity_decode
- *
- * @param array $matches Result from preg_replace_callback
- *
- * @return string Decoded entity
- */
- public static function xss_entity_decode_callback($matches)
- {
- return chr(hexdec($matches[1]));
- }
-
-
- /**
- * Check if we can process not exceeding memory_limit
- *
- * @param integer Required amount of memory
- *
- * @return boolean True if memory won't be exceeded, False otherwise
- */
- public static function mem_check($need)
- {
- $mem_limit = parse_bytes(ini_get('memory_limit'));
- $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB
-
- return $mem_limit > 0 && $memory + $need > $mem_limit ? false : true;
- }
-
-
- /**
- * Check if working in SSL mode
- *
- * @param integer $port HTTPS port number
- * @param boolean $use_https Enables 'use_https' option checking
- *
- * @return boolean
- */
- public static function https_check($port=null, $use_https=true)
- {
- if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') {
- return true;
- }
- if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])
- && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https'
- && in_array($_SERVER['REMOTE_ADDR'], rcube::get_instance()->config->get('proxy_whitelist', array()))) {
- return true;
- }
- if ($port && $_SERVER['SERVER_PORT'] == $port) {
- return true;
- }
- if ($use_https && rcube::get_instance()->config->get('use_https')) {
- return true;
- }
-
- return false;
- }
-
-
- /**
- * Replaces hostname variables.
- *
- * @param string $name Hostname
- * @param string $host Optional IMAP hostname
- *
- * @return string Hostname
- */
- public static function parse_host($name, $host = '')
- {
- if (!is_string($name)) {
- return $name;
- }
-
- // %n - host
- $n = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']);
- // %t - host name without first part, e.g. %n=mail.domain.tld, %t=domain.tld
- $t = preg_replace('/^[^\.]+\./', '', $n);
- // %d - domain name without first part
- $d = preg_replace('/^[^\.]+\./', '', $_SERVER['HTTP_HOST']);
- // %h - IMAP host
- $h = $_SESSION['storage_host'] ? $_SESSION['storage_host'] : $host;
- // %z - IMAP domain without first part, e.g. %h=imap.domain.tld, %z=domain.tld
- $z = preg_replace('/^[^\.]+\./', '', $h);
- // %s - domain name after the '@' from e-mail address provided at login screen. Returns FALSE if an invalid email is provided
- if (strpos($name, '%s') !== false) {
- $user_email = self::get_input_value('_user', self::INPUT_POST);
- $user_email = self::idn_convert($user_email, true);
- $matches = preg_match('/(.*)@([a-z0-9\.\-\[\]\:]+)/i', $user_email, $s);
- if ($matches < 1 || filter_var($s[1]."@".$s[2], FILTER_VALIDATE_EMAIL) === false) {
- return false;
- }
- }
-
- return str_replace(array('%n', '%t', '%d', '%h', '%z', '%s'), array($n, $t, $d, $h, $z, $s[2]), $name);
- }
-
-
- /**
- * Returns remote IP address and forwarded addresses if found
- *
- * @return string Remote IP address(es)
- */
- public static function remote_ip()
- {
- $address = $_SERVER['REMOTE_ADDR'];
-
- // append the NGINX X-Real-IP header, if set
- if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
- $remote_ip[] = 'X-Real-IP: ' . $_SERVER['HTTP_X_REAL_IP'];
- }
- // append the X-Forwarded-For header, if set
- if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
- $remote_ip[] = 'X-Forwarded-For: ' . $_SERVER['HTTP_X_FORWARDED_FOR'];
- }
-
- if (!empty($remote_ip)) {
- $address .= '(' . implode(',', $remote_ip) . ')';
- }
-
- return $address;
- }
-
-
- /**
- * Returns the real remote IP address
- *
- * @return string Remote IP address
- */
- public static function remote_addr()
- {
- // Check if any of the headers are set first to improve performance
- if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) || !empty($_SERVER['HTTP_X_REAL_IP'])) {
- $proxy_whitelist = rcube::get_instance()->config->get('proxy_whitelist', array());
- if (in_array($_SERVER['REMOTE_ADDR'], $proxy_whitelist)) {
- if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
- foreach(array_reverse(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])) as $forwarded_ip) {
- if (!in_array($forwarded_ip, $proxy_whitelist)) {
- return $forwarded_ip;
- }
- }
- }
-
- if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
- return $_SERVER['HTTP_X_REAL_IP'];
- }
- }
- }
-
- if (!empty($_SERVER['REMOTE_ADDR'])) {
- return $_SERVER['REMOTE_ADDR'];
- }
-
- return '';
- }
-
- /**
- * Read a specific HTTP request header.
- *
- * @param string $name Header name
- *
- * @return mixed Header value or null if not available
- */
- public static function request_header($name)
- {
- if (function_exists('getallheaders')) {
- $hdrs = array_change_key_case(getallheaders(), CASE_UPPER);
- $key = strtoupper($name);
- }
- else {
- $key = 'HTTP_' . strtoupper(strtr($name, '-', '_'));
- $hdrs = array_change_key_case($_SERVER, CASE_UPPER);
- }
-
- return $hdrs[$key];
- }
-
- /**
- * Explode quoted string
- *
- * @param string Delimiter expression string for preg_match()
- * @param string Input string
- *
- * @return array String items
- */
- public static function explode_quoted_string($delimiter, $string)
- {
- $result = array();
- $strlen = strlen($string);
-
- for ($q=$p=$i=0; $i < $strlen; $i++) {
- if ($string[$i] == "\"" && $string[$i-1] != "\\") {
- $q = $q ? false : true;
- }
- else if (!$q && preg_match("/$delimiter/", $string[$i])) {
- $result[] = substr($string, $p, $i - $p);
- $p = $i + 1;
- }
- }
-
- $result[] = (string) substr($string, $p);
-
- return $result;
- }
-
-
- /**
- * Improved equivalent to strtotime()
- *
- * @param string $date Date string
- *
- * @return int Unix timestamp
- */
- public static function strtotime($date)
- {
- $date = self::clean_datestr($date);
-
- // unix timestamp
- if (is_numeric($date)) {
- return (int) $date;
- }
-
- // if date parsing fails, we have a date in non-rfc format.
- // remove token from the end and try again
- while ((($ts = @strtotime($date)) === false) || ($ts < 0)) {
- $d = explode(' ', $date);
- array_pop($d);
- if (!$d) {
- break;
- }
- $date = implode(' ', $d);
- }
-
- return (int) $ts;
- }
-
- /**
- * Date parsing function that turns the given value into a DateTime object
- *
- * @param string $date Date string
- *
- * @return object DateTime instance or false on failure
- */
- public static function anytodatetime($date, $timezone = null)
- {
- if (is_object($date) && is_a($date, 'DateTime')) {
- return $date;
- }
-
- $dt = false;
- $date = self::clean_datestr($date);
-
- // try to parse string with DateTime first
- if (!empty($date)) {
- try {
- $dt = new DateTime($date, $timezone);
- }
- catch (Exception $e) {
- // ignore
- }
- }
-
- // try our advanced strtotime() method
- if (!$dt && ($timestamp = self::strtotime($date))) {
- try {
- $dt = new DateTime("@".$timestamp);
- }
- catch (Exception $e) {
- // ignore
- }
- }
-
- return $dt;
- }
-
- /**
- * Clean up date string for strtotime() input
- *
- * @param string $date Date string
- *
- * @return string Date string
- */
- public static function clean_datestr($date)
- {
- $date = trim($date);
-
- // check for MS Outlook vCard date format YYYYMMDD
- if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) {
- return sprintf('%04d-%02d-%02d 00:00:00', intval($m[1]), intval($m[2]), intval($m[3]));
- }
-
- // Clean malformed data
- $date = preg_replace(
- array(
- '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal
- '/[^a-z0-9\x20\x09:+-\/]/i', // remove any invalid characters
- '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names
- ),
- array(
- '\\1',
- '',
- '',
- ), $date);
-
- $date = trim($date);
-
- // try to fix dd/mm vs. mm/dd discrepancy, we can't do more here
- if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})$/', $date, $m)) {
- $mdy = $m[2] > 12 && $m[1] <= 12;
- $day = $mdy ? $m[2] : $m[1];
- $month = $mdy ? $m[1] : $m[2];
- $date = sprintf('%04d-%02d-%02d 00:00:00', intval($m[3]), $month, $day);
- }
- // I've found that YYYY.MM.DD is recognized wrong, so here's a fix
- else if (preg_match('/^(\d{4})\.(\d{1,2})\.(\d{1,2})$/', $date)) {
- $date = str_replace('.', '-', $date) . ' 00:00:00';
- }
-
- return $date;
- }
-
- /*
- * Idn_to_ascii wrapper.
- * Intl/Idn modules version of this function doesn't work with e-mail address
- */
- public static function idn_to_ascii($str)
- {
- return self::idn_convert($str, true);
- }
-
-
- /*
- * Idn_to_ascii wrapper.
- * Intl/Idn modules version of this function doesn't work with e-mail address
- */
- public static function idn_to_utf8($str)
- {
- return self::idn_convert($str, false);
- }
-
-
- public static function idn_convert($input, $is_utf=false)
- {
- if ($at = strpos($input, '@')) {
- $user = substr($input, 0, $at);
- $domain = substr($input, $at+1);
- }
- else {
- $domain = $input;
- }
-
- $domain = $is_utf ? idn_to_ascii($domain) : idn_to_utf8($domain);
-
- if ($domain === false) {
- return '';
- }
-
- return $at ? $user . '@' . $domain : $domain;
- }
-
- /**
- * Split the given string into word tokens
- *
- * @param string Input to tokenize
- * @return array List of tokens
- */
- public static function tokenize_string($str)
- {
- return explode(" ", preg_replace(
- array('/[\s;\/+-]+/i', '/(\d)[-.\s]+(\d)/', '/\s\w{1,3}\s/u'),
- array(' ', '\\1\\2', ' '),
- $str));
- }
-
- /**
- * Normalize the given string for fulltext search.
- * Currently only optimized for ISO-8859-1 and ISO-8859-2 characters; to be extended
- *
- * @param string Input string (UTF-8)
- * @param boolean True to return list of words as array
- *
- * @return mixed Normalized string or a list of normalized tokens
- */
- public static function normalize_string($str, $as_array = false)
- {
- // replace 4-byte unicode characters with '?' character,
- // these are not supported in default utf-8 charset on mysql,
- // the chance we'd need them in searching is very low
- $str = preg_replace('/('
- . '\xF0[\x90-\xBF][\x80-\xBF]{2}'
- . '|[\xF1-\xF3][\x80-\xBF]{3}'
- . '|\xF4[\x80-\x8F][\x80-\xBF]{2}'
- . ')/', '?', $str);
-
- // split by words
- $arr = self::tokenize_string($str);
-
- // detect character set
- if (utf8_encode(utf8_decode($str)) == $str) {
- // ISO-8859-1 (or ASCII)
- preg_match_all('/./u', 'äâàåáãæçéêëèïîìíñöôòøõóüûùúýÿ', $keys);
- preg_match_all('/./', 'aaaaaaaceeeeiiiinoooooouuuuyy', $values);
-
- $mapping = array_combine($keys[0], $values[0]);
- $mapping = array_merge($mapping, array('ß' => 'ss', 'ae' => 'a', 'oe' => 'o', 'ue' => 'u'));
- }
- else if (rcube_charset::convert(rcube_charset::convert($str, 'UTF-8', 'ISO-8859-2'), 'ISO-8859-2', 'UTF-8') == $str) {
- // ISO-8859-2
- preg_match_all('/./u', 'ąáâäćçčéęëěíîłľĺńňóôöŕřśšşťţůúűüźžżý', $keys);
- preg_match_all('/./', 'aaaaccceeeeiilllnnooorrsssttuuuuzzzy', $values);
-
- $mapping = array_combine($keys[0], $values[0]);
- $mapping = array_merge($mapping, array('ß' => 'ss', 'ae' => 'a', 'oe' => 'o', 'ue' => 'u'));
- }
-
- foreach ($arr as $i => $part) {
- $part = mb_strtolower($part);
-
- if (!empty($mapping)) {
- $part = strtr($part, $mapping);
- }
-
- $arr[$i] = $part;
- }
-
- return $as_array ? $arr : join(" ", $arr);
- }
-
- /**
- * Parse commandline arguments into a hash array
- *
- * @param array $aliases Argument alias names
- *
- * @return array Argument values hash
- */
- public static function get_opt($aliases = array())
- {
- $args = array();
-
- for ($i=1; $i < count($_SERVER['argv']); $i++) {
- $arg = $_SERVER['argv'][$i];
- $value = true;
- $key = null;
-
- if ($arg[0] == '-') {
- $key = preg_replace('/^-+/', '', $arg);
- $sp = strpos($arg, '=');
- if ($sp > 0) {
- $key = substr($key, 0, $sp - 2);
- $value = substr($arg, $sp+1);
- }
- else if (strlen($_SERVER['argv'][$i+1]) && $_SERVER['argv'][$i+1][0] != '-') {
- $value = $_SERVER['argv'][++$i];
- }
-
- $args[$key] = is_string($value) ? preg_replace(array('/^["\']/', '/["\']$/'), '', $value) : $value;
- }
- else {
- $args[] = $arg;
- }
-
- if ($alias = $aliases[$key]) {
- $args[$alias] = $args[$key];
- }
- }
-
- return $args;
- }
-
- /**
- * Safe password prompt for command line
- * from http://blogs.sitepoint.com/2009/05/01/interactive-cli-password-prompt-in-php/
- *
- * @return string Password
- */
- public static function prompt_silent($prompt = "Password:")
- {
- if (preg_match('/^win/i', PHP_OS)) {
- $vbscript = sys_get_temp_dir() . 'prompt_password.vbs';
- $vbcontent = 'wscript.echo(InputBox("' . addslashes($prompt) . '", "", "password here"))';
- file_put_contents($vbscript, $vbcontent);
-
- $command = "cscript //nologo " . escapeshellarg($vbscript);
- $password = rtrim(shell_exec($command));
- unlink($vbscript);
-
- return $password;
- }
- else {
- $command = "/usr/bin/env bash -c 'echo OK'";
- if (rtrim(shell_exec($command)) !== 'OK') {
- echo $prompt;
- $pass = trim(fgets(STDIN));
- echo chr(8)."\r" . $prompt . str_repeat("*", strlen($pass))."\n";
- return $pass;
- }
-
- $command = "/usr/bin/env bash -c 'read -s -p \"" . addslashes($prompt) . "\" mypassword && echo \$mypassword'";
- $password = rtrim(shell_exec($command));
- echo "\n";
- return $password;
- }
- }
-
- /**
- * Find out if the string content means true or false
- *
- * @param string $str Input value
- *
- * @return boolean Boolean value
- */
- public static function get_boolean($str)
- {
- $str = strtolower($str);
-
- return !in_array($str, array('false', '0', 'no', 'off', 'nein', ''), true);
- }
-
- /**
- * OS-dependent absolute path detection
- */
- public static function is_absolute_path($path)
- {
- if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
- return (bool) preg_match('!^[a-z]:[\\\\/]!i', $path);
- }
- else {
- return $path[0] == '/';
- }
- }
-
- /**
- * Resolve relative URL
- *
- * @param string $url Relative URL
- *
- * @return string Absolute URL
- */
- public static function resolve_url($url)
- {
- // prepend protocol://hostname:port
- if (!preg_match('|^https?://|', $url)) {
- $schema = 'http';
- $default_port = 80;
-
- if (self::https_check()) {
- $schema = 'https';
- $default_port = 443;
- }
-
- $prefix = $schema . '://' . preg_replace('/:\d+$/', '', $_SERVER['HTTP_HOST']);
- if ($_SERVER['SERVER_PORT'] != $default_port) {
- $prefix .= ':' . $_SERVER['SERVER_PORT'];
- }
-
- $url = $prefix . ($url[0] == '/' ? '' : '/') . $url;
- }
-
- return $url;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_vcard.php b/lib/ext/Roundcube/rcube_vcard.php
deleted file mode 100644
index 96add11..0000000
--- a/lib/ext/Roundcube/rcube_vcard.php
+++ /dev/null
@@ -1,904 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Logical representation of a vcard address record |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Logical representation of a vcard-based address record
- * Provides functions to parse and export vCard data format
- *
- * @package Framework
- * @subpackage Addressbook
- */
-class rcube_vcard
-{
- private static $values_decoded = false;
- private $raw = array(
- 'FN' => array(),
- 'N' => array(array('','','','','')),
- );
- private static $fieldmap = array(
- 'phone' => 'TEL',
- 'birthday' => 'BDAY',
- 'website' => 'URL',
- 'notes' => 'NOTE',
- 'email' => 'EMAIL',
- 'address' => 'ADR',
- 'jobtitle' => 'TITLE',
- 'department' => 'X-DEPARTMENT',
- 'gender' => 'X-GENDER',
- 'maidenname' => 'X-MAIDENNAME',
- 'anniversary' => 'X-ANNIVERSARY',
- 'assistant' => 'X-ASSISTANT',
- 'manager' => 'X-MANAGER',
- 'spouse' => 'X-SPOUSE',
- 'edit' => 'X-AB-EDIT',
- 'groups' => 'CATEGORIES',
- );
- private $typemap = array(
- 'IPHONE' => 'mobile',
- 'CELL' => 'mobile',
- 'WORK,FAX' => 'workfax',
- );
- private $phonetypemap = array(
- 'HOME1' => 'HOME',
- 'BUSINESS1' => 'WORK',
- 'BUSINESS2' => 'WORK2',
- 'BUSINESSFAX' => 'WORK,FAX',
- 'MOBILE' => 'CELL',
- );
- private $addresstypemap = array(
- 'BUSINESS' => 'WORK',
- );
- private $immap = array(
- 'X-JABBER' => 'jabber',
- 'X-ICQ' => 'icq',
- 'X-MSN' => 'msn',
- 'X-AIM' => 'aim',
- 'X-YAHOO' => 'yahoo',
- 'X-SKYPE' => 'skype',
- 'X-SKYPE-USERNAME' => 'skype',
- );
-
- public $business = false;
- public $displayname;
- public $surname;
- public $firstname;
- public $middlename;
- public $nickname;
- public $organization;
- public $email = array();
-
- public static $eol = "\r\n";
-
-
- /**
- * Constructor
- */
- public function __construct($vcard = null, $charset = RCUBE_CHARSET, $detect = false, $fieldmap = array())
- {
- if (!empty($fieldmap)) {
- $this->extend_fieldmap($fieldmap);
- }
-
- if (!empty($vcard)) {
- $this->load($vcard, $charset, $detect);
- }
- }
-
- /**
- * Load record from (internal, unfolded) vcard 3.0 format
- *
- * @param string vCard string to parse
- * @param string Charset of string values
- * @param boolean True if loading a 'foreign' vcard and extra heuristics for charset detection is required
- */
- public function load($vcard, $charset = RCUBE_CHARSET, $detect = false)
- {
- self::$values_decoded = false;
- $this->raw = self::vcard_decode(self::cleanup($vcard));
-
- // resolve charset parameters
- if ($charset == null) {
- $this->raw = self::charset_convert($this->raw);
- }
- // vcard has encoded values and charset should be detected
- else if ($detect && self::$values_decoded
- && ($detected_charset = self::detect_encoding(self::vcard_encode($this->raw)))
- && $detected_charset != RCUBE_CHARSET
- ) {
- $this->raw = self::charset_convert($this->raw, $detected_charset);
- }
-
- // consider FN empty if the same as the primary e-mail address
- if ($this->raw['FN'][0][0] == $this->raw['EMAIL'][0][0]) {
- $this->raw['FN'][0][0] = '';
- }
-
- // find well-known address fields
- $this->displayname = $this->raw['FN'][0][0];
- $this->surname = $this->raw['N'][0][0];
- $this->firstname = $this->raw['N'][0][1];
- $this->middlename = $this->raw['N'][0][2];
- $this->nickname = $this->raw['NICKNAME'][0][0];
- $this->organization = $this->raw['ORG'][0][0];
- $this->business = ($this->raw['X-ABSHOWAS'][0][0] == 'COMPANY') || (join('', (array)$this->raw['N'][0]) == '' && !empty($this->organization));
-
- foreach ((array)$this->raw['EMAIL'] as $i => $raw_email) {
- $this->email[$i] = is_array($raw_email) ? $raw_email[0] : $raw_email;
- }
-
- // make the pref e-mail address the first entry in $this->email
- $pref_index = $this->get_type_index('EMAIL', 'pref');
- if ($pref_index > 0) {
- $tmp = $this->email[0];
- $this->email[0] = $this->email[$pref_index];
- $this->email[$pref_index] = $tmp;
- }
-
- // fix broken vcards from Outlook that only supply ORG but not the required N or FN properties
- if (!strlen(trim($this->displayname . $this->surname . $this->firstname)) && strlen($this->organization)) {
- $this->displayname = $this->organization;
- }
- }
-
- /**
- * Return vCard data as associative array to be unsed in Roundcube address books
- *
- * @return array Hash array with key-value pairs
- */
- public function get_assoc()
- {
- $out = array('name' => $this->displayname);
- $typemap = $this->typemap;
-
- // copy name fields to output array
- foreach (array('firstname','surname','middlename','nickname','organization') as $col) {
- if (strlen($this->$col)) {
- $out[$col] = $this->$col;
- }
- }
-
- if ($this->raw['N'][0][3])
- $out['prefix'] = $this->raw['N'][0][3];
- if ($this->raw['N'][0][4])
- $out['suffix'] = $this->raw['N'][0][4];
-
- // convert from raw vcard data into associative data for Roundcube
- foreach (array_flip(self::$fieldmap) as $tag => $col) {
- foreach ((array)$this->raw[$tag] as $i => $raw) {
- if (is_array($raw)) {
- $k = -1;
- $key = $col;
- $subtype = '';
-
- if (!empty($raw['type'])) {
- $combined = join(',', self::array_filter((array)$raw['type'], 'internet,pref', true));
- $combined = strtoupper($combined);
-
- if ($typemap[$combined]) {
- $subtype = $typemap[$combined];
- }
- else if ($typemap[$raw['type'][++$k]]) {
- $subtype = $typemap[$raw['type'][$k]];
- }
- else {
- $subtype = strtolower($raw['type'][$k]);
- }
-
- while ($k < count($raw['type']) && ($subtype == 'internet' || $subtype == 'pref')) {
- $subtype = $typemap[$raw['type'][++$k]] ? $typemap[$raw['type'][$k]] : strtolower($raw['type'][$k]);
- }
- }
-
- // read vcard 2.1 subtype
- if (!$subtype) {
- foreach ($raw as $k => $v) {
- if (!is_numeric($k) && $v === true && ($k = strtolower($k))
- && !in_array($k, array('pref','internet','voice','base64'))
- ) {
- $k_uc = strtoupper($k);
- $subtype = $typemap[$k_uc] ? $typemap[$k_uc] : $k;
- break;
- }
- }
- }
-
- // force subtype if none set
- if (!$subtype && preg_match('/^(email|phone|address|website)/', $key)) {
- $subtype = 'other';
- }
-
- if ($subtype) {
- $key .= ':' . $subtype;
- }
-
- // split ADR values into assoc array
- if ($tag == 'ADR') {
- list(,, $value['street'], $value['locality'], $value['region'], $value['zipcode'], $value['country']) = $raw;
- $out[$key][] = $value;
- }
- else {
- $out[$key][] = $raw[0];
- }
- }
- else {
- $out[$col][] = $raw;
- }
- }
- }
-
- // handle special IM fields as used by Apple
- foreach ($this->immap as $tag => $type) {
- foreach ((array)$this->raw[$tag] as $i => $raw) {
- $out['im:'.$type][] = $raw[0];
- }
- }
-
- // copy photo data
- if ($this->raw['PHOTO']) {
- $out['photo'] = $this->raw['PHOTO'][0][0];
- }
-
- return $out;
- }
-
- /**
- * Convert the data structure into a vcard 3.0 string
- */
- public function export($folded = true)
- {
- $vcard = self::vcard_encode($this->raw);
- return $folded ? self::rfc2425_fold($vcard) : $vcard;
- }
-
- /**
- * Clear the given fields in the loaded vcard data
- *
- * @param array List of field names to be reset
- */
- public function reset($fields = null)
- {
- if (!$fields) {
- $fields = array_merge(array_values(self::$fieldmap), array_keys($this->immap),
- array('FN','N','ORG','NICKNAME','EMAIL','ADR','BDAY'));
- }
-
- foreach ($fields as $f) {
- unset($this->raw[$f]);
- }
-
- if (!$this->raw['N']) {
- $this->raw['N'] = array(array('','','','',''));
- }
- if (!$this->raw['FN']) {
- $this->raw['FN'] = array();
- }
-
- $this->email = array();
- }
-
- /**
- * Setter for address record fields
- *
- * @param string Field name
- * @param string Field value
- * @param string Type/section name
- */
- public function set($field, $value, $type = 'HOME')
- {
- $field = strtolower($field);
- $type_uc = strtoupper($type);
-
- switch ($field) {
- case 'name':
- case 'displayname':
- $this->raw['FN'][0][0] = $this->displayname = $value;
- break;
-
- case 'surname':
- $this->raw['N'][0][0] = $this->surname = $value;
- break;
-
- case 'firstname':
- $this->raw['N'][0][1] = $this->firstname = $value;
- break;
-
- case 'middlename':
- $this->raw['N'][0][2] = $this->middlename = $value;
- break;
-
- case 'prefix':
- $this->raw['N'][0][3] = $value;
- break;
-
- case 'suffix':
- $this->raw['N'][0][4] = $value;
- break;
-
- case 'nickname':
- $this->raw['NICKNAME'][0][0] = $this->nickname = $value;
- break;
-
- case 'organization':
- $this->raw['ORG'][0][0] = $this->organization = $value;
- break;
-
- case 'photo':
- if (strpos($value, 'http:') === 0) {
- // TODO: fetch file from URL and save it locally?
- $this->raw['PHOTO'][0] = array(0 => $value, 'url' => true);
- }
- else {
- $this->raw['PHOTO'][0] = array(0 => $value, 'base64' => (bool) preg_match('![^a-z0-9/=+-]!i', $value));
- }
- break;
-
- case 'email':
- $this->raw['EMAIL'][] = array(0 => $value, 'type' => array_filter(array('INTERNET', $type_uc)));
- $this->email[] = $value;
- break;
-
- case 'im':
- // save IM subtypes into extension fields
- $typemap = array_flip($this->immap);
- if ($field = $typemap[strtolower($type)]) {
- $this->raw[$field][] = array(0 => $value);
- }
- break;
-
- case 'birthday':
- case 'anniversary':
- if (($val = rcube_utils::anytodatetime($value)) && ($fn = self::$fieldmap[$field])) {
- $this->raw[$fn][] = array(0 => $val->format('Y-m-d'), 'value' => array('date'));
- }
- break;
-
- case 'address':
- if ($this->addresstypemap[$type_uc]) {
- $type = $this->addresstypemap[$type_uc];
- }
-
- $value = $value[0] ? $value : array('', '', $value['street'], $value['locality'], $value['region'], $value['zipcode'], $value['country']);
-
- // fall through if not empty
- if (!strlen(join('', $value))) {
- break;
- }
-
- default:
- if ($field == 'phone' && $this->phonetypemap[$type_uc]) {
- $type = $this->phonetypemap[$type_uc];
- }
-
- if (($tag = self::$fieldmap[$field]) && (is_array($value) || strlen($value))) {
- $index = count($this->raw[$tag]);
- $this->raw[$tag][$index] = (array)$value;
- if ($type) {
- $typemap = array_flip($this->typemap);
- $this->raw[$tag][$index]['type'] = explode(',', ($typemap[$type_uc] ? $typemap[$type_uc] : $type));
- }
- }
- break;
- }
- }
-
- /**
- * Setter for individual vcard properties
- *
- * @param string VCard tag name
- * @param array Value-set of this vcard property
- * @param boolean Set to true if the value-set should be appended instead of replacing any existing value-set
- */
- public function set_raw($tag, $value, $append = false)
- {
- $index = $append ? count($this->raw[$tag]) : 0;
- $this->raw[$tag][$index] = (array)$value;
- }
-
- /**
- * Find index with the '$type' attribute
- *
- * @param string Field name
- * @return int Field index having $type set
- */
- private function get_type_index($field, $type = 'pref')
- {
- $result = 0;
- if ($this->raw[$field]) {
- foreach ($this->raw[$field] as $i => $data) {
- if (is_array($data['type']) && in_array_nocase('pref', $data['type'])) {
- $result = $i;
- }
- }
- }
-
- return $result;
- }
-
- /**
- * Convert a whole vcard (array) to UTF-8.
- * If $force_charset is null, each member value that has a charset parameter will be converted
- */
- private static function charset_convert($card, $force_charset = null)
- {
- foreach ($card as $key => $node) {
- foreach ($node as $i => $subnode) {
- if (is_array($subnode) && (($charset = $force_charset) || ($subnode['charset'] && ($charset = $subnode['charset'][0])))) {
- foreach ($subnode as $j => $value) {
- if (is_numeric($j) && is_string($value)) {
- $card[$key][$i][$j] = rcube_charset::convert($value, $charset);
- }
- }
- unset($card[$key][$i]['charset']);
- }
- }
- }
-
- return $card;
- }
-
- /**
- * Extends fieldmap definition
- */
- public function extend_fieldmap($map)
- {
- if (is_array($map)) {
- self::$fieldmap = array_merge($map, self::$fieldmap);
- }
- }
-
- /**
- * Factory method to import a vcard file
- *
- * @param string vCard file content
- *
- * @return array List of rcube_vcard objects
- */
- public static function import($data)
- {
- $out = array();
-
- // check if charsets are specified (usually vcard version < 3.0 but this is not reliable)
- if (preg_match('/charset=/i', substr($data, 0, 2048))) {
- $charset = null;
- }
- // detect charset and convert to utf-8
- else if (($charset = self::detect_encoding($data)) && $charset != RCUBE_CHARSET) {
- $data = rcube_charset::convert($data, $charset);
- $data = preg_replace(array('/^[\xFE\xFF]{2}/', '/^\xEF\xBB\xBF/', '/^\x00+/'), '', $data); // also remove BOM
- $charset = RCUBE_CHARSET;
- }
-
- $vcard_block = '';
- $in_vcard_block = false;
-
- foreach (preg_split("/[\r\n]+/", $data) as $line) {
- if ($in_vcard_block && !empty($line)) {
- $vcard_block .= $line . "\n";
- }
-
- $line = trim($line);
-
- if (preg_match('/^END:VCARD$/i', $line)) {
- // parse vcard
- $obj = new rcube_vcard($vcard_block, $charset, true, self::$fieldmap);
- // FN and N is required by vCard format (RFC 2426)
- // on import we can be less restrictive, let's addressbook decide
- if (!empty($obj->displayname) || !empty($obj->surname) || !empty($obj->firstname) || !empty($obj->email)) {
- $out[] = $obj;
- }
-
- $in_vcard_block = false;
- }
- else if (preg_match('/^BEGIN:VCARD$/i', $line)) {
- $vcard_block = $line . "\n";
- $in_vcard_block = true;
- }
- }
-
- return $out;
- }
-
- /**
- * Normalize vcard data for better parsing
- *
- * @param string vCard block
- *
- * @return string Cleaned vcard block
- */
- public static function cleanup($vcard)
- {
- // convert Apple X-ABRELATEDNAMES into X-* fields for better compatibility
- $vcard = preg_replace_callback(
- '/item(\d+)\.(X-ABRELATEDNAMES)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
- array('self', 'x_abrelatednames_callback'),
- $vcard);
-
- // Cleanup
- $vcard = preg_replace(array(
- // convert special types (like Skype) to normal type='skype' classes with this simple regex ;)
- '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./si',
- '/^item\d*\.X-AB.*$/mi', // remove cruft like item1.X-AB*
- '/^item\d*\./mi', // remove item1.ADR instead of ADR
- '/\n+/', // remove empty lines
- '/^(N:[^;\R]*)$/m', // if N doesn't have any semicolons, add some
- ),
- array(
- '\2;type=\5\3:\4',
- '',
- '',
- "\n",
- '\1;;;;',
- ), $vcard);
-
- // convert X-WAB-GENDER to X-GENDER
- if (preg_match('/X-WAB-GENDER:(\d)/', $vcard, $matches)) {
- $value = $matches[1] == '2' ? 'male' : 'female';
- $vcard = preg_replace('/X-WAB-GENDER:\d/', 'X-GENDER:' . $value, $vcard);
- }
-
- return $vcard;
- }
-
- private static function x_abrelatednames_callback($matches)
- {
- return 'X-' . strtoupper($matches[5]) . $matches[3] . ':'. $matches[4];
- }
-
- private static function rfc2425_fold_callback($matches)
- {
- // chunk_split string and avoid lines breaking multibyte characters
- $c = 71;
- $out .= substr($matches[1], 0, $c);
- for ($n = $c; $c < strlen($matches[1]); $c++) {
- // break if length > 75 or mutlibyte character starts after position 71
- if ($n > 75 || ($n > 71 && ord($matches[1][$c]) >> 6 == 3)) {
- $out .= "\r\n ";
- $n = 0;
- }
- $out .= $matches[1][$c];
- $n++;
- }
-
- return $out;
- }
-
- public static function rfc2425_fold($val)
- {
- return preg_replace_callback('/([^\n]{72,})/', array('self', 'rfc2425_fold_callback'), $val);
- }
-
- /**
- * Decodes a vcard block (vcard 3.0 format, unfolded)
- * into an array structure
- *
- * @param string vCard block to parse
- *
- * @return array Raw data structure
- */
- private static function vcard_decode($vcard)
- {
- // Perform RFC2425 line unfolding and split lines
- $vcard = preg_replace(array("/\r/", "/\n\s+/"), '', $vcard);
- $lines = explode("\n", $vcard);
- $result = array();
-
- for ($i=0; $i < count($lines); $i++) {
- if (!($pos = strpos($lines[$i], ':'))) {
- continue;
- }
-
- $prefix = substr($lines[$i], 0, $pos);
- $data = substr($lines[$i], $pos+1);
-
- if (preg_match('/^(BEGIN|END)$/i', $prefix)) {
- continue;
- }
-
- // convert 2.1-style "EMAIL;internet;home:" to 3.0-style "EMAIL;TYPE=internet;TYPE=home:"
- if ($result['VERSION'][0] == "2.1"
- && preg_match('/^([^;]+);([^:]+)/', $prefix, $regs2)
- && !preg_match('/^TYPE=/i', $regs2[2])
- ) {
- $prefix = $regs2[1];
- foreach (explode(';', $regs2[2]) as $prop) {
- $prefix .= ';' . (strpos($prop, '=') ? $prop : 'TYPE='.$prop);
- }
- }
-
- if (preg_match_all('/([^\\;]+);?/', $prefix, $regs2)) {
- $entry = array();
- $field = strtoupper($regs2[1][0]);
- $enc = null;
-
- foreach($regs2[1] as $attrid => $attr) {
- $attr = preg_replace('/[\s\t\n\r\0\x0B]/', '', $attr);
- if ((list($key, $value) = explode('=', $attr)) && $value) {
- if ($key == 'ENCODING') {
- $value = strtoupper($value);
- // add next line(s) to value string if QP line end detected
- if ($value == 'QUOTED-PRINTABLE') {
- while (preg_match('/=$/', $lines[$i])) {
- $data .= "\n" . $lines[++$i];
- }
- }
- $enc = $value == 'BASE64' ? 'B' : $value;
- }
- else {
- $lc_key = strtolower($key);
- $entry[$lc_key] = array_merge((array)$entry[$lc_key], (array)self::vcard_unquote($value, ','));
- }
- }
- else if ($attrid > 0) {
- $entry[strtolower($key)] = true; // true means attr without =value
- }
- }
-
- // decode value
- if ($enc || !empty($entry['base64'])) {
- // save encoding type (#1488432)
- if ($enc == 'B') {
- $entry['encoding'] = 'B';
- // should we use vCard 3.0 instead?
- // $entry['base64'] = true;
- }
-
- $data = self::decode_value($data, $enc ? $enc : 'base64');
- }
- else if ($field == 'PHOTO') {
- // vCard 4.0 data URI, "PHOTO:data:image/jpeg;base64,..."
- if (preg_match('/^data:[a-z\/_-]+;base64,/i', $data, $m)) {
- $entry['encoding'] = $enc = 'B';
- $data = substr($data, strlen($m[0]));
- $data = self::decode_value($data, 'base64');
- }
- }
-
- if ($enc != 'B' && empty($entry['base64'])) {
- $data = self::vcard_unquote($data);
- }
-
- $entry = array_merge($entry, (array) $data);
- $result[$field][] = $entry;
- }
- }
-
- unset($result['VERSION']);
-
- return $result;
- }
-
- /**
- * Decode a given string with the encoding rule from ENCODING attributes
- *
- * @param string String to decode
- * @param string Encoding type (quoted-printable and base64 supported)
- *
- * @return string Decoded 8bit value
- */
- private static function decode_value($value, $encoding)
- {
- switch (strtolower($encoding)) {
- case 'quoted-printable':
- self::$values_decoded = true;
- return quoted_printable_decode($value);
-
- case 'base64':
- case 'b':
- self::$values_decoded = true;
- return base64_decode($value);
-
- default:
- return $value;
- }
- }
-
- /**
- * Encodes an entry for storage in our database (vcard 3.0 format, unfolded)
- *
- * @param array Raw data structure to encode
- *
- * @return string vCard encoded string
- */
- static function vcard_encode($data)
- {
- foreach ((array)$data as $type => $entries) {
- // valid N has 5 properties
- while ($type == "N" && is_array($entries[0]) && count($entries[0]) < 5) {
- $entries[0][] = "";
- }
-
- // make sure FN is not empty (required by RFC2426)
- if ($type == "FN" && empty($entries)) {
- $entries[0] = $data['EMAIL'][0][0];
- }
-
- foreach ((array)$entries as $entry) {
- $attr = '';
- if (is_array($entry)) {
- $value = array();
- foreach ($entry as $attrname => $attrvalues) {
- if (is_int($attrname)) {
- if (!empty($entry['base64']) || $entry['encoding'] == 'B') {
- $attrvalues = base64_encode($attrvalues);
- }
- $value[] = $attrvalues;
- }
- else if (is_bool($attrvalues)) {
- // true means just a tag, not tag=value, as in PHOTO;BASE64:...
- if ($attrvalues) {
- // vCard v3 uses ENCODING=B (#1489183)
- if ($attrname == 'base64') {
- $attr .= ";ENCODING=B";
- }
- else {
- $attr .= strtoupper(";$attrname");
- }
- }
- }
- else {
- foreach((array)$attrvalues as $attrvalue) {
- $attr .= strtoupper(";$attrname=") . self::vcard_quote($attrvalue, ',');
- }
- }
- }
- }
- else {
- $value = $entry;
- }
-
- // skip empty entries
- if (self::is_empty($value)) {
- continue;
- }
-
- $vcard .= self::vcard_quote($type) . $attr . ':' . self::vcard_quote($value) . self::$eol;
- }
- }
-
- return 'BEGIN:VCARD' . self::$eol . 'VERSION:3.0' . self::$eol . $vcard . 'END:VCARD';
- }
-
- /**
- * Join indexed data array to a vcard quoted string
- *
- * @param array Field data
- * @param string Separator
- *
- * @return string Joined and quoted string
- */
- public static function vcard_quote($s, $sep = ';')
- {
- if (is_array($s)) {
- foreach($s as $part) {
- $r[] = self::vcard_quote($part, $sep);
- }
- return(implode($sep, (array)$r));
- }
-
- return strtr($s, array('\\' => '\\\\', "\r" => '', "\n" => '\n', $sep => '\\'.$sep));
- }
-
- /**
- * Split quoted string
- *
- * @param string vCard string to split
- * @param string Separator char/string
- *
- * @return array List with splited values
- */
- private static function vcard_unquote($s, $sep = ';')
- {
- // break string into parts separated by $sep
- if (!empty($sep)) {
- // Handle properly backslash escaping (#1488896)
- $rep1 = array("\\\\" => "\010", "\\$sep" => "\007");
- $rep2 = array("\007" => "\\$sep", "\010" => "\\\\");
-
- if (count($parts = explode($sep, strtr($s, $rep1))) > 1) {
- foreach ($parts as $s) {
- $result[] = self::vcard_unquote(strtr($s, $rep2));
- }
- return $result;
- }
-
- $s = trim(strtr($s, $rep2));
- }
-
- // some implementations (GMail) use non-standard backslash before colon (#1489085)
- // we will handle properly any backslashed character - removing dummy backslahes
- // return strtr($s, array("\r" => '', '\\\\' => '\\', '\n' => "\n", '\N' => "\n", '\,' => ',', '\;' => ';'));
-
- $s = str_replace("\r", '', $s);
- $pos = 0;
-
- while (($pos = strpos($s, '\\', $pos)) !== false) {
- $next = substr($s, $pos + 1, 1);
- if ($next == 'n' || $next == 'N') {
- $s = substr_replace($s, "\n", $pos, 2);
- }
- else {
- $s = substr_replace($s, '', $pos, 1);
- }
-
- $pos += 1;
- }
-
- return $s;
- }
-
- /**
- * Check if vCard entry is empty: empty string or an array with
- * all entries empty.
- *
- * @param mixed $value Attribute value (string or array)
- *
- * @return bool True if the value is empty, False otherwise
- */
- private static function is_empty($value)
- {
- foreach ((array)$value as $v) {
- if (((string)$v) !== '') {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Extract array values by a filter
- *
- * @param array Array to filter
- * @param keys Array or comma separated list of values to keep
- * @param boolean Invert key selection: remove the listed values
- *
- * @return array The filtered array
- */
- private static function array_filter($arr, $values, $inverse = false)
- {
- if (!is_array($values)) {
- $values = explode(',', $values);
- }
-
- $result = array();
- $keep = array_flip((array)$values);
-
- foreach ($arr as $key => $val) {
- if ($inverse != isset($keep[strtolower($val)])) {
- $result[$key] = $val;
- }
- }
-
- return $result;
- }
-
- /**
- * Returns UNICODE type based on BOM (Byte Order Mark)
- *
- * @param string Input string to test
- *
- * @return string Detected encoding
- */
- private static function detect_encoding($string)
- {
- $fallback = rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); // fallback to Latin-1
-
- return rcube_charset::detect($string, $fallback);
- }
-}
diff --git a/lib/ext/Roundcube/rcube_washtml.php b/lib/ext/Roundcube/rcube_washtml.php
deleted file mode 100644
index 97ab56c..0000000
--- a/lib/ext/Roundcube/rcube_washtml.php
+++ /dev/null
@@ -1,624 +0,0 @@
-<?php
-
-/**
- +-----------------------------------------------------------------------+
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Utility class providing HTML sanityzer (based on Washtml class) |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- | Author: Aleksander Machniak <alec@alec.pl> |
- | Author: Frederic Motte <fmotte@ubixis.com> |
- +-----------------------------------------------------------------------+
- */
-
-/**
- * Washtml, a HTML sanityzer.
- *
- * Copyright (c) 2007 Frederic Motte <fmotte@ubixis.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * OVERVIEW:
- *
- * Wahstml take an untrusted HTML and return a safe html string.
- *
- * SYNOPSIS:
- *
- * $washer = new washtml($config);
- * $washer->wash($html);
- * It return a sanityzed string of the $html parameter without html and head tags.
- * $html is a string containing the html code to wash.
- * $config is an array containing options:
- * $config['allow_remote'] is a boolean to allow link to remote images.
- * $config['blocked_src'] string with image-src to be used for blocked remote images
- * $config['show_washed'] is a boolean to include washed out attributes as x-washed
- * $config['cid_map'] is an array where cid urls index urls to replace them.
- * $config['charset'] is a string containing the charset of the HTML document if it is not defined in it.
- * $washer->extlinks is a reference to a boolean that is set to true if remote images were removed. (FE: show remote images link)
- *
- * INTERNALS:
- *
- * Only tags and attributes in the static lists $html_elements and $html_attributes
- * are kept, inline styles are also filtered: all style identifiers matching
- * /[a-z\-]/i are allowed. Values matching colors, sizes, /[a-z\-]/i and safe
- * urls if allowed and cid urls if mapped are kept.
- *
- * Roundcube Changes:
- * - added $block_elements
- * - changed $ignore_elements behaviour
- * - added RFC2397 support
- * - base URL support
- * - invalid HTML comments removal before parsing
- * - "fixing" unitless CSS values for XHTML output
- * - base url resolving
- */
-
-/**
- * Utility class providing HTML sanityzer
- *
- * @package Framework
- * @subpackage Utils
- */
-class rcube_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',
- 'video', 'source',
- // 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', 'usemap', 'shape', 'media',
- // attributes of form elements
- 'type', 'rows', 'cols', 'disabled', 'readonly', 'checked', 'multiple', 'value'
- );
-
- /* Elements which could be empty and be returned in short form (<tag />) */
- static $void_elements = array('area', 'base', 'br', 'col', 'command', 'embed', 'hr',
- 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'
- );
-
- /* State for linked objects in HTML */
- public $extlinks = false;
-
- /* Current settings */
- private $config = array();
-
- /* Registered callback functions for tags */
- private $handlers = array();
-
- /* Allowed HTML elements */
- private $_html_elements = array();
-
- /* Ignore these HTML tags but process their content */
- private $_ignore_elements = array();
-
- /* Elements which could be empty and be returned in short form (<tag />) */
- private $_void_elements = array();
-
- /* Allowed HTML attributes */
- private $_html_attribs = array();
-
- /* Max nesting level */
- private $max_nesting_level;
-
-
- /**
- * Class constructor
- */
- public function __construct($p = array())
- {
- $this->_html_elements = array_flip((array)$p['html_elements']) + array_flip(self::$html_elements) ;
- $this->_html_attribs = array_flip((array)$p['html_attribs']) + array_flip(self::$html_attribs);
- $this->_ignore_elements = array_flip((array)$p['ignore_elements']) + array_flip(self::$ignore_elements);
- $this->_void_elements = array_flip((array)$p['void_elements']) + array_flip(self::$void_elements);
-
- unset($p['html_elements'], $p['html_attribs'], $p['ignore_elements'], $p['void_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)
- {
- $result = array();
-
- foreach (explode(';', $style) as $declaration) {
- if (preg_match('/^\s*([a-z\-]+)\s*:\s*(.*)\s*$/i', $declaration, $match)) {
- $cssid = $match[1];
- $str = $match[2];
- $value = '';
-
- foreach ($this->explode_style($str) as $val) {
- if (preg_match('/^url\(/i', $val)) {
- if (preg_match('/^url\(\s*[\'"]?([^\'"\)]*)[\'"]?\s*\)/iu', $val, $match)) {
- $url = $match[1];
- if (($src = $this->config['cid_map'][$url])
- || ($src = $this->config['cid_map'][$this->config['base_url'].$url])
- ) {
- $value .= ' url('.htmlspecialchars($src, ENT_QUOTES) . ')';
- }
- else if (preg_match('!^(https?:)?//[a-z0-9/._+-]+$!i', $url, $m)) {
- if ($this->config['allow_remote']) {
- $value .= ' url('.htmlspecialchars($m[0], ENT_QUOTES).')';
- }
- else {
- $this->extlinks = true;
- }
- }
- else if (preg_match('/^data:.+/i', $url)) { // RFC2397
- $value .= ' url('.htmlspecialchars($url, ENT_QUOTES).')';
- }
- }
- }
- else if (!preg_match('/^(behavior|expression)/i', $val)) {
- // whitelist ?
- $value .= ' ' . $val;
-
- // #1488535: Fix size units, so width:800 would be changed to width:800px
- if (preg_match('/^(left|right|top|bottom|width|height)/i', $cssid)
- && preg_match('/^[0-9]+$/', $val)
- ) {
- $value .= 'px';
- }
- }
- }
-
- if (isset($value[0])) {
- $result[] = $cssid . ':' . $value;
- }
- }
- }
-
- return implode('; ', $result);
- }
-
- /**
- * Take a node and return allowed attributes and check values
- */
- private function wash_attribs($node)
- {
- $t = '';
- $washed = '';
-
- foreach ($node->attributes as $key => $plop) {
- $key = strtolower($key);
- $value = $node->getAttribute($key);
-
- if (isset($this->_html_attribs[$key]) ||
- ($key == 'href' && ($value = trim($value))
- && !preg_match('!^(javascript|vbscript|data:text)!i', $value)
- && preg_match('!^([a-z][a-z0-9.+-]+:|//|#).+!i', $value))
- ) {
- $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"';
- }
- else if ($key == 'style' && ($style = $this->wash_style($value))) {
- $quot = strpos($style, '"') !== false ? "'" : '"';
- $t .= ' style=' . $quot . $style . $quot;
- }
- else if ($key == 'background'
- || ($key == 'src' && preg_match('/^(img|source)$/i', $node->tagName))
- || ($key == 'poster' && strtolower($node->tagName) == 'video')
- ) {
- if (($src = $this->config['cid_map'][$value])
- || ($src = $this->config['cid_map'][$this->config['base_url'].$value])
- ) {
- $t .= ' ' . $key . '="' . htmlspecialchars($src, ENT_QUOTES) . '"';
- }
- else if (preg_match('/^(http|https|ftp):.+/i', $value)) {
- if ($this->config['allow_remote']) {
- $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"';
- }
- else {
- $this->extlinks = true;
- if ($this->config['blocked_src']) {
- $t .= ' ' . $key . '="' . htmlspecialchars($this->config['blocked_src'], ENT_QUOTES) . '"';
- }
- }
- }
- else if (preg_match('/^data:.+/i', $value)) { // RFC2397
- $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"';
- }
- }
- else {
- $washed .= ($washed ? ' ' : '') . $key;
- }
- }
-
- return $t . ($washed && $this->config['show_washed'] ? ' x-washed="'.$washed.'"' : '');
- }
-
- /**
- * The main loop that recurse on a node tree.
- * It output only allowed tags with allowed attributes and allowed inline styles
- *
- * @param DOMNode $node HTML element
- * @param int $level Recurrence level (safe initial value found empirically)
- */
- private function dumpHtml($node, $level = 20)
- {
- if (!$node->hasChildNodes()) {
- return '';
- }
-
- $level++;
-
- if ($this->max_nesting_level > 0 && $level == $this->max_nesting_level - 1) {
- // log error message once
- if (!$this->max_nesting_level_error) {
- $this->max_nesting_level_error = true;
- rcube::raise_error(array('code' => 500, 'type' => 'php',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => "Maximum nesting level exceeded (xdebug.max_nesting_level={$this->max_nesting_level})"),
- true, false);
- }
- return '<!-- ignored -->';
- }
-
- $node = $node->firstChild;
- $dump = '';
-
- do {
- switch($node->nodeType) {
- 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, $level), $this);
- }
- else if (isset($this->_html_elements[$tagName])) {
- $content = $this->dumpHtml($node, $level);
- $dump .= '<' . $tagName . $this->wash_attribs($node) .
- ($content === '' && isset($this->_void_elements[$tagName]) ? ' />' : ">$content</$tagName>");
- }
- else if (isset($this->_ignore_elements[$tagName])) {
- $dump .= '<!-- ' . htmlspecialchars($tagName, ENT_QUOTES) . ' not allowed -->';
- }
- else {
- $dump .= '<!-- ' . htmlspecialchars($tagName, ENT_QUOTES) . ' ignored -->';
- $dump .= $this->dumpHtml($node, $level); // ignore tags not its content
- }
- break;
-
- case XML_CDATA_SECTION_NODE:
- $dump .= $node->nodeValue;
- break;
-
- case XML_TEXT_NODE:
- $dump .= htmlspecialchars($node->nodeValue);
- break;
-
- case XML_HTML_DOCUMENT_NODE:
- $dump .= $this->dumpHtml($node, $level);
- break;
-
- case XML_DOCUMENT_TYPE_NODE:
- break;
-
- default:
- $dump .= '<!-- node type ' . $node->nodeType . ' -->';
- }
- } while($node = $node->nextSibling);
-
- return $dump;
- }
-
- /**
- * Main function, give it untrusted HTML, tell it if you allow loading
- * remote images and give it a map to convert "cid:" urls.
- */
- public function wash($html)
- {
- // Charset seems to be ignored (probably if defined in the HTML document)
- $node = new DOMDocument('1.0', $this->config['charset']);
- $this->extlinks = false;
-
- $html = $this->cleanup($html);
-
- // Find base URL for images
- if (preg_match('/<base\s+href=[\'"]*([^\'"]+)/is', $html, $matches)) {
- $this->config['base_url'] = $matches[1];
- }
- else {
- $this->config['base_url'] = '';
- }
-
- // Detect max nesting level (for dumpHTML) (#1489110)
- $this->max_nesting_level = (int) @ini_get('xdebug.max_nesting_level');
-
- // Use optimizations if supported
- if (PHP_VERSION_ID >= 50400) {
- @$node->loadHTML($html, LIBXML_PARSEHUGE | LIBXML_COMPACT);
- }
- else {
- @$node->loadHTML($html);
- }
-
- return $this->dumpHtml($node);
- }
-
- /**
- * Getter for config parameters
- */
- public function get_config($prop)
- {
- return $this->config[$prop];
- }
-
- /**
- * Clean HTML input
- */
- private function cleanup($html)
- {
- // 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
- '/^(\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_replace = array(
- '\\1'.' &nbsp; '.'\\3',
- '',
- '',
- '<html>',
- );
- $html = preg_replace($html_search, $html_replace, trim($html));
-
- //-> Replace all of those weird MS Word quotes and other high characters
- $badwordchars = array(
- "\xe2\x80\x98", // left single quote
- "\xe2\x80\x99", // right single quote
- "\xe2\x80\x9c", // left double quote
- "\xe2\x80\x9d", // right double quote
- "\xe2\x80\x94", // em dash
- "\xe2\x80\xa6" // elipses
- );
- $fixedwordchars = array(
- "'",
- "'",
- '"',
- '"',
- '&mdash;',
- '...'
- );
- $html = str_replace($badwordchars, $fixedwordchars, $html);
-
- // PCRE errors handling (#1486856), should we use something like for every preg_* use?
- if ($html === null && ($preg_error = preg_last_error()) != PREG_NO_ERROR) {
- $errstr = "Could not clean up HTML message! PCRE Error: $preg_error.";
-
- if ($preg_error == PREG_BACKTRACK_LIMIT_ERROR) {
- $errstr .= " Consider raising pcre.backtrack_limit!";
- }
- if ($preg_error == PREG_RECURSION_LIMIT_ERROR) {
- $errstr .= " Consider raising pcre.recursion_limit!";
- }
-
- rcube::raise_error(array('code' => 620, 'type' => 'php',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $errstr), true, false);
-
- return '';
- }
-
- // fix (unknown/malformed) HTML tags before "wash"
- $html = preg_replace_callback('/(<(?!\!)[\/]*)([^\s>]+)([^>]*)/', array($this, 'html_tag_callback'), $html);
-
- // Remove invalid HTML comments (#1487759)
- // Don't remove valid conditional comments
- // Don't remove MSOutlook (<!-->) conditional comments (#1489004)
- $html = preg_replace('/<!--[^-<>\[\n]+>/', '', $html);
-
- // fix broken nested lists
- self::fix_broken_lists($html);
-
- // turn relative into absolute urls
- $html = self::resolve_base($html);
-
- return $html;
- }
-
- /**
- * Callback function for HTML tags fixing
- */
- public static function html_tag_callback($matches)
- {
- $tagname = $matches[2];
- $tagname = preg_replace(array(
- '/:.*$/', // Microsoft's Smart Tags <st1:xxxx>
- '/[^a-z0-9_\[\]\!-]/i', // forbidden characters
- ), '', $tagname);
-
- // fix invalid closing tags - remove any attributes (#1489446)
- if ($matches[1] == '</') {
- $matches[3] = '';
- }
-
- return $matches[1] . $tagname . $matches[3];
- }
-
- /**
- * Convert all relative URLs according to a <base> in HTML
- */
- public static function resolve_base($body)
- {
- // check for <base href=...>
- if (preg_match('!(<base.*href=["\']?)([hftps]{3,5}://[a-z0-9/.%-]+)!i', $body, $regs)) {
- $replacer = new rcube_base_replacer($regs[2]);
- $body = $replacer->replace($body);
- }
-
- return $body;
- }
-
- /**
- * Fix broken nested lists, they are not handled properly by DOMDocument (#1488768)
- */
- public static function fix_broken_lists(&$html)
- {
- // do two rounds, one for <ol>, one for <ul>
- foreach (array('ol', 'ul') as $tag) {
- $pos = 0;
- while (($pos = stripos($html, '<' . $tag, $pos)) !== false) {
- $pos++;
-
- // make sure this is an ol/ul tag
- if (!in_array($html[$pos+2], array(' ', '>'))) {
- continue;
- }
-
- $p = $pos;
- $in_li = false;
- $li_pos = 0;
-
- while (($p = strpos($html, '<', $p)) !== false) {
- $tt = strtolower(substr($html, $p, 4));
-
- // li open tag
- if ($tt == '<li>' || $tt == '<li ') {
- $in_li = true;
- $p += 4;
- }
- // li close tag
- else if ($tt == '</li' && in_array($html[$p+4], array(' ', '>'))) {
- $li_pos = $p;
- $p += 4;
- $in_li = false;
- }
- // ul/ol closing tag
- else if ($tt == '</' . $tag && in_array($html[$p+4], array(' ', '>'))) {
- break;
- }
- // nested ol/ul element out of li
- else if (!$in_li && $li_pos && ($tt == '<ol>' || $tt == '<ol ' || $tt == '<ul>' || $tt == '<ul ')) {
- // find closing tag of this ul/ol element
- $element = substr($tt, 1, 2);
- $cpos = $p;
- do {
- $tpos = stripos($html, '<' . $element, $cpos+1);
- $cpos = stripos($html, '</' . $element, $cpos+1);
- }
- while ($tpos !== false && $cpos !== false && $cpos > $tpos);
-
- // not found, this is invalid HTML, skip it
- if ($cpos === false) {
- break;
- }
-
- // get element content
- $end = strpos($html, '>', $cpos);
- $len = $end - $p + 1;
- $element = substr($html, $p, $len);
-
- // move element to the end of the last li
- $html = substr_replace($html, '', $p, $len);
- $html = substr_replace($html, $element, $li_pos, 0);
-
- $p = $end;
- }
- else {
- $p++;
- }
- }
- }
- }
- }
-
- /**
- * Explode css style value
- */
- protected function explode_style($style)
- {
- $style = trim($style);
-
- // first remove comments
- $pos = 0;
- while (($pos = strpos($style, '/*', $pos)) !== false) {
- $end = strpos($style, '*/', $pos+2);
-
- if ($end === false) {
- $style = substr($style, 0, $pos);
- }
- else {
- $style = substr_replace($style, '', $pos, $end - $pos + 2);
- }
- }
-
- $strlen = strlen($style);
- $result = array();
-
- // explode value
- for ($p=$i=0; $i < $strlen; $i++) {
- if (($style[$i] == "\"" || $style[$i] == "'") && $style[$i-1] != "\\") {
- if ($q == $style[$i]) {
- $q = false;
- }
- else if (!$q) {
- $q = $style[$i];
- }
- }
-
- if (!$q && $style[$i] == ' ' && !preg_match('/[,\(]/', $style[$i-1])) {
- $result[] = substr($style, $p, $i - $p);
- $p = $i + 1;
- }
- }
-
- $result[] = (string) substr($style, $p);
-
- return $result;
- }
-}
diff --git a/lib/plugins/kolab_auth/LICENSE b/lib/plugins/kolab_auth/LICENSE
deleted file mode 100644
index dba13ed..0000000
--- a/lib/plugins/kolab_auth/LICENSE
+++ /dev/null
@@ -1,661 +0,0 @@
- GNU AFFERO GENERAL PUBLIC LICENSE
- Version 3, 19 November 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU Affero General Public License is a free, copyleft license for
-software and other kinds of works, specifically designed to ensure
-cooperation with the community in the case of network server software.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-our General Public Licenses are intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- Developers that use our General Public Licenses protect your rights
-with two steps: (1) assert copyright on the software, and (2) offer
-you this License which gives you legal permission to copy, distribute
-and/or modify the software.
-
- A secondary benefit of defending all users' freedom is that
-improvements made in alternate versions of the program, if they
-receive widespread use, become available for other developers to
-incorporate. Many developers of free software are heartened and
-encouraged by the resulting cooperation. However, in the case of
-software used on network servers, this result may fail to come about.
-The GNU General Public License permits making a modified version and
-letting the public access it on a server without ever releasing its
-source code to the public.
-
- The GNU Affero General Public License is designed specifically to
-ensure that, in such cases, the modified source code becomes available
-to the community. It requires the operator of a network server to
-provide the source code of the modified version running there to the
-users of that server. Therefore, public use of a modified version, on
-a publicly accessible server, gives the public access to the source
-code of the modified version.
-
- An older license, called the Affero General Public License and
-published by Affero, was designed to accomplish similar goals. This is
-a different license, not a version of the Affero GPL, but Affero has
-released a new version of the Affero GPL which permits relicensing under
-this license.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU Affero General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Remote Network Interaction; Use with the GNU General Public License.
-
- Notwithstanding any other provision of this License, if you modify the
-Program, your modified version must prominently offer all users
-interacting with it remotely through a computer network (if your version
-supports such interaction) an opportunity to receive the Corresponding
-Source of your version by providing access to the Corresponding Source
-from a network server at no charge, through some standard or customary
-means of facilitating copying of software. This Corresponding Source
-shall include the Corresponding Source for any work covered by version 3
-of the GNU General Public License that is incorporated pursuant to the
-following paragraph.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the work with which it is combined will remain governed by version
-3 of the GNU General Public License.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU Affero General Public License from time to time. Such new versions
-will be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU Affero General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU Affero General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU Affero General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- 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 Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If your software can interact with users remotely through a computer
-network, you should also make sure that it provides a way for users to
-get its source. For example, if your program is a web application, its
-interface could display a "Source" link that leads users to an archive
-of the code. There are many ways you could offer source, and different
-solutions will be better for different programs; see section 13 for the
-specific requirements.
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU AGPL, see
-<http://www.gnu.org/licenses/>.
diff --git a/lib/plugins/kolab_auth/composer.json b/lib/plugins/kolab_auth/composer.json
deleted file mode 100644
index 3e7012f..0000000
--- a/lib/plugins/kolab_auth/composer.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "name": "kolab/kolab_auth",
- "type": "roundcube-plugin",
- "description": "Kolab authentication",
- "homepage": "http://git.kolab.org/roundcubemail-plugins-kolab/",
- "license": "AGPLv3",
- "version": "3.2.2",
- "authors": [
- {
- "name": "Thomas Bruederli",
- "email": "bruederli@kolabsys.com",
- "role": "Lead"
- },
- {
- "name": "Aleksander Machniak",
- "email": "machniak@kolabsys.com",
- "role": "Lead"
- }
- ],
- "repositories": [
- {
- "type": "composer",
- "url": "http://plugins.roundcube.net"
- }
- ],
- "require": {
- "php": ">=5.3.0",
- "roundcube/plugin-installer": ">=0.1.3"
- }
-}
diff --git a/lib/plugins/kolab_auth/config.inc.php.dist b/lib/plugins/kolab_auth/config.inc.php.dist
deleted file mode 100644
index 8c01d56..0000000
--- a/lib/plugins/kolab_auth/config.inc.php.dist
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-
-// The id of the LDAP address book (which refers to the $rcmail_config['ldap_public'])
-// or complete addressbook definition array.
-// --------------------------------------------------------------------
-// Note: Multi-domain (hosted) installations can resolve domain aliases
-// by adding following settings in kolab_auth_addressbook spec.:
-//
-// 'domain_base_dn' => 'cn=kolab,cn=config',
-// 'domain_filter' => '(&(objectclass=domainrelatedobject)(associateddomain=%s))',
-// 'domain_name_attr' => 'associateddomain',
-//
-// With this %dc variable in base_dn and groups/base_dn will be
-// replaced with DN string of resolved domain
-//---------------------------------------------------------------------
-$config['kolab_auth_addressbook'] = '';
-
-// This will overwrite defined filter
-$config['kolab_auth_filter'] = '(&(objectClass=kolabInetOrgPerson)(|(uid=%u)(mail=%fu)(alias=%fu)))';
-
-// Use this field (from fieldmap configuration) to get authentication ID. Don't use an array here!
-$config['kolab_auth_login'] = 'email';
-
-// Use these fields (from fieldmap configuration) for default identity.
-// If the value array contains more than one field, first non-empty will be used
-// Note: These aren't LDAP attributes, but field names in config
-// Note: If there's more than one email address, as many identities will be created
-$config['kolab_auth_name'] = array('name', 'cn');
-$config['kolab_auth_email'] = array('email');
-$config['kolab_auth_organization'] = array('organization');
-
-// Role field (from fieldmap configuration)
-$config['kolab_auth_role'] = 'role';
-
-// Template for user names displayed in the UI.
-// You can use all attributes from the 'fieldmap' property of the 'kolab_auth_addressbook' configuration
-$config['kolab_auth_user_displayname'] = '{name} ({ou})';
-
-// Login and password of the admin user. Enables "Login As" feature.
-$config['kolab_auth_admin_login'] = '';
-$config['kolab_auth_admin_password'] = '';
-
-// Enable audit logging for abuse of administrative privileges.
-$config['kolab_auth_auditlog'] = false;
-
-// As set of rules to define the required rights on the target entry
-// which allow an admin user to login as another user (the target).
-// The effective rights value refers to either entry level attribute level rights:
-// * entry:[read|add|delete]
-// * attrib:<attribute-name>:[read|write|delete]
-$config['kolab_auth_admin_rights'] = array(
- // Roundcube task => required effective right
- 'settings' => 'entry:read',
- 'mail' => 'entry:delete',
- 'addressbook' => 'entry:delete',
- // or use a wildcard entry like this:
- '*' => 'entry:read',
-);
-
-// Enable plugins on a role-by-role basis. In this example, the 'acl' plugin
-// is enabled for people with a 'cn=professional-user,dc=mykolab,dc=ch' role.
-//
-// Note that this does NOT mean the 'acl' plugin is disabled for other people.
-$config['kolab_auth_role_plugins'] = Array(
- 'cn=professional-user,dc=mykolab,dc=ch' => Array(
- 'acl',
- ),
- );
-
-// Settings on a role-by-role basis. In this example, the 'htmleditor' setting
-// is enabled(1) for people with a 'cn=professional-user,dc=mykolab,dc=ch' role,
-// and it cannot be overridden. Sample use-case: disable htmleditor for normal people,
-// do not allow the setting to be controlled through the preferences, enable the
-// html editor for professional users and allow them to override the setting in
-// the preferences.
-$config['kolab_auth_role_settings'] = Array(
- 'cn=professional-user,dc=mykolab,dc=ch' => Array(
- 'htmleditor' => Array(
- 'mode' => 'override',
- 'value' => 1,
- 'allow_override' => true
- ),
- ),
- );
-
-// List of LDAP addressbooks (keys of ldap_public configuration array)
-// for which base_dn variables (%dc, etc.) will be replaced according to authenticated user DN
-// Note: special name '*' for all LDAP addressbooks
-$config['kolab_auth_ldap_addressbooks'] = array('*');
-
-?>
diff --git a/lib/plugins/kolab_auth/kolab_auth.php b/lib/plugins/kolab_auth/kolab_auth.php
deleted file mode 100644
index 70051b6..0000000
--- a/lib/plugins/kolab_auth/kolab_auth.php
+++ /dev/null
@@ -1,799 +0,0 @@
-<?php
-
-/**
- * Kolab Authentication (based on ldap_authentication plugin)
- *
- * Authenticates on LDAP server, finds canonized authentication ID for IMAP
- * and for new users creates identity based on LDAP information.
- *
- * Supports impersonate feature (login as another user). To use this feature
- * imap_auth_type/smtp_auth_type must be set to DIGEST-MD5 or PLAIN.
- *
- * @version @package_version@
- * @author Aleksander Machniak <machniak@kolabsys.com>
- *
- * Copyright (C) 2011-2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_auth extends rcube_plugin
-{
- static $ldap;
- private $username;
- private $data = array();
-
- public function init()
- {
- $rcmail = rcube::get_instance();
-
- $this->load_config();
-
- $this->add_hook('authenticate', array($this, 'authenticate'));
- $this->add_hook('startup', array($this, 'startup'));
- $this->add_hook('user_create', array($this, 'user_create'));
-
- // Hook for password change
- $this->add_hook('password_ldap_bind', array($this, 'password_ldap_bind'));
-
- // Hooks related to "Login As" feature
- $this->add_hook('template_object_loginform', array($this, 'login_form'));
- $this->add_hook('storage_connect', array($this, 'imap_connect'));
- $this->add_hook('managesieve_connect', array($this, 'imap_connect'));
- $this->add_hook('smtp_connect', array($this, 'smtp_connect'));
- $this->add_hook('identity_form', array($this, 'identity_form'));
-
- // Hook to modify some configuration, e.g. ldap
- $this->add_hook('config_get', array($this, 'config_get'));
-
- // Hook to modify logging directory
- $this->add_hook('write_log', array($this, 'write_log'));
- $this->username = $_SESSION['username'];
-
- // Enable debug logs (per-user), when logged as another user
- if (!empty($_SESSION['kolab_auth_admin']) && $rcmail->config->get('kolab_auth_auditlog')) {
- $rcmail->config->set('debug_level', 1);
- $rcmail->config->set('devel_mode', true);
- $rcmail->config->set('smtp_log', true);
- $rcmail->config->set('log_logins', true);
- $rcmail->config->set('log_session', true);
- $rcmail->config->set('memcache_debug', true);
- $rcmail->config->set('imap_debug', true);
- $rcmail->config->set('ldap_debug', true);
- $rcmail->config->set('smtp_debug', true);
- $rcmail->config->set('sql_debug', true);
-
- // SQL debug need to be set directly on DB object
- // setting config variable will not work here because
- // the object is already initialized/configured
- if ($db = $rcmail->get_dbh()) {
- $db->set_debug(true);
- }
- }
- }
-
- /**
- * Startup hook handler
- */
- public function startup($args)
- {
- // Check access rights when logged in as another user
- if (!empty($_SESSION['kolab_auth_admin']) && $args['task'] != 'login' && $args['task'] != 'logout') {
- // access to specified task is forbidden,
- // redirect to the first task on the list
- if (!empty($_SESSION['kolab_auth_allowed_tasks'])) {
- $tasks = (array)$_SESSION['kolab_auth_allowed_tasks'];
- if (!in_array($args['task'], $tasks) && !in_array('*', $tasks)) {
- header('Location: ?_task=' . array_shift($tasks));
- die;
- }
-
- // add script that will remove disabled taskbar buttons
- if (!in_array('*', $tasks)) {
- $this->add_hook('render_page', array($this, 'render_page'));
- }
- }
- }
-
- // load per-user settings
- $this->load_user_role_plugins_and_settings();
-
- return $args;
- }
-
- /**
- * Modify some configuration according to LDAP user record
- */
- public function config_get($args)
- {
- // Replaces ldap_vars (%dc, etc) in public kolab ldap addressbooks
- // config based on the users base_dn. (for multi domain support)
- if ($args['name'] == 'ldap_public' && !empty($args['result'])) {
- $rcmail = rcube::get_instance();
- $kolab_books = (array) $rcmail->config->get('kolab_auth_ldap_addressbooks');
-
- foreach ($args['result'] as $name => $config) {
- if (in_array($name, $kolab_books) || in_array('*', $kolab_books)) {
- $args['result'][$name] = $this->patch_ldap_config($config);
- }
- }
- }
- else if ($args['name'] == 'kolab_users_directory' && !empty($args['result'])) {
- $args['result'] = $this->patch_ldap_config($args['result']);
- }
-
- return $args;
- }
-
- /**
- * Helper method to patch the given LDAP directory config with user-specific values
- */
- protected function patch_ldap_config($config)
- {
- if (is_array($config)) {
- $config['base_dn'] = self::parse_ldap_vars($config['base_dn']);
- $config['search_base_dn'] = self::parse_ldap_vars($config['search_base_dn']);
- $config['bind_dn'] = str_replace('%dn', $_SESSION['kolab_dn'], $config['bind_dn']);
-
- if (!empty($config['groups'])) {
- $config['groups']['base_dn'] = self::parse_ldap_vars($config['groups']['base_dn']);
- }
- }
-
- return $config;
- }
-
- /**
- * Modifies list of plugins and settings according to
- * specified LDAP roles
- */
- public function load_user_role_plugins_and_settings()
- {
- if (empty($_SESSION['user_roledns'])) {
- return;
- }
-
- $rcmail = rcube::get_instance();
-
- // Example 'kolab_auth_role_plugins' =
- //
- // Array(
- // '<role_dn>' => Array('plugin1', 'plugin2'),
- // );
- //
- // NOTE that <role_dn> may in fact be something like: 'cn=role,%dc'
-
- $role_plugins = $rcmail->config->get('kolab_auth_role_plugins');
-
- // Example $rcmail_config['kolab_auth_role_settings'] =
- //
- // Array(
- // '<role_dn>' => Array(
- // '$setting' => Array(
- // 'mode' => '(override|merge)', (default: override)
- // 'value' => <>,
- // 'allow_override' => (true|false) (default: false)
- // ),
- // ),
- // );
- //
- // NOTE that <role_dn> may in fact be something like: 'cn=role,%dc'
-
- $role_settings = $rcmail->config->get('kolab_auth_role_settings');
-
- if (!empty($role_plugins)) {
- foreach ($role_plugins as $role_dn => $plugins) {
- $role_dn = self::parse_ldap_vars($role_dn);
- if (!empty($role_plugins[$role_dn])) {
- $role_plugins[$role_dn] = array_unique(array_merge((array)$role_plugins[$role_dn], $plugins));
- } else {
- $role_plugins[$role_dn] = $plugins;
- }
- }
- }
-
- if (!empty($role_settings)) {
- foreach ($role_settings as $role_dn => $settings) {
- $role_dn = self::parse_ldap_vars($role_dn);
- if (!empty($role_settings[$role_dn])) {
- $role_settings[$role_dn] = array_merge((array)$role_settings[$role_dn], $settings);
- } else {
- $role_settings[$role_dn] = $settings;
- }
- }
- }
-
- foreach ($_SESSION['user_roledns'] as $role_dn) {
- if (!empty($role_settings[$role_dn]) && is_array($role_settings[$role_dn])) {
- foreach ($role_settings[$role_dn] as $setting_name => $setting) {
- if (!isset($setting['mode'])) {
- $setting['mode'] = 'override';
- }
-
- if ($setting['mode'] == "override") {
- $rcmail->config->set($setting_name, $setting['value']);
- } elseif ($setting['mode'] == "merge") {
- $orig_setting = $rcmail->config->get($setting_name);
-
- if (!empty($orig_setting)) {
- if (is_array($orig_setting)) {
- $rcmail->config->set($setting_name, array_merge($orig_setting, $setting['value']));
- }
- } else {
- $rcmail->config->set($setting_name, $setting['value']);
- }
- }
-
- $dont_override = (array) $rcmail->config->get('dont_override');
-
- if (empty($setting['allow_override'])) {
- $rcmail->config->set('dont_override', array_merge($dont_override, array($setting_name)));
- }
- else {
- if (in_array($setting_name, $dont_override)) {
- $_dont_override = array();
- foreach ($dont_override as $_setting) {
- if ($_setting != $setting_name) {
- $_dont_override[] = $_setting;
- }
- }
- $rcmail->config->set('dont_override', $_dont_override);
- }
- }
-
- if ($setting_name == 'skin') {
- if ($rcmail->output->type == 'html') {
- $rcmail->output->set_skin($setting['value']);
- $rcmail->output->set_env('skin', $setting['value']);
- }
- }
- }
- }
-
- if (!empty($role_plugins[$role_dn])) {
- foreach ((array)$role_plugins[$role_dn] as $plugin) {
- $this->api->load_plugin($plugin);
- }
- }
- }
- }
-
- /**
- * Logging method replacement to print debug/errors into
- * a separate (sub)folder for each user
- */
- public function write_log($args)
- {
- $rcmail = rcube::get_instance();
-
- if ($rcmail->config->get('log_driver') == 'syslog') {
- return $args;
- }
-
- // log_driver == 'file' is assumed here
- $log_dir = $rcmail->config->get('log_dir', RCUBE_INSTALL_PATH . 'logs');
-
- // Append original username + target username for audit-logging
- if ($rcmail->config->get('kolab_auth_auditlog') && !empty($_SESSION['kolab_auth_admin'])) {
- $args['dir'] = $log_dir . '/' . strtolower($_SESSION['kolab_auth_admin']) . '/' . strtolower($this->username);
-
- // Attempt to create the directory
- if (!is_dir($args['dir'])) {
- @mkdir($args['dir'], 0750, true);
- }
- }
- // Define the user log directory if a username is provided
- else if ($rcmail->config->get('per_user_logging') && !empty($this->username)) {
- $user_log_dir = $log_dir . '/' . strtolower($this->username);
- if (is_writable($user_log_dir)) {
- $args['dir'] = $user_log_dir;
- }
- else if ($args['name'] != 'errors') {
- $args['abort'] = true; // don't log if unauthenticed
- }
- }
-
- return $args;
- }
-
- /**
- * Sets defaults for new user.
- */
- public function user_create($args)
- {
- if (!empty($this->data['user_email'])) {
- // addresses list is supported
- if (array_key_exists('email_list', $args)) {
- $email_list = array_unique($this->data['user_email']);
-
- // add organization to the list
- if (!empty($this->data['user_organization'])) {
- foreach ($email_list as $idx => $email) {
- $email_list[$idx] = array(
- 'organization' => $this->data['user_organization'],
- 'email' => $email,
- );
- }
- }
-
- $args['email_list'] = $email_list;
- }
- else {
- $args['user_email'] = $this->data['user_email'][0];
- }
- }
-
- if (!empty($this->data['user_name'])) {
- $args['user_name'] = $this->data['user_name'];
- }
-
- return $args;
- }
-
- /**
- * Modifies login form adding additional "Login As" field
- */
- public function login_form($args)
- {
- $this->add_texts('localization/');
-
- $rcmail = rcube::get_instance();
- $admin_login = $rcmail->config->get('kolab_auth_admin_login');
- $group = $rcmail->config->get('kolab_auth_group');
- $role_attr = $rcmail->config->get('kolab_auth_role');
-
- // Show "Login As" input
- if (empty($admin_login) || (empty($group) && empty($role_attr))) {
- return $args;
- }
-
- $input = new html_inputfield(array('name' => '_loginas', 'id' => 'rcmloginas',
- 'type' => 'text', 'autocomplete' => 'off'));
- $row = html::tag('tr', null,
- html::tag('td', 'title', html::label('rcmloginas', Q($this->gettext('loginas'))))
- . html::tag('td', 'input', $input->show(trim(rcube_utils::get_input_value('_loginas', rcube_utils::INPUT_POST))))
- );
- $args['content'] = preg_replace('/<\/tbody>/i', $row . '</tbody>', $args['content']);
-
- return $args;
- }
-
- /**
- * Find user credentials In LDAP.
- */
- public function authenticate($args)
- {
- // get username and host
- $host = $args['host'];
- $user = $args['user'];
- $pass = $args['pass'];
- $loginas = trim(rcube_utils::get_input_value('_loginas', rcube_utils::INPUT_POST));
-
- if (empty($user) || empty($pass)) {
- $args['abort'] = true;
- return $args;
- }
-
- // temporarily set the current username to the one submitted
- $this->username = $user;
-
- $ldap = self::ldap();
- if (!$ldap || !$ldap->ready) {
- $args['abort'] = true;
- $args['kolab_ldap_error'] = true;
- $message = sprintf(
- 'Login failure for user %s from %s in session %s (error %s)',
- $user,
- rcube_utils::remote_ip(),
- session_id(),
- "LDAP not ready"
- );
-
- rcube::write_log('userlogins', $message);
-
- return $args;
- }
-
- // Find user record in LDAP
- $record = $ldap->get_user_record($user, $host);
-
- if (empty($record)) {
- $args['abort'] = true;
- $message = sprintf(
- 'Login failure for user %s from %s in session %s (error %s)',
- $user,
- rcube_utils::remote_ip(),
- session_id(),
- "No user record found"
- );
-
- rcube::write_log('userlogins', $message);
-
- return $args;
- }
-
- $rcmail = rcube::get_instance();
- $admin_login = $rcmail->config->get('kolab_auth_admin_login');
- $admin_pass = $rcmail->config->get('kolab_auth_admin_password');
- $login_attr = $rcmail->config->get('kolab_auth_login');
- $name_attr = $rcmail->config->get('kolab_auth_name');
- $email_attr = $rcmail->config->get('kolab_auth_email');
- $org_attr = $rcmail->config->get('kolab_auth_organization');
- $role_attr = $rcmail->config->get('kolab_auth_role');
- $imap_attr = $rcmail->config->get('kolab_auth_mailhost');
-
- if (!empty($role_attr) && !empty($record[$role_attr])) {
- $_SESSION['user_roledns'] = (array)($record[$role_attr]);
- }
-
- if (!empty($imap_attr) && !empty($record[$imap_attr])) {
- $default_host = $rcmail->config->get('default_host');
- if (!empty($default_host)) {
- rcube::write_log("errors", "Both default host and kolab_auth_mailhost set. Incompatible.");
- } else {
- $args['host'] = "tls://" . $record[$imap_attr];
- }
- }
-
- // Login As...
- if (!empty($loginas) && $admin_login) {
- // Authenticate to LDAP
- $result = $ldap->bind($record['dn'], $pass);
-
- if (!$result) {
- $args['abort'] = true;
- $message = sprintf(
- 'Login failure for user %s from %s in session %s (error %s)',
- $user,
- rcube_utils::remote_ip(),
- session_id(),
- "Unable to bind with '" . $record['dn'] . "'"
- );
-
- rcube::write_log('userlogins', $message);
-
- return $args;
- }
-
- $isadmin = false;
- $admin_rights = $rcmail->config->get('kolab_auth_admin_rights', array());
-
- // @deprecated: fall-back to the old check if the original user has/belongs to administrative role/group
- if (empty($admin_rights)) {
- $group = $rcmail->config->get('kolab_auth_group');
- $role_dn = $rcmail->config->get('kolab_auth_role_value');
-
- // check role attribute
- if (!empty($role_attr) && !empty($role_dn) && !empty($record[$role_attr])) {
- $role_dn = $ldap->parse_vars($role_dn, $user, $host);
- if (in_array($role_dn, (array)$record[$role_attr])) {
- $isadmin = true;
- }
- }
-
- // check group
- if (!$isadmin && !empty($group)) {
- $groups = $ldap->get_user_groups($record['dn'], $user, $host);
- if (in_array($group, $groups)) {
- $isadmin = true;
- }
- }
-
- if ($isadmin) {
- // user has admin privileges privilage, get "login as" user credentials
- $target_entry = $ldap->get_user_record($loginas, $host);
- $allowed_tasks = $rcmail->config->get('kolab_auth_allowed_tasks');
- }
- }
- else {
- // get "login as" user credentials
- $target_entry = $ldap->get_user_record($loginas, $host);
-
- if (!empty($target_entry)) {
- // get effective rights to determine login-as permissions
- $effective_rights = (array)$ldap->effective_rights($target_entry['dn']);
-
- if (!empty($effective_rights)) {
- $effective_rights['attrib'] = $effective_rights['attributeLevelRights'];
- $effective_rights['entry'] = $effective_rights['entryLevelRights'];
-
- // compare the rights with the permissions mapping
- $allowed_tasks = array();
- foreach ($admin_rights as $task => $perms) {
- $perms_ = explode(':', $perms);
- $type = array_shift($perms_);
- $req = array_pop($perms_);
- $attrib = array_pop($perms_);
-
- if (array_key_exists($type, $effective_rights)) {
- if ($type == 'entry' && in_array($req, $effective_rights[$type])) {
- $allowed_tasks[] = $task;
- }
- else if ($type == 'attrib' && array_key_exists($attrib, $effective_rights[$type]) &&
- in_array($req, $effective_rights[$type][$attrib])) {
- $allowed_tasks[] = $task;
- }
- }
- }
-
- $isadmin = !empty($allowed_tasks);
- }
- }
- }
-
- // Save original user login for log (see below)
- if ($login_attr) {
- $origname = is_array($record[$login_attr]) ? $record[$login_attr][0] : $record[$login_attr];
- }
- else {
- $origname = $user;
- }
-
- if (!$isadmin || empty($target_entry)) {
- $this->add_texts('localization/');
-
- $args['abort'] = true;
- $args['error'] = $this->gettext(array(
- 'name' => 'loginasnotallowed',
- 'vars' => array('user' => Q($loginas)),
- ));
-
- $message = sprintf(
- 'Login failure for user %s (as user %s) from %s in session %s (error %s)',
- $user,
- $loginas,
- rcube_utils::remote_ip(),
- session_id(),
- "No privileges to login as '" . $loginas . "'"
- );
-
- rcube::write_log('userlogins', $message);
-
- return $args;
- }
-
- // replace $record with target entry
- $record = $target_entry;
-
- $args['user'] = $this->username = $loginas;
-
- // Mark session to use SASL proxy for IMAP authentication
- $_SESSION['kolab_auth_admin'] = strtolower($origname);
- $_SESSION['kolab_auth_login'] = $rcmail->encrypt($admin_login);
- $_SESSION['kolab_auth_password'] = $rcmail->encrypt($admin_pass);
- $_SESSION['kolab_auth_allowed_tasks'] = $allowed_tasks;
- }
-
- // Store UID and DN of logged user in session for use by other plugins
- $_SESSION['kolab_uid'] = is_array($record['uid']) ? $record['uid'][0] : $record['uid'];
- $_SESSION['kolab_dn'] = $record['dn'];
-
- // Store LDAP replacement variables used for current user
- // This improves performance of load_user_role_plugins_and_settings()
- // which is executed on every request (via startup hook) and where
- // we don't like to use LDAP (connection + bind + search)
- $_SESSION['kolab_auth_vars'] = $ldap->get_parse_vars();
-
- // Set user login
- if ($login_attr) {
- $this->data['user_login'] = is_array($record[$login_attr]) ? $record[$login_attr][0] : $record[$login_attr];
- }
- if ($this->data['user_login']) {
- $args['user'] = $this->username = $this->data['user_login'];
- }
-
- // User name for identity (first log in)
- foreach ((array)$name_attr as $field) {
- $name = is_array($record[$field]) ? $record[$field][0] : $record[$field];
- if (!empty($name)) {
- $this->data['user_name'] = $name;
- break;
- }
- }
- // User email(s) for identity (first log in)
- foreach ((array)$email_attr as $field) {
- $email = is_array($record[$field]) ? array_filter($record[$field]) : $record[$field];
- if (!empty($email)) {
- $this->data['user_email'] = array_merge((array)$this->data['user_email'], (array)$email);
- }
- }
- // Organization name for identity (first log in)
- foreach ((array)$org_attr as $field) {
- $organization = is_array($record[$field]) ? $record[$field][0] : $record[$field];
- if (!empty($organization)) {
- $this->data['user_organization'] = $organization;
- break;
- }
- }
-
- // Log "Login As" usage
- if (!empty($origname)) {
- rcube::write_log('userlogins', sprintf('Admin login for %s by %s from %s',
- $args['user'], $origname, rcube_utils::remote_ip()));
- }
-
- // load per-user settings/plugins
- $this->load_user_role_plugins_and_settings();
-
- return $args;
- }
-
- /**
- * Set user DN for password change (password plugin with ldap_simple driver)
- */
- public function password_ldap_bind($args)
- {
- $args['user_dn'] = $_SESSION['kolab_dn'];
-
- $rcmail = rcube::get_instance();
-
- $rcmail->config->set('password_ldap_method', 'user');
-
- return $args;
- }
-
- /**
- * Sets SASL Proxy login/password for IMAP and Managesieve auth
- */
- public function imap_connect($args)
- {
- if (!empty($_SESSION['kolab_auth_admin'])) {
- $rcmail = rcube::get_instance();
- $admin_login = $rcmail->decrypt($_SESSION['kolab_auth_login']);
- $admin_pass = $rcmail->decrypt($_SESSION['kolab_auth_password']);
-
- $args['auth_cid'] = $admin_login;
- $args['auth_pw'] = $admin_pass;
- }
-
- return $args;
- }
-
- /**
- * Sets SASL Proxy login/password for SMTP auth
- */
- public function smtp_connect($args)
- {
- if (!empty($_SESSION['kolab_auth_admin'])) {
- $rcmail = rcube::get_instance();
- $admin_login = $rcmail->decrypt($_SESSION['kolab_auth_login']);
- $admin_pass = $rcmail->decrypt($_SESSION['kolab_auth_password']);
-
- $args['smtp_auth_cid'] = $admin_login;
- $args['smtp_auth_pw'] = $admin_pass;
- }
-
- return $args;
- }
-
- /**
- * Hook to replace the plain text input field for email address by a drop-down list
- * with all email addresses (including aliases) from this user's LDAP record.
- */
- public function identity_form($args)
- {
- $rcmail = rcube::get_instance();
- $ident_level = intval($rcmail->config->get('identities_level', 0));
-
- // do nothing if email address modification is disabled
- if ($ident_level == 1 || $ident_level == 3) {
- return $args;
- }
-
- $ldap = self::ldap();
- if (!$ldap || !$ldap->ready || empty($_SESSION['kolab_dn'])) {
- return $args;
- }
-
- $emails = array();
- $user_record = $ldap->get_record($_SESSION['kolab_dn']);
-
- foreach ((array)$rcmail->config->get('kolab_auth_email', array()) as $col) {
- $values = rcube_addressbook::get_col_values($col, $user_record, true);
- if (!empty($values))
- $emails = array_merge($emails, array_filter($values));
- }
-
- // kolab_delegation might want to modify this addresses list
- $plugin = $rcmail->plugins->exec_hook('kolab_auth_emails', array('emails' => $emails));
- $emails = $plugin['emails'];
-
- if (!empty($emails)) {
- $args['form']['addressing']['content']['email'] = array(
- 'type' => 'select',
- 'options' => array_combine($emails, $emails),
- );
- }
-
- return $args;
- }
-
- /**
- * Action executed before the page is rendered to add an onload script
- * that will remove all taskbar buttons for disabled tasks
- */
- public function render_page($args)
- {
- $rcmail = rcube::get_instance();
- $tasks = (array)$_SESSION['kolab_auth_allowed_tasks'];
- $tasks[] = 'logout';
-
- // disable buttons in taskbar
- $script = "
- \$('a').filter(function() {
- var ev = \$(this).attr('onclick');
- return ev && ev.match(/'switch-task','([a-z]+)'/)
- && \$.inArray(RegExp.\$1, " . json_encode($tasks) . ") < 0;
- }).remove();
- ";
-
- $rcmail->output->add_script($script, 'docready');
- }
-
- /**
- * Initializes LDAP object and connects to LDAP server
- */
- public static function ldap()
- {
- if (self::$ldap) {
- return self::$ldap;
- }
-
- $rcmail = rcube::get_instance();
- $addressbook = $rcmail->config->get('kolab_auth_addressbook');
-
- if (!is_array($addressbook)) {
- $ldap_config = (array)$rcmail->config->get('ldap_public');
- $addressbook = $ldap_config[$addressbook];
- }
-
- if (empty($addressbook)) {
- return null;
- }
-
- require_once __DIR__ . '/kolab_auth_ldap.php';
-
- self::$ldap = new kolab_auth_ldap($addressbook);
-
- return self::$ldap;
- }
-
- /**
- * Close LDAP connection
- */
- public static function ldap_close()
- {
- if (self::$ldap) {
- self::$ldap->close();
- self::$ldap = null;
- }
- }
-
- /**
- * Parses LDAP DN string with replacing supported variables.
- * See kolab_auth_ldap::parse_vars()
- *
- * @param string $str LDAP DN string
- *
- * @return string Parsed DN string
- */
- public static function parse_ldap_vars($str)
- {
- if (!empty($_SESSION['kolab_auth_vars'])) {
- $str = strtr($str, $_SESSION['kolab_auth_vars']);
- }
-
- return $str;
- }
-}
diff --git a/lib/plugins/kolab_auth/kolab_auth_ldap.php b/lib/plugins/kolab_auth/kolab_auth_ldap.php
deleted file mode 100644
index 431133b..0000000
--- a/lib/plugins/kolab_auth/kolab_auth_ldap.php
+++ /dev/null
@@ -1,548 +0,0 @@
-<?php
-
-/**
- * Kolab Authentication
- *
- * @version @package_version@
- * @author Aleksander Machniak <machniak@kolabsys.com>
- *
- * Copyright (C) 2011-2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * Wrapper class for rcube_ldap_generic
- */
-class kolab_auth_ldap extends rcube_ldap_generic
-{
- private $icache = array();
- private $conf = array();
- private $fieldmap = array();
-
-
- function __construct($p)
- {
- $rcmail = rcube::get_instance();
-
- $this->conf = $p;
- $this->conf['kolab_auth_user_displayname'] = $rcmail->config->get('kolab_auth_user_displayname', '{name}');
-
- $this->fieldmap = $p['fieldmap'];
- $this->fieldmap['uid'] = 'uid';
-
- $p['attributes'] = array_values($this->fieldmap);
- $p['debug'] = (bool) $rcmail->config->get('ldap_debug');
-
- // Connect to the server (with bind)
- parent::__construct($p);
- $this->_connect();
-
- $rcmail->add_shutdown_function(array($this, 'close'));
- }
-
- /**
- * Establish a connection to the LDAP server
- */
- private function _connect()
- {
- // try to connect + bind for every host configured
- // with OpenLDAP 2.x ldap_connect() always succeeds but ldap_bind will fail if host isn't reachable
- // see http://www.php.net/manual/en/function.ldap-connect.php
- foreach ((array)$this->config['hosts'] as $host) {
- // skip host if connection failed
- if (!$this->connect($host)) {
- continue;
- }
-
- $bind_pass = $this->config['bind_pass'];
- $bind_user = $this->config['bind_user'];
- $bind_dn = $this->config['bind_dn'];
-
- if (empty($bind_pass)) {
- $this->ready = true;
- }
- else {
- if (!empty($bind_dn)) {
- $this->ready = $this->bind($bind_dn, $bind_pass);
- }
- else if (!empty($this->config['auth_cid'])) {
- $this->ready = $this->sasl_bind($this->config['auth_cid'], $bind_pass, $bind_user);
- }
- else {
- $this->ready = $this->sasl_bind($bind_user, $bind_pass);
- }
- }
-
- // connection established, we're done here
- if ($this->ready) {
- break;
- }
-
- } // end foreach hosts
-
- if (!is_resource($this->conn)) {
- rcube::raise_error(array('code' => 100, 'type' => 'ldap',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Could not connect to any LDAP server, last tried $host"), true);
-
- $this->ready = false;
- }
-
- return $this->ready;
- }
-
- /**
- * Fetches user data from LDAP addressbook
- */
- function get_user_record($user, $host)
- {
- $rcmail = rcube::get_instance();
- $filter = $rcmail->config->get('kolab_auth_filter');
- $filter = $this->parse_vars($filter, $user, $host);
- $base_dn = $this->parse_vars($this->config['base_dn'], $user, $host);
- $scope = $this->config['scope'];
-
- // @TODO: print error if filter is empty
-
- // get record
- if ($result = parent::search($base_dn, $filter, $scope, $this->attributes)) {
- if ($result->count() == 1) {
- $entries = $result->entries(true);
- $dn = key($entries);
- $entry = array_pop($entries);
- $entry = $this->field_mapping($dn, $entry);
-
- return $entry;
- }
- }
- }
-
- /**
- * Fetches user data from LDAP addressbook
- */
- function get_user_groups($dn, $user, $host)
- {
- if (empty($dn) || empty($this->config['groups'])) {
- return array();
- }
-
- $base_dn = $this->parse_vars($this->config['groups']['base_dn'], $user, $host);
- $name_attr = $this->config['groups']['name_attr'] ? $this->config['groups']['name_attr'] : 'cn';
- $member_attr = $this->get_group_member_attr();
- $filter = "(member=$dn)(uniqueMember=$dn)";
-
- if ($member_attr != 'member' && $member_attr != 'uniqueMember')
- $filter .= "($member_attr=$dn)";
- $filter = strtr("(|$filter)", array("\\" => "\\\\"));
-
- $result = parent::search($base_dn, $filter, 'sub', array('dn', $name_attr));
-
- if (!$result) {
- return array();
- }
-
- $groups = array();
- foreach ($result as $entry) {
- $dn = $entry['dn'];
- $entry = rcube_ldap_generic::normalize_entry($entry);
-
- $groups[$dn] = $entry[$name_attr];
- }
-
- return $groups;
- }
-
- /**
- * Get a specific LDAP record
- *
- * @param string DN
- *
- * @return array Record data
- */
- function get_record($dn)
- {
- if (!$this->ready) {
- return;
- }
-
- if ($rec = $this->get_entry($dn)) {
- $rec = rcube_ldap_generic::normalize_entry($rec);
- $rec = $this->field_mapping($dn, $rec);
- }
-
- return $rec;
- }
-
- /**
- * Replace LDAP record data items
- *
- * @param string $dn DN
- * @param array $entry LDAP entry
- *
- * return bool True on success, False on failure
- */
- function replace($dn, $entry)
- {
- // fields mapping
- foreach ($this->fieldmap as $field => $attr) {
- if (array_key_exists($field, $entry)) {
- $entry[$attr] = $entry[$field];
- if ($attr != $field) {
- unset($entry[$field]);
- }
- }
- }
-
- return $this->mod_replace($dn, $entry);
- }
-
- /**
- * Search records (simplified version of rcube_ldap::search)
- *
- * @param mixed $fields The field name or array of field names to search in
- * @param mixed $value Search value (or array of values when $fields is array)
- * @param int $mode Matching mode:
- * 0 - partial (*abc*),
- * 1 - strict (=),
- * 2 - prefix (abc*)
- * @param array $required List of fields that cannot be empty
- * @param int $limit Number of records
- * @param int $count Returns the number of records found
- *
- * @return array List or false on error
- */
- function dosearch($fields, $value, $mode=1, $required = array(), $limit = 0, &$count = 0)
- {
- if (empty($fields)) {
- return array();
- }
-
- $mode = intval($mode);
-
- // use AND operator for advanced searches
- $filter = is_array($value) ? '(&' : '(|';
-
- // set wildcards
- $wp = $ws = '';
- if (!empty($this->config['fuzzy_search']) && $mode != 1) {
- $ws = '*';
- if (!$mode) {
- $wp = '*';
- }
- }
-
- foreach ((array)$fields as $idx => $field) {
- $val = is_array($value) ? $value[$idx] : $value;
- $attrs = (array) $this->fieldmap[$field];
-
- if (empty($attrs)) {
- $filter .= "($field=$wp" . rcube_ldap_generic::quote_string($val) . "$ws)";
- }
- else {
- if (count($attrs) > 1)
- $filter .= '(|';
- foreach ($attrs as $f)
- $filter .= "($f=$wp" . rcube_ldap_generic::quote_string($val) . "$ws)";
- if (count($attrs) > 1)
- $filter .= ')';
- }
- }
- $filter .= ')';
-
- // add required (non empty) fields filter
- $req_filter = '';
-
- foreach ((array)$required as $field) {
- if (in_array($field, (array)$fields)) // required field is already in search filter
- continue;
-
- $attrs = (array) $this->fieldmap[$field];
-
- if (empty($attrs)) {
- $req_filter .= "($field=*)";
- }
- else {
- if (count($attrs) > 1)
- $req_filter .= '(|';
- foreach ($attrs as $f)
- $req_filter .= "($f=*)";
- if (count($attrs) > 1)
- $req_filter .= ')';
- }
- }
-
- if (!empty($req_filter)) {
- $filter = '(&' . $req_filter . $filter . ')';
- }
-
- // avoid double-wildcard if $value is empty
- $filter = preg_replace('/\*+/', '*', $filter);
-
- // add general filter to query
- if (!empty($this->config['filter'])) {
- $filter = '(&(' . preg_replace('/^\(|\)$/', '', $this->config['filter']) . ')' . $filter . ')';
- }
-
- $base_dn = $this->parse_vars($this->config['base_dn']);
- $scope = $this->config['scope'];
- $attrs = array_values($this->fieldmap);
- $list = array();
-
- if ($result = $this->search($base_dn, $filter, $scope, $attrs)) {
- $count = $result->count();
- $i = 0;
- foreach ($result as $entry) {
- if ($limit && $limit <= $i) {
- break;
- }
-
- $dn = $entry['dn'];
- $entry = rcube_ldap_generic::normalize_entry($entry);
- $list[$dn] = $this->field_mapping($dn, $entry);
- $i++;
- }
- }
-
- return $list;
- }
-
- /**
- * Set filter used in search()
- */
- function set_filter($filter)
- {
- $this->config['filter'] = $filter;
- }
-
- /**
- * Maps LDAP attributes to defined fields
- */
- protected function field_mapping($dn, $entry)
- {
- $entry['dn'] = $dn;
-
- // fields mapping
- foreach ($this->fieldmap as $field => $attr) {
- // $entry might be indexed by lower-case attribute names
- $attr_lc = strtolower($attr);
- if (isset($entry[$attr_lc])) {
- $entry[$field] = $entry[$attr_lc];
- }
- else if (isset($entry[$attr])) {
- $entry[$field] = $entry[$attr];
- }
- }
-
- // compose display name according to config
- if (empty($this->fieldmap['displayname'])) {
- $entry['displayname'] = rcube_addressbook::compose_search_name(
- $entry,
- $entry['email'],
- $entry['name'],
- $this->conf['kolab_auth_user_displayname']
- );
- }
-
- return $entry;
- }
-
- /**
- * Detects group member attribute name
- */
- private function get_group_member_attr($object_classes = array())
- {
- if (empty($object_classes)) {
- $object_classes = $this->config['groups']['object_classes'];
- }
- if (!empty($object_classes)) {
- foreach ((array)$object_classes as $oc) {
- switch (strtolower($oc)) {
- case 'group':
- case 'groupofnames':
- case 'kolabgroupofnames':
- $member_attr = 'member';
- break;
-
- case 'groupofuniquenames':
- case 'kolabgroupofuniquenames':
- $member_attr = 'uniqueMember';
- break;
- }
- }
- }
-
- if (!empty($member_attr)) {
- return $member_attr;
- }
-
- if (!empty($this->config['groups']['member_attr'])) {
- return $this->config['groups']['member_attr'];
- }
-
- return 'member';
- }
-
- /**
- * Prepares filter query for LDAP search
- */
- function parse_vars($str, $user = null, $host = null)
- {
- // When authenticating user $user is always set
- // if not set it means we use this LDAP object for other
- // purposes, e.g. kolab_delegation, then username with
- // correct domain is in a session
- if (!$user) {
- $user = $_SESSION['username'];
- }
-
- if (isset($this->icache[$user])) {
- list($user, $dc) = $this->icache[$user];
- }
- else {
- $orig_user = $user;
- $rcmail = rcube::get_instance();
-
- // get default domain
- if ($username_domain = $rcmail->config->get('username_domain')) {
- if ($host && is_array($username_domain) && isset($username_domain[$host])) {
- $domain = rcube_utils::parse_host($username_domain[$host], $host);
- }
- else if (is_string($username_domain)) {
- $domain = rcube_utils::parse_host($username_domain, $host);
- }
- }
-
- // realmed username (with domain)
- if (strpos($user, '@')) {
- list($usr, $dom) = explode('@', $user);
-
- // unrealm domain, user login can contain a domain alias
- if ($dom != $domain && ($dc = $this->find_domain($dom))) {
- // @FIXME: we should replace domain in $user, I suppose
- }
- }
- else if ($domain) {
- $user .= '@' . $domain;
- }
-
- $this->icache[$orig_user] = array($user, $dc);
- }
-
- // replace variables in filter
- list($u, $d) = explode('@', $user);
-
- // hierarchal domain string
- if (empty($dc)) {
- $dc = 'dc=' . strtr($d, array('.' => ',dc='));
- }
-
- $replaces = array('%dc' => $dc, '%d' => $d, '%fu' => $user, '%u' => $u);
-
- $this->parse_replaces = $replaces;
-
- return strtr($str, $replaces);
- }
-
- /**
- * Find root domain for specified domain
- *
- * @param string $domain Domain name
- *
- * @return string Domain DN string
- */
- function find_domain($domain)
- {
- if (empty($domain) || empty($this->config['domain_base_dn']) || empty($this->config['domain_filter'])) {
- return null;
- }
-
- $base_dn = $this->config['domain_base_dn'];
- $filter = $this->config['domain_filter'];
- $name_attr = $this->config['domain_name_attribute'];
-
- if (empty($name_attr)) {
- $name_attr = 'associateddomain';
- }
-
- $filter = str_replace('%s', rcube_ldap_generic::quote_string($domain), $filter);
- $result = parent::search($base_dn, $filter, 'sub', array($name_attr, 'inetdomainbasedn'));
-
- if (!$result) {
- return null;
- }
-
- $entries = $result->entries(true);
- $entry_dn = key($entries);
- $entry = $entries[$entry_dn];
-
- if (is_array($entry)) {
- if (!empty($entry['inetdomainbasedn'])) {
- return $entry['inetdomainbasedn'];
- }
-
- $domain = is_array($entry[$name_attr]) ? $entry[$name_attr][0] : $entry[$name_attr];
-
- return $domain ? 'dc=' . implode(',dc=', explode('.', $domain)) : null;
- }
- }
-
- /**
- * Returns variables used for replacement in (last) parse_vars() call
- *
- * @return array Variable-value hash array
- */
- public function get_parse_vars()
- {
- return $this->parse_replaces;
- }
-
- /**
- * Register additional fields
- */
- public function extend_fieldmap($map)
- {
- foreach ((array)$map as $name => $attr) {
- if (!in_array($attr, $this->attributes)) {
- $this->attributes[] = $attr;
- $this->fieldmap[$name] = $attr;
- }
- }
- }
-
- /**
- * HTML-safe DN string encoding
- *
- * @param string $str DN string
- *
- * @return string Encoded HTML identifier string
- */
- static function dn_encode($str)
- {
- return rtrim(strtr(base64_encode($str), '+/', '-_'), '=');
- }
-
- /**
- * Decodes DN string encoded with _dn_encode()
- *
- * @param string $str Encoded HTML identifier string
- *
- * @return string DN string
- */
- static function dn_decode($str)
- {
- $str = str_pad(strtr($str, '-_', '+/'), strlen($str) % 4, '=', STR_PAD_RIGHT);
- return base64_decode($str);
- }
-}
diff --git a/lib/plugins/kolab_auth/localization/de_CH.inc b/lib/plugins/kolab_auth/localization/de_CH.inc
deleted file mode 100644
index 0332070..0000000
--- a/lib/plugins/kolab_auth/localization/de_CH.inc
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Auth plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
- */
-$labels['loginas'] = 'Anmelden als';
-?>
diff --git a/lib/plugins/kolab_auth/localization/de_DE.inc b/lib/plugins/kolab_auth/localization/de_DE.inc
deleted file mode 100644
index 3918e6e..0000000
--- a/lib/plugins/kolab_auth/localization/de_DE.inc
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Auth plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
- */
-$labels['loginas'] = 'Anmelden als';
-$labels['loginasnotallowed'] = 'Keine Privilegien zum Anmelden als $user';
-?>
diff --git a/lib/plugins/kolab_auth/localization/en_US.inc b/lib/plugins/kolab_auth/localization/en_US.inc
deleted file mode 100644
index 4882bdc..0000000
--- a/lib/plugins/kolab_auth/localization/en_US.inc
+++ /dev/null
@@ -1,14 +0,0 @@
-<?php
-
-/**
- * Localizations for the Kolab Auth plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
- */
-
-$labels['loginas'] = 'Login As';
-$labels['loginasnotallowed'] = 'No privileges to login as $user';
-
-?>
diff --git a/lib/plugins/kolab_auth/localization/es_ES.inc b/lib/plugins/kolab_auth/localization/es_ES.inc
deleted file mode 100644
index ed203e6..0000000
--- a/lib/plugins/kolab_auth/localization/es_ES.inc
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Auth plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
- */
-?>
diff --git a/lib/plugins/kolab_auth/localization/et_EE.inc b/lib/plugins/kolab_auth/localization/et_EE.inc
deleted file mode 100644
index ed203e6..0000000
--- a/lib/plugins/kolab_auth/localization/et_EE.inc
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Auth plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
- */
-?>
diff --git a/lib/plugins/kolab_auth/localization/fr_FR.inc b/lib/plugins/kolab_auth/localization/fr_FR.inc
deleted file mode 100644
index 6538f5b..0000000
--- a/lib/plugins/kolab_auth/localization/fr_FR.inc
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Auth plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
- */
-$labels['loginas'] = 'Se connecter en tant que';
-$labels['loginasnotallowed'] = 'Pas de privilège de se connecter comme $utilisateur';
-?>
diff --git a/lib/plugins/kolab_auth/localization/ja_JP.inc b/lib/plugins/kolab_auth/localization/ja_JP.inc
deleted file mode 100644
index e360737..0000000
--- a/lib/plugins/kolab_auth/localization/ja_JP.inc
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Auth plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
- */
-$labels['loginas'] = 'ログイン';
-?>
diff --git a/lib/plugins/kolab_auth/localization/nl_NL.inc b/lib/plugins/kolab_auth/localization/nl_NL.inc
deleted file mode 100644
index ea3a1c0..0000000
--- a/lib/plugins/kolab_auth/localization/nl_NL.inc
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Auth plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
- */
-$labels['loginas'] = 'Log in als';
-?>
diff --git a/lib/plugins/kolab_auth/localization/pl_PL.inc b/lib/plugins/kolab_auth/localization/pl_PL.inc
deleted file mode 100644
index ca67859..0000000
--- a/lib/plugins/kolab_auth/localization/pl_PL.inc
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Auth plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
- */
-$labels['loginas'] = 'Zaloguj jako';
-?>
diff --git a/lib/plugins/kolab_auth/localization/ru_RU.inc b/lib/plugins/kolab_auth/localization/ru_RU.inc
deleted file mode 100644
index ac9e5a7..0000000
--- a/lib/plugins/kolab_auth/localization/ru_RU.inc
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Auth plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
- */
-$labels['loginas'] = 'Войти как';
-$labels['loginasnotallowed'] = 'Нет привилегий войти как $user';
-?>
diff --git a/lib/plugins/kolab_folders/LICENSE b/lib/plugins/kolab_folders/LICENSE
deleted file mode 100644
index dba13ed..0000000
--- a/lib/plugins/kolab_folders/LICENSE
+++ /dev/null
@@ -1,661 +0,0 @@
- GNU AFFERO GENERAL PUBLIC LICENSE
- Version 3, 19 November 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU Affero General Public License is a free, copyleft license for
-software and other kinds of works, specifically designed to ensure
-cooperation with the community in the case of network server software.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-our General Public Licenses are intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- Developers that use our General Public Licenses protect your rights
-with two steps: (1) assert copyright on the software, and (2) offer
-you this License which gives you legal permission to copy, distribute
-and/or modify the software.
-
- A secondary benefit of defending all users' freedom is that
-improvements made in alternate versions of the program, if they
-receive widespread use, become available for other developers to
-incorporate. Many developers of free software are heartened and
-encouraged by the resulting cooperation. However, in the case of
-software used on network servers, this result may fail to come about.
-The GNU General Public License permits making a modified version and
-letting the public access it on a server without ever releasing its
-source code to the public.
-
- The GNU Affero General Public License is designed specifically to
-ensure that, in such cases, the modified source code becomes available
-to the community. It requires the operator of a network server to
-provide the source code of the modified version running there to the
-users of that server. Therefore, public use of a modified version, on
-a publicly accessible server, gives the public access to the source
-code of the modified version.
-
- An older license, called the Affero General Public License and
-published by Affero, was designed to accomplish similar goals. This is
-a different license, not a version of the Affero GPL, but Affero has
-released a new version of the Affero GPL which permits relicensing under
-this license.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU Affero General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Remote Network Interaction; Use with the GNU General Public License.
-
- Notwithstanding any other provision of this License, if you modify the
-Program, your modified version must prominently offer all users
-interacting with it remotely through a computer network (if your version
-supports such interaction) an opportunity to receive the Corresponding
-Source of your version by providing access to the Corresponding Source
-from a network server at no charge, through some standard or customary
-means of facilitating copying of software. This Corresponding Source
-shall include the Corresponding Source for any work covered by version 3
-of the GNU General Public License that is incorporated pursuant to the
-following paragraph.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the work with which it is combined will remain governed by version
-3 of the GNU General Public License.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU Affero General Public License from time to time. Such new versions
-will be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU Affero General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU Affero General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU Affero General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- 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 Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If your software can interact with users remotely through a computer
-network, you should also make sure that it provides a way for users to
-get its source. For example, if your program is a web application, its
-interface could display a "Source" link that leads users to an archive
-of the code. There are many ways you could offer source, and different
-solutions will be better for different programs; see section 13 for the
-specific requirements.
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU AGPL, see
-<http://www.gnu.org/licenses/>.
diff --git a/lib/plugins/kolab_folders/composer.json b/lib/plugins/kolab_folders/composer.json
deleted file mode 100644
index a4a9877..0000000
--- a/lib/plugins/kolab_folders/composer.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "name": "kolab/kolab_folders",
- "type": "roundcube-plugin",
- "description": "Type-aware folder management/listing for Kolab",
- "homepage": "http://git.kolab.org/roundcubemail-plugins-kolab/",
- "license": "AGPLv3",
- "version": "3.2.3",
- "authors": [
- {
- "name": "Aleksander Machniak",
- "email": "machniak@kolabsys.com",
- "role": "Lead"
- }
- ],
- "repositories": [
- {
- "type": "composer",
- "url": "http://plugins.roundcube.net"
- }
- ],
- "require": {
- "php": ">=5.3.0",
- "roundcube/plugin-installer": ">=0.1.3",
- "kolab/libkolab": ">=3.2.3"
- }
-}
diff --git a/lib/plugins/kolab_folders/config.inc.php.dist b/lib/plugins/kolab_folders/config.inc.php.dist
deleted file mode 100644
index 0c9bd12..0000000
--- a/lib/plugins/kolab_folders/config.inc.php.dist
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-
-// Default kolab-specific folders. Set values to non-empty
-// strings to create default folders of apropriate type.
-// If there is no default folder with specified type in user mailbox,
-// it will be created.
-// Note: Mail folders will be also subscribed.
-
-// Default Configuration folder
-$config['kolab_folders_configuration_default'] = '';
-// Default Calendar folder
-$config['kolab_folders_event_default'] = '';
-// Default Contacts (Addressbook) folder
-$config['kolab_folders_contact_default'] = '';
-// Default Tasks folder
-$config['kolab_folders_task_default'] = '';
-// Default Notes folder
-$config['kolab_folders_note_default'] = '';
-// Default Journal folder
-$config['kolab_folders_journal_default'] = '';
-// Default Files folder
-$config['kolab_folders_file_default'] = '';
-// Default FreeBusy folder
-$config['kolab_folders_freebusy_default'] = '';
-
-// INBOX folder
-$config['kolab_folders_mail_inbox'] = '';
-// Drafts folder
-$config['kolab_folders_mail_drafts'] = '';
-// Sent folder
-$config['kolab_folders_mail_sentitems'] = '';
-// Trash folder
-$config['kolab_folders_mail_wastebasket'] = '';
-// Others folders
-$config['kolab_folders_mail_outbox'] = '';
-$config['kolab_folders_mail_junkemail'] = '';
diff --git a/lib/plugins/kolab_folders/kolab_folders.js b/lib/plugins/kolab_folders/kolab_folders.js
deleted file mode 100644
index b9d9225..0000000
--- a/lib/plugins/kolab_folders/kolab_folders.js
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- * Client script for the Kolab folder management/listing extension
- *
- * @author Aleksander Machniak <machniak@kolabsys.com>
- *
- * @licstart The following is the entire license notice for the
- * JavaScript code in this file.
- *
- * Copyright (C) 2011, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * @licend The above is the entire license notice
- * for the JavaScript code in this file.
- */
-
-window.rcmail && rcmail.env.action == 'folders' && rcmail.addEventListener('init', function() {
- var filter = $(rcmail.gui_objects.foldersfilter),
- optgroup = $('<optgroup>').attr('label', rcmail.gettext('kolab_folders.folderctype'));
-
- // remove disabled namespaces
- filter.children('option').each(function(i, opt) {
- $.each(rcmail.env.skip_roots || [], function() {
- if (opt.value == this) {
- $(opt).remove();
- }
- });
- });
-
- // add type options to the filter
- $.each(rcmail.env.foldertypes, function() {
- optgroup.append($('<option>').attr('value', 'type-' + this).text(rcmail.gettext('kolab_folders.foldertype' + this)));
- });
-
- // overwrite default onchange handler
- filter.attr('onchange', '')
- .on('change', function() { return kolab_folders_filter(this.value); })
- .append(optgroup);
-});
-
-window.rcmail && rcmail.env.action != 'folders' && $(document).ready(function() {
- // Add onchange handler for folder type SELECT, and call it on form init
- $('#_ctype').change(function() {
- var type = $(this).val(),
- sub = $('#_subtype'),
- subtypes = rcmail.env.kolab_folder_subtypes[type] || {};
-
- // reset subtype selector
- sub.html('<option value=""></option>');
-
- // append available subtypes for the given folder type
- $.each(subtypes, function(val, label) {
- $('<option>').attr('value', val).text(label).appendTo(sub);
- });
-
- // And re-set subtype
- sub.val(rcmail.env.kolab_folder_subtype);
- });
-});
-
-function kolab_folders_filter(filter)
-{
- var type = filter.match(/^type-([a-z]+)$/) ? RegExp.$1 : null;
-
- rcmail.subscription_list.reset_search();
-
- if (!type) {
- // clear type filter
- if (rcmail.folder_filter_type) {
- $('li', rcmail.subscription_list.container).removeData('filtered').show();
- rcmail.folder_filter_type = null;
- }
-
- // apply namespace filter
- rcmail.folder_filter(filter);
- }
- else {
- rcmail.folder_filter_type = type;
- rcmail.subscription_list.container.children('li').each(function() {
- kolab_folder_filter_match(this, type);
- });
- }
-
- return false;
-}
-
-function kolab_folder_filter_match(elem, type)
-{
- var found = 0, cl = elem.className || '',
- $elem = $(elem),
- children = $('ul', elem).children('li');
-
- // subfolders...
- children.each(function() {
- found += kolab_folder_filter_match(this, type);
- });
-
- if (found || cl.match(new RegExp('type-' + type))
- || (type == 'mail' && !children.length && !cl.match(/(^| )type-([a-z]+)/))
- ) {
- if (found || !$elem.is('.virtual')) {
- found++;
- }
- }
-
- if (found) {
- $elem.removeData('filtered').show();
- }
- else {
- $elem.data('filtered', true).hide();
- }
-
- return found;
-}
diff --git a/lib/plugins/kolab_folders/kolab_folders.php b/lib/plugins/kolab_folders/kolab_folders.php
deleted file mode 100644
index b3c2e8e..0000000
--- a/lib/plugins/kolab_folders/kolab_folders.php
+++ /dev/null
@@ -1,638 +0,0 @@
-<?php
-
-/**
- * Type-aware folder management/listing for Kolab
- *
- * @version @package_version@
- * @author Aleksander Machniak <machniak@kolabsys.com>
- *
- * Copyright (C) 2011, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_folders extends rcube_plugin
-{
- public $task = '?(?!login).*';
-
- public $types = array('mail', 'event', 'journal', 'task', 'note', 'contact', 'configuration', 'file', 'freebusy');
- public $subtypes = array(
- 'mail' => array('inbox', 'drafts', 'sentitems', 'outbox', 'wastebasket', 'junkemail'),
- 'event' => array('default', 'confidential'),
- 'task' => array('default', 'confidential'),
- 'journal' => array('default'),
- 'note' => array('default'),
- 'contact' => array('default'),
- 'configuration' => array('default'),
- 'file' => array('default'),
- 'freebusy' => array('default'),
- );
- public $act_types = array('event', 'task');
-
- private $rc;
- private static $instance;
-
-
- /**
- * Plugin initialization.
- */
- function init()
- {
- self::$instance = $this;
- $this->rc = rcube::get_instance();
-
- // load required plugin
- $this->require_plugin('libkolab');
-
- // Folder listing hooks
- $this->add_hook('storage_folders', array($this, 'mailboxes_list'));
-
- // Folder manager hooks
- $this->add_hook('folder_form', array($this, 'folder_form'));
- $this->add_hook('folder_update', array($this, 'folder_save'));
- $this->add_hook('folder_create', array($this, 'folder_save'));
- $this->add_hook('folder_delete', array($this, 'folder_save'));
- $this->add_hook('folder_rename', array($this, 'folder_save'));
- $this->add_hook('folders_list', array($this, 'folders_list'));
-
- // Special folders setting
- $this->add_hook('preferences_save', array($this, 'prefs_save'));
- }
-
- /**
- * Handler for mailboxes_list hook. Enables type-aware lists filtering.
- */
- function mailboxes_list($args)
- {
- // infinite loop prevention
- if ($this->is_processing) {
- return $args;
- }
-
- if (!$this->metadata_support()) {
- return $args;
- }
-
- $this->is_processing = true;
-
- // get folders
- $folders = kolab_storage::list_folders($args['root'], $args['name'], $args['filter'], $args['mode'] == 'LSUB', $folderdata);
-
- $this->is_processing = false;
-
- if (!is_array($folders)) {
- return $args;
- }
-
- // Create default folders
- if ($args['root'] == '' && $args['name'] = '*') {
- $this->create_default_folders($folders, $args['filter'], $folderdata, $args['mode'] == 'LSUB');
- }
-
- $args['folders'] = $folders;
-
- return $args;
- }
-
- /**
- * Handler for folders_list hook. Add css classes to folder rows.
- */
- function folders_list($args)
- {
- if (!$this->metadata_support()) {
- return $args;
- }
-
- // load translations
- $this->add_texts('localization/', false);
-
- // Add javascript script to the client
- $this->include_script('kolab_folders.js');
-
- $this->add_label('folderctype');
- foreach ($this->types as $type) {
- $this->add_label('foldertype' . $type);
- }
-
- $skip_namespace = $this->rc->config->get('kolab_skip_namespace');
- $skip_roots = array();
-
- if (!empty($skip_namespace)) {
- $storage = $this->rc->get_storage();
- foreach ((array)$skip_namespace as $ns) {
- foreach((array)$storage->get_namespace($ns) as $root) {
- $skip_roots[] = rtrim($root[0], $root[1]);
- }
- }
- }
-
- $this->rc->output->set_env('skip_roots', $skip_roots);
- $this->rc->output->set_env('foldertypes', $this->types);
-
- // get folders types
- $folderdata = kolab_storage::folders_typedata();
-
- if (!is_array($folderdata)) {
- return $args;
- }
-
- // Add type-based style for table rows
- // See kolab_folders::folder_class_name()
- if ($table = $args['table']) {
- for ($i=1, $cnt=$table->size(); $i<=$cnt; $i++) {
- $attrib = $table->get_row_attribs($i);
- $folder = $attrib['foldername']; // UTF7-IMAP
- $type = $folderdata[$folder];
-
- if (!$type) {
- $type = 'mail';
- }
-
- $class_name = self::folder_class_name($type);
- $attrib['class'] = trim($attrib['class'] . ' ' . $class_name);
- $table->set_row_attribs($attrib, $i);
- }
- }
-
- // Add type-based class for list items
- if (is_array($args['list'])) {
- foreach ((array)$args['list'] as $k => $item) {
- $folder = $item['folder_imap']; // UTF7-IMAP
- $type = $folderdata[$folder];
-
- if (!$type) {
- $type = 'mail';
- }
-
- $class_name = self::folder_class_name($type);
- $args['list'][$k]['class'] = trim($item['class'] . ' ' . $class_name);
- }
- }
-
- return $args;
- }
-
- /**
- * Handler for folder info/edit form (folder_form hook).
- * Adds folder type selector.
- */
- function folder_form($args)
- {
- if (!$this->metadata_support()) {
- return $args;
- }
- // load translations
- $this->add_texts('localization/', false);
-
- // INBOX folder is of type mail.inbox and this cannot be changed
- if ($args['name'] == 'INBOX') {
- $args['form']['props']['fieldsets']['settings']['content']['foldertype'] = array(
- 'label' => $this->gettext('folderctype'),
- 'value' => sprintf('%s (%s)', $this->gettext('foldertypemail'), $this->gettext('inbox')),
- );
-
- return $args;
- }
-
- if ($args['options']['is_root']) {
- return $args;
- }
-
- $mbox = strlen($args['name']) ? $args['name'] : $args['parent_name'];
-
- if (isset($_POST['_ctype'])) {
- $new_ctype = trim(rcube_utils::get_input_value('_ctype', rcube_utils::INPUT_POST));
- $new_subtype = trim(rcube_utils::get_input_value('_subtype', rcube_utils::INPUT_POST));
- }
-
- // Get type of the folder or the parent
- if (strlen($mbox)) {
- list($ctype, $subtype) = $this->get_folder_type($mbox);
- if (strlen($args['parent_name']) && $subtype == 'default')
- $subtype = ''; // there can be only one
- }
-
- if (!$ctype) {
- $ctype = 'mail';
- }
-
- $storage = $this->rc->get_storage();
-
- // Don't allow changing type of shared folder, according to ACL
- if (strlen($mbox)) {
- $options = $storage->folder_info($mbox);
- if ($options['namespace'] != 'personal' && !in_array('a', (array)$options['rights'])) {
- if (in_array($ctype, $this->types)) {
- $value = $this->gettext('foldertype'.$ctype);
- }
- else {
- $value = $ctype;
- }
- if ($subtype) {
- $value .= ' ('. ($subtype == 'default' ? $this->gettext('default') : $subtype) .')';
- }
-
- $args['form']['props']['fieldsets']['settings']['content']['foldertype'] = array(
- 'label' => $this->gettext('folderctype'),
- 'value' => $value,
- );
-
- return $args;
- }
- }
-
- // Add javascript script to the client
- $this->include_script('kolab_folders.js');
-
- // build type SELECT fields
- $type_select = new html_select(array('name' => '_ctype', 'id' => '_ctype'));
- $sub_select = new html_select(array('name' => '_subtype', 'id' => '_subtype'));
- $sub_select->add('', '');
-
- foreach ($this->types as $type) {
- $type_select->add($this->gettext('foldertype'.$type), $type);
- }
- // add non-supported type
- if (!in_array($ctype, $this->types)) {
- $type_select->add($ctype, $ctype);
- }
-
- $sub_types = array();
- foreach ($this->subtypes as $ftype => $subtypes) {
- $sub_types[$ftype] = array_combine($subtypes, array_map(array($this, 'gettext'), $subtypes));
-
- // fill options for the current folder type
- if ($ftype == $ctype || $ftype == $new_ctype) {
- $sub_select->add(array_values($sub_types[$ftype]), $subtypes);
- }
- }
-
- $args['form']['props']['fieldsets']['settings']['content']['foldertype'] = array(
- 'label' => $this->gettext('folderctype'),
- 'value' => $type_select->show(isset($new_ctype) ? $new_ctype : $ctype)
- . $sub_select->show(isset($new_subtype) ? $new_subtype : $subtype),
- );
-
- $this->rc->output->set_env('kolab_folder_subtypes', $sub_types);
- $this->rc->output->set_env('kolab_folder_subtype', isset($new_subtype) ? $new_subtype : $subtype);
-
- return $args;
- }
-
- /**
- * Handler for folder update/create action (folder_update/folder_create hook).
- */
- function folder_save($args)
- {
- // Folder actions from folders list
- if (empty($args['record'])) {
- return $args;
- }
-
- // Folder create/update with form
- $ctype = trim(rcube_utils::get_input_value('_ctype', rcube_utils::INPUT_POST));
- $subtype = trim(rcube_utils::get_input_value('_subtype', rcube_utils::INPUT_POST));
- $mbox = $args['record']['name'];
- $old_mbox = $args['record']['oldname'];
- $subscribe = $args['record']['subscribe'];
-
- if (empty($ctype)) {
- return $args;
- }
-
- // load translations
- $this->add_texts('localization/', false);
-
- // Skip folder creation/rename in core
- // @TODO: Maybe we should provide folder_create_after and folder_update_after hooks?
- // Using create_mailbox/rename_mailbox here looks bad
- $args['abort'] = true;
-
- // There can be only one default folder of specified type
- if ($subtype == 'default') {
- $default = $this->get_default_folder($ctype);
-
- if ($default !== null && $old_mbox != $default) {
- $args['result'] = false;
- $args['message'] = $this->gettext('defaultfolderexists');
- return $args;
- }
- }
- // Subtype sanity-checks
- else if ($subtype && (!($subtypes = $this->subtypes[$ctype]) || !in_array($subtype, $subtypes))) {
- $subtype = '';
- }
-
- $ctype .= $subtype ? '.'.$subtype : '';
-
- $storage = $this->rc->get_storage();
-
- // Create folder
- if (!strlen($old_mbox)) {
- // By default don't subscribe to non-mail folders
- if ($subscribe)
- $subscribe = (bool) preg_match('/^mail/', $ctype);
-
- $result = $storage->create_folder($mbox, $subscribe);
- // Set folder type
- if ($result) {
- $this->set_folder_type($mbox, $ctype);
- }
- }
- // Rename folder
- else {
- if ($old_mbox != $mbox) {
- $result = $storage->rename_folder($old_mbox, $mbox);
- }
- else {
- $result = true;
- }
-
- if ($result) {
- list($oldtype, $oldsubtype) = $this->get_folder_type($mbox);
- $oldtype .= $oldsubtype ? '.'.$oldsubtype : '';
-
- if ($ctype != $oldtype) {
- $this->set_folder_type($mbox, $ctype);
- }
- }
- }
-
- $args['record']['class'] = self::folder_class_name($ctype);
- $args['record']['subscribe'] = $subscribe;
- $args['result'] = $result;
-
- return $args;
- }
-
- /**
- * Handler for user preferences save (preferences_save hook)
- *
- * @param array $args Hash array with hook parameters
- *
- * @return array Hash array with modified hook parameters
- */
- public function prefs_save($args)
- {
- if ($args['section'] != 'folders') {
- return $args;
- }
-
- $dont_override = (array) $this->rc->config->get('dont_override', array());
-
- // map config option name to kolab folder type annotation
- $opts = array(
- 'drafts_mbox' => 'mail.drafts',
- 'sent_mbox' => 'mail.sentitems',
- 'junk_mbox' => 'mail.junkemail',
- 'trash_mbox' => 'mail.wastebasket',
- );
-
- // check if any of special folders has been changed
- foreach ($opts as $opt_name => $type) {
- $new = $args['prefs'][$opt_name];
- $old = $this->rc->config->get($opt_name);
- if (!strlen($new) || $new === $old || in_array($opt_name, $dont_override)) {
- unset($opts[$opt_name]);
- }
- }
-
- if (empty($opts)) {
- return $args;
- }
-
- $folderdata = kolab_storage::folders_typedata();
-
- if (!is_array($folderdata)) {
- return $args;
- }
-
- foreach ($opts as $opt_name => $type) {
- $foldername = $args['prefs'][$opt_name];
-
- // get all folders of specified type
- $folders = array_intersect($folderdata, array($type));
-
- // folder already annotated with specified type
- if (!empty($folders[$foldername])) {
- continue;
- }
-
- // set type to the new folder
- $this->set_folder_type($foldername, $type);
-
- // unset old folder(s) type annotation
- list($maintype, $subtype) = explode('.', $type);
- foreach (array_keys($folders) as $folder) {
- $this->set_folder_type($folder, $maintype);
- }
- }
-
- return $args;
- }
-
- /**
- * Checks if IMAP server supports any of METADATA, ANNOTATEMORE, ANNOTATEMORE2
- *
- * @return boolean
- */
- function metadata_support()
- {
- $storage = $this->rc->get_storage();
-
- return $storage->get_capability('METADATA') ||
- $storage->get_capability('ANNOTATEMORE') ||
- $storage->get_capability('ANNOTATEMORE2');
- }
-
- /**
- * Checks if IMAP server supports any of METADATA, ANNOTATEMORE, ANNOTATEMORE2
- *
- * @param string $folder Folder name
- *
- * @return array Folder content-type
- */
- function get_folder_type($folder)
- {
- return explode('.', (string)kolab_storage::folder_type($folder));
- }
-
- /**
- * Sets folder content-type.
- *
- * @param string $folder Folder name
- * @param string $type Content type
- *
- * @return boolean True on success
- */
- function set_folder_type($folder, $type = 'mail')
- {
- return kolab_storage::set_folder_type($folder, $type);
- }
-
- /**
- * Returns the name of default folder
- *
- * @param string $type Folder type
- *
- * @return string Folder name
- */
- function get_default_folder($type)
- {
- $folderdata = kolab_storage::folders_typedata();
-
- if (!is_array($folderdata)) {
- return null;
- }
-
- // get all folders of specified type
- $folderdata = array_intersect($folderdata, array($type.'.default'));
-
- return key($folderdata);
- }
-
- /**
- * Returns CSS class name for specified folder type
- *
- * @param string $type Folder type
- *
- * @return string Class name
- */
- static function folder_class_name($type)
- {
- list($ctype, $subtype) = explode('.', $type);
-
- $class[] = 'type-' . ($ctype ? $ctype : 'mail');
-
- if ($subtype)
- $class[] = 'subtype-' . $subtype;
-
- return implode(' ', $class);
- }
-
- /**
- * Creates default folders if they doesn't exist
- */
- private function create_default_folders(&$folders, $filter, $folderdata = null, $lsub = false)
- {
- $storage = $this->rc->get_storage();
- $namespace = $storage->get_namespace();
- $defaults = array();
- $prefix = '';
-
- // Find personal namespace prefix
- if (is_array($namespace['personal']) && count($namespace['personal']) == 1) {
- $prefix = $namespace['personal'][0][0];
- }
-
- $this->load_config();
-
- // get configured defaults
- foreach ($this->types as $type) {
- foreach ((array)$this->subtypes[$type] as $subtype) {
- $opt_name = 'kolab_folders_' . $type . '_' . $subtype;
- if ($folder = $this->rc->config->get($opt_name)) {
- // convert configuration value to UTF7-IMAP charset
- $folder = rcube_charset::convert($folder, RCUBE_CHARSET, 'UTF7-IMAP');
- // and namespace prefix if needed
- if ($prefix && strpos($folder, $prefix) === false && $folder != 'INBOX') {
- $folder = $prefix . $folder;
- }
- $defaults[$type . '.' . $subtype] = $folder;
- }
- }
- }
-
- if (empty($defaults)) {
- return;
- }
-
- if ($folderdata === null) {
- $folderdata = kolab_storage::folders_typedata();
- }
-
- if (!is_array($folderdata)) {
- return;
- }
-
- // find default folders
- foreach ($defaults as $type => $foldername) {
- // get all folders of specified type
- $_folders = array_intersect($folderdata, array($type));
-
- // default folder found
- if (!empty($_folders)) {
- continue;
- }
-
- list($type1, $type2) = explode('.', $type);
-
- $activate = in_array($type1, $this->act_types);
- $exists = false;
- $result = false;
-
- // check if folder exists
- if (!empty($folderdata[$foldername]) || $foldername == 'INBOX') {
- $exists = true;
- }
- else if ((!$filter || $filter == $type1) && in_array($foldername, $folders)) {
- // this assumes also that subscribed folder exists
- $exists = true;
- }
- else {
- $exists = $storage->folder_exists($foldername);
- }
-
- // create folder
- if (!$exists) {
- $exists = $storage->create_folder($foldername);
- }
-
- // set type + subscribe + activate
- if ($exists) {
- if ($result = kolab_storage::set_folder_type($foldername, $type)) {
- // check if folder is subscribed
- if ((!$filter || $filter == $type1) && $lsub && in_array($foldername, $folders)) {
- // already subscribed
- $subscribed = true;
- }
- else {
- $subscribed = $storage->subscribe($foldername);
- }
-
- // activate folder
- if ($activate) {
- kolab_storage::folder_activate($foldername, true);
- }
- }
- }
-
- // add new folder to the result
- if ($result && (!$filter || $filter == $type1) && (!$lsub || $subscribed)) {
- $folders[] = $foldername;
- }
- }
- }
-
- /**
- * Static getter for default folder of the given type
- *
- * @param string $type Folder type
- * @return string Folder name
- */
- public static function default_folder($type)
- {
- return self::$instance->get_default_folder($type);
- }
-}
diff --git a/lib/plugins/kolab_folders/localization/de_CH.inc b/lib/plugins/kolab_folders/localization/de_CH.inc
deleted file mode 100644
index 91c24d3..0000000
--- a/lib/plugins/kolab_folders/localization/de_CH.inc
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Folders plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_folders/
- */
-$labels['folderctype'] = 'Ordnerinhalt';
-$labels['foldertypemail'] = 'E-Mail';
-$labels['foldertypeevent'] = 'Kalender';
-$labels['foldertypejournal'] = 'Journal';
-$labels['foldertypetask'] = 'Aufgaben';
-$labels['foldertypenote'] = 'Notizen';
-$labels['foldertypecontact'] = 'Kontakte';
-$labels['foldertypeconfiguration'] = 'Konfiguration';
-$labels['foldertypefile'] = 'Dateien';
-$labels['foldertypefreebusy'] = 'Frei-Besetzt';
-$labels['default'] = 'Standard';
-$labels['inbox'] = 'Posteingang';
-$labels['drafts'] = 'Entwürfe';
-$labels['sentitems'] = 'Gesendet';
-$labels['outbox'] = 'Postausgang';
-$labels['wastebasket'] = 'Gelöscht';
-$labels['junkemail'] = 'Spam';
-$labels['confidential'] = 'Confidential';
-$messages['defaultfolderexists'] = 'Es existiert bereits ein Standardordner für den angegebenen Typ';
-?>
diff --git a/lib/plugins/kolab_folders/localization/de_DE.inc b/lib/plugins/kolab_folders/localization/de_DE.inc
deleted file mode 100644
index 24749ad..0000000
--- a/lib/plugins/kolab_folders/localization/de_DE.inc
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Folders plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_folders/
- */
-$labels['folderctype'] = 'Ordnerinhalt';
-$labels['foldertypemail'] = 'E-Mail';
-$labels['foldertypeevent'] = 'Kalender';
-$labels['foldertypejournal'] = 'Journal';
-$labels['foldertypetask'] = 'Aufgaben';
-$labels['foldertypenote'] = 'Notizen';
-$labels['foldertypecontact'] = 'Kontakte';
-$labels['foldertypeconfiguration'] = 'Konfiguration';
-$labels['foldertypefile'] = 'Dateien';
-$labels['foldertypefreebusy'] = 'Frei/Belegt';
-$labels['default'] = 'Standard';
-$labels['inbox'] = 'Posteingang';
-$labels['drafts'] = 'Entwürfe';
-$labels['sentitems'] = 'Gesendet';
-$labels['outbox'] = 'Postausgang';
-$labels['wastebasket'] = 'Mülleimer';
-$labels['junkemail'] = 'Spam';
-$labels['confidential'] = 'Vertraulich';
-$messages['defaultfolderexists'] = 'Es gibt bereits einen Standardordner dieses Typs';
-?>
diff --git a/lib/plugins/kolab_folders/localization/en_US.inc b/lib/plugins/kolab_folders/localization/en_US.inc
deleted file mode 100644
index 0910d9d..0000000
--- a/lib/plugins/kolab_folders/localization/en_US.inc
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-
-/**
- * Localizations for the Kolab Folders plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_folders/
- */
-
-$labels = array();
-
-$labels['folderctype'] = 'Content type';
-$labels['foldertypemail'] = 'Mail';
-$labels['foldertypeevent'] = 'Calendar';
-$labels['foldertypejournal'] = 'Journal';
-$labels['foldertypetask'] = 'Tasks';
-$labels['foldertypenote'] = 'Notes';
-$labels['foldertypecontact'] = 'Contacts';
-$labels['foldertypeconfiguration'] = 'Configuration';
-$labels['foldertypefile'] = 'Files';
-$labels['foldertypefreebusy'] = 'Free-Busy';
-
-$labels['default'] = 'Default';
-$labels['inbox'] = 'Inbox';
-$labels['drafts'] = 'Drafts';
-$labels['sentitems'] = 'Sent';
-$labels['outbox'] = 'Outbox';
-$labels['wastebasket'] = 'Trash';
-$labels['junkemail'] = 'Junk';
-$labels['confidential'] = 'Confidential';
-
-$messages['defaultfolderexists'] = 'There is already default folder of specified type';
-
-?>
diff --git a/lib/plugins/kolab_folders/localization/es_ES.inc b/lib/plugins/kolab_folders/localization/es_ES.inc
deleted file mode 100644
index b53712b..0000000
--- a/lib/plugins/kolab_folders/localization/es_ES.inc
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Folders plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_folders/
- */
-$labels['folderctype'] = 'Content type';
-$labels['foldertypemail'] = 'Mail';
-$labels['foldertypeevent'] = 'Calendar';
-$labels['foldertypejournal'] = 'Journal';
-$labels['foldertypetask'] = 'Tareas';
-$labels['foldertypenote'] = 'Notas';
-$labels['foldertypecontact'] = 'Contactos';
-$labels['foldertypeconfiguration'] = 'Configuración';
-$labels['foldertypefile'] = 'Files';
-$labels['foldertypefreebusy'] = 'Free-Busy';
-$labels['default'] = 'Default';
-$labels['inbox'] = 'Inbox';
-$labels['drafts'] = 'Drafts';
-$labels['sentitems'] = 'Sent';
-$labels['outbox'] = 'Outbox';
-$labels['wastebasket'] = 'Trash';
-$labels['junkemail'] = 'Junk';
-$labels['confidential'] = 'Confidential';
-$messages['defaultfolderexists'] = 'There is already default folder of specified type';
-?>
diff --git a/lib/plugins/kolab_folders/localization/et_EE.inc b/lib/plugins/kolab_folders/localization/et_EE.inc
deleted file mode 100644
index 5a12004..0000000
--- a/lib/plugins/kolab_folders/localization/et_EE.inc
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Folders plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_folders/
- */
-$labels['folderctype'] = 'Content type';
-$labels['foldertypemail'] = 'Mail';
-$labels['foldertypeevent'] = 'Calendar';
-$labels['foldertypejournal'] = 'Journal';
-$labels['foldertypetask'] = 'Tasks';
-$labels['foldertypenote'] = 'Notes';
-$labels['foldertypecontact'] = 'Contacts';
-$labels['foldertypeconfiguration'] = 'Configuration';
-$labels['foldertypefile'] = 'Files';
-$labels['foldertypefreebusy'] = 'Free-Busy';
-$labels['default'] = 'Default';
-$labels['inbox'] = 'Inbox';
-$labels['drafts'] = 'Drafts';
-$labels['sentitems'] = 'Sent';
-$labels['outbox'] = 'Outbox';
-$labels['wastebasket'] = 'Trash';
-$labels['junkemail'] = 'Junk';
-$labels['confidential'] = 'Confidential';
-$messages['defaultfolderexists'] = 'There is already default folder of specified type';
-?>
diff --git a/lib/plugins/kolab_folders/localization/fr_FR.inc b/lib/plugins/kolab_folders/localization/fr_FR.inc
deleted file mode 100644
index 41e506e..0000000
--- a/lib/plugins/kolab_folders/localization/fr_FR.inc
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Folders plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_folders/
- */
-$labels['folderctype'] = 'Type de contenu';
-$labels['foldertypemail'] = 'Courriel';
-$labels['foldertypeevent'] = 'Calendrier';
-$labels['foldertypejournal'] = 'Journal';
-$labels['foldertypetask'] = 'Tâches';
-$labels['foldertypenote'] = 'Notes';
-$labels['foldertypecontact'] = 'Contacts';
-$labels['foldertypeconfiguration'] = 'Configuration';
-$labels['foldertypefile'] = 'Fichiers';
-$labels['foldertypefreebusy'] = 'Disponible/Occupé';
-$labels['default'] = 'Par Défaut';
-$labels['inbox'] = 'Courrier entrant';
-$labels['drafts'] = 'Brouillons';
-$labels['sentitems'] = 'Envoyés';
-$labels['outbox'] = 'Courrier sortant';
-$labels['wastebasket'] = 'Corbeille';
-$labels['junkemail'] = 'Indésirables';
-$labels['confidential'] = 'Confidentiel';
-$messages['defaultfolderexists'] = 'Il existe déjà un répertoire par défaut pour le type spécifié';
-?>
diff --git a/lib/plugins/kolab_folders/localization/ja_JP.inc b/lib/plugins/kolab_folders/localization/ja_JP.inc
deleted file mode 100644
index 6dfd611..0000000
--- a/lib/plugins/kolab_folders/localization/ja_JP.inc
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Folders plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_folders/
- */
-$labels['folderctype'] = 'コンテンツタイプ';
-$labels['foldertypemail'] = 'メール';
-$labels['foldertypeevent'] = 'カレンダー';
-$labels['foldertypejournal'] = 'ジャーナル';
-$labels['foldertypetask'] = 'タスク';
-$labels['foldertypenote'] = 'ノート';
-$labels['foldertypecontact'] = 'コンタクト';
-$labels['foldertypeconfiguration'] = '設定';
-$labels['foldertypefile'] = 'ファイル';
-$labels['foldertypefreebusy'] = '空状況';
-$labels['default'] = 'デフォルト';
-$labels['inbox'] = '受信箱';
-$labels['drafts'] = '下書き';
-$labels['sentitems'] = '送信済';
-$labels['outbox'] = '送信箱';
-$labels['wastebasket'] = 'ごみ箱';
-$labels['junkemail'] = '迷惑メール';
-$labels['confidential'] = 'Confidential';
-$messages['defaultfolderexists'] = '指定したタイプの初期フォルダは既にあります。';
-?>
diff --git a/lib/plugins/kolab_folders/localization/nl_NL.inc b/lib/plugins/kolab_folders/localization/nl_NL.inc
deleted file mode 100644
index a80aca5..0000000
--- a/lib/plugins/kolab_folders/localization/nl_NL.inc
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Folders plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_folders/
- */
-$labels['folderctype'] = 'Inhoudstype';
-$labels['foldertypemail'] = 'Mail';
-$labels['foldertypeevent'] = 'Agenda';
-$labels['foldertypejournal'] = 'Dagboek';
-$labels['foldertypetask'] = 'Taken';
-$labels['foldertypenote'] = 'Notities';
-$labels['foldertypecontact'] = 'Adresboek';
-$labels['foldertypeconfiguration'] = 'Configuratie';
-$labels['foldertypefile'] = 'Bestanden';
-$labels['foldertypefreebusy'] = 'Vrij/Bezet';
-$labels['default'] = 'Standaard';
-$labels['inbox'] = 'Inbox';
-$labels['drafts'] = 'Concepten';
-$labels['sentitems'] = 'Verzonden';
-$labels['outbox'] = 'Te versturen';
-$labels['wastebasket'] = 'Prullenbak';
-$labels['junkemail'] = 'Ongewenst';
-$labels['confidential'] = 'Vertrouwelijk';
-$messages['defaultfolderexists'] = 'Er is reeds een standaard map voor dit type inhoud';
-?>
diff --git a/lib/plugins/kolab_folders/localization/pl_PL.inc b/lib/plugins/kolab_folders/localization/pl_PL.inc
deleted file mode 100644
index 8d9f61a..0000000
--- a/lib/plugins/kolab_folders/localization/pl_PL.inc
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Folders plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_folders/
- */
-$labels['folderctype'] = 'Typ treści';
-$labels['foldertypemail'] = 'Poczta';
-$labels['foldertypeevent'] = 'Kalendarz';
-$labels['foldertypejournal'] = 'Dziennik';
-$labels['foldertypetask'] = 'Zadania';
-$labels['foldertypenote'] = 'Notatki';
-$labels['foldertypecontact'] = 'Kontakty';
-$labels['foldertypeconfiguration'] = 'Konfiguracja';
-$labels['foldertypefile'] = 'Pliki';
-$labels['foldertypefreebusy'] = 'Wolny-Zajęty';
-$labels['default'] = 'Domyślny';
-$labels['inbox'] = 'Odebrane';
-$labels['drafts'] = 'Kopie robocze';
-$labels['sentitems'] = 'Wysłane';
-$labels['outbox'] = 'Poczta wychodząca';
-$labels['wastebasket'] = 'Kosz';
-$labels['junkemail'] = 'Spam';
-$labels['confidential'] = 'Confidential';
-$messages['defaultfolderexists'] = 'Folder domyślny wybranego typu już istnieje';
-?>
diff --git a/lib/plugins/kolab_folders/localization/ru_RU.inc b/lib/plugins/kolab_folders/localization/ru_RU.inc
deleted file mode 100644
index 4e50bff..0000000
--- a/lib/plugins/kolab_folders/localization/ru_RU.inc
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/**
- * Localizations for the Kolab Folders plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_folders/
- */
-$labels['folderctype'] = 'Тип ящика';
-$labels['foldertypemail'] = 'Почта';
-$labels['foldertypeevent'] = 'Календарь';
-$labels['foldertypejournal'] = 'Журнал';
-$labels['foldertypetask'] = 'Задачи';
-$labels['foldertypenote'] = 'Заметки';
-$labels['foldertypecontact'] = 'Контакты';
-$labels['foldertypeconfiguration'] = 'Настройки';
-$labels['foldertypefile'] = 'Файлы';
-$labels['foldertypefreebusy'] = 'Занят/Свободен';
-$labels['default'] = 'По умолчанию';
-$labels['inbox'] = 'Входящие';
-$labels['drafts'] = 'Черновики';
-$labels['sentitems'] = 'Отправленные';
-$labels['outbox'] = 'Исходящие';
-$labels['wastebasket'] = 'Корзина';
-$labels['junkemail'] = 'Спам';
-$labels['confidential'] = 'Конфиденциально';
-$messages['defaultfolderexists'] = 'Уже назначен ящик по умолчанию для указанного типа';
-?>
diff --git a/lib/plugins/libkolab/LICENSE b/lib/plugins/libkolab/LICENSE
deleted file mode 100644
index dba13ed..0000000
--- a/lib/plugins/libkolab/LICENSE
+++ /dev/null
@@ -1,661 +0,0 @@
- GNU AFFERO GENERAL PUBLIC LICENSE
- Version 3, 19 November 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU Affero General Public License is a free, copyleft license for
-software and other kinds of works, specifically designed to ensure
-cooperation with the community in the case of network server software.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-our General Public Licenses are intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- Developers that use our General Public Licenses protect your rights
-with two steps: (1) assert copyright on the software, and (2) offer
-you this License which gives you legal permission to copy, distribute
-and/or modify the software.
-
- A secondary benefit of defending all users' freedom is that
-improvements made in alternate versions of the program, if they
-receive widespread use, become available for other developers to
-incorporate. Many developers of free software are heartened and
-encouraged by the resulting cooperation. However, in the case of
-software used on network servers, this result may fail to come about.
-The GNU General Public License permits making a modified version and
-letting the public access it on a server without ever releasing its
-source code to the public.
-
- The GNU Affero General Public License is designed specifically to
-ensure that, in such cases, the modified source code becomes available
-to the community. It requires the operator of a network server to
-provide the source code of the modified version running there to the
-users of that server. Therefore, public use of a modified version, on
-a publicly accessible server, gives the public access to the source
-code of the modified version.
-
- An older license, called the Affero General Public License and
-published by Affero, was designed to accomplish similar goals. This is
-a different license, not a version of the Affero GPL, but Affero has
-released a new version of the Affero GPL which permits relicensing under
-this license.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU Affero General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Remote Network Interaction; Use with the GNU General Public License.
-
- Notwithstanding any other provision of this License, if you modify the
-Program, your modified version must prominently offer all users
-interacting with it remotely through a computer network (if your version
-supports such interaction) an opportunity to receive the Corresponding
-Source of your version by providing access to the Corresponding Source
-from a network server at no charge, through some standard or customary
-means of facilitating copying of software. This Corresponding Source
-shall include the Corresponding Source for any work covered by version 3
-of the GNU General Public License that is incorporated pursuant to the
-following paragraph.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the work with which it is combined will remain governed by version
-3 of the GNU General Public License.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU Affero General Public License from time to time. Such new versions
-will be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU Affero General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU Affero General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU Affero General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- 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 Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If your software can interact with users remotely through a computer
-network, you should also make sure that it provides a way for users to
-get its source. For example, if your program is a web application, its
-interface could display a "Source" link that leads users to an archive
-of the code. There are many ways you could offer source, and different
-solutions will be better for different programs; see section 13 for the
-specific requirements.
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU AGPL, see
-<http://www.gnu.org/licenses/>.
diff --git a/lib/plugins/libkolab/README b/lib/plugins/libkolab/README
deleted file mode 100644
index 2f94839..0000000
--- a/lib/plugins/libkolab/README
+++ /dev/null
@@ -1,28 +0,0 @@
-libkolab plugin to access to Kolab groupware data
-=================================================
-
-The contained library classes establish a connection to the Kolab server
-and manage the access to the Kolab groupware objects stored in various
-IMAP folders. For reading and writing these objects, the PHP bindings of
-the libkolabxml library are used.
-
-
-REQUIREMENTS
-------------
-* libkolabxml PHP bindings
- - kolabformat.so loaded into PHP
- - kolabformat.php placed somewhere in the include_path
-* PEAR: HTTP/Request2
-* PEAR: Net/URL2
-
-
-INSTALLATION
-------------
-To use local cache you need to create a dedicated table in Roundcube's database.
-To do so, execute the SQL commands in SQL/<yourdatabase>.initial.sql
-
-
-CONFIGURATION
--------------
-Rename config.inc.php.dist to config.inc.php in the plugin folder.
-For available configuration options see config.inc.php.dist file.
diff --git a/lib/plugins/libkolab/SQL/mysql.initial.sql b/lib/plugins/libkolab/SQL/mysql.initial.sql
deleted file mode 100644
index 98e7e78..0000000
--- a/lib/plugins/libkolab/SQL/mysql.initial.sql
+++ /dev/null
@@ -1,187 +0,0 @@
-/**
- * libkolab database schema
- *
- * @version 1.1
- * @author Thomas Bruederli
- * @licence GNU AGPL
- **/
-
-
-DROP TABLE IF EXISTS `kolab_folders`;
-
-CREATE TABLE `kolab_folders` (
- `folder_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
- `resource` VARCHAR(255) NOT NULL,
- `type` VARCHAR(32) NOT NULL,
- `synclock` INT(10) NOT NULL DEFAULT '0',
- `ctag` VARCHAR(40) DEFAULT NULL,
- PRIMARY KEY(`folder_id`),
- INDEX `resource_type` (`resource`, `type`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-DROP TABLE IF EXISTS `kolab_cache`;
-
-DROP TABLE IF EXISTS `kolab_cache_contact`;
-
-CREATE TABLE `kolab_cache_contact` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` LONGTEXT NOT NULL,
- `xml` LONGBLOB NOT NULL,
- `tags` TEXT NOT NULL,
- `words` TEXT NOT NULL,
- `type` VARCHAR(32) CHARACTER SET ascii NOT NULL,
- `name` VARCHAR(255) NOT NULL,
- `firstname` VARCHAR(255) NOT NULL,
- `surname` VARCHAR(255) NOT NULL,
- `email` VARCHAR(255) NOT NULL,
- CONSTRAINT `fk_kolab_cache_contact_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`),
- INDEX `contact_type` (`folder_id`,`type`),
- INDEX `contact_uid2msguid` (`folder_id`,`uid`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-DROP TABLE IF EXISTS `kolab_cache_event`;
-
-CREATE TABLE `kolab_cache_event` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` LONGTEXT NOT NULL,
- `xml` LONGBLOB NOT NULL,
- `tags` TEXT NOT NULL,
- `words` TEXT NOT NULL,
- `dtstart` DATETIME,
- `dtend` DATETIME,
- CONSTRAINT `fk_kolab_cache_event_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`),
- INDEX `event_uid2msguid` (`folder_id`,`uid`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-DROP TABLE IF EXISTS `kolab_cache_task`;
-
-CREATE TABLE `kolab_cache_task` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` LONGTEXT NOT NULL,
- `xml` LONGBLOB NOT NULL,
- `tags` TEXT NOT NULL,
- `words` TEXT NOT NULL,
- `dtstart` DATETIME,
- `dtend` DATETIME,
- CONSTRAINT `fk_kolab_cache_task_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`),
- INDEX `task_uid2msguid` (`folder_id`,`uid`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-DROP TABLE IF EXISTS `kolab_cache_journal`;
-
-CREATE TABLE `kolab_cache_journal` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` LONGTEXT NOT NULL,
- `xml` LONGBLOB NOT NULL,
- `tags` TEXT NOT NULL,
- `words` TEXT NOT NULL,
- `dtstart` DATETIME,
- `dtend` DATETIME,
- CONSTRAINT `fk_kolab_cache_journal_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`),
- INDEX `journal_uid2msguid` (`folder_id`,`uid`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-DROP TABLE IF EXISTS `kolab_cache_note`;
-
-CREATE TABLE `kolab_cache_note` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` LONGTEXT NOT NULL,
- `xml` LONGBLOB NOT NULL,
- `tags` TEXT NOT NULL,
- `words` TEXT NOT NULL,
- CONSTRAINT `fk_kolab_cache_note_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`),
- INDEX `note_uid2msguid` (`folder_id`,`uid`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-DROP TABLE IF EXISTS `kolab_cache_file`;
-
-CREATE TABLE `kolab_cache_file` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` LONGTEXT NOT NULL,
- `xml` LONGBLOB NOT NULL,
- `tags` TEXT NOT NULL,
- `words` TEXT NOT NULL,
- `filename` varchar(255) DEFAULT NULL,
- CONSTRAINT `fk_kolab_cache_file_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`),
- INDEX `folder_filename` (`folder_id`, `filename`),
- INDEX `file_uid2msguid` (`folder_id`,`uid`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-DROP TABLE IF EXISTS `kolab_cache_configuration`;
-
-CREATE TABLE `kolab_cache_configuration` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` LONGTEXT NOT NULL,
- `xml` LONGBLOB NOT NULL,
- `tags` TEXT NOT NULL,
- `words` TEXT NOT NULL,
- `type` VARCHAR(32) CHARACTER SET ascii NOT NULL,
- CONSTRAINT `fk_kolab_cache_configuration_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`),
- INDEX `configuration_type` (`folder_id`,`type`),
- INDEX `configuration_uid2msguid` (`folder_id`,`uid`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-DROP TABLE IF EXISTS `kolab_cache_freebusy`;
-
-CREATE TABLE `kolab_cache_freebusy` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` LONGTEXT NOT NULL,
- `xml` LONGBLOB NOT NULL,
- `tags` TEXT NOT NULL,
- `words` TEXT NOT NULL,
- `dtstart` DATETIME,
- `dtend` DATETIME,
- CONSTRAINT `fk_kolab_cache_freebusy_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`),
- INDEX `freebusy_uid2msguid` (`folder_id`,`uid`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-
-INSERT INTO `system` (`name`, `value`) VALUES ('libkolab-version', '2015011600');
diff --git a/lib/plugins/libkolab/SQL/mysql/2013011000.sql b/lib/plugins/libkolab/SQL/mysql/2013011000.sql
deleted file mode 100644
index fe6741a..0000000
--- a/lib/plugins/libkolab/SQL/mysql/2013011000.sql
+++ /dev/null
@@ -1 +0,0 @@
--- empty
\ No newline at end of file
diff --git a/lib/plugins/libkolab/SQL/mysql/2013041900.sql b/lib/plugins/libkolab/SQL/mysql/2013041900.sql
deleted file mode 100644
index 76577e6..0000000
--- a/lib/plugins/libkolab/SQL/mysql/2013041900.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-DELETE FROM `kolab_cache` WHERE `type` = 'file';
-ALTER TABLE `kolab_cache` ADD `filename` varchar(255) DEFAULT NULL;
-ALTER TABLE `kolab_cache` ADD INDEX `resource_filename` (`resource`, `filename`);
diff --git a/lib/plugins/libkolab/SQL/mysql/2013100400.sql b/lib/plugins/libkolab/SQL/mysql/2013100400.sql
deleted file mode 100644
index d41d0e1..0000000
--- a/lib/plugins/libkolab/SQL/mysql/2013100400.sql
+++ /dev/null
@@ -1,174 +0,0 @@
-CREATE TABLE `kolab_folders` (
- `folder_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
- `resource` VARCHAR(255) NOT NULL,
- `type` VARCHAR(32) NOT NULL,
- `synclock` INT(10) NOT NULL DEFAULT '0',
- `ctag` VARCHAR(40) DEFAULT NULL,
- PRIMARY KEY(`folder_id`),
- INDEX `resource_type` (`resource`, `type`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-CREATE TABLE `kolab_cache_contact` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` TEXT NOT NULL,
- `xml` TEXT NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
- `words` TEXT NOT NULL,
- `type` VARCHAR(32) CHARACTER SET ascii NOT NULL,
- CONSTRAINT `fk_kolab_cache_contact_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`),
- INDEX `contact_type` (`folder_id`,`type`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-CREATE TABLE `kolab_cache_event` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` TEXT NOT NULL,
- `xml` TEXT NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
- `words` TEXT NOT NULL,
- `dtstart` DATETIME,
- `dtend` DATETIME,
- CONSTRAINT `fk_kolab_cache_event_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-CREATE TABLE `kolab_cache_task` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` TEXT NOT NULL,
- `xml` TEXT NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
- `words` TEXT NOT NULL,
- `dtstart` DATETIME,
- `dtend` DATETIME,
- CONSTRAINT `fk_kolab_cache_task_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-CREATE TABLE `kolab_cache_journal` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` TEXT NOT NULL,
- `xml` TEXT NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
- `words` TEXT NOT NULL,
- `dtstart` DATETIME,
- `dtend` DATETIME,
- CONSTRAINT `fk_kolab_cache_journal_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-CREATE TABLE `kolab_cache_note` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` TEXT NOT NULL,
- `xml` TEXT NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
- `words` TEXT NOT NULL,
- CONSTRAINT `fk_kolab_cache_note_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-CREATE TABLE `kolab_cache_file` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` TEXT NOT NULL,
- `xml` TEXT NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
- `words` TEXT NOT NULL,
- `filename` varchar(255) DEFAULT NULL,
- CONSTRAINT `fk_kolab_cache_file_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`),
- INDEX `folder_filename` (`folder_id`, `filename`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-CREATE TABLE `kolab_cache_configuration` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` TEXT NOT NULL,
- `xml` TEXT NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
- `words` TEXT NOT NULL,
- `type` VARCHAR(32) CHARACTER SET ascii NOT NULL,
- CONSTRAINT `fk_kolab_cache_configuration_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`),
- INDEX `configuration_type` (`folder_id`,`type`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-CREATE TABLE `kolab_cache_freebusy` (
- `folder_id` BIGINT UNSIGNED NOT NULL,
- `msguid` BIGINT UNSIGNED NOT NULL,
- `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
- `created` DATETIME DEFAULT NULL,
- `changed` DATETIME DEFAULT NULL,
- `data` TEXT NOT NULL,
- `xml` TEXT NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
- `words` TEXT NOT NULL,
- `dtstart` DATETIME,
- `dtend` DATETIME,
- CONSTRAINT `fk_kolab_cache_freebusy_folder` FOREIGN KEY (`folder_id`)
- REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY(`folder_id`,`msguid`)
-) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-
-
--- Migrate data from old kolab_cache table
-
-INSERT INTO kolab_folders (resource, type)
- SELECT DISTINCT resource, type
- FROM kolab_cache WHERE type IN ('event','contact','task','file');
-
-INSERT INTO kolab_cache_event (folder_id, msguid, uid, created, changed, data, xml, tags, words, dtstart, dtend)
- SELECT kolab_folders.folder_id, msguid, uid, created, changed, data, xml, tags, words, dtstart, dtend
- FROM kolab_cache LEFT JOIN kolab_folders ON (kolab_folders.resource = kolab_cache.resource)
- WHERE kolab_cache.type = 'event' AND kolab_folders.folder_id IS NOT NULL;
-
-INSERT INTO kolab_cache_task (folder_id, msguid, uid, created, changed, data, xml, tags, words, dtstart, dtend)
- SELECT kolab_folders.folder_id, msguid, uid, created, changed, data, xml, tags, words, dtstart, dtend
- FROM kolab_cache LEFT JOIN kolab_folders ON (kolab_folders.resource = kolab_cache.resource)
- WHERE kolab_cache.type = 'task' AND kolab_folders.folder_id IS NOT NULL;
-
-INSERT INTO kolab_cache_contact (folder_id, msguid, uid, created, changed, data, xml, tags, words, type)
- SELECT kolab_folders.folder_id, msguid, uid, created, changed, data, xml, tags, words, kolab_cache.type
- FROM kolab_cache LEFT JOIN kolab_folders ON (kolab_folders.resource = kolab_cache.resource)
- WHERE kolab_cache.type IN ('contact','distribution-list') AND kolab_folders.folder_id IS NOT NULL;
-
-INSERT INTO kolab_cache_file (folder_id, msguid, uid, created, changed, data, xml, tags, words, filename)
- SELECT kolab_folders.folder_id, msguid, uid, created, changed, data, xml, tags, words, filename
- FROM kolab_cache LEFT JOIN kolab_folders ON (kolab_folders.resource = kolab_cache.resource)
- WHERE kolab_cache.type = 'file' AND kolab_folders.folder_id IS NOT NULL;
-
-
-DROP TABLE IF EXISTS `kolab_cache`;
-
diff --git a/lib/plugins/libkolab/SQL/mysql/2013110400.sql b/lib/plugins/libkolab/SQL/mysql/2013110400.sql
deleted file mode 100644
index 5b7a9ef..0000000
--- a/lib/plugins/libkolab/SQL/mysql/2013110400.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE `kolab_cache_contact` CHANGE `xml` `xml` LONGTEXT NOT NULL;
diff --git a/lib/plugins/libkolab/SQL/mysql/2013121100.sql b/lib/plugins/libkolab/SQL/mysql/2013121100.sql
deleted file mode 100644
index 8cab5ef..0000000
--- a/lib/plugins/libkolab/SQL/mysql/2013121100.sql
+++ /dev/null
@@ -1,13 +0,0 @@
--- well, these deletes are really optional
--- we can clear all caches or only contacts/events/tasks
--- the issue we're fixing here was about contacts (Bug #2662)
-DELETE FROM `kolab_folders` WHERE `type` IN ('contact', 'event', 'task');
-
-ALTER TABLE `kolab_cache_contact` CHANGE `xml` `xml` LONGBLOB NOT NULL;
-ALTER TABLE `kolab_cache_event` CHANGE `xml` `xml` LONGBLOB NOT NULL;
-ALTER TABLE `kolab_cache_task` CHANGE `xml` `xml` LONGBLOB NOT NULL;
-ALTER TABLE `kolab_cache_journal` CHANGE `xml` `xml` LONGBLOB NOT NULL;
-ALTER TABLE `kolab_cache_note` CHANGE `xml` `xml` LONGBLOB NOT NULL;
-ALTER TABLE `kolab_cache_file` CHANGE `xml` `xml` LONGBLOB NOT NULL;
-ALTER TABLE `kolab_cache_configuration` CHANGE `xml` `xml` LONGBLOB NOT NULL;
-ALTER TABLE `kolab_cache_freebusy` CHANGE `xml` `xml` LONGBLOB NOT NULL;
diff --git a/lib/plugins/libkolab/SQL/mysql/2014021000.sql b/lib/plugins/libkolab/SQL/mysql/2014021000.sql
deleted file mode 100644
index 31ce699..0000000
--- a/lib/plugins/libkolab/SQL/mysql/2014021000.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-ALTER TABLE `kolab_cache_contact` ADD `name` VARCHAR(255) NOT NULL,
- ADD `firstname` VARCHAR(255) NOT NULL,
- ADD `surname` VARCHAR(255) NOT NULL,
- ADD `email` VARCHAR(255) NOT NULL;
-
--- updating or clearing all contacts caches is required.
--- either run `bin/modcache.sh update --type=contact` or execute the following query:
--- DELETE FROM `kolab_folders` WHERE `type`='contact';
-
diff --git a/lib/plugins/libkolab/SQL/mysql/2014032700.sql b/lib/plugins/libkolab/SQL/mysql/2014032700.sql
deleted file mode 100644
index a45fae3..0000000
--- a/lib/plugins/libkolab/SQL/mysql/2014032700.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-ALTER TABLE `kolab_cache_configuration` ADD INDEX `configuration_uid2msguid` (`folder_id`, `uid`, `msguid`);
-ALTER TABLE `kolab_cache_contact` ADD INDEX `contact_uid2msguid` (`folder_id`, `uid`, `msguid`);
-ALTER TABLE `kolab_cache_event` ADD INDEX `event_uid2msguid` (`folder_id`, `uid`, `msguid`);
-ALTER TABLE `kolab_cache_task` ADD INDEX `task_uid2msguid` (`folder_id`, `uid`, `msguid`);
-ALTER TABLE `kolab_cache_journal` ADD INDEX `journal_uid2msguid` (`folder_id`, `uid`, `msguid`);
-ALTER TABLE `kolab_cache_note` ADD INDEX `note_uid2msguid` (`folder_id`, `uid`, `msguid`);
-ALTER TABLE `kolab_cache_file` ADD INDEX `file_uid2msguid` (`folder_id`, `uid`, `msguid`);
-ALTER TABLE `kolab_cache_freebusy` ADD INDEX `freebusy_uid2msguid` (`folder_id`, `uid`, `msguid`);
diff --git a/lib/plugins/libkolab/SQL/mysql/2014040900.sql b/lib/plugins/libkolab/SQL/mysql/2014040900.sql
deleted file mode 100644
index cfcaa9d..0000000
--- a/lib/plugins/libkolab/SQL/mysql/2014040900.sql
+++ /dev/null
@@ -1,16 +0,0 @@
-ALTER TABLE `kolab_cache_contact` CHANGE `data` `data` LONGTEXT NOT NULL;
-ALTER TABLE `kolab_cache_event` CHANGE `data` `data` LONGTEXT NOT NULL;
-ALTER TABLE `kolab_cache_task` CHANGE `data` `data` LONGTEXT NOT NULL;
-ALTER TABLE `kolab_cache_journal` CHANGE `data` `data` LONGTEXT NOT NULL;
-ALTER TABLE `kolab_cache_note` CHANGE `data` `data` LONGTEXT NOT NULL;
-ALTER TABLE `kolab_cache_file` CHANGE `data` `data` LONGTEXT NOT NULL;
-ALTER TABLE `kolab_cache_configuration` CHANGE `data` `data` LONGTEXT NOT NULL;
-ALTER TABLE `kolab_cache_freebusy` CHANGE `data` `data` LONGTEXT NOT NULL;
-
--- rebuild cache entries for xcal objects with alarms
-DELETE FROM `kolab_cache_event` WHERE tags LIKE '% x-has-alarms %';
-DELETE FROM `kolab_cache_task` WHERE tags LIKE '% x-has-alarms %';
-
--- force cache synchronization
-UPDATE `kolab_folders` SET ctag='' WHERE `type` IN ('event','task');
-
diff --git a/lib/plugins/libkolab/SQL/mysql/2014112700.sql b/lib/plugins/libkolab/SQL/mysql/2014112700.sql
deleted file mode 100644
index 90c77b8..0000000
--- a/lib/plugins/libkolab/SQL/mysql/2014112700.sql
+++ /dev/null
@@ -1,2 +0,0 @@
--- delete cache entries for old folder identifiers
-DELETE FROM `kolab_folders` WHERE `resource` LIKE 'imap://anonymous@%';
diff --git a/lib/plugins/libkolab/SQL/mysql/2015011600.sql b/lib/plugins/libkolab/SQL/mysql/2015011600.sql
deleted file mode 100644
index be523ae..0000000
--- a/lib/plugins/libkolab/SQL/mysql/2015011600.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-ALTER TABLE `kolab_cache_contact` MODIFY `tags` text NOT NULL;
-ALTER TABLE `kolab_cache_event` MODIFY `tags` text NOT NULL;
-ALTER TABLE `kolab_cache_task` MODIFY `tags` text NOT NULL;
-ALTER TABLE `kolab_cache_journal` MODIFY `tags` text NOT NULL;
-ALTER TABLE `kolab_cache_note` MODIFY `tags` text NOT NULL;
-ALTER TABLE `kolab_cache_file` MODIFY `tags` text NOT NULL;
-ALTER TABLE `kolab_cache_configuration` MODIFY `tags` text NOT NULL;
-ALTER TABLE `kolab_cache_freebusy` MODIFY `tags` text NOT NULL;
diff --git a/lib/plugins/libkolab/SQL/oracle.initial.sql b/lib/plugins/libkolab/SQL/oracle.initial.sql
deleted file mode 100644
index 8f1ed64..0000000
--- a/lib/plugins/libkolab/SQL/oracle.initial.sql
+++ /dev/null
@@ -1,184 +0,0 @@
-/**
- * libkolab database schema
- *
- * @version 1.1
- * @author Aleksander Machniak
- * @licence GNU AGPL
- **/
-
-
-CREATE TABLE "kolab_folders" (
- "folder_id" number NOT NULL PRIMARY KEY,
- "resource" VARCHAR(255) NOT NULL,
- "type" VARCHAR(32) NOT NULL,
- "synclock" integer DEFAULT 0 NOT NULL,
- "ctag" VARCHAR(40) DEFAULT NULL
-);
-
-CREATE INDEX "kolab_folders_resource_idx" ON "kolab_folders" ("resource", "type");
-
-CREATE SEQUENCE "kolab_folders_seq"
- START WITH 1 INCREMENT BY 1 NOMAXVALUE;
-
-CREATE TRIGGER "kolab_folders_seq_trig"
-BEFORE INSERT ON "kolab_folders" FOR EACH ROW
-BEGIN
- :NEW."folder_id" := "kolab_folders_seq".nextval;
-END;
-/
-
-CREATE TABLE "kolab_cache_contact" (
- "folder_id" number NOT NULL
- REFERENCES "kolab_folders" ("folder_id") ON DELETE CASCADE,
- "msguid" number NOT NULL,
- "uid" varchar(128) NOT NULL,
- "created" timestamp DEFAULT NULL,
- "changed" timestamp DEFAULT NULL,
- "data" clob NOT NULL,
- "xml" clob NOT NULL,
- "tags" clob DEFAULT NULL,
- "words" clob DEFAULT NULL,
- "type" varchar(32) NOT NULL,
- "name" varchar(255) DEFAULT NULL,
- "firstname" varchar(255) DEFAULT NULL,
- "surname" varchar(255) DEFAULT NULL,
- "email" varchar(255) DEFAULT NULL,
- PRIMARY KEY ("folder_id", "msguid")
-);
-
-CREATE INDEX "kolab_cache_contact_type_idx" ON "kolab_cache_contact" ("folder_id", "type");
-CREATE INDEX "kolab_cache_contact_uid2msguid" ON "kolab_cache_contact" ("folder_id", "uid", "msguid");
-
-
-CREATE TABLE "kolab_cache_event" (
- "folder_id" number NOT NULL
- REFERENCES "kolab_folders" ("folder_id") ON DELETE CASCADE,
- "msguid" number NOT NULL,
- "uid" varchar(128) NOT NULL,
- "created" timestamp DEFAULT NULL,
- "changed" timestamp DEFAULT NULL,
- "data" clob NOT NULL,
- "xml" clob NOT NULL,
- "tags" clob DEFAULT NULL,
- "words" clob DEFAULT NULL,
- "dtstart" timestamp DEFAULT NULL,
- "dtend" timestamp DEFAULT NULL,
- PRIMARY KEY ("folder_id", "msguid")
-);
-
-CREATE INDEX "kolab_cache_event_uid2msguid" ON "kolab_cache_event" ("folder_id", "uid", "msguid");
-
-
-CREATE TABLE "kolab_cache_task" (
- "folder_id" number NOT NULL
- REFERENCES "kolab_folders" ("folder_id") ON DELETE CASCADE,
- "msguid" number NOT NULL,
- "uid" varchar(128) NOT NULL,
- "created" timestamp DEFAULT NULL,
- "changed" timestamp DEFAULT NULL,
- "data" clob NOT NULL,
- "xml" clob NOT NULL,
- "tags" clob DEFAULT NULL,
- "words" clob DEFAULT NULL,
- "dtstart" timestamp DEFAULT NULL,
- "dtend" timestamp DEFAULT NULL,
- PRIMARY KEY ("folder_id", "msguid")
-);
-
-CREATE INDEX "kolab_cache_task_uid2msguid" ON "kolab_cache_task" ("folder_id", "uid", "msguid");
-
-
-CREATE TABLE "kolab_cache_journal" (
- "folder_id" number NOT NULL
- REFERENCES "kolab_folders" ("folder_id") ON DELETE CASCADE,
- "msguid" number NOT NULL,
- "uid" varchar(128) NOT NULL,
- "created" timestamp DEFAULT NULL,
- "changed" timestamp DEFAULT NULL,
- "data" clob NOT NULL,
- "xml" clob NOT NULL,
- "tags" clob DEFAULT NULL,
- "words" clob DEFAULT NULL,
- "dtstart" timestamp DEFAULT NULL,
- "dtend" timestamp DEFAULT NULL,
- PRIMARY KEY ("folder_id", "msguid")
-);
-
-CREATE INDEX "kolab_cache_journal_uid2msguid" ON "kolab_cache_journal" ("folder_id", "uid", "msguid");
-
-
-CREATE TABLE "kolab_cache_note" (
- "folder_id" number NOT NULL
- REFERENCES "kolab_folders" ("folder_id") ON DELETE CASCADE,
- "msguid" number NOT NULL,
- "uid" varchar(128) NOT NULL,
- "created" timestamp DEFAULT NULL,
- "changed" timestamp DEFAULT NULL,
- "data" clob NOT NULL,
- "xml" clob NOT NULL,
- "tags" clob DEFAULT NULL,
- "words" clob DEFAULT NULL,
- PRIMARY KEY ("folder_id", "msguid")
-);
-
-CREATE INDEX "kolab_cache_note_uid2msguid" ON "kolab_cache_note" ("folder_id", "uid", "msguid");
-
-
-CREATE TABLE "kolab_cache_file" (
- "folder_id" number NOT NULL
- REFERENCES "kolab_folders" ("folder_id") ON DELETE CASCADE,
- "msguid" number NOT NULL,
- "uid" varchar(128) NOT NULL,
- "created" timestamp DEFAULT NULL,
- "changed" timestamp DEFAULT NULL,
- "data" clob NOT NULL,
- "xml" clob NOT NULL,
- "tags" clob DEFAULT NULL,
- "words" clob DEFAULT NULL,
- "filename" varchar(255) DEFAULT NULL,
- PRIMARY KEY ("folder_id", "msguid")
-);
-
-CREATE INDEX "kolab_cache_file_filename" ON "kolab_cache_file" ("folder_id", "filename");
-CREATE INDEX "kolab_cache_file_uid2msguid" ON "kolab_cache_file" ("folder_id", "uid", "msguid");
-
-
-CREATE TABLE "kolab_cache_configuration" (
- "folder_id" number NOT NULL
- REFERENCES "kolab_folders" ("folder_id") ON DELETE CASCADE,
- "msguid" number NOT NULL,
- "uid" varchar(128) NOT NULL,
- "created" timestamp DEFAULT NULL,
- "changed" timestamp DEFAULT NULL,
- "data" clob NOT NULL,
- "xml" clob NOT NULL,
- "tags" clob DEFAULT NULL,
- "words" clob DEFAULT NULL,
- "type" varchar(32) NOT NULL,
- PRIMARY KEY ("folder_id", "msguid")
-);
-
-CREATE INDEX "kolab_cache_config_type" ON "kolab_cache_configuration" ("folder_id", "type");
-CREATE INDEX "kolab_cache_config_uid2msguid" ON "kolab_cache_configuration" ("folder_id", "uid", "msguid");
-
-
-CREATE TABLE "kolab_cache_freebusy" (
- "folder_id" number NOT NULL
- REFERENCES "kolab_folders" ("folder_id") ON DELETE CASCADE,
- "msguid" number NOT NULL,
- "uid" varchar(128) NOT NULL,
- "created" timestamp DEFAULT NULL,
- "changed" timestamp DEFAULT NULL,
- "data" clob NOT NULL,
- "xml" clob NOT NULL,
- "tags" clob DEFAULT NULL,
- "words" clob DEFAULT NULL,
- "dtstart" timestamp DEFAULT NULL,
- "dtend" timestamp DEFAULT NULL,
- PRIMARY KEY("folder_id", "msguid")
-);
-
-CREATE INDEX "kolab_cache_fb_uid2msguid" ON "kolab_cache_freebusy" ("folder_id", "uid", "msguid");
-
-
-INSERT INTO "system" ("name", "value") VALUES ('libkolab-version', '2015011600');
diff --git a/lib/plugins/libkolab/SQL/oracle/2015011600.sql b/lib/plugins/libkolab/SQL/oracle/2015011600.sql
deleted file mode 100644
index 69f7953..0000000
--- a/lib/plugins/libkolab/SQL/oracle/2015011600.sql
+++ /dev/null
@@ -1,40 +0,0 @@
--- direct change from varchar to clob does not work, need temp column (#4257)
-ALTER TABLE "kolab_cache_contact" ADD "tags1" clob DEFAULT NULL;
-UPDATE "kolab_cache_contact" SET "tags1" = "tags";
-ALTER TABLE "kolab_cache_contact" DROP COLUMN "tags";
-ALTER TABLE "kolab_cache_contact" RENAME COLUMN "tags1" TO "tags";
-
-ALTER TABLE "kolab_cache_event" ADD "tags1" clob DEFAULT NULL;
-UPDATE "kolab_cache_event" SET "tags1" = "tags";
-ALTER TABLE "kolab_cache_event" DROP COLUMN "tags";
-ALTER TABLE "kolab_cache_event" RENAME COLUMN "tags1" TO "tags";
-
-ALTER TABLE "kolab_cache_task" ADD "tags1" clob DEFAULT NULL;
-UPDATE "kolab_cache_task" SET "tags1" = "tags";
-ALTER TABLE "kolab_cache_task" DROP COLUMN "tags";
-ALTER TABLE "kolab_cache_task" RENAME COLUMN "tags1" TO "tags";
-
-ALTER TABLE "kolab_cache_journal" ADD "tags1" clob DEFAULT NULL;
-UPDATE "kolab_cache_journal" SET "tags1" = "tags";
-ALTER TABLE "kolab_cache_journal" DROP COLUMN "tags";
-ALTER TABLE "kolab_cache_journal" RENAME COLUMN "tags1" TO "tags";
-
-ALTER TABLE "kolab_cache_note" ADD "tags1" clob DEFAULT NULL;
-UPDATE "kolab_cache_note" SET "tags1" = "tags";
-ALTER TABLE "kolab_cache_note" DROP COLUMN "tags";
-ALTER TABLE "kolab_cache_note" RENAME COLUMN "tags1" TO "tags";
-
-ALTER TABLE "kolab_cache_file" ADD "tags1" clob DEFAULT NULL;
-UPDATE "kolab_cache_file" SET "tags1" = "tags";
-ALTER TABLE "kolab_cache_file" DROP COLUMN "tags";
-ALTER TABLE "kolab_cache_file" RENAME COLUMN "tags1" TO "tags";
-
-ALTER TABLE "kolab_cache_configuration" ADD "tags1" clob DEFAULT NULL;
-UPDATE "kolab_cache_configuration" SET "tags1" = "tags";
-ALTER TABLE "kolab_cache_configuration" DROP COLUMN "tags";
-ALTER TABLE "kolab_cache_configuration" RENAME COLUMN "tags1" TO "tags";
-
-ALTER TABLE "kolab_cache_freebusy" ADD "tags1" clob DEFAULT NULL;
-UPDATE "kolab_cache_freebusy" SET "tags1" = "tags";
-ALTER TABLE "kolab_cache_freebusy" DROP COLUMN "tags";
-ALTER TABLE "kolab_cache_freebusy" RENAME COLUMN "tags1" TO "tags";
diff --git a/lib/plugins/libkolab/SQL/postgres.initial.sql b/lib/plugins/libkolab/SQL/postgres.initial.sql
deleted file mode 100644
index e06346c..0000000
--- a/lib/plugins/libkolab/SQL/postgres.initial.sql
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * libkolab database schema
- *
- * @version @package_version@
- * @author Sidlyarenko Sergey
- * @licence GNU AGPL
- **/
-
-DROP TABLE IF EXISTS kolab_cache;
-
-CREATE TABLE kolab_cache (
- resource character varying(255) NOT NULL,
- type character varying(32) NOT NULL,
- msguid NUMERIC(20) NOT NULL,
- uid character varying(128) NOT NULL,
- created timestamp without time zone DEFAULT NULL,
- changed timestamp without time zone DEFAULT NULL,
- data text NOT NULL,
- xml text NOT NULL,
- dtstart timestamp without time zone,
- dtend timestamp without time zone,
- tags character varying(255) NOT NULL,
- words text NOT NULL,
- filename character varying(255) DEFAULT NULL,
- PRIMARY KEY(resource, type, msguid)
-);
-
-CREATE INDEX kolab_cache_resource_filename_idx ON kolab_cache (resource, filename);
-
-
-INSERT INTO system (name, value) VALUES ('libkolab-version', '2013041900');
diff --git a/lib/plugins/libkolab/UPGRADING b/lib/plugins/libkolab/UPGRADING
deleted file mode 100644
index e7f04d8..0000000
--- a/lib/plugins/libkolab/UPGRADING
+++ /dev/null
@@ -1,9 +0,0 @@
-UPGRADING instructions
-======================
-
-To update database schema please run in Roundcube bin/ directory:
-
-updatedb.sh --package=libkolab --version=<version> --dir=../plugins/libkolab/SQL
-
-[*] Replace <version> with Roundcube version e.g. 0.7.3
-[*] Roundcube should be upgraded before plugin upgrades
diff --git a/lib/plugins/libkolab/bin/modcache.sh b/lib/plugins/libkolab/bin/modcache.sh
deleted file mode 100755
index 533fefd..0000000
--- a/lib/plugins/libkolab/bin/modcache.sh
+++ /dev/null
@@ -1,235 +0,0 @@
-#!/usr/bin/env php
-<?php
-
-/**
- * Kolab storage cache modification script
- *
- * @version 3.1
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012-2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-define('INSTALL_PATH', realpath('.') . '/' );
-ini_set('display_errors', 1);
-
-if (!file_exists(INSTALL_PATH . 'program/include/clisetup.php'))
- die("Execute this from the Roundcube installation dir!\n\n");
-
-require_once INSTALL_PATH . 'program/include/clisetup.php';
-
-function print_usage()
-{
- print "Usage: modcache.sh [OPTIONS] ACTION [USERNAME ARGS ...]\n";
- print "Possible actions are: expunge, clear, prewarm\n";
- print "-a, --all Clear/expunge all caches\n";
- print "-h, --host IMAP host name\n";
- print "-u, --user IMAP user name to authenticate\n";
- print "-t, --type Object types to clear/expunge cache\n";
- print "-l, --limit Limit the number of records to be expunged\n";
-}
-
-// read arguments
-$opts = get_opt(array(
- 'a' => 'all',
- 'h' => 'host',
- 'u' => 'user',
- 'p' => 'password',
- 't' => 'type',
- 'l' => 'limit',
- 'v' => 'verbose',
-));
-
-$opts['username'] = !empty($opts[1]) ? $opts[1] : $opts['user'];
-$action = $opts[0];
-
-$rcmail = rcube::get_instance(rcube::INIT_WITH_DB | rcube::INIT_WITH_PLUGINS);
-
-
-// connect to database
-$db = $rcmail->get_dbh();
-$db->db_connect('w');
-if (!$db->is_connected() || $db->is_error())
- die("No DB connection\n");
-
-ini_set('display_errors', 1);
-
-/*
- * Script controller
- */
-switch (strtolower($action)) {
-
-/*
- * Clear/expunge all cache records
- */
-case 'expunge':
- $folder_types = $opts['type'] ? explode(',', $opts['type']) : array('contact','configuration','event','file','journal','note','task');
- $folder_types_db = array_map(array($db, 'quote'), $folder_types);
- $expire = strtotime(!empty($opts[2]) ? $opts[2] : 'now - 10 days');
- $sql_where = "type IN (" . join(',', $folder_types_db) . ")";
-
- if ($opts['username']) {
- $sql_where .= ' AND resource LIKE ?';
- }
-
- $sql_query = "DELETE FROM %s WHERE folder_id IN (SELECT folder_id FROM kolab_folders WHERE $sql_where) AND created <= " . $db->quote(date('Y-m-d 00:00:00', $expire));
- if ($opts['limit']) {
- $sql_query = ' LIMIT ' . intval($opts['limit']);
- }
- foreach ($folder_types as $type) {
- $table_name = 'kolab_cache_' . $type;
- $db->query(sprintf($sql_query, $table_name), resource_prefix($opts).'%');
- echo $db->affected_rows() . " records deleted from '$table_name'\n";
- }
-
- $db->query("UPDATE kolab_folders SET ctag='' WHERE $sql_where", resource_prefix($opts).'%');
- break;
-
-case 'clear':
- $folder_types = $opts['type'] ? explode(',', $opts['type']) : array('contact','configuration','event','file','journal','note','task');
- $folder_types_db = array_map(array($db, 'quote'), $folder_types);
-
- if ($opts['all']) {
- $sql_query = "DELETE FROM kolab_folders WHERE 1";
- }
- else if ($opts['username']) {
- $sql_query = "DELETE FROM kolab_folders WHERE type IN (" . join(',', $folder_types_db) . ") AND resource LIKE ?";
- }
-
- if ($sql_query) {
- $db->query($sql_query, resource_prefix($opts).'%');
- echo $db->affected_rows() . " records deleted from 'kolab_folders'\n";
- }
- break;
-
-
-/*
- * Prewarm cache by synchronizing objects for the given user
- */
-case 'prewarm':
- // make sure libkolab classes are loaded
- $rcmail->plugins->load_plugin('libkolab');
-
- if (authenticate($opts)) {
- $folder_types = $opts['type'] ? explode(',', $opts['type']) : array('contact','configuration','event','file','task');
- foreach ($folder_types as $type) {
- // sync every folder of the given type
- foreach (kolab_storage::get_folders($type) as $folder) {
- echo "Synching " . $folder->name . " ($type) ... ";
- echo $folder->count($type) . "\n";
-
- // also sync distribution lists in contact folders
- if ($type == 'contact') {
- echo "Synching " . $folder->name . " (distribution-list) ... ";
- echo $folder->count('distribution-list') . "\n";
- }
- }
- }
- }
- else
- die("Authentication failed for " . $opts['user']);
- break;
-
-/**
- * Update the cache meta columns from the serialized/xml data
- * (might be run after a schema update)
- */
-case 'update':
- // make sure libkolab classes are loaded
- $rcmail->plugins->load_plugin('libkolab');
-
- $folder_types = $opts['type'] ? explode(',', $opts['type']) : array('contact','configuration','event','file','task');
- foreach ($folder_types as $type) {
- $class = 'kolab_storage_cache_' . $type;
- $sql_result = $db->query("SELECT folder_id FROM kolab_folders WHERE type=? AND synclock = 0", $type);
- while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) {
- $folder = new $class;
- $folder->select_by_id($sql_arr['folder_id']);
- echo "Updating " . $sql_arr['folder_id'] . " ($type) ";
- foreach ($folder->select() as $object) {
- $object['_formatobj']->to_array(); // load data
- $folder->save($object['_msguid'], $object, $object['_msguid']);
- echo ".";
- }
- echo "done.\n";
- }
- }
- break;
-
-
-/*
- * Unknown action => show usage
- */
-default:
- print_usage();
- exit;
-}
-
-
-/**
- * Compose cache resource URI prefix for the given user credentials
- */
-function resource_prefix($opts)
-{
- return 'imap://' . str_replace('%', '\\%', urlencode($opts['username'])) . '@' . $opts['host'] . '/';
-}
-
-
-/**
- * Authenticate to the IMAP server with the given user credentials
- */
-function authenticate(&$opts)
-{
- global $rcmail;
-
- // prompt for password
- if (empty($opts['password']) && ($opts['username'] || $opts['user'])) {
- $opts['password'] = prompt_silent("Password: ");
- }
-
- // simulate "login as" feature
- if ($opts['user'] && $opts['user'] != $opts['username'])
- $_POST['_loginas'] = $opts['username'];
- else if (empty($opts['user']))
- $opts['user'] = $opts['username'];
-
- // let the kolab_auth plugin do its magic
- $auth = $rcmail->plugins->exec_hook('authenticate', array(
- 'host' => trim($opts['host']),
- 'user' => trim($opts['user']),
- 'pass' => $opts['password'],
- 'cookiecheck' => false,
- 'valid' => !empty($opts['user']) && !empty($opts['host']),
- ));
-
- if ($auth['valid']) {
- $storage = $rcmail->get_storage();
- if ($storage->connect($auth['host'], $auth['user'], $auth['pass'], 143, false)) {
- if ($opts['verbose'])
- echo "IMAP login succeeded.\n";
- if (($user = rcube_user::query($opts['username'], $auth['host'])) && $user->ID)
- $rcmail->user = $user;
- }
- else
- die("Login to IMAP server failed!\n");
- }
- else {
- die("Invalid login credentials!\n");
- }
-
- return $auth['valid'];
-}
-
diff --git a/lib/plugins/libkolab/bin/randomcontacts.sh b/lib/plugins/libkolab/bin/randomcontacts.sh
deleted file mode 100755
index e4a820c..0000000
--- a/lib/plugins/libkolab/bin/randomcontacts.sh
+++ /dev/null
@@ -1,181 +0,0 @@
-#!/usr/bin/env php
-<?php
-
-/**
- * Generate a number contacts with random data
- *
- * @version 3.1
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-define('INSTALL_PATH', realpath('.') . '/' );
-ini_set('display_errors', 1);
-
-if (!file_exists(INSTALL_PATH . 'program/include/clisetup.php'))
- die("Execute this from the Roundcube installation dir!\n\n");
-
-require_once INSTALL_PATH . 'program/include/clisetup.php';
-
-function print_usage()
-{
- print "Usage: randomcontacts.sh [OPTIONS] USERNAME FOLDER\n";
- print "Create random contact that for then given user in the specified folder.\n";
- print "-n, --num Number of contacts to be created, defaults to 50\n";
- print "-h, --host IMAP host name\n";
- print "-p, --password IMAP user password\n";
-}
-
-// read arguments
-$opts = get_opt(array(
- 'n' => 'num',
- 'h' => 'host',
- 'u' => 'user',
- 'p' => 'pass',
- 'v' => 'verbose',
-));
-
-$opts['username'] = !empty($opts[0]) ? $opts[0] : $opts['user'];
-$opts['folder'] = $opts[1];
-
-$rcmail = rcube::get_instance(rcube::INIT_WITH_DB | rcube::INIT_WITH_PLUGINS);
-$rcmail->plugins->load_plugins(array('libkolab'));
-ini_set('display_errors', 1);
-
-
-if (empty($opts['host'])) {
- $opts['host'] = $rcmail->config->get('default_host');
- if (is_array($opts['host'])) // not unique
- $opts['host'] = null;
-}
-
-if (empty($opts['username']) || empty($opts['folder']) || empty($opts['host'])) {
- print_usage();
- exit;
-}
-
-// prompt for password
-if (empty($opts['pass'])) {
- $opts['pass'] = rcube_utils::prompt_silent("Password: ");
-}
-
-// parse $host URL
-$a_host = parse_url($opts['host']);
-if ($a_host['host']) {
- $host = $a_host['host'];
- $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? TRUE : FALSE;
- $imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143);
-}
-else {
- $host = $opts['host'];
- $imap_port = 143;
-}
-
-// instantiate IMAP class
-$IMAP = $rcmail->get_storage();
-
-// try to connect to IMAP server
-if ($IMAP->connect($host, $opts['username'], $opts['pass'], $imap_port, $imap_ssl)) {
- print "IMAP login successful.\n";
- $user = rcube_user::query($opts['username'], $host);
- $rcmail->user = $user ?: new rcube_user(null, array('username' => $opts['username'], 'host' => $host));
-}
-else {
- die("IMAP login failed for user " . $opts['username'] . " @ $host\n");
-}
-
-// get contacts folder
-$folder = kolab_storage::get_folder($opts['folder']);
-if (!$folder || empty($folder->type)) {
- die("Invalid Address Book " . $opts['folder'] . "\n");
-}
-
-$format = new kolab_format_contact;
-
-$num = $opts['num'] ? intval($opts['num']) : 50;
-echo "Creating $num contacts in " . $folder->get_resource_uri() . "\n";
-
-for ($i=0; $i < $num; $i++) {
- // generate random names
- $contact = array(
- 'surname' => random_string(rand(1,2)),
- 'firstname' => random_string(rand(1,2)),
- 'organization' => random_string(rand(0,2)),
- 'profession' => random_string(rand(1,2)),
- 'email' => array(),
- 'phone' => array(),
- 'address' => array(),
- 'notes' => random_string(rand(10,200)),
- );
-
- // randomly add email addresses
- $em = rand(1,3);
- for ($e=0; $e < $em; $e++) {
- $type = array_rand($format->emailtypes);
- $contact['email'][] = array(
- 'address' => strtolower(random_string(1) . '@' . random_string(1) . '.tld'),
- 'type' => $type,
- );
- }
-
- // randomly add phone numbers
- $ph = rand(1,4);
- for ($p=0; $p < $ph; $p++) {
- $type = array_rand($format->phonetypes);
- $contact['phone'][] = array(
- 'number' => '+'.rand(2,8).rand(1,9).rand(1,9).rand(0,9).rand(0,9).rand(0,9).rand(0,9).rand(0,9).rand(0,9).rand(0,9).rand(0,9),
- 'type' => $type,
- );
- }
-
- // randomly add addresses
- $ad = rand(0,2);
- for ($a=0; $a < $ad; $a++) {
- $type = array_rand($format->addresstypes);
- $contact['address'][] = array(
- 'street' => random_string(rand(1,3)),
- 'locality' => random_string(rand(1,2)),
- 'code' => rand(1000, 89999),
- 'country' => random_string(1),
- 'type' => $type,
- );
- }
-
- $contact['name'] = $contact['firstname'] . ' ' . $contact['surname'];
-
- if ($folder->save($contact, 'contact')) {
- echo ".";
- }
- else {
- echo "x";
- break; // abort on error
- }
-}
-
-echo " done.\n";
-
-
-
-function random_string($len)
-{
- $words = explode(" ", "The Hough transform is named after Paul Hough who patented the method in 1962. It is a technique which can be used to isolate features of a particular shape within an image. Because it requires that the desired features be specified in some parametric form, the classical Hough transform is most commonly used for the de- tection of regular curves such as lines, circles, ellipses, etc. A generalized Hough transform can be employed in applications where a simple analytic description of a features is not possible. Due to the computational complexity of the generalized Hough algorithm, we restrict the main focus of this discussion to the classical Hough transform. Despite its domain restrictions, the classical Hough transform hereafter referred to without the classical prefix retains many applications, as most manufac- tured parts and many anatomical parts investigated in medical imagery contain feature boundaries which can be described by regular curves. The main advantage of the Hough transform technique is that it is tolerant of gaps in feature boundary descriptions and is relatively unaffected by image noise.");
- for ($i = 0; $i < $len; $i++) {
- $str .= $words[rand(0,count($words)-1)] . " ";
- }
-
- return rtrim($str);
-}
diff --git a/lib/plugins/libkolab/bin/readcache.sh b/lib/plugins/libkolab/bin/readcache.sh
deleted file mode 100755
index 7e6a3a3..0000000
--- a/lib/plugins/libkolab/bin/readcache.sh
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/usr/bin/env php
-<?php
-
-/**
- * Kolab storage cache testing script
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-define('INSTALL_PATH', realpath('.') . '/' );
-ini_set('display_errors', 1);
-libxml_use_internal_errors(true);
-
-if (!file_exists(INSTALL_PATH . 'program/include/clisetup.php'))
- die("Execute this from the Roundcube installation dir!\n\n");
-
-require_once INSTALL_PATH . 'program/include/clisetup.php';
-
-function print_usage()
-{
- print "Usage: readcache.sh [OPTIONS] FOLDER\n";
- print "-h, --host IMAP host name\n";
- print "-l, --limit Limit the number of records to be listed\n";
-}
-
-// read arguments
-$opts = get_opt(array(
- 'h' => 'host',
- 'l' => 'limit',
- 'v' => 'verbose',
-));
-
-$folder = $opts[0];
-$imap_host = $opts['host'];
-
-$rcmail = rcube::get_instance(rcube::INIT_WITH_DB | rcube::INIT_WITH_PLUGINS);
-
-if (empty($imap_host)) {
- $default_host = $rcmail->config->get('default_host');
- if (is_array($default_host)) {
- list($k,$v) = each($default_host);
- $imap_host = is_numeric($k) ? $v : $k;
- }
- else {
- $imap_host = $default_host;
- }
-
- // strip protocol prefix
- $imap_host = preg_replace('!^[a-z]+://!', '', $imap_host);
-}
-
-if (empty($folder) || empty($imap_host)) {
- print_usage();
- exit;
-}
-
-// connect to database
-$db = $rcmail->get_dbh();
-$db->db_connect('r');
-if (!$db->is_connected() || $db->is_error())
- die("No DB connection\n");
-
-
-// resolve folder_id
-if (!is_numeric($folder)) {
- if (strpos($folder, '@')) {
- list($mailbox, $domain) = explode('@', $folder);
- list($username, $subpath) = explode('/', preg_replace('!^user/!', '', $mailbox), 2);
- $folder_uri = 'imap://' . urlencode($username.'@'.$domain) . '@' . $imap_host . '/' . $subpath;
- }
- else {
- die("Invalid mailbox identifier! Example: user/john.doe/Calendar@example.org\n");
- }
-
- print "Resolving folder $folder_uri...";
- $sql_result = $db->query('SELECT * FROM `kolab_folders` WHERE `resource`=?', $folder_uri);
- if ($sql_result && ($folder_data = $db->fetch_assoc($sql_result))) {
- $folder_id = $folder_data['folder_id'];
- print $folder_id;
- }
- print "\n";
-}
-else {
- $folder_id = intval($folder);
- $sql_result = $db->query('SELECT * FROM `kolab_folders` WHERE `folder_id`=?', $folder_id);
- if ($sql_result) {
- $folder_data = $db->fetch_assoc($sql_result);
- }
-}
-
-if (empty($folder_data)) {
- die("Can't find cache mailbox for '$folder'\n");
-}
-
-print "Querying cache for folder $folder_id ($folder_data[type])...\n";
-
-$extra_cols = array(
- 'event' => array('dtstart','dtend'),
- 'contact' => array('type'),
-);
-
-$cache_table = $db->table_name('kolab_cache_' . $folder_data['type']);
-$extra_cols_ = $extra_cols[$folder_data['type']] ?: array();
-$sql_arr = $db->fetch_assoc($db->query("SELECT COUNT(*) as cnt FROM `$cache_table` WHERE `folder_id`=?", intval($folder_id)));
-
-print "CTag = " . $folder_data['ctag'] . "\n";
-print "Lock = " . $folder_data['synclock'] . "\n";
-print "Count = " . $sql_arr['cnt'] . "\n";
-print "----------------------------------------------------------------------------------\n";
-print "<MSG>\t<UUID>\t<CHANGED>\t<DATA>\t<XML>\t";
-print join("\t", array_map(function($c) { return '<' . strtoupper($c) . '>'; }, $extra_cols_));
-print "\n----------------------------------------------------------------------------------\n";
-
-$result = $db->limitquery("SELECT * FROM `$cache_table` WHERE `folder_id`=?", 0, $opts['limit'], intval($folder_id));
-while ($result && ($sql_arr = $db->fetch_assoc($result))) {
- print $sql_arr['msguid'] . "\t" . $sql_arr['uid'] . "\t" . $sql_arr['changed'];
-
- // try to unserialize data block
- $object = @unserialize(@base64_decode($sql_arr['data']));
- print "\t" . ($object === false ? 'FAIL!' : ($object['uid'] == $sql_arr['uid'] ? 'OK' : '!!!'));
-
- // check XML validity
- $xml = simplexml_load_string($sql_arr['xml']);
- print "\t" . ($xml === false ? 'FAIL!' : 'OK');
-
- // print extra cols
- array_walk($extra_cols_, function($c) use ($sql_arr) {
- print "\t" . $sql_arr[$c];
- });
-
- print "\n";
-}
-
-print "----------------------------------------------------------------------------------\n";
-echo "Done.\n";
diff --git a/lib/plugins/libkolab/composer.json b/lib/plugins/libkolab/composer.json
deleted file mode 100644
index b458df6..0000000
--- a/lib/plugins/libkolab/composer.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "name": "kolab/libkolab",
- "type": "roundcube-plugin",
- "description": "Plugin to setup a basic environment for the interaction with a Kolab server.",
- "homepage": "http://git.kolab.org/roundcubemail-plugins-kolab/",
- "license": "AGPLv3",
- "version": "3.2.3",
- "authors": [
- {
- "name": "Thomas Bruederli",
- "email": "bruederli@kolabsys.com",
- "role": "Lead"
- },
- {
- "name": "Alensader Machniak",
- "email": "machniak@kolabsys.com",
- "role": "Developer"
- }
- ],
- "repositories": [
- {
- "type": "composer",
- "url": "http://plugins.roundcube.net"
- }
- ],
- "require": {
- "php": ">=5.3.0",
- "roundcube/plugin-installer": ">=0.1.3"
- }
-}
diff --git a/lib/plugins/libkolab/config.inc.php.dist b/lib/plugins/libkolab/config.inc.php.dist
deleted file mode 100644
index 7efa8d1..0000000
--- a/lib/plugins/libkolab/config.inc.php.dist
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-
-/* Configuration for libkolab */
-
-// Enable caching of Kolab objects in local database
-$config['kolab_cache'] = true;
-
-// Specify format version to write Kolab objects (must be a string value!)
-$config['kolab_format_version'] = '3.0';
-
-// Optional override of the URL to read and trigger Free/Busy information of Kolab users
-// Defaults to https://<imap-server->/freebusy
-$config['kolab_freebusy_server'] = null;
-
-// Enables listing of only subscribed folders. This e.g. will limit
-// folders in calendar view or available addressbooks
-$config['kolab_use_subscriptions'] = false;
-
-// List any of 'personal','shared','other' namespaces to be excluded from groupware folder listing
-// example: array('other');
-$config['kolab_skip_namespace'] = null;
-
-// Enables the use of displayname folder annotations as introduced in KEP:?
-// for displaying resource folder names (experimental!)
-$config['kolab_custom_display_names'] = false;
-
-// Configuration of HTTP requests.
-// See http://pear.php.net/manual/en/package.http.http-request2.config.php
-// for list of supported configuration options (array keys)
-$config['kolab_http_request'] = array();
-
-// When kolab_cache is enabled Roundcube's messages cache will be redundant
-// when working on kolab folders. Here we can:
-// 2 - bypass messages/indexes cache completely
-// 1 - bypass only messages, but use index cache
-$config['kolab_messages_cache_bypass'] = 0;
-
-// LDAP directory to find avilable users for folder sharing.
-// Either contains an array with LDAP addressbook configuration or refers to entry in $config['ldap_public'].
-// If not specified, the configuraton from 'kolab_auth_addressbook' will be used.
-// Should be provided for multi-domain setups with placeholders like %dc, %d, %u, %fu or %dn.
-$config['kolab_users_directory'] = null;
-
-// Filter to be used for resolving user folders in LDAP.
-// Defaults to the 'kolab_auth_filter' configuration option.
-$config['kolab_users_filter'] = '(&(objectclass=kolabInetOrgPerson)(|(uid=%u)(mail=%fu)))';
-
-// Which property of the LDAP user record to use for user folder mapping in IMAP.
-// Defaults to the 'kolab_auth_login' configuration option.
-$config['kolab_users_id_attrib'] = null;
-
-// Use these attributes when searching users in LDAP
-$config['kolab_users_search_attrib'] = array('cn','mail','alias');
-
-// JSON-RPC endpoint configuration of the Bonnie web service providing historic data for groupware objects
-$config['kolab_bonnie_api'] = array(
- 'uri' => 'https://<kolab-hostname>:8080/api/rpc',
- 'user' => 'webclient',
- 'pass' => 'Welcome2KolabSystems',
- 'secret' => '8431f191707fffffff00000000cccc',
- 'debug' => true, // logs requests/responses to <log-dir>/bonnie
-);
diff --git a/lib/plugins/libkolab/js/folderlist.js b/lib/plugins/libkolab/js/folderlist.js
deleted file mode 100644
index 62a60ef..0000000
--- a/lib/plugins/libkolab/js/folderlist.js
+++ /dev/null
@@ -1,350 +0,0 @@
-/**
- * Kolab groupware folders treelist widget
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * @licstart The following is the entire license notice for the
- * JavaScript code in this file.
- *
- * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * @licend The above is the entire license notice
- * for the JavaScript code in this file.
- */
-
-function kolab_folderlist(node, p)
-{
- // extends treelist.js
- rcube_treelist_widget.call(this, node, p);
-
- // private vars
- var me = this;
- var search_results;
- var search_results_widget;
- var search_results_container;
- var listsearch_request;
- var search_messagebox;
-
- var Q = rcmail.quote_html;
-
- // render the results for folderlist search
- function render_search_results(results)
- {
- if (results.length) {
- // create treelist widget to present the search results
- if (!search_results_widget) {
- var list_id = (me.container.attr('id') || p.id_prefix || '0')
- search_results_container = $('<div class="searchresults"></div>')
- .html(p.search_title ? '<h2 class="boxtitle" id="st:' + list_id + '">' + p.search_title + '</h2>' : '')
- .insertAfter(me.container);
-
- search_results_widget = new rcube_treelist_widget('<ul>', {
- id_prefix: p.id_prefix,
- id_encode: p.id_encode,
- id_decode: p.id_decode,
- selectable: false
- });
- // copy classes from main list
- search_results_widget.container.addClass(me.container.attr('class')).attr('aria-labelledby', 'st:' + list_id);
-
- // register click handler on search result's checkboxes to select the given item for listing
- search_results_widget.container
- .appendTo(search_results_container)
- .on('click', 'input[type=checkbox], a.subscribed, span.subscribed', function(e) {
- var node, has_children, li = $(this).closest('li'),
- id = li.attr('id').replace(new RegExp('^'+p.id_prefix), '');
- if (p.id_decode)
- id = p.id_decode(id);
- node = search_results_widget.get_node(id);
- has_children = node.children && node.children.length;
-
- e.stopPropagation();
- e.bubbles = false;
-
- // activate + subscribe
- if ($(e.target).hasClass('subscribed')) {
- search_results[id].subscribed = true;
- $(e.target).attr('aria-checked', 'true');
- li.children().first()
- .toggleClass('subscribed')
- .find('input[type=checkbox]').get(0).checked = true;
-
- if (has_children && search_results[id].group == 'other user') {
- li.find('ul li > div').addClass('subscribed')
- .find('a.subscribed').attr('aria-checked', 'true');;
- }
- }
- else if (!this.checked) {
- return;
- }
-
- // copy item to the main list
- add_result2list(id, li, true);
-
- if (has_children) {
- li.find('input[type=checkbox]').first().prop('disabled', true).prop('checked', true);
- li.find('a.subscribed, span.subscribed').first().hide();
- }
- else {
- li.remove();
- }
-
- // set partial subscription status
- if (search_results[id].subscribed && search_results[id].parent && search_results[id].group == 'other') {
- parent_subscription_status($(me.get_item(id, true)));
- }
-
- // set focus to cloned checkbox
- if (rcube_event.is_keyboard(e)) {
- $(me.get_item(id, true)).find('input[type=checkbox]').first().focus();
- }
- })
- .on('click', function(e) {
- var prop, id = String($(e.target).closest('li').attr('id')).replace(new RegExp('^'+p.id_prefix), '');
- if (p.id_decode)
- id = p.id_decode(id);
-
- // forward event
- if (prop = search_results[id]) {
- e.data = prop;
- if (me.triggerEvent('click-item', e) === false) {
- e.stopPropagation();
- return false;
- }
- }
- });
- }
-
- // add results to list
- for (var prop, item, i=0; i < results.length; i++) {
- prop = results[i];
- item = $(prop.html);
- search_results[prop.id] = prop;
- search_results_widget.insert({
- id: prop.id,
- classes: [ prop.group || '' ],
- html: item,
- collapsed: true,
- virtual: prop.virtual
- }, prop.parent);
-
- // disable checkbox if item already exists in main list
- if (me.get_node(prop.id) && !me.get_node(prop.id).virtual) {
- item.find('input[type=checkbox]').first().prop('disabled', true).prop('checked', true);
- item.find('a.subscribed, span.subscribed').hide();
- }
- }
-
- search_results_container.show();
- }
- }
-
- // helper method to (recursively) add a search result item to the main list widget
- function add_result2list(id, li, active)
- {
- var node = search_results_widget.get_node(id),
- prop = search_results[id],
- parent_id = prop.parent || null,
- has_children = node.children && node.children.length,
- dom_node = has_children ? li.children().first().clone(true, true) : li.children().first(),
- childs = [];
-
- // find parent node and insert at the right place
- if (parent_id && me.get_node(parent_id)) {
- dom_node.children('span,a').first().html(Q(prop.editname || prop.listname));
- }
- else if (parent_id && search_results[parent_id]) {
- // copy parent tree from search results
- add_result2list(parent_id, $(search_results_widget.get_item(parent_id)), false);
- }
- else if (parent_id) {
- // use full name for list display
- dom_node.children('span,a').first().html(Q(prop.name));
- }
-
- // replace virtual node with a real one
- if (me.get_node(id)) {
- $(me.get_item(id, true)).children().first()
- .replaceWith(dom_node)
- .removeClass('virtual');
- }
- else {
- // copy childs, too
- if (has_children && prop.group == 'other user') {
- for (var cid, j=0; j < node.children.length; j++) {
- if ((cid = node.children[j].id) && search_results[cid]) {
- childs.push(search_results_widget.get_node(cid));
- }
- }
- }
-
- // move this result item to the main list widget
- me.insert({
- id: id,
- classes: [ prop.group || '' ],
- virtual: prop.virtual,
- html: dom_node,
- level: node.level,
- collapsed: true,
- children: childs
- }, parent_id, prop.group);
- }
-
- delete prop.html;
- prop.active = active;
- me.triggerEvent('insert-item', { id: id, data: prop, item: li });
-
- // register childs, too
- if (childs.length) {
- for (var cid, j=0; j < node.children.length; j++) {
- if ((cid = node.children[j].id) && search_results[cid]) {
- prop = search_results[cid];
- delete prop.html;
- prop.active = false;
- me.triggerEvent('insert-item', { id: cid, data: prop });
- }
- }
- }
- }
-
- // update the given item's parent's (partial) subscription state
- function parent_subscription_status(li)
- {
- var top_li = li.closest(me.container.children('li')),
- all_childs = $('li > div:not(.treetoggle)', top_li),
- subscribed = all_childs.filter('.subscribed').length;
-
- if (subscribed == 0) {
- top_li.children('div:first').removeClass('subscribed partial');
- }
- else {
- top_li.children('div:first')
- .addClass('subscribed')[subscribed < all_childs.length ? 'addClass' : 'removeClass']('partial');
- }
- }
-
- // do some magic when search is performed on the widget
- this.addEventListener('search', function(search) {
- // hide search results
- if (search_results_widget) {
- search_results_container.hide();
- search_results_widget.reset();
- }
- search_results = {};
-
- if (search_messagebox)
- rcmail.hide_message(search_messagebox);
-
- // send search request(s) to server
- if (search.query && search.execute) {
- // require a minimum length for the search string
- if (rcmail.env.autocomplete_min_length && search.query.length < rcmail.env.autocomplete_min_length && search.query != '*') {
- search_messagebox = rcmail.display_message(
- rcmail.get_label('autocompletechars').replace('$min', rcmail.env.autocomplete_min_length));
- return;
- }
-
- if (listsearch_request) {
- // ignore, let the currently running request finish
- if (listsearch_request.query == search.query) {
- return;
- }
- else { // cancel previous search request
- rcmail.multi_thread_request_abort(listsearch_request.id);
- listsearch_request = null;
- }
- }
-
- var sources = p.search_sources || [ 'folders' ];
- var reqid = rcmail.multi_thread_http_request({
- items: sources,
- threads: rcmail.env.autocomplete_threads || 1,
- action: p.search_action || 'listsearch',
- postdata: { action:'search', q:search.query, source:'%s' },
- lock: rcmail.display_message(rcmail.get_label('searching'), 'loading'),
- onresponse: render_search_results,
- whendone: function(data){
- listsearch_request = null;
- me.triggerEvent('search-complete', data);
- }
- });
-
- listsearch_request = { id:reqid, query:search.query };
- }
- else if (!search.query && listsearch_request) {
- rcmail.multi_thread_request_abort(listsearch_request.id);
- listsearch_request = null;
- }
- });
-
- this.container.on('click', 'a.subscribed, span.subscribed', function(e) {
- var li = $(this).closest('li'),
- id = li.attr('id').replace(new RegExp('^'+p.id_prefix), ''),
- div = li.children().first(),
- is_subscribed;
-
- if (me.is_search()) {
- id = id.replace(/--xsR$/, '');
- li = $(me.get_item(id, true));
- div = $(div).add(li.children().first());
- }
-
- if (p.id_decode)
- id = p.id_decode(id);
-
- div.toggleClass('subscribed');
- is_subscribed = div.hasClass('subscribed');
- $(this).attr('aria-checked', is_subscribed ? 'true' : 'false');
- me.triggerEvent('subscribe', { id: id, subscribed: is_subscribed, item: li });
-
- // update subscribe state of all 'virtual user' child folders
- if (li.hasClass('other user')) {
- $('ul li > div', li).each(function() {
- $(this)[is_subscribed ? 'addClass' : 'removeClass']('subscribed');
- $('.subscribed', div).attr('aria-checked', is_subscribed ? 'true' : 'false');
- });
- div.removeClass('partial');
- }
- // propagate subscription state to parent 'virtual user' folder
- else if (li.closest('li.other.user').length) {
- parent_subscription_status(li);
- }
-
- e.stopPropagation();
- return false;
- });
-
- this.container.on('click', 'a.remove', function(e) {
- var li = $(this).closest('li'),
- id = li.attr('id').replace(new RegExp('^'+p.id_prefix), '');
-
- if (me.is_search()) {
- id = id.replace(/--xsR$/, '');
- li = $(me.get_item(id, true));
- }
-
- if (p.id_decode)
- id = p.id_decode(id);
-
- me.triggerEvent('remove', { id: id, item: li });
-
- e.stopPropagation();
- return false;
- });
-}
-
-// link prototype from base class
-kolab_folderlist.prototype = rcube_treelist_widget.prototype;
diff --git a/lib/plugins/libkolab/lib/kolab_bonnie_api.php b/lib/plugins/libkolab/lib/kolab_bonnie_api.php
deleted file mode 100644
index e8ac131..0000000
--- a/lib/plugins/libkolab/lib/kolab_bonnie_api.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-
-/**
- * Provider class for accessing historic groupware object data through the Bonnie service
- *
- * API Specification at https://wiki.kolabsys.com/User:Bruederli/Draft:Bonnie_Client_API
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_bonnie_api
-{
- public $ready = false;
-
- private $config = array();
- private $client = null;
-
-
- /**
- * Default constructor
- */
- public function __construct($config)
- {
- $this->config = $config;
-
- $this->client = new kolab_bonnie_api_client($config['uri'], $config['timeout'] ?: 5, (bool)$config['debug']);
-
- $this->client->set_secret($config['secret']);
- $this->client->set_authentication($config['user'], $config['pass']);
- $this->client->set_request_user(rcube::get_instance()->get_user_name());
-
- $this->ready = !empty($config['secret']) && !empty($config['user']) && !empty($config['pass']);
- }
-
- /**
- * Wrapper function for <object>.changelog() API call
- */
- public function changelog($type, $uid, $mailbox=null)
- {
- return $this->client->execute($type.'.changelog', array('uid' => $uid, 'mailbox' => $mailbox));
- }
-
- /**
- * Wrapper function for <object>.diff() API call
- */
- public function diff($type, $uid, $rev, $mailbox=null)
- {
- return $this->client->execute($type.'.diff', array('uid' => $uid, 'rev' => $rev, 'mailbox' => $mailbox));
- }
-
- /**
- * Wrapper function for <object>.get() API call
- */
- public function get($type, $uid, $rev, $mailbox=null)
- {
- return $this->client->execute($type.'.get', array('uid' => $uid, 'rev' => intval($rev), 'mailbox' => $mailbox));
- }
-
- /**
- * Generic wrapper for direct API calls
- */
- public function _execute($method, $params = array())
- {
- return $this->client->execute($method, $params);
- }
-
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/lib/kolab_bonnie_api_client.php b/lib/plugins/libkolab/lib/kolab_bonnie_api_client.php
deleted file mode 100644
index bc209f4..0000000
--- a/lib/plugins/libkolab/lib/kolab_bonnie_api_client.php
+++ /dev/null
@@ -1,239 +0,0 @@
-<?php
-
-/**
- * JSON-RPC client class with some extra features for communicating with the Bonnie API service.
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_bonnie_api_client
-{
- /**
- * URL of the RPC endpoint
- * @var string
- */
- protected $url;
-
- /**
- * HTTP client timeout in seconds
- * @var integer
- */
- protected $timeout;
-
- /**
- * Debug flag
- * @var bool
- */
- protected $debug;
-
- /**
- * Username for authentication
- * @var string
- */
- protected $username;
-
- /**
- * Password for authentication
- * @var string
- */
- protected $password;
-
- /**
- * Secret key for request signing
- * @var string
- */
- protected $secret;
-
- /**
- * Default HTTP headers to send to the server
- * @var array
- */
- protected $headers = array(
- 'Connection' => 'close',
- 'Content-Type' => 'application/json',
- 'Accept' => 'application/json',
- );
-
- /**
- * Constructor
- *
- * @param string $url Server URL
- * @param integer $timeout Request timeout
- * @param bool $debug Enabled debug logging
- * @param array $headers Custom HTTP headers
- */
- public function __construct($url, $timeout = 5, $debug = false, $headers = array())
- {
- $this->url = $url;
- $this->timeout = $timeout;
- $this->debug = $debug;
- $this->headers = array_merge($this->headers, $headers);
- }
-
- /**
- * Setter for secret key for request signing
- */
- public function set_secret($secret)
- {
- $this->secret = $secret;
- }
-
- /**
- * Setter for the X-Request-User header
- */
- public function set_request_user($username)
- {
- $this->headers['X-Request-User'] = $username;
- }
-
- /**
- * Set authentication parameters
- *
- * @param string $username Username
- * @param string $password Password
- */
- public function set_authentication($username, $password)
- {
- $this->username = $username;
- $this->password = $password;
- }
-
- /**
- * Automatic mapping of procedures
- *
- * @param string $method Procedure name
- * @param array $params Procedure arguments
- * @return mixed
- */
- public function __call($method, $params)
- {
- return $this->execute($method, $params);
- }
-
- /**
- * Execute an RPC command
- *
- * @param string $method Procedure name
- * @param array $params Procedure arguments
- * @return mixed
- */
- public function execute($method, array $params = array())
- {
- $id = mt_rand();
-
- $payload = array(
- 'jsonrpc' => '2.0',
- 'method' => $method,
- 'id' => $id,
- );
-
- if (!empty($params)) {
- $payload['params'] = $params;
- }
-
- $result = $this->send_request($payload, $method != 'system.keygen');
-
- if (isset($result['id']) && $result['id'] == $id && array_key_exists('result', $result)) {
- return $result['result'];
- }
- else if (isset($result['error'])) {
- $this->_debug('ERROR', $result);
- }
-
- return null;
- }
-
- /**
- * Do the HTTP request
- *
- * @param string $payload Data to send
- */
- protected function send_request($payload, $sign = true)
- {
- try {
- $payload_ = json_encode($payload);
-
- // add request signature
- if ($sign && !empty($this->secret)) {
- $this->headers['X-Request-Sign'] = $this->request_signature($payload_);
- }
- else if ($this->headers['X-Request-Sign']) {
- unset($this->headers['X-Request-Sign']);
- }
-
- $this->_debug('REQUEST', $payload, $this->headers);
- $request = libkolab::http_request($this->url, 'POST', array('timeout' => $this->timeout));
- $request->setHeader($this->headers);
- $request->setAuth($this->username, $this->password);
- $request->setBody($payload_);
-
- $response = $request->send();
-
- if ($response->getStatus() == 200) {
- $result = json_decode($response->getBody(), true);
- $this->_debug('RESPONSE', $result);
- }
- else {
- throw new Exception(sprintf("HTTP %d %s", $response->getStatus(), $response->getReasonPhrase()));
- }
- }
- catch (Exception $e) {
- rcube::raise_error(array(
- 'code' => 500,
- 'type' => 'php',
- 'message' => "Bonnie API request failed: " . $e->getMessage(),
- ), true);
-
- return array('id' => $payload['id'], 'error' => $e->getMessage(), 'code' => -32000);
- }
-
- return is_array($result) ? $result : array();
- }
-
- /**
- * Compute the hmac signature for the current event payload using
- * the secret key configured for this API client
- *
- * @param string $data The request payload data
- * @return string The request signature
- */
- protected function request_signature($data)
- {
- // TODO: get the session key with a system.keygen call
- return hash_hmac('sha256', $this->headers['X-Request-User'] . ':' . $data, $this->secret);
- }
-
- /**
- * Write debug log
- */
- protected function _debug(/* $message, $data1, data2, ...*/)
- {
- if (!$this->debug)
- return;
-
- $args = func_get_args();
-
- $msg = array();
- foreach ($args as $arg) {
- $msg[] = !is_string($arg) ? var_export($arg, true) : $arg;
- }
-
- rcube::write_log('bonnie', join(";\n", $msg));
- }
-
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/lib/kolab_date_recurrence.php b/lib/plugins/libkolab/lib/kolab_date_recurrence.php
deleted file mode 100644
index 06dd331..0000000
--- a/lib/plugins/libkolab/lib/kolab_date_recurrence.php
+++ /dev/null
@@ -1,135 +0,0 @@
-<?php
-
-/**
- * Recurrence computation class for xcal-based Kolab format objects
- *
- * Utility class to compute instances of recurring events.
- * It requires the libcalendaring PHP module to be installed and loaded.
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-class kolab_date_recurrence
-{
- private /* EventCal */ $engine;
- private /* kolab_format_xcal */ $object;
- private /* DateTime */ $start;
- private /* DateTime */ $next;
- private /* cDateTime */ $cnext;
- private /* DateInterval */ $duration;
-
- /**
- * Default constructor
- *
- * @param array The Kolab object to operate on
- */
- function __construct($object)
- {
- $data = $object->to_array();
-
- $this->object = $object;
- $this->engine = $object->to_libcal();
- $this->start = $this->next = $data['start'];
- $this->cnext = kolab_format::get_datetime($this->next);
-
- if (is_object($data['start']) && is_object($data['end']))
- $this->duration = $data['start']->diff($data['end']);
- else
- $this->duration = new DateInterval('PT' . ($data['end'] - $data['start']) . 'S');
- }
-
- /**
- * Get date/time of the next occurence of this event
- *
- * @param boolean Return a Unix timestamp instead of a DateTime object
- * @return mixed DateTime object/unix timestamp or False if recurrence ended
- */
- public function next_start($timestamp = false)
- {
- $time = false;
-
- if ($this->engine && $this->next) {
- if (($cnext = new cDateTime($this->engine->getNextOccurence($this->cnext))) && $cnext->isValid()) {
- $next = kolab_format::php_datetime($cnext);
- $time = $timestamp ? $next->format('U') : $next;
- $this->cnext = $cnext;
- $this->next = $next;
- }
- }
-
- return $time;
- }
-
- /**
- * Get the next recurring instance of this event
- *
- * @return mixed Array with event properties or False if recurrence ended
- */
- public function next_instance()
- {
- if ($next_start = $this->next_start()) {
- $next_end = clone $next_start;
- $next_end->add($this->duration);
-
- $next = $this->object->to_array();
- $next['recurrence_id'] = $next_start->format('Y-m-d');
- $next['start'] = $next_start;
- $next['end'] = $next_end;
- unset($next['_formatobj']);
-
- return $next;
- }
-
- return false;
- }
-
- /**
- * Get the end date of the occurence of this recurrence cycle
- *
- * @return DateTime|bool End datetime of the last event or False if recurrence exceeds limit
- */
- public function end()
- {
- $event = $this->object->to_array();
-
- // recurrence end date is given
- if ($event['recurrence']['UNTIL'] instanceof DateTime) {
- return $event['recurrence']['UNTIL'];
- }
-
- // let libkolab do the work
- if ($this->engine && ($cend = $this->engine->getLastOccurrence()) && ($end_dt = kolab_format::php_datetime(new cDateTime($cend)))) {
- return $end_dt;
- }
-
- // determine a reasonable end date if none given
- if (!$event['recurrence']['COUNT'] && $event['end'] instanceof DateTime) {
- switch ($event['recurrence']['FREQ']) {
- case 'YEARLY': $intvl = 'P100Y'; break;
- case 'MONTHLY': $intvl = 'P20Y'; break;
- default: $intvl = 'P10Y'; break;
- }
-
- $end_dt = clone $event['end'];
- $end_dt->add(new DateInterval($intvl));
- return $end_dt;
- }
-
- return false;
- }
-}
diff --git a/lib/plugins/libkolab/lib/kolab_format.php b/lib/plugins/libkolab/lib/kolab_format.php
deleted file mode 100644
index 625483b..0000000
--- a/lib/plugins/libkolab/lib/kolab_format.php
+++ /dev/null
@@ -1,699 +0,0 @@
-<?php
-
-/**
- * Kolab format model class wrapping libkolabxml bindings
- *
- * Abstract base class for different Kolab groupware objects read from/written
- * to the new Kolab 3 format using the PHP bindings of libkolabxml.
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-abstract class kolab_format
-{
- public static $timezone;
-
- public /*abstract*/ $CTYPE;
- public /*abstract*/ $CTYPEv2;
-
- protected /*abstract*/ $objclass;
- protected /*abstract*/ $read_func;
- protected /*abstract*/ $write_func;
-
- protected $obj;
- protected $data;
- protected $xmldata;
- protected $xmlobject;
- protected $formaterror;
- protected $loaded = false;
- protected $version = '3.0';
-
- const KTYPE_PREFIX = 'application/x-vnd.kolab.';
- const PRODUCT_ID = 'Roundcube-libkolab-1.1';
-
- // mapping table for valid PHP timezones not supported by libkolabxml
- // basically the entire list of ftp://ftp.iana.org/tz/data/backward
- protected static $timezone_map = array(
- 'Africa/Asmera' => 'Africa/Asmara',
- 'Africa/Timbuktu' => 'Africa/Abidjan',
- 'America/Argentina/ComodRivadavia' => 'America/Argentina/Catamarca',
- 'America/Atka' => 'America/Adak',
- 'America/Buenos_Aires' => 'America/Argentina/Buenos_Aires',
- 'America/Catamarca' => 'America/Argentina/Catamarca',
- 'America/Coral_Harbour' => 'America/Atikokan',
- 'America/Cordoba' => 'America/Argentina/Cordoba',
- 'America/Ensenada' => 'America/Tijuana',
- 'America/Fort_Wayne' => 'America/Indiana/Indianapolis',
- 'America/Indianapolis' => 'America/Indiana/Indianapolis',
- 'America/Jujuy' => 'America/Argentina/Jujuy',
- 'America/Knox_IN' => 'America/Indiana/Knox',
- 'America/Louisville' => 'America/Kentucky/Louisville',
- 'America/Mendoza' => 'America/Argentina/Mendoza',
- 'America/Porto_Acre' => 'America/Rio_Branco',
- 'America/Rosario' => 'America/Argentina/Cordoba',
- 'America/Virgin' => 'America/Port_of_Spain',
- 'Asia/Ashkhabad' => 'Asia/Ashgabat',
- 'Asia/Calcutta' => 'Asia/Kolkata',
- 'Asia/Chungking' => 'Asia/Shanghai',
- 'Asia/Dacca' => 'Asia/Dhaka',
- 'Asia/Katmandu' => 'Asia/Kathmandu',
- 'Asia/Macao' => 'Asia/Macau',
- 'Asia/Saigon' => 'Asia/Ho_Chi_Minh',
- 'Asia/Tel_Aviv' => 'Asia/Jerusalem',
- 'Asia/Thimbu' => 'Asia/Thimphu',
- 'Asia/Ujung_Pandang' => 'Asia/Makassar',
- 'Asia/Ulan_Bator' => 'Asia/Ulaanbaatar',
- 'Atlantic/Faeroe' => 'Atlantic/Faroe',
- 'Atlantic/Jan_Mayen' => 'Europe/Oslo',
- 'Australia/ACT' => 'Australia/Sydney',
- 'Australia/Canberra' => 'Australia/Sydney',
- 'Australia/LHI' => 'Australia/Lord_Howe',
- 'Australia/NSW' => 'Australia/Sydney',
- 'Australia/North' => 'Australia/Darwin',
- 'Australia/Queensland' => 'Australia/Brisbane',
- 'Australia/South' => 'Australia/Adelaide',
- 'Australia/Tasmania' => 'Australia/Hobart',
- 'Australia/Victoria' => 'Australia/Melbourne',
- 'Australia/West' => 'Australia/Perth',
- 'Australia/Yancowinna' => 'Australia/Broken_Hill',
- 'Brazil/Acre' => 'America/Rio_Branco',
- 'Brazil/DeNoronha' => 'America/Noronha',
- 'Brazil/East' => 'America/Sao_Paulo',
- 'Brazil/West' => 'America/Manaus',
- 'Canada/Atlantic' => 'America/Halifax',
- 'Canada/Central' => 'America/Winnipeg',
- 'Canada/East-Saskatchewan' => 'America/Regina',
- 'Canada/Eastern' => 'America/Toronto',
- 'Canada/Mountain' => 'America/Edmonton',
- 'Canada/Newfoundland' => 'America/St_Johns',
- 'Canada/Pacific' => 'America/Vancouver',
- 'Canada/Saskatchewan' => 'America/Regina',
- 'Canada/Yukon' => 'America/Whitehorse',
- 'Chile/Continental' => 'America/Santiago',
- 'Chile/EasterIsland' => 'Pacific/Easter',
- 'Cuba' => 'America/Havana',
- 'Egypt' => 'Africa/Cairo',
- 'Eire' => 'Europe/Dublin',
- 'Europe/Belfast' => 'Europe/London',
- 'Europe/Tiraspol' => 'Europe/Chisinau',
- 'GB' => 'Europe/London',
- 'GB-Eire' => 'Europe/London',
- 'Greenwich' => 'Etc/GMT',
- 'Hongkong' => 'Asia/Hong_Kong',
- 'Iceland' => 'Atlantic/Reykjavik',
- 'Iran' => 'Asia/Tehran',
- 'Israel' => 'Asia/Jerusalem',
- 'Jamaica' => 'America/Jamaica',
- 'Japan' => 'Asia/Tokyo',
- 'Kwajalein' => 'Pacific/Kwajalein',
- 'Libya' => 'Africa/Tripoli',
- 'Mexico/BajaNorte' => 'America/Tijuana',
- 'Mexico/BajaSur' => 'America/Mazatlan',
- 'Mexico/General' => 'America/Mexico_City',
- 'NZ' => 'Pacific/Auckland',
- 'NZ-CHAT' => 'Pacific/Chatham',
- 'Navajo' => 'America/Denver',
- 'PRC' => 'Asia/Shanghai',
- 'Pacific/Ponape' => 'Pacific/Pohnpei',
- 'Pacific/Samoa' => 'Pacific/Pago_Pago',
- 'Pacific/Truk' => 'Pacific/Chuuk',
- 'Pacific/Yap' => 'Pacific/Chuuk',
- 'Poland' => 'Europe/Warsaw',
- 'Portugal' => 'Europe/Lisbon',
- 'ROC' => 'Asia/Taipei',
- 'ROK' => 'Asia/Seoul',
- 'Singapore' => 'Asia/Singapore',
- 'Turkey' => 'Europe/Istanbul',
- 'UCT' => 'Etc/UCT',
- 'US/Alaska' => 'America/Anchorage',
- 'US/Aleutian' => 'America/Adak',
- 'US/Arizona' => 'America/Phoenix',
- 'US/Central' => 'America/Chicago',
- 'US/East-Indiana' => 'America/Indiana/Indianapolis',
- 'US/Eastern' => 'America/New_York',
- 'US/Hawaii' => 'Pacific/Honolulu',
- 'US/Indiana-Starke' => 'America/Indiana/Knox',
- 'US/Michigan' => 'America/Detroit',
- 'US/Mountain' => 'America/Denver',
- 'US/Pacific' => 'America/Los_Angeles',
- 'US/Samoa' => 'Pacific/Pago_Pago',
- 'Universal' => 'Etc/UTC',
- 'W-SU' => 'Europe/Moscow',
- 'Zulu' => 'Etc/UTC',
- );
-
- /**
- * Factory method to instantiate a kolab_format object of the given type and version
- *
- * @param string Object type to instantiate
- * @param float Format version
- * @param string Cached xml data to initialize with
- * @return object kolab_format
- */
- public static function factory($type, $version = '3.0', $xmldata = null)
- {
- if (!isset(self::$timezone))
- self::$timezone = new DateTimeZone('UTC');
-
- if (!self::supports($version))
- return PEAR::raiseError("No support for Kolab format version " . $version);
-
- $type = preg_replace('/configuration\.[a-z._]+$/', 'configuration', $type);
- $suffix = preg_replace('/[^a-z]+/', '', $type);
- $classname = 'kolab_format_' . $suffix;
- if (class_exists($classname))
- return new $classname($xmldata, $version);
-
- return PEAR::raiseError("Failed to load Kolab Format wrapper for type " . $type);
- }
-
- /**
- * Determine support for the given format version
- *
- * @param float Format version to check
- * @return boolean True if supported, False otherwise
- */
- public static function supports($version)
- {
- if ($version == '2.0')
- return class_exists('kolabobject');
- // default is version 3
- return class_exists('kolabformat');
- }
-
- /**
- * Convert the given date/time value into a cDateTime object
- *
- * @param mixed Date/Time value either as unix timestamp, date string or PHP DateTime object
- * @param DateTimeZone The timezone the date/time is in. Use global default if Null, local time if False
- * @param boolean True of the given date has no time component
- * @return object The libkolabxml date/time object
- */
- public static function get_datetime($datetime, $tz = null, $dateonly = false)
- {
- // use timezone information from datetime of global setting
- if (!$tz && $tz !== false) {
- if ($datetime instanceof DateTime)
- $tz = $datetime->getTimezone();
- if (!$tz)
- $tz = self::$timezone;
- }
- $result = new cDateTime();
-
- try {
- // got a unix timestamp (in UTC)
- if (is_numeric($datetime)) {
- $datetime = new DateTime('@'.$datetime, new DateTimeZone('UTC'));
- if ($tz) $datetime->setTimezone($tz);
- }
- else if (is_string($datetime) && strlen($datetime)) {
- $datetime = $tz ? new DateTime($datetime, $tz) : new DateTime($datetime);
- }
- }
- catch (Exception $e) {}
-
- if ($datetime instanceof DateTime) {
- $result->setDate($datetime->format('Y'), $datetime->format('n'), $datetime->format('j'));
-
- if (!$dateonly)
- $result->setTime($datetime->format('G'), $datetime->format('i'), $datetime->format('s'));
-
- if ($tz && in_array($tz->getName(), array('UTC', 'GMT', '+00:00', 'Z'))) {
- $result->setUTC(true);
- }
- else if ($tz !== false) {
- $tzid = $tz->getName();
- if (array_key_exists($tzid, self::$timezone_map))
- $tzid = self::$timezone_map[$tzid];
- $result->setTimezone($tzid);
- }
- }
-
- return $result;
- }
-
- /**
- * Convert the given cDateTime into a PHP DateTime object
- *
- * @param object cDateTime The libkolabxml datetime object
- * @return object DateTime PHP datetime instance
- */
- public static function php_datetime($cdt)
- {
- if (!is_object($cdt) || !$cdt->isValid())
- return null;
-
- $d = new DateTime;
- $d->setTimezone(self::$timezone);
-
- try {
- if ($tzs = $cdt->timezone()) {
- $tz = new DateTimeZone($tzs);
- $d->setTimezone($tz);
- }
- else if ($cdt->isUTC()) {
- $d->setTimezone(new DateTimeZone('UTC'));
- }
- }
- catch (Exception $e) { }
-
- $d->setDate($cdt->year(), $cdt->month(), $cdt->day());
-
- if ($cdt->isDateOnly()) {
- $d->_dateonly = true;
- $d->setTime(12, 0, 0); // set time to noon to avoid timezone troubles
- }
- else {
- $d->setTime($cdt->hour(), $cdt->minute(), $cdt->second());
- }
-
- return $d;
- }
-
- /**
- * Convert a libkolabxml vector to a PHP array
- *
- * @param object vector Object
- * @return array Indexed array containing vector elements
- */
- public static function vector2array($vec, $max = PHP_INT_MAX)
- {
- $arr = array();
- for ($i=0; $i < $vec->size() && $i < $max; $i++)
- $arr[] = $vec->get($i);
- return $arr;
- }
-
- /**
- * Build a libkolabxml vector (string) from a PHP array
- *
- * @param array Array with vector elements
- * @return object vectors
- */
- public static function array2vector($arr)
- {
- $vec = new vectors;
- foreach ((array)$arr as $val) {
- if (strlen($val))
- $vec->push($val);
- }
- return $vec;
- }
-
- /**
- * Parse the X-Kolab-Type header from MIME messages and return the object type in short form
- *
- * @param string X-Kolab-Type header value
- * @return string Kolab object type (contact,event,task,note,etc.)
- */
- public static function mime2object_type($x_kolab_type)
- {
- return preg_replace(
- array('/dictionary.[a-z.]+$/', '/contact.distlist$/'),
- array( 'dictionary', 'distribution-list'),
- substr($x_kolab_type, strlen(self::KTYPE_PREFIX))
- );
- }
-
-
- /**
- * Default constructor of all kolab_format_* objects
- */
- public function __construct($xmldata = null, $version = null)
- {
- $this->obj = new $this->objclass;
- $this->xmldata = $xmldata;
-
- if ($version)
- $this->version = $version;
-
- // use libkolab module if available
- if (class_exists('kolabobject'))
- $this->xmlobject = new XMLObject();
- }
-
- /**
- * Check for format errors after calling kolabformat::write*()
- *
- * @return boolean True if there were errors, False if OK
- */
- protected function format_errors()
- {
- $ret = $log = false;
- switch (kolabformat::error()) {
- case kolabformat::NoError:
- $ret = false;
- break;
- case kolabformat::Warning:
- $ret = false;
- $uid = is_object($this->obj) ? $this->obj->uid() : $this->data['uid'];
- $log = "Warning @ $uid";
- break;
- default:
- $ret = true;
- $log = "Error";
- }
-
- if ($log && !isset($this->formaterror)) {
- rcube::raise_error(array(
- 'code' => 660,
- 'type' => 'php',
- 'file' => __FILE__,
- 'line' => __LINE__,
- 'message' => "kolabformat $log: " . kolabformat::errorMessage(),
- ), true);
-
- $this->formaterror = $ret;
- }
-
- return $ret;
- }
-
- /**
- * Save the last generated UID to the object properties.
- * Should be called after kolabformat::writeXXXX();
- */
- protected function update_uid()
- {
- // get generated UID
- if (!$this->data['uid']) {
- if ($this->xmlobject) {
- $this->data['uid'] = $this->xmlobject->getSerializedUID();
- }
- if (empty($this->data['uid'])) {
- $this->data['uid'] = kolabformat::getSerializedUID();
- }
- $this->obj->setUid($this->data['uid']);
- }
- }
-
- /**
- * Initialize libkolabxml object with cached xml data
- */
- protected function init()
- {
- if (!$this->loaded) {
- if ($this->xmldata) {
- $this->load($this->xmldata);
- $this->xmldata = null;
- }
- $this->loaded = true;
- }
- }
-
- /**
- * Get constant value for libkolab's version parameter
- *
- * @param float Version value to convert
- * @return int Constant value of either kolabobject::KolabV2 or kolabobject::KolabV3 or false if kolabobject module isn't available
- */
- protected function libversion($v = null)
- {
- if (class_exists('kolabobject')) {
- $version = $v ?: $this->version;
- if ($version <= '2.0')
- return kolabobject::KolabV2;
- else
- return kolabobject::KolabV3;
- }
-
- return false;
- }
-
- /**
- * Determine the correct libkolab(xml) wrapper function for the given call
- * depending on the available PHP modules
- */
- protected function libfunc($func)
- {
- if (is_array($func) || strpos($func, '::'))
- return $func;
- else if (class_exists('kolabobject'))
- return array($this->xmlobject, $func);
- else
- return 'kolabformat::' . $func;
- }
-
- /**
- * Direct getter for object properties
- */
- public function __get($var)
- {
- return $this->data[$var];
- }
-
- /**
- * Load Kolab object data from the given XML block
- *
- * @param string XML data
- * @return boolean True on success, False on failure
- */
- public function load($xml)
- {
- $this->formaterror = null;
- $read_func = $this->libfunc($this->read_func);
-
- if (is_array($read_func))
- $r = call_user_func($read_func, $xml, $this->libversion());
- else
- $r = call_user_func($read_func, $xml, false);
-
- if (is_resource($r))
- $this->obj = new $this->objclass($r);
- else if (is_a($r, $this->objclass))
- $this->obj = $r;
-
- $this->loaded = !$this->format_errors();
- }
-
- /**
- * Write object data to XML format
- *
- * @param float Format version to write
- * @return string XML data
- */
- public function write($version = null)
- {
- $this->formaterror = null;
-
- $this->init();
- $write_func = $this->libfunc($this->write_func);
- if (is_array($write_func))
- $this->xmldata = call_user_func($write_func, $this->obj, $this->libversion($version), self::PRODUCT_ID);
- else
- $this->xmldata = call_user_func($write_func, $this->obj, self::PRODUCT_ID);
-
- if (!$this->format_errors())
- $this->update_uid();
- else
- $this->xmldata = null;
-
- return $this->xmldata;
- }
-
- /**
- * Set properties to the kolabformat object
- *
- * @param array Object data as hash array
- */
- public function set(&$object)
- {
- $this->init();
-
- if (!empty($object['uid']))
- $this->obj->setUid($object['uid']);
-
- // set some automatic values if missing
- if (empty($object['created']) && method_exists($this->obj, 'setCreated')) {
- $cdt = $this->obj->created();
- $object['created'] = $cdt && $cdt->isValid() ? self::php_datetime($cdt) : new DateTime('now', new DateTimeZone('UTC'));
- if (!$cdt || !$cdt->isValid())
- $this->obj->setCreated(self::get_datetime($object['created']));
- }
-
- $object['changed'] = new DateTime('now', new DateTimeZone('UTC'));
- $this->obj->setLastModified(self::get_datetime($object['changed']));
-
- // Save custom properties of the given object
- if (isset($object['x-custom']) && method_exists($this->obj, 'setCustomProperties')) {
- $vcustom = new vectorcs;
- foreach ((array)$object['x-custom'] as $cp) {
- if (is_array($cp))
- $vcustom->push(new CustomProperty($cp[0], $cp[1]));
- }
- $this->obj->setCustomProperties($vcustom);
- }
- // load custom properties from XML for caching (#2238) if method exists (#3125)
- else if (method_exists($this->obj, 'customProperties')) {
- $object['x-custom'] = array();
- $vcustom = $this->obj->customProperties();
- for ($i=0; $i < $vcustom->size(); $i++) {
- $cp = $vcustom->get($i);
- $object['x-custom'][] = array($cp->identifier, $cp->value);
- }
- }
- }
-
- /**
- * Convert the Kolab object into a hash array data structure
- *
- * @param array Additional data for merge
- *
- * @return array Kolab object data as hash array
- */
- public function to_array($data = array())
- {
- $this->init();
-
- // read object properties into local data object
- $object = array(
- 'uid' => $this->obj->uid(),
- 'changed' => self::php_datetime($this->obj->lastModified()),
- );
-
- // not all container support the created property
- if (method_exists($this->obj, 'created')) {
- $object['created'] = self::php_datetime($this->obj->created());
- }
-
- // read custom properties
- if (method_exists($this->obj, 'customProperties')) {
- $vcustom = $this->obj->customProperties();
- for ($i=0; $i < $vcustom->size(); $i++) {
- $cp = $vcustom->get($i);
- $object['x-custom'][] = array($cp->identifier, $cp->value);
- }
- }
-
- // merge with additional data, e.g. attachments from the message
- if ($data) {
- foreach ($data as $idx => $value) {
- if (is_array($value)) {
- $object[$idx] = array_merge((array)$object[$idx], $value);
- }
- else {
- $object[$idx] = $value;
- }
- }
- }
-
- return $object;
- }
-
- /**
- * Object validation method to be implemented by derived classes
- */
- abstract public function is_valid();
-
- /**
- * Callback for kolab_storage_cache to get object specific tags to cache
- *
- * @return array List of tags to save in cache
- */
- public function get_tags()
- {
- return array();
- }
-
- /**
- * Callback for kolab_storage_cache to get words to index for fulltext search
- *
- * @return array List of words to save in cache
- */
- public function get_words()
- {
- return array();
- }
-
- /**
- * Utility function to extract object attachment data
- *
- * @param array Hash array reference to append attachment data into
- */
- public function get_attachments(&$object)
- {
- $this->init();
-
- // handle attachments
- $vattach = $this->obj->attachments();
- for ($i=0; $i < $vattach->size(); $i++) {
- $attach = $vattach->get($i);
-
- // skip cid: attachments which are mime message parts handled by kolab_storage_folder
- if (substr($attach->uri(), 0, 4) != 'cid:' && $attach->label()) {
- $name = $attach->label();
- $key = $name . (isset($object['_attachments'][$name]) ? '.'.$i : '');
- $content = $attach->data();
- $object['_attachments'][$key] = array(
- 'id' => 'i:'.$i,
- 'name' => $name,
- 'mimetype' => $attach->mimetype(),
- 'size' => strlen($content),
- 'content' => $content,
- );
- }
- else if (in_array(substr($attach->uri(), 0, 4), array('http','imap'))) {
- $object['links'][] = $attach->uri();
- }
- }
- }
-
- /**
- * Utility function to set attachment properties to the kolabformat object
- *
- * @param array Object data as hash array
- * @param boolean True to always overwrite attachment information
- */
- protected function set_attachments($object, $write = true)
- {
- // save attachments
- $vattach = new vectorattachment;
- foreach ((array) $object['_attachments'] as $cid => $attr) {
- if (empty($attr))
- continue;
- $attach = new Attachment;
- $attach->setLabel((string)$attr['name']);
- $attach->setUri('cid:' . $cid, $attr['mimetype'] ?: 'application/octet-stream');
- if ($attach->isValid()) {
- $vattach->push($attach);
- $write = true;
- }
- else {
- rcube::raise_error(array(
- 'code' => 660,
- 'type' => 'php',
- 'file' => __FILE__,
- 'line' => __LINE__,
- 'message' => "Invalid attributes for attachment $cid: " . var_export($attr, true),
- ), true);
- }
- }
-
- foreach ((array) $object['links'] as $link) {
- $attach = new Attachment;
- $attach->setUri($link, 'unknown');
- $vattach->push($attach);
- $write = true;
- }
-
- if ($write) {
- $this->obj->setAttachments($vattach);
- }
- }
-}
diff --git a/lib/plugins/libkolab/lib/kolab_format_configuration.php b/lib/plugins/libkolab/lib/kolab_format_configuration.php
deleted file mode 100644
index ceb7ebb..0000000
--- a/lib/plugins/libkolab/lib/kolab_format_configuration.php
+++ /dev/null
@@ -1,284 +0,0 @@
-<?php
-
-/**
- * Kolab Configuration data model class
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_format_configuration extends kolab_format
-{
- public $CTYPE = 'application/vnd.kolab+xml';
- public $CTYPEv2 = 'application/x-vnd.kolab.configuration';
-
- protected $objclass = 'Configuration';
- protected $read_func = 'readConfiguration';
- protected $write_func = 'writeConfiguration';
-
- private $type_map = array(
- 'category' => Configuration::TypeCategoryColor,
- 'dictionary' => Configuration::TypeDictionary,
- 'file_driver' => Configuration::TypeFileDriver,
- 'relation' => Configuration::TypeRelation,
- 'snippet' => Configuration::TypeSnippet,
- );
-
- private $driver_settings_fields = array('host', 'port', 'username', 'password');
-
- /**
- * Set properties to the kolabformat object
- *
- * @param array Object data as hash array
- */
- public function set(&$object)
- {
- // read type-specific properties
- switch ($object['type']) {
- case 'dictionary':
- $dict = new Dictionary($object['language']);
- $dict->setEntries(self::array2vector($object['e']));
- $this->obj = new Configuration($dict);
- break;
-
- case 'category':
- // TODO: implement this
- $categories = new vectorcategorycolor;
- $this->obj = new Configuration($categories);
- break;
-
- case 'file_driver':
- $driver = new FileDriver($object['driver'], $object['title']);
-
- $driver->setEnabled((bool) $object['enabled']);
-
- foreach ($this->driver_settings_fields as $field) {
- $value = $object[$field];
- if ($value !== null) {
- $driver->{'set' . ucfirst($field)}($value);
- }
- }
-
- $this->obj = new Configuration($driver);
- break;
-
- case 'relation':
- $relation = new Relation(strval($object['name']), strval($object['category']));
-
- if ($object['color']) {
- $relation->setColor($object['color']);
- }
- if ($object['parent']) {
- $relation->setParent($object['parent']);
- }
- if ($object['iconName']) {
- $relation->setIconName($object['iconName']);
- }
- if ($object['priority'] > 0) {
- $relation->setPriority((int) $object['priority']);
- }
- if (!empty($object['members'])) {
- $relation->setMembers(self::array2vector($object['members']));
- }
-
- $this->obj = new Configuration($relation);
- break;
-
- case 'snippet':
- $collection = new SnippetCollection($object['name']);
- $snippets = new vectorsnippets;
-
- foreach ((array) $object['snippets'] as $item) {
- $snippet = new snippet($item['name'], $item['text']);
- $snippet->setTextType(strtolower($item['type']) == 'html' ? Snippet::HTML : Snippet::Plain);
- if ($item['shortcut']) {
- $snippet->setShortCut($item['shortcut']);
- }
-
- $snippets->push($snippet);
- }
-
- $collection->setSnippets($snippets);
-
- $this->obj = new Configuration($collection);
- break;
-
- default:
- return false;
- }
-
- // adjust content-type string
- $this->CTYPEv2 = 'application/x-vnd.kolab.configuration.' . $object['type'];
-
- // reset old object data, otherwise set() will overwrite current data (#4095)
- $this->xmldata = null;
- // set common object properties
- parent::set($object);
-
- // cache this data
- $this->data = $object;
- unset($this->data['_formatobj']);
- }
-
- /**
- *
- */
- public function is_valid()
- {
- return $this->data || (is_object($this->obj) && $this->obj->isValid());
- }
-
- /**
- * Convert the Configuration object into a hash array data structure
- *
- * @param array Additional data for merge
- *
- * @return array Config object data as hash array
- */
- public function to_array($data = array())
- {
- // return cached result
- if (!empty($this->data)) {
- return $this->data;
- }
-
- // read common object props into local data object
- $object = parent::to_array($data);
-
- $type_map = array_flip($this->type_map);
-
- $object['type'] = $type_map[$this->obj->type()];
-
- // read type-specific properties
- switch ($object['type']) {
- case 'dictionary':
- $dict = $this->obj->dictionary();
- $object['language'] = $dict->language();
- $object['e'] = self::vector2array($dict->entries());
- break;
-
- case 'category':
- // TODO: implement this
- break;
-
- case 'file_driver':
- $driver = $this->obj->fileDriver();
-
- $object['driver'] = $driver->driver();
- $object['title'] = $driver->title();
- $object['enabled'] = $driver->enabled();
-
- foreach ($this->driver_settings_fields as $field) {
- $object[$field] = $driver->{$field}();
- }
-
- break;
-
- case 'relation':
- $relation = $this->obj->relation();
-
- $object['name'] = $relation->name();
- $object['category'] = $relation->type();
- $object['color'] = $relation->color();
- $object['parent'] = $relation->parent();
- $object['iconName'] = $relation->iconName();
- $object['priority'] = $relation->priority();
- $object['members'] = self::vector2array($relation->members());
-
- break;
-
- case 'snippet':
- $collection = $this->obj->snippets();
-
- $object['name'] = $collection->name();
- $object['snippets'] = array();
-
- $snippets = $collection->snippets();
- for ($i=0; $i < $snippets->size(); $i++) {
- $snippet = $snippets->get($i);
- $object['snippets'][] = array(
- 'name' => $snippet->name(),
- 'text' => $snippet->text(),
- 'type' => $snippet->textType() == Snippet::HTML ? 'html' : 'plain',
- 'shortcut' => $snippet->shortCut(),
- );
- }
-
- break;
- }
-
- // adjust content-type string
- if ($object['type']) {
- $this->CTYPEv2 = 'application/x-vnd.kolab.configuration.' . $object['type'];
- }
-
- $this->data = $object;
- return $this->data;
- }
-
- /**
- * Callback for kolab_storage_cache to get object specific tags to cache
- *
- * @return array List of tags to save in cache
- */
- public function get_tags()
- {
- $tags = array();
-
- switch ($this->data['type']) {
- case 'dictionary':
- $tags = array($this->data['language']);
- break;
-
- case 'relation':
- $tags = array('category:' . $this->data['category']);
- break;
- }
-
- return $tags;
- }
-
- /**
- * Callback for kolab_storage_cache to get words to index for fulltext search
- *
- * @return array List of words to save in cache
- */
- public function get_words()
- {
- $words = array();
-
- foreach ((array)$this->data['members'] as $url) {
- $member = kolab_storage_config::parse_member_url($url);
-
- if (empty($member)) {
- if (strpos($url, 'urn:uuid:') === 0) {
- $words[] = substr($url, 9);
- }
- }
- else if (!empty($member['params']['message-id'])) {
- $words[] = $member['params']['message-id'];
- }
- else {
- // derive message identifier from URI
- $words[] = md5($url);
- }
- }
-
- return $words;
- }
-}
diff --git a/lib/plugins/libkolab/lib/kolab_format_contact.php b/lib/plugins/libkolab/lib/kolab_format_contact.php
deleted file mode 100644
index 806a819..0000000
--- a/lib/plugins/libkolab/lib/kolab_format_contact.php
+++ /dev/null
@@ -1,482 +0,0 @@
-<?php
-
-/**
- * Kolab Contact model class
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_format_contact extends kolab_format
-{
- public $CTYPE = 'application/vcard+xml';
- public $CTYPEv2 = 'application/x-vnd.kolab.contact';
-
- protected $objclass = 'Contact';
- protected $read_func = 'readContact';
- protected $write_func = 'writeContact';
-
- public static $fulltext_cols = array('name', 'firstname', 'surname', 'middlename', 'email:address');
-
- public $phonetypes = array(
- 'home' => Telephone::Home,
- 'work' => Telephone::Work,
- 'text' => Telephone::Text,
- 'main' => Telephone::Voice,
- 'homefax' => Telephone::Fax,
- 'workfax' => Telephone::Fax,
- 'mobile' => Telephone::Cell,
- 'video' => Telephone::Video,
- 'pager' => Telephone::Pager,
- 'car' => Telephone::Car,
- 'other' => Telephone::Textphone,
- );
-
- public $emailtypes = array(
- 'home' => Email::Home,
- 'work' => Email::Work,
- 'other' => Email::NoType,
- );
-
- public $addresstypes = array(
- 'home' => Address::Home,
- 'work' => Address::Work,
- 'office' => 0,
- );
-
- private $gendermap = array(
- 'female' => Contact::Female,
- 'male' => Contact::Male,
- );
-
- private $relatedmap = array(
- 'manager' => Related::Manager,
- 'assistant' => Related::Assistant,
- 'spouse' => Related::Spouse,
- 'children' => Related::Child,
- );
-
-
- /**
- * Default constructor
- */
- function __construct($xmldata = null, $version = 3.0)
- {
- parent::__construct($xmldata, $version);
-
- // complete phone types
- $this->phonetypes['homefax'] |= Telephone::Home;
- $this->phonetypes['workfax'] |= Telephone::Work;
- }
-
- /**
- * Set contact properties to the kolabformat object
- *
- * @param array Contact data as hash array
- */
- public function set(&$object)
- {
- // set common object properties
- parent::set($object);
-
- // do the hard work of setting object values
- $nc = new NameComponents;
- $nc->setSurnames(self::array2vector($object['surname']));
- $nc->setGiven(self::array2vector($object['firstname']));
- $nc->setAdditional(self::array2vector($object['middlename']));
- $nc->setPrefixes(self::array2vector($object['prefix']));
- $nc->setSuffixes(self::array2vector($object['suffix']));
- $this->obj->setNameComponents($nc);
- $this->obj->setName($object['name']);
- $this->obj->setCategories(self::array2vector($object['categories']));
-
- if (isset($object['nickname']))
- $this->obj->setNickNames(self::array2vector($object['nickname']));
- if (isset($object['jobtitle']))
- $this->obj->setTitles(self::array2vector($object['jobtitle']));
-
- // organisation related properties (affiliation)
- $org = new Affiliation;
- $offices = new vectoraddress;
- if ($object['organization'])
- $org->setOrganisation($object['organization']);
- if ($object['department'])
- $org->setOrganisationalUnits(self::array2vector($object['department']));
- if ($object['profession'])
- $org->setRoles(self::array2vector($object['profession']));
-
- $rels = new vectorrelated;
- foreach (array('manager','assistant') as $field) {
- if (!empty($object[$field])) {
- $reltype = $this->relatedmap[$field];
- foreach ((array)$object[$field] as $value) {
- $rels->push(new Related(Related::Text, $value, $reltype));
- }
- }
- }
- $org->setRelateds($rels);
-
- // im, email, url
- $this->obj->setIMaddresses(self::array2vector($object['im']));
-
- if (class_exists('vectoremail')) {
- $vemails = new vectoremail;
- foreach ((array)$object['email'] as $email) {
- $type = $this->emailtypes[$email['type']];
- $vemails->push(new Email($email['address'], intval($type)));
- }
- }
- else {
- $vemails = self::array2vector(array_map(function($v){ return $v['address']; }, $object['email']));
- }
- $this->obj->setEmailAddresses($vemails);
-
- $vurls = new vectorurl;
- foreach ((array)$object['website'] as $url) {
- $type = $url['type'] == 'blog' ? Url::Blog : Url::NoType;
- $vurls->push(new Url($url['url'], $type));
- }
- $this->obj->setUrls($vurls);
-
- // addresses
- $adrs = new vectoraddress;
- foreach ((array)$object['address'] as $address) {
- $adr = new Address;
- $type = $this->addresstypes[$address['type']];
- if (isset($type))
- $adr->setTypes($type);
- else if ($address['type'])
- $adr->setLabel($address['type']);
- if ($address['street'])
- $adr->setStreet($address['street']);
- if ($address['locality'])
- $adr->setLocality($address['locality']);
- if ($address['code'])
- $adr->setCode($address['code']);
- if ($address['region'])
- $adr->setRegion($address['region']);
- if ($address['country'])
- $adr->setCountry($address['country']);
-
- if ($address['type'] == 'office')
- $offices->push($adr);
- else
- $adrs->push($adr);
- }
- $this->obj->setAddresses($adrs);
- $org->setAddresses($offices);
-
- // add org affiliation after addresses are set
- $orgs = new vectoraffiliation;
- $orgs->push($org);
- $this->obj->setAffiliations($orgs);
-
- // telephones
- $tels = new vectortelephone;
- foreach ((array)$object['phone'] as $phone) {
- $tel = new Telephone;
- if (isset($this->phonetypes[$phone['type']]))
- $tel->setTypes($this->phonetypes[$phone['type']]);
- $tel->setNumber($phone['number']);
- $tels->push($tel);
- }
- $this->obj->setTelephones($tels);
-
- if (isset($object['gender']))
- $this->obj->setGender($this->gendermap[$object['gender']] ? $this->gendermap[$object['gender']] : Contact::NotSet);
- if (isset($object['notes']))
- $this->obj->setNote($object['notes']);
- if (isset($object['freebusyurl']))
- $this->obj->setFreeBusyUrl($object['freebusyurl']);
- if (isset($object['lang']))
- $this->obj->setLanguages(self::array2vector($object['lang']));
- if (isset($object['birthday']))
- $this->obj->setBDay(self::get_datetime($object['birthday'], false, true));
- if (isset($object['anniversary']))
- $this->obj->setAnniversary(self::get_datetime($object['anniversary'], false, true));
-
- if (!empty($object['photo'])) {
- if ($type = rcube_mime::image_content_type($object['photo']))
- $this->obj->setPhoto($object['photo'], $type);
- }
- else if (isset($object['photo']))
- $this->obj->setPhoto('','');
- else if ($this->obj->photoMimetype()) // load saved photo for caching
- $object['photo'] = $this->obj->photo();
-
- // spouse and children are relateds
- $rels = new vectorrelated;
- foreach (array('spouse','children') as $field) {
- if (!empty($object[$field])) {
- $reltype = $this->relatedmap[$field];
- foreach ((array)$object[$field] as $value) {
- $rels->push(new Related(Related::Text, $value, $reltype));
- }
- }
- }
- // add other relateds
- if (is_array($object['related'])) {
- foreach ($object['related'] as $value) {
- $rels->push(new Related(Related::Text, $value));
- }
- }
- $this->obj->setRelateds($rels);
-
- // insert/replace crypto keys
- $pgp_index = $pkcs7_index = -1;
- $keys = $this->obj->keys();
- for ($i=0; $i < $keys->size(); $i++) {
- $key = $keys->get($i);
- if ($pgp_index < 0 && $key->type() == Key::PGP)
- $pgp_index = $i;
- else if ($pkcs7_index < 0 && $key->type() == Key::PKCS7_MIME)
- $pkcs7_index = $i;
- }
-
- $pgpkey = $object['pgppublickey'] ? new Key($object['pgppublickey'], Key::PGP) : new Key();
- $pkcs7key = $object['pkcs7publickey'] ? new Key($object['pkcs7publickey'], Key::PKCS7_MIME) : new Key();
-
- if ($pgp_index >= 0)
- $keys->set($pgp_index, $pgpkey);
- else if (!empty($object['pgppublickey']))
- $keys->push($pgpkey);
- if ($pkcs7_index >= 0)
- $keys->set($pkcs7_index, $pkcs7key);
- else if (!empty($object['pkcs7publickey']))
- $keys->push($pkcs7key);
-
- $this->obj->setKeys($keys);
-
- // TODO: handle language, gpslocation, etc.
-
- // set type property for proper caching
- $object['_type'] = 'contact';
-
- // cache this data
- $this->data = $object;
- unset($this->data['_formatobj']);
- }
-
- /**
- *
- */
- public function is_valid()
- {
- return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->uid() /*$this->obj->isValid()*/));
- }
-
- /**
- * Convert the Contact object into a hash array data structure
- *
- * @param array Additional data for merge
- *
- * @return array Contact data as hash array
- */
- public function to_array($data = array())
- {
- // return cached result
- if (!empty($this->data))
- return $this->data;
-
- // read common object props into local data object
- $object = parent::to_array($data);
-
- $object['name'] = $this->obj->name();
-
- $nc = $this->obj->nameComponents();
- $object['surname'] = join(' ', self::vector2array($nc->surnames()));
- $object['firstname'] = join(' ', self::vector2array($nc->given()));
- $object['middlename'] = join(' ', self::vector2array($nc->additional()));
- $object['prefix'] = join(' ', self::vector2array($nc->prefixes()));
- $object['suffix'] = join(' ', self::vector2array($nc->suffixes()));
- $object['nickname'] = join(' ', self::vector2array($this->obj->nickNames()));
- $object['jobtitle'] = join(' ', self::vector2array($this->obj->titles()));
- $object['categories'] = self::vector2array($this->obj->categories());
-
- // organisation related properties (affiliation)
- $orgs = $this->obj->affiliations();
- if ($orgs->size()) {
- $org = $orgs->get(0);
- $object['organization'] = $org->organisation();
- $object['profession'] = join(' ', self::vector2array($org->roles()));
- $object['department'] = join(' ', self::vector2array($org->organisationalUnits()));
- $this->read_relateds($org->relateds(), $object);
- }
-
- $object['im'] = self::vector2array($this->obj->imAddresses());
-
- $emails = $this->obj->emailAddresses();
- if ($emails instanceof vectoremail) {
- $emailtypes = array_flip($this->emailtypes);
- for ($i=0; $i < $emails->size(); $i++) {
- $email = $emails->get($i);
- $object['email'][] = array('address' => $email->address(), 'type' => $emailtypes[$email->types()]);
- }
- }
- else {
- $object['email'] = self::vector2array($emails);
- }
-
- $urls = $this->obj->urls();
- for ($i=0; $i < $urls->size(); $i++) {
- $url = $urls->get($i);
- $subtype = $url->type() == Url::Blog ? 'blog' : 'homepage';
- $object['website'][] = array('url' => $url->url(), 'type' => $subtype);
- }
-
- // addresses
- $this->read_addresses($this->obj->addresses(), $object);
- if ($org && ($offices = $org->addresses()))
- $this->read_addresses($offices, $object, 'office');
-
- // telehones
- $tels = $this->obj->telephones();
- $teltypes = array_flip($this->phonetypes);
- for ($i=0; $i < $tels->size(); $i++) {
- $tel = $tels->get($i);
- $object['phone'][] = array('number' => $tel->number(), 'type' => $teltypes[$tel->types()]);
- }
-
- $object['notes'] = $this->obj->note();
- $object['freebusyurl'] = $this->obj->freeBusyUrl();
- $object['lang'] = self::vector2array($this->obj->languages());
-
- if ($bday = self::php_datetime($this->obj->bDay()))
- $object['birthday'] = $bday;
-
- if ($anniversary = self::php_datetime($this->obj->anniversary()))
- $object['anniversary'] = $anniversary;
-
- $gendermap = array_flip($this->gendermap);
- if (($g = $this->obj->gender()) && $gendermap[$g])
- $object['gender'] = $gendermap[$g];
-
- if ($this->obj->photoMimetype())
- $object['photo'] = $this->obj->photo();
- else if ($this->xmlobject && ($photo_name = $this->xmlobject->pictureAttachmentName()))
- $object['photo'] = $photo_name;
-
- // relateds -> spouse, children
- $this->read_relateds($this->obj->relateds(), $object, 'related');
-
- // crypto settings: currently only key values are supported
- $keys = $this->obj->keys();
- for ($i=0; is_object($keys) && $i < $keys->size(); $i++) {
- $key = $keys->get($i);
- if ($key->type() == Key::PGP)
- $object['pgppublickey'] = $key->key();
- else if ($key->type() == Key::PKCS7_MIME)
- $object['pkcs7publickey'] = $key->key();
- }
-
- $this->data = $object;
- return $this->data;
- }
-
- /**
- * Callback for kolab_storage_cache to get words to index for fulltext search
- *
- * @return array List of words to save in cache
- */
- public function get_words()
- {
- $data = '';
- foreach (self::$fulltext_cols as $colname) {
- list($col, $field) = explode(':', $colname);
-
- if ($field) {
- $a = array();
- foreach ((array)$this->data[$col] as $attr)
- $a[] = $attr[$field];
- $val = join(' ', $a);
- }
- else {
- $val = is_array($this->data[$col]) ? join(' ', $this->data[$col]) : $this->data[$col];
- }
-
- if (strlen($val))
- $data .= $val . ' ';
- }
-
- return array_unique(rcube_utils::normalize_string($data, true));
- }
-
- /**
- * Callback for kolab_storage_cache to get object specific tags to cache
- *
- * @return array List of tags to save in cache
- */
- public function get_tags()
- {
- $tags = array();
-
- if (!empty($this->data['birthday'])) {
- $tags[] = 'x-has-birthday';
- }
-
- return $tags;
- }
-
- /**
- * Helper method to copy contents of an Address vector to the contact data object
- */
- private function read_addresses($addresses, &$object, $type = null)
- {
- $adrtypes = array_flip($this->addresstypes);
-
- for ($i=0; $i < $addresses->size(); $i++) {
- $adr = $addresses->get($i);
- $object['address'][] = array(
- 'type' => $type ? $type : ($adrtypes[$adr->types()] ? $adrtypes[$adr->types()] : ''), /*$adr->label()),*/
- 'street' => $adr->street(),
- 'code' => $adr->code(),
- 'locality' => $adr->locality(),
- 'region' => $adr->region(),
- 'country' => $adr->country()
- );
- }
- }
-
- /**
- * Helper method to map contents of a Related vector to the contact data object
- */
- private function read_relateds($rels, &$object, $catchall = null)
- {
- $typemap = array_flip($this->relatedmap);
-
- for ($i=0; $i < $rels->size(); $i++) {
- $rel = $rels->get($i);
- if ($rel->type() != Related::Text) // we can't handle UID relations yet
- continue;
-
- $known = false;
- $types = $rel->relationTypes();
- foreach ($typemap as $t => $field) {
- if ($types & $t) {
- $object[$field][] = $rel->text();
- $known = true;
- break;
- }
- }
-
- if (!$known && $catchall) {
- $object[$catchall][] = $rel->text();
- }
- }
- }
-}
diff --git a/lib/plugins/libkolab/lib/kolab_format_distributionlist.php b/lib/plugins/libkolab/lib/kolab_format_distributionlist.php
deleted file mode 100644
index 88c6f7b..0000000
--- a/lib/plugins/libkolab/lib/kolab_format_distributionlist.php
+++ /dev/null
@@ -1,125 +0,0 @@
-<?php
-
-/**
- * Kolab Distribution List model class
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_format_distributionlist extends kolab_format
-{
- public $CTYPE = 'application/vcard+xml';
- public $CTYPEv2 = 'application/x-vnd.kolab.distribution-list';
-
- protected $objclass = 'DistList';
- protected $read_func = 'readDistlist';
- protected $write_func = 'writeDistlist';
-
-
- /**
- * Set properties to the kolabformat object
- *
- * @param array Object data as hash array
- */
- public function set(&$object)
- {
- // set common object properties
- parent::set($object);
-
- $this->obj->setName($object['name']);
-
- $seen = array();
- $members = new vectorcontactref;
- foreach ((array)$object['member'] as $i => $member) {
- if ($member['uid']) {
- $key = 'uid:' . $member['uid'];
- $m = new ContactReference(ContactReference::UidReference, $member['uid']);
- }
- else if ($member['email']) {
- $key = 'mailto:' . $member['email'];
- $m = new ContactReference(ContactReference::EmailReference, $member['email']);
- $m->setName($member['name']);
- }
- else {
- continue;
- }
-
- if (!$seen[$key]++) {
- $members->push($m);
- }
- else {
- // remove dupes for caching
- unset($object['member'][$i]);
- }
- }
-
- $this->obj->setMembers($members);
-
- // set type property for proper caching
- $object['_type'] = 'distribution-list';
-
- // cache this data
- $this->data = $object;
- unset($this->data['_formatobj']);
- }
-
- public function is_valid()
- {
- return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->isValid()));
- }
-
- /**
- * Convert the Distlist object into a hash array data structure
- *
- * @param array Additional data for merge
- *
- * @return array Distribution list data as hash array
- */
- public function to_array($data = array())
- {
- // return cached result
- if (!empty($this->data))
- return $this->data;
-
- // read common object props into local data object
- $object = parent::to_array($data);
-
- // add object properties
- $object += array(
- 'name' => $this->obj->name(),
- 'member' => array(),
- '_type' => 'distribution-list',
- );
-
- $members = $this->obj->members();
- for ($i=0; $i < $members->size(); $i++) {
- $member = $members->get($i);
-// if ($member->type() == ContactReference::UidReference && ($uid = $member->uid()))
- $object['member'][] = array(
- 'uid' => $member->uid(),
- 'email' => $member->email(),
- 'name' => $member->name(),
- );
- }
-
- $this->data = $object;
- return $this->data;
- }
-
-}
diff --git a/lib/plugins/libkolab/lib/kolab_format_event.php b/lib/plugins/libkolab/lib/kolab_format_event.php
deleted file mode 100644
index 8cad89a..0000000
--- a/lib/plugins/libkolab/lib/kolab_format_event.php
+++ /dev/null
@@ -1,244 +0,0 @@
-<?php
-
-/**
- * Kolab Event model class
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_format_event extends kolab_format_xcal
-{
- public $CTYPEv2 = 'application/x-vnd.kolab.event';
-
- public $scheduling_properties = array('start', 'end', 'allday', 'location', 'status', 'cancelled');
-
- protected $objclass = 'Event';
- protected $read_func = 'readEvent';
- protected $write_func = 'writeEvent';
-
- /**
- * Default constructor
- */
- function __construct($data = null, $version = 3.0)
- {
- parent::__construct(is_string($data) ? $data : null, $version);
-
- // got an Event object as argument
- if (is_object($data) && is_a($data, $this->objclass)) {
- $this->obj = $data;
- $this->loaded = true;
- }
- }
-
- /**
- * Clones into an instance of libcalendaring's extended EventCal class
- *
- * @return mixed EventCal object or false on failure
- */
- public function to_libcal()
- {
- static $error_logged = false;
-
- if (class_exists('kolabcalendaring')) {
- return new EventCal($this->obj);
- }
- else if (!$error_logged) {
- $error_logged = true;
- rcube::raise_error(array(
- 'code' => 900, 'type' => 'php',
- 'message' => "required kolabcalendaring module not found"
- ), true);
- }
-
- return false;
- }
-
- /**
- * Set event properties to the kolabformat object
- *
- * @param array Event data as hash array
- */
- public function set(&$object)
- {
- // set common xcal properties
- parent::set($object);
-
- // do the hard work of setting object values
- $this->obj->setStart(self::get_datetime($object['start'], null, $object['allday']));
- $this->obj->setEnd(self::get_datetime($object['end'], null, $object['allday']));
- $this->obj->setTransparency($object['free_busy'] == 'free');
-
- $status = kolabformat::StatusUndefined;
- if ($object['free_busy'] == 'tentative')
- $status = kolabformat::StatusTentative;
- if ($object['cancelled'])
- $status = kolabformat::StatusCancelled;
- else if ($object['status'] && array_key_exists($object['status'], $this->status_map))
- $status = $this->status_map[$object['status']];
- $this->obj->setStatus($status);
-
- // save recurrence exceptions
- if (is_array($object['recurrence']) && $object['recurrence']['EXCEPTIONS']) {
- $vexceptions = new vectorevent;
- foreach((array)$object['recurrence']['EXCEPTIONS'] as $i => $exception) {
- $exevent = new kolab_format_event;
- $exevent->set(($compacted = $this->compact_exception($exception, $object))); // only save differing values
- $exevent->obj->setRecurrenceID(self::get_datetime($exception['start'], null, true), (bool)$exception['thisandfuture']);
- $vexceptions->push($exevent->obj);
- // write cleaned-up exception data back to memory/cache
- $object['recurrence']['EXCEPTIONS'][$i] = $this->expand_exception($compacted, $object);
- }
- $this->obj->setExceptions($vexceptions);
- }
-
- // cache this data
- $this->data = $object;
- unset($this->data['_formatobj']);
- }
-
- /**
- *
- */
- public function is_valid()
- {
- return !$this->formaterror && (($this->data && !empty($this->data['start']) && !empty($this->data['end'])) ||
- (is_object($this->obj) && $this->obj->isValid() && $this->obj->uid()));
- }
-
- /**
- * Convert the Event object into a hash array data structure
- *
- * @param array Additional data for merge
- *
- * @return array Event data as hash array
- */
- public function to_array($data = array())
- {
- // return cached result
- if (!empty($this->data))
- return $this->data;
-
- // read common xcal props
- $object = parent::to_array($data);
-
- // read object properties
- $object += array(
- 'end' => self::php_datetime($this->obj->end()),
- 'allday' => $this->obj->start()->isDateOnly(),
- 'free_busy' => $this->obj->transparency() ? 'free' : 'busy', // TODO: transparency is only boolean
- 'attendees' => array(),
- );
-
- // derive event end from duration (#1916)
- if (!$object['end'] && $object['start'] && ($duration = $this->obj->duration()) && $duration->isValid()) {
- $interval = new DateInterval('PT0S');
- $interval->d = $duration->weeks() * 7 + $duration->days();
- $interval->h = $duration->hours();
- $interval->i = $duration->minutes();
- $interval->s = $duration->seconds();
- $object['end'] = clone $object['start'];
- $object['end']->add($interval);
- }
-
- // organizer is part of the attendees list in Roundcube
- if ($object['organizer']) {
- $object['organizer']['role'] = 'ORGANIZER';
- array_unshift($object['attendees'], $object['organizer']);
- }
-
- // status defines different event properties...
- $status = $this->obj->status();
- if ($status == kolabformat::StatusTentative)
- $object['free_busy'] = 'tentative';
- else if ($status == kolabformat::StatusCancelled)
- $object['cancelled'] = true;
-
- // this is an exception object
- if ($this->obj->recurrenceID()->isValid()) {
- $object['thisandfuture'] = $this->obj->thisAndFuture();
- }
- // read exception event objects
- else if (($exceptions = $this->obj->exceptions()) && is_object($exceptions) && $exceptions->size()) {
- $recurrence_exceptions = array();
- for ($i=0; $i < $exceptions->size(); $i++) {
- if (($exobj = $exceptions->get($i))) {
- $exception = new kolab_format_event($exobj);
- if ($exception->is_valid()) {
- $recurrence_exceptions[] = $this->expand_exception($exception->to_array(), $object);
- }
- }
- }
- $object['recurrence']['EXCEPTIONS'] = $recurrence_exceptions;
- }
-
- return $this->data = $object;
- }
-
- /**
- * Callback for kolab_storage_cache to get object specific tags to cache
- *
- * @return array List of tags to save in cache
- */
- public function get_tags()
- {
- $tags = parent::get_tags();
-
- foreach ((array)$this->data['categories'] as $cat) {
- $tags[] = rcube_utils::normalize_string($cat);
- }
-
- return $tags;
- }
-
- /**
- * Remove some attributes from the exception container
- */
- private function compact_exception($exception, $master)
- {
- $forbidden = array('recurrence','organizer','attendees','sequence');
-
- foreach ($forbidden as $prop) {
- if (array_key_exists($prop, $exception)) {
- unset($exception[$prop]);
- }
- }
-
- foreach ($master as $prop => $value) {
- if (isset($exception[$prop]) && gettype($exception[$prop]) == gettype($value) && $exception[$prop] == $value) {
- unset($exception[$prop]);
- }
- }
-
- return $exception;
- }
-
- /**
- * Copy attributes not specified by the exception from the master event
- */
- private function expand_exception($exception, $master)
- {
- foreach ($master as $prop => $value) {
- if (empty($exception[$prop]) && !empty($value))
- $exception[$prop] = $value;
- }
-
- return $exception;
- }
-
-}
diff --git a/lib/plugins/libkolab/lib/kolab_format_file.php b/lib/plugins/libkolab/lib/kolab_format_file.php
deleted file mode 100644
index 34c0ca6..0000000
--- a/lib/plugins/libkolab/lib/kolab_format_file.php
+++ /dev/null
@@ -1,156 +0,0 @@
-<?php
-
-/**
- * Kolab File model class
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- * @author Aleksander Machniak <machniak@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_format_file extends kolab_format
-{
- public $CTYPE = 'application/vnd.kolab+xml';
-
- protected $objclass = 'File';
- protected $read_func = 'kolabformat::readKolabFile';
- protected $write_func = 'kolabformat::writeKolabFile';
-
- protected $sensitivity_map = array(
- 'public' => kolabformat::ClassPublic,
- 'private' => kolabformat::ClassPrivate,
- 'confidential' => kolabformat::ClassConfidential,
- );
-
- /**
- * Set properties to the kolabformat object
- *
- * @param array Object data as hash array
- */
- public function set(&$object)
- {
- // set common object properties
- parent::set($object);
-
- $this->obj->setClassification($this->sensitivity_map[$object['sensitivity']]);
- $this->obj->setCategories(self::array2vector($object['categories']));
-
- if (isset($object['notes'])) {
- $this->obj->setNote($object['notes']);
- }
-
- // Add file attachment
- if (!empty($object['_attachments'])) {
- $cid = key($object['_attachments']);
- $attach_attr = $object['_attachments'][$cid];
- $attach = new Attachment;
-
- $attach->setLabel((string)$attach_attr['name']);
- $attach->setUri('cid:' . $cid, $attach_attr['mimetype']);
- $this->obj->setFile($attach);
-
- // make sure size is set, so object saved in cache contains this info
- if (!isset($attach_attr['size'])) {
- $size = 0;
-
- if (!empty($attach_attr['content'])) {
- if (is_resource($attach_attr['content'])) {
- $stat = fstat($attach_attr['content']);
- $size = $stat ? $stat['size'] : 0;
- }
- else {
- $size = strlen($attach_attr['content']);
- }
- }
- else if (isset($attach_attr['path'])) {
- $size = @filesize($attach_attr['path']);
- }
-
- $object['_attachments'][$cid]['size'] = $size;
- }
- }
-
- // cache this data
- $this->data = $object;
- unset($this->data['_formatobj']);
- }
-
- /**
- * Check if object's data validity
- */
- public function is_valid()
- {
- return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->isValid()));
- }
-
- /**
- * Convert the Configuration object into a hash array data structure
- *
- * @param array Additional data for merge
- *
- * @return array Config object data as hash array
- */
- public function to_array($data = array())
- {
- // return cached result
- if (!empty($this->data)) {
- return $this->data;
- }
-
- // read common object props into local data object
- $object = parent::to_array($data);
-
- $sensitivity_map = array_flip($this->sensitivity_map);
-
- // read object properties
- $object += array(
- 'sensitivity' => $sensitivity_map[$this->obj->classification()],
- 'categories' => self::vector2array($this->obj->categories()),
- 'notes' => $this->obj->note(),
- );
-
- return $this->data = $object;
- }
-
- /**
- * Callback for kolab_storage_cache to get object specific tags to cache
- *
- * @return array List of tags to save in cache
- */
- public function get_tags()
- {
- $tags = array();
-
- foreach ((array)$this->data['categories'] as $cat) {
- $tags[] = rcube_utils::normalize_string($cat);
- }
-
- // Add file mimetype to tags
- if (!empty($this->data['_attachments'])) {
- reset($this->data['_attachments']);
- $key = key($this->data['_attachments']);
- $attachment = $this->data['_attachments'][$key];
-
- if ($attachment['mimetype']) {
- $tags[] = $attachment['mimetype'];
- }
- }
-
- return $tags;
- }
-}
diff --git a/lib/plugins/libkolab/lib/kolab_format_journal.php b/lib/plugins/libkolab/lib/kolab_format_journal.php
deleted file mode 100644
index f7ccd31..0000000
--- a/lib/plugins/libkolab/lib/kolab_format_journal.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-
-/**
- * Kolab Journal model class
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_format_journal extends kolab_format
-{
- public $CTYPE = 'application/calendar+xml';
- public $CTYPEv2 = 'application/x-vnd.kolab.journal';
-
- protected $objclass = 'Journal';
- protected $read_func = 'readJournal';
- protected $write_func = 'writeJournal';
-
-
- /**
- * Set properties to the kolabformat object
- *
- * @param array Object data as hash array
- */
- public function set(&$object)
- {
- // set common object properties
- parent::set($object);
-
- // TODO: set object propeties
-
- // cache this data
- $this->data = $object;
- unset($this->data['_formatobj']);
- }
-
- /**
- *
- */
- public function is_valid()
- {
- return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->isValid()));
- }
-
- /**
- * Convert the Configuration object into a hash array data structure
- *
- * @param array Additional data for merge
- *
- * @return array Config object data as hash array
- */
- public function to_array($data = array())
- {
- // return cached result
- if (!empty($this->data))
- return $this->data;
-
- // read common object props into local data object
- $object = parent::to_array($data);
-
- // TODO: read object properties
-
- $this->data = $object;
- return $this->data;
- }
-
-}
diff --git a/lib/plugins/libkolab/lib/kolab_format_note.php b/lib/plugins/libkolab/lib/kolab_format_note.php
deleted file mode 100644
index bca5156..0000000
--- a/lib/plugins/libkolab/lib/kolab_format_note.php
+++ /dev/null
@@ -1,153 +0,0 @@
-<?php
-
-/**
- * Kolab Note model class
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_format_note extends kolab_format
-{
- public $CTYPE = 'application/vnd.kolab+xml';
- public $CTYPEv2 = 'application/x-vnd.kolab.note';
-
- public static $fulltext_cols = array('title', 'description', 'categories');
-
- protected $objclass = 'Note';
- protected $read_func = 'readNote';
- protected $write_func = 'writeNote';
-
- protected $sensitivity_map = array(
- 'public' => kolabformat::ClassPublic,
- 'private' => kolabformat::ClassPrivate,
- 'confidential' => kolabformat::ClassConfidential,
- );
-
- /**
- * Set properties to the kolabformat object
- *
- * @param array Object data as hash array
- */
- public function set(&$object)
- {
- // set common object properties
- parent::set($object);
-
- $this->obj->setSummary($object['title']);
- $this->obj->setDescription($object['description']);
- $this->obj->setClassification($this->sensitivity_map[$object['sensitivity']]);
- $this->obj->setCategories(self::array2vector($object['categories']));
-
- $this->set_attachments($object);
-
- // cache this data
- $this->data = $object;
- unset($this->data['_formatobj']);
- }
-
- /**
- *
- */
- public function is_valid()
- {
- return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->isValid()));
- }
-
- /**
- * Convert the Configuration object into a hash array data structure
- *
- * @param array Additional data for merge
- *
- * @return array Config object data as hash array
- */
- public function to_array($data = array())
- {
- // return cached result
- if (!empty($this->data))
- return $this->data;
-
- // read common object props into local data object
- $object = parent::to_array($data);
-
- $sensitivity_map = array_flip($this->sensitivity_map);
-
- // read object properties
- $object += array(
- 'sensitivity' => $sensitivity_map[$this->obj->classification()],
- 'categories' => self::vector2array($this->obj->categories()),
- 'title' => $this->obj->summary(),
- 'description' => $this->obj->description(),
- );
-
- $this->get_attachments($object);
-
- return $this->data = $object;
- }
-
- /**
- * Callback for kolab_storage_cache to get object specific tags to cache
- *
- * @return array List of tags to save in cache
- */
- public function get_tags()
- {
- $tags = array();
-
- foreach ((array)$this->data['categories'] as $cat) {
- $tags[] = rcube_utils::normalize_string($cat);
- }
-
- // add tag for message references
- foreach ((array)$this->data['links'] as $link) {
- $url = parse_url($link);
- if ($url['scheme'] == 'imap') {
- parse_str($url['query'], $param);
- $tags[] = 'ref:' . trim($param['message-id'] ?: urldecode($url['fragment']), '<> ');
- }
- }
-
- return $tags;
- }
-
- /**
- * Callback for kolab_storage_cache to get words to index for fulltext search
- *
- * @return array List of words to save in cache
- */
- public function get_words()
- {
- $data = '';
- foreach (self::$fulltext_cols as $col) {
- // convert HTML content to plain text
- if ($col == 'description' && preg_match('/<(html|body)(\s[a-z]|>)/', $this->data[$col], $m) && strpos($this->data[$col], '</'.$m[1].'>')) {
- $converter = new rcube_html2text($this->data[$col], false, false, 0);
- $val = $converter->get_text();
- }
- else {
- $val = is_array($this->data[$col]) ? join(' ', $this->data[$col]) : $this->data[$col];
- }
-
- if (strlen($val))
- $data .= $val . ' ';
- }
-
- return array_filter(array_unique(rcube_utils::normalize_string($data, true)));
- }
-
-}
diff --git a/lib/plugins/libkolab/lib/kolab_format_task.php b/lib/plugins/libkolab/lib/kolab_format_task.php
deleted file mode 100644
index 52744d4..0000000
--- a/lib/plugins/libkolab/lib/kolab_format_task.php
+++ /dev/null
@@ -1,129 +0,0 @@
-<?php
-
-/**
- * Kolab Task (ToDo) model class
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_format_task extends kolab_format_xcal
-{
- public $CTYPEv2 = 'application/x-vnd.kolab.task';
-
- public $scheduling_properties = array('start', 'due', 'summary', 'status');
-
- protected $objclass = 'Todo';
- protected $read_func = 'readTodo';
- protected $write_func = 'writeTodo';
-
-
- /**
- * Set properties to the kolabformat object
- *
- * @param array Object data as hash array
- */
- public function set(&$object)
- {
- // set common xcal properties
- parent::set($object);
-
- $this->obj->setPercentComplete(intval($object['complete']));
-
- $status = kolabformat::StatusUndefined;
- if ($object['complete'] == 100 && !array_key_exists('status', $object))
- $status = kolabformat::StatusCompleted;
- else if ($object['status'] && array_key_exists($object['status'], $this->status_map))
- $status = $this->status_map[$object['status']];
- $this->obj->setStatus($status);
-
- $this->obj->setStart(self::get_datetime($object['start'], null, $object['start']->_dateonly));
- $this->obj->setDue(self::get_datetime($object['due'], null, $object['due']->_dateonly));
-
- $related = new vectors;
- if (!empty($object['parent_id']))
- $related->push($object['parent_id']);
- $this->obj->setRelatedTo($related);
-
- // cache this data
- $this->data = $object;
- unset($this->data['_formatobj']);
- }
-
- /**
- *
- */
- public function is_valid()
- {
- return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->isValid()));
- }
-
- /**
- * Convert the Configuration object into a hash array data structure
- *
- * @param array Additional data for merge
- *
- * @return array Config object data as hash array
- */
- public function to_array($data = array())
- {
- // return cached result
- if (!empty($this->data))
- return $this->data;
-
- // read common xcal props
- $object = parent::to_array($data);
-
- $object['complete'] = intval($this->obj->percentComplete());
-
- // if due date is set
- if ($due = $this->obj->due())
- $object['due'] = self::php_datetime($due);
-
- // related-to points to parent task; we only support one relation
- $related = self::vector2array($this->obj->relatedTo());
- if (count($related))
- $object['parent_id'] = $related[0];
-
- // TODO: map more properties
-
- $this->data = $object;
- return $this->data;
- }
-
- /**
- * Callback for kolab_storage_cache to get object specific tags to cache
- *
- * @return array List of tags to save in cache
- */
- public function get_tags()
- {
- $tags = parent::get_tags();
-
- if ($this->data['status'] == 'COMPLETED' || ($this->data['complete'] == 100 && empty($this->data['status'])))
- $tags[] = 'x-complete';
-
- if ($this->data['priority'] == 1)
- $tags[] = 'x-flagged';
-
- if ($this->data['parent_id'])
- $tags[] = 'x-parent:' . $this->data['parent_id'];
-
- return $tags;
- }
-}
diff --git a/lib/plugins/libkolab/lib/kolab_format_xcal.php b/lib/plugins/libkolab/lib/kolab_format_xcal.php
deleted file mode 100644
index ad54505..0000000
--- a/lib/plugins/libkolab/lib/kolab_format_xcal.php
+++ /dev/null
@@ -1,630 +0,0 @@
-<?php
-
-/**
- * Xcal based Kolab format class wrapping libkolabxml bindings
- *
- * Base class for xcal-based Kolab groupware objects such as event, todo, journal
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-abstract class kolab_format_xcal extends kolab_format
-{
- public $CTYPE = 'application/calendar+xml';
-
- public static $fulltext_cols = array('title', 'description', 'location', 'attendees:name', 'attendees:email', 'categories');
-
- public $scheduling_properties = array('start', 'end', 'location');
-
- protected $sensitivity_map = array(
- 'public' => kolabformat::ClassPublic,
- 'private' => kolabformat::ClassPrivate,
- 'confidential' => kolabformat::ClassConfidential,
- );
-
- protected $role_map = array(
- 'REQ-PARTICIPANT' => kolabformat::Required,
- 'OPT-PARTICIPANT' => kolabformat::Optional,
- 'NON-PARTICIPANT' => kolabformat::NonParticipant,
- 'CHAIR' => kolabformat::Chair,
- );
-
- protected $cutype_map = array(
- 'INDIVIDUAL' => kolabformat::CutypeIndividual,
- 'GROUP' => kolabformat::CutypeGroup,
- 'ROOM' => kolabformat::CutypeRoom,
- 'RESOURCE' => kolabformat::CutypeResource,
- 'UNKNOWN' => kolabformat::CutypeUnknown,
- );
-
- protected $rrule_type_map = array(
- 'MINUTELY' => RecurrenceRule::Minutely,
- 'HOURLY' => RecurrenceRule::Hourly,
- 'DAILY' => RecurrenceRule::Daily,
- 'WEEKLY' => RecurrenceRule::Weekly,
- 'MONTHLY' => RecurrenceRule::Monthly,
- 'YEARLY' => RecurrenceRule::Yearly,
- );
-
- protected $weekday_map = array(
- 'MO' => kolabformat::Monday,
- 'TU' => kolabformat::Tuesday,
- 'WE' => kolabformat::Wednesday,
- 'TH' => kolabformat::Thursday,
- 'FR' => kolabformat::Friday,
- 'SA' => kolabformat::Saturday,
- 'SU' => kolabformat::Sunday,
- );
-
- protected $alarm_type_map = array(
- 'DISPLAY' => Alarm::DisplayAlarm,
- 'EMAIL' => Alarm::EMailAlarm,
- 'AUDIO' => Alarm::AudioAlarm,
- );
-
- protected $status_map = array(
- 'NEEDS-ACTION' => kolabformat::StatusNeedsAction,
- 'IN-PROCESS' => kolabformat::StatusInProcess,
- 'COMPLETED' => kolabformat::StatusCompleted,
- 'CANCELLED' => kolabformat::StatusCancelled,
- 'TENTATIVE' => kolabformat::StatusTentative,
- 'CONFIRMED' => kolabformat::StatusConfirmed,
- 'DRAFT' => kolabformat::StatusDraft,
- 'FINAL' => kolabformat::StatusFinal,
- );
-
- protected $part_status_map = array(
- 'UNKNOWN' => kolabformat::PartNeedsAction,
- 'NEEDS-ACTION' => kolabformat::PartNeedsAction,
- 'TENTATIVE' => kolabformat::PartTentative,
- 'ACCEPTED' => kolabformat::PartAccepted,
- 'DECLINED' => kolabformat::PartDeclined,
- 'DELEGATED' => kolabformat::PartDelegated,
- );
-
-
- /**
- * Convert common xcard properties into a hash array data structure
- *
- * @param array Additional data for merge
- *
- * @return array Object data as hash array
- */
- public function to_array($data = array())
- {
- // read common object props
- $object = parent::to_array($data);
-
- $status_map = array_flip($this->status_map);
- $sensitivity_map = array_flip($this->sensitivity_map);
-
- $object += array(
- 'sequence' => intval($this->obj->sequence()),
- 'title' => $this->obj->summary(),
- 'location' => $this->obj->location(),
- 'description' => $this->obj->description(),
- 'url' => $this->obj->url(),
- 'status' => $status_map[$this->obj->status()],
- 'sensitivity' => $sensitivity_map[$this->obj->classification()],
- 'priority' => $this->obj->priority(),
- 'categories' => self::vector2array($this->obj->categories()),
- 'start' => self::php_datetime($this->obj->start()),
- );
-
- if (method_exists($this->obj, 'comment')) {
- $object['comment'] = $this->obj->comment();
- }
-
- // read organizer and attendees
- if (($organizer = $this->obj->organizer()) && ($organizer->email() || $organizer->name())) {
- $object['organizer'] = array(
- 'email' => $organizer->email(),
- 'name' => $organizer->name(),
- );
- }
-
- $role_map = array_flip($this->role_map);
- $cutype_map = array_flip($this->cutype_map);
- $part_status_map = array_flip($this->part_status_map);
- $attvec = $this->obj->attendees();
- for ($i=0; $i < $attvec->size(); $i++) {
- $attendee = $attvec->get($i);
- $cr = $attendee->contact();
- if ($cr->email() != $object['organizer']['email']) {
- $delegators = $delegatees = array();
- $vdelegators = $attendee->delegatedFrom();
- for ($j=0; $j < $vdelegators->size(); $j++) {
- $delegators[] = $vdelegators->get($j)->email();
- }
- $vdelegatees = $attendee->delegatedTo();
- for ($j=0; $j < $vdelegatees->size(); $j++) {
- $delegatees[] = $vdelegatees->get($j)->email();
- }
-
- $object['attendees'][] = array(
- 'role' => $role_map[$attendee->role()],
- 'cutype' => $cutype_map[$attendee->cutype()],
- 'status' => $part_status_map[$attendee->partStat()],
- 'rsvp' => $attendee->rsvp(),
- 'email' => $cr->email(),
- 'name' => $cr->name(),
- 'delegated-from' => $delegators,
- 'delegated-to' => $delegatees,
- );
- }
- }
-
- // read recurrence rule
- if (($rr = $this->obj->recurrenceRule()) && $rr->isValid()) {
- $rrule_type_map = array_flip($this->rrule_type_map);
- $object['recurrence'] = array('FREQ' => $rrule_type_map[$rr->frequency()]);
-
- if ($intvl = $rr->interval())
- $object['recurrence']['INTERVAL'] = $intvl;
-
- if (($count = $rr->count()) && $count > 0) {
- $object['recurrence']['COUNT'] = $count;
- }
- else if ($until = self::php_datetime($rr->end())) {
- $until->setTime($object['start']->format('G'), $object['start']->format('i'), 0);
- $object['recurrence']['UNTIL'] = $until;
- }
-
- if (($byday = $rr->byday()) && $byday->size()) {
- $weekday_map = array_flip($this->weekday_map);
- $weekdays = array();
- for ($i=0; $i < $byday->size(); $i++) {
- $daypos = $byday->get($i);
- $prefix = $daypos->occurence();
- $weekdays[] = ($prefix ? $prefix : '') . $weekday_map[$daypos->weekday()];
- }
- $object['recurrence']['BYDAY'] = join(',', $weekdays);
- }
-
- if (($bymday = $rr->bymonthday()) && $bymday->size()) {
- $object['recurrence']['BYMONTHDAY'] = join(',', self::vector2array($bymday));
- }
-
- if (($bymonth = $rr->bymonth()) && $bymonth->size()) {
- $object['recurrence']['BYMONTH'] = join(',', self::vector2array($bymonth));
- }
-
- if ($exdates = $this->obj->exceptionDates()) {
- for ($i=0; $i < $exdates->size(); $i++) {
- if ($exdate = self::php_datetime($exdates->get($i)))
- $object['recurrence']['EXDATE'][] = $exdate;
- }
- }
- }
-
- if ($rdates = $this->obj->recurrenceDates()) {
- for ($i=0; $i < $rdates->size(); $i++) {
- if ($rdate = self::php_datetime($rdates->get($i)))
- $object['recurrence']['RDATE'][] = $rdate;
- }
- }
-
- // read alarm
- $valarms = $this->obj->alarms();
- $alarm_types = array_flip($this->alarm_type_map);
- $object['valarms'] = array();
- for ($i=0; $i < $valarms->size(); $i++) {
- $alarm = $valarms->get($i);
- $type = $alarm_types[$alarm->type()];
-
- if ($type == 'DISPLAY' || $type == 'EMAIL' || $type == 'AUDIO') { // only some alarms are supported
- $valarm = array(
- 'action' => $type,
- 'summary' => $alarm->summary(),
- 'description' => $alarm->description(),
- );
-
- if ($type == 'EMAIL') {
- $valarm['attendees'] = array();
- $attvec = $alarm->attendees();
- for ($j=0; $j < $attvec->size(); $j++) {
- $cr = $attvec->get($j);
- $valarm['attendees'][] = $cr->email();
- }
- }
- else if ($type == 'AUDIO') {
- $attach = $alarm->audioFile();
- $valarm['uri'] = $attach->uri();
- }
-
- if ($start = self::php_datetime($alarm->start())) {
- $object['alarms'] = '@' . $start->format('U');
- $valarm['trigger'] = $start;
- }
- else if ($offset = $alarm->relativeStart()) {
- $prefix = $alarm->relativeTo() == kolabformat::End ? '+' : '-';
- $value = $time = '';
- if ($w = $offset->weeks()) $value .= $w . 'W';
- else if ($d = $offset->days()) $value .= $d . 'D';
- else if ($h = $offset->hours()) $time .= $h . 'H';
- else if ($m = $offset->minutes()) $time .= $m . 'M';
- else if ($s = $offset->seconds()) $time .= $s . 'S';
-
- // assume 'at event time'
- if (empty($value) && empty($time)) {
- $prefix = '';
- $time = '0S';
- }
-
- $object['alarms'] = $prefix . $value . $time;
- $valarm['trigger'] = $prefix . 'P' . $value . ($time ? 'T' . $time : '');
- }
-
- // read alarm duration and repeat properties
- if (($duration = $alarm->duration()) && $duration->isValid()) {
- $value = $time = '';
- if ($w = $duration->weeks()) $value .= $w . 'W';
- else if ($d = $duration->days()) $value .= $d . 'D';
- else if ($h = $duration->hours()) $time .= $h . 'H';
- else if ($m = $duration->minutes()) $time .= $m . 'M';
- else if ($s = $duration->seconds()) $time .= $s . 'S';
- $valarm['duration'] = 'P' . $value . ($time ? 'T' . $time : '');
- $valarm['repeat'] = $alarm->numrepeat();
- }
-
- $object['alarms'] .= ':' . $type; // legacy property
- $object['valarms'][] = array_filter($valarm);
- }
- }
-
- $this->get_attachments($object);
-
- return $object;
- }
-
-
- /**
- * Set common xcal properties to the kolabformat object
- *
- * @param array Event data as hash array
- */
- public function set(&$object)
- {
- $this->init();
-
- $is_new = !$this->obj->uid();
- $old_sequence = $this->obj->sequence();
- $reschedule = $is_new;
-
- // set common object properties
- parent::set($object);
-
- // set sequence value
- if (!isset($object['sequence'])) {
- if ($is_new) {
- $object['sequence'] = 0;
- }
- else {
- $object['sequence'] = $old_sequence;
- $old = $this->data['uid'] ? $this->data : $this->to_array();
-
- // increment sequence when updating properties relevant for scheduling.
- // RFC 5545: "It is incremented [...] each time the Organizer makes a significant revision to the calendar component."
- // TODO: make the list of properties considered 'significant' for scheduling configurable
- foreach ($this->scheduling_properties as $prop) {
- $a = $old[$prop];
- $b = $object[$prop];
- if ($object['allday'] && ($prop == 'start' || $prop == 'end') && $a instanceof DateTime && $b instanceof DateTime) {
- $a = $a->format('Y-m-d');
- $b = $b->format('Y-m-d');
- }
- if ($a != $b) {
- $object['sequence']++;
- break;
- }
- }
- }
- }
- $this->obj->setSequence(intval($object['sequence']));
-
- if ($object['sequence'] > $old_sequence) {
- $reschedule = true;
- }
-
- $this->obj->setSummary($object['title']);
- $this->obj->setLocation($object['location']);
- $this->obj->setDescription($object['description']);
- $this->obj->setPriority($object['priority']);
- $this->obj->setClassification($this->sensitivity_map[$object['sensitivity']]);
- $this->obj->setCategories(self::array2vector($object['categories']));
- $this->obj->setUrl(strval($object['url']));
-
- if (method_exists($this->obj, 'setComment')) {
- $this->obj->setComment($object['comment']);
- }
-
- // process event attendees
- $attendees = new vectorattendee;
- foreach ((array)$object['attendees'] as $i => $attendee) {
- if ($attendee['role'] == 'ORGANIZER') {
- $object['organizer'] = $attendee;
- }
- else if ($attendee['email'] != $object['organizer']['email']) {
- $cr = new ContactReference(ContactReference::EmailReference, $attendee['email']);
- $cr->setName($attendee['name']);
-
- // set attendee RSVP if missing
- if (!isset($attendee['rsvp'])) {
- $object['attendees'][$i]['rsvp'] = $attendee['rsvp'] = true;
- }
-
- $att = new Attendee;
- $att->setContact($cr);
- $att->setPartStat($this->part_status_map[$attendee['status']]);
- $att->setRole($this->role_map[$attendee['role']] ? $this->role_map[$attendee['role']] : kolabformat::Required);
- $att->setCutype($this->cutype_map[$attendee['cutype']] ? $this->cutype_map[$attendee['cutype']] : kolabformat::CutypeIndividual);
- $att->setRSVP((bool)$attendee['rsvp']);
-
- if (!empty($attendee['delegated-from'])) {
- $vdelegators = new vectorcontactref;
- foreach ((array)$attendee['delegated-from'] as $delegator) {
- $vdelegators->push(new ContactReference(ContactReference::EmailReference, $delegator));
- }
- $att->setDelegatedFrom($vdelegators);
- }
- if (!empty($attendee['delegated-to'])) {
- $vdelegatees = new vectorcontactref;
- foreach ((array)$attendee['delegated-to'] as $delegatee) {
- $vdelegatees->push(new ContactReference(ContactReference::EmailReference, $delegatee));
- }
- $att->setDelegatedTo($vdelegatees);
- }
-
- if ($att->isValid()) {
- $attendees->push($att);
- }
- else {
- rcube::raise_error(array(
- 'code' => 600, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Invalid event attendee: " . json_encode($attendee),
- ), true);
- }
- }
- }
- $this->obj->setAttendees($attendees);
-
- if ($object['organizer']) {
- $organizer = new ContactReference(ContactReference::EmailReference, $object['organizer']['email']);
- $organizer->setName($object['organizer']['name']);
- $this->obj->setOrganizer($organizer);
- }
-
- // save recurrence rule
- $rr = new RecurrenceRule;
- $rr->setFrequency(RecurrenceRule::FreqNone);
-
- if ($object['recurrence'] && !empty($object['recurrence']['FREQ'])) {
- $rr->setFrequency($this->rrule_type_map[$object['recurrence']['FREQ']]);
-
- if ($object['recurrence']['INTERVAL'])
- $rr->setInterval(intval($object['recurrence']['INTERVAL']));
-
- if ($object['recurrence']['BYDAY']) {
- $byday = new vectordaypos;
- foreach (explode(',', $object['recurrence']['BYDAY']) as $day) {
- $occurrence = 0;
- if (preg_match('/^([\d-]+)([A-Z]+)$/', $day, $m)) {
- $occurrence = intval($m[1]);
- $day = $m[2];
- }
- if (isset($this->weekday_map[$day]))
- $byday->push(new DayPos($occurrence, $this->weekday_map[$day]));
- }
- $rr->setByday($byday);
- }
-
- if ($object['recurrence']['BYMONTHDAY']) {
- $bymday = new vectori;
- foreach (explode(',', $object['recurrence']['BYMONTHDAY']) as $day)
- $bymday->push(intval($day));
- $rr->setBymonthday($bymday);
- }
-
- if ($object['recurrence']['BYMONTH']) {
- $bymonth = new vectori;
- foreach (explode(',', $object['recurrence']['BYMONTH']) as $month)
- $bymonth->push(intval($month));
- $rr->setBymonth($bymonth);
- }
-
- if ($object['recurrence']['COUNT'])
- $rr->setCount(intval($object['recurrence']['COUNT']));
- else if ($object['recurrence']['UNTIL'])
- $rr->setEnd(self::get_datetime($object['recurrence']['UNTIL'], null, true));
-
- if ($rr->isValid()) {
- // add exception dates (only if recurrence rule is valid)
- $exdates = new vectordatetime;
- foreach ((array)$object['recurrence']['EXDATE'] as $exdate)
- $exdates->push(self::get_datetime($exdate, null, true));
- $this->obj->setExceptionDates($exdates);
- }
- else {
- rcube::raise_error(array(
- 'code' => 600, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Invalid event recurrence rule: " . json_encode($object['recurrence']),
- ), true);
- }
- }
-
- $this->obj->setRecurrenceRule($rr);
-
- // save recurrence dates (aka RDATE)
- if (!empty($object['recurrence']['RDATE'])) {
- $rdates = new vectordatetime;
- foreach ((array)$object['recurrence']['RDATE'] as $rdate)
- $rdates->push(self::get_datetime($rdate, null, true));
- $this->obj->setRecurrenceDates($rdates);
- }
-
- // save alarm
- $valarms = new vectoralarm;
- if ($object['valarms']) {
- foreach ($object['valarms'] as $valarm) {
- if (!array_key_exists($valarm['action'], $this->alarm_type_map)) {
- continue; // skip unknown alarm types
- }
-
- if ($valarm['action'] == 'EMAIL') {
- $recipients = new vectorcontactref;
- foreach (($valarm['attendees'] ?: array($object['_owner'])) as $email) {
- $recipients->push(new ContactReference(ContactReference::EmailReference, $email));
- }
- $alarm = new Alarm(
- strval($valarm['summary'] ?: $object['title']),
- strval($valarm['description'] ?: $object['description']),
- $recipients
- );
- }
- else if ($valarm['action'] == 'AUDIO') {
- $attach = new Attachment;
- $attach->setUri($valarm['uri'] ?: 'null', 'unknown');
- $alarm = new Alarm($attach);
- }
- else {
- // action == DISPLAY
- $alarm = new Alarm(strval($valarm['summary'] ?: $object['title']));
- }
-
- if (is_object($valarm['trigger']) && $valarm['trigger'] instanceof DateTime) {
- $alarm->setStart(self::get_datetime($valarm['trigger'], new DateTimeZone('UTC')));
- }
- else {
- try {
- $prefix = $valarm['trigger'][0];
- $period = new DateInterval(preg_replace('/[^0-9PTWDHMS]/', '', $valarm['trigger']));
- $duration = new Duration($period->d, $period->h, $period->i, $period->s, $prefix == '-');
- }
- catch (Exception $e) {
- // skip alarm with invalid trigger values
- rcube::raise_error($e, true);
- continue;
- }
-
- $alarm->setRelativeStart($duration, $prefix == '-' ? kolabformat::Start : kolabformat::End);
- }
-
- if ($valarm['duration']) {
- try {
- $d = new DateInterval($valarm['duration']);
- $duration = new Duration($d->d, $d->h, $d->i, $d->s);
- $alarm->setDuration($duration, intval($valarm['repeat']));
- }
- catch (Exception $e) {
- // ignore
- }
- }
-
- $valarms->push($alarm);
- }
- }
- // legacy support
- else if ($object['alarms']) {
- list($offset, $type) = explode(":", $object['alarms']);
-
- if ($type == 'EMAIL' && !empty($object['_owner'])) { // email alarms implicitly go to event owner
- $recipients = new vectorcontactref;
- $recipients->push(new ContactReference(ContactReference::EmailReference, $object['_owner']));
- $alarm = new Alarm($object['title'], strval($object['description']), $recipients);
- }
- else { // default: display alarm
- $alarm = new Alarm($object['title']);
- }
-
- if (preg_match('/^@(\d+)/', $offset, $d)) {
- $alarm->setStart(self::get_datetime($d[1], new DateTimeZone('UTC')));
- }
- else if (preg_match('/^([-+]?)P?T?(\d+)([SMHDW])/', $offset, $d)) {
- $days = $hours = $minutes = $seconds = 0;
- switch ($d[3]) {
- case 'W': $days = 7*intval($d[2]); break;
- case 'D': $days = intval($d[2]); break;
- case 'H': $hours = intval($d[2]); break;
- case 'M': $minutes = intval($d[2]); break;
- case 'S': $seconds = intval($d[2]); break;
- }
- $alarm->setRelativeStart(new Duration($days, $hours, $minutes, $seconds, $d[1] == '-'), $d[1] == '-' ? kolabformat::Start : kolabformat::End);
- }
-
- $valarms->push($alarm);
- }
- $this->obj->setAlarms($valarms);
-
- $this->set_attachments($object);
- }
-
- /**
- * Callback for kolab_storage_cache to get words to index for fulltext search
- *
- * @return array List of words to save in cache
- */
- public function get_words()
- {
- $data = '';
- foreach (self::$fulltext_cols as $colname) {
- list($col, $field) = explode(':', $colname);
-
- if ($field) {
- $a = array();
- foreach ((array)$this->data[$col] as $attr)
- $a[] = $attr[$field];
- $val = join(' ', $a);
- }
- else {
- $val = is_array($this->data[$col]) ? join(' ', $this->data[$col]) : $this->data[$col];
- }
-
- if (strlen($val))
- $data .= $val . ' ';
- }
-
- return array_unique(rcube_utils::normalize_string($data, true));
- }
-
- /**
- * Callback for kolab_storage_cache to get object specific tags to cache
- *
- * @return array List of tags to save in cache
- */
- public function get_tags()
- {
- $tags = array();
-
- if (!empty($this->data['valarms'])) {
- $tags[] = 'x-has-alarms';
- }
-
- // create tags reflecting participant status
- if (is_array($this->data['attendees'])) {
- foreach ($this->data['attendees'] as $attendee) {
- if (!empty($attendee['email']) && !empty($attendee['status']))
- $tags[] = 'x-partstat:' . $attendee['email'] . ':' . strtolower($attendee['status']);
- }
- }
-
- return $tags;
- }
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/lib/kolab_storage.php b/lib/plugins/libkolab/lib/kolab_storage.php
deleted file mode 100644
index 47c1e4b..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage.php
+++ /dev/null
@@ -1,1571 +0,0 @@
-<?php
-
-/**
- * Kolab storage class providing static methods to access groupware objects on a Kolab server.
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- * @author Aleksander Machniak <machniak@kolabsys.com>
- *
- * Copyright (C) 2012-2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage
-{
- const CTYPE_KEY = '/shared/vendor/kolab/folder-type';
- const CTYPE_KEY_PRIVATE = '/private/vendor/kolab/folder-type';
- const COLOR_KEY_SHARED = '/shared/vendor/kolab/color';
- const COLOR_KEY_PRIVATE = '/private/vendor/kolab/color';
- const NAME_KEY_SHARED = '/shared/vendor/kolab/displayname';
- const NAME_KEY_PRIVATE = '/private/vendor/kolab/displayname';
- const UID_KEY_SHARED = '/shared/vendor/kolab/uniqueid';
- const UID_KEY_PRIVATE = '/private/vendor/kolab/uniqueid';
- const UID_KEY_CYRUS = '/shared/vendor/cmu/cyrus-imapd/uniqueid';
-
- const ERROR_IMAP_CONN = 1;
- const ERROR_CACHE_DB = 2;
- const ERROR_NO_PERMISSION = 3;
- const ERROR_INVALID_FOLDER = 4;
-
- public static $version = '3.0';
- public static $last_error;
- public static $encode_ids = false;
-
- private static $ready = false;
- private static $with_tempsubs = true;
- private static $subscriptions;
- private static $typedata = array();
- private static $states;
- private static $config;
- private static $imap;
- private static $ldap;
-
- // Default folder names
- private static $default_folders = array(
- 'event' => 'Calendar',
- 'contact' => 'Contacts',
- 'task' => 'Tasks',
- 'note' => 'Notes',
- 'file' => 'Files',
- 'configuration' => 'Configuration',
- 'journal' => 'Journal',
- 'mail.inbox' => 'INBOX',
- 'mail.drafts' => 'Drafts',
- 'mail.sentitems' => 'Sent',
- 'mail.wastebasket' => 'Trash',
- 'mail.outbox' => 'Outbox',
- 'mail.junkemail' => 'Junk',
- );
-
-
- /**
- * Setup the environment needed by the libs
- */
- public static function setup()
- {
- if (self::$ready)
- return true;
-
- $rcmail = rcube::get_instance();
- self::$config = $rcmail->config;
- self::$version = strval($rcmail->config->get('kolab_format_version', self::$version));
- self::$imap = $rcmail->get_storage();
- self::$ready = class_exists('kolabformat') &&
- (self::$imap->get_capability('METADATA') || self::$imap->get_capability('ANNOTATEMORE') || self::$imap->get_capability('ANNOTATEMORE2'));
-
- if (self::$ready) {
- // set imap options
- self::$imap->set_options(array(
- 'skip_deleted' => true,
- 'threading' => false,
- ));
- }
- else if (!class_exists('kolabformat')) {
- rcube::raise_error(array(
- 'code' => 900, 'type' => 'php',
- 'message' => "required kolabformat module not found"
- ), true);
- }
- else {
- rcube::raise_error(array(
- 'code' => 900, 'type' => 'php',
- 'message' => "IMAP server doesn't support METADATA or ANNOTATEMORE"
- ), true);
- }
-
- return self::$ready;
- }
-
- /**
- * Initializes LDAP object to resolve Kolab users
- */
- public static function ldap()
- {
- if (self::$ldap) {
- return self::$ldap;
- }
-
- self::setup();
-
- $config = self::$config->get('kolab_users_directory', self::$config->get('kolab_auth_addressbook'));
-
- if (!is_array($config)) {
- $ldap_config = (array)self::$config->get('ldap_public');
- $config = $ldap_config[$config];
- }
-
- if (empty($config)) {
- return null;
- }
-
- // overwrite filter option
- if ($filter = self::$config->get('kolab_users_filter')) {
- self::$config->set('kolab_auth_filter', $filter);
- }
-
- // re-use the LDAP wrapper class from kolab_auth plugin
- require_once rtrim(RCUBE_PLUGINS_DIR, '/') . '/kolab_auth/kolab_auth_ldap.php';
-
- self::$ldap = new kolab_auth_ldap($config);
-
- return self::$ldap;
- }
-
- /**
- * Get a list of storage folders for the given data type
- *
- * @param string Data type to list folders for (contact,distribution-list,event,task,note)
- * @param boolean Enable to return subscribed folders only (null to use configured subscription mode)
- *
- * @return array List of Kolab_Folder objects (folder names in UTF7-IMAP)
- */
- public static function get_folders($type, $subscribed = null)
- {
- $folders = $folderdata = array();
-
- if (self::setup()) {
- foreach ((array)self::list_folders('', '*', $type, $subscribed, $folderdata) as $foldername) {
- $folders[$foldername] = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
- }
- }
-
- return $folders;
- }
-
- /**
- * Getter for the storage folder for the given type
- *
- * @param string Data type to list folders for (contact,distribution-list,event,task,note)
- * @return object kolab_storage_folder The folder object
- */
- public static function get_default_folder($type)
- {
- if (self::setup()) {
- foreach ((array)self::list_folders('', '*', $type . '.default', false, $folderdata) as $foldername) {
- return new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
- }
- }
-
- return null;
- }
-
- /**
- * Getter for a specific storage folder
- *
- * @param string IMAP folder to access (UTF7-IMAP)
- * @param string Expected folder type
- *
- * @return object kolab_storage_folder The folder object
- */
- public static function get_folder($folder, $type = null)
- {
- return self::setup() ? new kolab_storage_folder($folder, $type) : null;
- }
-
- /**
- * Getter for a single Kolab object, identified by its UID.
- * This will search all folders storing objects of the given type.
- *
- * @param string Object UID
- * @param string Object type (contact,event,task,journal,file,note,configuration)
- * @return array The Kolab object represented as hash array or false if not found
- */
- public static function get_object($uid, $type)
- {
- self::setup();
- $folder = null;
- foreach ((array)self::list_folders('', '*', $type, null, $folderdata) as $foldername) {
- if (!$folder)
- $folder = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
- else
- $folder->set_folder($foldername, $type, $folderdata[$foldername]);
-
- if ($object = $folder->get_object($uid, '*'))
- return $object;
- }
-
- return false;
- }
-
- /**
- * Execute cross-folder searches with the given query.
- *
- * @param array Pseudo-SQL query as list of filter parameter triplets
- * @param string Object type (contact,event,task,journal,file,note,configuration)
- * @return array List of Kolab data objects (each represented as hash array)
- * @see kolab_storage_format::select()
- */
- public static function select($query, $type)
- {
- self::setup();
- $folder = null;
- $result = array();
-
- foreach ((array)self::list_folders('', '*', $type, null, $folderdata) as $foldername) {
- if (!$folder)
- $folder = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
- else
- $folder->set_folder($foldername, $type, $folderdata[$foldername]);
-
- foreach ($folder->select($query, '*') as $object) {
- $result[] = $object;
- }
- }
-
- return $result;
- }
-
- /**
- * Returns Free-busy server URL
- */
- public static function get_freebusy_server()
- {
- $url = 'https://' . $_SESSION['imap_host'] . '/freebusy';
- $url = self::$config->get('kolab_freebusy_server', $url);
- $url = rcube_utils::resolve_url($url);
-
- return unslashify($url);
- }
-
- /**
- * Compose an URL to query the free/busy status for the given user
- */
- public static function get_freebusy_url($email)
- {
- return self::get_freebusy_server() . '/' . $email . '.ifb';
- }
-
- /**
- * Creates folder ID from folder name
- *
- * @param string $folder Folder name (UTF7-IMAP)
- * @param boolean $enc Use lossless encoding
- * @return string Folder ID string
- */
- public static function folder_id($folder, $enc = null)
- {
- return $enc == true || ($enc === null && self::$encode_ids) ?
- self::id_encode($folder) :
- asciiwords(strtr($folder, '/.-', '___'));
- }
-
- /**
- * Encode the given ID to a safe ascii representation
- *
- * @param string $id Arbitrary identifier string
- *
- * @return string Ascii representation
- */
- public static function id_encode($id)
- {
- return rtrim(strtr(base64_encode($id), '+/', '-_'), '=');
- }
-
- /**
- * Convert the given identifier back to it's raw value
- *
- * @param string $id Ascii identifier
- * @return string Raw identifier string
- */
- public static function id_decode($id)
- {
- return base64_decode(str_pad(strtr($id, '-_', '+/'), strlen($id) % 4, '=', STR_PAD_RIGHT));
- }
-
- /**
- * Return the (first) path of the requested IMAP namespace
- *
- * @param string Namespace name (personal, shared, other)
- * @return string IMAP root path for that namespace
- */
- public static function namespace_root($name)
- {
- foreach ((array)self::$imap->get_namespace($name) as $paths) {
- if (strlen($paths[0]) > 1) {
- return $paths[0];
- }
- }
-
- return '';
- }
-
-
- /**
- * Deletes IMAP folder
- *
- * @param string $name Folder name (UTF7-IMAP)
- *
- * @return bool True on success, false on failure
- */
- public static function folder_delete($name)
- {
- // clear cached entries first
- if ($folder = self::get_folder($name))
- $folder->cache->purge();
-
- $rcmail = rcube::get_instance();
- $plugin = $rcmail->plugins->exec_hook('folder_delete', array('name' => $name));
-
- $success = self::$imap->delete_folder($name);
- self::$last_error = self::$imap->get_error_str();
-
- return $success;
- }
-
- /**
- * Creates IMAP folder
- *
- * @param string $name Folder name (UTF7-IMAP)
- * @param string $type Folder type
- * @param bool $subscribed Sets folder subscription
- * @param bool $active Sets folder state (client-side subscription)
- *
- * @return bool True on success, false on failure
- */
- public static function folder_create($name, $type = null, $subscribed = false, $active = false)
- {
- self::setup();
-
- $rcmail = rcube::get_instance();
- $plugin = $rcmail->plugins->exec_hook('folder_create', array('record' => array(
- 'name' => $name,
- 'subscribe' => $subscribed,
- )));
-
- if ($saved = self::$imap->create_folder($name, $subscribed)) {
- // set metadata for folder type
- if ($type) {
- $saved = self::set_folder_type($name, $type);
-
- // revert if metadata could not be set
- if (!$saved) {
- self::$imap->delete_folder($name);
- }
- // activate folder
- else if ($active) {
- self::set_state($name, true);
- }
- }
- }
-
- if ($saved) {
- return true;
- }
-
- self::$last_error = self::$imap->get_error_str();
- return false;
- }
-
-
- /**
- * Renames IMAP folder
- *
- * @param string $oldname Old folder name (UTF7-IMAP)
- * @param string $newname New folder name (UTF7-IMAP)
- *
- * @return bool True on success, false on failure
- */
- public static function folder_rename($oldname, $newname)
- {
- self::setup();
-
- $rcmail = rcube::get_instance();
- $plugin = $rcmail->plugins->exec_hook('folder_rename', array(
- 'oldname' => $oldname, 'newname' => $newname));
-
- $oldfolder = self::get_folder($oldname);
- $active = self::folder_is_active($oldname);
- $success = self::$imap->rename_folder($oldname, $newname);
- self::$last_error = self::$imap->get_error_str();
-
- // pass active state to new folder name
- if ($success && $active) {
- self::set_state($oldname, false);
- self::set_state($newname, true);
- }
-
- // assign existing cache entries to new resource uri
- if ($success && $oldfolder) {
- $oldfolder->cache->rename($newname);
- }
-
- return $success;
- }
-
-
- /**
- * Rename or Create a new IMAP folder.
- *
- * Does additional checks for permissions and folder name restrictions
- *
- * @param array Hash array with folder properties and metadata
- * - name: Folder name
- * - oldname: Old folder name when changed
- * - parent: Parent folder to create the new one in
- * - type: Folder type to create
- * - subscribed: Subscribed flag (IMAP subscription)
- * - active: Activation flag (client-side subscription)
- * @return mixed New folder name or False on failure
- */
- public static function folder_update(&$prop)
- {
- self::setup();
-
- $folder = rcube_charset::convert($prop['name'], RCUBE_CHARSET, 'UTF7-IMAP');
- $oldfolder = $prop['oldname']; // UTF7
- $parent = $prop['parent']; // UTF7
- $delimiter = self::$imap->get_hierarchy_delimiter();
-
- if (strlen($oldfolder)) {
- $options = self::$imap->folder_info($oldfolder);
- }
-
- if (!empty($options) && ($options['norename'] || $options['protected'])) {
- }
- // sanity checks (from steps/settings/save_folder.inc)
- else if (!strlen($folder)) {
- self::$last_error = 'cannotbeempty';
- return false;
- }
- else if (strlen($folder) > 128) {
- self::$last_error = 'nametoolong';
- return false;
- }
- else {
- // these characters are problematic e.g. when used in LIST/LSUB
- foreach (array($delimiter, '%', '*') as $char) {
- if (strpos($folder, $char) !== false) {
- self::$last_error = 'forbiddencharacter';
- return false;
- }
- }
- }
-
- if (!empty($options) && ($options['protected'] || $options['norename'])) {
- $folder = $oldfolder;
- }
- else if (strlen($parent)) {
- $folder = $parent . $delimiter . $folder;
- }
- else {
- // add namespace prefix (when needed)
- $folder = self::$imap->mod_folder($folder, 'in');
- }
-
- // Check access rights to the parent folder
- if (strlen($parent) && (!strlen($oldfolder) || $oldfolder != $folder)) {
- $parent_opts = self::$imap->folder_info($parent);
- if ($parent_opts['namespace'] != 'personal'
- && (empty($parent_opts['rights']) || !preg_match('/[ck]/', implode($parent_opts['rights'])))
- ) {
- self::$last_error = 'No permission to create folder';
- return false;
- }
- }
-
- // update the folder name
- if (strlen($oldfolder)) {
- if ($oldfolder != $folder) {
- $result = self::folder_rename($oldfolder, $folder);
- }
- else
- $result = true;
- }
- // create new folder
- else {
- $result = self::folder_create($folder, $prop['type'], $prop['subscribed'], $prop['active']);
- }
-
- if ($result) {
- self::set_folder_props($folder, $prop);
- }
-
- return $result ? $folder : false;
- }
-
-
- /**
- * Getter for human-readable name of Kolab object (folder)
- * See http://wiki.kolab.org/UI-Concepts/Folder-Listing for reference
- *
- * @param string $folder IMAP folder name (UTF7-IMAP)
- * @param string $folder_ns Will be set to namespace name of the folder
- *
- * @return string Name of the folder-object
- */
- public static function object_name($folder, &$folder_ns=null)
- {
- self::setup();
-
- // find custom display name in folder METADATA
- if ($name = self::custom_displayname($folder)) {
- return $name;
- }
-
- $found = false;
- $namespace = self::$imap->get_namespace();
-
- if (!empty($namespace['shared'])) {
- foreach ($namespace['shared'] as $ns) {
- if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
- $prefix = '';
- $folder = substr($folder, strlen($ns[0]));
- $delim = $ns[1];
- $found = true;
- $folder_ns = 'shared';
- break;
- }
- }
- }
- if (!$found && !empty($namespace['other'])) {
- foreach ($namespace['other'] as $ns) {
- if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
- // remove namespace prefix
- $folder = substr($folder, strlen($ns[0]));
- $delim = $ns[1];
- // get username
- $pos = strpos($folder, $delim);
- if ($pos) {
- $prefix = '('.substr($folder, 0, $pos).')';
- $folder = substr($folder, $pos+1);
- }
- else {
- $prefix = '('.$folder.')';
- $folder = '';
- }
-
- $found = true;
- $folder_ns = 'other';
- break;
- }
- }
- }
- if (!$found && !empty($namespace['personal'])) {
- foreach ($namespace['personal'] as $ns) {
- if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
- // remove namespace prefix
- $folder = substr($folder, strlen($ns[0]));
- $prefix = '';
- $delim = $ns[1];
- $found = true;
- break;
- }
- }
- }
-
- if (empty($delim))
- $delim = self::$imap->get_hierarchy_delimiter();
-
- $folder = rcube_charset::convert($folder, 'UTF7-IMAP');
- $folder = html::quote($folder);
- $folder = str_replace(html::quote($delim), ' &raquo; ', $folder);
-
- if ($prefix)
- $folder = html::quote($prefix) . ($folder !== '' ? ' ' . $folder : '');
-
- if (!$folder_ns)
- $folder_ns = 'personal';
-
- return $folder;
- }
-
- /**
- * Get custom display name (saved in metadata) for the given folder
- */
- public static function custom_displayname($folder)
- {
- // find custom display name in folder METADATA
- if (self::$config->get('kolab_custom_display_names', true)) {
- $metadata = self::$imap->get_metadata($folder, array(self::NAME_KEY_PRIVATE, self::NAME_KEY_SHARED));
- if (($name = $metadata[$folder][self::NAME_KEY_PRIVATE]) || ($name = $metadata[$folder][self::NAME_KEY_SHARED])) {
- return $name;
- }
- }
-
- return false;
- }
-
- /**
- * Helper method to generate a truncated folder name to display.
- * Note: $origname is a string returned by self::object_name()
- */
- public static function folder_displayname($origname, &$names)
- {
- $name = $origname;
-
- // find folder prefix to truncate
- for ($i = count($names)-1; $i >= 0; $i--) {
- if (strpos($name, $names[$i] . ' &raquo; ') === 0) {
- $length = strlen($names[$i] . ' &raquo; ');
- $prefix = substr($name, 0, $length);
- $count = count(explode(' &raquo; ', $prefix));
- $diff = 1;
-
- // check if prefix folder is in other users namespace
- for ($n = count($names)-1; $n >= 0; $n--) {
- if (strpos($prefix, '(' . $names[$n] . ') ') === 0) {
- $diff = 0;
- break;
- }
- }
-
- $name = str_repeat('&nbsp;&nbsp;&nbsp;', $count - $diff) . '&raquo; ' . substr($name, $length);
- break;
- }
- // other users namespace and parent folder exists
- else if (strpos($name, '(' . $names[$i] . ') ') === 0) {
- $length = strlen('(' . $names[$i] . ') ');
- $prefix = substr($name, 0, $length);
- $count = count(explode(' &raquo; ', $prefix));
- $name = str_repeat('&nbsp;&nbsp;&nbsp;', $count) . '&raquo; ' . substr($name, $length);
- break;
- }
- }
-
- $names[] = $origname;
-
- return $name;
- }
-
-
- /**
- * Creates a SELECT field with folders list
- *
- * @param string $type Folder type
- * @param array $attrs SELECT field attributes (e.g. name)
- * @param string $current The name of current folder (to skip it)
- *
- * @return html_select SELECT object
- */
- public static function folder_selector($type, $attrs, $current = '')
- {
- // get all folders of specified type (sorted)
- $folders = self::get_folders($type, true);
-
- $delim = self::$imap->get_hierarchy_delimiter();
- $names = array();
- $len = strlen($current);
-
- if ($len && ($rpos = strrpos($current, $delim))) {
- $parent = substr($current, 0, $rpos);
- $p_len = strlen($parent);
- }
-
- // Filter folders list
- foreach ($folders as $c_folder) {
- $name = $c_folder->name;
-
- // skip current folder and it's subfolders
- if ($len) {
- if ($name == $current) {
- // Make sure parent folder is listed (might be skipped e.g. if it's namespace root)
- if ($p_len && !isset($names[$parent])) {
- $names[$parent] = self::object_name($parent);
- }
- continue;
- }
- if (strpos($name, $current.$delim) === 0) {
- continue;
- }
- }
-
- // always show the parent of current folder
- if ($p_len && $name == $parent) {
- }
- // skip folders where user have no rights to create subfolders
- else if ($c_folder->get_owner() != $_SESSION['username']) {
- $rights = $c_folder->get_myrights();
- if (!preg_match('/[ck]/', $rights)) {
- continue;
- }
- }
-
- $names[$name] = self::object_name($name);
- }
-
- // Build SELECT field of parent folder
- $attrs['is_escaped'] = true;
- $select = new html_select($attrs);
- $select->add('---', '');
-
- $listnames = array();
- foreach (array_keys($names) as $imap_name) {
- $name = $origname = $names[$imap_name];
-
- // find folder prefix to truncate
- for ($i = count($listnames)-1; $i >= 0; $i--) {
- if (strpos($name, $listnames[$i].' &raquo; ') === 0) {
- $length = strlen($listnames[$i].' &raquo; ');
- $prefix = substr($name, 0, $length);
- $count = count(explode(' &raquo; ', $prefix));
- $name = str_repeat('&nbsp;&nbsp;', $count-1) . '&raquo; ' . substr($name, $length);
- break;
- }
- }
-
- $listnames[] = $origname;
- $select->add($name, $imap_name);
- }
-
- return $select;
- }
-
-
- /**
- * Returns a list of folder names
- *
- * @param string Optional root folder
- * @param string Optional name pattern
- * @param string Data type to list folders for (contact,event,task,journal,file,note,mail,configuration)
- * @param boolean Enable to return subscribed folders only (null to use configured subscription mode)
- * @param array Will be filled with folder-types data
- *
- * @return array List of folders
- */
- public static function list_folders($root = '', $mbox = '*', $filter = null, $subscribed = null, &$folderdata = array())
- {
- if (!self::setup()) {
- return null;
- }
-
- // use IMAP subscriptions
- if ($subscribed === null && self::$config->get('kolab_use_subscriptions')) {
- $subscribed = true;
- }
-
- if (!$filter) {
- // Get ALL folders list, standard way
- if ($subscribed) {
- $folders = self::$imap->list_folders_subscribed($root, $mbox);
- // add temporarily subscribed folders
- if (self::$with_tempsubs && is_array($_SESSION['kolab_subscribed_folders'])) {
- $folders = array_unique(array_merge($folders, $_SESSION['kolab_subscribed_folders']));
- }
- }
- else {
- $folders = self::_imap_list_folders($root, $mbox);
- }
-
- return $folders;
- }
- $prefix = $root . $mbox;
- $regexp = '/^' . preg_quote($filter, '/') . '(\..+)?$/';
-
- // get folders types for all folders
- if (!$subscribed || $prefix == '*' || !self::$config->get('kolab_skip_namespace')) {
- $folderdata = self::folders_typedata($prefix);
- }
- else {
- // fetch folder types for the effective list of (subscribed) folders when post-filtering
- $folderdata = array();
- }
-
- if (!is_array($folderdata)) {
- return array();
- }
-
- // In some conditions we can skip LIST command (?)
- if (!$subscribed && $filter != 'mail' && $prefix == '*') {
- foreach ($folderdata as $folder => $type) {
- if (!preg_match($regexp, $type)) {
- unset($folderdata[$folder]);
- }
- }
-
- return self::$imap->sort_folder_list(array_keys($folderdata), true);
- }
-
- // Get folders list
- if ($subscribed) {
- $folders = self::$imap->list_folders_subscribed($root, $mbox);
-
- // add temporarily subscribed folders
- if (self::$with_tempsubs && is_array($_SESSION['kolab_subscribed_folders'])) {
- $folders = array_unique(array_merge($folders, $_SESSION['kolab_subscribed_folders']));
- }
- }
- else {
- $folders = self::_imap_list_folders($root, $mbox);
- }
-
- // In case of an error, return empty list (?)
- if (!is_array($folders)) {
- return array();
- }
-
- // Filter folders list
- foreach ($folders as $idx => $folder) {
- // lookup folder type
- if (!array_key_exists($folder, $folderdata)) {
- $folderdata[$folder] = self::folder_type($folder);
- }
-
- $type = $folderdata[$folder];
-
- if ($filter == 'mail' && empty($type)) {
- continue;
- }
- if (empty($type) || !preg_match($regexp, $type)) {
- unset($folders[$idx]);
- }
- }
-
- return $folders;
- }
-
- /**
- * Wrapper for rcube_imap::list_folders() with optional post-filtering
- */
- protected static function _imap_list_folders($root, $mbox)
- {
- $postfilter = null;
-
- // compose a post-filter expression for the excluded namespaces
- if ($root . $mbox == '*' && ($skip_ns = self::$config->get('kolab_skip_namespace'))) {
- $excludes = array();
- foreach ((array)$skip_ns as $ns) {
- if ($ns_root = self::namespace_root($ns)) {
- $excludes[] = $ns_root;
- }
- }
-
- if (count($excludes)) {
- $postfilter = '!^(' . join(')|(', array_map('preg_quote', $excludes)) . ')!';
- }
- }
-
- // use normal LIST command to return all folders, it's fast enough
- $folders = self::$imap->list_folders($root, $mbox, null, null, !empty($postfilter));
-
- if (!empty($postfilter)) {
- $folders = array_filter($folders, function($folder) use ($postfilter) { return !preg_match($postfilter, $folder); });
- $folders = self::$imap->sort_folder_list($folders);
- }
-
- return $folders;
- }
-
-
- /**
- * Search for shared or otherwise not listed groupware folders the user has access
- *
- * @param string Folder type of folders to search for
- * @param string Search string
- * @param array Namespace(s) to exclude results from
- *
- * @return array List of matching kolab_storage_folder objects
- */
- public static function search_folders($type, $query, $exclude_ns = array())
- {
- if (!self::setup()) {
- return array();
- }
-
- $folders = array();
- $query = str_replace('*', '', $query);
-
- // find unsubscribed IMAP folders of the given type
- foreach ((array)self::list_folders('', '*', $type, false, $folderdata) as $foldername) {
- // FIXME: only consider the last part of the folder path for searching?
- $realname = strtolower(rcube_charset::convert($foldername, 'UTF7-IMAP'));
- if (($query == '' || strpos($realname, $query) !== false) &&
- !self::folder_is_subscribed($foldername, true) &&
- !in_array(self::$imap->folder_namespace($foldername), (array)$exclude_ns)
- ) {
- $folders[] = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
- }
- }
-
- return $folders;
- }
-
-
- /**
- * Sort the given list of kolab folders by namespace/name
- *
- * @param array List of kolab_storage_folder objects
- * @return array Sorted list of folders
- */
- public static function sort_folders($folders)
- {
- $pad = ' ';
- $out = array();
- $nsnames = array('personal' => array(), 'shared' => array(), 'other' => array());
-
- foreach ($folders as $folder) {
- $folders[$folder->name] = $folder;
- $ns = $folder->get_namespace();
- $nsnames[$ns][$folder->name] = strtolower(html_entity_decode(self::object_name($folder->name, $ns), ENT_COMPAT, RCUBE_CHARSET)) . $pad; // decode &raquo;
- }
-
- // $folders is a result of get_folders() we can assume folders were already sorted
- foreach (array_keys($nsnames) as $ns) {
- asort($nsnames[$ns], SORT_LOCALE_STRING);
- foreach (array_keys($nsnames[$ns]) as $utf7name) {
- $out[] = $folders[$utf7name];
- }
- }
-
- return $out;
- }
-
-
- /**
- * Check the folder tree and add the missing parents as virtual folders
- *
- * @param array $folders Folders list
- * @param object $tree Reference to the root node of the folder tree
- *
- * @return array Flat folders list
- */
- public static function folder_hierarchy($folders, &$tree = null)
- {
- $_folders = array();
- $delim = self::$imap->get_hierarchy_delimiter();
- $other_ns = rtrim(self::namespace_root('other'), $delim);
- $tree = new kolab_storage_folder_virtual('', '<root>', ''); // create tree root
- $refs = array('' => $tree);
-
- foreach ($folders as $idx => $folder) {
- $path = explode($delim, $folder->name);
- array_pop($path);
- $folder->parent = join($delim, $path);
- $folder->children = array(); // reset list
-
- // skip top folders or ones with a custom displayname
- if (count($path) < 1 || kolab_storage::custom_displayname($folder->name)) {
- $tree->children[] = $folder;
- }
- else {
- $parents = array();
- $depth = $folder->get_namespace() == 'personal' ? 1 : 2;
-
- while (count($path) >= $depth && ($parent = join($delim, $path))) {
- array_pop($path);
- $parent_parent = join($delim, $path);
- if (!$refs[$parent]) {
- if ($folder->type && self::folder_type($parent) == $folder->type) {
- $refs[$parent] = new kolab_storage_folder($parent, $folder->type, $folder->type);
- $refs[$parent]->parent = $parent_parent;
- }
- else if ($parent_parent == $other_ns) {
- $refs[$parent] = new kolab_storage_folder_user($parent, $parent_parent);
- }
- else {
- $name = kolab_storage::object_name($parent, $folder->get_namespace());
- $refs[$parent] = new kolab_storage_folder_virtual($parent, $name, $folder->get_namespace(), $parent_parent);
- }
- $parents[] = $refs[$parent];
- }
- }
-
- if (!empty($parents)) {
- $parents = array_reverse($parents);
- foreach ($parents as $parent) {
- $parent_node = $refs[$parent->parent] ?: $tree;
- $parent_node->children[] = $parent;
- $_folders[] = $parent;
- }
- }
-
- $parent_node = $refs[$folder->parent] ?: $tree;
- $parent_node->children[] = $folder;
- }
-
- $refs[$folder->name] = $folder;
- $_folders[] = $folder;
- unset($folders[$idx]);
- }
-
- return $_folders;
- }
-
-
- /**
- * Returns folder types indexed by folder name
- *
- * @param string $prefix Folder prefix (Default '*' for all folders)
- *
- * @return array|bool List of folders, False on failure
- */
- public static function folders_typedata($prefix = '*')
- {
- if (!self::setup()) {
- return false;
- }
-
- // return cached result
- if (is_array(self::$typedata[$prefix])) {
- return self::$typedata[$prefix];
- }
-
- $type_keys = array(self::CTYPE_KEY, self::CTYPE_KEY_PRIVATE);
-
- // fetch metadata from *some* folders only
- if (($prefix == '*' || $prefix == '') && ($skip_ns = self::$config->get('kolab_skip_namespace'))) {
- $delimiter = self::$imap->get_hierarchy_delimiter();
- $folderdata = $blacklist = array();
- foreach ((array)$skip_ns as $ns) {
- if ($ns_root = rtrim(self::namespace_root($ns), $delimiter)) {
- $blacklist[] = $ns_root;
- }
- }
- foreach (array('personal','other','shared') as $ns) {
- if (!in_array($ns, (array)$skip_ns)) {
- $ns_root = rtrim(self::namespace_root($ns), $delimiter);
-
- // list top-level folders and their childs one by one
- // GETMETADATA "%" doesn't list shared or other namespace folders but "*" would
- if ($ns_root == '') {
- foreach ((array)self::$imap->get_metadata('%', $type_keys) as $folder => $metadata) {
- if (!in_array($folder, $blacklist)) {
- $folderdata[$folder] = $metadata;
- $opts = self::$imap->folder_attributes($folder);
- if (!in_array('\\HasNoChildren', $opts) && ($data = self::$imap->get_metadata($folder.$delimiter.'*', $type_keys))) {
- $folderdata += $data;
- }
- }
- }
- }
- else if ($data = self::$imap->get_metadata($ns_root.$delimiter.'*', $type_keys)) {
- $folderdata += $data;
- }
- }
- }
- }
- else {
- $folderdata = self::$imap->get_metadata($prefix, $type_keys);
- }
-
- if (!is_array($folderdata)) {
- return false;
- }
-
- // keep list in memory
- self::$typedata[$prefix] = array_map(array('kolab_storage', 'folder_select_metadata'), $folderdata);
-
- return self::$typedata[$prefix];
- }
-
-
- /**
- * Callback for array_map to select the correct annotation value
- */
- public static function folder_select_metadata($types)
- {
- if (!empty($types[self::CTYPE_KEY_PRIVATE])) {
- return $types[self::CTYPE_KEY_PRIVATE];
- }
- else if (!empty($types[self::CTYPE_KEY])) {
- list($ctype, ) = explode('.', $types[self::CTYPE_KEY]);
- return $ctype;
- }
- return null;
- }
-
-
- /**
- * Returns type of IMAP folder
- *
- * @param string $folder Folder name (UTF7-IMAP)
- *
- * @return string Folder type
- */
- public static function folder_type($folder)
- {
- self::setup();
-
- // return in-memory cached result
- foreach (self::$typedata as $typedata) {
- if (array_key_exists($folder, $typedata)) {
- return $typedata[$folder];
- }
- }
-
- $metadata = self::$imap->get_metadata($folder, array(self::CTYPE_KEY, self::CTYPE_KEY_PRIVATE));
-
- if (!is_array($metadata)) {
- return null;
- }
-
- if (!empty($metadata[$folder])) {
- return self::folder_select_metadata($metadata[$folder]);
- }
-
- return 'mail';
- }
-
-
- /**
- * Sets folder content-type.
- *
- * @param string $folder Folder name
- * @param string $type Content type
- *
- * @return boolean True on success
- */
- public static function set_folder_type($folder, $type='mail')
- {
- self::setup();
-
- list($ctype, $subtype) = explode('.', $type);
-
- $success = self::$imap->set_metadata($folder, array(self::CTYPE_KEY => $ctype, self::CTYPE_KEY_PRIVATE => $subtype ? $type : null));
-
- if (!$success) // fallback: only set private annotation
- $success |= self::$imap->set_metadata($folder, array(self::CTYPE_KEY_PRIVATE => $type));
-
- return $success;
- }
-
-
- /**
- * Check subscription status of this folder
- *
- * @param string $folder Folder name
- * @param boolean $temp Include temporary/session subscriptions
- *
- * @return boolean True if subscribed, false if not
- */
- public static function folder_is_subscribed($folder, $temp = false)
- {
- if (self::$subscriptions === null) {
- self::setup();
- self::$with_tempsubs = false;
- self::$subscriptions = self::$imap->list_folders_subscribed();
- self::$with_tempsubs = true;
- }
-
- return in_array($folder, self::$subscriptions) ||
- ($temp && in_array($folder, (array)$_SESSION['kolab_subscribed_folders']));
- }
-
-
- /**
- * Change subscription status of this folder
- *
- * @param string $folder Folder name
- * @param boolean $temp Only subscribe temporarily for the current session
- *
- * @return True on success, false on error
- */
- public static function folder_subscribe($folder, $temp = false)
- {
- self::setup();
-
- // temporary/session subscription
- if ($temp) {
- if (self::folder_is_subscribed($folder)) {
- return true;
- }
- else if (!is_array($_SESSION['kolab_subscribed_folders']) || !in_array($folder, $_SESSION['kolab_subscribed_folders'])) {
- $_SESSION['kolab_subscribed_folders'][] = $folder;
- return true;
- }
- }
- else if (self::$imap->subscribe($folder)) {
- self::$subscriptions = null;
- return true;
- }
-
- return false;
- }
-
-
- /**
- * Change subscription status of this folder
- *
- * @param string $folder Folder name
- * @param boolean $temp Only remove temporary subscription
- *
- * @return True on success, false on error
- */
- public static function folder_unsubscribe($folder, $temp = false)
- {
- self::setup();
-
- // temporary/session subscription
- if ($temp) {
- if (is_array($_SESSION['kolab_subscribed_folders']) && ($i = array_search($folder, $_SESSION['kolab_subscribed_folders'])) !== false) {
- unset($_SESSION['kolab_subscribed_folders'][$i]);
- }
- return true;
- }
- else if (self::$imap->unsubscribe($folder)) {
- self::$subscriptions = null;
- return true;
- }
-
- return false;
- }
-
-
- /**
- * Check activation status of this folder
- *
- * @param string $folder Folder name
- *
- * @return boolean True if active, false if not
- */
- public static function folder_is_active($folder)
- {
- $active_folders = self::get_states();
-
- return in_array($folder, $active_folders);
- }
-
-
- /**
- * Change activation status of this folder
- *
- * @param string $folder Folder name
- *
- * @return True on success, false on error
- */
- public static function folder_activate($folder)
- {
- // activation implies temporary subscription
- self::folder_subscribe($folder, true);
- return self::set_state($folder, true);
- }
-
-
- /**
- * Change activation status of this folder
- *
- * @param string $folder Folder name
- *
- * @return True on success, false on error
- */
- public static function folder_deactivate($folder)
- {
- // remove from temp subscriptions, really?
- self::folder_unsubscribe($folder, true);
-
- return self::set_state($folder, false);
- }
-
-
- /**
- * Return list of active folders
- */
- private static function get_states()
- {
- if (self::$states !== null) {
- return self::$states;
- }
-
- $rcube = rcube::get_instance();
- $folders = $rcube->config->get('kolab_active_folders');
-
- if ($folders !== null) {
- self::$states = !empty($folders) ? explode('**', $folders) : array();
- }
- // for backward-compatibility copy server-side subscriptions to activation states
- else {
- self::setup();
- if (self::$subscriptions === null) {
- self::$with_tempsubs = false;
- self::$subscriptions = self::$imap->list_folders_subscribed();
- self::$with_tempsubs = true;
- }
- self::$states = self::$subscriptions;
- $folders = implode(self::$states, '**');
- $rcube->user->save_prefs(array('kolab_active_folders' => $folders));
- }
-
- return self::$states;
- }
-
-
- /**
- * Update list of active folders
- */
- private static function set_state($folder, $state)
- {
- self::get_states();
-
- // update in-memory list
- $idx = array_search($folder, self::$states);
- if ($state && $idx === false) {
- self::$states[] = $folder;
- }
- else if (!$state && $idx !== false) {
- unset(self::$states[$idx]);
- }
-
- // update user preferences
- $folders = implode(self::$states, '**');
- $rcube = rcube::get_instance();
- return $rcube->user->save_prefs(array('kolab_active_folders' => $folders));
- }
-
- /**
- * Creates default folder of specified type
- * To be run when none of subscribed folders (of specified type) is found
- *
- * @param string $type Folder type
- * @param string $props Folder properties (color, etc)
- *
- * @return string Folder name
- */
- public static function create_default_folder($type, $props = array())
- {
- if (!self::setup()) {
- return;
- }
-
- $folders = self::$imap->get_metadata('*', array(kolab_storage::CTYPE_KEY_PRIVATE));
-
- // from kolab_folders config
- $folder_type = strpos($type, '.') ? str_replace('.', '_', $type) : $type . '_default';
- $default_name = self::$config->get('kolab_folders_' . $folder_type);
- $folder_type = str_replace('_', '.', $folder_type);
-
- // check if we have any folder in personal namespace
- // folder(s) may exist but not subscribed
- foreach ((array)$folders as $f => $data) {
- if (strpos($data[self::CTYPE_KEY_PRIVATE], $type) === 0) {
- $folder = $f;
- break;
- }
- }
-
- if (!$folder) {
- if (!$default_name) {
- $default_name = self::$default_folders[$type];
- }
-
- if (!$default_name) {
- return;
- }
-
- $folder = rcube_charset::convert($default_name, RCUBE_CHARSET, 'UTF7-IMAP');
- $prefix = self::$imap->get_namespace('prefix');
-
- // add personal namespace prefix if needed
- if ($prefix && strpos($folder, $prefix) !== 0 && $folder != 'INBOX') {
- $folder = $prefix . $folder;
- }
-
- if (!self::$imap->folder_exists($folder)) {
- if (!self::$imap->create_folder($folder)) {
- return;
- }
- }
-
- self::set_folder_type($folder, $folder_type);
- }
-
- self::folder_subscribe($folder);
-
- if ($props['active']) {
- self::set_state($folder, true);
- }
-
- if (!empty($props)) {
- self::set_folder_props($folder, $props);
- }
-
- return $folder;
- }
-
- /**
- * Sets folder metadata properties
- *
- * @param string $folder Folder name
- * @param array $prop Folder properties
- */
- public static function set_folder_props($folder, &$prop)
- {
- if (!self::setup()) {
- return;
- }
-
- // TODO: also save 'showalarams' and other properties here
- $ns = self::$imap->folder_namespace($folder);
- $supported = array(
- 'color' => array(self::COLOR_KEY_SHARED, self::COLOR_KEY_PRIVATE),
- 'displayname' => array(self::NAME_KEY_SHARED, self::NAME_KEY_PRIVATE),
- );
-
- foreach ($supported as $key => $metakeys) {
- if (array_key_exists($key, $prop)) {
- $meta_saved = false;
- if ($ns == 'personal') // save in shared namespace for personal folders
- $meta_saved = self::$imap->set_metadata($folder, array($metakeys[0] => $prop[$key]));
- if (!$meta_saved) // try in private namespace
- $meta_saved = self::$imap->set_metadata($folder, array($metakeys[1] => $prop[$key]));
- if ($meta_saved)
- unset($prop[$key]); // unsetting will prevent fallback to local user prefs
- }
- }
- }
-
-
- /**
- *
- * @param mixed $query Search value (or array of field => value pairs)
- * @param int $mode Matching mode: 0 - partial (*abc*), 1 - strict (=), 2 - prefix (abc*)
- * @param array $required List of fields that shall ot be empty
- * @param int $limit Maximum number of records
- * @param int $count Returns the number of records found
- *
- * @return array List or false on error
- */
- public static function search_users($query, $mode = 1, $required = array(), $limit = 0, &$count = 0)
- {
- $query = str_replace('*', '', $query);
-
- // requires a working LDAP setup
- if (!self::ldap() || strlen($query) == 0) {
- return array();
- }
-
- // search users using the configured attributes
- $results = self::$ldap->dosearch(self::$config->get('kolab_users_search_attrib', array('cn','mail','alias')), $query, $mode, $required, $limit, $count);
-
- // exclude myself
- if ($_SESSION['kolab_dn']) {
- unset($results[$_SESSION['kolab_dn']]);
- }
-
- // resolve to IMAP folder name
- $root = self::namespace_root('other');
- $user_attrib = self::$config->get('kolab_users_id_attrib', self::$config->get('kolab_auth_login', 'mail'));
-
- array_walk($results, function(&$user, $dn) use ($root, $user_attrib) {
- list($localpart, ) = explode('@', $user[$user_attrib]);
- $user['kolabtargetfolder'] = $root . $localpart;
- });
-
- return $results;
- }
-
-
- /**
- * Returns a list of IMAP folders shared by the given user
- *
- * @param array User entry from LDAP
- * @param string Data type to list folders for (contact,event,task,journal,file,note,mail,configuration)
- * @param boolean Return subscribed folders only (null to use configured subscription mode)
- * @param array Will be filled with folder-types data
- *
- * @return array List of folders
- */
- public static function list_user_folders($user, $type, $subscribed = null, &$folderdata = array())
- {
- self::setup();
-
- $folders = array();
-
- // use localpart of user attribute as root for folder listing
- $user_attrib = self::$config->get('kolab_users_id_attrib', self::$config->get('kolab_auth_login', 'mail'));
- if (!empty($user[$user_attrib])) {
- list($mbox) = explode('@', $user[$user_attrib]);
-
- $delimiter = self::$imap->get_hierarchy_delimiter();
- $other_ns = self::namespace_root('other');
- $folders = self::list_folders($other_ns . $mbox . $delimiter, '*', $type, $subscribed, $folderdata);
- }
-
- return $folders;
- }
-
-
- /**
- * Get a list of (virtual) top-level folders from the other users namespace
- *
- * @param string Data type to list folders for (contact,event,task,journal,file,note,mail,configuration)
- * @param boolean Enable to return subscribed folders only (null to use configured subscription mode)
- *
- * @return array List of kolab_storage_folder_user objects
- */
- public static function get_user_folders($type, $subscribed)
- {
- $folders = $folderdata = array();
-
- if (self::setup()) {
- $delimiter = self::$imap->get_hierarchy_delimiter();
- $other_ns = rtrim(self::namespace_root('other'), $delimiter);
- $path_len = count(explode($delimiter, $other_ns));
-
- foreach ((array)self::list_folders($other_ns . $delimiter, '*', '', $subscribed) as $foldername) {
- if ($foldername == 'INBOX') // skip INBOX which is added by default
- continue;
-
- $path = explode($delimiter, $foldername);
-
- // compare folder type if a subfolder is listed
- if ($type && count($path) > $path_len + 1 && $type != self::folder_type($foldername)) {
- continue;
- }
-
- // truncate folder path to top-level folders of the 'other' namespace
- $foldername = join($delimiter, array_slice($path, 0, $path_len + 1));
-
- if (!$folders[$foldername]) {
- $folders[$foldername] = new kolab_storage_folder_user($foldername, $other_ns);
- }
- }
-
- // for every (subscribed) user folder, list all (unsubscribed) subfolders
- foreach ($folders as $userfolder) {
- foreach ((array)self::list_folders($userfolder->name . $delimiter, '*', $type, false, $folderdata) as $foldername) {
- if (!$folders[$foldername]) {
- $folders[$foldername] = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
- $userfolder->children[] = $folders[$foldername];
- }
- }
- }
- }
-
- return $folders;
- }
-
-
- /**
- * Handler for user_delete plugin hooks
- *
- * Remove all cache data from the local database related to the given user.
- */
- public static function delete_user_folders($args)
- {
- $db = rcmail::get_instance()->get_dbh();
- $prefix = 'imap://' . urlencode($args['username']) . '@' . $args['host'] . '/%';
- $db->query("DELETE FROM " . $db->table_name('kolab_folders', true) . " WHERE `resource` LIKE ?", $prefix);
- }
-}
diff --git a/lib/plugins/libkolab/lib/kolab_storage_cache.php b/lib/plugins/libkolab/lib/kolab_storage_cache.php
deleted file mode 100644
index 227fa4e..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_cache.php
+++ /dev/null
@@ -1,1135 +0,0 @@
-<?php
-
-/**
- * Kolab storage cache class providing a local caching layer for Kolab groupware objects.
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012-2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_cache
-{
- const DB_DATE_FORMAT = 'Y-m-d H:i:s';
-
- public $sync_complete = false;
-
- protected $db;
- protected $imap;
- protected $folder;
- protected $uid2msg;
- protected $objects;
- protected $metadata = array();
- protected $folder_id;
- protected $resource_uri;
- protected $enabled = true;
- protected $synched = false;
- protected $synclock = false;
- protected $ready = false;
- protected $cache_table;
- protected $folders_table;
- protected $max_sql_packet;
- protected $max_sync_lock_time = 600;
- protected $binary_items = array();
- protected $extra_cols = array();
- protected $order_by = null;
- protected $limit = null;
- protected $error = 0;
-
-
- /**
- * Factory constructor
- */
- public static function factory(kolab_storage_folder $storage_folder)
- {
- $subclass = 'kolab_storage_cache_' . $storage_folder->type;
- if (class_exists($subclass)) {
- return new $subclass($storage_folder);
- }
- else {
- rcube::raise_error(array(
- 'code' => 900,
- 'type' => 'php',
- 'message' => "No kolab_storage_cache class found for folder '$storage_folder->name' of type '$storage_folder->type'"
- ), true);
-
- return new kolab_storage_cache($storage_folder);
- }
- }
-
-
- /**
- * Default constructor
- */
- public function __construct(kolab_storage_folder $storage_folder = null)
- {
- $rcmail = rcube::get_instance();
- $this->db = $rcmail->get_dbh();
- $this->imap = $rcmail->get_storage();
- $this->enabled = $rcmail->config->get('kolab_cache', false);
- $this->folders_table = $this->db->table_name('kolab_folders');
-
- if ($this->enabled) {
- // always read folder cache and lock state from DB master
- $this->db->set_table_dsn('kolab_folders', 'w');
- // remove sync-lock on script termination
- $rcmail->add_shutdown_function(array($this, '_sync_unlock'));
- }
-
- if ($storage_folder)
- $this->set_folder($storage_folder);
- }
-
- /**
- * Direct access to cache by folder_id
- * (only for internal use)
- */
- public function select_by_id($folder_id)
- {
- $sql_arr = $this->db->fetch_assoc($this->db->query("SELECT * FROM `{$this->folders_table}` WHERE `folder_id` = ?", $folder_id));
- if ($sql_arr) {
- $this->metadata = $sql_arr;
- $this->folder_id = $sql_arr['folder_id'];
- $this->folder = new StdClass;
- $this->folder->type = $sql_arr['type'];
- $this->resource_uri = $sql_arr['resource'];
- $this->cache_table = $this->db->table_name('kolab_cache_' . $sql_arr['type']);
- $this->ready = true;
- }
- }
-
- /**
- * Connect cache with a storage folder
- *
- * @param kolab_storage_folder The storage folder instance to connect with
- */
- public function set_folder(kolab_storage_folder $storage_folder)
- {
- $this->folder = $storage_folder;
-
- if (empty($this->folder->name) || !$this->folder->valid) {
- $this->ready = false;
- return;
- }
-
- // compose fully qualified ressource uri for this instance
- $this->resource_uri = $this->folder->get_resource_uri();
- $this->cache_table = $this->db->table_name('kolab_cache_' . $this->folder->type);
- $this->ready = $this->enabled && !empty($this->folder->type);
- $this->folder_id = null;
- }
-
- /**
- * Returns true if this cache supports query by type
- */
- public function has_type_col()
- {
- return in_array('type', $this->extra_cols);
- }
-
- /**
- * Getter for the numeric ID used in cache tables
- */
- public function get_folder_id()
- {
- $this->_read_folder_data();
- return $this->folder_id;
- }
-
- /**
- * Returns code of last error
- *
- * @return int Error code
- */
- public function get_error()
- {
- return $this->error;
- }
-
- /**
- * Synchronize local cache data with remote
- */
- public function synchronize()
- {
- // only sync once per request cycle
- if ($this->synched)
- return;
-
- // increase time limit
- @set_time_limit($this->max_sync_lock_time - 60);
-
- // get effective time limit we have for synchronization (~70% of the execution time)
- $time_limit = ini_get('max_execution_time') * 0.7;
- $sync_start = time();
-
- // assume sync will be completed
- $this->sync_complete = true;
-
- if (!$this->ready) {
- // kolab cache is disabled, synchronize IMAP mailbox cache only
- $this->imap->folder_sync($this->folder->name);
- }
- else {
- // read cached folder metadata
- $this->_read_folder_data();
-
- // check cache status hash first ($this->metadata is set in _read_folder_data())
- if ($this->metadata['ctag'] != $this->folder->get_ctag()) {
- // lock synchronization for this folder or wait if locked
- $this->_sync_lock();
-
- // disable messages cache if configured to do so
- $this->bypass(true);
-
- // synchronize IMAP mailbox cache
- $this->imap->folder_sync($this->folder->name);
-
- // compare IMAP index with object cache index
- $imap_index = $this->imap->index($this->folder->name, null, null, true, true);
-
- // determine objects to fetch or to invalidate
- if (!$imap_index->is_error()) {
- $imap_index = $imap_index->get();
-
- // read cache index
- $sql_result = $this->db->query(
- "SELECT `msguid`, `uid` FROM `{$this->cache_table}` WHERE `folder_id` = ?",
- $this->folder_id
- );
-
- $old_index = array();
- while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
- $old_index[] = $sql_arr['msguid'];
- }
-
- // fetch new objects from imap
- $i = 0;
- foreach (array_diff($imap_index, $old_index) as $msguid) {
- if ($object = $this->folder->read_object($msguid, '*')) {
- $this->_extended_insert($msguid, $object);
-
- // check time limit and abort sync if running too long
- if (++$i % 50 == 0 && time() - $sync_start > $time_limit) {
- $this->sync_complete = false;
- break;
- }
- }
- }
- $this->_extended_insert(0, null);
-
- // delete invalid entries from local DB
- $del_index = array_diff($old_index, $imap_index);
- if (!empty($del_index)) {
- $quoted_ids = join(',', array_map(array($this->db, 'quote'), $del_index));
- $this->db->query(
- "DELETE FROM `{$this->cache_table}` WHERE `folder_id` = ? AND `msguid` IN ($quoted_ids)",
- $this->folder_id
- );
- }
-
- // update ctag value (will be written to database in _sync_unlock())
- if ($this->sync_complete) {
- $this->metadata['ctag'] = $this->folder->get_ctag();
- }
- }
-
- $this->bypass(false);
-
- // remove lock
- $this->_sync_unlock();
- }
- }
-
- $this->check_error();
- $this->synched = time();
- }
-
-
- /**
- * Read a single entry from cache or from IMAP directly
- *
- * @param string Related IMAP message UID
- * @param string Object type to read
- * @param string IMAP folder name the entry relates to
- * @param array Hash array with object properties or null if not found
- */
- public function get($msguid, $type = null, $foldername = null)
- {
- // delegate to another cache instance
- if ($foldername && $foldername != $this->folder->name) {
- $success = false;
- if ($targetfolder = kolab_storage::get_folder($foldername)) {
- $success = $targetfolder->cache->get($msguid, $type);
- $this->error = $targetfolder->cache->get_error();
- }
- return $success;
- }
-
- // load object if not in memory
- if (!isset($this->objects[$msguid])) {
- if ($this->ready) {
- $this->_read_folder_data();
-
- $sql_result = $this->db->query(
- "SELECT * FROM `{$this->cache_table}` ".
- "WHERE `folder_id` = ? AND `msguid` = ?",
- $this->folder_id,
- $msguid
- );
-
- if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
- $this->objects = array($msguid => $this->_unserialize($sql_arr)); // store only this object in memory (#2827)
- }
- }
-
- // fetch from IMAP if not present in cache
- if (empty($this->objects[$msguid])) {
- if ($object = $this->folder->read_object($msguid, $type ?: '*', $foldername)) {
- $this->objects = array($msguid => $object);
- $this->set($msguid, $object);
- }
- }
- }
-
- $this->check_error();
- return $this->objects[$msguid];
- }
-
-
- /**
- * Insert/Update a cache entry
- *
- * @param string Related IMAP message UID
- * @param mixed Hash array with object properties to save or false to delete the cache entry
- * @param string IMAP folder name the entry relates to
- */
- public function set($msguid, $object, $foldername = null)
- {
- if (!$msguid) {
- return;
- }
-
- // delegate to another cache instance
- if ($foldername && $foldername != $this->folder->name) {
- if ($targetfolder = kolab_storage::get_folder($foldername)) {
- $targetfolder->cache->set($msguid, $object);
- $this->error = $targetfolder->cache->get_error();
- }
- return;
- }
-
- // remove old entry
- if ($this->ready) {
- $this->_read_folder_data();
- $this->db->query("DELETE FROM `{$this->cache_table}` WHERE `folder_id` = ? AND `msguid` = ?",
- $this->folder_id, $msguid);
- }
-
- if ($object) {
- // insert new object data...
- $this->save($msguid, $object);
- }
- else {
- // ...or set in-memory cache to false
- $this->objects[$msguid] = $object;
- }
-
- $this->check_error();
- }
-
-
- /**
- * Insert (or update) a cache entry
- *
- * @param int Related IMAP message UID
- * @param mixed Hash array with object properties to save or false to delete the cache entry
- * @param int Optional old message UID (for update)
- */
- public function save($msguid, $object, $olduid = null)
- {
- // write to cache
- if ($this->ready) {
- $this->_read_folder_data();
-
- $sql_data = $this->_serialize($object);
- $sql_data['folder_id'] = $this->folder_id;
- $sql_data['msguid'] = $msguid;
- $sql_data['uid'] = $object['uid'];
-
- $args = array();
- $cols = array('folder_id', 'msguid', 'uid', 'changed', 'data', 'xml', 'tags', 'words');
- $cols = array_merge($cols, $this->extra_cols);
-
- foreach ($cols as $idx => $col) {
- $cols[$idx] = $this->db->quote_identifier($col);
- $args[] = $sql_data[$col];
- }
-
- if ($olduid) {
- foreach ($cols as $idx => $col) {
- $cols[$idx] = "$col = ?";
- }
-
- $query = "UPDATE `{$this->cache_table}` SET " . implode(', ', $cols)
- . " WHERE `folder_id` = ? AND `msguid` = ?";
- $args[] = $this->folder_id;
- $args[] = $olduid;
- }
- else {
- $query = "INSERT INTO `{$this->cache_table}` (`created`, " . implode(', ', $cols)
- . ") VALUES (" . $this->db->now() . str_repeat(', ?', count($cols)) . ")";
- }
-
- $result = $this->db->query($query, $args);
-
- if (!$this->db->affected_rows($result)) {
- rcube::raise_error(array(
- 'code' => 900, 'type' => 'php',
- 'message' => "Failed to write to kolab cache"
- ), true);
- }
- }
-
- // keep a copy in memory for fast access
- $this->objects = array($msguid => $object);
- $this->uid2msg = array($object['uid'] => $msguid);
-
- $this->check_error();
- }
-
-
- /**
- * Move an existing cache entry to a new resource
- *
- * @param string Entry's IMAP message UID
- * @param string Entry's Object UID
- * @param object kolab_storage_folder Target storage folder instance
- */
- public function move($msguid, $uid, $target)
- {
- if ($this->ready) {
- // clear cached uid mapping and force new lookup
- unset($target->cache->uid2msg[$uid]);
-
- // resolve new message UID in target folder
- if ($new_msguid = $target->cache->uid2msguid($uid)) {
- $this->_read_folder_data();
-
- $this->db->query(
- "UPDATE `{$this->cache_table}` SET `folder_id` = ?, `msguid` = ? ".
- "WHERE `folder_id` = ? AND `msguid` = ?",
- $target->cache->get_folder_id(),
- $new_msguid,
- $this->folder_id,
- $msguid
- );
-
- $result = $this->db->affected_rows();
- }
- }
-
- if (empty($result)) {
- // just clear cache entry
- $this->set($msguid, false);
- }
-
- unset($this->uid2msg[$uid]);
- $this->check_error();
- }
-
-
- /**
- * Remove all objects from local cache
- */
- public function purge()
- {
- if (!$this->ready) {
- return true;
- }
-
- $this->_read_folder_data();
-
- $result = $this->db->query(
- "DELETE FROM `{$this->cache_table}` WHERE `folder_id` = ?",
- $this->folder_id
- );
-
- return $this->db->affected_rows($result);
- }
-
- /**
- * Update resource URI for existing cache entries
- *
- * @param string Target IMAP folder to move it to
- */
- public function rename($new_folder)
- {
- if (!$this->ready) {
- return;
- }
-
- if ($target = kolab_storage::get_folder($new_folder)) {
- // resolve new message UID in target folder
- $this->db->query(
- "UPDATE `{$this->folders_table}` SET `resource` = ? ".
- "WHERE `resource` = ?",
- $target->get_resource_uri(),
- $this->resource_uri
- );
-
- $this->check_error();
- }
- else {
- $this->error = kolab_storage::ERROR_IMAP_CONN;
- }
- }
-
- /**
- * Select Kolab objects filtered by the given query
- *
- * @param array Pseudo-SQL query as list of filter parameter triplets
- * triplet: array('<colname>', '<comparator>', '<value>')
- * @param boolean Set true to only return UIDs instead of complete objects
- * @return array List of Kolab data objects (each represented as hash array) or UIDs
- */
- public function select($query = array(), $uids = false)
- {
- $result = $uids ? array() : new kolab_storage_dataset($this);
-
- // read from local cache DB (assume it to be synchronized)
- if ($this->ready) {
- $this->_read_folder_data();
-
- // fetch full object data on one query if a small result set is expected
- $fetchall = !$uids && ($this->limit ? $this->limit[0] : $this->count($query)) < 500;
- $sql_query = "SELECT " . ($fetchall ? '*' : '`msguid` AS `_msguid`, `uid`') . " FROM `{$this->cache_table}` ".
- "WHERE `folder_id` = ? " . $this->_sql_where($query);
- if (!empty($this->order_by)) {
- $sql_query .= ' ORDER BY ' . $this->order_by;
- }
- $sql_result = $this->limit ?
- $this->db->limitquery($sql_query, $this->limit[1], $this->limit[0], $this->folder_id) :
- $this->db->query($sql_query, $this->folder_id);
-
- if ($this->db->is_error($sql_result)) {
- if ($uids) {
- return null;
- }
- $result->set_error(true);
- return $result;
- }
-
- while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
- if ($uids) {
- $this->uid2msg[$sql_arr['uid']] = $sql_arr['_msguid'];
- $result[] = $sql_arr['uid'];
- }
- else if ($fetchall && ($object = $this->_unserialize($sql_arr))) {
- $result[] = $object;
- }
- else if (!$fetchall) {
- // only add msguid to dataset index
- $result[] = $sql_arr;
- }
- }
- }
- // use IMAP
- else {
- $filter = $this->_query2assoc($query);
-
- if ($filter['type']) {
- $search = 'UNDELETED HEADER X-Kolab-Type ' . kolab_format::KTYPE_PREFIX . $filter['type'];
- $index = $this->imap->search_once($this->folder->name, $search);
- }
- else {
- $index = $this->imap->index($this->folder->name, null, null, true, true);
- }
-
- if ($index->is_error()) {
- $this->check_error();
- if ($uids) {
- return null;
- }
- $result->set_error(true);
- return $result;
- }
-
- $index = $index->get();
- $result = $uids ? $index : $this->_fetch($index, $filter['type']);
-
- // TODO: post-filter result according to query
- }
-
- // We don't want to cache big results in-memory, however
- // if we select only one object here, there's a big chance we will need it later
- if (!$uids && count($result) == 1) {
- if ($msguid = $result[0]['_msguid']) {
- $this->uid2msg[$result[0]['uid']] = $msguid;
- $this->objects = array($msguid => $result[0]);
- }
- }
-
- $this->check_error();
-
- return $result;
- }
-
-
- /**
- * Get number of objects mathing the given query
- *
- * @param array $query Pseudo-SQL query as list of filter parameter triplets
- * @return integer The number of objects of the given type
- */
- public function count($query = array())
- {
- // read from local cache DB (assume it to be synchronized)
- if ($this->ready) {
- $this->_read_folder_data();
-
- $sql_result = $this->db->query(
- "SELECT COUNT(*) AS `numrows` FROM `{$this->cache_table}` ".
- "WHERE `folder_id` = ?" . $this->_sql_where($query),
- $this->folder_id
- );
-
- if ($this->db->is_error($sql_result)) {
- return null;
- }
-
- $sql_arr = $this->db->fetch_assoc($sql_result);
- $count = intval($sql_arr['numrows']);
- }
- // use IMAP
- else {
- $filter = $this->_query2assoc($query);
-
- if ($filter['type']) {
- $search = 'UNDELETED HEADER X-Kolab-Type ' . kolab_format::KTYPE_PREFIX . $filter['type'];
- $index = $this->imap->search_once($this->folder->name, $search);
- }
- else {
- $index = $this->imap->index($this->folder->name, null, null, true, true);
- }
-
- if ($index->is_error()) {
- $this->check_error();
- return null;
- }
-
- // TODO: post-filter result according to query
-
- $count = $index->count();
- }
-
- $this->check_error();
- return $count;
- }
-
- /**
- * Define ORDER BY clause for cache queries
- */
- public function set_order_by($sortcols)
- {
- if (!empty($sortcols)) {
- $this->order_by = '`' . join('`, `', (array)$sortcols) . '`';
- }
- else {
- $this->order_by = null;
- }
- }
-
- /**
- * Define LIMIT clause for cache queries
- */
- public function set_limit($length, $offset = 0)
- {
- $this->limit = array($length, $offset);
- }
-
- /**
- * Helper method to compose a valid SQL query from pseudo filter triplets
- */
- protected function _sql_where($query)
- {
- $sql_where = '';
- foreach ((array) $query as $param) {
- if (is_array($param[0])) {
- $subq = array();
- foreach ($param[0] as $q) {
- $subq[] = preg_replace('/^\s*AND\s+/i', '', $this->_sql_where(array($q)));
- }
- if (!empty($subq)) {
- $sql_where .= ' AND (' . implode($param[1] == 'OR' ? ' OR ' : ' AND ', $subq) . ')';
- }
- continue;
- }
- else if ($param[1] == '=' && is_array($param[2])) {
- $qvalue = '(' . join(',', array_map(array($this->db, 'quote'), $param[2])) . ')';
- $param[1] = 'IN';
- }
- else if ($param[1] == '~' || $param[1] == 'LIKE' || $param[1] == '!~' || $param[1] == '!LIKE') {
- $not = ($param[1] == '!~' || $param[1] == '!LIKE') ? 'NOT ' : '';
- $param[1] = $not . 'LIKE';
- $qvalue = $this->db->quote('%'.preg_replace('/(^\^|\$$)/', ' ', $param[2]).'%');
- }
- else if ($param[0] == 'tags') {
- $param[1] = ($param[1] == '!=' ? 'NOT ' : '' ) . 'LIKE';
- $qvalue = $this->db->quote('% '.$param[2].' %');
- }
- else {
- $qvalue = $this->db->quote($param[2]);
- }
-
- $sql_where .= sprintf(' AND %s %s %s',
- $this->db->quote_identifier($param[0]),
- $param[1],
- $qvalue
- );
- }
-
- return $sql_where;
- }
-
- /**
- * Helper method to convert the given pseudo-query triplets into
- * an associative filter array with 'equals' values only
- */
- protected function _query2assoc($query)
- {
- // extract object type from query parameter
- $filter = array();
- foreach ($query as $param) {
- if ($param[1] == '=')
- $filter[$param[0]] = $param[2];
- }
- return $filter;
- }
-
- /**
- * Fetch messages from IMAP
- *
- * @param array List of message UIDs to fetch
- * @param string Requested object type or * for all
- * @param string IMAP folder to read from
- * @return array List of parsed Kolab objects
- */
- protected function _fetch($index, $type = null, $folder = null)
- {
- $results = new kolab_storage_dataset($this);
- foreach ((array)$index as $msguid) {
- if ($object = $this->folder->read_object($msguid, $type, $folder)) {
- $results[] = $object;
- $this->set($msguid, $object);
- }
- }
-
- return $results;
- }
-
- /**
- * Helper method to convert the given Kolab object into a dataset to be written to cache
- */
- protected function _serialize($object)
- {
- $sql_data = array('changed' => null, 'xml' => '', 'tags' => '', 'words' => '');
-
- if ($object['changed']) {
- $sql_data['changed'] = date('Y-m-d H:i:s', is_object($object['changed']) ? $object['changed']->format('U') : $object['changed']);
- }
-
- if ($object['_formatobj']) {
- $sql_data['xml'] = preg_replace('!(</?[a-z0-9:-]+>)[\n\r\t\s]+!ms', '$1', (string)$object['_formatobj']->write(3.0));
- $sql_data['tags'] = ' ' . join(' ', $object['_formatobj']->get_tags()) . ' '; // pad with spaces for strict/prefix search
- $sql_data['words'] = ' ' . join(' ', $object['_formatobj']->get_words()) . ' ';
- }
-
- // extract object data
- $data = array();
- foreach ($object as $key => $val) {
- // skip empty properties
- if ($val === "" || $val === null) {
- continue;
- }
- // mark binary data to be extracted from xml on unserialize()
- if (isset($this->binary_items[$key])) {
- $data[$key] = true;
- }
- else if ($key[0] != '_') {
- $data[$key] = $val;
- }
- else if ($key == '_attachments') {
- foreach ($val as $k => $att) {
- unset($att['content'], $att['path']);
- if ($att['id'])
- $data[$key][$k] = $att;
- }
- }
- }
-
- // use base64 encoding (Bug #1912, #2662)
- $sql_data['data'] = base64_encode(serialize($data));
-
- return $sql_data;
- }
-
- /**
- * Helper method to turn stored cache data into a valid storage object
- */
- protected function _unserialize($sql_arr)
- {
- // check if data is a base64-encoded string, for backward compat.
- if (strpos(substr($sql_arr['data'], 0, 64), ':') === false) {
- $sql_arr['data'] = base64_decode($sql_arr['data']);
- }
-
- $object = unserialize($sql_arr['data']);
-
- // de-serialization failed
- if ($object === false) {
- rcube::raise_error(array(
- 'code' => 900, 'type' => 'php',
- 'message' => "Malformed data for {$this->resource_uri}/{$sql_arr['msguid']} object."
- ), true);
-
- return null;
- }
-
- // decode binary properties
- foreach ($this->binary_items as $key => $regexp) {
- if (!empty($object[$key]) && preg_match($regexp, $sql_arr['xml'], $m)) {
- $object[$key] = base64_decode($m[1]);
- }
- }
-
- $object_type = $sql_arr['type'] ?: $this->folder->type;
- $format_type = $this->folder->type == 'configuration' ? 'configuration' : $object_type;
-
- // add meta data
- $object['_type'] = $object_type;
- $object['_msguid'] = $sql_arr['msguid'];
- $object['_mailbox'] = $this->folder->name;
- $object['_size'] = strlen($sql_arr['xml']);
- $object['_formatobj'] = kolab_format::factory($format_type, 3.0, $sql_arr['xml']);
-
- return $object;
- }
-
- /**
- * Write records into cache using extended inserts to reduce the number of queries to be executed
- *
- * @param int Message UID. Set 0 to commit buffered inserts
- * @param array Kolab object to cache
- */
- protected function _extended_insert($msguid, $object)
- {
- static $buffer = '';
-
- $line = '';
- if ($object) {
- $sql_data = $this->_serialize($object);
-
- // Skip multifolder insert for Oracle, we can't put long data inline
- if ($this->db->db_provider == 'oracle') {
- $extra_cols = '';
- if ($this->extra_cols) {
- $extra_cols = array_map(function($n) { return "`{$n}`"; }, $this->extra_cols);
- $extra_cols = ', ' . join(', ', $extra_cols);
- $extra_args = str_repeat(', ?', count($this->extra_cols));
- }
-
- $params = array($this->folder_id, $msguid, $object['uid'], $sql_data['changed'],
- $sql_data['data'], $sql_data['xml'], $sql_data['tags'], $sql_data['words']);
-
- foreach ($this->extra_cols as $col) {
- $params[] = $sql_data[$col];
- }
-
- $result = $this->db->query(
- "INSERT INTO `{$this->cache_table}` "
- . " (`folder_id`, `msguid`, `uid`, `created`, `changed`, `data`, `xml`, `tags`, `words` $extra_cols)"
- . " VALUES (?, ?, ?, " . $this->db->now() . ", ?, ?, ?, ?, ? $extra_args)",
- $params
- );
-
- if (!$this->db->affected_rows($result)) {
- rcube::raise_error(array(
- 'code' => 900, 'type' => 'php',
- 'message' => "Failed to write to kolab cache"
- ), true);
- }
-
- return;
- }
-
- $values = array(
- $this->db->quote($this->folder_id),
- $this->db->quote($msguid),
- $this->db->quote($object['uid']),
- $this->db->now(),
- $this->db->quote($sql_data['changed']),
- $this->db->quote($sql_data['data']),
- $this->db->quote($sql_data['xml']),
- $this->db->quote($sql_data['tags']),
- $this->db->quote($sql_data['words']),
- );
- foreach ($this->extra_cols as $col) {
- $values[] = $this->db->quote($sql_data[$col]);
- }
- $line = '(' . join(',', $values) . ')';
- }
-
- if ($buffer && (!$msguid || (strlen($buffer) + strlen($line) > $this->max_sql_packet()))) {
- $extra_cols = '';
- if ($this->extra_cols) {
- $extra_cols = array_map(function($n) { return "`{$n}`"; }, $this->extra_cols);
- $extra_cols = ', ' . join(', ', $extra_cols);
- }
-
- $result = $this->db->query(
- "INSERT INTO `{$this->cache_table}` ".
- " (`folder_id`, `msguid`, `uid`, `created`, `changed`, `data`, `xml`, `tags`, `words` $extra_cols)".
- " VALUES $buffer"
- );
-
- if (!$this->db->affected_rows($result)) {
- rcube::raise_error(array(
- 'code' => 900, 'type' => 'php',
- 'message' => "Failed to write to kolab cache"
- ), true);
- }
-
- $buffer = '';
- }
-
- $buffer .= ($buffer ? ',' : '') . $line;
- }
-
- /**
- * Returns max_allowed_packet from mysql config
- */
- protected function max_sql_packet()
- {
- if (!$this->max_sql_packet) {
- // mysql limit or max 4 MB
- $value = $this->db->get_variable('max_allowed_packet', 1048500);
- $this->max_sql_packet = min($value, 4*1024*1024) - 2000;
- }
-
- return $this->max_sql_packet;
- }
-
- /**
- * Read this folder's ID and cache metadata
- */
- protected function _read_folder_data()
- {
- // already done
- if (!empty($this->folder_id) || !$this->ready)
- return;
-
- $sql_arr = $this->db->fetch_assoc($this->db->query(
- "SELECT `folder_id`, `synclock`, `ctag`"
- . " FROM `{$this->folders_table}` WHERE `resource` = ?",
- $this->resource_uri
- ));
-
- if ($sql_arr) {
- $this->metadata = $sql_arr;
- $this->folder_id = $sql_arr['folder_id'];
- }
- else {
- $this->db->query("INSERT INTO `{$this->folders_table}` (`resource`, `type`)"
- . " VALUES (?, ?)", $this->resource_uri, $this->folder->type);
-
- $this->folder_id = $this->db->insert_id('kolab_folders');
- $this->metadata = array();
- }
- }
-
- /**
- * Check lock record for this folder and wait if locked or set lock
- */
- protected function _sync_lock()
- {
- if (!$this->ready)
- return;
-
- $this->_read_folder_data();
-
- // abort if database is not set-up
- if ($this->db->is_error()) {
- $this->check_error();
- $this->ready = false;
- return;
- }
-
- $read_query = "SELECT `synclock`, `ctag` FROM `{$this->folders_table}` WHERE `folder_id` = ?";
- $write_query = "UPDATE `{$this->folders_table}` SET `synclock` = ? WHERE `folder_id` = ? AND `synclock` = ?";
-
- // wait if locked (expire locks after 10 minutes) ...
- // ... or if setting lock fails (another process meanwhile set it)
- while (
- (intval($this->metadata['synclock']) + $this->max_sync_lock_time > time()) ||
- (($res = $this->db->query($write_query, time(), $this->folder_id, intval($this->metadata['synclock']))) &&
- !($affected = $this->db->affected_rows($res)))
- ) {
- usleep(500000);
- $this->metadata = $this->db->fetch_assoc($this->db->query($read_query, $this->folder_id));
- }
-
- $this->synclock = $affected > 0;
- }
-
- /**
- * Remove lock for this folder
- */
- public function _sync_unlock()
- {
- if (!$this->ready || !$this->synclock)
- return;
-
- $this->db->query(
- "UPDATE `{$this->folders_table}` SET `synclock` = 0, `ctag` = ? WHERE `folder_id` = ?",
- $this->metadata['ctag'],
- $this->folder_id
- );
-
- $this->synclock = false;
- }
-
- /**
- * Check IMAP connection error state
- */
- protected function check_error()
- {
- if (($err_code = $this->imap->get_error_code()) < 0) {
- $this->error = kolab_storage::ERROR_IMAP_CONN;
- if (($res_code = $this->imap->get_response_code()) !== 0 && in_array($res_code, array(rcube_storage::NOPERM, rcube_storage::READONLY))) {
- $this->error = kolab_storage::ERROR_NO_PERMISSION;
- }
- }
- else if ($this->db->is_error()) {
- $this->error = kolab_storage::ERROR_CACHE_DB;
- }
- }
-
- /**
- * Resolve an object UID into an IMAP message UID
- *
- * @param string Kolab object UID
- * @param boolean Include deleted objects
- * @return int The resolved IMAP message UID
- */
- public function uid2msguid($uid, $deleted = false)
- {
- // query local database if available
- if (!isset($this->uid2msg[$uid]) && $this->ready) {
- $this->_read_folder_data();
-
- $sql_result = $this->db->query(
- "SELECT `msguid` FROM `{$this->cache_table}` ".
- "WHERE `folder_id` = ? AND `uid` = ? ORDER BY `msguid` DESC",
- $this->folder_id,
- $uid
- );
-
- if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
- $this->uid2msg[$uid] = $sql_arr['msguid'];
- }
- }
-
- if (!isset($this->uid2msg[$uid])) {
- // use IMAP SEARCH to get the right message
- $index = $this->imap->search_once($this->folder->name, ($deleted ? '' : 'UNDELETED ') .
- 'HEADER SUBJECT ' . rcube_imap_generic::escape($uid));
- $results = $index->get();
- $this->uid2msg[$uid] = end($results);
- }
-
- return $this->uid2msg[$uid];
- }
-
- /**
- * Getter for protected member variables
- */
- public function __get($name)
- {
- if ($name == 'folder_id') {
- $this->_read_folder_data();
- }
-
- return $this->$name;
- }
-
- /**
- * Bypass Roundcube messages cache.
- * Roundcube cache duplicates information already stored in kolab_cache.
- *
- * @param bool $disable True disables, False enables messages cache
- */
- public function bypass($disable = false)
- {
- // if kolab cache is disabled do nothing
- if (!$this->enabled) {
- return;
- }
-
- static $messages_cache, $cache_bypass;
-
- if ($messages_cache === null) {
- $rcmail = rcube::get_instance();
- $messages_cache = (bool) $rcmail->config->get('messages_cache');
- $cache_bypass = (int) $rcmail->config->get('kolab_messages_cache_bypass');
- }
-
- if ($messages_cache) {
- // handle recurrent (multilevel) bypass() calls
- if ($disable) {
- $this->cache_bypassed += 1;
- if ($this->cache_bypassed > 1) {
- return;
- }
- }
- else {
- $this->cache_bypassed -= 1;
- if ($this->cache_bypassed > 0) {
- return;
- }
- }
-
- switch ($cache_bypass) {
- case 2:
- // Disable messages cache completely
- $this->imap->set_messages_caching(!$disable);
- break;
-
- case 1:
- // We'll disable messages cache, but keep index cache.
- // Default mode is both (MODE_INDEX | MODE_MESSAGE)
- $mode = rcube_imap_cache::MODE_INDEX;
-
- if (!$disable) {
- $mode |= rcube_imap_cache::MODE_MESSAGE;
- }
-
- $this->imap->set_messages_caching(true, $mode);
- }
- }
- }
-
-}
diff --git a/lib/plugins/libkolab/lib/kolab_storage_cache_configuration.php b/lib/plugins/libkolab/lib/kolab_storage_cache_configuration.php
deleted file mode 100644
index c3c7ac4..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_cache_configuration.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-
-/**
- * Kolab storage cache class for configuration objects
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_cache_configuration extends kolab_storage_cache
-{
- protected $extra_cols = array('type');
-
- /**
- * Helper method to convert the given Kolab object into a dataset to be written to cache
- *
- * @override
- */
- protected function _serialize($object)
- {
- $sql_data = parent::_serialize($object);
- $sql_data['type'] = $object['type'];
-
- return $sql_data;
- }
-
- /**
- * Select Kolab objects filtered by the given query
- *
- * @param array Pseudo-SQL query as list of filter parameter triplets
- * @param boolean Set true to only return UIDs instead of complete objects
- * @return array List of Kolab data objects (each represented as hash array) or UIDs
- */
- public function select($query = array(), $uids = false)
- {
- // modify query for IMAP search: query param 'type' is actually a subtype
- if (!$this->ready) {
- foreach ($query as $i => $tuple) {
- if ($tuple[0] == 'type') {
- $tuple[2] = 'configuration.' . $tuple[2];
- $query[$i] = $tuple;
- }
- }
- }
-
- return parent::select($query, $uids);
- }
-
- /**
- * Helper method to compose a valid SQL query from pseudo filter triplets
- */
- protected function _sql_where($query)
- {
- if (is_array($query)) {
- foreach ($query as $idx => $param) {
- // convert category filter
- if ($param[0] == 'category') {
- $param[2] = array_map(function($n) { return 'category:' . $n; }, (array) $param[2]);
-
- $query[$idx][0] = 'tags';
- $query[$idx][2] = count($param[2]) > 1 ? $param[2] : $param[2][0];
- }
- // convert member filter (we support only = operator with single value)
- else if ($param[0] == 'member') {
- $query[$idx][0] = 'words';
- $query[$idx][1] = '~';
- $query[$idx][2] = '^' . $param[2] . '$';
- }
- }
- }
-
- return parent::_sql_where($query);
- }
-}
diff --git a/lib/plugins/libkolab/lib/kolab_storage_cache_contact.php b/lib/plugins/libkolab/lib/kolab_storage_cache_contact.php
deleted file mode 100644
index 9666a39..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_cache_contact.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-
-/**
- * Kolab storage cache class for contact objects
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_cache_contact extends kolab_storage_cache
-{
- protected $extra_cols = array('type','name','firstname','surname','email');
- protected $binary_items = array(
- 'photo' => '|<photo><uri>[^;]+;base64,([^<]+)</uri></photo>|i',
- 'pgppublickey' => '|<key><uri>date:application/pgp-keys;base64,([^<]+)</uri></key>|i',
- 'pkcs7publickey' => '|<key><uri>date:application/pkcs7-mime;base64,([^<]+)</uri></key>|i',
- );
-
- /**
- * Helper method to convert the given Kolab object into a dataset to be written to cache
- *
- * @override
- */
- protected function _serialize($object)
- {
- $sql_data = parent::_serialize($object);
- $sql_data['type'] = $object['_type'];
-
- // columns for sorting
- $sql_data['name'] = rcube_charset::clean($object['name'] . $object['prefix']);
- $sql_data['firstname'] = rcube_charset::clean($object['firstname'] . $object['middlename'] . $object['surname']);
- $sql_data['surname'] = rcube_charset::clean($object['surname'] . $object['firstname'] . $object['middlename']);
- $sql_data['email'] = rcube_charset::clean(is_array($object['email']) ? $object['email'][0] : $object['email']);
-
- if (is_array($sql_data['email'])) {
- $sql_data['email'] = $sql_data['email']['address'];
- }
- // avoid value being null
- if (empty($sql_data['email'])) {
- $sql_data['email'] = '';
- }
-
- return $sql_data;
- }
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/lib/kolab_storage_cache_event.php b/lib/plugins/libkolab/lib/kolab_storage_cache_event.php
deleted file mode 100644
index 5fc44cd..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_cache_event.php
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-
-/**
- * Kolab storage cache class for calendar event objects
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_cache_event extends kolab_storage_cache
-{
- protected $extra_cols = array('dtstart','dtend');
-
- /**
- * Helper method to convert the given Kolab object into a dataset to be written to cache
- *
- * @override
- */
- protected function _serialize($object)
- {
- $sql_data = parent::_serialize($object);
-
- $sql_data['dtstart'] = is_object($object['start']) ? $object['start']->format(self::DB_DATE_FORMAT) : date(self::DB_DATE_FORMAT, $object['start']);
- $sql_data['dtend'] = is_object($object['end']) ? $object['end']->format(self::DB_DATE_FORMAT) : date(self::DB_DATE_FORMAT, $object['end']);
-
- // extend date range for recurring events
- if ($object['recurrence'] && $object['_formatobj']) {
- $recurrence = new kolab_date_recurrence($object['_formatobj']);
- $dtend = $recurrence->end() ?: new DateTime('now +10 years');
- $sql_data['dtend'] = $dtend->format(self::DB_DATE_FORMAT);
- }
-
- return $sql_data;
- }
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/lib/kolab_storage_cache_file.php b/lib/plugins/libkolab/lib/kolab_storage_cache_file.php
deleted file mode 100644
index ea1823d..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_cache_file.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-/**
- * Kolab storage cache class for file objects
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_cache_file extends kolab_storage_cache
-{
- protected $extra_cols = array('filename');
-
- /**
- * Helper method to convert the given Kolab object into a dataset to be written to cache
- *
- * @override
- */
- protected function _serialize($object)
- {
- $sql_data = parent::_serialize($object);
-
- if (!empty($object['_attachments'])) {
- reset($object['_attachments']);
- $sql_data['filename'] = $object['_attachments'][key($object['_attachments'])]['name'];
- }
-
- return $sql_data;
- }
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/lib/kolab_storage_cache_freebusy.php b/lib/plugins/libkolab/lib/kolab_storage_cache_freebusy.php
deleted file mode 100644
index d8ab554..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_cache_freebusy.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-/**
- * Kolab storage cache class for freebusy objects
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_cache_freebusy extends kolab_storage_cache
-{
- protected $extra_cols = array('dtstart','dtend');
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/lib/kolab_storage_cache_journal.php b/lib/plugins/libkolab/lib/kolab_storage_cache_journal.php
deleted file mode 100644
index a63577b..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_cache_journal.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-
-/**
- * Kolab storage cache class for journal objects
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_cache_journal extends kolab_storage_cache
-{
- protected $extra_cols = array('dtstart','dtend');
-
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/lib/kolab_storage_cache_mongodb.php b/lib/plugins/libkolab/lib/kolab_storage_cache_mongodb.php
deleted file mode 100644
index 8ae95e4..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_cache_mongodb.php
+++ /dev/null
@@ -1,561 +0,0 @@
-<?php
-
-/**
- * Kolab storage cache class providing a local caching layer for Kolab groupware objects.
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_cache_mongodb
-{
- private $db;
- private $imap;
- private $folder;
- private $uid2msg;
- private $objects;
- private $index = array();
- private $resource_uri;
- private $enabled = true;
- private $synched = false;
- private $synclock = false;
- private $ready = false;
- private $max_sql_packet = 1046576; // 1 MB - 2000 bytes
- private $binary_cols = array('photo','pgppublickey','pkcs7publickey');
-
-
- /**
- * Default constructor
- */
- public function __construct(kolab_storage_folder $storage_folder = null)
- {
- $rcmail = rcube::get_instance();
- $mongo = new Mongo();
- $this->db = $mongo->kolab_cache;
- $this->imap = $rcmail->get_storage();
- $this->enabled = $rcmail->config->get('kolab_cache', false);
-
- if ($this->enabled) {
- // remove sync-lock on script termination
- $rcmail->add_shutdown_function(array($this, '_sync_unlock'));
- }
-
- if ($storage_folder)
- $this->set_folder($storage_folder);
- }
-
-
- /**
- * Connect cache with a storage folder
- *
- * @param kolab_storage_folder The storage folder instance to connect with
- */
- public function set_folder(kolab_storage_folder $storage_folder)
- {
- $this->folder = $storage_folder;
-
- if (empty($this->folder->name)) {
- $this->ready = false;
- return;
- }
-
- // compose fully qualified ressource uri for this instance
- $this->resource_uri = $this->folder->get_resource_uri();
- $this->ready = $this->enabled;
- }
-
-
- /**
- * Synchronize local cache data with remote
- */
- public function synchronize()
- {
- // only sync once per request cycle
- if ($this->synched)
- return;
-
- // increase time limit
- @set_time_limit(500);
-
- // lock synchronization for this folder or wait if locked
- $this->_sync_lock();
-
- // synchronize IMAP mailbox cache
- $this->imap->folder_sync($this->folder->name);
-
- // compare IMAP index with object cache index
- $imap_index = $this->imap->index($this->folder->name);
- $this->index = $imap_index->get();
-
- // determine objects to fetch or to invalidate
- if ($this->ready) {
- // read cache index
- $old_index = array();
- $cursor = $this->db->cache->find(array('resource' => $this->resource_uri), array('msguid' => 1, 'uid' => 1));
- foreach ($cursor as $doc) {
- $old_index[] = $doc['msguid'];
- $this->uid2msg[$doc['uid']] = $doc['msguid'];
- }
-
- // fetch new objects from imap
- foreach (array_diff($this->index, $old_index) as $msguid) {
- if ($object = $this->folder->read_object($msguid, '*')) {
- try {
- $this->db->cache->insert($this->_serialize($object, $msguid));
- }
- catch (Exception $e) {
- rcmail::raise_error(array(
- 'code' => 900, 'type' => 'php',
- 'message' => "Failed to write to mongodb cache: " . $e->getMessage(),
- ), true);
- }
- }
- }
-
- // delete invalid entries from local DB
- $del_index = array_diff($old_index, $this->index);
- if (!empty($del_index)) {
- $this->db->cache->remove(array('resource' => $this->resource_uri, 'msguid' => array('$in' => $del_index)));
- }
- }
-
- // remove lock
- $this->_sync_unlock();
-
- $this->synched = time();
- }
-
-
- /**
- * Read a single entry from cache or from IMAP directly
- *
- * @param string Related IMAP message UID
- * @param string Object type to read
- * @param string IMAP folder name the entry relates to
- * @param array Hash array with object properties or null if not found
- */
- public function get($msguid, $type = null, $foldername = null)
- {
- // delegate to another cache instance
- if ($foldername && $foldername != $this->folder->name) {
- return kolab_storage::get_folder($foldername)->cache->get($msguid, $object);
- }
-
- // load object if not in memory
- if (!isset($this->objects[$msguid])) {
- if ($this->ready && ($doc = $this->db->cache->findOne(array('resource' => $this->resource_uri, 'msguid' => $msguid))))
- $this->objects[$msguid] = $this->_unserialize($doc);
-
- // fetch from IMAP if not present in cache
- if (empty($this->objects[$msguid])) {
- $result = $this->_fetch(array($msguid), $type, $foldername);
- $this->objects[$msguid] = $result[0];
- }
- }
-
- return $this->objects[$msguid];
- }
-
-
- /**
- * Insert/Update a cache entry
- *
- * @param string Related IMAP message UID
- * @param mixed Hash array with object properties to save or false to delete the cache entry
- * @param string IMAP folder name the entry relates to
- */
- public function set($msguid, $object, $foldername = null)
- {
- // delegate to another cache instance
- if ($foldername && $foldername != $this->folder->name) {
- kolab_storage::get_folder($foldername)->cache->set($msguid, $object);
- return;
- }
-
- // write to cache
- if ($this->ready) {
- // remove old entry
- $this->db->cache->remove(array('resource' => $this->resource_uri, 'msguid' => $msguid));
-
- // write new object data if not false (wich means deleted)
- if ($object) {
- try {
- $this->db->cache->insert($this->_serialize($object, $msguid));
- }
- catch (Exception $e) {
- rcmail::raise_error(array(
- 'code' => 900, 'type' => 'php',
- 'message' => "Failed to write to mongodb cache: " . $e->getMessage(),
- ), true);
- }
- }
- }
-
- // keep a copy in memory for fast access
- $this->objects[$msguid] = $object;
-
- if ($object)
- $this->uid2msg[$object['uid']] = $msguid;
- }
-
- /**
- * Move an existing cache entry to a new resource
- *
- * @param string Entry's IMAP message UID
- * @param string Entry's Object UID
- * @param string Target IMAP folder to move it to
- */
- public function move($msguid, $objuid, $target_folder)
- {
- $target = kolab_storage::get_folder($target_folder);
-
- // resolve new message UID in target folder
- if ($new_msguid = $target->cache->uid2msguid($objuid)) {
-/*
- $this->db->query(
- "UPDATE kolab_cache SET resource=?, msguid=? ".
- "WHERE resource=? AND msguid=? AND type<>?",
- $target->get_resource_uri(),
- $new_msguid,
- $this->resource_uri,
- $msguid,
- 'lock'
- );
-*/
- }
- else {
- // just clear cache entry
- $this->set($msguid, false);
- }
-
- unset($this->uid2msg[$uid]);
- }
-
-
- /**
- * Remove all objects from local cache
- */
- public function purge($type = null)
- {
- return $this->db->cache->remove(array(), array('safe' => true));
- }
-
-
- /**
- * Select Kolab objects filtered by the given query
- *
- * @param array Pseudo-SQL query as list of filter parameter triplets
- * triplet: array('<colname>', '<comparator>', '<value>')
- * @return array List of Kolab data objects (each represented as hash array)
- */
- public function select($query = array())
- {
- $result = array();
-
- // read from local cache DB (assume it to be synchronized)
- if ($this->ready) {
- $cursor = $this->db->cache->find(array('resource' => $this->resource_uri) + $this->_mongo_filter($query));
- foreach ($cursor as $doc) {
- if ($object = $this->_unserialize($doc))
- $result[] = $object;
- }
- }
- else {
- // extract object type from query parameter
- $filter = $this->_query2assoc($query);
-
- // use 'list' for folder's default objects
- if ($filter['type'] == $this->type) {
- $index = $this->index;
- }
- else { // search by object type
- $search = 'UNDELETED HEADER X-Kolab-Type ' . kolab_storage_folder::KTYPE_PREFIX . $filter['type'];
- $index = $this->imap->search_once($this->folder->name, $search)->get();
- }
-
- // fetch all messages in $index from IMAP
- $result = $this->_fetch($index, $filter['type']);
-
- // TODO: post-filter result according to query
- }
-
- return $result;
- }
-
-
- /**
- * Get number of objects mathing the given query
- *
- * @param array $query Pseudo-SQL query as list of filter parameter triplets
- * @return integer The number of objects of the given type
- */
- public function count($query = array())
- {
- $count = 0;
-
- // cache is in sync, we can count records in local DB
- if ($this->synched) {
- $cursor = $this->db->cache->find(array('resource' => $this->resource_uri) + $this->_mongo_filter($query));
- $count = $cursor->valid() ? $cursor->count() : 0;
- }
- else {
- // search IMAP by object type
- $filter = $this->_query2assoc($query);
- $ctype = kolab_storage_folder::KTYPE_PREFIX . $filter['type'];
- $index = $this->imap->search_once($this->folder->name, 'UNDELETED HEADER X-Kolab-Type ' . $ctype);
- $count = $index->count();
- }
-
- return $count;
- }
-
- /**
- * Helper method to convert the pseudo-SQL query into a valid mongodb filter
- */
- private function _mongo_filter($query)
- {
- $filters = array();
- foreach ($query as $param) {
- $filter = array();
- if ($param[1] == '=' && is_array($param[2])) {
- $filter[$param[0]] = array('$in' => $param[2]);
- $filters[] = $filter;
- }
- else if ($param[1] == '=') {
- $filters[] = array($param[0] => $param[2]);
- }
- else if ($param[1] == 'LIKE' || $param[1] == '~') {
- $filter[$param[0]] = array('$regex' => preg_quote($param[2]), '$options' => 'i');
- $filters[] = $filter;
- }
- else if ($param[1] == '!~' || $param[1] == '!LIKE') {
- $filter[$param[0]] = array('$not' => '/' . preg_quote($param[2]) . '/i');
- $filters[] = $filter;
- }
- else {
- $op = '';
- switch ($param[1]) {
- case '>': $op = '$gt'; break;
- case '>=': $op = '$gte'; break;
- case '<': $op = '$lt'; break;
- case '<=': $op = '$lte'; break;
- case '!=':
- case '<>': $op = '$gte'; break;
- }
- if ($op) {
- $filter[$param[0]] = array($op => $param[2]);
- $filters[] = $filter;
- }
- }
- }
-
- return array('$and' => $filters);
- }
-
- /**
- * Helper method to convert the given pseudo-query triplets into
- * an associative filter array with 'equals' values only
- */
- private function _query2assoc($query)
- {
- // extract object type from query parameter
- $filter = array();
- foreach ($query as $param) {
- if ($param[1] == '=')
- $filter[$param[0]] = $param[2];
- }
- return $filter;
- }
-
- /**
- * Fetch messages from IMAP
- *
- * @param array List of message UIDs to fetch
- * @return array List of parsed Kolab objects
- */
- private function _fetch($index, $type = null, $folder = null)
- {
- $results = array();
- foreach ((array)$index as $msguid) {
- if ($object = $this->folder->read_object($msguid, $type, $folder)) {
- $results[] = $object;
- $this->set($msguid, $object);
- }
- }
-
- return $results;
- }
-
-
- /**
- * Helper method to convert the given Kolab object into a dataset to be written to cache
- */
- private function _serialize($object, $msguid)
- {
- $bincols = array_flip($this->binary_cols);
- $doc = array(
- 'resource' => $this->resource_uri,
- 'type' => $object['_type'] ? $object['_type'] : $this->folder->type,
- 'msguid' => $msguid,
- 'uid' => $object['uid'],
- 'xml' => '',
- 'tags' => array(),
- 'words' => array(),
- 'objcols' => array(),
- );
-
- // set type specific values
- if ($this->folder->type == 'event') {
- // database runs in server's timezone so using date() is what we want
- $doc['dtstart'] = date('Y-m-d H:i:s', is_object($object['start']) ? $object['start']->format('U') : $object['start']);
- $doc['dtend'] = date('Y-m-d H:i:s', is_object($object['end']) ? $object['end']->format('U') : $object['end']);
-
- // extend date range for recurring events
- if ($object['recurrence']) {
- $doc['dtend'] = date('Y-m-d H:i:s', $object['recurrence']['UNTIL'] ?: strtotime('now + 2 years'));
- }
- }
-
- if ($object['_formatobj']) {
- $doc['xml'] = preg_replace('!(</?[a-z0-9:-]+>)[\n\r\t\s]+!ms', '$1', (string)$object['_formatobj']->write());
- $doc['tags'] = $object['_formatobj']->get_tags();
- $doc['words'] = $object['_formatobj']->get_words();
- }
-
- // extract object data
- $data = array();
- foreach ($object as $key => $val) {
- if ($val === "" || $val === null) {
- // skip empty properties
- continue;
- }
- if (isset($bincols[$key])) {
- $data[$key] = base64_encode($val);
- }
- else if (is_object($val)) {
- if (is_a($val, 'DateTime')) {
- $data[$key] = array('_class' => 'DateTime', 'date' => $val->format('Y-m-d H:i:s'), 'timezone' => $val->getTimezone()->getName());
- $doc['objcols'][] = $key;
- }
- }
- else if ($key[0] != '_') {
- $data[$key] = $val;
- }
- else if ($key == '_attachments') {
- foreach ($val as $k => $att) {
- unset($att['content'], $att['path']);
- if ($att['id'])
- $data[$key][$k] = $att;
- }
- }
- }
-
- $doc['data'] = $data;
- return $doc;
- }
-
- /**
- * Helper method to turn stored cache data into a valid storage object
- */
- private function _unserialize($doc)
- {
- $object = $doc['data'];
-
- // decode binary properties
- foreach ($this->binary_cols as $key) {
- if (!empty($object[$key]))
- $object[$key] = base64_decode($object[$key]);
- }
-
- // restore serialized objects
- foreach ((array)$doc['objcols'] as $key) {
- switch ($object[$key]['_class']) {
- case 'DateTime':
- $val = new DateTime($object[$key]['date'], new DateTimeZone($object[$key]['timezone']));
- $object[$key] = $val;
- break;
- }
- }
-
- // add meta data
- $object['_type'] = $doc['type'];
- $object['_msguid'] = $doc['msguid'];
- $object['_mailbox'] = $this->folder->name;
- $object['_formatobj'] = kolab_format::factory($doc['type'], $doc['xml']);
-
- return $object;
- }
-
- /**
- * Check lock record for this folder and wait if locked or set lock
- */
- private function _sync_lock()
- {
- if (!$this->ready)
- return;
-
- $this->synclock = true;
- $lock = $this->db->locks->findOne(array('resource' => $this->resource_uri));
-
- // create lock record if not exists
- if (!$lock) {
- $this->db->locks->insert(array('resource' => $this->resource_uri, 'created' => time()));
- }
- // wait if locked (expire locks after 10 minutes)
- else if ((time() - $lock['created']) < 600) {
- usleep(500000);
- return $this->_sync_lock();
- }
- // set lock
- else {
- $lock['created'] = time();
- $this->db->locks->update(array('_id' => $lock['_id']), $lock, array('safe' => true));
- }
- }
-
- /**
- * Remove lock for this folder
- */
- public function _sync_unlock()
- {
- if (!$this->ready || !$this->synclock)
- return;
-
- $this->db->locks->remove(array('resource' => $this->resource_uri));
- }
-
- /**
- * Resolve an object UID into an IMAP message UID
- *
- * @param string Kolab object UID
- * @param boolean Include deleted objects
- * @return int The resolved IMAP message UID
- */
- public function uid2msguid($uid, $deleted = false)
- {
- if (!isset($this->uid2msg[$uid])) {
- // use IMAP SEARCH to get the right message
- $index = $this->imap->search_once($this->folder->name, ($deleted ? '' : 'UNDELETED ') . 'HEADER SUBJECT ' . $uid);
- $results = $index->get();
- $this->uid2msg[$uid] = $results[0];
- }
-
- return $this->uid2msg[$uid];
- }
-
-}
diff --git a/lib/plugins/libkolab/lib/kolab_storage_cache_note.php b/lib/plugins/libkolab/lib/kolab_storage_cache_note.php
deleted file mode 100644
index 8546927..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_cache_note.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-/**
- * Kolab storage cache class for note objects
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_cache_note extends kolab_storage_cache
-{
-
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/lib/kolab_storage_cache_task.php b/lib/plugins/libkolab/lib/kolab_storage_cache_task.php
deleted file mode 100644
index 7bf5c79..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_cache_task.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-/**
- * Kolab storage cache class for task objects
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_cache_task extends kolab_storage_cache
-{
- protected $extra_cols = array('dtstart','dtend');
-
- /**
- * Helper method to convert the given Kolab object into a dataset to be written to cache
- *
- * @override
- */
- protected function _serialize($object)
- {
- $sql_data = parent::_serialize($object) + array('dtstart' => null, 'dtend' => null);
-
- if ($object['start'])
- $sql_data['dtstart'] = is_object($object['start']) ? $object['start']->format(self::DB_DATE_FORMAT) : date(self::DB_DATE_FORMAT, $object['start']);
- if ($object['due'])
- $sql_data['dtend'] = is_object($object['due']) ? $object['due']->format(self::DB_DATE_FORMAT) : date(self::DB_DATE_FORMAT, $object['due']);
-
- return $sql_data;
- }
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/lib/kolab_storage_config.php b/lib/plugins/libkolab/lib/kolab_storage_config.php
deleted file mode 100644
index 036b827..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_config.php
+++ /dev/null
@@ -1,866 +0,0 @@
-<?php
-
-/**
- * Kolab storage class providing access to configuration objects on a Kolab server.
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- * @author Aleksander Machniak <machniak@kolabsys.com>
- *
- * Copyright (C) 2012-2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_config
-{
- const FOLDER_TYPE = 'configuration';
-
-
- /**
- * Singleton instace of kolab_storage_config
- *
- * @var kolab_storage_config
- */
- static protected $instance;
-
- private $folders;
- private $default;
- private $enabled;
-
-
- /**
- * This implements the 'singleton' design pattern
- *
- * @return kolab_storage_config The one and only instance
- */
- static function get_instance()
- {
- if (!self::$instance) {
- self::$instance = new kolab_storage_config();
- }
-
- return self::$instance;
- }
-
- /**
- * Private constructor (finds default configuration folder as a config source)
- */
- private function __construct()
- {
- // get all configuration folders
- $this->folders = kolab_storage::get_folders(self::FOLDER_TYPE, false);
-
- foreach ($this->folders as $folder) {
- if ($folder->default) {
- $this->default = $folder;
- break;
- }
- }
-
- // if no folder is set as default, choose the first one
- if (!$this->default) {
- $this->default = reset($this->folders);
- }
-
- // attempt to create a default folder if it does not exist
- if (!$this->default) {
- $folder_name = 'Configuration';
- $folder_type = self::FOLDER_TYPE . '.default';
-
- if (kolab_storage::folder_create($folder_name, $folder_type, true)) {
- $this->default = new kolab_storage_folder($folder_name, $folder_type);
- }
- }
-
- // check if configuration folder exist
- if ($this->default && $this->default->name) {
- $this->enabled = true;
- }
- }
-
- /**
- * Check wether any configuration storage (folder) exists
- *
- * @return bool
- */
- public function is_enabled()
- {
- return $this->enabled;
- }
-
- /**
- * Get configuration objects
- *
- * @param array $filter Search filter
- * @param bool $default Enable to get objects only from default folder
- * @param int $limit Max. number of records (per-folder)
- *
- * @return array List of objects
- */
- public function get_objects($filter = array(), $default = false, $limit = 0)
- {
- $list = array();
-
- foreach ($this->folders as $folder) {
- // we only want to read from default folder
- if ($default && !$folder->default) {
- continue;
- }
-
- // for better performance it's good to assume max. number of records
- if ($limit) {
- $folder->set_order_and_limit(null, $limit);
- }
-
- foreach ($folder->select($filter) as $object) {
- unset($object['_formatobj']);
- $list[] = $object;
- }
- }
-
- return $list;
- }
-
- /**
- * Get configuration object
- *
- * @param string $uid Object UID
- * @param bool $default Enable to get objects only from default folder
- *
- * @return array Object data
- */
- public function get_object($uid, $default = false)
- {
- foreach ($this->folders as $folder) {
- // we only want to read from default folder
- if ($default && !$folder->default) {
- continue;
- }
-
- if ($object = $folder->get_object($uid)) {
- return $object;
- }
- }
- }
-
- /**
- * Create/update configuration object
- *
- * @param array $object Object data
- * @param string $type Object type
- *
- * @return bool True on success, False on failure
- */
- public function save(&$object, $type)
- {
- if (!$this->enabled) {
- return false;
- }
-
- $folder = $this->find_folder($object);
-
- if ($type) {
- $object['type'] = $type;
- }
-
- return $folder->save($object, self::FOLDER_TYPE . '.' . $object['type'], $object['uid']);
- }
-
- /**
- * Remove configuration object
- *
- * @param string $uid Object UID
- *
- * @return bool True on success, False on failure
- */
- public function delete($uid)
- {
- if (!$this->enabled) {
- return false;
- }
-
- // fetch the object to find folder
- $object = $this->get_object($uid);
-
- if (!$object) {
- return false;
- }
-
- $folder = $this->find_folder($object);
-
- return $folder->delete($uid);
- }
-
- /**
- * Find folder
- */
- public function find_folder($object = array())
- {
- // find folder object
- if ($object['_mailbox']) {
- foreach ($this->folders as $folder) {
- if ($folder->name == $object['_mailbox']) {
- break;
- }
- }
- }
- else {
- $folder = $this->default;
- }
-
- return $folder;
- }
-
- /**
- * Builds relation member URI
- *
- * @param string|array Object UUID or Message folder, UID, Search headers (Message-Id, Date)
- *
- * @return string $url Member URI
- */
- public static function build_member_url($params)
- {
- // param is object UUID
- if (is_string($params) && !empty($params)) {
- return 'urn:uuid:' . $params;
- }
-
- if (empty($params) || !strlen($params['folder'])) {
- return null;
- }
-
- $rcube = rcube::get_instance();
- $storage = $rcube->get_storage();
-
- // modify folder spec. according to namespace
- $folder = $params['folder'];
- $ns = $storage->folder_namespace($folder);
-
- if ($ns == 'shared') {
- // Note: this assumes there's only one shared namespace root
- if ($ns = $storage->get_namespace('shared')) {
- if ($prefix = $ns[0][0]) {
- $folder = 'shared' . substr($folder, strlen($prefix));
- }
- }
- }
- else {
- if ($ns == 'other') {
- // Note: this assumes there's only one other users namespace root
- if ($ns = $storage->get_namespace('shared')) {
- if ($prefix = $ns[0][0]) {
- $folder = 'user' . substr($folder, strlen($prefix));
- }
- }
- }
- else {
- $folder = 'user' . '/' . $rcube->get_user_name() . '/' . $folder;
- }
- }
-
- $folder = implode('/', array_map('rawurlencode', explode('/', $folder)));
-
- // build URI
- $url = 'imap:///' . $folder;
-
- // UID is optional here because sometimes we want
- // to build just a member uri prefix
- if ($params['uid']) {
- $url .= '/' . $params['uid'];
- }
-
- unset($params['folder']);
- unset($params['uid']);
-
- if (!empty($params)) {
- $url .= '?' . http_build_query($params, '', '&');
- }
-
- return $url;
- }
-
- /**
- * Parses relation member string
- *
- * @param string $url Member URI
- *
- * @return array Message folder, UID, Search headers (Message-Id, Date)
- */
- public static function parse_member_url($url)
- {
- // Look for IMAP URI:
- // imap:///(user/username@domain|shared)/<folder>/<UID>?<search_params>
- if (strpos($url, 'imap:///') === 0) {
- $rcube = rcube::get_instance();
- $storage = $rcube->get_storage();
-
- // parse_url does not work with imap:/// prefix
- $url = parse_url(substr($url, 8));
- $path = explode('/', $url['path']);
- parse_str($url['query'], $params);
-
- $uid = array_pop($path);
- $ns = array_shift($path);
- $path = array_map('rawurldecode', $path);
-
- // resolve folder name
- if ($ns == 'shared') {
- $folder = implode('/', $path);
- // Note: this assumes there's only one shared namespace root
- if ($ns = $storage->get_namespace('shared')) {
- if ($prefix = $ns[0][0]) {
- $folder = $prefix . '/' . $folder;
- }
- }
- }
- else if ($ns == 'user') {
- $username = array_shift($path);
- $folder = implode('/', $path);
-
- if ($username != $rcube->get_user_name()) {
- // Note: this assumes there's only one other users namespace root
- if ($ns = $storage->get_namespace('other')) {
- if ($prefix = $ns[0][0]) {
- $folder = $prefix . '/' . $username . '/' . $folder;
- }
- }
- }
- else if (!strlen($folder)) {
- $folder = 'INBOX';
- }
- }
- else {
- return;
- }
-
- return array(
- 'folder' => $folder,
- 'uid' => $uid,
- 'params' => $params,
- );
- }
-
- return false;
- }
-
- /**
- * Build array of member URIs from set of messages
- *
- * @param string $folder Folder name
- * @param array $messages Array of rcube_message objects
- *
- * @return array List of members (IMAP URIs)
- */
- public static function build_members($folder, $messages)
- {
- $members = array();
-
- foreach ((array) $messages as $msg) {
- $params = array(
- 'folder' => $folder,
- 'uid' => $msg->uid,
- );
-
- // add search parameters:
- // we don't want to build "invalid" searches e.g. that
- // will return false positives (more or wrong messages)
- if (($messageid = $msg->get('message-id', false)) && ($date = $msg->get('date', false))) {
- $params['message-id'] = $messageid;
- $params['date'] = $date;
-
- if ($subject = $msg->get('subject', false)) {
- $params['subject'] = substr($subject, 0, 256);
- }
- }
-
- $members[] = self::build_member_url($params);
- }
-
- return $members;
- }
-
- /**
- * Resolve/validate/update members (which are IMAP URIs) of relation object.
- *
- * @param array $tag Tag object
- * @param bool $force Force members list update
- *
- * @return array Folder/UIDs list
- */
- public static function resolve_members(&$tag, $force = true)
- {
- $result = array();
-
- foreach ((array) $tag['members'] as $member) {
- // IMAP URI members
- if ($url = self::parse_member_url($member)) {
- $folder = $url['folder'];
-
- if (!$force) {
- $result[$folder][] = $url['uid'];
- }
- else {
- $result[$folder]['uid'][] = $url['uid'];
- $result[$folder]['params'][] = $url['params'];
- $result[$folder]['member'][] = $member;
- }
- }
- }
-
- if (empty($result) || !$force) {
- return $result;
- }
-
- $rcube = rcube::get_instance();
- $storage = $rcube->get_storage();
- $search = array();
- $missing = array();
-
- // first we search messages by Folder+UID
- foreach ($result as $folder => $data) {
- // @FIXME: maybe better use index() which is cached?
- // @TODO: consider skip_deleted option
- $index = $storage->search_once($folder, 'UID ' . rcube_imap_generic::compressMessageSet($data['uid']));
- $uids = $index->get();
-
- // messages that were not found need to be searched by search parameters
- $not_found = array_diff($data['uid'], $uids);
- if (!empty($not_found)) {
- foreach ($not_found as $uid) {
- $idx = array_search($uid, $data['uid']);
-
- if ($p = $data['params'][$idx]) {
- $search[] = $p;
- }
-
- $missing[] = $result[$folder]['member'][$idx];
-
- unset($result[$folder]['uid'][$idx]);
- unset($result[$folder]['params'][$idx]);
- unset($result[$folder]['member'][$idx]);
- }
- }
-
- $result[$folder] = $uids;
- }
-
- // search in all subscribed mail folders using search parameters
- if (!empty($search)) {
- // remove not found members from the members list
- $tag['members'] = array_diff($tag['members'], $missing);
-
- // get subscribed folders
- $folders = $storage->list_folders_subscribed('', '*', 'mail', null, true);
-
- // @TODO: do this search in chunks (for e.g. 10 messages)?
- $search_str = '';
-
- foreach ($search as $p) {
- $search_params = array();
- foreach ($p as $key => $val) {
- $key = strtoupper($key);
- // don't search by subject, we don't want false-positives
- if ($key != 'SUBJECT') {
- $search_params[] = 'HEADER ' . $key . ' ' . rcube_imap_generic::escape($val);
- }
- }
-
- $search_str .= ' (' . implode(' ', $search_params) . ')';
- }
-
- $search_str = trim(str_repeat(' OR', count($search)-1) . $search_str);
-
- // search
- $search = $storage->search_once($folders, $search_str);
-
- // handle search result
- $folders = (array) $search->get_parameters('MAILBOX');
-
- foreach ($folders as $folder) {
- $set = $search->get_set($folder);
- $uids = $set->get();
-
- if (!empty($uids)) {
- $msgs = $storage->fetch_headers($folder, $uids, false);
- $members = self::build_members($folder, $msgs);
-
- // merge new members into the tag members list
- $tag['members'] = array_merge($tag['members'], $members);
-
- // add UIDs into the result
- $result[$folder] = array_unique(array_merge((array)$result[$folder], $uids));
- }
- }
-
- // update tag object with new members list
- $tag['members'] = array_unique($tag['members']);
- kolab_storage_config::get_instance()->save($tag, 'relation', false);
- }
-
- return $result;
- }
-
- /**
- * Assign tags to kolab objects
- *
- * @param array $records List of kolab objects
- *
- * @return array List of tags
- */
- public function apply_tags(&$records)
- {
- // first convert categories into tags
- foreach ($records as $i => $rec) {
- if (!empty($rec['categories'])) {
- $folder = new kolab_storage_folder($rec['_mailbox']);
- if ($object = $folder->get_object($rec['uid'])) {
- $tags = $rec['categories'];
-
- unset($object['categories']);
- unset($records[$i]['categories']);
-
- $this->save_tags($rec['uid'], $tags);
- $folder->save($object, $rec['_type'], $rec['uid']);
- }
- }
- }
-
- $tags = array();
-
- // assign tags to objects
- foreach ($this->get_tags() as $tag) {
- foreach ($records as $idx => $rec) {
- $uid = self::build_member_url($rec['uid']);
- if (in_array($uid, (array) $tag['members'])) {
- $records[$idx]['tags'][] = $tag['name'];
- }
- }
-
- $tags[] = $tag['name'];
- }
-
- $tags = array_unique($tags);
-
- return $tags;
- }
-
- /**
- * Update object tags
- *
- * @param string $uid Kolab object UID
- * @param array $tags List of tag names
- */
- public function save_tags($uid, $tags)
- {
- $url = self::build_member_url($uid);
- $relations = $this->get_tags();
-
- foreach ($relations as $idx => $relation) {
- $selected = !empty($tags) && in_array($relation['name'], $tags);
- $found = !empty($relation['members']) && in_array($url, $relation['members']);
- $update = false;
-
- // remove member from the relation
- if ($found && !$selected) {
- $relation['members'] = array_diff($relation['members'], (array) $url);
- $update = true;
- }
- // add member to the relation
- else if (!$found && $selected) {
- $relation['members'][] = $url;
- $update = true;
- }
-
- if ($update) {
- if ($this->save($relation, 'relation')) {
- $this->tags[$idx] = $relation; // update in-memory cache
- }
- }
-
- if ($selected) {
- $tags = array_diff($tags, (array)$relation['name']);
- }
- }
-
- // create new relations
- if (!empty($tags)) {
- foreach ($tags as $tag) {
- $relation = array(
- 'name' => $tag,
- 'members' => (array) $url,
- 'category' => 'tag',
- );
-
- if ($this->save($relation, 'relation')) {
- $this->tags[] = $relation; // update in-memory cache
- }
- }
- }
- }
-
- /**
- * Get tags (all or referring to specified object)
- *
- * @param string $uid Optional object UID
- *
- * @return array List of Relation objects
- */
- public function get_tags($uid = '*')
- {
- if (!isset($this->tags)) {
- $default = true;
- $filter = array(
- array('type', '=', 'relation'),
- array('category', '=', 'tag')
- );
-
- // use faster method
- if ($uid && $uid != '*') {
- $filter[] = array('member', '=', $uid);
- $tags = $this->get_objects($filter, $default);
- }
- else {
- $this->tags = $tags = $this->get_objects($filter, $default);
- }
- }
- else {
- $tags = $this->tags;
- }
-
- if ($uid === '*') {
- return $tags;
- }
-
- $result = array();
- $search = self::build_member_url($uid);
-
- foreach ($tags as $tag) {
- if (in_array($search, (array) $tag['members'])) {
- $result[] = $tag;
- }
- }
-
- return $result;
- }
-
- /**
- * Find objects linked with the given groupware object through a relation
- *
- * @param string Object UUID
- * @param array List of related URIs
- */
- public function get_object_links($uid)
- {
- $links = array();
- $object_uri = self::build_member_url($uid);
-
- foreach ($this->get_relations_for_member($uid) as $relation) {
- if (in_array($object_uri, (array) $relation['members'])) {
- // make relation members up-to-date
- kolab_storage_config::resolve_members($relation);
-
- foreach ($relation['members'] as $member) {
- if ($member != $object_uri) {
- $links[] = $member;
- }
- }
- }
- }
-
- return array_unique($links);
- }
-
- /**
- *
- */
- public function save_object_links($uid, $links, $remove = array())
- {
- $object_uri = self::build_member_url($uid);
- $relations = $this->get_relations_for_member($uid);
- $done = false;
-
- foreach ($relations as $relation) {
- // make relation members up-to-date
- kolab_storage_config::resolve_members($relation);
-
- // remove and add links
- $members = array_diff($relation['members'], (array)$remove);
- $members = array_unique(array_merge($members, $links));
-
- // make sure the object_uri is still a member
- if (!in_array($object_uri, $members)) {
- $members[$object_uri];
- }
-
- // remove relation if no other members remain
- if (count($members) <= 1) {
- $done = $this->delete($relation['uid']);
- }
- // update relation object if members changed
- else if (count(array_diff($members, $relation['members'])) || count(array_diff($relation['members'], $members))) {
- $relation['members'] = $members;
- $done = $this->save($relation, 'relation');
- $links = array();
- }
- // no changes, we're happy
- else {
- $done = true;
- $links = array();
- }
- }
-
- // create a new relation
- if (!$done && !empty($links)) {
- $relation = array(
- 'members' => array_merge($links, array($object_uri)),
- 'category' => 'generic',
- );
-
- $ret = $this->save($relation, 'relation');
- }
-
- return $ret;
- }
-
- /**
- * Find relation objects referring to specified note
- */
- public function get_relations_for_member($uid, $reltype = 'generic')
- {
- $default = true;
- $filter = array(
- array('type', '=', 'relation'),
- array('category', '=', $reltype),
- array('member', '=', $uid),
- );
-
- return $this->get_objects($filter, $default, 100);
- }
-
- /**
- * Find kolab objects assigned to specified e-mail message
- *
- * @param rcube_message $message E-mail message
- * @param string $folder Folder name
- * @param string $type Result objects type
- *
- * @return array List of kolab objects
- */
- public function get_message_relations($message, $folder, $type)
- {
- static $_cache = array();
-
- $result = array();
- $uids = array();
- $default = true;
- $uri = self::get_message_uri($message, $folder);
- $filter = array(
- array('type', '=', 'relation'),
- array('category', '=', 'generic'),
- );
-
- // query by message-id
- $member_id = $message->get('message-id', false);
- if (empty($member_id)) {
- // derive message identifier from URI
- $member_id = md5($uri);
- }
- $filter[] = array('member', '=', $member_id);
-
- if (!isset($_cache[$uri])) {
- // get UIDs of related groupware objects
- foreach ($this->get_objects($filter, $default) as $relation) {
- // we don't need to update members if the URI is found
- if (!in_array($uri, $relation['members'])) {
- // update members...
- $messages = kolab_storage_config::resolve_members($relation);
- // ...and check again
- if (empty($messages[$folder]) || !in_array($message->uid, $messages[$folder])) {
- continue;
- }
- }
-
- // find groupware object UID(s)
- foreach ($relation['members'] as $member) {
- if (strpos($member, 'urn:uuid:') === 0) {
- $uids[] = substr($member, 9);
- }
- }
- }
-
- // remember this lookup
- $_cache[$uri] = $uids;
- }
- else {
- $uids = $_cache[$uri];
- }
-
- // get kolab objects of specified type
- if (!empty($uids)) {
- $query = array(array('uid', '=', array_unique($uids)));
- $result = kolab_storage::select($query, $type);
- }
-
- return $result;
- }
-
- /**
- * Build a URI representing the given message reference
- */
- public static function get_message_uri($headers, $folder)
- {
- $params = array(
- 'folder' => $headers->folder ?: $folder,
- 'uid' => $headers->uid,
- );
-
- if (($messageid = $headers->get('message-id', false)) && ($date = $headers->get('date', false))) {
- $params['message-id'] = $messageid;
- $params['date'] = $date;
-
- if ($subject = $headers->get('subject')) {
- $params['subject'] = $subject;
- }
- }
-
- return self::build_member_url($params);
- }
-
- /**
- * Resolve the email message reference from the given URI
- */
- public function get_message_reference($uri, $rel = null)
- {
- if ($linkref = self::parse_member_url($uri)) {
- $linkref['subject'] = $linkref['params']['subject'];
- $linkref['uri'] = $uri;
-
- $rcmail = rcube::get_instance();
- if (method_exists($rcmail, 'url')) {
- $linkref['mailurl'] = $rcmail->url(array(
- 'task' => 'mail',
- 'action' => 'show',
- 'mbox' => $linkref['folder'],
- 'uid' => $linkref['uid'],
- 'rel' => $rel,
- ));
- }
-
- unset($linkref['params']);
- }
-
- return $linkref;
- }
-}
diff --git a/lib/plugins/libkolab/lib/kolab_storage_dataset.php b/lib/plugins/libkolab/lib/kolab_storage_dataset.php
deleted file mode 100644
index 9ddf3f9..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_dataset.php
+++ /dev/null
@@ -1,154 +0,0 @@
-<?php
-
-/**
- * Dataset class providing the results of a select operation on a kolab_storage_folder.
- *
- * Can be used as a normal array as well as an iterator in foreach() loops.
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class kolab_storage_dataset implements Iterator, ArrayAccess, Countable
-{
- private $cache; // kolab_storage_cache instance to use for fetching data
- private $memlimit = 0;
- private $buffer = false;
- private $index = array();
- private $data = array();
- private $iteratorkey = 0;
- private $error = null;
-
- /**
- * Default constructor
- *
- * @param object kolab_storage_cache instance to be used for fetching objects upon access
- */
- public function __construct($cache)
- {
- $this->cache = $cache;
-
- // enable in-memory buffering up until 1/5 of the available memory
- if (function_exists('memory_get_usage')) {
- $this->memlimit = parse_bytes(ini_get('memory_limit')) / 5;
- $this->buffer = true;
- }
- }
-
- /**
- * Return error state
- */
- public function is_error()
- {
- return !empty($this->error);
- }
-
- /**
- * Set error state
- */
- public function set_error($err)
- {
- $this->error = $err;
- }
-
-
- /*** Implement PHP Countable interface ***/
-
- public function count()
- {
- return count($this->index);
- }
-
-
- /*** Implement PHP ArrayAccess interface ***/
-
- public function offsetSet($offset, $value)
- {
- $uid = $value['_msguid'];
-
- if (is_null($offset)) {
- $offset = count($this->index);
- $this->index[] = $uid;
- }
- else {
- $this->index[$offset] = $uid;
- }
-
- // keep full payload data in memory if possible
- if ($this->memlimit && $this->buffer && isset($value['_mailbox'])) {
- $this->data[$offset] = $value;
-
- // check memory usage and stop buffering
- if ($offset % 10 == 0) {
- $this->buffer = memory_get_usage() < $this->memlimit;
- }
- }
- }
-
- public function offsetExists($offset)
- {
- return isset($this->index[$offset]);
- }
-
- public function offsetUnset($offset)
- {
- unset($this->index[$offset]);
- }
-
- public function offsetGet($offset)
- {
- if (isset($this->data[$offset])) {
- return $this->data[$offset];
- }
- else if ($msguid = $this->index[$offset]) {
- return $this->cache->get($msguid);
- }
-
- return null;
- }
-
-
- /*** Implement PHP Iterator interface ***/
-
- public function current()
- {
- return $this->offsetGet($this->iteratorkey);
- }
-
- public function key()
- {
- return $this->iteratorkey;
- }
-
- public function next()
- {
- $this->iteratorkey++;
- return $this->valid();
- }
-
- public function rewind()
- {
- $this->iteratorkey = 0;
- }
-
- public function valid()
- {
- return !empty($this->index[$this->iteratorkey]);
- }
-
-}
diff --git a/lib/plugins/libkolab/lib/kolab_storage_folder.php b/lib/plugins/libkolab/lib/kolab_storage_folder.php
deleted file mode 100644
index ab3c63f..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_folder.php
+++ /dev/null
@@ -1,1166 +0,0 @@
-<?php
-
-/**
- * The kolab_storage_folder class represents an IMAP folder on the Kolab server.
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- * @author Aleksander Machniak <machniak@kolabsys.com>
- *
- * Copyright (C) 2012-2013, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-class kolab_storage_folder extends kolab_storage_folder_api
-{
- /**
- * The kolab_storage_cache instance for caching operations
- * @var object
- */
- public $cache;
-
- /**
- * Indicate validity status
- * @var boolean
- */
- public $valid = false;
-
- protected $error = 0;
-
- protected $resource_uri;
-
-
- /**
- * Default constructor
- *
- * @param string The folder name/path
- * @param string Expected folder type
- */
- function __construct($name, $type = null, $type_annotation = null)
- {
- parent::__construct($name);
- $this->imap->set_options(array('skip_deleted' => true));
- $this->set_folder($name, $type, $type_annotation);
- }
-
-
- /**
- * Set the IMAP folder this instance connects to
- *
- * @param string The folder name/path
- * @param string Expected folder type
- * @param string Optional folder type if known
- */
- public function set_folder($name, $type = null, $type_annotation = null)
- {
- if (empty($type_annotation)) {
- $type_annotation = kolab_storage::folder_type($name);
- }
-
- $oldtype = $this->type;
- list($this->type, $suffix) = explode('.', $type_annotation);
- $this->default = $suffix == 'default';
- $this->subtype = $this->default ? '' : $suffix;
- $this->name = $name;
- $this->id = kolab_storage::folder_id($name);
- $this->valid = !empty($this->type) && $this->type != 'mail' && (!$type || $this->type == $type);
-
- if (!$this->valid) {
- $this->error = $this->imap->get_error_code() < 0 ? kolab_storage::ERROR_IMAP_CONN : kolab_storage::ERROR_INVALID_FOLDER;
- }
-
- // reset cached object properties
- $this->owner = $this->namespace = $this->resource_uri = $this->info = $this->idata = null;
-
- // get a new cache instance if folder type changed
- if (!$this->cache || $this->type != $oldtype)
- $this->cache = kolab_storage_cache::factory($this);
- else
- $this->cache->set_folder($this);
-
- $this->imap->set_folder($this->name);
- }
-
- /**
- * Returns code of last error
- *
- * @return int Error code
- */
- public function get_error()
- {
- return $this->error ?: $this->cache->get_error();
- }
-
- /**
- * Check IMAP connection error state
- */
- public function check_error()
- {
- if (($err_code = $this->imap->get_error_code()) < 0) {
- $this->error = kolab_storage::ERROR_IMAP_CONN;
- if (($res_code = $this->imap->get_response_code()) !== 0 && in_array($res_code, array(rcube_storage::NOPERM, rcube_storage::READONLY))) {
- $this->error = kolab_storage::ERROR_NO_PERMISSION;
- }
- }
-
- return $this->error;
- }
-
- /**
- * Compose a unique resource URI for this IMAP folder
- */
- public function get_resource_uri()
- {
- if (!empty($this->resource_uri))
- return $this->resource_uri;
-
- // strip namespace prefix from folder name
- $ns = $this->get_namespace();
- $nsdata = $this->imap->get_namespace($ns);
- if (is_array($nsdata[0]) && strlen($nsdata[0][0]) && strpos($this->name, $nsdata[0][0]) === 0) {
- $subpath = substr($this->name, strlen($nsdata[0][0]));
- if ($ns == 'other') {
- list($user, $suffix) = explode($nsdata[0][1], $subpath, 2);
- $subpath = $suffix;
- }
- }
- else {
- $subpath = $this->name;
- }
-
- // compose fully qualified ressource uri for this instance
- $this->resource_uri = 'imap://' . urlencode($this->get_owner(true)) . '@' . $this->imap->options['host'] . '/' . $subpath;
- return $this->resource_uri;
- }
-
- /**
- * Helper method to extract folder UID metadata
- *
- * @return string Folder's UID
- */
- public function get_uid()
- {
- // UID is defined in folder METADATA
- $metakeys = array(kolab_storage::UID_KEY_SHARED, kolab_storage::UID_KEY_PRIVATE, kolab_storage::UID_KEY_CYRUS);
- $metadata = $this->get_metadata($metakeys);
- foreach ($metakeys as $key) {
- if (($uid = $metadata[$key])) {
- return $uid;
- }
- }
-
- // generate a folder UID and set it to IMAP
- $uid = rtrim(chunk_split(md5($this->name . $this->get_owner() . uniqid('-', true)), 12, '-'), '-');
- if ($this->set_uid($uid)) {
- return $uid;
- }
-
- // create hash from folder name if we can't write the UID metadata
- return md5($this->name . $this->get_owner());
- }
-
- /**
- * Helper method to set an UID value to the given IMAP folder instance
- *
- * @param string Folder's UID
- * @return boolean True on succes, False on failure
- */
- public function set_uid($uid)
- {
- if (!($success = $this->set_metadata(array(kolab_storage::UID_KEY_SHARED => $uid)))) {
- $success = $this->set_metadata(array(kolab_storage::UID_KEY_PRIVATE => $uid));
- }
-
- $this->check_error();
- return $success;
- }
-
- /**
- * Compose a folder Etag identifier
- */
- public function get_ctag()
- {
- $fdata = $this->get_imap_data();
- $this->check_error();
- return sprintf('%d-%d-%d', $fdata['UIDVALIDITY'], $fdata['HIGHESTMODSEQ'], $fdata['UIDNEXT']);
- }
-
- /**
- * Check activation status of this folder
- *
- * @return boolean True if enabled, false if not
- */
- public function is_active()
- {
- return kolab_storage::folder_is_active($this->name);
- }
-
- /**
- * Change activation status of this folder
- *
- * @param boolean The desired subscription status: true = active, false = not active
- *
- * @return True on success, false on error
- */
- public function activate($active)
- {
- return $active ? kolab_storage::folder_activate($this->name) : kolab_storage::folder_deactivate($this->name);
- }
-
- /**
- * Check subscription status of this folder
- *
- * @return boolean True if subscribed, false if not
- */
- public function is_subscribed()
- {
- return kolab_storage::folder_is_subscribed($this->name);
- }
-
- /**
- * Change subscription status of this folder
- *
- * @param boolean The desired subscription status: true = subscribed, false = not subscribed
- *
- * @return True on success, false on error
- */
- public function subscribe($subscribed)
- {
- return $subscribed ? kolab_storage::folder_subscribe($this->name) : kolab_storage::folder_unsubscribe($this->name);
- }
-
- /**
- * Get number of objects stored in this folder
- *
- * @param mixed Pseudo-SQL query as list of filter parameter triplets
- * or string with object type (e.g. contact, event, todo, journal, note, configuration)
- * @return integer The number of objects of the given type
- * @see self::select()
- */
- public function count($query = null)
- {
- if (!$this->valid) {
- return 0;
- }
-
- // synchronize cache first
- $this->cache->synchronize();
-
- return $this->cache->count($this->_prepare_query($query));
- }
-
-
- /**
- * List all Kolab objects of the given type
- *
- * @param string $type Object type (e.g. contact, event, todo, journal, note, configuration)
- * @return array List of Kolab data objects (each represented as hash array)
- */
- public function get_objects($type = null)
- {
- if (!$type) $type = $this->type;
-
- if (!$this->valid) {
- return array();
- }
-
- // synchronize caches
- $this->cache->synchronize();
-
- // fetch objects from cache
- return $this->cache->select($this->_prepare_query($type));
- }
-
-
- /**
- * Select *some* Kolab objects matching the given query
- *
- * @param array Pseudo-SQL query as list of filter parameter triplets
- * triplet: array('<colname>', '<comparator>', '<value>')
- * @return array List of Kolab data objects (each represented as hash array)
- */
- public function select($query = array())
- {
- if (!$this->valid) {
- return array();
- }
-
- // check query argument
- if (empty($query)) {
- return $this->get_objects();
- }
-
- // synchronize caches
- $this->cache->synchronize();
-
- // fetch objects from cache
- return $this->cache->select($this->_prepare_query($query));
- }
-
-
- /**
- * Getter for object UIDs only
- *
- * @param array Pseudo-SQL query as list of filter parameter triplets
- * @return array List of Kolab object UIDs
- */
- public function get_uids($query = array())
- {
- if (!$this->valid) {
- return array();
- }
-
- // synchronize caches
- $this->cache->synchronize();
-
- // fetch UIDs from cache
- return $this->cache->select($this->_prepare_query($query), true);
- }
-
- /**
- * Setter for ORDER BY and LIMIT parameters for cache queries
- *
- * @param array List of columns to order by
- * @param integer Limit result set to this length
- * @param integer Offset row
- */
- public function set_order_and_limit($sortcols, $length = null, $offset = 0)
- {
- $this->cache->set_order_by($sortcols);
-
- if ($length !== null) {
- $this->cache->set_limit($length, $offset);
- }
- }
-
- /**
- * Helper method to sanitize query arguments
- */
- private function _prepare_query($query)
- {
- // string equals type query
- // FIXME: should not be called this way!
- if (is_string($query)) {
- return $this->cache->has_type_col() && !empty($query) ? array(array('type','=',$query)) : array();
- }
-
- foreach ((array)$query as $i => $param) {
- if ($param[0] == 'type' && !$this->cache->has_type_col()) {
- unset($query[$i]);
- }
- else if (($param[0] == 'dtstart' || $param[0] == 'dtend' || $param[0] == 'changed')) {
- if (is_object($param[2]) && is_a($param[2], 'DateTime'))
- $param[2] = $param[2]->format('U');
- if (is_numeric($param[2]))
- $query[$i][2] = date('Y-m-d H:i:s', $param[2]);
- }
- }
-
- return $query;
- }
-
-
- /**
- * Getter for a single Kolab object, identified by its UID
- *
- * @param string $uid Object UID
- * @param string $type Object type (e.g. contact, event, todo, journal, note, configuration)
- * Defaults to folder type
- *
- * @return array The Kolab object represented as hash array
- */
- public function get_object($uid, $type = null)
- {
- if (!$this->valid) {
- return false;
- }
-
- // synchronize caches
- $this->cache->synchronize();
-
- $msguid = $this->cache->uid2msguid($uid);
-
- if ($msguid && ($object = $this->cache->get($msguid, $type))) {
- return $object;
- }
-
- return false;
- }
-
-
- /**
- * Fetch a Kolab object attachment which is stored in a separate part
- * of the mail MIME message that represents the Kolab record.
- *
- * @param string Object's UID
- * @param string The attachment's mime number
- * @param string IMAP folder where message is stored;
- * If set, that also implies that the given UID is an IMAP UID
- * @param bool True to print the part content
- * @param resource File pointer to save the message part
- * @param boolean Disables charset conversion
- *
- * @return mixed The attachment content as binary string
- */
- public function get_attachment($uid, $part, $mailbox = null, $print = false, $fp = null, $skip_charset_conv = false)
- {
- if ($this->valid && ($msguid = ($mailbox ? $uid : $this->cache->uid2msguid($uid)))) {
- $this->imap->set_folder($mailbox ? $mailbox : $this->name);
-
- if (substr($part, 0, 2) == 'i:') {
- // attachment data is stored in XML
- if ($object = $this->cache->get($msguid)) {
- // load data from XML (attachment content is not stored in cache)
- if ($object['_formatobj'] && isset($object['_size'])) {
- $object['_attachments'] = array();
- $object['_formatobj']->get_attachments($object);
- }
-
- foreach ($object['_attachments'] as $attach) {
- if ($attach['id'] == $part) {
- if ($print) echo $attach['content'];
- else if ($fp) fwrite($fp, $attach['content']);
- else return $attach['content'];
- return true;
- }
- }
- }
- }
- else {
- // return message part from IMAP directly
- return $this->imap->get_message_part($msguid, $part, null, $print, $fp, $skip_charset_conv);
- }
- }
-
- return null;
- }
-
-
- /**
- * Fetch the mime message from the storage server and extract
- * the Kolab groupware object from it
- *
- * @param string The IMAP message UID to fetch
- * @param string The object type expected (use wildcard '*' to accept all types)
- * @param string The folder name where the message is stored
- *
- * @return mixed Hash array representing the Kolab object, a kolab_format instance or false if not found
- */
- public function read_object($msguid, $type = null, $folder = null)
- {
- if (!$this->valid) {
- return false;
- }
-
- if (!$type) $type = $this->type;
- if (!$folder) $folder = $this->name;
-
- $this->imap->set_folder($folder);
-
- $this->cache->bypass(true);
- $message = new rcube_message($msguid);
- $this->cache->bypass(false);
-
- // Message doesn't exist?
- if (empty($message->headers)) {
- return false;
- }
-
- // extract the X-Kolab-Type header from the XML attachment part if missing
- if (empty($message->headers->others['x-kolab-type'])) {
- foreach ((array)$message->attachments as $part) {
- if (strpos($part->mimetype, kolab_format::KTYPE_PREFIX) === 0) {
- $message->headers->others['x-kolab-type'] = $part->mimetype;
- break;
- }
- }
- }
- // fix buggy messages stating the X-Kolab-Type header twice
- else if (is_array($message->headers->others['x-kolab-type'])) {
- $message->headers->others['x-kolab-type'] = reset($message->headers->others['x-kolab-type']);
- }
-
- // no object type header found: abort
- if (empty($message->headers->others['x-kolab-type'])) {
- rcube::raise_error(array(
- 'code' => 600,
- 'type' => 'php',
- 'file' => __FILE__,
- 'line' => __LINE__,
- 'message' => "No X-Kolab-Type information found in message $msguid ($this->name).",
- ), true);
- return false;
- }
-
- $object_type = kolab_format::mime2object_type($message->headers->others['x-kolab-type']);
- $content_type = kolab_format::KTYPE_PREFIX . $object_type;
-
- // check object type header and abort on mismatch
- if ($type != '*' && $object_type != $type)
- return false;
-
- $attachments = array();
-
- // get XML part
- foreach ((array)$message->attachments as $part) {
- if (!$xml && ($part->mimetype == $content_type || preg_match('!application/([a-z.]+\+)?xml!', $part->mimetype))) {
- $xml = $message->get_part_body($part->mime_id, true);
- }
- else if ($part->filename || $part->content_id) {
- $key = $part->content_id ? trim($part->content_id, '<>') : $part->filename;
- $size = null;
-
- // Use Content-Disposition 'size' as for the Kolab Format spec.
- if (isset($part->d_parameters['size'])) {
- $size = $part->d_parameters['size'];
- }
- // we can trust part size only if it's not encoded
- else if ($part->encoding == 'binary' || $part->encoding == '7bit' || $part->encoding == '8bit') {
- $size = $part->size;
- }
-
- $attachments[$key] = array(
- 'id' => $part->mime_id,
- 'name' => $part->filename,
- 'mimetype' => $part->mimetype,
- 'size' => $size,
- );
- }
- }
-
- if (!$xml) {
- rcube::raise_error(array(
- 'code' => 600,
- 'type' => 'php',
- 'file' => __FILE__,
- 'line' => __LINE__,
- 'message' => "Could not find Kolab data part in message $msguid ($this->name).",
- ), true);
- return false;
- }
-
- // check kolab format version
- $format_version = $message->headers->others['x-kolab-mime-version'];
- if (empty($format_version)) {
- list($xmltype, $subtype) = explode('.', $object_type);
- $xmlhead = substr($xml, 0, 512);
-
- // detect old Kolab 2.0 format
- if (strpos($xmlhead, '<' . $xmltype) !== false && strpos($xmlhead, 'xmlns=') === false)
- $format_version = '2.0';
- else
- $format_version = '3.0'; // assume 3.0
- }
-
- // get Kolab format handler for the given type
- $format = kolab_format::factory($object_type, $format_version);
-
- if (is_a($format, 'PEAR_Error'))
- return false;
-
- // load Kolab object from XML part
- $format->load($xml);
-
- if ($format->is_valid()) {
- $object = $format->to_array(array('_attachments' => $attachments));
- $object['_type'] = $object_type;
- $object['_msguid'] = $msguid;
- $object['_mailbox'] = $this->name;
- $object['_formatobj'] = $format;
-
- return $object;
- }
- else {
- // try to extract object UID from XML block
- if (preg_match('!<uid>(.+)</uid>!Uims', $xml, $m))
- $msgadd = " UID = " . trim(strip_tags($m[1]));
-
- rcube::raise_error(array(
- 'code' => 600,
- 'type' => 'php',
- 'file' => __FILE__,
- 'line' => __LINE__,
- 'message' => "Could not parse Kolab object data in message $msguid ($this->name)." . $msgadd,
- ), true);
- }
-
- return false;
- }
-
- /**
- * Save an object in this folder.
- *
- * @param array $object The array that holds the data of the object.
- * @param string $type The type of the kolab object.
- * @param string $uid The UID of the old object if it existed before
- * @return boolean True on success, false on error
- */
- public function save(&$object, $type = null, $uid = null)
- {
- if (!$this->valid) {
- return false;
- }
-
- if (!$type)
- $type = $this->type;
-
- // copy attachments from old message
- if (!empty($object['_msguid']) && ($old = $this->cache->get($object['_msguid'], $type, $object['_mailbox']))) {
- foreach ((array)$old['_attachments'] as $key => $att) {
- if (!isset($object['_attachments'][$key])) {
- $object['_attachments'][$key] = $old['_attachments'][$key];
- }
- // unset deleted attachment entries
- if ($object['_attachments'][$key] == false) {
- unset($object['_attachments'][$key]);
- }
- // load photo.attachment from old Kolab2 format to be directly embedded in xcard block
- else if ($type == 'contact' && ($key == 'photo.attachment' || $key == 'kolab-picture.png') && $att['id']) {
- if (!isset($object['photo']))
- $object['photo'] = $this->get_attachment($object['_msguid'], $att['id'], $object['_mailbox']);
- unset($object['_attachments'][$key]);
- }
- }
- }
-
- // save contact photo to attachment for Kolab2 format
- if (kolab_storage::$version == '2.0' && $object['photo']) {
- $attkey = 'kolab-picture.png'; // this file name is hard-coded in libkolab/kolabformatV2/contact.cpp
- $object['_attachments'][$attkey] = array(
- 'mimetype'=> rcube_mime::image_content_type($object['photo']),
- 'content' => preg_match('![^a-z0-9/=+-]!i', $object['photo']) ? $object['photo'] : base64_decode($object['photo']),
- );
- }
-
- // process attachments
- if (is_array($object['_attachments'])) {
- $numatt = count($object['_attachments']);
- foreach ($object['_attachments'] as $key => $attachment) {
- // FIXME: kolab_storage and Roundcube attachment hooks use different fields!
- if (empty($attachment['content']) && !empty($attachment['data'])) {
- $attachment['content'] = $attachment['data'];
- unset($attachment['data'], $object['_attachments'][$key]['data']);
- }
-
- // make sure size is set, so object saved in cache contains this info
- if (!isset($attachment['size'])) {
- if (!empty($attachment['content'])) {
- if (is_resource($attachment['content'])) {
- // this need to be a seekable resource, otherwise
- // fstat() failes and we're unable to determine size
- // here nor in rcube_imap_generic before IMAP APPEND
- $stat = fstat($attachment['content']);
- $attachment['size'] = $stat ? $stat['size'] : 0;
- }
- else {
- $attachment['size'] = strlen($attachment['content']);
- }
- }
- else if (!empty($attachment['path'])) {
- $attachment['size'] = filesize($attachment['path']);
- }
- $object['_attachments'][$key] = $attachment;
- }
-
- // generate unique keys (used as content-id) for attachments
- if (is_numeric($key) && $key < $numatt) {
- // derrive content-id from attachment file name
- $ext = preg_match('/(\.[a-z0-9]{1,6})$/i', $attachment['name'], $m) ? $m[1] : null;
- $basename = preg_replace('/[^a-z0-9_.-]/i', '', basename($attachment['name'], $ext)); // to 7bit ascii
- if (!$basename) $basename = 'noname';
- $cid = $basename . '.' . microtime(true) . $ext;
-
- $object['_attachments'][$cid] = $attachment;
- unset($object['_attachments'][$key]);
- }
- }
- }
-
- // save recurrence exceptions as individual objects due to lack of support in Kolab v2 format
- if (kolab_storage::$version == '2.0' && $object['recurrence']['EXCEPTIONS']) {
- $this->save_recurrence_exceptions($object, $type);
- }
-
- // check IMAP BINARY extension support for 'file' objects
- // allow configuration to workaround bug in Cyrus < 2.4.17
- $rcmail = rcube::get_instance();
- $binary = $type == 'file' && !$rcmail->config->get('kolab_binary_disable') && $this->imap->get_capability('BINARY');
-
- // generate and save object message
- if ($raw_msg = $this->build_message($object, $type, $binary, $body_file)) {
- // resolve old msguid before saving
- if ($uid && empty($object['_msguid']) && ($msguid = $this->cache->uid2msguid($uid))) {
- $object['_msguid'] = $msguid;
- $object['_mailbox'] = $this->name;
- }
-
- $result = $this->imap->save_message($this->name, $raw_msg, null, false, null, null, $binary);
-
- // update cache with new UID
- if ($result) {
- $old_uid = $object['_msguid'];
-
- $object['_msguid'] = $result;
- $object['_mailbox'] = $this->name;
-
- if ($old_uid) {
- // delete old message
- $this->cache->bypass(true);
- $this->imap->delete_message($old_uid, $object['_mailbox']);
- $this->cache->bypass(false);
- }
-
- // insert/update message in cache
- $this->cache->save($result, $object, $old_uid);
- }
-
- // remove temp file
- if ($body_file) {
- @unlink($body_file);
- }
- }
-
- return $result;
- }
-
- /**
- * Save recurrence exceptions as individual objects.
- * The Kolab v2 format doesn't allow us to save fully embedded exception objects.
- *
- * @param array Hash array with event properties
- * @param string Object type
- */
- private function save_recurrence_exceptions(&$object, $type = null)
- {
- if ($object['recurrence']['EXCEPTIONS']) {
- $exdates = array();
- foreach ((array)$object['recurrence']['EXDATE'] as $exdate) {
- $key = is_a($exdate, 'DateTime') ? $exdate->format('Y-m-d') : strval($exdate);
- $exdates[$key] = 1;
- }
-
- // save every exception as individual object
- foreach((array)$object['recurrence']['EXCEPTIONS'] as $exception) {
- $exception['uid'] = self::recurrence_exception_uid($object['uid'], $exception['start']->format('Ymd'));
- $exception['sequence'] = $object['sequence'] + 1;
-
- if ($exception['thisandfuture']) {
- $exception['recurrence'] = $object['recurrence'];
-
- // adjust the recurrence duration of the exception
- if ($object['recurrence']['COUNT']) {
- $recurrence = new kolab_date_recurrence($object['_formatobj']);
- if ($end = $recurrence->end()) {
- unset($exception['recurrence']['COUNT']);
- $exception['recurrence']['UNTIL'] = $end;
- }
- }
-
- // set UNTIL date if we have a thisandfuture exception
- $untildate = clone $exception['start'];
- $untildate->sub(new DateInterval('P1D'));
- $object['recurrence']['UNTIL'] = $untildate;
- unset($object['recurrence']['COUNT']);
- }
- else {
- if (!$exdates[$exception['start']->format('Y-m-d')])
- $object['recurrence']['EXDATE'][] = clone $exception['start'];
- unset($exception['recurrence']);
- }
-
- unset($exception['recurrence']['EXCEPTIONS'], $exception['_formatobj'], $exception['_msguid']);
- $this->save($exception, $type, $exception['uid']);
- }
-
- unset($object['recurrence']['EXCEPTIONS']);
- }
- }
-
- /**
- * Generate an object UID with the given recurrence-ID in a way that it is
- * unique (the original UID is not a substring) but still recoverable.
- */
- private static function recurrence_exception_uid($uid, $recurrence_id)
- {
- $offset = -2;
- return substr($uid, 0, $offset) . '-' . $recurrence_id . '-' . substr($uid, $offset);
- }
-
- /**
- * Delete the specified object from this folder.
- *
- * @param mixed $object The Kolab object to delete or object UID
- * @param boolean $expunge Should the folder be expunged?
- *
- * @return boolean True if successful, false on error
- */
- public function delete($object, $expunge = true)
- {
- if (!$this->valid) {
- return false;
- }
-
- $msguid = is_array($object) ? $object['_msguid'] : $this->cache->uid2msguid($object);
- $success = false;
-
- $this->cache->bypass(true);
-
- if ($msguid && $expunge) {
- $success = $this->imap->delete_message($msguid, $this->name);
- }
- else if ($msguid) {
- $success = $this->imap->set_flag($msguid, 'DELETED', $this->name);
- }
-
- $this->cache->bypass(false);
-
- if ($success) {
- $this->cache->set($msguid, false);
- }
-
- return $success;
- }
-
-
- /**
- *
- */
- public function delete_all()
- {
- if (!$this->valid) {
- return false;
- }
-
- $this->cache->purge();
- $this->cache->bypass(true);
- $result = $this->imap->clear_folder($this->name);
- $this->cache->bypass(false);
-
- return $result;
- }
-
-
- /**
- * Restore a previously deleted object
- *
- * @param string Object UID
- * @return mixed Message UID on success, false on error
- */
- public function undelete($uid)
- {
- if (!$this->valid) {
- return false;
- }
-
- if ($msguid = $this->cache->uid2msguid($uid, true)) {
- $this->cache->bypass(true);
- $result = $this->imap->set_flag($msguid, 'UNDELETED', $this->name);
- $this->cache->bypass(false);
-
- if ($result) {
- return $msguid;
- }
- }
-
- return false;
- }
-
-
- /**
- * Move a Kolab object message to another IMAP folder
- *
- * @param string Object UID
- * @param string IMAP folder to move object to
- * @return boolean True on success, false on failure
- */
- public function move($uid, $target_folder)
- {
- if (!$this->valid) {
- return false;
- }
-
- if (is_string($target_folder))
- $target_folder = kolab_storage::get_folder($target_folder);
-
- if ($msguid = $this->cache->uid2msguid($uid)) {
- $this->cache->bypass(true);
- $result = $this->imap->move_message($msguid, $target_folder->name, $this->name);
- $this->cache->bypass(false);
-
- if ($result) {
- $this->cache->move($msguid, $uid, $target_folder);
- return true;
- }
- else {
- rcube::raise_error(array(
- 'code' => 600, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Failed to move message $msguid to $target_folder: " . $this->imap->get_error_str(),
- ), true);
- }
- }
-
- return false;
- }
-
-
- /**
- * Creates source of the configuration object message
- *
- * @param array $object The array that holds the data of the object.
- * @param string $type The type of the kolab object.
- * @param bool $binary Enables use of binary encoding of attachment(s)
- * @param string $body_file Reference to filename of message body
- *
- * @return mixed Message as string or array with two elements
- * (one for message file path, second for message headers)
- */
- private function build_message(&$object, $type, $binary, &$body_file)
- {
- // load old object to preserve data we don't understand/process
- if (is_object($object['_formatobj']))
- $format = $object['_formatobj'];
- else if ($object['_msguid'] && ($old = $this->cache->get($object['_msguid'], $type, $object['_mailbox'])))
- $format = $old['_formatobj'];
-
- // create new kolab_format instance
- if (!$format)
- $format = kolab_format::factory($type, kolab_storage::$version);
-
- if (PEAR::isError($format))
- return false;
-
- $format->set($object);
- $xml = $format->write(kolab_storage::$version);
- $object['uid'] = $format->uid; // read UID from format
- $object['_formatobj'] = $format;
-
- if (empty($xml) || !$format->is_valid() || empty($object['uid'])) {
- return false;
- }
-
- $mime = new Mail_mime("\r\n");
- $rcmail = rcube::get_instance();
- $headers = array();
- $files = array();
- $part_id = 1;
- $encoding = $binary ? 'binary' : 'base64';
-
- if ($user_email = $rcmail->get_user_email()) {
- $headers['From'] = $user_email;
- $headers['To'] = $user_email;
- }
- $headers['Date'] = date('r');
- $headers['X-Kolab-Type'] = kolab_format::KTYPE_PREFIX . $type;
- $headers['X-Kolab-Mime-Version'] = kolab_storage::$version;
- $headers['Subject'] = $object['uid'];
-// $headers['Message-ID'] = $rcmail->gen_message_id();
- $headers['User-Agent'] = $rcmail->config->get('useragent');
-
- // 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 (!empty($object['_attachments']) && ($mem_limit = parse_bytes(ini_get('memory_limit'))) > 0) {
- $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB
-
- foreach ($object['_attachments'] as $attachment) {
- $memory += $attachment['size'];
- }
-
- // 1.33 is for base64, we need at least 4x more memory than the message size
- if ($memory * ($binary ? 1 : 1.33) * 4 > $mem_limit) {
- $marker = '%%%~~~' . md5(microtime(true) . $memory) . '~~~%%%';
- $is_file = true;
- $temp_dir = unslashify($rcmail->config->get('temp_dir'));
- $mime->setParam('delay_file_io', true);
- }
- }
-
- $mime->headers($headers);
- $mime->setTXTBody("This is a Kolab Groupware object. "
- . "To view this object you will need an email client that understands the Kolab Groupware format. "
- . "For a list of such email clients please visit http://www.kolab.org/\n\n");
-
- $ctype = kolab_storage::$version == '2.0' ? $format->CTYPEv2 : $format->CTYPE;
- // Convert new lines to \r\n, to wrokaround "NO Message contains bare newlines"
- // when APPENDing from temp file
- $xml = preg_replace('/\r?\n/', "\r\n", $xml);
-
- $mime->addAttachment($xml, // file
- $ctype, // content-type
- 'kolab.xml', // filename
- false, // is_file
- '8bit', // encoding
- 'attachment', // disposition
- RCUBE_CHARSET // charset
- );
- $part_id++;
-
- // save object attachments as separate parts
- foreach ((array)$object['_attachments'] as $key => $att) {
- if (empty($att['content']) && !empty($att['id'])) {
- // @TODO: use IMAP CATENATE to skip attachment fetch+push operation
- $msguid = !empty($object['_msguid']) ? $object['_msguid'] : $object['uid'];
- if ($is_file) {
- $att['path'] = tempnam($temp_dir, 'rcmAttmnt');
- if (($fp = fopen($att['path'], 'w')) && $this->get_attachment($msguid, $att['id'], $object['_mailbox'], false, $fp, true)) {
- fclose($fp);
- }
- else {
- return false;
- }
- }
- else {
- $att['content'] = $this->get_attachment($msguid, $att['id'], $object['_mailbox'], false, null, true);
- }
- }
-
- $headers = array('Content-ID' => Mail_mimePart::encodeHeader('Content-ID', '<' . $key . '>', RCUBE_CHARSET, 'quoted-printable'));
- $name = !empty($att['name']) ? $att['name'] : $key;
-
- // To store binary files we can use faster method
- // without writting full message content to a temporary file but
- // directly to IMAP, see rcube_imap_generic::append().
- // I.e. use file handles where possible
- if (!empty($att['path'])) {
- if ($is_file && $binary) {
- $files[] = fopen($att['path'], 'r');
- $mime->addAttachment($marker, $att['mimetype'], $name, false, $encoding, 'attachment', '', '', '', null, null, '', RCUBE_CHARSET, $headers);
- }
- else {
- $mime->addAttachment($att['path'], $att['mimetype'], $name, true, $encoding, 'attachment', '', '', '', null, null, '', RCUBE_CHARSET, $headers);
- }
- }
- else {
- if (is_resource($att['content']) && $is_file && $binary) {
- $files[] = $att['content'];
- $mime->addAttachment($marker, $att['mimetype'], $name, false, $encoding, 'attachment', '', '', '', null, null, '', RCUBE_CHARSET, $headers);
- }
- else {
- if (is_resource($att['content'])) {
- @rewind($att['content']);
- $att['content'] = stream_get_contents($att['content']);
- }
- $mime->addAttachment($att['content'], $att['mimetype'], $name, false, $encoding, 'attachment', '', '', '', null, null, '', RCUBE_CHARSET, $headers);
- }
- }
-
- $object['_attachments'][$key]['id'] = ++$part_id;
- }
-
- if (!$is_file || !empty($files)) {
- $message = $mime->getMessage();
- }
-
- // parse message and build message array with
- // attachment file pointers in place of file markers
- if (!empty($files)) {
- $message = explode($marker, $message);
- $tmp = array();
-
- foreach ($message as $msg_part) {
- $tmp[] = $msg_part;
- if ($file = array_shift($files)) {
- $tmp[] = $file;
- }
- }
- $message = $tmp;
- }
- // write complete message body into temp file
- else if ($is_file) {
- // use common temp dir
- $body_file = tempnam($temp_dir, 'rcmMsg');
-
- if (PEAR::isError($mime_result = $mime->saveMessageBody($body_file))) {
- self::raise_error(array('code' => 650, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Could not create message: ".$mime_result->getMessage()),
- true, false);
- return false;
- }
-
- $message = array(trim($mime->txtHeaders()) . "\r\n\r\n", fopen($body_file, 'r'));
- }
-
- return $message;
- }
-
-
- /**
- * Triggers any required updates after changes within the
- * folder. This is currently only required for handling free/busy
- * information with Kolab.
- *
- * @return boolean|PEAR_Error True if successfull.
- */
- public function trigger()
- {
- $owner = $this->get_owner();
- $result = false;
-
- switch($this->type) {
- case 'event':
- if ($this->get_namespace() == 'personal') {
- $result = $this->trigger_url(
- sprintf('%s/trigger/%s/%s.pfb',
- kolab_storage::get_freebusy_server(),
- urlencode($owner),
- urlencode($this->imap->mod_folder($this->name))
- ),
- $this->imap->options['user'],
- $this->imap->options['password']
- );
- }
- break;
-
- default:
- return true;
- }
-
- if ($result && is_object($result) && is_a($result, 'PEAR_Error')) {
- return PEAR::raiseError(sprintf("Failed triggering folder %s. Error was: %s",
- $this->name, $result->getMessage()));
- }
-
- return $result;
- }
-
- /**
- * Triggers a URL.
- *
- * @param string $url The URL to be triggered.
- * @param string $auth_user Username to authenticate with
- * @param string $auth_passwd Password for basic auth
- * @return boolean|PEAR_Error True if successfull.
- */
- private function trigger_url($url, $auth_user = null, $auth_passwd = null)
- {
- try {
- $request = libkolab::http_request($url);
-
- // set authentication credentials
- if ($auth_user && $auth_passwd)
- $request->setAuth($auth_user, $auth_passwd);
-
- $result = $request->send();
- // rcube::write_log('trigger', $result->getBody());
- }
- catch (Exception $e) {
- return PEAR::raiseError($e->getMessage());
- }
-
- return true;
- }
-
-}
-
diff --git a/lib/plugins/libkolab/lib/kolab_storage_folder_api.php b/lib/plugins/libkolab/lib/kolab_storage_folder_api.php
deleted file mode 100644
index 7280389..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_folder_api.php
+++ /dev/null
@@ -1,351 +0,0 @@
-<?php
-
-/**
- * Abstract interface class for Kolab storage IMAP folder objects
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-abstract class kolab_storage_folder_api
-{
- /**
- * Folder identifier
- * @var string
- */
- public $id;
-
- /**
- * The folder name.
- * @var string
- */
- public $name;
-
- /**
- * The type of this folder.
- * @var string
- */
- public $type;
-
- /**
- * The subtype of this folder.
- * @var string
- */
- public $subtype;
-
- /**
- * Is this folder set to be the default for its type
- * @var boolean
- */
- public $default = false;
-
- /**
- * List of direct child folders
- * @var array
- */
- public $children = array();
-
- /**
- * Name of the parent folder
- * @var string
- */
- public $parent = '';
-
- protected $imap;
- protected $owner;
- protected $info;
- protected $idata;
- protected $namespace;
-
-
- /**
- * Private constructor
- */
- protected function __construct($name)
- {
- $this->name = $name;
- $this->id = kolab_storage::folder_id($name);
- $this->imap = rcube::get_instance()->get_storage();
- }
-
-
- /**
- * Returns the owner of the folder.
- *
- * @param boolean Return a fully qualified owner name (i.e. including domain for shared folders)
- * @return string The owner of this folder.
- */
- public function get_owner($fully_qualified = false)
- {
- // return cached value
- if (isset($this->owner))
- return $this->owner;
-
- $info = $this->get_folder_info();
- $rcmail = rcube::get_instance();
-
- switch ($info['namespace']) {
- case 'personal':
- $this->owner = $rcmail->get_user_name();
- break;
-
- case 'shared':
- $this->owner = 'anonymous';
- break;
-
- default:
- list($prefix, $this->owner) = explode($this->imap->get_hierarchy_delimiter(), $info['name']);
- $fully_qualified = true; // enforce email addresses (backwards compatibility)
- break;
- }
-
- if ($fully_qualified && strpos($this->owner, '@') === false) {
- // extract domain from current user name
- $domain = strstr($rcmail->get_user_name(), '@');
- // fall back to mail_domain config option
- if (empty($domain) && ($mdomain = $rcmail->config->mail_domain($this->imap->options['host']))) {
- $domain = '@' . $mdomain;
- }
- $this->owner .= $domain;
- }
-
- return $this->owner;
- }
-
-
- /**
- * Getter for the name of the namespace to which the IMAP folder belongs
- *
- * @return string Name of the namespace (personal, other, shared)
- */
- public function get_namespace()
- {
- if (!isset($this->namespace))
- $this->namespace = $this->imap->folder_namespace($this->name);
- return $this->namespace;
- }
-
-
- /**
- * Get the display name value of this folder
- *
- * @return string Folder name
- */
- public function get_name()
- {
- return kolab_storage::object_name($this->name, $this->get_namespace());
- }
-
-
- /**
- * Getter for the top-end folder name (not the entire path)
- *
- * @return string Name of this folder
- */
- public function get_foldername()
- {
- $parts = explode('/', $this->name);
- return rcube_charset::convert(end($parts), 'UTF7-IMAP');
- }
-
- /**
- * Getter for parent folder path
- *
- * @return string Full path to parent folder
- */
- public function get_parent()
- {
- $path = explode('/', $this->name);
- array_pop($path);
-
- // don't list top-level namespace folder
- if (count($path) == 1 && in_array($this->get_namespace(), array('other', 'shared'))) {
- $path = array();
- }
-
- return join('/', $path);
- }
-
- /**
- * Getter for the Cyrus mailbox identifier corresponding to this folder
- * (e.g. user/john.doe/Calendar/Personal@example.org)
- *
- * @return string Mailbox ID
- */
- public function get_mailbox_id()
- {
- $info = $this->get_folder_info();
- $owner = $this->get_owner();
- list($user, $domain) = explode('@', $owner);
-
- switch ($info['namespace']) {
- case 'personal':
- return sprintf('user/%s/%s@%s', $user, $this->name, $domain);
-
- case 'shared':
- $ns = $this->imap->get_namespace('shared');
- $prefix = is_array($ns) ? $ns[0][0] : '';
- list(, $domain) = explode('@', rcube::get_instance()->get_user_name());
- return substr($this->name, strlen($prefix)) . '@' . $domain;
-
- default:
- $ns = $this->imap->get_namespace('other');
- $prefix = is_array($ns) ? $ns[0][0] : '';
- list($user, $folder) = explode($this->imap->get_hierarchy_delimiter(), substr($info['name'], strlen($prefix)), 2);
- if (strpos($user, '@')) {
- list($user, $domain) = explode('@', $user);
- }
- return sprintf('user/%s/%s@%s', $user, $folder, $domain);
- }
- }
-
- /**
- * Get the color value stored in metadata
- *
- * @param string Default color value to return if not set
- * @return mixed Color value from IMAP metadata or $default is not set
- */
- public function get_color($default = null)
- {
- // color is defined in folder METADATA
- $metadata = $this->get_metadata(array(kolab_storage::COLOR_KEY_PRIVATE, kolab_storage::COLOR_KEY_SHARED));
- if (($color = $metadata[kolab_storage::COLOR_KEY_PRIVATE]) || ($color = $metadata[kolab_storage::COLOR_KEY_SHARED])) {
- return $color;
- }
-
- return $default;
- }
-
-
- /**
- * Returns IMAP metadata/annotations (GETMETADATA/GETANNOTATION)
- *
- * @param array List of metadata keys to read
- * @return array Metadata entry-value hash array on success, NULL on error
- */
- public function get_metadata($keys)
- {
- $metadata = rcube::get_instance()->get_storage()->get_metadata($this->name, (array)$keys);
- return $metadata[$this->name];
- }
-
-
- /**
- * Sets IMAP metadata/annotations (SETMETADATA/SETANNOTATION)
- *
- * @param array $entries Entry-value array (use NULL value as NIL)
- * @return boolean True on success, False on failure
- */
- public function set_metadata($entries)
- {
- return $this->imap->set_metadata($this->name, $entries);
- }
-
-
- /**
- *
- */
- public function get_folder_info()
- {
- if (!isset($this->info))
- $this->info = $this->imap->folder_info($this->name);
-
- return $this->info;
- }
-
- /**
- * Make IMAP folder data available for this folder
- */
- public function get_imap_data()
- {
- if (!isset($this->idata))
- $this->idata = $this->imap->folder_data($this->name);
-
- return $this->idata;
- }
-
-
- /**
- * Get IMAP ACL information for this folder
- *
- * @return string Permissions as string
- */
- public function get_myrights()
- {
- $rights = $this->info['rights'];
-
- if (!is_array($rights))
- $rights = $this->imap->my_rights($this->name);
-
- return join('', (array)$rights);
- }
-
-
- /**
- * Check activation status of this folder
- *
- * @return boolean True if enabled, false if not
- */
- public function is_active()
- {
- return kolab_storage::folder_is_active($this->name);
- }
-
- /**
- * Change activation status of this folder
- *
- * @param boolean The desired subscription status: true = active, false = not active
- *
- * @return True on success, false on error
- */
- public function activate($active)
- {
- return $active ? kolab_storage::folder_activate($this->name) : kolab_storage::folder_deactivate($this->name);
- }
-
- /**
- * Check subscription status of this folder
- *
- * @return boolean True if subscribed, false if not
- */
- public function is_subscribed()
- {
- return kolab_storage::folder_is_subscribed($this->name);
- }
-
- /**
- * Change subscription status of this folder
- *
- * @param boolean The desired subscription status: true = subscribed, false = not subscribed
- *
- * @return True on success, false on error
- */
- public function subscribe($subscribed)
- {
- return $subscribed ? kolab_storage::folder_subscribe($this->name) : kolab_storage::folder_unsubscribe($this->name);
- }
-
- /**
- * Return folder name as string representation of this object
- *
- * @return string Full IMAP folder name
- */
- public function __toString()
- {
- return $this->name;
- }
-}
-
diff --git a/lib/plugins/libkolab/lib/kolab_storage_folder_user.php b/lib/plugins/libkolab/lib/kolab_storage_folder_user.php
deleted file mode 100644
index 7c141c5..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_folder_user.php
+++ /dev/null
@@ -1,135 +0,0 @@
-<?php
-
-/**
- * Class that represents a (virtual) folder in the 'other' namespace
- * implementing a subset of the kolab_storage_folder API.
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-class kolab_storage_folder_user extends kolab_storage_folder_virtual
-{
- protected static $ldapcache = array();
-
- public $ldaprec;
- public $type;
-
- /**
- * Default constructor
- */
- public function __construct($name, $parent = '', $ldaprec = null)
- {
- parent::__construct($name, $name, 'other', $parent);
-
- if (!empty($ldaprec)) {
- self::$ldapcache[$name] = $this->ldaprec = $ldaprec;
- }
- // use value cached in memory for repeated lookups
- else if (array_key_exists($name, self::$ldapcache)) {
- $this->ldaprec = self::$ldapcache[$name];
- }
- // lookup user in LDAP and set $this->ldaprec
- else if ($ldap = kolab_storage::ldap()) {
- // get domain from current user
- list(,$domain) = explode('@', rcube::get_instance()->get_user_name());
- $this->ldaprec = $ldap->get_user_record(parent::get_foldername($this->name) . '@' . $domain, $_SESSION['imap_host']);
- if (!empty($this->ldaprec)) {
- $this->ldaprec['kolabtargetfolder'] = $name;
- }
- self::$ldapcache[$name] = $this->ldaprec;
- }
- }
-
- /**
- * Getter for the top-end folder name to be displayed
- *
- * @return string Name of this folder
- */
- public function get_foldername()
- {
- return $this->ldaprec ? ($this->ldaprec['displayname'] ?: $this->ldaprec['name']) :
- parent::get_foldername();
- }
-
- /**
- * Getter for a more informative title of this user folder
- *
- * @return string Title for the given user record
- */
- public function get_title()
- {
- return trim($this->ldaprec['displayname'] . '; ' . $this->ldaprec['mail'], '; ');
- }
-
- /**
- * Returns the owner of the folder.
- *
- * @return string The owner of this folder.
- */
- public function get_owner()
- {
- return $this->ldaprec['mail'];
- }
-
- /**
- * Check subscription status of this folder.
- * Subscription of a virtual user folder depends on the subscriptions of subfolders.
- *
- * @return boolean True if subscribed, false if not
- */
- public function is_subscribed()
- {
- if (!empty($this->type)) {
- $children = $subscribed = 0;
- $delimiter = $this->imap->get_hierarchy_delimiter();
- foreach ((array)kolab_storage::list_folders($this->name . $delimiter, '*', $this->type, false) as $subfolder) {
- if (kolab_storage::folder_is_subscribed($subfolder)) {
- $subscribed++;
- }
- $children++;
- }
- if ($subscribed > 0) {
- return $subscribed == $children ? true : 2;
- }
- }
-
- return false;
- }
-
- /**
- * Change subscription status of this folder
- *
- * @param boolean The desired subscription status: true = subscribed, false = not subscribed
- *
- * @return True on success, false on error
- */
- public function subscribe($subscribed)
- {
- $success = false;
-
- // (un)subscribe all subfolders of a given type
- if (!empty($this->type)) {
- $delimiter = $this->imap->get_hierarchy_delimiter();
- foreach ((array)kolab_storage::list_folders($this->name . $delimiter, '*', $this->type, false) as $subfolder) {
- $success |= ($subscribed ? kolab_storage::folder_subscribe($subfolder) : kolab_storage::folder_unsubscribe($subfolder));
- }
- }
-
- return $success;
- }
-
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/lib/kolab_storage_folder_virtual.php b/lib/plugins/libkolab/lib/kolab_storage_folder_virtual.php
deleted file mode 100644
index e419ced..0000000
--- a/lib/plugins/libkolab/lib/kolab_storage_folder_virtual.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-
-/**
- * Helper class that represents a virtual IMAP folder
- * with a subset of the kolab_storage_folder API.
- *
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-class kolab_storage_folder_virtual extends kolab_storage_folder_api
-{
- public $virtual = true;
-
- protected $displayname;
-
- public function __construct($name, $dispname, $ns, $parent = '')
- {
- parent::__construct($name);
-
- $this->namespace = $ns;
- $this->parent = $parent;
- $this->displayname = $dispname;
- }
-
- /**
- * Get the display name value of this folder
- *
- * @return string Folder name
- */
- public function get_name()
- {
- return $this->displayname ?: parent::get_name();
- }
-
- /**
- * Get the color value stored in metadata
- *
- * @param string Default color value to return if not set
- * @return mixed Color value from IMAP metadata or $default is not set
- */
- public function get_color($default = null)
- {
- return $default;
- }
-}
\ No newline at end of file
diff --git a/lib/plugins/libkolab/libkolab.php b/lib/plugins/libkolab/libkolab.php
deleted file mode 100644
index 052724c..0000000
--- a/lib/plugins/libkolab/libkolab.php
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-
-/**
- * Kolab core library
- *
- * Plugin to setup a basic environment for the interaction with a Kolab server.
- * Other Kolab-related plugins will depend on it and can use the library classes
- *
- * @version @package_version@
- * @author Thomas Bruederli <bruederli@kolabsys.com>
- *
- * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-class libkolab extends rcube_plugin
-{
- static $http_requests = array();
-
- /**
- * Required startup method of a Roundcube plugin
- */
- public function init()
- {
- // load local config
- $this->load_config();
-
- // extend include path to load bundled lib classes
- $include_path = $this->home . '/lib' . PATH_SEPARATOR . ini_get('include_path');
- set_include_path($include_path);
-
- $this->add_hook('storage_init', array($this, 'storage_init'));
- $this->add_hook('user_delete', array('kolab_storage', 'delete_user_folders'));
-
- $rcmail = rcube::get_instance();
- try {
- kolab_format::$timezone = new DateTimeZone($rcmail->config->get('timezone', 'GMT'));
- }
- catch (Exception $e) {
- rcube::raise_error($e, true);
- kolab_format::$timezone = new DateTimeZone('GMT');
- }
- }
-
- /**
- * Hook into IMAP FETCH HEADER.FIELDS command and request Kolab-specific headers
- */
- function storage_init($p)
- {
- $p['fetch_headers'] = trim($p['fetch_headers'] .' X-KOLAB-TYPE X-KOLAB-MIME-VERSION');
- return $p;
- }
-
- /**
- * Wrapper function to load and initalize the HTTP_Request2 Object
- *
- * @param string|Net_Url2 Request URL
- * @param string Request method ('OPTIONS','GET','HEAD','POST','PUT','DELETE','TRACE','CONNECT')
- * @param array Configuration for this Request instance, that will be merged
- * with default configuration
- *
- * @return HTTP_Request2 Request object
- */
- public static function http_request($url = '', $method = 'GET', $config = array())
- {
- $rcube = rcube::get_instance();
- $http_config = (array) $rcube->config->get('kolab_http_request');
-
- // deprecated configuration options
- if (empty($http_config)) {
- foreach (array('ssl_verify_peer', 'ssl_verify_host') as $option) {
- $value = $rcube->config->get('kolab_' . $option, true);
- if (is_bool($value)) {
- $http_config[$option] = $value;
- }
- }
- }
-
- if (!empty($config)) {
- $http_config = array_merge($http_config, $config);
- }
-
- $key = md5(serialize($http_config));
-
- if (!($request = self::$http_requests[$key])) {
- // load HTTP_Request2
- require_once 'HTTP/Request2.php';
-
- try {
- $request = new HTTP_Request2();
- $request->setConfig($http_config);
- }
- catch (Exception $e) {
- rcube::raise_error($e, true, true);
- }
-
- // proxy User-Agent string
- $request->setHeader('user-agent', $_SERVER['HTTP_USER_AGENT']);
-
- self::$http_requests[$key] = $request;
- }
-
- // cleanup
- try {
- $request->setBody('');
- $request->setUrl($url);
- $request->setMethod($method);
- }
- catch (Exception $e) {
- rcube::raise_error($e, true, true);
- }
-
- return $request;
- }
-
- /**
- * Wrapper function for generating a html diff using the FineDiff class by Raymond Hill
- */
- public static function html_diff($from, $to)
- {
- include_once __dir__ . '/vendor/finediff.php';
-
- $diff = new FineDiff($from, $to, FineDiff::$wordGranularity);
- return $diff->renderDiffToHTML();
- }
-}
diff --git a/lib/plugins/libkolab/vendor/finediff.php b/lib/plugins/libkolab/vendor/finediff.php
deleted file mode 100644
index b3c416c..0000000
--- a/lib/plugins/libkolab/vendor/finediff.php
+++ /dev/null
@@ -1,688 +0,0 @@
-<?php
-/**
-* FINE granularity DIFF
-*
-* Computes a set of instructions to convert the content of
-* one string into another.
-*
-* Copyright (c) 2011 Raymond Hill (http://raymondhill.net/blog/?p=441)
-*
-* Licensed under The MIT License
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy
-* of this software and associated documentation files (the "Software"), to deal
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the Software is
-* furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-* THE SOFTWARE.
-*
-* @copyright Copyright 2011 (c) Raymond Hill (http://raymondhill.net/blog/?p=441)
-* @link http://www.raymondhill.net/finediff/
-* @version 0.6
-* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
-*/
-
-/**
-* Usage (simplest):
-*
-* include 'finediff.php';
-*
-* // for the stock stack, granularity values are:
-* // FineDiff::$paragraphGranularity = paragraph/line level
-* // FineDiff::$sentenceGranularity = sentence level
-* // FineDiff::$wordGranularity = word level
-* // FineDiff::$characterGranularity = character level [default]
-*
-* $opcodes = FineDiff::getDiffOpcodes($from_text, $to_text [, $granularityStack = null] );
-* // store opcodes for later use...
-*
-* ...
-*
-* // restore $to_text from $from_text + $opcodes
-* include 'finediff.php';
-* $to_text = FineDiff::renderToTextFromOpcodes($from_text, $opcodes);
-*
-* ...
-*/
-
-/**
-* Persisted opcodes (string) are a sequence of atomic opcode.
-* A single opcode can be one of the following:
-* c | c{n} | d | d{n} | i:{c} | i{length}:{s}
-* 'c' = copy one character from source
-* 'c{n}' = copy n characters from source
-* 'd' = skip one character from source
-* 'd{n}' = skip n characters from source
-* 'i:{c} = insert character 'c'
-* 'i{n}:{s}' = insert string s, which is of length n
-*
-* Do not exist as of now, under consideration:
-* 'm{n}:{o} = move n characters from source o characters ahead.
-* It would be essentially a shortcut for a delete->copy->insert
-* command (swap) for when the inserted segment is exactly the same
-* as the deleted one, and with only a copy operation in between.
-* TODO: How often this case occurs? Is it worth it? Can only
-* be done as a postprocessing method (->optimize()?)
-*/
-abstract class FineDiffOp {
- abstract public function getFromLen();
- abstract public function getToLen();
- abstract public function getOpcode();
- }
-
-class FineDiffDeleteOp extends FineDiffOp {
- public function __construct($len) {
- $this->fromLen = $len;
- }
- public function getFromLen() {
- return $this->fromLen;
- }
- public function getToLen() {
- return 0;
- }
- public function getOpcode() {
- if ( $this->fromLen === 1 ) {
- return 'd';
- }
- return "d{$this->fromLen}";
- }
- }
-
-class FineDiffInsertOp extends FineDiffOp {
- public function __construct($text) {
- $this->text = $text;
- }
- public function getFromLen() {
- return 0;
- }
- public function getToLen() {
- return strlen($this->text);
- }
- public function getText() {
- return $this->text;
- }
- public function getOpcode() {
- $to_len = strlen($this->text);
- if ( $to_len === 1 ) {
- return "i:{$this->text}";
- }
- return "i{$to_len}:{$this->text}";
- }
- }
-
-class FineDiffReplaceOp extends FineDiffOp {
- public function __construct($fromLen, $text) {
- $this->fromLen = $fromLen;
- $this->text = $text;
- }
- public function getFromLen() {
- return $this->fromLen;
- }
- public function getToLen() {
- return strlen($this->text);
- }
- public function getText() {
- return $this->text;
- }
- public function getOpcode() {
- if ( $this->fromLen === 1 ) {
- $del_opcode = 'd';
- }
- else {
- $del_opcode = "d{$this->fromLen}";
- }
- $to_len = strlen($this->text);
- if ( $to_len === 1 ) {
- return "{$del_opcode}i:{$this->text}";
- }
- return "{$del_opcode}i{$to_len}:{$this->text}";
- }
- }
-
-class FineDiffCopyOp extends FineDiffOp {
- public function __construct($len) {
- $this->len = $len;
- }
- public function getFromLen() {
- return $this->len;
- }
- public function getToLen() {
- return $this->len;
- }
- public function getOpcode() {
- if ( $this->len === 1 ) {
- return 'c';
- }
- return "c{$this->len}";
- }
- public function increase($size) {
- return $this->len += $size;
- }
- }
-
-/**
-* FineDiff ops
-*
-* Collection of ops
-*/
-class FineDiffOps {
- public function appendOpcode($opcode, $from, $from_offset, $from_len) {
- if ( $opcode === 'c' ) {
- $edits[] = new FineDiffCopyOp($from_len);
- }
- else if ( $opcode === 'd' ) {
- $edits[] = new FineDiffDeleteOp($from_len);
- }
- else /* if ( $opcode === 'i' ) */ {
- $edits[] = new FineDiffInsertOp(substr($from, $from_offset, $from_len));
- }
- }
- public $edits = array();
- }
-
-/**
-* FineDiff class
-*
-* TODO: Document
-*
-*/
-class FineDiff {
-
- /**------------------------------------------------------------------------
- *
- * Public section
- *
- */
-
- /**
- * Constructor
- * ...
- * The $granularityStack allows FineDiff to be configurable so that
- * a particular stack tailored to the specific content of a document can
- * be passed.
- */
- public function __construct($from_text = '', $to_text = '', $granularityStack = null) {
- // setup stack for generic text documents by default
- $this->granularityStack = $granularityStack ? $granularityStack : FineDiff::$characterGranularity;
- $this->edits = array();
- $this->from_text = $from_text;
- $this->doDiff($from_text, $to_text);
- }
-
- public function getOps() {
- return $this->edits;
- }
-
- public function getOpcodes() {
- $opcodes = array();
- foreach ( $this->edits as $edit ) {
- $opcodes[] = $edit->getOpcode();
- }
- return implode('', $opcodes);
- }
-
- public function renderDiffToHTML() {
- $in_offset = 0;
- $html = '';
- foreach ( $this->edits as $edit ) {
- $n = $edit->getFromLen();
- if ( $edit instanceof FineDiffCopyOp ) {
- $html .= FineDiff::renderDiffToHTMLFromOpcode('c', $this->from_text, $in_offset, $n);
- }
- else if ( $edit instanceof FineDiffDeleteOp ) {
- $html .= FineDiff::renderDiffToHTMLFromOpcode('d', $this->from_text, $in_offset, $n);
- }
- else if ( $edit instanceof FineDiffInsertOp ) {
- $html .= FineDiff::renderDiffToHTMLFromOpcode('i', $edit->getText(), 0, $edit->getToLen());
- }
- else /* if ( $edit instanceof FineDiffReplaceOp ) */ {
- $html .= FineDiff::renderDiffToHTMLFromOpcode('d', $this->from_text, $in_offset, $n);
- $html .= FineDiff::renderDiffToHTMLFromOpcode('i', $edit->getText(), 0, $edit->getToLen());
- }
- $in_offset += $n;
- }
- return $html;
- }
-
- /**------------------------------------------------------------------------
- * Return an opcodes string describing the diff between a "From" and a
- * "To" string
- */
- public static function getDiffOpcodes($from, $to, $granularities = null) {
- $diff = new FineDiff($from, $to, $granularities);
- return $diff->getOpcodes();
- }
-
- /**------------------------------------------------------------------------
- * Return an iterable collection of diff ops from an opcodes string
- */
- public static function getDiffOpsFromOpcodes($opcodes) {
- $diffops = new FineDiffOps();
- FineDiff::renderFromOpcodes(null, $opcodes, array($diffops,'appendOpcode'));
- return $diffops->edits;
- }
-
- /**------------------------------------------------------------------------
- * Re-create the "To" string from the "From" string and an "Opcodes" string
- */
- public static function renderToTextFromOpcodes($from, $opcodes) {
- return FineDiff::renderFromOpcodes($from, $opcodes, array('FineDiff','renderToTextFromOpcode'));
- }
-
- /**------------------------------------------------------------------------
- * Render the diff to an HTML string
- */
- public static function renderDiffToHTMLFromOpcodes($from, $opcodes) {
- return FineDiff::renderFromOpcodes($from, $opcodes, array('FineDiff','renderDiffToHTMLFromOpcode'));
- }
-
- /**------------------------------------------------------------------------
- * Generic opcodes parser, user must supply callback for handling
- * single opcode
- */
- public static function renderFromOpcodes($from, $opcodes, $callback) {
- if ( !is_callable($callback) ) {
- return '';
- }
- $out = '';
- $opcodes_len = strlen($opcodes);
- $from_offset = $opcodes_offset = 0;
- while ( $opcodes_offset < $opcodes_len ) {
- $opcode = substr($opcodes, $opcodes_offset, 1);
- $opcodes_offset++;
- $n = intval(substr($opcodes, $opcodes_offset));
- if ( $n ) {
- $opcodes_offset += strlen(strval($n));
- }
- else {
- $n = 1;
- }
- if ( $opcode === 'c' ) { // copy n characters from source
- $out .= call_user_func($callback, 'c', $from, $from_offset, $n, '');
- $from_offset += $n;
- }
- else if ( $opcode === 'd' ) { // delete n characters from source
- $out .= call_user_func($callback, 'd', $from, $from_offset, $n, '');
- $from_offset += $n;
- }
- else /* if ( $opcode === 'i' ) */ { // insert n characters from opcodes
- $out .= call_user_func($callback, 'i', $opcodes, $opcodes_offset + 1, $n);
- $opcodes_offset += 1 + $n;
- }
- }
- return $out;
- }
-
- /**
- * Stock granularity stacks and delimiters
- */
-
- const paragraphDelimiters = "\n\r";
- public static $paragraphGranularity = array(
- FineDiff::paragraphDelimiters
- );
- const sentenceDelimiters = ".\n\r";
- public static $sentenceGranularity = array(
- FineDiff::paragraphDelimiters,
- FineDiff::sentenceDelimiters
- );
- const wordDelimiters = " \t.\n\r";
- public static $wordGranularity = array(
- FineDiff::paragraphDelimiters,
- FineDiff::sentenceDelimiters,
- FineDiff::wordDelimiters
- );
- const characterDelimiters = "";
- public static $characterGranularity = array(
- FineDiff::paragraphDelimiters,
- FineDiff::sentenceDelimiters,
- FineDiff::wordDelimiters,
- FineDiff::characterDelimiters
- );
-
- public static $textStack = array(
- ".",
- " \t.\n\r",
- ""
- );
-
- /**------------------------------------------------------------------------
- *
- * Private section
- *
- */
-
- /**
- * Entry point to compute the diff.
- */
- private function doDiff($from_text, $to_text) {
- $this->last_edit = false;
- $this->stackpointer = 0;
- $this->from_text = $from_text;
- $this->from_offset = 0;
- // can't diff without at least one granularity specifier
- if ( empty($this->granularityStack) ) {
- return;
- }
- $this->_processGranularity($from_text, $to_text);
- }
-
- /**
- * This is the recursive function which is responsible for
- * handling/increasing granularity.
- *
- * Incrementally increasing the granularity is key to compute the
- * overall diff in a very efficient way.
- */
- private function _processGranularity($from_segment, $to_segment) {
- $delimiters = $this->granularityStack[$this->stackpointer++];
- $has_next_stage = $this->stackpointer < count($this->granularityStack);
- foreach ( FineDiff::doFragmentDiff($from_segment, $to_segment, $delimiters) as $fragment_edit ) {
- // increase granularity
- if ( $fragment_edit instanceof FineDiffReplaceOp && $has_next_stage ) {
- $this->_processGranularity(
- substr($this->from_text, $this->from_offset, $fragment_edit->getFromLen()),
- $fragment_edit->getText()
- );
- }
- // fuse copy ops whenever possible
- else if ( $fragment_edit instanceof FineDiffCopyOp && $this->last_edit instanceof FineDiffCopyOp ) {
- $this->edits[count($this->edits)-1]->increase($fragment_edit->getFromLen());
- $this->from_offset += $fragment_edit->getFromLen();
- }
- else {
- /* $fragment_edit instanceof FineDiffCopyOp */
- /* $fragment_edit instanceof FineDiffDeleteOp */
- /* $fragment_edit instanceof FineDiffInsertOp */
- $this->edits[] = $this->last_edit = $fragment_edit;
- $this->from_offset += $fragment_edit->getFromLen();
- }
- }
- $this->stackpointer--;
- }
-
- /**
- * This is the core algorithm which actually perform the diff itself,
- * fragmenting the strings as per specified delimiters.
- *
- * This function is naturally recursive, however for performance purpose
- * a local job queue is used instead of outright recursivity.
- */
- private static function doFragmentDiff($from_text, $to_text, $delimiters) {
- // Empty delimiter means character-level diffing.
- // In such case, use code path optimized for character-level
- // diffing.
- if ( empty($delimiters) ) {
- return FineDiff::doCharDiff($from_text, $to_text);
- }
-
- $result = array();
-
- // fragment-level diffing
- $from_text_len = strlen($from_text);
- $to_text_len = strlen($to_text);
- $from_fragments = FineDiff::extractFragments($from_text, $delimiters);
- $to_fragments = FineDiff::extractFragments($to_text, $delimiters);
-
- $jobs = array(array(0, $from_text_len, 0, $to_text_len));
-
- $cached_array_keys = array();
-
- while ( $job = array_pop($jobs) ) {
-
- // get the segments which must be diff'ed
- list($from_segment_start, $from_segment_end, $to_segment_start, $to_segment_end) = $job;
-
- // catch easy cases first
- $from_segment_length = $from_segment_end - $from_segment_start;
- $to_segment_length = $to_segment_end - $to_segment_start;
- if ( !$from_segment_length || !$to_segment_length ) {
- if ( $from_segment_length ) {
- $result[$from_segment_start * 4] = new FineDiffDeleteOp($from_segment_length);
- }
- else if ( $to_segment_length ) {
- $result[$from_segment_start * 4 + 1] = new FineDiffInsertOp(substr($to_text, $to_segment_start, $to_segment_length));
- }
- continue;
- }
-
- // find longest copy operation for the current segments
- $best_copy_length = 0;
-
- $from_base_fragment_index = $from_segment_start;
-
- $cached_array_keys_for_current_segment = array();
-
- while ( $from_base_fragment_index < $from_segment_end ) {
- $from_base_fragment = $from_fragments[$from_base_fragment_index];
- $from_base_fragment_length = strlen($from_base_fragment);
- // performance boost: cache array keys
- if ( !isset($cached_array_keys_for_current_segment[$from_base_fragment]) ) {
- if ( !isset($cached_array_keys[$from_base_fragment]) ) {
- $to_all_fragment_indices = $cached_array_keys[$from_base_fragment] = array_keys($to_fragments, $from_base_fragment, true);
- }
- else {
- $to_all_fragment_indices = $cached_array_keys[$from_base_fragment];
- }
- // get only indices which falls within current segment
- if ( $to_segment_start > 0 || $to_segment_end < $to_text_len ) {
- $to_fragment_indices = array();
- foreach ( $to_all_fragment_indices as $to_fragment_index ) {
- if ( $to_fragment_index < $to_segment_start ) { continue; }
- if ( $to_fragment_index >= $to_segment_end ) { break; }
- $to_fragment_indices[] = $to_fragment_index;
- }
- $cached_array_keys_for_current_segment[$from_base_fragment] = $to_fragment_indices;
- }
- else {
- $to_fragment_indices = $to_all_fragment_indices;
- }
- }
- else {
- $to_fragment_indices = $cached_array_keys_for_current_segment[$from_base_fragment];
- }
- // iterate through collected indices
- foreach ( $to_fragment_indices as $to_base_fragment_index ) {
- $fragment_index_offset = $from_base_fragment_length;
- // iterate until no more match
- for (;;) {
- $fragment_from_index = $from_base_fragment_index + $fragment_index_offset;
- if ( $fragment_from_index >= $from_segment_end ) {
- break;
- }
- $fragment_to_index = $to_base_fragment_index + $fragment_index_offset;
- if ( $fragment_to_index >= $to_segment_end ) {
- break;
- }
- if ( $from_fragments[$fragment_from_index] !== $to_fragments[$fragment_to_index] ) {
- break;
- }
- $fragment_length = strlen($from_fragments[$fragment_from_index]);
- $fragment_index_offset += $fragment_length;
- }
- if ( $fragment_index_offset > $best_copy_length ) {
- $best_copy_length = $fragment_index_offset;
- $best_from_start = $from_base_fragment_index;
- $best_to_start = $to_base_fragment_index;
- }
- }
- $from_base_fragment_index += strlen($from_base_fragment);
- // If match is larger than half segment size, no point trying to find better
- // TODO: Really?
- if ( $best_copy_length >= $from_segment_length / 2) {
- break;
- }
- // no point to keep looking if what is left is less than
- // current best match
- if ( $from_base_fragment_index + $best_copy_length >= $from_segment_end ) {
- break;
- }
- }
-
- if ( $best_copy_length ) {
- $jobs[] = array($from_segment_start, $best_from_start, $to_segment_start, $best_to_start);
- $result[$best_from_start * 4 + 2] = new FineDiffCopyOp($best_copy_length);
- $jobs[] = array($best_from_start + $best_copy_length, $from_segment_end, $best_to_start + $best_copy_length, $to_segment_end);
- }
- else {
- $result[$from_segment_start * 4 ] = new FineDiffReplaceOp($from_segment_length, substr($to_text, $to_segment_start, $to_segment_length));
- }
- }
-
- ksort($result, SORT_NUMERIC);
- return array_values($result);
- }
-
- /**
- * Perform a character-level diff.
- *
- * The algorithm is quite similar to doFragmentDiff(), except that
- * the code path is optimized for character-level diff -- strpos() is
- * used to find out the longest common subequence of characters.
- *
- * We try to find a match using the longest possible subsequence, which
- * is at most the length of the shortest of the two strings, then incrementally
- * reduce the size until a match is found.
- *
- * I still need to study more the performance of this function. It
- * appears that for long strings, the generic doFragmentDiff() is more
- * performant. For word-sized strings, doCharDiff() is somewhat more
- * performant.
- */
- private static function doCharDiff($from_text, $to_text) {
- $result = array();
- $jobs = array(array(0, strlen($from_text), 0, strlen($to_text)));
- while ( $job = array_pop($jobs) ) {
- // get the segments which must be diff'ed
- list($from_segment_start, $from_segment_end, $to_segment_start, $to_segment_end) = $job;
- $from_segment_len = $from_segment_end - $from_segment_start;
- $to_segment_len = $to_segment_end - $to_segment_start;
-
- // catch easy cases first
- if ( !$from_segment_len || !$to_segment_len ) {
- if ( $from_segment_len ) {
- $result[$from_segment_start * 4 + 0] = new FineDiffDeleteOp($from_segment_len);
- }
- else if ( $to_segment_len ) {
- $result[$from_segment_start * 4 + 1] = new FineDiffInsertOp(substr($to_text, $to_segment_start, $to_segment_len));
- }
- continue;
- }
- if ( $from_segment_len >= $to_segment_len ) {
- $copy_len = $to_segment_len;
- while ( $copy_len ) {
- $to_copy_start = $to_segment_start;
- $to_copy_start_max = $to_segment_end - $copy_len;
- while ( $to_copy_start <= $to_copy_start_max ) {
- $from_copy_start = strpos(substr($from_text, $from_segment_start, $from_segment_len), substr($to_text, $to_copy_start, $copy_len));
- if ( $from_copy_start !== false ) {
- $from_copy_start += $from_segment_start;
- break 2;
- }
- $to_copy_start++;
- }
- $copy_len--;
- }
- }
- else {
- $copy_len = $from_segment_len;
- while ( $copy_len ) {
- $from_copy_start = $from_segment_start;
- $from_copy_start_max = $from_segment_end - $copy_len;
- while ( $from_copy_start <= $from_copy_start_max ) {
- $to_copy_start = strpos(substr($to_text, $to_segment_start, $to_segment_len), substr($from_text, $from_copy_start, $copy_len));
- if ( $to_copy_start !== false ) {
- $to_copy_start += $to_segment_start;
- break 2;
- }
- $from_copy_start++;
- }
- $copy_len--;
- }
- }
- // match found
- if ( $copy_len ) {
- $jobs[] = array($from_segment_start, $from_copy_start, $to_segment_start, $to_copy_start);
- $result[$from_copy_start * 4 + 2] = new FineDiffCopyOp($copy_len);
- $jobs[] = array($from_copy_start + $copy_len, $from_segment_end, $to_copy_start + $copy_len, $to_segment_end);
- }
- // no match, so delete all, insert all
- else {
- $result[$from_segment_start * 4] = new FineDiffReplaceOp($from_segment_len, substr($to_text, $to_segment_start, $to_segment_len));
- }
- }
- ksort($result, SORT_NUMERIC);
- return array_values($result);
- }
-
- /**
- * Efficiently fragment the text into an array according to
- * specified delimiters.
- * No delimiters means fragment into single character.
- * The array indices are the offset of the fragments into
- * the input string.
- * A sentinel empty fragment is always added at the end.
- * Careful: No check is performed as to the validity of the
- * delimiters.
- */
- private static function extractFragments($text, $delimiters) {
- // special case: split into characters
- if ( empty($delimiters) ) {
- $chars = str_split($text, 1);
- $chars[strlen($text)] = '';
- return $chars;
- }
- $fragments = array();
- $start = $end = 0;
- for (;;) {
- $end += strcspn($text, $delimiters, $end);
- $end += strspn($text, $delimiters, $end);
- if ( $end === $start ) {
- break;
- }
- $fragments[$start] = substr($text, $start, $end - $start);
- $start = $end;
- }
- $fragments[$start] = '';
- return $fragments;
- }
-
- /**
- * Stock opcode renderers
- */
- private static function renderToTextFromOpcode($opcode, $from, $from_offset, $from_len) {
- if ( $opcode === 'c' || $opcode === 'i' ) {
- return substr($from, $from_offset, $from_len);
- }
- return '';
- }
-
- private static function renderDiffToHTMLFromOpcode($opcode, $from, $from_offset, $from_len) {
- if ( $opcode === 'c' ) {
- return htmlentities(substr($from, $from_offset, $from_len));
- }
- else if ( $opcode === 'd' ) {
- $deletion = substr($from, $from_offset, $from_len);
- if ( strcspn($deletion, " \n\r") === 0 ) {
- $deletion = str_replace(array("\n","\r"), array('\n','\r'), $deletion);
- }
- return '<del>' . htmlentities($deletion) . '</del>';
- }
- else /* if ( $opcode === 'i' ) */ {
- return '<ins>' . htmlentities(substr($from, $from_offset, $from_len)) . '</ins>';
- }
- return '';
- }
- }
-
diff --git a/lib/plugins/libkolab/vendor/finediff_modifications.diff b/lib/plugins/libkolab/vendor/finediff_modifications.diff
deleted file mode 100644
index 3a9ad5c..0000000
--- a/lib/plugins/libkolab/vendor/finediff_modifications.diff
+++ /dev/null
@@ -1,121 +0,0 @@
---- finediff.php.orig 2014-07-29 14:24:10.000000000 +0200
-+++ finediff.php 2014-07-29 14:30:38.000000000 +0200
-@@ -234,25 +234,25 @@
-
- public function renderDiffToHTML() {
- $in_offset = 0;
-- ob_start();
-+ $html = '';
- foreach ( $this->edits as $edit ) {
- $n = $edit->getFromLen();
- if ( $edit instanceof FineDiffCopyOp ) {
-- FineDiff::renderDiffToHTMLFromOpcode('c', $this->from_text, $in_offset, $n);
-+ $html .= FineDiff::renderDiffToHTMLFromOpcode('c', $this->from_text, $in_offset, $n);
- }
- else if ( $edit instanceof FineDiffDeleteOp ) {
-- FineDiff::renderDiffToHTMLFromOpcode('d', $this->from_text, $in_offset, $n);
-+ $html .= FineDiff::renderDiffToHTMLFromOpcode('d', $this->from_text, $in_offset, $n);
- }
- else if ( $edit instanceof FineDiffInsertOp ) {
-- FineDiff::renderDiffToHTMLFromOpcode('i', $edit->getText(), 0, $edit->getToLen());
-+ $html .= FineDiff::renderDiffToHTMLFromOpcode('i', $edit->getText(), 0, $edit->getToLen());
- }
- else /* if ( $edit instanceof FineDiffReplaceOp ) */ {
-- FineDiff::renderDiffToHTMLFromOpcode('d', $this->from_text, $in_offset, $n);
-- FineDiff::renderDiffToHTMLFromOpcode('i', $edit->getText(), 0, $edit->getToLen());
-+ $html .= FineDiff::renderDiffToHTMLFromOpcode('d', $this->from_text, $in_offset, $n);
-+ $html .= FineDiff::renderDiffToHTMLFromOpcode('i', $edit->getText(), 0, $edit->getToLen());
- }
- $in_offset += $n;
- }
-- return ob_get_clean();
-+ return $html;
- }
-
- /**------------------------------------------------------------------------
-@@ -277,18 +277,14 @@
- * Re-create the "To" string from the "From" string and an "Opcodes" string
- */
- public static function renderToTextFromOpcodes($from, $opcodes) {
-- ob_start();
-- FineDiff::renderFromOpcodes($from, $opcodes, array('FineDiff','renderToTextFromOpcode'));
-- return ob_get_clean();
-+ return FineDiff::renderFromOpcodes($from, $opcodes, array('FineDiff','renderToTextFromOpcode'));
- }
-
- /**------------------------------------------------------------------------
- * Render the diff to an HTML string
- */
- public static function renderDiffToHTMLFromOpcodes($from, $opcodes) {
-- ob_start();
-- FineDiff::renderFromOpcodes($from, $opcodes, array('FineDiff','renderDiffToHTMLFromOpcode'));
-- return ob_get_clean();
-+ return FineDiff::renderFromOpcodes($from, $opcodes, array('FineDiff','renderDiffToHTMLFromOpcode'));
- }
-
- /**------------------------------------------------------------------------
-@@ -297,8 +293,9 @@
- */
- public static function renderFromOpcodes($from, $opcodes, $callback) {
- if ( !is_callable($callback) ) {
-- return;
-+ return '';
- }
-+ $out = '';
- $opcodes_len = strlen($opcodes);
- $from_offset = $opcodes_offset = 0;
- while ( $opcodes_offset < $opcodes_len ) {
-@@ -312,18 +309,19 @@
- $n = 1;
- }
- if ( $opcode === 'c' ) { // copy n characters from source
-- call_user_func($callback, 'c', $from, $from_offset, $n, '');
-+ $out .= call_user_func($callback, 'c', $from, $from_offset, $n, '');
- $from_offset += $n;
- }
- else if ( $opcode === 'd' ) { // delete n characters from source
-- call_user_func($callback, 'd', $from, $from_offset, $n, '');
-+ $out .= call_user_func($callback, 'd', $from, $from_offset, $n, '');
- $from_offset += $n;
- }
- else /* if ( $opcode === 'i' ) */ { // insert n characters from opcodes
-- call_user_func($callback, 'i', $opcodes, $opcodes_offset + 1, $n);
-+ $out .= call_user_func($callback, 'i', $opcodes, $opcodes_offset + 1, $n);
- $opcodes_offset += 1 + $n;
- }
- }
-+ return $out;
- }
-
- /**
-@@ -665,24 +663,26 @@
- */
- private static function renderToTextFromOpcode($opcode, $from, $from_offset, $from_len) {
- if ( $opcode === 'c' || $opcode === 'i' ) {
-- echo substr($from, $from_offset, $from_len);
-+ return substr($from, $from_offset, $from_len);
- }
-+ return '';
- }
-
- private static function renderDiffToHTMLFromOpcode($opcode, $from, $from_offset, $from_len) {
- if ( $opcode === 'c' ) {
-- echo htmlentities(substr($from, $from_offset, $from_len));
-+ return htmlentities(substr($from, $from_offset, $from_len));
- }
- else if ( $opcode === 'd' ) {
- $deletion = substr($from, $from_offset, $from_len);
- if ( strcspn($deletion, " \n\r") === 0 ) {
- $deletion = str_replace(array("\n","\r"), array('\n','\r'), $deletion);
- }
-- echo '<del>', htmlentities($deletion), '</del>';
-+ return '<del>' . htmlentities($deletion) . '</del>';
- }
- else /* if ( $opcode === 'i' ) */ {
-- echo '<ins>', htmlentities(substr($from, $from_offset, $from_len)), '</ins>';
-+ return '<ins>' . htmlentities(substr($from, $from_offset, $from_len)) . '</ins>';
- }
-+ return '';
- }
- }
-
diff --git a/lib/plugins/managesieve/Changelog b/lib/plugins/managesieve/Changelog
deleted file mode 100644
index 5255d5b..0000000
--- a/lib/plugins/managesieve/Changelog
+++ /dev/null
@@ -1,325 +0,0 @@
-* version 8.2 [2015-01-14]
------------------------------------------------------------
-- Fix bug where actions without if/elseif/else in sieve scripts were skipped
-- Support "not allof" test as a negation of all sub-tests
-- Fix bug where vacation rule was saved to wrong script if managesieve_kolab_master=true
-- Improve procedure of script selection to write a vacation rule
-
-* version 8.1 [2014-12-09]
------------------------------------------------------------
-- Added simple API to manage vacation rule
-- Fix missing css/js scripts in filter form in mail task
-- Fix default vacation status (#1490019)
-- Make possible to set vacation start/end date and time
-- Fix compatibility with contextmenu plugin
-
-* version 8.0 [2014-07-16]
------------------------------------------------------------
-- Fix bug where non-existing (or unsubscribed) folder wasn't listed in folder selector (#1489956)
-- Added optional separate interface for out-of-office management (#1488266)
-- Fix disabled "create filter" action
-- Fix enotify/notify extension handling
-- Improved UI accessibility
-- Added option to specify connection socket parameters - managesieve_conn_options
-- Support vacation date rules without date extension (#1489978)
-
-* version 7.2 [2014-02-14]
------------------------------------------------------------
-- Nicely handle server-side modification of script names (#1489412)
-- Add Filters tab/section using plugin API hook
-- Fix issue where folder selector wasn't visible on new filter form
-- Fix issue where multi-select fields were not visible in new filter action rows (#1489600)
-- Fix issue in displaying filter form when managesieve_kolab_master=true
- and sieve variables extension is supported by the server (#1489599)
-- Fix wrong action folder selection if managesieve_domains is not empty (#1489617)
-- Fix filter creation from an email when preview frame is disabled (#1489647)
-
-* version 7.1 [2013-11-22]
------------------------------------------------------------
-- lib/Net_Sieve.php moved to Roundcube /lib directory
-- Added managesieve_domains option to limit redirect destinations
-- Fix bug where at least one additional address of vacation message was required (#1489345)
-- Fix so i;ascii-numeric comparator is not forced as default for :count and :value operators
-- Fix date/currentdate related form issues and comparators handling (#1489346)
-- Fix a bug where deleted filter was not removed from the list
-
-* version 7.0 [2013-09-09]
------------------------------------------------------------
-- Add vacation-seconds extension support (RFC 6131)
-- Several script parser code improvements
-- Support string list arguments in filter form (#1489018)
-- Support date, currendate and index tests - RFC5260 (#1488120)
-- Split plugin file into two files
-- Fix handling of &, <, > characters in scripts/filter names (#1489208)
-- Support 'keep' action (#1489226)
-- Add common headers to header selector (#1489271)
-
-* version 6.2 [2013-02-17]
------------------------------------------------------------
-- Support tls:// prefix in managesieve_host option
-- Removed depracated functions usage
-- Don't trim whitespace in folder names (#1488955)
-
-* version 6.1 [2012-12-21]
------------------------------------------------------------
-- Fixed filter activation/deactivation confirmation message (#1488765)
-- Moved rcube_* classes to <plugin>/lib/Roundcube for compat. with Roundcube Framework autoloader
-- Fixed filter selection after filter deletion (#1488832)
-- Fixed compatibility with jQueryUI-1.9
-- Don't force 'stop' action on last rule in a script
-
-* version 6.0 [2012-10-03]
------------------------------------------------------------
-- Fixed issue with DBMail bug [http://pear.php.net/bugs/bug.php?id=19077] (#1488594)
-- Added support for enotify/notify (RFC5435, RFC5436, draft-ietf-sieve-notify-00)
-- Change default port to 4190 (IANA-allocated), add port auto-detection (#1488713)
-- Added request size limits detection and script corruption prevention (#1488648)
-- Fix so scripts listed in managesieve_filename_exceptions aren't displayed on the list (#1488724)
-
-* version 5.2 [2012-07-24]
------------------------------------------------------------
-- Added GUI for variables setting - RFC5229 (patch from Paweł Słowik)
-- Fixed scrollbars in Larry's iframes
-- Fix performance issue in message_headers_output hook handling
-
-* version 5.1 [2012-06-21]
------------------------------------------------------------
-- Fixed filter popup width (for non-english localizations)
-- Fixed tokenizer infinite loop on invalid script content
-- Larry skin support
-- Fixed custom header name validity check, made RFC2822-compliant
-
-* version 5.0 [2012-01-05]
------------------------------------------------------------
-- Fixed setting test type to :is when none is specified
-- Fixed javascript error in IE8
-- Fixed possible ID duplication when adding filter rules very fast (#1488288)
-- Fixed bug where drag layer wasn't removed when dragging was ended over sets list
-
-* 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]
------------------------------------------------------------
-- Fixed handling of error in Net_Sieve::listScripts()
-- Fixed handling of REFERRAL responses (http://pear.php.net/bugs/bug.php?id=17107)
-- Fixed bug where wrong folders hierarchy was displayed on folders listing
-
-* version 4.2 [2011-05-24]
------------------------------------------------------------
-- Moved elsif replacement code to handle only imports from other formats
-- Fixed mod_mailbox() usage for newer Roundcube versions
-- Fixed regex extension (error: regex require missing)
-
-* version 4.1 [2011-03-07]
------------------------------------------------------------
-- Fix fileinto target is always INBOX (#1487776)
-- Fix escaping of backslash character in quoted strings (#1487780)
-- Fix handling of non-safe characters (double-quote, backslash)
- or UTF-8 characters (dovecot's implementation bug workaround)
- in script names
-- Fix saving of a script using flags extension on servers with imap4flags support (#1487825)
-
-* version 4.0 [2011-02-10]
------------------------------------------------------------
-- Fix STARTTLS for timsieved < 2.3.10
-- Added :regex and :matches support (#1487746)
-- Added setflag/addflag/removeflag support (#1487449)
-- Added support for vacation :subject field (#1487120)
-- rcube_sieve_script class moved to separate file
-- Moved javascript code from skin templates into managesieve.js file
-
-* version 3.0 [2011-02-01]
------------------------------------------------------------
-- Added support for SASL proxy authentication (#1486691)
-- Fixed parsing of scripts with \r\n line separator
-- Apply forgotten changes for form errors handling
-- Fix multi-line strings parsing (#1487685)
-- Added tests for script parser
-- Rewritten script parser
-- Fix double request when clicking on Filters tab using Firefox
-
-* version 2.10 [2010-10-10]
------------------------------------------------------------
-- Fixed import from Avelsieve
-- Use localized size units (#1486976)
-- Added support for relational operators and i;ascii-numeric comparator
-- Added popups with form errors
-
-* version 2.9 [2010-08-02]
------------------------------------------------------------
-- Fixed vacation parameters parsing (#1486883)
-
-* version 2.8 [2010-07-08]
------------------------------------------------------------
-- Added managesieve_auth_type option (#1486731)
-
-* version 2.7 [2010-07-06]
------------------------------------------------------------
-- Update Net_Sieve to version 1.3.0 (fixes LOGIN athentication)
-- Added support for copying and copy sending of messages (COPY extension)
-
-* version 2.6 [2010-06-03]
------------------------------------------------------------
-- Support %n and %d variables in managesieve_host option
-
-* version 2.5 [2010-05-04]
------------------------------------------------------------
-- Fix filters set label after activation
-- Fix filters set activation, add possibility to deactivate sets (#1486699)
-- Fix download button state when sets list is empty
-- Fix errors when sets list is empty
-
-* version 2.4 [2010-04-01]
------------------------------------------------------------
-- Fixed bug in DIGEST-MD5 authentication (http://pear.php.net/bugs/bug.php?id=17285)
-- Fixed disabling rules with many tests
-- Small css unification with core
-- Scripts import/export
-
-* version 2.3 [2010-03-18]
------------------------------------------------------------
-- Added import from Horde-INGO
-- Support for more than one match using if+stop instead of if+elsif structures (#1486078)
-- Support for selectively disabling rules within a single sieve script (#1485882)
-- Added vertical splitter
-
-* version 2.2 [2010-02-06]
------------------------------------------------------------
-- Fix handling of "<>" characters in filter names (#1486477)
-
-* version 2.1 [2010-01-12]
------------------------------------------------------------
-- Fix "require" structure generation when many modules are used
-- Fix problem with '<' and '>' characters in header tests
-
-* version 2.0 [2009-11-02]
------------------------------------------------------------
-- Added 'managesieve_debug' option
-- Added multi-script support
-- Small css improvements + sprite image buttons
-- PEAR::NetSieve 1.2.0b1
-
-* version 1.7 [2009-09-20]
------------------------------------------------------------
-- Support multiple managesieve hosts using %h variable
- in managesieve_host option
-- Fix first rule deleting (#1486140)
-
-* version 1.6 [2009-09-08]
------------------------------------------------------------
-- Fix warning when importing squirrelmail rules
-- Fix handling of "true" as "anyof (true)" test
-
-* version 1.5 [2009-09-04]
------------------------------------------------------------
-- Added es_ES, ua_UA localizations
-- Added 'managesieve_mbox_encoding' option
-
-* version 1.4 [2009-07-29]
------------------------------------------------------------
-- Updated PEAR::Net_Sieve to 1.1.7
-
-* version 1.3 [2009-07-24]
------------------------------------------------------------
-- support more languages
-- support config.inc.php file
-
-* version 1.2 [2009-06-28]
------------------------------------------------------------
-- Support IMAP namespaces in fileinto (#1485943)
-- Added it_IT localization
-
-* version 1.1 [2009-05-27]
------------------------------------------------------------
-- Added new icons
-- Added support for headers lists (coma-separated) in rules
-- Added de_CH localization
-
-* version 1.0 [2009-05-21]
------------------------------------------------------------
-- Rewritten using plugin API
-- Added hu_HU localization (Tamas Tevesz)
-
-* version beta7 (svn-r2300) [2009-03-01]
------------------------------------------------------------
-- Added SquirrelMail script auto-import (Jonathan Ernst)
-- Added 'vacation' support (Jonathan Ernst & alec)
-- Added 'stop' support (Jonathan Ernst)
-- Added option for extensions disabling (Jonathan Ernst & alec)
-- Added fi_FI, nl_NL, bg_BG localization
-- Small style fixes
-
-* version 0.2-stable1 (svn-r2205) [2009-01-03]
------------------------------------------------------------
-- Fix moving down filter row
-- Fixes for compressed js files in stable release package
-- Created patch for svn version r2205
-
-* version 0.2-stable [2008-12-31]
------------------------------------------------------------
-- Added ru_RU, fr_FR, zh_CN translation
-- Fixes for Roundcube 0.2-stable
-
-* version 0.2-beta [2008-09-21]
------------------------------------------------------------
-- Small css fixes for IE
-- Fixes for Roundcube 0.2-beta
-
-* version beta6 [2008-08-08]
------------------------------------------------------------
-- Added de_DE translation
-- Fix for Roundcube r1634
-
-* version beta5 [2008-06-10]
------------------------------------------------------------
-- Fixed 'exists' operators
-- Fixed 'not*' operators for custom headers
-- Fixed filters deleting
-
-* version beta4 [2008-06-09]
------------------------------------------------------------
-- Fix for Roundcube r1490
-
-* version beta3 [2008-05-22]
------------------------------------------------------------
-- Fixed textarea error class setting
-- Added pagetitle setting
-- Added option 'managesieve_replace_delimiter'
-- Fixed errors on IE (still need some css fixes)
-
-* version beta2 [2008-05-20]
------------------------------------------------------------
-- Use 'if' only for first filter and 'elsif' for the rest
-
-* version beta1 [2008-05-15]
------------------------------------------------------------
-- Initial version for Roundcube r1388.
diff --git a/lib/plugins/managesieve/composer.json b/lib/plugins/managesieve/composer.json
deleted file mode 100644
index 6d640da..0000000
--- a/lib/plugins/managesieve/composer.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "name": "roundcube/managesieve",
- "type": "roundcube-plugin",
- "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.",
- "license": "GPLv3+",
- "version": "8.2",
- "authors": [
- {
- "name": "Aleksander Machniak",
- "email": "alec@alec.pl",
- "role": "Lead"
- }
- ],
- "repositories": [
- {
- "type": "composer",
- "url": "http://plugins.roundcube.net"
- },
- {
- "type": "pear",
- "url": "http://pear.php.net/"
- }
- ],
- "require": {
- "php": ">=5.3.0",
- "roundcube/plugin-installer": ">=0.1.3",
- "pear-pear/Net_Sieve": ">=1.3.2"
- }
-}
diff --git a/lib/plugins/managesieve/config.inc.php.dist b/lib/plugins/managesieve/config.inc.php.dist
deleted file mode 100644
index b9f9a50..0000000
--- a/lib/plugins/managesieve/config.inc.php.dist
+++ /dev/null
@@ -1,90 +0,0 @@
-<?php
-
-// managesieve server port. When empty the port will be determined automatically
-// using getservbyname() function, with 4190 as a fallback.
-$config['managesieve_port'] = null;
-
-// managesieve server address, default is localhost.
-// Replacement variables supported in host name:
-// %h - user's IMAP hostname
-// %n - http hostname ($_SERVER['SERVER_NAME'])
-// %d - domain (http hostname without the first part)
-// For example %n = mail.domain.tld, %d = domain.tld
-$config['managesieve_host'] = 'localhost';
-
-// authentication method. Can be CRAM-MD5, DIGEST-MD5, PLAIN, LOGIN, EXTERNAL
-// or none. Optional, defaults to best method supported by server.
-$config['managesieve_auth_type'] = null;
-
-// Optional managesieve authentication identifier to be used as authorization proxy.
-// Authenticate as a different user but act on behalf of the logged in user.
-// Works with PLAIN and DIGEST-MD5 auth.
-$config['managesieve_auth_cid'] = null;
-
-// Optional managesieve authentication password to be used for imap_auth_cid
-$config['managesieve_auth_pw'] = null;
-
-// use or not TLS for managesieve server connection
-// Note: tls:// prefix in managesieve_host is also supported
-$config['managesieve_usetls'] = false;
-
-// Connection scket context options
-// See http://php.net/manual/en/context.ssl.php
-// The example below enables server certificate validation
-//$config['managesieve_conn_options'] = array(
-// 'ssl' => array(
-// 'verify_peer' => true,
-// 'verify_depth' => 3,
-// 'cafile' => '/etc/openssl/certs/ca.crt',
-// ),
-// );
-$config['managesieve_conn_options'] = null;
-
-// default contents of filters script (eg. default spam filter)
-$config['managesieve_default'] = '/etc/dovecot/sieve/global';
-
-// The name of the script which will be used when there's no user script
-$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
-$config['managesieve_mbox_encoding'] = 'UTF-8';
-
-// I need this because my dovecot (with listescape plugin) uses
-// ':' delimiter, but creates folders with dot delimiter
-$config['managesieve_replace_delimiter'] = '';
-
-// disabled sieve extensions (body, copy, date, editheader, encoded-character,
-// envelope, environment, ereject, fileinto, ihave, imap4flags, index,
-// mailbox, mboxmetadata, regex, reject, relational, servermetadata,
-// spamtest, spamtestplus, subaddress, vacation, variables, virustest, etc.
-// Note: not all extensions are implemented
-$config['managesieve_disabled_extensions'] = array();
-
-// Enables debugging of conversation with sieve server. Logs it into <log_dir>/sieve
-$config['managesieve_debug'] = false;
-
-// Enables features described in http://wiki.kolab.org/KEP:14
-$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.
-$config['managesieve_filename_extension'] = '.sieve';
-
-// List of reserved script names (without extension).
-// Scripts listed here will be not presented to the user.
-$config['managesieve_filename_exceptions'] = array();
-
-// List of domains limiting destination emails in redirect action
-// If not empty, user will need to select domain from a list
-$config['managesieve_domains'] = array();
-
-// Enables separate management interface for vacation responses (out-of-office)
-// 0 - no separate section (default),
-// 1 - add Vacation section,
-// 2 - add Vacation section, but hide Filters section
-$config['managesieve_vacation'] = 0;
-
-// Supported methods of notify extension. Default: 'mailto'
-$config['managesieve_notify_methods'] = array('mailto');
diff --git a/lib/plugins/managesieve/lib/Roundcube/rcube_sieve.php b/lib/plugins/managesieve/lib/Roundcube/rcube_sieve.php
deleted file mode 100644
index 389c850..0000000
--- a/lib/plugins/managesieve/lib/Roundcube/rcube_sieve.php
+++ /dev/null
@@ -1,389 +0,0 @@
-<?php
-
-/**
- * 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 as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-// Managesieve Protocol: RFC5804
-
-class rcube_sieve
-{
- private $sieve; // Net_Sieve object
- private $error = false; // error flag
- private $list = array(); // scripts list
-
- public $script; // rcube_sieve_script object
- public $current; // name of currently loaded script
- private $exts; // array of supported extensions
-
- const ERROR_CONNECTION = 1;
- const ERROR_LOGIN = 2;
- const ERROR_NOT_EXISTS = 3; // script not exists
- const ERROR_INSTALL = 4; // script installation
- const ERROR_ACTIVATE = 5; // script activation
- const ERROR_DELETE = 6; // script deletion
- const ERROR_INTERNAL = 7; // internal error
- const ERROR_DEACTIVATE = 8; // script activation
- const ERROR_OTHER = 255; // other/unknown error
-
-
- /**
- * Object constructor
- *
- * @param string Username (for managesieve login)
- * @param string Password (for managesieve login)
- * @param string Managesieve server hostname/address
- * @param string Managesieve server port number
- * @param string Managesieve authentication method
- * @param boolean Enable/disable TLS use
- * @param array Disabled extensions
- * @param boolean Enable/disable debugging
- * @param string Proxy authentication identifier
- * @param string Proxy authentication password
- * @param array List of options to pass to stream_context_create().
- */
- public function __construct($username, $password='', $host='localhost', $port=2000,
- $auth_type=null, $usetls=true, $disabled=array(), $debug=false,
- $auth_cid=null, $auth_pw=null, $options=array())
- {
- $this->sieve = new Net_Sieve();
-
- if ($debug) {
- $this->sieve->setDebug(true, array($this, 'debug_handler'));
- }
-
- if (PEAR::isError($this->sieve->connect($host, $port, $options, $usetls))) {
- return $this->_set_error(self::ERROR_CONNECTION);
- }
-
- if (!empty($auth_cid)) {
- $authz = $username;
- $username = $auth_cid;
- $password = $auth_pw;
- }
-
- if (PEAR::isError($this->sieve->login($username, $password,
- $auth_type ? strtoupper($auth_type) : null, $authz))
- ) {
- return $this->_set_error(self::ERROR_LOGIN);
- }
-
- $this->exts = $this->get_extensions();
-
- // 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() {
- $this->sieve->disconnect();
- }
-
- /**
- * Getter for error code
- */
- public function error()
- {
- return $this->error ? $this->error : false;
- }
-
- /**
- * Saves current script into server
- */
- public function save($name = null)
- {
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- if (!$this->script)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- if (!$name)
- $name = $this->current;
-
- $script = $this->script->as_text();
-
- if (!$script)
- $script = '/* empty script */';
-
- if (PEAR::isError($this->sieve->installScript($name, $script)))
- return $this->_set_error(self::ERROR_INSTALL);
-
- return true;
- }
-
- /**
- * Saves text script into server
- */
- public function save_script($name, $content = null)
- {
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- if (!$content)
- $content = '/* empty script */';
-
- if (PEAR::isError($this->sieve->installScript($name, $content)))
- return $this->_set_error(self::ERROR_INSTALL);
-
- return true;
- }
-
- /**
- * Activates specified script
- */
- public function activate($name = null)
- {
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- if (!$name)
- $name = $this->current;
-
- if (PEAR::isError($this->sieve->setActive($name)))
- return $this->_set_error(self::ERROR_ACTIVATE);
-
- return true;
- }
-
- /**
- * De-activates specified script
- */
- public function deactivate()
- {
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- if (PEAR::isError($this->sieve->setActive('')))
- return $this->_set_error(self::ERROR_DEACTIVATE);
-
- return true;
- }
-
- /**
- * Removes specified script
- */
- public function remove($name = null)
- {
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- if (!$name)
- $name = $this->current;
-
- // script must be deactivated first
- if ($name == $this->sieve->getActive())
- if (PEAR::isError($this->sieve->setActive('')))
- return $this->_set_error(self::ERROR_DELETE);
-
- if (PEAR::isError($this->sieve->removeScript($name)))
- return $this->_set_error(self::ERROR_DELETE);
-
- if ($name == $this->current)
- $this->current = null;
-
- return true;
- }
-
- /**
- * Gets list of supported by server Sieve extensions
- */
- public function get_extensions()
- {
- if ($this->exts)
- return $this->exts;
-
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- $ext = $this->sieve->getExtensions();
-
- if (PEAR::isError($ext)) {
- return array();
- }
-
- // we're working on lower-cased names
- $ext = array_map('strtolower', (array) $ext);
-
- if ($this->script) {
- $supported = $this->script->get_extensions();
- foreach ($ext as $idx => $ext_name)
- if (!in_array($ext_name, $supported))
- unset($ext[$idx]);
- }
-
- return array_values($ext);
- }
-
- /**
- * Gets list of scripts from server
- */
- public function get_scripts()
- {
- if (!$this->list) {
-
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- $list = $this->sieve->listScripts();
-
- if (PEAR::isError($list))
- return $this->_set_error(self::ERROR_OTHER);
-
- $this->list = $list;
- }
-
- return $this->list;
- }
-
- /**
- * Returns active script name
- */
- public function get_active()
- {
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- return $this->sieve->getActive();
- }
-
- /**
- * Loads script by name
- */
- public function load($name)
- {
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- if ($this->current == $name)
- return true;
-
- $script = $this->sieve->getScript($name);
-
- if (PEAR::isError($script))
- return $this->_set_error(self::ERROR_OTHER);
-
- // try to parse from Roundcube format
- $this->script = $this->_parse($script);
-
- $this->current = $name;
-
- return true;
- }
-
- /**
- * Loads script from text content
- */
- public function load_script($script)
- {
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- // try to parse from Roundcube format
- $this->script = $this->_parse($script);
- }
-
- /**
- * Creates rcube_sieve_script object from text script
- */
- private function _parse($txt)
- {
- // 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;
- }
- }
- if (!empty($script->content[$idx+1]) && $script->content[$idx+1]['type'] != 'if') {
- $script->content[$idx]['actions'][] = array('type' => 'stop');
- }
- }
- }
-
- return $script;
- }
-
- /**
- * Gets specified script as text
- */
- public function get_script($name)
- {
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- $content = $this->sieve->getScript($name);
-
- if (PEAR::isError($content))
- return $this->_set_error(self::ERROR_OTHER);
-
- return $content;
- }
-
- /**
- * Creates empty script or copy of other script
- */
- public function copy($name, $copy)
- {
- if (!$this->sieve)
- return $this->_set_error(self::ERROR_INTERNAL);
-
- if ($copy) {
- $content = $this->sieve->getScript($copy);
-
- if (PEAR::isError($content))
- return $this->_set_error(self::ERROR_OTHER);
- }
-
- return $this->save_script($name, $content);
- }
-
- private function _set_error($error)
- {
- $this->error = $error;
- return false;
- }
-
- /**
- * This is our own debug handler for connection
- */
- public function debug_handler(&$sieve, $message)
- {
- rcube::write_log('sieve', preg_replace('/\r\n$/', '', $message));
- }
-}
diff --git a/lib/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php b/lib/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php
deleted file mode 100644
index d412e17..0000000
--- a/lib/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php
+++ /dev/null
@@ -1,2381 +0,0 @@
-<?php
-
-/**
- * Managesieve (Sieve Filters) Engine
- *
- * Engine part of Managesieve plugin implementing UI and backend access.
- *
- * Copyright (C) 2008-2014, The Roundcube Dev Team
- * Copyright (C) 2011-2014, 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 as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-class rcube_sieve_engine
-{
- protected $rc;
- protected $sieve;
- protected $errors;
- protected $form;
- protected $tips = array();
- protected $script = array();
- protected $exts = array();
- protected $list;
- protected $active = array();
- protected $headers = array(
- 'subject' => 'Subject',
- 'from' => 'From',
- 'to' => 'To',
- );
- protected $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",
- );
- protected $notify_methods = array(
- 'mailto',
- // 'sms',
- // 'tel',
- );
- protected $notify_importance_options = array(
- 3 => 'notifyimportancelow',
- 2 => 'notifyimportancenormal',
- 1 => 'notifyimportancehigh'
- );
-
- const VERSION = '8.2';
- const PROGNAME = 'Roundcube (Managesieve)';
- const PORT = 4190;
-
-
- /**
- * Class constructor
- */
- function __construct($plugin)
- {
- $this->rc = rcube::get_instance();
- $this->plugin = $plugin;
- }
-
- /**
- * Loads configuration, initializes plugin (including sieve connection)
- */
- function start($mode = null)
- {
- // register UI objects
- $this->rc->output->add_handlers(array(
- 'filterslist' => array($this, 'filters_list'),
- 'filtersetslist' => array($this, 'filtersets_list'),
- 'filterframe' => array($this, 'filter_frame'),
- 'filterform' => array($this, 'filter_form'),
- 'filtersetform' => array($this, 'filterset_form'),
- ));
-
- // connect to managesieve server
- $error = $this->connect($_SESSION['username'], $this->rc->decrypt($_SESSION['password']));
-
- // load current/active script
- if (!$error) {
- // Get list of scripts
- $list = $this->list_scripts();
-
- // reset current script when entering filters UI (#1489412)
- if ($this->rc->action == 'plugin.managesieve') {
- $this->rc->session->remove('managesieve_current');
- }
-
- if ($mode != 'vacation') {
- if (!empty($_GET['_set']) || !empty($_POST['_set'])) {
- $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true);
- }
- else if (!empty($_SESSION['managesieve_current'])) {
- $script_name = $_SESSION['managesieve_current'];
- }
- }
-
- $error = $this->load_script($script_name);
- }
-
- // finally set script objects
- if ($error) {
- switch ($error) {
- case rcube_sieve::ERROR_CONNECTION:
- case rcube_sieve::ERROR_LOGIN:
- $this->rc->output->show_message('managesieve.filterconnerror', 'error');
- rcube::raise_error(array('code' => 403, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Unable to connect to managesieve on $host:$port"), true, false);
- break;
-
- default:
- $this->rc->output->show_message('managesieve.filterunknownerror', 'error');
- break;
- }
-
- // reload interface in case of possible error when specified script wasn't found (#1489412)
- if ($script_name !== null && !empty($list) && !in_array($script_name, $list)) {
- $this->rc->output->command('reload', 500);
- }
-
- // to disable 'Add filter' button set env variable
- $this->rc->output->set_env('filterconnerror', true);
- $this->script = array();
- }
- else {
- $this->exts = $this->sieve->get_extensions();
- $this->init_script();
- $this->rc->output->set_env('currentset', $this->sieve->current);
- $_SESSION['managesieve_current'] = $this->sieve->current;
- }
-
- return $error;
- }
-
- /**
- * Connect to configured managesieve server
- *
- * @param string $username User login
- * @param string $password User password
- *
- * @return int Connection status: 0 on success, >0 on failure
- */
- public function connect($username, $password)
- {
- // Get connection parameters
- $host = $this->rc->config->get('managesieve_host', 'localhost');
- $port = $this->rc->config->get('managesieve_port');
- $tls = $this->rc->config->get('managesieve_usetls', false);
-
- $host = rcube_utils::parse_host($host);
- $host = rcube_utils::idn_to_ascii($host);
-
- // remove tls:// prefix, set TLS flag
- if (($host = preg_replace('|^tls://|i', '', $host, 1, $cnt)) && $cnt) {
- $tls = true;
- }
-
- if (empty($port)) {
- $port = getservbyname('sieve', 'tcp');
- if (empty($port)) {
- $port = self::PORT;
- }
- }
-
- $plugin = $this->rc->plugins->exec_hook('managesieve_connect', array(
- 'user' => $username,
- 'password' => $password,
- 'host' => $host,
- 'port' => $port,
- 'usetls' => $tls,
- 'auth_type' => $this->rc->config->get('managesieve_auth_type'),
- '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'),
- 'socket_options' => $this->rc->config->get('managesieve_conn_options'),
- ));
-
- // try to connect to managesieve server and to fetch the script
- $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'],
- $plugin['socket_options']
- );
-
- return $this->sieve->error();
- }
-
- /**
- * Load specified (or active) script
- *
- * @param string $script_name Optional script name
- *
- * @return int Connection status: 0 on success, >0 on failure
- */
- protected function load_script($script_name = null)
- {
- // Get list of scripts
- $list = $this->list_scripts();
-
- if ($script_name === null || $script_name === '') {
- // get (first) active script
- if (!empty($this->active)) {
- $script_name = $this->active[0];
- }
- else if ($list) {
- $script_name = $list[0];
- }
- // create a new (initial) script
- else {
- // if script not exists build default script contents
- $script_file = $this->rc->config->get('managesieve_default');
- $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)) {
- $this->activate_script($script_name);
- $this->list[] = $script_name;
- }
- }
- }
-
- if ($script_name) {
- $this->sieve->load($script_name);
- }
-
- return $this->sieve->error();
- }
-
- /**
- * User interface actions handler
- */
- function actions()
- {
- $error = $this->start();
-
- // Handle user requests
- if ($action = rcube_utils::get_input_value('_act', rcube_utils::INPUT_GPC)) {
- $fid = (int) rcube_utils::get_input_value('_fid', rcube_utils::INPUT_POST);
-
- if ($action == 'delete' && !$error) {
- if (isset($this->script[$fid])) {
- if ($this->sieve->script->delete_rule($fid))
- $result = $this->save_script();
-
- 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 == 'move' && !$error) {
- if (isset($this->script[$fid])) {
- $to = (int) rcube_utils::get_input_value('_to', rcube_utils::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) {
- $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.moveerror', 'error');
- }
- }
- }
- else if ($action == 'act' && !$error) {
- if (isset($this->script[$fid])) {
- $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) {
- 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 {
- 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 = rcube_utils::get_input_value('_set', rcube_utils::INPUT_POST, true);
- $result = $this->activate_script($script_name);
- $kep14 = $this->rc->config->get('managesieve_kolab_master');
-
- if ($result === true) {
- $this->rc->output->set_env('active_sets', $this->active);
- $this->rc->output->show_message('managesieve.setactivated', 'confirmation');
- $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) {
- $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_POST, true);
- $result = $this->deactivate_script($script_name);
-
- if ($result === true) {
- $this->rc->output->set_env('active_sets', $this->active);
- $this->rc->output->show_message('managesieve.setdeactivated', 'confirmation');
- $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 = rcube_utils::get_input_value('_set', rcube_utils::INPUT_POST, true);
- $result = $this->remove_script($script_name);
-
- if ($result === true) {
- $this->rc->output->show_message('managesieve.setdeleted', 'confirmation');
- $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 = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true);
- $script = $this->sieve->get_script($script_name);
-
- if (PEAR::isError($script))
- exit;
-
- $browser = new rcube_browser;
-
- // send download headers
- header("Content-Type: application/octet-stream");
- header("Content-Length: ".strlen($script));
-
- if ($browser->ie) {
- header("Content-Type: application/force-download");
- $filename = rawurlencode($script_name);
- }
- else {
- $filename = addcslashes($script_name, '\\"');
- }
-
- header("Content-Disposition: attachment; filename=\"$filename.txt\"");
- echo $script;
- exit;
- }
- else if ($action == 'list') {
- $result = $this->list_rules();
-
- $this->rc->output->command('managesieve_updatelist', 'list', array('list' => $result));
- }
- else if ($action == 'ruleadd') {
- $rid = rcube_utils::get_input_value('_rid', rcube_utils::INPUT_POST);
- $id = $this->genid();
- $content = $this->rule_div($fid, $id, false);
-
- $this->rc->output->command('managesieve_rulefill', $content, $id, $rid);
- }
- else if ($action == 'actionadd') {
- $aid = rcube_utils::get_input_value('_aid', rcube_utils::INPUT_POST);
- $id = $this->genid();
- $content = $this->action_div($fid, $id, false);
-
- $this->rc->output->command('managesieve_actionfill', $content, $id, $aid);
- }
-
- $this->rc->output->send();
- }
- else if ($this->rc->task == 'mail') {
- // Initialize the form
- $rules = rcube_utils::get_input_value('r', rcube_utils::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->send();
- }
-
- function save()
- {
- // Init plugin and handle managesieve connection
- $error = $this->start();
-
- // get request size limits (#1488648)
- $max_post = max(array(
- ini_get('max_input_vars'),
- ini_get('suhosin.request.max_vars'),
- ini_get('suhosin.post.max_vars'),
- ));
- $max_depth = max(array(
- ini_get('suhosin.request.max_array_depth'),
- ini_get('suhosin.post.max_array_depth'),
- ));
-
- // check request size limit
- if ($max_post && count($_POST, COUNT_RECURSIVE) >= $max_post) {
- rcube::raise_error(array(
- 'code' => 500, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Request size limit exceeded (one of max_input_vars/suhosin.request.max_vars/suhosin.post.max_vars)"
- ), true, false);
- $this->rc->output->show_message('managesieve.filtersaveerror', 'error');
- }
- // check request depth limits
- else if ($max_depth && count($_POST['_header']) > $max_depth) {
- rcube::raise_error(array(
- 'code' => 500, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Request size limit exceeded (one of suhosin.request.max_array_depth/suhosin.post.max_array_depth)"
- ), true, false);
- $this->rc->output->show_message('managesieve.filtersaveerror', 'error');
- }
- // filters set add action
- else if (!empty($_POST['_newset'])) {
- $name = rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true);
- $copy = rcube_utils::get_input_value('_copy', rcube_utils::INPUT_POST, true);
- $from = rcube_utils::get_input_value('_from', rcube_utils::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->plugin->gettext('cannotbeempty');
- }
- else if (mb_strlen($name) > 128) {
- $this->errors['name'] = $this->plugin->gettext('nametoolong');
- }
- else if (!empty($exceptions) && in_array($name, (array)$exceptions)) {
- $this->errors['name'] = $this->plugin->gettext('namereserved');
- }
- else if (!empty($kolab) && in_array($name_uc, array('MASTER', 'USER', 'MANAGEMENT'))) {
- $this->errors['name'] = $this->plugin->gettext('namereserved');
- }
- else if (in_array($name, $list)) {
- $this->errors['name'] = $this->plugin->gettext('setexist');
- }
- else if ($from == 'file') {
- // from file
- if (is_uploaded_file($_FILES['_file']['tmp_name'])) {
- $file = file_get_contents($_FILES['_file']['tmp_name']);
- $file = preg_replace('/\r/', '', $file);
- // for security don't save script directly
- // check syntax before, like this...
- $this->sieve->load_script($file);
- if (!$this->save_script($name)) {
- $this->errors['file'] = $this->plugin->gettext('setcreateerror');
- }
- }
- else { // upload failed
- $err = $_FILES['_file']['error'];
-
- if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
- $msg = $this->rc->gettext(array('name' => 'filesizeerror',
- 'vars' => array('size' =>
- $this->rc->show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
- }
- else {
- $this->errors['file'] = $this->plugin->gettext('fileuploaderror');
- }
- }
- }
- else if (!$this->sieve->copy($name, $from == 'set' ? $copy : '')) {
- $error = 'managesieve.setcreateerror';
- }
-
- 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_updatelist', 'setadd',
- array('name' => $name, 'index' => $index));
- } else if ($msg) {
- $this->rc->output->command('display_message', $msg, 'error');
- } else if ($error) {
- $this->rc->output->show_message($error, 'error');
- }
- }
- // filter add/edit action
- else if (isset($_POST['_name'])) {
- $name = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true));
- $fid = trim(rcube_utils::get_input_value('_fid', rcube_utils::INPUT_POST));
- $join = trim(rcube_utils::get_input_value('_join', rcube_utils::INPUT_POST));
-
- // and arrays
- $headers = rcube_utils::get_input_value('_header', rcube_utils::INPUT_POST);
- $cust_headers = rcube_utils::get_input_value('_custom_header', rcube_utils::INPUT_POST);
- $ops = rcube_utils::get_input_value('_rule_op', rcube_utils::INPUT_POST);
- $sizeops = rcube_utils::get_input_value('_rule_size_op', rcube_utils::INPUT_POST);
- $sizeitems = rcube_utils::get_input_value('_rule_size_item', rcube_utils::INPUT_POST);
- $sizetargets = rcube_utils::get_input_value('_rule_size_target', rcube_utils::INPUT_POST);
- $targets = rcube_utils::get_input_value('_rule_target', rcube_utils::INPUT_POST, true);
- $mods = rcube_utils::get_input_value('_rule_mod', rcube_utils::INPUT_POST);
- $mod_types = rcube_utils::get_input_value('_rule_mod_type', rcube_utils::INPUT_POST);
- $body_trans = rcube_utils::get_input_value('_rule_trans', rcube_utils::INPUT_POST);
- $body_types = rcube_utils::get_input_value('_rule_trans_type', rcube_utils::INPUT_POST, true);
- $comparators = rcube_utils::get_input_value('_rule_comp', rcube_utils::INPUT_POST);
- $indexes = rcube_utils::get_input_value('_rule_index', rcube_utils::INPUT_POST);
- $lastindexes = rcube_utils::get_input_value('_rule_index_last', rcube_utils::INPUT_POST);
- $dateheaders = rcube_utils::get_input_value('_rule_date_header', rcube_utils::INPUT_POST);
- $dateparts = rcube_utils::get_input_value('_rule_date_part', rcube_utils::INPUT_POST);
- $act_types = rcube_utils::get_input_value('_action_type', rcube_utils::INPUT_POST, true);
- $mailboxes = rcube_utils::get_input_value('_action_mailbox', rcube_utils::INPUT_POST, true);
- $act_targets = rcube_utils::get_input_value('_action_target', rcube_utils::INPUT_POST, true);
- $domain_targets = rcube_utils::get_input_value('_action_target_domain', rcube_utils::INPUT_POST);
- $area_targets = rcube_utils::get_input_value('_action_target_area', rcube_utils::INPUT_POST, true);
- $reasons = rcube_utils::get_input_value('_action_reason', rcube_utils::INPUT_POST, true);
- $addresses = rcube_utils::get_input_value('_action_addresses', rcube_utils::INPUT_POST, true);
- $intervals = rcube_utils::get_input_value('_action_interval', rcube_utils::INPUT_POST);
- $interval_types = rcube_utils::get_input_value('_action_interval_type', rcube_utils::INPUT_POST);
- $subject = rcube_utils::get_input_value('_action_subject', rcube_utils::INPUT_POST, true);
- $flags = rcube_utils::get_input_value('_action_flags', rcube_utils::INPUT_POST);
- $varnames = rcube_utils::get_input_value('_action_varname', rcube_utils::INPUT_POST);
- $varvalues = rcube_utils::get_input_value('_action_varvalue', rcube_utils::INPUT_POST);
- $varmods = rcube_utils::get_input_value('_action_varmods', rcube_utils::INPUT_POST);
- $notifymethods = rcube_utils::get_input_value('_action_notifymethod', rcube_utils::INPUT_POST);
- $notifytargets = rcube_utils::get_input_value('_action_notifytarget', rcube_utils::INPUT_POST, true);
- $notifyoptions = rcube_utils::get_input_value('_action_notifyoption', rcube_utils::INPUT_POST, true);
- $notifymessages = rcube_utils::get_input_value('_action_notifymessage', rcube_utils::INPUT_POST, true);
- $notifyfrom = rcube_utils::get_input_value('_action_notifyfrom', rcube_utils::INPUT_POST);
- $notifyimp = rcube_utils::get_input_value('_action_notifyimportance', rcube_utils::INPUT_POST);
-
- // we need a "hack" for radiobuttons
- foreach ($sizeitems as $item)
- $items[] = $item;
-
- $this->form['disabled'] = $_POST['_disabled'] ? true : false;
- $this->form['join'] = $join=='allof' ? true : false;
- $this->form['name'] = $name;
- $this->form['tests'] = array();
- $this->form['actions'] = array();
-
- if ($name == '')
- $this->errors['name'] = $this->plugin->gettext('cannotbeempty');
- else {
- foreach($this->script as $idx => $rule)
- if($rule['name'] == $name && $idx != $fid) {
- $this->errors['name'] = $this->plugin->gettext('ruleexist');
- break;
- }
- }
-
- $i = 0;
- // rules
- if ($join == 'any') {
- $this->form['tests'][0]['test'] = 'true';
- }
- else {
- foreach ($headers as $idx => $header) {
- // targets are indexed differently (assume form order)
- $target = $this->strip_value(array_shift($targets), true);
- $header = $this->strip_value($header);
- $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->plugin->gettext('cannotbeempty');
- else if (!preg_match('/^[0-9]+(K|M|G)?$/i', $sizetarget.$sizeitem, $m)) {
- $this->errors['tests'][$i]['sizetarget'] = $this->plugin->gettext('forbiddenchars');
- $this->form['tests'][$i]['item'] = $sizeitem;
- }
- else
- $this->form['tests'][$i]['arg'] .= $m[1];
- }
- else if ($header == 'currentdate') {
- $datepart = $this->strip_value($dateparts[$idx]);
-
- if (preg_match('/^not/', $operator))
- $this->form['tests'][$i]['not'] = true;
- $type = preg_replace('/^not/', '', $operator);
-
- if ($type == 'exists') {
- $this->errors['tests'][$i]['op'] = true;
- }
-
- $this->form['tests'][$i]['test'] = 'currentdate';
- $this->form['tests'][$i]['type'] = $type;
- $this->form['tests'][$i]['part'] = $datepart;
- $this->form['tests'][$i]['arg'] = $target;
-
- if ($type != 'exists') {
- if (!count($target)) {
- $this->errors['tests'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
- }
- else if (strpos($type, 'count-') === 0) {
- foreach ($target as $arg) {
- if (preg_match('/[^0-9]/', $arg)) {
- $this->errors['tests'][$i]['target'] = $this->plugin->gettext('forbiddenchars');
- }
- }
- }
- else if (strpos($type, 'value-') === 0) {
- // Some date/time formats do not support i;ascii-numeric comparator
- if ($comparator == 'i;ascii-numeric' && in_array($datepart, array('date', 'time', 'iso8601', 'std11'))) {
- $comparator = '';
- }
- }
-
- if (!preg_match('/^(regex|matches|count-)/', $type) && count($target)) {
- foreach ($target as $arg) {
- if (!$this->validate_date_part($datepart, $arg)) {
- $this->errors['tests'][$i]['target'] = $this->plugin->gettext('invaliddateformat');
- break;
- }
- }
- }
- }
- }
- else if ($header == 'date') {
- $datepart = $this->strip_value($dateparts[$idx]);
- $dateheader = $this->strip_value($dateheaders[$idx]);
- $index = $this->strip_value($indexes[$idx]);
- $indexlast = $this->strip_value($lastindexes[$idx]);
-
- if (preg_match('/^not/', $operator))
- $this->form['tests'][$i]['not'] = true;
- $type = preg_replace('/^not/', '', $operator);
-
- if ($type == 'exists') {
- $this->errors['tests'][$i]['op'] = true;
- }
-
- if (!empty($index) && $mod != 'envelope') {
- $this->form['tests'][$i]['index'] = intval($index);
- $this->form['tests'][$i]['last'] = !empty($indexlast);
- }
-
- if (empty($dateheader)) {
- $dateheader = 'Date';
- }
- else if (!preg_match('/^[\x21-\x39\x41-\x7E]+$/i', $dateheader)) {
- $this->errors['tests'][$i]['dateheader'] = $this->plugin->gettext('forbiddenchars');
- }
-
- $this->form['tests'][$i]['test'] = 'date';
- $this->form['tests'][$i]['type'] = $type;
- $this->form['tests'][$i]['part'] = $datepart;
- $this->form['tests'][$i]['arg'] = $target;
- $this->form['tests'][$i]['header'] = $dateheader;
-
- if ($type != 'exists') {
- if (!count($target)) {
- $this->errors['tests'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
- }
- else if (strpos($type, 'count-') === 0) {
- foreach ($target as $arg) {
- if (preg_match('/[^0-9]/', $arg)) {
- $this->errors['tests'][$i]['target'] = $this->plugin->gettext('forbiddenchars');
- }
- }
- }
- else if (strpos($type, 'value-') === 0) {
- // Some date/time formats do not support i;ascii-numeric comparator
- if ($comparator == 'i;ascii-numeric' && in_array($datepart, array('date', 'time', 'iso8601', 'std11'))) {
- $comparator = '';
- }
- }
-
- if (count($target) && !preg_match('/^(regex|matches|count-)/', $type)) {
- foreach ($target as $arg) {
- if (!$this->validate_date_part($datepart, $arg)) {
- $this->errors['tests'][$i]['target'] = $this->plugin->gettext('invaliddateformat');
- break;
- }
- }
- }
- }
- }
- else if ($header == 'body') {
- $trans = $this->strip_value($body_trans[$idx]);
- $trans_type = $this->strip_value($body_types[$idx], true);
-
- if (preg_match('/^not/', $operator))
- $this->form['tests'][$i]['not'] = true;
- $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 (empty($target) && $type != 'exists') {
- $this->errors['tests'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
- }
- else if (preg_match('/^(value|count)-/', $type)) {
- foreach ($target as $target_value) {
- if (preg_match('/[^0-9]/', $target_value)) {
- $this->errors['tests'][$i]['target'] = $this->plugin->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(array_shift($cust_headers));
- $mod = $this->strip_value($mods[$idx]);
- $mod_type = $this->strip_value($mod_types[$idx]);
- $index = $this->strip_value($indexes[$idx]);
- $indexlast = $this->strip_value($lastindexes[$idx]);
-
- if (preg_match('/^not/', $operator))
- $this->form['tests'][$i]['not'] = true;
- $type = preg_replace('/^not/', '', $operator);
-
- if (!empty($index) && $mod != 'envelope') {
- $this->form['tests'][$i]['index'] = intval($index);
- $this->form['tests'][$i]['last'] = !empty($indexlast);
- }
-
- if ($header == '...') {
- if (!count($headers))
- $this->errors['tests'][$i]['header'] = $this->plugin->gettext('cannotbeempty');
- else {
- foreach ($headers as $hr) {
- // RFC2822: printable ASCII except colon
- if (!preg_match('/^[\x21-\x39\x41-\x7E]+$/i', $hr)) {
- $this->errors['tests'][$i]['header'] = $this->plugin->gettext('forbiddenchars');
- }
- }
- }
-
- if (empty($this->errors['tests'][$i]['header']))
- $cust_header = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers;
- }
-
- $header = $header == '...' ? $cust_header : $header;
-
- if (is_array($header)) {
- foreach ($header as $h_index => $val) {
- if (isset($this->headers[$val])) {
- $header[$h_index] = $this->headers[$val];
- }
- }
- }
-
- if ($type == 'exists') {
- $this->form['tests'][$i]['test'] = 'exists';
- $this->form['tests'][$i]['arg'] = $header;
- }
- else {
- $test = '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'] = $test;
- $this->form['tests'][$i]['arg1'] = $header;
- $this->form['tests'][$i]['arg2'] = $target;
-
- if (empty($target)) {
- $this->errors['tests'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
- }
- else if (preg_match('/^(value|count)-/', $type)) {
- foreach ($target as $target_value) {
- if (preg_match('/[^0-9]/', $target_value)) {
- $this->errors['tests'][$i]['target'] = $this->plugin->gettext('forbiddenchars');
- }
- }
- }
-
- if ($mod) {
- $this->form['tests'][$i]['part'] = $mod_type;
- }
- }
- }
-
- if ($header != 'size' && $comparator) {
- $this->form['tests'][$i]['comparator'] = $comparator;
- }
-
- $i++;
- }
- }
-
- $i = 0;
- // actions
- foreach ($act_types as $idx => $type) {
- $type = $this->strip_value($type);
-
- switch ($type) {
- case 'fileinto':
- case 'fileinto_copy':
- $mailbox = $this->strip_value($mailboxes[$idx], false, false);
- $this->form['actions'][$i]['target'] = $this->mod_mailbox($mailbox, 'in');
-
- if ($type == 'fileinto_copy') {
- $type = 'fileinto';
- $this->form['actions'][$i]['copy'] = true;
- }
- break;
-
- case 'reject':
- case 'ereject':
- $target = $this->strip_value($area_targets[$idx]);
- $this->form['actions'][$i]['target'] = str_replace("\r\n", "\n", $target);
-
- // if ($target == '')
-// $this->errors['actions'][$i]['targetarea'] = $this->plugin->gettext('cannotbeempty');
- break;
-
- case 'redirect':
- case 'redirect_copy':
- $target = $this->strip_value($act_targets[$idx]);
- $domain = $this->strip_value($domain_targets[$idx]);
-
- // force one of the configured domains
- $domains = (array) $this->rc->config->get('managesieve_domains');
- if (!empty($domains) && !empty($target)) {
- if (!$domain || !in_array($domain, $domains)) {
- $domain = $domains[0];
- }
-
- $target .= '@' . $domain;
- }
-
- $this->form['actions'][$i]['target'] = $target;
-
- if ($target == '')
- $this->errors['actions'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
- else if (!rcube_utils::check_email($target))
- $this->errors['actions'][$i]['target'] = $this->plugin->gettext(!empty($domains) ? 'forbiddenchars' : 'noemailwarning');
-
- if ($type == 'redirect_copy') {
- $type = 'redirect';
- $this->form['actions'][$i]['copy'] = true;
- }
-
- break;
-
- case 'addflag':
- case 'setflag':
- case 'removeflag':
- $_target = array();
- if (empty($flags[$idx])) {
- $this->errors['actions'][$i]['target'] = $this->plugin->gettext('noflagset');
- }
- else {
- foreach ($flags[$idx] as $flag) {
- $_target[] = $this->strip_value($flag);
- }
- }
- $this->form['actions'][$i]['target'] = $_target;
- break;
-
- case 'vacation':
- $reason = $this->strip_value($reasons[$idx]);
- $interval_type = $interval_types[$idx] == 'seconds' ? 'seconds' : 'days';
-
- $this->form['actions'][$i]['reason'] = str_replace("\r\n", "\n", $reason);
- $this->form['actions'][$i]['subject'] = $subject[$idx];
- $this->form['actions'][$i]['addresses'] = array_shift($addresses);
- $this->form['actions'][$i][$interval_type] = $intervals[$idx];
-// @TODO: vacation :mime, :from, :handle
-
- foreach ((array)$this->form['actions'][$i]['addresses'] as $aidx => $address) {
- $this->form['actions'][$i]['addresses'][$aidx] = $address = trim($address);
-
- if (empty($address)) {
- unset($this->form['actions'][$i]['addresses'][$aidx]);
- }
- else if (!rcube_utils::check_email($address)) {
- $this->errors['actions'][$i]['addresses'] = $this->plugin->gettext('noemailwarning');
- break;
- }
- }
-
- if ($this->form['actions'][$i]['reason'] == '')
- $this->errors['actions'][$i]['reason'] = $this->plugin->gettext('cannotbeempty');
- if ($this->form['actions'][$i][$interval_type] && !preg_match('/^[0-9]+$/', $this->form['actions'][$i][$interval_type]))
- $this->errors['actions'][$i]['interval'] = $this->plugin->gettext('forbiddenchars');
- break;
-
- case 'set':
- $this->form['actions'][$i]['name'] = $varnames[$idx];
- $this->form['actions'][$i]['value'] = $varvalues[$idx];
- foreach ((array)$varmods[$idx] as $v_m) {
- $this->form['actions'][$i][$v_m] = true;
- }
-
- if (empty($varnames[$idx])) {
- $this->errors['actions'][$i]['name'] = $this->plugin->gettext('cannotbeempty');
- }
- else if (!preg_match('/^[0-9a-z_]+$/i', $varnames[$idx])) {
- $this->errors['actions'][$i]['name'] = $this->plugin->gettext('forbiddenchars');
- }
-
- if (!isset($varvalues[$idx]) || $varvalues[$idx] === '') {
- $this->errors['actions'][$i]['value'] = $this->plugin->gettext('cannotbeempty');
- }
- break;
-
- case 'notify':
- if (empty($notifymethods[$idx])) {
- $this->errors['actions'][$i]['method'] = $this->plugin->gettext('cannotbeempty');
- }
- if (empty($notifytargets[$idx])) {
- $this->errors['actions'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
- }
- if (!empty($notifyfrom[$idx]) && !rcube_utils::check_email($notifyfrom[$idx])) {
- $this->errors['actions'][$i]['from'] = $this->plugin->gettext('noemailwarning');
- }
-
- // skip empty options
- foreach ((array)$notifyoptions[$idx] as $opt_idx => $opt) {
- if (!strlen(trim($opt))) {
- unset($notifyoptions[$idx][$opt_idx]);
- }
- }
-
- $this->form['actions'][$i]['method'] = $notifymethods[$idx] . ':' . $notifytargets[$idx];
- $this->form['actions'][$i]['options'] = $notifyoptions[$idx];
- $this->form['actions'][$i]['message'] = $notifymessages[$idx];
- $this->form['actions'][$i]['from'] = $notifyfrom[$idx];
- $this->form['actions'][$i]['importance'] = $notifyimp[$idx];
- break;
- }
-
- $this->form['actions'][$i]['type'] = $type;
- $i++;
- }
-
- if (!$this->errors && !$error) {
- // save the script
- if (!isset($this->script[$fid])) {
- $fid = $this->sieve->script->add_rule($this->form);
- $new = true;
- }
- else {
- $fid = $this->sieve->script->update_rule($fid, $this->form);
- }
-
- if ($fid !== false)
- $save = $this->save_script();
-
- if ($save && $fid !== false) {
- $this->rc->output->show_message('managesieve.filtersaved', 'confirmation');
- if ($this->rc->task != 'mail') {
- $this->rc->output->command('parent.managesieve_updatelist',
- isset($new) ? 'add' : 'update',
- array(
- 'name' => $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');
-// $this->rc->output->send();
- }
- }
- }
-
- $this->send();
- }
-
- protected function send()
- {
- // Handle form action
- if (isset($_GET['_framed']) || isset($_POST['_framed'])) {
- if (isset($_GET['_newset']) || isset($_POST['_newset'])) {
- $this->rc->output->send('managesieve.setedit');
- }
- else {
- $this->rc->output->send('managesieve.filteredit');
- }
- }
- else {
- $this->rc->output->set_pagetitle($this->plugin->gettext('filters'));
- $this->rc->output->send('managesieve.managesieve');
- }
- }
-
- // return the filters list as HTML table
- function filters_list($attrib)
- {
- // add id to message list table if not specified
- if (!strlen($attrib['id']))
- $attrib['id'] = 'rcmfilterslist';
-
- // define list of cols to be displayed
- $a_show_cols = array('name');
-
- $result = $this->list_rules();
-
- // create XHTML table
- $out = $this->rc->table_output($attrib, $result, $a_show_cols, 'id');
-
- // set client env
- $this->rc->output->add_gui_object('filterslist', $attrib['id']);
- $this->rc->output->include_script('list.js');
-
- // add some labels to client
- $this->rc->output->add_label('managesieve.filterdeleteconfirm');
-
- return $out;
- }
-
- // return the filters list as <SELECT>
- 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->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' => $set,
- 'id' => 'S'.$idx,
- 'class' => !in_array($set, $this->active) ? 'disabled' : '',
- );
- }
- }
-
- // create XHTML table
- $out = $this->rc->table_output($attrib, $result, $a_show_cols, 'id');
-
- $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);
- }
-
- // set client env
- if (!$no_env) {
- $this->rc->output->add_gui_object('filtersetslist', $attrib['id']);
- $this->rc->output->add_label('managesieve.setdeleteconfirm');
- }
-
- return $out;
- }
-
- function filter_frame($attrib)
- {
- return $this->rc->output->frame($attrib, true);
- }
-
- function filterset_form($attrib)
- {
- if (!$attrib['id'])
- $attrib['id'] = 'rcmfiltersetform';
-
- $out = '<form name="filtersetform" action="./" method="post" enctype="multipart/form-data">'."\n";
-
- $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task));
- $hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-save'));
- $hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0)));
- $hiddenfields->add(array('name' => '_newset', 'value' => 1));
-
- $out .= $hiddenfields->show();
-
- $name = rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST);
- $copy = rcube_utils::get_input_value('_copy', rcube_utils::INPUT_POST);
- $selected = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST);
-
- // filter set name input
- $input_name = new html_inputfield(array('name' => '_name', 'id' => '_name', 'size' => 30,
- 'class' => ($this->errors['name'] ? 'error' : '')));
-
- $out .= sprintf('<label for="%s"><b>%s:</b></label> %s<br /><br />',
- '_name', rcube::Q($this->plugin->gettext('filtersetname')), $input_name->show($name));
-
- $out .="\n<fieldset class=\"itemlist\"><legend>" . $this->plugin->gettext('filters') . ":</legend>\n";
- $out .= '<input type="radio" id="from_none" name="_from" value="none"'
- .(!$selected || $selected=='none' ? ' checked="checked"' : '').'></input>';
- $out .= sprintf('<label for="%s">%s</label> ', 'from_none', rcube::Q($this->plugin->gettext('none')));
-
- // filters set list
- $list = $this->list_scripts();
- $select = new html_select(array('name' => '_copy', 'id' => '_copy'));
-
- if (is_array($list)) {
- asort($list, SORT_LOCALE_STRING);
-
- 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>';
- $out .= sprintf('<label for="%s">%s:</label> ', 'from_set', rcube::Q($this->plugin->gettext('fromset')));
- $out .= $select->show($copy);
- }
-
- // script upload box
- $upload = new html_inputfield(array('name' => '_file', 'id' => '_file', 'size' => 30,
- 'type' => 'file', 'class' => ($this->errors['file'] ? 'error' : '')));
-
- $out .= '<br /><input type="radio" id="from_file" name="_from" value="file"'
- .($selected=='file' ? ' checked="checked"' : '').'></input>';
- $out .= sprintf('<label for="%s">%s:</label> ', 'from_file', rcube::Q($this->plugin->gettext('fromfile')));
- $out .= $upload->show();
- $out .= '</fieldset>';
-
- $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;
- }
-
-
- function filter_form($attrib)
- {
- if (!$attrib['id'])
- $attrib['id'] = 'rcmfilterform';
-
- $fid = rcube_utils::get_input_value('_fid', rcube_utils::INPUT_GPC);
- $scr = isset($this->form) ? $this->form : $this->script[$fid];
-
- $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task));
- $hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-save'));
- $hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0)));
- $hiddenfields->add(array('name' => '_fid', 'value' => $fid));
-
- $out = '<form name="filterform" action="./" method="post">'."\n";
- $out .= $hiddenfields->show();
-
- // 'any' flag
- if ((!isset($this->form) && empty($scr['tests']) && !empty($scr))
- || (sizeof($scr['tests']) == 1 && $scr['tests'][0]['test'] == 'true' && !$scr['tests'][0]['not'])
- ) {
- $any = true;
- }
-
- // filter name input
- $field_id = '_name';
- $input_name = new html_inputfield(array('name' => '_name', 'id' => $field_id, 'size' => 30,
- 'class' => ($this->errors['name'] ? 'error' : '')));
-
- if ($this->errors['name'])
- $this->add_tip($field_id, $this->errors['name'], true);
-
- if (isset($scr))
- $input_name = $input_name->show($scr['name']);
- else
- $input_name = $input_name->show();
-
- $out .= sprintf("\n<label for=\"%s\"><b>%s:</b></label> %s\n",
- $field_id, rcube::Q($this->plugin->gettext('filtername')), $input_name);
-
- // filter set selector
- if ($this->rc->task == 'mail') {
- $out .= sprintf("\n&nbsp;<label for=\"%s\"><b>%s:</b></label> %s\n",
- $field_id, rcube::Q($this->plugin->gettext('filterset')),
- $this->filtersets_list(array('id' => 'sievescriptname'), true));
- }
-
- $out .= '<br /><br /><fieldset><legend>' . rcube::Q($this->plugin->gettext('messagesrules')) . "</legend>\n";
-
- // any, allof, anyof radio buttons
- $field_id = '_allof';
- $input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'allof',
- 'onclick' => 'rule_join_radio(\'allof\')', 'class' => 'radio'));
-
- if (isset($scr) && !$any)
- $input_join = $input_join->show($scr['join'] ? 'allof' : '');
- else
- $input_join = $input_join->show();
-
- $out .= sprintf("%s<label for=\"%s\">%s</label>&nbsp;\n",
- $input_join, $field_id, rcube::Q($this->plugin->gettext('filterallof')));
-
- $field_id = '_anyof';
- $input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'anyof',
- 'onclick' => 'rule_join_radio(\'anyof\')', 'class' => 'radio'));
-
- if (isset($scr) && !$any)
- $input_join = $input_join->show($scr['join'] ? '' : 'anyof');
- else
- $input_join = $input_join->show('anyof'); // default
-
- $out .= sprintf("%s<label for=\"%s\">%s</label>\n",
- $input_join, $field_id, rcube::Q($this->plugin->gettext('filteranyof')));
-
- $field_id = '_any';
- $input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'any',
- 'onclick' => 'rule_join_radio(\'any\')', 'class' => 'radio'));
-
- $input_join = $input_join->show($any ? 'any' : '');
-
- $out .= sprintf("%s<label for=\"%s\">%s</label>\n",
- $input_join, $field_id, rcube::Q($this->plugin->gettext('filterany')));
-
- $rows_num = !empty($scr['tests']) ? sizeof($scr['tests']) : 1;
-
- $out .= '<div id="rules"'.($any ? ' style="display: none"' : '').'>';
- for ($x=0; $x<$rows_num; $x++)
- $out .= $this->rule_div($fid, $x);
- $out .= "</div>\n";
-
- $out .= "</fieldset>\n";
-
- // actions
- $out .= '<fieldset><legend>' . rcube::Q($this->plugin->gettext('messagesactions')) . "</legend>\n";
-
- $rows_num = isset($scr) ? sizeof($scr['actions']) : 1;
-
- $out .= '<div id="actions">';
- for ($x=0; $x<$rows_num; $x++)
- $out .= $this->action_div($fid, $x);
- $out .= "</div>\n";
-
- $out .= "</fieldset>\n";
-
- $this->print_tips();
-
- if ($scr['disabled']) {
- $this->rc->output->set_env('rule_disabled', true);
- }
- $this->rc->output->add_label(
- 'managesieve.ruledeleteconfirm',
- 'managesieve.actiondeleteconfirm'
- );
- $this->rc->output->add_gui_object('sieveform', 'filterform');
-
- return $out;
- }
-
- function rule_div($fid, $id, $div=true)
- {
- $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']);
-
- // headers select
- $select_header = new html_select(array('name' => "_header[]", 'id' => 'header'.$id,
- 'onchange' => 'rule_header_select(' .$id .')'));
-
- foreach ($this->headers as $index => $header) {
- $header = $this->rc->text_exists($index) ? $this->plugin->gettext($index) : $header;
- $select_header->add($header, $index);
- }
- $select_header->add($this->plugin->gettext('...'), '...');
- if (in_array('body', $this->exts))
- $select_header->add($this->plugin->gettext('body'), 'body');
- $select_header->add($this->plugin->gettext('size'), 'size');
- if (in_array('date', $this->exts)) {
- $select_header->add($this->plugin->gettext('datetest'), 'date');
- $select_header->add($this->plugin->gettext('currdate'), 'currentdate');
- }
-
- if (isset($rule['test'])) {
- if (in_array($rule['test'], array('header', 'address', 'envelope'))
- && !is_array($rule['arg1'])
- && ($header = strtolower($rule['arg1']))
- && isset($this->headers[$header])
- ) {
- $test = $header;
- }
- else if ($rule['test'] == 'exists'
- && !is_array($rule['arg'])
- && ($header = strtolower($rule['arg']))
- && isset($this->headers[$header])
- ) {
- $test = $header;
- }
- else if (in_array($rule['test'], array('size', 'body', 'date', 'currentdate'))) {
- $test = $rule['test'];
- }
- else if ($rule['test'] != 'true') {
- $test = '...';
- }
- }
-
- $aout = $select_header->show($test);
-
- // custom headers input
- if (isset($rule['test']) && in_array($rule['test'], array('header', 'address', 'envelope'))) {
- $custom = (array) $rule['arg1'];
- if (count($custom) == 1 && isset($this->headers[strtolower($custom[0])])) {
- unset($custom);
- }
- }
- else if (isset($rule['test']) && $rule['test'] == 'exists') {
- $custom = (array) $rule['arg'];
- if (count($custom) == 1 && isset($this->headers[strtolower($custom[0])])) {
- unset($custom);
- }
- }
-
- $tout = $this->list_input($id, 'custom_header', $custom, isset($custom),
- $this->error_class($id, 'test', 'header', 'custom_header'), 15) . "\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(this, '.$id.')'));
- $select_op->add(rcube::Q($this->plugin->gettext('filtercontains')), 'contains');
- $select_op->add(rcube::Q($this->plugin->gettext('filternotcontains')), 'notcontains');
- $select_op->add(rcube::Q($this->plugin->gettext('filteris')), 'is');
- $select_op->add(rcube::Q($this->plugin->gettext('filterisnot')), 'notis');
- $select_op->add(rcube::Q($this->plugin->gettext('filterexists')), 'exists');
- $select_op->add(rcube::Q($this->plugin->gettext('filternotexists')), 'notexists');
- $select_op->add(rcube::Q($this->plugin->gettext('filtermatches')), 'matches');
- $select_op->add(rcube::Q($this->plugin->gettext('filternotmatches')), 'notmatches');
- if (in_array('regex', $this->exts)) {
- $select_op->add(rcube::Q($this->plugin->gettext('filterregex')), 'regex');
- $select_op->add(rcube::Q($this->plugin->gettext('filternotregex')), 'notregex');
- }
- if (in_array('relational', $this->exts)) {
- $select_op->add(rcube::Q($this->plugin->gettext('countisgreaterthan')), 'count-gt');
- $select_op->add(rcube::Q($this->plugin->gettext('countisgreaterthanequal')), 'count-ge');
- $select_op->add(rcube::Q($this->plugin->gettext('countislessthan')), 'count-lt');
- $select_op->add(rcube::Q($this->plugin->gettext('countislessthanequal')), 'count-le');
- $select_op->add(rcube::Q($this->plugin->gettext('countequals')), 'count-eq');
- $select_op->add(rcube::Q($this->plugin->gettext('countnotequals')), 'count-ne');
- $select_op->add(rcube::Q($this->plugin->gettext('valueisgreaterthan')), 'value-gt');
- $select_op->add(rcube::Q($this->plugin->gettext('valueisgreaterthanequal')), 'value-ge');
- $select_op->add(rcube::Q($this->plugin->gettext('valueislessthan')), 'value-lt');
- $select_op->add(rcube::Q($this->plugin->gettext('valueislessthanequal')), 'value-le');
- $select_op->add(rcube::Q($this->plugin->gettext('valueequals')), 'value-eq');
- $select_op->add(rcube::Q($this->plugin->gettext('valuenotequals')), 'value-ne');
- }
-
- $test = self::rule_test($rule);
- $target = '';
-
- // target(s) input
- if (in_array($rule['test'], array('header', 'address', 'envelope'))) {
- $target = $rule['arg2'];
- }
- else if (in_array($rule['test'], array('body', 'date', 'currentdate'))) {
- $target = $rule['arg'];
- }
- else if ($rule['test'] == 'size') {
- if (preg_match('/^([0-9]+)(K|M|G)?$/', $rule['arg'], $matches)) {
- $sizetarget = $matches[1];
- $sizeitem = $matches[2];
- }
- else {
- $sizetarget = $rule['arg'];
- $sizeitem = $rule['item'];
- }
- }
-
- // (current)date part select
- if (in_array('date', $this->exts) || in_array('currentdate', $this->exts)) {
- $date_parts = array('date', 'iso8601', 'std11', 'julian', 'time',
- 'year', 'month', 'day', 'hour', 'minute', 'second', 'weekday', 'zone');
- $select_dp = new html_select(array('name' => "_rule_date_part[]", 'id' => 'rule_date_part'.$id,
- 'style' => in_array($rule['test'], array('currentdate', 'date')) && !preg_match('/^(notcount|count)-/', $test) ? '' : 'display:none',
- 'class' => 'datepart_selector',
- ));
-
- foreach ($date_parts as $part) {
- $select_dp->add(rcube::Q($this->plugin->gettext($part)), $part);
- }
-
- $tout .= $select_dp->show($rule['test'] == 'currentdate' || $rule['test'] == 'date' ? $rule['part'] : '');
- }
-
- $tout .= $select_op->show($test);
- $tout .= $this->list_input($id, 'rule_target', $target,
- $rule['test'] != 'size' && $rule['test'] != 'exists',
- $this->error_class($id, 'test', 'target', 'rule_target')) . "\n";
-
- $select_size_op = new html_select(array('name' => "_rule_size_op[]", 'id' => 'rule_size_op'.$id));
- $select_size_op->add(rcube::Q($this->plugin->gettext('filterover')), 'over');
- $select_size_op->add(rcube::Q($this->plugin->gettext('filterunder')), 'under');
-
- $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') .' />
- <label><input type="radio" name="_rule_size_item['.$id.']" value=""'
- . (!$sizeitem ? ' checked="checked"' : '') .' class="radio" />'.$this->rc->gettext('B').'</label>
- <label><input type="radio" name="_rule_size_item['.$id.']" value="K"'
- . ($sizeitem=='K' ? ' checked="checked"' : '') .' class="radio" />'.$this->rc->gettext('KB').'</label>
- <label><input type="radio" name="_rule_size_item['.$id.']" value="M"'
- . ($sizeitem=='M' ? ' checked="checked"' : '') .' class="radio" />'.$this->rc->gettext('MB').'</label>
- <label><input type="radio" name="_rule_size_item['.$id.']" value="G"'
- . ($sizeitem=='G' ? ' checked="checked"' : '') .' class="radio" />'.$this->rc->gettext('GB').'</label>';
- $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(rcube::Q($this->plugin->gettext('none')), '');
- $select_mod->add(rcube::Q($this->plugin->gettext('address')), 'address');
- if (in_array('envelope', $this->exts))
- $select_mod->add(rcube::Q($this->plugin->gettext('envelope')), 'envelope');
-
- $select_type = new html_select(array('name' => "_rule_mod_type[]", 'id' => 'rule_mod_type'.$id));
- $select_type->add(rcube::Q($this->plugin->gettext('allparts')), 'all');
- $select_type->add(rcube::Q($this->plugin->gettext('domain')), 'domain');
- $select_type->add(rcube::Q($this->plugin->gettext('localpart')), 'localpart');
- if (in_array('subaddress', $this->exts)) {
- $select_type->add(rcube::Q($this->plugin->gettext('user')), 'user');
- $select_type->add(rcube::Q($this->plugin->gettext('detail')), 'detail');
- }
-
- $need_mod = !in_array($rule['test'], array('size', 'body', 'date', 'currentdate'));
- $mout = '<div id="rule_mod' .$id. '" class="adv"' . (!$need_mod ? ' style="display:none"' : '') . '>';
- $mout .= ' <span class="label">' . rcube::Q($this->plugin->gettext('modifier')) . ' </span>';
- $mout .= $select_mod->show($rule['test']);
- $mout .= ' <span id="rule_mod_type' . $id . '"';
- $mout .= ' style="display:' . (in_array($rule['test'], array('address', 'envelope')) ? 'inline' : 'none') .'">';
- $mout .= rcube::Q($this->plugin->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(rcube::Q($this->plugin->gettext('text')), 'text');
- $select_mod->add(rcube::Q($this->plugin->gettext('undecoded')), 'raw');
- $select_mod->add(rcube::Q($this->plugin->gettext('contenttype')), 'content');
-
- $mout .= '<div id="rule_trans' .$id. '" class="adv"' . ($rule['test'] != 'body' ? ' style="display:none"' : '') . '>';
- $mout .= '<span class="label">' . rcube::Q($this->plugin->gettext('modifier')) . '</span>';
- $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"' . ($rule['part'] != 'content' ? ' style="display:none"' : '')
- . $this->error_class($id, 'test', 'part', 'rule_trans_type') .' />';
- $mout .= '</div>';
-
- // Advanced modifiers (body transformations)
- $select_comp = new html_select(array('name' => "_rule_comp[]", 'id' => 'rule_comp_op'.$id));
- $select_comp->add(rcube::Q($this->plugin->gettext('default')), '');
- $select_comp->add(rcube::Q($this->plugin->gettext('octet')), 'i;octet');
- $select_comp->add(rcube::Q($this->plugin->gettext('asciicasemap')), 'i;ascii-casemap');
- if (in_array('comparator-i;ascii-numeric', $this->exts)) {
- $select_comp->add(rcube::Q($this->plugin->gettext('asciinumeric')), 'i;ascii-numeric');
- }
-
- // Comparators
- $mout .= '<div id="rule_comp' .$id. '" class="adv"' . ($rule['test'] == 'size' ? ' style="display:none"' : '') . '>';
- $mout .= '<span class="label">' . rcube::Q($this->plugin->gettext('comparator')) . '</span>';
- $mout .= $select_comp->show($rule['comparator']);
- $mout .= '</div>';
-
- // Date header
- if (in_array('date', $this->exts)) {
- $mout .= '<div id="rule_date_header_div' .$id. '" class="adv"'. ($rule['test'] != 'date' ? ' style="display:none"' : '') .'>';
- $mout .= '<span class="label">' . rcube::Q($this->plugin->gettext('dateheader')) . '</span>';
- $mout .= '<input type="text" name="_rule_date_header[]" id="rule_date_header'.$id
- . '" value="'. Q($rule['test'] == 'date' ? $rule['header'] : '')
- . '" size="15"' . $this->error_class($id, 'test', 'dateheader', 'rule_date_header') .' />';
- $mout .= '</div>';
- }
-
- // Index
- if (in_array('index', $this->exts)) {
- $need_index = in_array($rule['test'], array('header', ', address', 'date'));
- $mout .= '<div id="rule_index_div' .$id. '" class="adv"'. (!$need_index ? ' style="display:none"' : '') .'>';
- $mout .= '<span class="label">' . rcube::Q($this->plugin->gettext('index')) . '</span>';
- $mout .= '<input type="text" name="_rule_index[]" id="rule_index'.$id
- . '" value="'. ($rule['index'] ? intval($rule['index']) : '')
- . '" size="3"' . $this->error_class($id, 'test', 'index', 'rule_index') .' />';
- $mout .= '&nbsp;<input type="checkbox" name="_rule_index_last[]" id="rule_index_last'.$id
- . '" value="1"' . (!empty($rule['last']) ? ' checked="checked"' : '') . ' />'
- . '<label for="rule_index_last'.$id.'">'.rcube::Q($this->plugin->gettext('indexlast')).'</label>';
- $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="'. rcube::Q($this->plugin->gettext('advancedopts')). '"
- onclick="rule_adv_switch(' . $id .', this)" class="show">&nbsp;&nbsp;</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 .= '<a href="#" id="ruleadd' . $id .'" title="'. rcube::Q($this->plugin->gettext('add')). '"
- onclick="rcmail.managesieve_ruleadd(' . $id .')" class="button add"></a>';
- $out .= '<a href="#" id="ruledel' . $id .'" title="'. rcube::Q($this->plugin->gettext('del')). '"
- onclick="rcmail.managesieve_ruledel(' . $id .')" class="button del' . ($rows_num<2 ? ' disabled' : '') .'"></a>';
- $out .= '</td>';
- $out .= '</tr></table>';
-
- $out .= $div ? "</div>\n" : '';
-
- return $out;
- }
-
- private static function rule_test(&$rule)
- {
- // first modify value/count tests with 'not' keyword
- // we'll revert the meaning of operators
- if ($rule['not'] && preg_match('/^(count|value)-([gteqnl]{2})/', $rule['type'], $m)) {
- $rule['not'] = false;
-
- switch ($m[2]) {
- case 'gt': $rule['type'] = $m[1] . '-le'; break;
- case 'ge': $rule['type'] = $m[1] . '-lt'; break;
- case 'lt': $rule['type'] = $m[1] . '-ge'; break;
- case 'le': $rule['type'] = $m[1] . '-gt'; break;
- case 'eq': $rule['type'] = $m[1] . '-ne'; break;
- case 'ne': $rule['type'] = $m[1] . '-eq'; break;
- }
- }
- else if ($rule['not'] && $rule['test'] == 'size') {
- $rule['not'] = false;
- $rule['type'] = $rule['type'] == 'over' ? 'under' : 'over';
- }
-
- $set = array('header', 'address', 'envelope', 'body', 'date', 'currentdate');
-
- // build test string supported by select element
- if ($rule['size']) {
- $test = $rule['type'];
- }
- else if (in_array($rule['test'], $set)) {
- $test = ($rule['not'] ? 'not' : '') . ($rule['type'] ? $rule['type'] : 'is');
- }
- else {
- $test = ($rule['not'] ? 'not' : '') . $rule['test'];
- }
-
- return $test;
- }
-
- function action_div($fid, $id, $div=true)
- {
- $action = isset($this->form) ? $this->form['actions'][$id] : $this->script[$fid]['actions'][$id];
- $rows_num = isset($this->form) ? sizeof($this->form['actions']) : sizeof($this->script[$fid]['actions']);
-
- $out = $div ? '<div class="actionrow" id="actionrow' .$id .'">'."\n" : '';
-
- $out .= '<table><tr><td class="rowactions">';
-
- // action select
- $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(rcube::Q($this->plugin->gettext('messagemoveto')), 'fileinto');
- if (in_array('fileinto', $this->exts) && in_array('copy', $this->exts))
- $select_action->add(rcube::Q($this->plugin->gettext('messagecopyto')), 'fileinto_copy');
- $select_action->add(rcube::Q($this->plugin->gettext('messageredirect')), 'redirect');
- if (in_array('copy', $this->exts))
- $select_action->add(rcube::Q($this->plugin->gettext('messagesendcopy')), 'redirect_copy');
- if (in_array('reject', $this->exts))
- $select_action->add(rcube::Q($this->plugin->gettext('messagediscard')), 'reject');
- else if (in_array('ereject', $this->exts))
- $select_action->add(rcube::Q($this->plugin->gettext('messagediscard')), 'ereject');
- if (in_array('vacation', $this->exts))
- $select_action->add(rcube::Q($this->plugin->gettext('messagereply')), 'vacation');
- $select_action->add(rcube::Q($this->plugin->gettext('messagedelete')), 'discard');
- if (in_array('imapflags', $this->exts) || in_array('imap4flags', $this->exts)) {
- $select_action->add(rcube::Q($this->plugin->gettext('setflags')), 'setflag');
- $select_action->add(rcube::Q($this->plugin->gettext('addflags')), 'addflag');
- $select_action->add(rcube::Q($this->plugin->gettext('removeflags')), 'removeflag');
- }
- if (in_array('variables', $this->exts)) {
- $select_action->add(rcube::Q($this->plugin->gettext('setvariable')), 'set');
- }
- if (in_array('enotify', $this->exts) || in_array('notify', $this->exts)) {
- $select_action->add(rcube::Q($this->plugin->gettext('notify')), 'notify');
- }
- $select_action->add(rcube::Q($this->plugin->gettext('messagekeep')), 'keep');
- $select_action->add(rcube::Q($this->plugin->gettext('rulestop')), 'stop');
-
- $select_type = $action['type'];
- if (in_array($action['type'], array('fileinto', 'redirect')) && $action['copy']) {
- $select_type .= '_copy';
- }
-
- $out .= $select_action->show($select_type);
- $out .= '</td>';
-
- // actions target inputs
- $out .= '<td class="rowtargets">';
-
- // force domain selection in redirect email input
- $domains = (array) $this->rc->config->get('managesieve_domains');
- if (!empty($domains)) {
- sort($domains);
-
- $domain_select = new html_select(array('name' => "_action_target_domain[$id]", 'id' => 'action_target_domain'.$id));
- $domain_select->add(array_combine($domains, $domains));
-
- if ($action['type'] == 'redirect') {
- $parts = explode('@', $action['target']);
- if (!empty($parts)) {
- $action['domain'] = array_pop($parts);
- $action['target'] = implode('@', $parts);
- }
- }
- }
-
- // redirect target
- $out .= '<span id="redirect_target' . $id . '" style="white-space:nowrap;'
- . ' display:' . ($action['type'] == 'redirect' ? 'inline' : 'none') . '">'
- . '<input type="text" name="_action_target['.$id.']" id="action_target' .$id. '"'
- . ' value="' .($action['type'] == 'redirect' ? rcube::Q($action['target'], 'strict', false) : '') . '"'
- . (!empty($domains) ? ' size="20"' : ' size="35"')
- . $this->error_class($id, 'action', 'target', 'action_target') .' />'
- . (!empty($domains) ? ' @ ' . $domain_select->show($action['domain']) : '')
- . '</span>';
-
- // (e)reject target
- $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')) ? rcube::Q($action['target'], 'strict', false) : '')
- . "</textarea>\n";
-
- // vacation
- $vsec = in_array('vacation-seconds', $this->exts);
- $out .= '<div id="action_vacation' .$id.'" style="display:' .($action['type']=='vacation' ? 'inline' : 'none') .'">';
- $out .= '<span class="label">'. rcube::Q($this->plugin->gettext('vacationreason')) .'</span><br />'
- .'<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">' .rcube::Q($this->plugin->gettext('vacationsubject')) . '</span><br />'
- .'<input type="text" name="_action_subject['.$id.']" id="action_subject'.$id.'" '
- .'value="' . (is_array($action['subject']) ? rcube::Q(implode(', ', $action['subject']), 'strict', false) : $action['subject']) . '" size="35" '
- . $this->error_class($id, 'action', 'subject', 'action_subject') .' />';
- $out .= '<br /><span class="label">' .rcube::Q($this->plugin->gettext('vacationaddr')) . '</span><br />'
- . $this->list_input($id, 'action_addresses', $action['addresses'], true,
- $this->error_class($id, 'action', 'addresses', 'action_addresses'), 30);
- $out .= '<br /><span class="label">' . rcube::Q($this->plugin->gettext($vsec ? 'vacationinterval' : 'vacationdays')) . '</span><br />'
- .'<input type="text" name="_action_interval['.$id.']" id="action_interval'.$id.'" '
- .'value="' .rcube::Q(isset($action['seconds']) ? $action['seconds'] : $action['days'], 'strict', false) . '" size="2" '
- . $this->error_class($id, 'action', 'interval', 'action_interval') .' />';
- if ($vsec) {
- $out .= '&nbsp;<label><input type="radio" name="_action_interval_type['.$id.']" value="days"'
- . (!isset($action['seconds']) ? ' checked="checked"' : '') .' class="radio" />'.$this->plugin->gettext('days').'</label>'
- . '&nbsp;<label><input type="radio" name="_action_interval_type['.$id.']" value="seconds"'
- . (isset($action['seconds']) ? ' checked="checked"' : '') .' class="radio" />'.$this->plugin->gettext('seconds').'</label>';
- }
- $out .= '</div>';
-
- // flags
- $flags = array(
- 'read' => '\\Seen',
- 'answered' => '\\Answered',
- 'flagged' => '\\Flagged',
- 'deleted' => '\\Deleted',
- 'draft' => '\\Draft',
- );
- $flags_target = (array)$action['target'];
-
- $out .= '<div id="action_flags' .$id.'" style="display:'
- . (preg_match('/^(set|add|remove)flag$/', $action['type']) ? 'inline' : 'none') . '"'
- . $this->error_class($id, 'action', 'flags', 'action_flags') . '>';
- foreach ($flags as $fidx => $flag) {
- $out .= '<input type="checkbox" name="_action_flags[' .$id .'][]" value="' . $flag . '"'
- . (in_array_nocase($flag, $flags_target) ? 'checked="checked"' : '') . ' />'
- . rcube::Q($this->plugin->gettext('flag'.$fidx)) .'<br>';
- }
- $out .= '</div>';
-
- // set variable
- $set_modifiers = array(
- 'lower',
- 'upper',
- 'lowerfirst',
- 'upperfirst',
- 'quotewildcard',
- 'length'
- );
-
- $out .= '<div id="action_set' .$id.'" style="display:' .($action['type']=='set' ? 'inline' : 'none') .'">';
- $out .= '<span class="label">' .rcube::Q($this->plugin->gettext('setvarname')) . '</span><br />'
- .'<input type="text" name="_action_varname['.$id.']" id="action_varname'.$id.'" '
- .'value="' . rcube::Q($action['name']) . '" size="35" '
- . $this->error_class($id, 'action', 'name', 'action_varname') .' />';
- $out .= '<br /><span class="label">' .rcube::Q($this->plugin->gettext('setvarvalue')) . '</span><br />'
- .'<input type="text" name="_action_varvalue['.$id.']" id="action_varvalue'.$id.'" '
- .'value="' . rcube::Q($action['value']) . '" size="35" '
- . $this->error_class($id, 'action', 'value', 'action_varvalue') .' />';
- $out .= '<br /><span class="label">' .rcube::Q($this->plugin->gettext('setvarmodifiers')) . '</span><br />';
- foreach ($set_modifiers as $s_m) {
- $s_m_id = 'action_varmods' . $id . $s_m;
- $out .= sprintf('<input type="checkbox" name="_action_varmods[%s][]" value="%s" id="%s"%s />%s<br>',
- $id, $s_m, $s_m_id,
- (array_key_exists($s_m, (array)$action) && $action[$s_m] ? ' checked="checked"' : ''),
- rcube::Q($this->plugin->gettext('var' . $s_m)));
- }
- $out .= '</div>';
-
- // notify
- $notify_methods = (array) $this->rc->config->get('managesieve_notify_methods');
- $importance_options = $this->notify_importance_options;
-
- if (empty($notify_methods)) {
- $notify_methods = $this->notify_methods;
- }
-
- list($method, $target) = explode(':', $action['method'], 2);
- $method = strtolower($method);
-
- if ($method && !in_array($method, $notify_methods)) {
- $notify_methods[] = $method;
- }
-
- $select_method = new html_select(array(
- 'name' => "_action_notifymethod[$id]",
- 'id' => "_action_notifymethod$id",
- 'class' => $this->error_class($id, 'action', 'method', 'action_notifymethod'),
- ));
- foreach ($notify_methods as $m_n) {
- $select_method->add(rcube::Q($this->rc->text_exists('managesieve.notifymethod'.$m_n) ? $this->plugin->gettext('managesieve.notifymethod'.$m_n) : $m_n), $m_n);
- }
-
- $select_importance = new html_select(array(
- 'name' => "_action_notifyimportance[$id]",
- 'id' => "_action_notifyimportance$id",
- 'class' => $this->error_class($id, 'action', 'importance', 'action_notifyimportance')
- ));
- foreach ($importance_options as $io_v => $io_n) {
- $select_importance->add(rcube::Q($this->plugin->gettext($io_n)), $io_v);
- }
-
- // @TODO: nice UI for mailto: (other methods too) URI parameters
- $out .= '<div id="action_notify' .$id.'" style="display:' .($action['type'] == 'notify' ? 'inline' : 'none') .'">';
- $out .= '<span class="label">' .rcube::Q($this->plugin->gettext('notifytarget')) . '</span><br />'
- . $select_method->show($method)
- .'<input type="text" name="_action_notifytarget['.$id.']" id="action_notifytarget'.$id.'" '
- .'value="' . rcube::Q($target) . '" size="25" '
- . $this->error_class($id, 'action', 'target', 'action_notifytarget') .' />';
- $out .= '<br /><span class="label">'. rcube::Q($this->plugin->gettext('notifymessage')) .'</span><br />'
- .'<textarea name="_action_notifymessage['.$id.']" id="action_notifymessage' .$id. '" '
- .'rows="3" cols="35" '. $this->error_class($id, 'action', 'message', 'action_notifymessage') . '>'
- . rcube::Q($action['message'], 'strict', false) . "</textarea>\n";
- if (in_array('enotify', $this->exts)) {
- $out .= '<br /><span class="label">' .rcube::Q($this->plugin->gettext('notifyfrom')) . '</span><br />'
- .'<input type="text" name="_action_notifyfrom['.$id.']" id="action_notifyfrom'.$id.'" '
- .'value="' . rcube::Q($action['from']) . '" size="35" '
- . $this->error_class($id, 'action', 'from', 'action_notifyfrom') .' />';
- }
- $out .= '<br /><span class="label">' . rcube::Q($this->plugin->gettext('notifyimportance')) . '</span><br />';
- $out .= $select_importance->show($action['importance'] ? (int) $action['importance'] : 2);
- $out .= '<div id="action_notifyoption_div' . $id . '">'
- .'<span class="label">' . rcube::Q($this->plugin->gettext('notifyoptions')) . '</span><br />'
- .$this->list_input($id, 'action_notifyoption', (array)$action['options'], true,
- $this->error_class($id, 'action', 'options', 'action_notifyoption'), 30) . '</div>';
- $out .= '</div>';
-
- // mailbox select
- if ($action['type'] == 'fileinto') {
- $mailbox = $this->mod_mailbox($action['target'], 'out');
- // make sure non-existing (or unsubscribed) mailbox is listed (#1489956)
- $additional = array($mailbox);
- }
- else {
- $mailbox = '';
- }
-
- $select = $this->rc->folder_selector(array(
- 'realnames' => false,
- 'maxlength' => 100,
- 'id' => 'action_mailbox' . $id,
- 'name' => "_action_mailbox[$id]",
- 'style' => 'display:'.(empty($action['type']) || $action['type'] == 'fileinto' ? 'inline' : 'none'),
- 'additional' => $additional,
- ));
- $out .= $select->show($mailbox);
- $out .= '</td>';
-
- // add/del buttons
- $out .= '<td class="rowbuttons">';
- $out .= '<a href="#" id="actionadd' . $id .'" title="'. rcube::Q($this->plugin->gettext('add')). '"
- onclick="rcmail.managesieve_actionadd(' . $id .')" class="button add"></a>';
- $out .= '<a href="#" id="actiondel' . $id .'" title="'. rcube::Q($this->plugin->gettext('del')). '"
- onclick="rcmail.managesieve_actiondel(' . $id .')" class="button del' . ($rows_num<2 ? ' disabled' : '') .'"></a>';
- $out .= '</td>';
-
- $out .= '</tr></table>';
-
- $out .= $div ? "</div>\n" : '';
-
- return $out;
- }
-
- protected function genid()
- {
- return preg_replace('/[^0-9]/', '', microtime(true));
- }
-
- protected function strip_value($str, $allow_html = false, $trim = true)
- {
- if (is_array($str)) {
- foreach ($str as $idx => $val) {
- $val = $this->strip_value($val, $allow_html, $trim);
-
- if ($val === '') {
- unset($str[$idx]);
- }
- }
-
- return $str;
- }
-
- if (!$allow_html) {
- $str = strip_tags($str);
- }
-
- return $trim ? trim($str) : $str;
- }
-
- protected function error_class($id, $type, $target, $elem_prefix='')
- {
- // TODO: tooltips
- if (($type == 'test' && ($str = $this->errors['tests'][$id][$target])) ||
- ($type == 'action' && ($str = $this->errors['actions'][$id][$target]))
- ) {
- $this->add_tip($elem_prefix.$id, $str, true);
- return ' class="error"';
- }
-
- return '';
- }
-
- protected function add_tip($id, $str, $error=false)
- {
- if ($error)
- $str = html::span('sieve error', $str);
-
- $this->tips[] = array($id, $str);
- }
-
- protected function print_tips()
- {
- if (empty($this->tips))
- return;
-
- $script = rcmail_output::JS_OBJECT_NAME.'.managesieve_tip_register('.json_encode($this->tips).');';
- $this->rc->output->add_script($script, 'foot');
- }
-
- protected function list_input($id, $name, $value, $enabled, $class, $size=null)
- {
- $value = (array) $value;
- $value = array_map(array('rcube', 'Q'), $value);
- $value = implode("\n", $value);
-
- return '<textarea data-type="list" name="_' . $name . '['.$id.']" id="' . $name.$id . '"'
- . ($enabled ? '' : ' disabled="disabled"')
- . ($size ? ' data-size="'.$size.'"' : '')
- . $class
- . ' style="display:none">' . $value . '</textarea>';
- }
-
- /**
- * Validate input for date part elements
- */
- protected function validate_date_part($type, $value)
- {
- // we do simple validation of date/part format
- switch ($type) {
- case 'date': // yyyy-mm-dd
- return preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $value);
- case 'iso8601':
- return preg_match('/^[0-9: .,ZWT+-]+$/', $value);
- case 'std11':
- return preg_match('/^((Sun|Mon|Tue|Wed|Thu|Fri|Sat),\s+)?[0-9]{1,2}\s+'
- . '(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+[0-9]{2,4}\s+'
- . '[0-9]{2}:[0-9]{2}(:[0-9]{2})?\s+([+-]*[0-9]{4}|[A-Z]{1,3})$', $value);
- case 'julian':
- return preg_match('/^[0-9]+$/', $value);
- case 'time': // hh:mm:ss
- return preg_match('/^[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $value);
- case 'year':
- return preg_match('/^[0-9]{4}$/', $value);
- case 'month':
- return preg_match('/^[0-9]{2}$/', $value) && $value > 0 && $value < 13;
- case 'day':
- return preg_match('/^[0-9]{2}$/', $value) && $value > 0 && $value < 32;
- case 'hour':
- return preg_match('/^[0-9]{2}$/', $value) && $value < 24;
- case 'minute':
- return preg_match('/^[0-9]{2}$/', $value) && $value < 60;
- case 'second':
- // According to RFC5260, seconds can be from 00 to 60
- return preg_match('/^[0-9]{2}$/', $value) && $value < 61;
- case 'weekday':
- return preg_match('/^[0-9]$/', $value) && $value < 7;
- case 'zone':
- return preg_match('/^[+-][0-9]{4}$/', $value);
- }
- }
-
- /**
- * Converts mailbox name from/to UTF7-IMAP from/to internal Sieve encoding
- * with delimiter replacement.
- *
- * @param string $mailbox Mailbox name
- * @param string $mode Conversion direction ('in'|'out')
- *
- * @return string Mailbox name
- */
- protected function mod_mailbox($mailbox, $mode = 'out')
- {
- $delimiter = $_SESSION['imap_delimiter'];
- $replace_delimiter = $this->rc->config->get('managesieve_replace_delimiter');
- $mbox_encoding = $this->rc->config->get('managesieve_mbox_encoding', 'UTF7-IMAP');
-
- if ($mode == 'out') {
- $mailbox = rcube_charset::convert($mailbox, $mbox_encoding, 'UTF7-IMAP');
- if ($replace_delimiter && $replace_delimiter != $delimiter)
- $mailbox = str_replace($replace_delimiter, $delimiter, $mailbox);
- }
- else {
- $mailbox = rcube_charset::convert($mailbox, 'UTF7-IMAP', $mbox_encoding);
- if ($replace_delimiter && $replace_delimiter != $delimiter)
- $mailbox = str_replace($delimiter, $replace_delimiter, $mailbox);
- }
-
- 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']);
- // make sure the script exist
- if (in_array($name, $this->list)) {
- $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);
- }
-
- // Hide scripts from config
- $exceptions = $this->rc->config->get('managesieve_filename_exceptions');
- if (!empty($exceptions)) {
- $this->list = array_diff($this->list, (array)$exceptions);
- }
- }
-
- // reindex
- if (!empty($this->list)) {
- $this->list = array_values($this->list);
- }
-
- 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 && 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 $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 $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 (empty($filter['actions'])) {
- continue;
- }
- $fname = $filter['name'] ? $filter['name'] : "#$i";
- $result[] = array(
- 'id' => $idx,
- 'name' => $fname,
- 'class' => $filter['disabled'] ? 'disabled' : '',
- );
- $i++;
- }
-
- return $result;
- }
-
- /**
- * Initializes internal script data
- */
- protected function init_script()
- {
- $this->script = $this->sieve->script->as_array();
-
- if (!$this->script) {
- return;
- }
-
- $headers = array();
- $exceptions = array('date', 'currentdate', 'size', 'body');
-
- // find common headers used in script, will be added to the list
- // of available (predefined) headers (#1489271)
- foreach ($this->script as $rule) {
- foreach ((array) $rule['tests'] as $test) {
- if ($test['test'] == 'header') {
- foreach ((array) $test['arg1'] as $header) {
- $lc_header = strtolower($header);
-
- // skip special names to not confuse UI
- if (in_array($lc_header, $exceptions)) {
- continue;
- }
-
- if (!isset($this->headers[$lc_header]) && !isset($headers[$lc_header])) {
- $headers[$lc_header] = $header;
- }
- }
- }
- }
- }
-
- ksort($headers);
-
- $this->headers += $headers;
- }
-}
diff --git a/lib/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php b/lib/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php
deleted file mode 100644
index 518d79d..0000000
--- a/lib/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php
+++ /dev/null
@@ -1,1217 +0,0 @@
-<?php
-
-/**
- * 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 as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-class rcube_sieve_script
-{
- public $content = array(); // script rules array
-
- private $vars = array(); // "global" variables
- private $prefix = ''; // script header (comments)
- private $supported = array( // Sieve extensions supported by class
- 'body', // RFC5173
- 'copy', // RFC3894
- 'date', // RFC5260
- 'enotify', // RFC5435
- 'envelope', // RFC5228
- 'ereject', // RFC5429
- 'fileinto', // RFC5228
- 'imapflags', // draft-melnikov-sieve-imapflags-06
- 'imap4flags', // RFC5232
- 'include', // draft-ietf-sieve-include-12
- 'index', // RFC5260
- 'notify', // draft-martin-sieve-notify-01,
- 'regex', // draft-ietf-sieve-regex-01
- 'reject', // RFC5429
- 'relational', // RFC3431
- 'subaddress', // RFC5233
- 'vacation', // RFC5230
- 'vacation-seconds', // RFC6131
- 'variables', // RFC5229
- // @TODO: spamtest+virustest, mailbox
- );
-
- /**
- * Object constructor
- *
- * @param string Script's text content
- * @param array List of capabilities supported by server
- */
- public function __construct($script, $capabilities=array())
- {
- $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]);
- }
- }
- }
-
- // Parse text content of the script
- $this->_parse_text($script);
- }
-
- /**
- * Adds rule to the script (at the end)
- *
- * @param string Rule name
- * @param array Rule content (as array)
- *
- * @return int The index of the new rule
- */
- public function add_rule($content)
- {
- // TODO: check this->supported
- array_push($this->content, $content);
- return sizeof($this->content)-1;
- }
-
- public function delete_rule($index)
- {
- if(isset($this->content[$index])) {
- unset($this->content[$index]);
- return true;
- }
- return false;
- }
-
- public function size()
- {
- return sizeof($this->content);
- }
-
- public function update_rule($index, $content)
- {
- // TODO: check this->supported
- if ($this->content[$index]) {
- $this->content[$index] = $content;
- return $index;
- }
- 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()
- {
- $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";
- }
- }
- }
-
- $imapflags = in_array('imap4flags', $this->supported) ? 'imap4flags' : 'imapflags';
- $notify = in_array('enotify', $this->supported) ? 'enotify' : 'notify';
-
- // rules
- foreach ($this->content as $rule) {
- $script = '';
- $tests = array();
- $i = 0;
-
- // header
- if (!empty($rule['name']) && strlen($rule['name'])) {
- $script .= '# rule:[' . $rule['name'] . "]\n";
- }
-
- // constraints expressions
- 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;
-
- 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 ' : '');
- $tests[$i] .= 'header';
-
- $this->add_index($test, $tests[$i], $exts);
- $this->add_operator($test, $tests[$i], $exts);
-
- $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 ($test['test'] != 'envelope') {
- $this->add_index($test, $tests[$i], $exts);
- }
-
- // :all address-part is optional, skip it
- if (!empty($test['part']) && $test['part'] != 'all') {
- $tests[$i] .= ' :' . $test['part'];
- if ($test['part'] == 'user' || $test['part'] == 'detail') {
- array_push($exts, 'subaddress');
- }
- }
-
- $this->add_operator($test, $tests[$i], $exts);
-
- $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';
-
- if (!empty($test['part'])) {
- $tests[$i] .= ' :' . $test['part'];
-
- if (!empty($test['content']) && $test['part'] == 'content') {
- $tests[$i] .= ' ' . self::escape_string($test['content']);
- }
- }
-
- $this->add_operator($test, $tests[$i], $exts);
-
- $tests[$i] .= ' ' . self::escape_string($test['arg']);
- break;
-
- case 'date':
- case 'currentdate':
- array_push($exts, 'date');
-
- $tests[$i] .= ($test['not'] ? 'not ' : '') . $test['test'];
-
- $this->add_index($test, $tests[$i], $exts);
-
- if (!empty($test['originalzone']) && $test['test'] == 'date') {
- $tests[$i] .= ' :originalzone';
- }
- else if (!empty($test['zone'])) {
- $tests[$i] .= ' :zone ' . self::escape_string($test['zone']);
- }
-
- $this->add_operator($test, $tests[$i], $exts);
-
- if ($test['test'] == 'date') {
- $tests[$i] .= ' ' . self::escape_string($test['header']);
- }
-
- $tests[$i] .= ' ' . self::escape_string($test['part']);
- $tests[$i] .= ' ' . self::escape_string($test['arg']);
-
- break;
- }
- $i++;
- }
- }
-
- // disabled rule: if false #....
- if (!empty($tests)) {
- $script .= 'if ' . ($rule['disabled'] ? 'false # ' : '');
-
- 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;
- }
- $script .= "\n{\n";
- }
-
- // action(s)
- 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 'redirect':
- $action_script .= 'redirect ';
- if ($action['copy']) {
- $action_script .= ':copy ';
- array_push($exts, 'copy');
- }
- $action_script .= self::escape_string($action['target']);
- break;
-
- case 'reject':
- case 'ereject':
- array_push($exts, $action['type']);
- $action_script .= $action['type'].' '
- . self::escape_string($action['target']);
- break;
-
- case 'addflag':
- case 'setflag':
- case 'removeflag':
- array_push($exts, $imapflags);
- $action_script .= $action['type'].' '
- . self::escape_string($action['target']);
- break;
-
- case 'keep':
- case 'discard':
- case 'stop':
- $action_script .= $action['type'];
- 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 '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 'notify':
- array_push($exts, $notify);
- $action_script .= 'notify';
-
- $method = $action['method'];
- unset($action['method']);
- $action['options'] = (array) $action['options'];
-
- // Here we support draft-martin-sieve-notify-01 used by Cyrus
- if ($notify == 'notify') {
- switch ($action['importance']) {
- case 1: $action_script .= " :high"; break;
- //case 2: $action_script .= " :normal"; break;
- case 3: $action_script .= " :low"; break;
- }
-
- // Old-draft way: :method "mailto" :options "email@address"
- if (!empty($method)) {
- $parts = explode(':', $method, 2);
- $action['method'] = $parts[0];
- array_unshift($action['options'], $parts[1]);
- }
-
- unset($action['importance']);
- unset($action['from']);
- unset($method);
- }
-
- foreach (array('id', 'importance', 'method', 'options', 'from', 'message') as $n_tag) {
- if (!empty($action[$n_tag])) {
- $action_script .= " :$n_tag " . self::escape_string($action[$n_tag]);
- }
- }
-
- if (!empty($method)) {
- $action_script .= ' ' . self::escape_string($method);
- }
-
- break;
-
- case 'vacation':
- array_push($exts, 'vacation');
- $action_script .= 'vacation';
- if (isset($action['seconds'])) {
- array_push($exts, 'vacation-seconds');
- $action_script .= " :seconds " . intval($action['seconds']);
- }
- else if (!empty($action['days'])) {
- $action_script .= " :days " . intval($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";
- }
- }
- }
-
- if ($script) {
- $output .= $script . (!empty($tests) ? "}\n" : '');
- $idx++;
- }
- }
-
- // requires
- if (!empty($exts)) {
- $exts = array_unique($exts);
-
- if (in_array('vacation-seconds', $exts) && ($key = array_search('vacation', $exts)) !== false) {
- unset($exts[$key]);
- }
-
- sort($exts); // for convenience use always the same order
-
- $output = 'require ["' . implode('","', $exts) . "\"];\n" . $output;
- }
-
- if (!empty($this->prefix)) {
- $output = $this->prefix . "\n\n" . $output;
- }
-
- return $output;
- }
-
- /**
- * Returns script object
- *
- */
- public function as_array()
- {
- return $this->content;
- }
-
- /**
- * Returns array of supported extensions
- *
- */
- public function get_extensions()
- {
- return array_values($this->supported);
- }
-
- /**
- * Converts text script to rules array
- *
- * @param string Text script
- */
- private function _parse_text($script)
- {
- $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';
- }
- }
-
- // Control structures/blocks
- if (preg_match('/^(if|else|elsif)/i', $script)) {
- $rule = $this->_tokenize_rule($script);
- if (strlen($rulename) && !empty($rule)) {
- $rule['name'] = $rulename;
- }
- }
- // 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];
- unset($rule);
- }
- else {
- $rule = array('actions' => $rule);
- }
- }
- }
-
- $rulename = '';
-
- if (!empty($rule)) {
- $this->content[] = $rule;
- }
- }
-
- 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)
- {
- $cond = strtolower(self::tokenize($content, 1));
-
- if ($cond != 'if' && $cond != 'elsif' && $cond != 'else') {
- return null;
- }
-
- $disabled = false;
- $join = false;
- $join_not = false;
-
- // disabled rule (false + comment): if false # .....
- if (preg_match('/^\s*false\s+#/i', $content)) {
- $content = preg_replace('/^\s*false\s+#\s*/i', '', $content);
- $disabled = true;
- }
-
- while (strlen($content)) {
- $tokens = self::tokenize($content, true);
- $separator = array_pop($tokens);
-
- if (!empty($tokens)) {
- $token = array_shift($tokens);
- }
- else {
- $token = $separator;
- }
-
- $token = strtolower($token);
-
- if ($token == 'not') {
- $not = true;
- $token = strtolower(array_shift($tokens));
- }
- else {
- $not = false;
- }
-
- // we support "not allof" as a negation of allof sub-tests
- if ($join_not) {
- $not = !$not;
- }
-
- switch ($token) {
- case 'allof':
- $join = true;
- $join_not = $not;
- break;
-
- case 'anyof':
- break;
-
- case 'size':
- $test = array('test' => 'size', 'not' => $not);
-
- $test['arg'] = array_pop($tokens);
-
- for ($i=0, $len=count($tokens); $i<$len; $i++) {
- if (!is_array($tokens[$i])
- && preg_match('/^:(under|over)$/i', $tokens[$i])
- ) {
- $test['type'] = strtolower(substr($tokens[$i], 1));
- }
- }
-
- $tests[] = $test;
- break;
-
- case 'header':
- case 'address':
- case 'envelope':
- $test = array('test' => $token, 'not' => $not);
-
- $test['arg2'] = array_pop($tokens);
- $test['arg1'] = array_pop($tokens);
-
- $test += $this->test_tokens($tokens);
-
- if ($token != 'header' && !empty($tokens)) {
- for ($i=0, $len=count($tokens); $i<$len; $i++) {
- if (!is_array($tokens[$i]) && preg_match('/^:(localpart|domain|all|user|detail)$/i', $tokens[$i])) {
- $test['part'] = strtolower(substr($tokens[$i], 1));
- }
- }
- }
-
- $tests[] = $test;
- break;
-
- case 'body':
- $test = array('test' => 'body', 'not' => $not);
-
- $test['arg'] = array_pop($tokens);
-
- $test += $this->test_tokens($tokens);
-
- for ($i=0, $len=count($tokens); $i<$len; $i++) {
- if (!is_array($tokens[$i]) && preg_match('/^:(raw|content|text)$/i', $tokens[$i])) {
- $test['part'] = strtolower(substr($tokens[$i], 1));
-
- if ($test['part'] == 'content') {
- $test['content'] = $tokens[++$i];
- }
- }
- }
-
- $tests[] = $test;
- break;
-
- case 'date':
- case 'currentdate':
- $test = array('test' => $token, 'not' => $not);
-
- $test['arg'] = array_pop($tokens);
- $test['part'] = array_pop($tokens);
-
- if ($token == 'date') {
- $test['header'] = array_pop($tokens);
- }
-
- $test += $this->test_tokens($tokens);
-
- for ($i=0, $len=count($tokens); $i<$len; $i++) {
- if (!is_array($tokens[$i]) && preg_match('/^:zone$/i', $tokens[$i])) {
- $test['zone'] = $tokens[++$i];
- }
- else if (!is_array($tokens[$i]) && preg_match('/^:originalzone$/i', $tokens[$i])) {
- $test['originalzone'] = true;
- }
- }
-
- $tests[] = $test;
- break;
-
- case 'exists':
- $tests[] = array('test' => 'exists', 'not' => $not,
- 'arg' => array_pop($tokens));
- break;
-
- case 'true':
- $tests[] = array('test' => 'true', 'not' => $not);
- break;
-
- case 'false':
- $tests[] = array('test' => 'true', 'not' => !$not);
- break;
- }
-
- // goto actions...
- if ($separator == '{') {
- break;
- }
- }
-
- // ...and actions block
- $actions = $this->_parse_actions($content);
-
- if ($tests && $actions) {
- $result = array(
- 'type' => $cond,
- 'tests' => $tests,
- 'actions' => $actions,
- 'join' => $join,
- 'disabled' => $disabled,
- );
- }
-
- return $result;
- }
-
- /**
- * Parse body of actions section
- *
- * @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, $end = '}')
- {
- $result = null;
-
- while (strlen($content)) {
- $tokens = self::tokenize($content, true);
- $separator = array_pop($tokens);
- $token = !empty($tokens) ? array_shift($tokens) : $separator;
-
- switch ($token) {
- case 'discard':
- case 'keep':
- case 'stop':
- $result[] = array('type' => $token);
- break;
-
- case 'fileinto':
- case 'redirect':
- $action = array('type' => $token, 'target' => array_pop($tokens));
- $args = array('copy');
- $action += $this->action_arguments($tokens, $args);
-
- $result[] = $action;
- break;
-
- case 'vacation':
- $action = array('type' => 'vacation', 'reason' => array_pop($tokens));
- $args = array('mime');
- $vargs = array('seconds', 'days', 'addresses', 'subject', 'handle', 'from');
- $action += $this->action_arguments($tokens, $args, $vargs);
-
- $result[] = $action;
- break;
-
- case 'reject':
- case 'ereject':
- case 'setflag':
- case 'addflag':
- case 'removeflag':
- $result[] = array('type' => $token, 'target' => array_pop($tokens));
- break;
-
- case 'include':
- $action = array('type' => 'include', 'target' => array_pop($tokens));
- $args = array('once', 'optional', 'global', 'personal');
- $action += $this->action_arguments($tokens, $args);
-
- $result[] = $action;
- break;
-
- case 'set':
- $action = array('type' => 'set', 'value' => array_pop($tokens), 'name' => array_pop($tokens));
- $args = array('lower', 'upper', 'lowerfirst', 'upperfirst', 'quotewildcard', 'length');
- $action += $this->action_arguments($tokens, $args);
-
- $result[] = $action;
- break;
-
- case 'require':
- // skip, will be build according to used commands
- // $result[] = array('type' => 'require', 'target' => array_pop($tokens));
- break;
-
- case 'notify':
- $action = array('type' => 'notify');
- $priorities = array('high' => 1, 'normal' => 2, 'low' => 3);
- $vargs = array('from', 'id', 'importance', 'options', 'message', 'method');
- $args = array_keys($priorities);
- $action += $this->action_arguments($tokens, $args, $vargs);
-
- // Here we'll convert draft-martin-sieve-notify-01 into RFC 5435
- if (!isset($action['importance'])) {
- foreach ($priorities as $key => $val) {
- if (isset($action[$key])) {
- $action['importance'] = $val;
- unset($action[$key]);
- }
- }
- }
-
- $action['options'] = (array) $action['options'];
-
- // Old-draft way: :method "mailto" :options "email@address"
- if (!empty($action['method']) && !empty($action['options'])) {
- $action['method'] .= ':' . array_shift($action['options']);
- }
- // unnamed parameter is a :method in enotify extension
- else if (!isset($action['method'])) {
- $action['method'] = array_pop($tokens);
- }
-
- $result[] = $action;
- break;
- }
-
- if ($separator == $end)
- break;
- }
-
- return $result;
- }
-
- /**
- * Add comparator to the test
- */
- 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']);
- }
- }
-
- /**
- * Add index argument to the test
- */
- private function add_index($test, &$out, &$exts)
- {
- if (!empty($test['index'])) {
- array_push($exts, 'index');
- $out .= ' :index ' . intval($test['index']) . ($test['last'] ? ' :last' : '');
- }
- }
-
- /**
- * Add operators to the test
- */
- private function add_operator($test, &$out, &$exts)
- {
- if (empty($test['type'])) {
- return;
- }
-
- // relational operator
- if (preg_match('/^(value|count)-([gteqnl]{2})/', $test['type'], $m)) {
- array_push($exts, 'relational');
-
- $out .= ' :' . $m[1] . ' "' . $m[2] . '"';
- }
- else {
- if ($test['type'] == 'regex') {
- array_push($exts, 'regex');
- }
-
- $out .= ' :' . $test['type'];
- }
-
- $this->add_comparator($test, $out, $exts);
- }
-
- /**
- * Extract test tokens
- */
- private function test_tokens(&$tokens)
- {
- $test = array();
- $result = array();
-
- for ($i=0, $len=count($tokens); $i<$len; $i++) {
- if (!is_array($tokens[$i]) && preg_match('/^:comparator$/i', $tokens[$i])) {
- $test['comparator'] = $tokens[++$i];
- }
- else if (!is_array($tokens[$i]) && preg_match('/^:(count|value)$/i', $tokens[$i])) {
- $test['type'] = strtolower(substr($tokens[$i], 1)) . '-' . $tokens[++$i];
- }
- else if (!is_array($tokens[$i]) && preg_match('/^:(is|contains|matches|regex)$/i', $tokens[$i])) {
- $test['type'] = strtolower(substr($tokens[$i], 1));
- }
- else if (!is_array($tokens[$i]) && preg_match('/^:index$/i', $tokens[$i])) {
- $test['index'] = intval($tokens[++$i]);
- if ($tokens[$i+1] && preg_match('/^:last$/i', $tokens[$i+1])) {
- $test['last'] = true;
- $i++;
- }
- }
- else {
- $result[] = $tokens[$i];
- }
- }
-
- $tokens = $result;
-
- return $test;
- }
-
- /**
- * Extract action arguments
- */
- private function action_arguments(&$tokens, $bool_args, $val_args = array())
- {
- $action = array();
- $result = array();
-
- for ($i=0, $len=count($tokens); $i<$len; $i++) {
- $tok = $tokens[$i];
- if (!is_array($tok) && $tok[0] == ':') {
- $tok = strtolower(substr($tok, 1));
- if (in_array($tok, $bool_args)) {
- $action[$tok] = true;
- }
- else if (in_array($tok, $val_args)) {
- $action[$tok] = $tokens[++$i];
- }
- else {
- $result[] = $tok;
- }
- }
- else {
- $result[] = $tok;
- }
- }
-
- $tokens = $result;
-
- return $action;
- }
-
- /**
- * Escape special chars into quoted string value or multi-line string
- * or list of strings
- *
- * @param string $str Text or array (list) of strings
- *
- * @return string Result text
- */
- static function escape_string($str)
- {
- if (is_array($str) && count($str) > 1) {
- foreach($str as $idx => $val)
- $str[$idx] = self::escape_string($val);
-
- return '[' . implode(',', $str) . ']';
- }
- else if (is_array($str)) {
- $str = array_pop($str);
- }
-
- // multi-line string
- if (preg_match('/[\r\n\0]/', $str) || strlen($str) > 1024) {
- return sprintf("text:\n%s\n.\n", self::escape_multiline_string($str));
- }
- // quoted-string
- else {
- return '"' . addcslashes($str, '\\"') . '"';
- }
- }
-
- /**
- * Escape special chars in multi-line string value
- *
- * @param string $str Text
- *
- * @return string Text
- */
- static function escape_multiline_string($str)
- {
- $str = preg_split('/(\r?\n)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
-
- foreach ($str as $idx => $line) {
- // dot-stuffing
- if (isset($line[0]) && $line[0] == '.') {
- $str[$idx] = '.' . $line;
- }
- }
-
- return implode($str);
- }
-
- /**
- * Splits script into string tokens
- *
- * @param string &$str The script
- * @param mixed $num Number of tokens to return, 0 for all
- * or True for all tokens until separator is found.
- * Separator will be returned as last token.
- *
- * @return mixed Tokens array or string if $num=1
- */
- static function tokenize(&$str, $num=0)
- {
- $result = array();
-
- // remove spaces from the beginning of the string
- while (($str = ltrim($str)) !== ''
- && (!$num || $num === true || count($result) < $num)
- ) {
- switch ($str[0]) {
-
- // Quoted string
- case '"':
- $len = strlen($str);
-
- for ($pos=1; $pos<$len; $pos++) {
- if ($str[$pos] == '"') {
- break;
- }
- if ($str[$pos] == "\\") {
- if ($str[$pos + 1] == '"' || $str[$pos + 1] == "\\") {
- $pos++;
- }
- }
- }
- if ($str[$pos] != '"') {
- // error
- }
- // we need to strip slashes for a quoted string
- $result[] = stripslashes(substr($str, 1, $pos - 1));
- $str = substr($str, $pos + 1);
- break;
-
- // Parenthesized list
- case '[':
- $str = substr($str, 1);
- $result[] = self::tokenize($str, 0);
- break;
- case ']':
- $str = substr($str, 1);
- return $result;
- break;
-
- // list/test separator
- case ',':
- // command separator
- case ';':
- // block/tests-list
- case '(':
- case ')':
- case '{':
- case '}':
- $sep = $str[0];
- $str = substr($str, 1);
- if ($num === true) {
- $result[] = $sep;
- break 2;
- }
- break;
-
- // bracket-comment
- case '/':
- if ($str[1] == '*') {
- if ($end_pos = strpos($str, '*/')) {
- $str = substr($str, $end_pos + 2);
- }
- else {
- // error
- $str = '';
- }
- }
- break;
-
- // hash-comment
- case '#':
- if ($lf_pos = strpos($str, "\n")) {
- $str = substr($str, $lf_pos);
- break;
- }
- else {
- $str = '';
- }
-
- // String atom
- default:
- // empty or one character
- if ($str === '' || $str === null) {
- break 2;
- }
- if (strlen($str) < 2) {
- $result[] = $str;
- $str = '';
- break;
- }
-
- // tag/identifier/number
- if (preg_match('/^([a-z0-9:_]+)/i', $str, $m)) {
- $str = substr($str, strlen($m[1]));
-
- if ($m[1] != 'text:') {
- $result[] = $m[1];
- }
- // multiline string
- else {
- // possible hash-comment after "text:"
- if (preg_match('/^( |\t)*(#[^\n]+)?\n/', $str, $m)) {
- $str = substr($str, strlen($m[0]));
- }
- // get text until alone dot in a line
- if (preg_match('/^(.*)\r?\n\.\r?\n/sU', $str, $m)) {
- $text = $m[1];
- // remove dot-stuffing
- $text = str_replace("\n..", "\n.", $text);
- $str = substr($str, strlen($m[0]));
- }
- else {
- $text = '';
- }
-
- $result[] = $text;
- }
- }
- // fallback, skip one character as infinite loop prevention
- else {
- $str = substr($str, 1);
- }
-
- break;
- }
- }
-
- return $num === 1 ? (isset($result[0]) ? $result[0] : null) : $result;
- }
-
-}
diff --git a/lib/plugins/managesieve/lib/Roundcube/rcube_sieve_vacation.php b/lib/plugins/managesieve/lib/Roundcube/rcube_sieve_vacation.php
deleted file mode 100644
index 28fd801..0000000
--- a/lib/plugins/managesieve/lib/Roundcube/rcube_sieve_vacation.php
+++ /dev/null
@@ -1,850 +0,0 @@
-<?php
-
-/**
- * Managesieve Vacation Engine
- *
- * Engine part of Managesieve plugin implementing UI and backend access.
- *
- * Copyright (C) 2011-2014, 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 as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-class rcube_sieve_vacation extends rcube_sieve_engine
-{
- protected $error;
- protected $script_name;
- protected $vacation = array();
-
- function actions()
- {
- $error = $this->start('vacation');
-
- // find current vacation rule
- if (!$error) {
- $this->vacation_rule();
- $this->vacation_post();
- }
-
- $this->plugin->add_label('vacation.saving');
- $this->rc->output->add_handlers(array(
- 'vacationform' => array($this, 'vacation_form'),
- ));
-
- $this->rc->output->set_pagetitle($this->plugin->gettext('vacation'));
- $this->rc->output->send('managesieve.vacation');
- }
-
- /**
- * Find and load sieve script with/for vacation rule
- *
- * @return int Connection status: 0 on success, >0 on failure
- */
- protected function load_script()
- {
- if ($this->script_name !== null) {
- return 0;
- }
-
- $list = $this->list_scripts();
- $master = $this->rc->config->get('managesieve_kolab_master');
- $included = array();
-
- $this->script_name = false;
-
- // first try the active script(s)...
- if (!empty($this->active)) {
- // Note: there can be more than one active script on KEP:14-enabled server
- foreach ($this->active as $script) {
- if ($this->sieve->load($script)) {
- foreach ($this->sieve->script->as_array() as $rule) {
- if (!empty($rule['actions'])) {
- if ($rule['actions'][0]['type'] == 'vacation') {
- $this->script_name = $script;
- return 0;
- }
- else if (empty($master) && $rule['actions'][0]['type'] == 'include') {
- $included[] = $rule['actions'][0]['target'];
- }
- }
- }
- }
- }
-
- // ...else try scripts included in active script (not for KEP:14)
- foreach ($included as $script) {
- if ($this->sieve->load($script)) {
- foreach ($this->sieve->script->as_array() as $rule) {
- if (!empty($rule['actions']) && $rule['actions'][0]['type'] == 'vacation') {
- $this->script_name = $script;
- return 0;
- }
- }
- }
- }
- }
-
- // try all other scripts
- if (!empty($list)) {
- // else try included scripts
- foreach (array_diff($list, $included, $this->active) as $script) {
- if ($this->sieve->load($script)) {
- foreach ($this->sieve->script->as_array() as $rule) {
- if (!empty($rule['actions']) && $rule['actions'][0]['type'] == 'vacation') {
- $this->script_name = $script;
- return 0;
- }
- }
- }
- }
-
- // none of the scripts contains existing vacation rule
- // use any (first) active or just existing script (in that order)
- if (!empty($this->active)) {
- $this->sieve->load($this->script_name = $this->active[0]);
- }
- else {
- $this->sieve->load($this->script_name = $list[0]);
- }
- }
-
- return $this->sieve->error();
- }
-
- private function vacation_rule()
- {
- if ($this->script_name === false || $this->script_name === null || !$this->sieve->load($this->script_name)) {
- return;
- }
-
- $list = array();
- $active = in_array($this->script_name, $this->active);
-
- // find (first) vacation rule
- foreach ($this->script as $idx => $rule) {
- if (empty($this->vacation) && !empty($rule['actions']) && $rule['actions'][0]['type'] == 'vacation') {
- foreach ($rule['actions'] as $act) {
- if ($act['type'] == 'discard' || $act['type'] == 'keep') {
- $action = $act['type'];
- }
- else if ($act['type'] == 'redirect') {
- $action = $act['copy'] ? 'copy' : 'redirect';
- $target = $act['target'];
- }
- }
-
- $this->vacation = array_merge($rule['actions'][0], array(
- 'idx' => $idx,
- 'disabled' => $rule['disabled'] || !$active,
- 'name' => $rule['name'],
- 'tests' => $rule['tests'],
- 'action' => $action ?: 'keep',
- 'target' => $target,
- ));
- }
- else if ($active) {
- $list[$idx] = $rule['name'];
- }
- }
-
- $this->vacation['list'] = $list;
- }
-
- private function vacation_post()
- {
- if (empty($_POST)) {
- return;
- }
-
- $date_extension = in_array('date', $this->exts);
- $regex_extension = in_array('regex', $this->exts);
-
- // set user's timezone
- try {
- $timezone = new DateTimeZone($this->rc->config->get('timezone', 'GMT'));
- }
- catch (Exception $e) {
- $timezone = new DateTimeZone('GMT');
- }
-
- $status = rcube_utils::get_input_value('vacation_status', rcube_utils::INPUT_POST);
- $subject = rcube_utils::get_input_value('vacation_subject', rcube_utils::INPUT_POST, true);
- $reason = rcube_utils::get_input_value('vacation_reason', rcube_utils::INPUT_POST, true);
- $addresses = rcube_utils::get_input_value('vacation_addresses', rcube_utils::INPUT_POST, true);
- $interval = rcube_utils::get_input_value('vacation_interval', rcube_utils::INPUT_POST);
- $interval_type = rcube_utils::get_input_value('vacation_interval_type', rcube_utils::INPUT_POST);
- $date_from = rcube_utils::get_input_value('vacation_datefrom', rcube_utils::INPUT_POST);
- $date_to = rcube_utils::get_input_value('vacation_dateto', rcube_utils::INPUT_POST);
- $time_from = rcube_utils::get_input_value('vacation_timefrom', rcube_utils::INPUT_POST);
- $time_to = rcube_utils::get_input_value('vacation_timeto', rcube_utils::INPUT_POST);
- $after = rcube_utils::get_input_value('vacation_after', rcube_utils::INPUT_POST);
- $action = rcube_utils::get_input_value('vacation_action', rcube_utils::INPUT_POST);
- $target = rcube_utils::get_input_value('action_target', rcube_utils::INPUT_POST, true);
- $target_domain = rcube_utils::get_input_value('action_domain', rcube_utils::INPUT_POST);
-
- $interval_type = $interval_type == 'seconds' ? 'seconds' : 'days';
- $vacation_action['type'] = 'vacation';
- $vacation_action['reason'] = $this->strip_value(str_replace("\r\n", "\n", $reason));
- $vacation_action['subject'] = $subject;
- $vacation_action['addresses'] = $addresses;
- $vacation_action[$interval_type] = $interval;
- $vacation_tests = (array) $this->vacation['tests'];
-
- foreach ((array) $vacation_action['addresses'] as $aidx => $address) {
- $vacation_action['addresses'][$aidx] = $address = trim($address);
-
- if (empty($address)) {
- unset($vacation_action['addresses'][$aidx]);
- }
- else if (!rcube_utils::check_email($address)) {
- $error = 'noemailwarning';
- break;
- }
- }
-
- if ($vacation_action['reason'] == '') {
- $error = 'managesieve.emptyvacationbody';
- }
-
- if ($vacation_action[$interval_type] && !preg_match('/^[0-9]+$/', $vacation_action[$interval_type])) {
- $error = 'managesieve.forbiddenchars';
- }
-
- // find and remove existing date/regex/true rules
- foreach ((array) $vacation_tests as $idx => $t) {
- if ($t['test'] == 'currentdate' || $t['test'] == 'true'
- || ($t['test'] == 'header' && $t['type'] == 'regex' && $t['arg1'] == 'received')
- ) {
- unset($vacation_tests[$idx]);
- }
- }
-
- if ($date_extension) {
- foreach (array('date_from', 'date_to') as $var) {
- $time = ${str_replace('date', 'time', $var)};
- $date = trim($$var . ' ' . $time);
-
- if ($date && ($dt = rcube_utils::anytodatetime($date, $timezone))) {
- if ($time) {
- $vacation_tests[] = array(
- 'test' => 'currentdate',
- 'part' => 'iso8601',
- 'type' => 'value-' . ($var == 'date_from' ? 'ge' : 'le'),
- 'zone' => $dt->format('O'),
- 'arg' => str_replace('+00:00', 'Z', strtoupper($dt->format('c'))),
- );
- }
- else {
- $vacation_tests[] = array(
- 'test' => 'currentdate',
- 'part' => 'date',
- 'type' => 'value-' . ($var == 'date_from' ? 'ge' : 'le'),
- 'zone' => $dt->format('O'),
- 'arg' => $dt->format('Y-m-d'),
- );
- }
- }
- }
- }
- else if ($regex_extension) {
- // Add date range rules if range specified
- if ($date_from && $date_to) {
- if ($tests = self::build_regexp_tests($date_from, $date_to, $error)) {
- $vacation_tests = array_merge($vacation_tests, $tests);
- }
- }
- }
-
- if ($action == 'redirect' || $action == 'copy') {
- if ($target_domain) {
- $target .= '@' . $target_domain;
- }
-
- if (empty($target) || !rcube_utils::check_email($target)) {
- $error = 'noemailwarning';
- }
- }
-
- if (empty($vacation_tests)) {
- $vacation_tests = $this->rc->config->get('managesieve_vacation_test', array(array('test' => 'true')));
- }
-
- if (!$error) {
- $rule = $this->vacation;
- $rule['type'] = 'if';
- $rule['name'] = $rule['name'] ?: $this->plugin->gettext('vacation');
- $rule['disabled'] = $status == 'off';
- $rule['tests'] = $vacation_tests;
- $rule['join'] = $date_extension ? count($vacation_tests) > 1 : false;
- $rule['actions'] = array($vacation_action);
- $rule['after'] = $after;
-
- if ($action && $action != 'keep') {
- $rule['actions'][] = array(
- 'type' => $action == 'discard' ? 'discard' : 'redirect',
- 'copy' => $action == 'copy',
- 'target' => $action != 'discard' ? $target : '',
- );
- }
-
- if ($this->save_vacation_script($rule)) {
- $this->rc->output->show_message('managesieve.vacationsaved', 'confirmation');
- $this->rc->output->send();
- }
- }
-
- $this->rc->output->show_message($error ? $error : 'managesieve.saveerror', 'error');
- $this->rc->output->send();
- }
-
- /**
- * Independent vacation form
- */
- public function vacation_form($attrib)
- {
- // check supported extensions
- $date_extension = in_array('date', $this->exts);
- $regex_extension = in_array('regex', $this->exts);
- $seconds_extension = in_array('vacation-seconds', $this->exts);
-
- // build FORM tag
- $form_id = !empty($attrib['id']) ? $attrib['id'] : 'form';
- $out = $this->rc->output->request_form(array(
- 'id' => $form_id,
- 'name' => $form_id,
- 'method' => 'post',
- 'task' => 'settings',
- 'action' => 'plugin.managesieve-vacation',
- 'noclose' => true
- ) + $attrib);
-
- // form elements
- $subject = new html_inputfield(array('name' => 'vacation_subject', 'id' => 'vacation_subject', 'size' => 50));
- $reason = new html_textarea(array('name' => 'vacation_reason', 'id' => 'vacation_reason', 'cols' => 60, 'rows' => 8));
- $interval = new html_inputfield(array('name' => 'vacation_interval', 'id' => 'vacation_interval', 'size' => 5));
- $addresses = '<textarea name="vacation_addresses" id="vacation_addresses" data-type="list" data-size="30" style="display: none">'
- . rcube::Q(implode("\n", (array) $this->vacation['addresses']), 'strict', false) . '</textarea>';
- $status = new html_select(array('name' => 'vacation_status', 'id' => 'vacation_status'));
- $action = new html_select(array('name' => 'vacation_action', 'id' => 'vacation_action', 'onchange' => 'vacation_action_select()'));
-
- $status->add($this->plugin->gettext('vacation.on'), 'on');
- $status->add($this->plugin->gettext('vacation.off'), 'off');
-
- $action->add($this->plugin->gettext('vacation.keep'), 'keep');
- $action->add($this->plugin->gettext('vacation.discard'), 'discard');
- $action->add($this->plugin->gettext('vacation.redirect'), 'redirect');
- if (in_array('copy', $this->exts)) {
- $action->add($this->plugin->gettext('vacation.copy'), 'copy');
- }
-
- if ($this->rc->config->get('managesieve_vacation') != 2 && count($this->vacation['list'])) {
- $after = new html_select(array('name' => 'vacation_after', 'id' => 'vacation_after'));
-
- $after->add('', '');
- foreach ($this->vacation['list'] as $idx => $rule) {
- $after->add($rule, $idx);
- }
- }
-
- $interval_txt = $interval->show(isset($this->vacation['seconds']) ? $this->vacation['seconds'] : $this->vacation['days']);
- if ($seconds_extension) {
- $interval_select = new html_select(array('name' => 'vacation_interval_type'));
- $interval_select->add($this->plugin->gettext('days'), 'days');
- $interval_select->add($this->plugin->gettext('seconds'), 'seconds');
- $interval_txt .= '&nbsp;' . $interval_select->show(isset($this->vacation['seconds']) ? 'seconds' : 'days');
- }
- else {
- $interval_txt .= '&nbsp;' . $this->plugin->gettext('days');
- }
-
- if ($date_extension || $regex_extension) {
- $date_from = new html_inputfield(array('name' => 'vacation_datefrom', 'id' => 'vacation_datefrom', 'class' => 'datepicker', 'size' => 12));
- $date_to = new html_inputfield(array('name' => 'vacation_dateto', 'id' => 'vacation_dateto', 'class' => 'datepicker', 'size' => 12));
- $date_format = $this->rc->config->get('date_format', 'Y-m-d');
- }
-
- if ($date_extension) {
- $time_from = new html_inputfield(array('name' => 'vacation_timefrom', 'id' => 'vacation_timefrom', 'size' => 6));
- $time_to = new html_inputfield(array('name' => 'vacation_timeto', 'id' => 'vacation_timeto', 'size' => 6));
- $time_format = $this->rc->config->get('time_format', 'H:i');
- $date_value = array();
-
- foreach ((array) $this->vacation['tests'] as $test) {
- if ($test['test'] == 'currentdate') {
- $idx = $test['type'] == 'value-ge' ? 'from' : 'to';
-
- if ($test['part'] == 'date') {
- $date_value[$idx]['date'] = $test['arg'];
- }
- else if ($test['part'] == 'iso8601') {
- $date_value[$idx]['datetime'] = $test['arg'];
- }
- }
- }
-
- foreach ($date_value as $idx => $value) {
- $date = $value['datetime'] ?: $value['date'];
- $date_value[$idx] = $this->rc->format_date($date, $date_format, false);
-
- if (!empty($value['datetime'])) {
- $date_value['time_' . $idx] = $this->rc->format_date($date, $time_format, true);
- }
- }
- }
- else if ($regex_extension) {
- // Sieve 'date' extension not available, read start/end from RegEx based rules instead
- if ($date_tests = self::parse_regexp_tests($this->vacation['tests'])) {
- $date_value['from'] = $this->rc->format_date($date_tests['from'], $date_format, false);
- $date_value['to'] = $this->rc->format_date($date_tests['to'], $date_format, false);
- }
- }
-
- // force domain selection in redirect email input
- $domains = (array) $this->rc->config->get('managesieve_domains');
- $redirect = $this->vacation['action'] == 'redirect' || $this->vacation['action'] == 'copy';
-
- if (!empty($domains)) {
- sort($domains);
-
- $domain_select = new html_select(array('name' => 'action_domain', 'id' => 'action_domain'));
- $domain_select->add(array_combine($domains, $domains));
-
- if ($redirect && $this->vacation['target']) {
- $parts = explode('@', $this->vacation['target']);
- if (!empty($parts)) {
- $this->vacation['domain'] = array_pop($parts);
- $this->vacation['target'] = implode('@', $parts);
- }
- }
- }
-
- // redirect target
- $action_target = ' <span id="action_target_span" style="display:' . ($redirect ? 'inline' : 'none') . '">'
- . '<input type="text" name="action_target" id="action_target"'
- . ' value="' .($redirect ? rcube::Q($this->vacation['target'], 'strict', false) : '') . '"'
- . (!empty($domains) ? ' size="20"' : ' size="35"') . '/>'
- . (!empty($domains) ? ' @ ' . $domain_select->show($this->vacation['domain']) : '')
- . '</span>';
-
- // Message tab
- $table = new html_table(array('cols' => 2));
-
- $table->add('title', html::label('vacation_subject', $this->plugin->gettext('vacation.subject')));
- $table->add(null, $subject->show($this->vacation['subject']));
- $table->add('title', html::label('vacation_reason', $this->plugin->gettext('vacation.body')));
- $table->add(null, $reason->show($this->vacation['reason']));
-
- if ($date_extension || $regex_extension) {
- $table->add('title', html::label('vacation_datefrom', $this->plugin->gettext('vacation.start')));
- $table->add(null, $date_from->show($date_value['from']) . ($time_from ? ' ' . $time_from->show($date_value['time_from']) : ''));
- $table->add('title', html::label('vacation_dateto', $this->plugin->gettext('vacation.end')));
- $table->add(null, $date_to->show($date_value['to']) . ($time_to ? ' ' . $time_to->show($date_value['time_to']) : ''));
- }
-
- $table->add('title', html::label('vacation_status', $this->plugin->gettext('vacation.status')));
- $table->add(null, $status->show(!isset($this->vacation['disabled']) || $this->vacation['disabled'] ? 'off' : 'on'));
-
- $out .= html::tag('fieldset', $class, html::tag('legend', null, $this->plugin->gettext('vacation.reply')) . $table->show($attrib));
-
- // Advanced tab
- $table = new html_table(array('cols' => 2));
-
- $table->add('title', html::label('vacation_addresses', $this->plugin->gettext('vacation.addresses')));
- $table->add(null, $addresses);
- $table->add('title', html::label('vacation_interval', $this->plugin->gettext('vacation.interval')));
- $table->add(null, $interval_txt);
-
- if ($after) {
- $table->add('title', html::label('vacation_after', $this->plugin->gettext('vacation.after')));
- $table->add(null, $after->show($this->vacation['idx'] - 1));
- }
-
- $table->add('title', html::label('vacation_action', $this->plugin->gettext('vacation.action')));
- $table->add('vacation', $action->show($this->vacation['action']) . $action_target);
-
- $out .= html::tag('fieldset', $class, html::tag('legend', null, $this->plugin->gettext('vacation.advanced')) . $table->show($attrib));
-
- $out .= '</form>';
-
- $this->rc->output->add_gui_object('sieveform', $form_id);
-
- if ($time_format) {
- $this->rc->output->set_env('time_format', $time_format);
- }
-
- return $out;
- }
-
- public static function build_regexp_tests($date_from, $date_to, &$error)
- {
- $tests = array();
- $dt_from = rcube_utils::anytodatetime($date_from);
- $dt_to = rcube_utils::anytodatetime($date_to);
- $interval = $dt_from->diff($dt_to);
-
- if ($interval->invert || $interval->days > 365) {
- $error = 'managesieve.invaliddateformat';
- return;
- }
-
- $dt_i = $dt_from;
- $interval = new DateInterval('P1D');
- $matchexp = '';
-
- while (!$dt_i->diff($dt_to)->invert) {
- $days = (int) $dt_i->format('d');
- $matchexp .= $days < 10 ? "[ 0]$days" : $days;
-
- if ($days == $dt_i->format('t') || $dt_i->diff($dt_to)->days == 0) {
- $test = array(
- 'test' => 'header',
- 'type' => 'regex',
- 'arg1' => 'received',
- 'arg2' => '('.$matchexp.') '.$dt_i->format('M Y')
- );
-
- $tests[] = $test;
- $matchexp = '';
- }
- else {
- $matchexp .= '|';
- }
-
- $dt_i->add($interval);
- }
-
- return $tests;
- }
-
- public static function parse_regexp_tests($tests)
- {
- $rx_from = '/^\(([0-9]{2}).*\)\s([A-Za-z]+)\s([0-9]{4})/';
- $rx_to = '/^\(.*([0-9]{2})\)\s([A-Za-z]+)\s([0-9]{4})/';
- $result = array();
-
- foreach ((array) $tests as $test) {
- if ($test['test'] == 'header' && $test['type'] == 'regex' && $test['arg1'] == 'received') {
- $textexp = preg_replace('/\[ ([^\]]*)\]/', '0', $test['arg2']);
-
- if (!$result['from'] && preg_match($rx_from, $textexp, $matches)) {
- $result['from'] = $matches[1]." ".$matches[2]." ".$matches[3];
- }
-
- if (preg_match($rx_to, $textexp, $matches)) {
- $result['to'] = $matches[1]." ".$matches[2]." ".$matches[3];
- }
- }
- }
-
- return $result;
- }
-
- /**
- * Saves vacation script (adding some variables)
- */
- protected function save_vacation_script($rule)
- {
- // if script does not exist create a new one
- if ($this->script_name === null || $this->script_name === false) {
- $this->script_name = $this->rc->config->get('managesieve_script_name');
- if (empty($this->script_name)) {
- $this->script_name = 'roundcube';
- }
-
- $this->script = array($rule);
- $script_active = false;
- }
- // if script exists
- else {
- $script_active = in_array($this->script_name, $this->active);
-
- // re-order rules if needed
- if (isset($rule['after']) && $rule['after'] !== '') {
- // reset original vacation rule
- if (isset($this->vacation['idx'])) {
- $this->script[$this->vacation['idx']] = null;
- }
-
- // add at target position
- if ($rule['after'] >= count($this->script) - 1) {
- $this->script[] = $rule;
- }
- else {
- $script = array();
-
- foreach ($this->script as $idx => $r) {
- if ($r) {
- $script[] = $r;
- }
-
- if ($idx == $rule['after']) {
- $script[] = $rule;
- }
- }
-
- $this->script = $script;
- }
-
- $this->script = array_values(array_filter($this->script));
- }
- // update original vacation rule if it exists
- else if (isset($this->vacation['idx'])) {
- $this->script[$this->vacation['idx']] = $rule;
- }
- // otherwise put vacation rule on top
- else {
- array_unshift($this->script, $rule);
- }
-
- // if the script was not active, we need to de-activate
- // all rules except the vacation rule, but only if it is not disabled
- if (!$script_active && !$rule['disabled']) {
- foreach ($this->script as $idx => $r) {
- if (empty($r['actions']) || $r['actions'][0]['type'] != 'vacation') {
- $this->script[$idx]['disabled'] = true;
- }
- }
- }
- }
-
- $this->sieve->script->content = $this->script;
-
- // save the script
- $saved = $this->save_script($this->script_name);
-
- // activate the script
- if ($saved && !$script_active && !$rule['disabled']) {
- $this->activate_script($this->script_name);
- }
-
- return $saved;
- }
-
- /**
- * API: get vacation rule
- *
- * @return array Vacation rule information
- */
- public function get_vacation()
- {
- $this->exts = $this->sieve->get_extensions();
- $this->init_script();
- $this->vacation_rule();
-
- // check supported extensions
- $date_extension = in_array('date', $this->exts);
- $regex_extension = in_array('regex', $this->exts);
- $seconds_extension = in_array('vacation-seconds', $this->exts);
-
- // set user's timezone
- try {
- $timezone = new DateTimeZone($this->rc->config->get('timezone', 'GMT'));
- }
- catch (Exception $e) {
- $timezone = new DateTimeZone('GMT');
- }
-
- if ($date_extension) {
- $date_value = array();
- foreach ((array) $this->vacation['tests'] as $test) {
- if ($test['test'] == 'currentdate') {
- $idx = $test['type'] == 'value-ge' ? 'start' : 'end';
-
- if ($test['part'] == 'date') {
- $date_value[$idx]['date'] = $test['arg'];
- }
- else if ($test['part'] == 'iso8601') {
- $date_value[$idx]['datetime'] = $test['arg'];
- }
- }
- }
-
- foreach ($date_value as $idx => $value) {
- $$idx = new DateTime($value['datetime'] ?: $value['date'], $timezone);
- }
- }
- else if ($regex_extension) {
- // Sieve 'date' extension not available, read start/end from RegEx based rules instead
- if ($date_tests = self::parse_regexp_tests($this->vacation['tests'])) {
- $from = new DateTime($date_tests['from'] . ' ' . '00:00:00', $timezone);
- $to = new DateTime($date_tests['to'] . ' ' . '23:59:59', $timezone);
- }
- }
-
- if (isset($this->vacation['seconds'])) {
- $interval = $this->vacation['seconds'] . 's';
- }
- else if (isset($this->vacation['days'])) {
- $interval = $this->vacation['days'] . 'd';
- }
-
- $vacation = array(
- 'supported' => $this->exts,
- 'interval' => $interval,
- 'start' => $start,
- 'end' => $end,
- 'enabled' => $this->vacation['reason'] && empty($this->vacation['disabled']),
- 'message' => $this->vacation['reason'],
- 'subject' => $this->vacation['subject'],
- 'action' => $this->vacation['action'],
- 'target' => $this->vacation['target'],
- 'addresses' => $this->vacation['addresses'],
- );
-
- return $vacation;
- }
-
- /**
- * API: set vacation rule
- *
- * @param array $vacation Vacation rule information (see self::get_vacation())
- *
- * @return bool True on success, False on failure
- */
- public function set_vacation($data)
- {
- $this->exts = $this->sieve->get_extensions();
- $this->error = false;
-
- $this->init_script();
- $this->vacation_rule();
-
- // check supported extensions
- $date_extension = in_array('date', $this->exts);
- $regex_extension = in_array('regex', $this->exts);
- $seconds_extension = in_array('vacation-seconds', $this->exts);
-
- $vacation['type'] = 'vacation';
- $vacation['reason'] = $this->strip_value(str_replace("\r\n", "\n", $data['message']));
- $vacation['addresses'] = $data['addresses'];
- $vacation['subject'] = $data['subject'];
- $vacation_tests = (array) $this->vacation['tests'];
-
- foreach ((array) $vacation['addresses'] as $aidx => $address) {
- $vacation['addresses'][$aidx] = $address = trim($address);
-
- if (empty($address)) {
- unset($vacation['addresses'][$aidx]);
- }
- else if (!rcube_utils::check_email($address)) {
- $this->error = "Invalid address in vacation addresses: $address";
- return false;
- }
- }
-
- if ($vacation['reason'] == '') {
- $this->error = "No vacation message specified";
- return false;
- }
-
- if ($data['interval']) {
- if (!preg_match('/^([0-9]+)\s*([sd])$/', $data['interval'], $m)) {
- $this->error = "Invalid vacation interval value: " . $data['interval'];
- return false;
- }
- else if ($m[1]) {
- $vacation[strtolower($m[2]) == 's' ? 'seconds' : 'days'] = $m[1];
- }
- }
-
- // find and remove existing date/regex/true rules
- foreach ((array) $vacation_tests as $idx => $t) {
- if ($t['test'] == 'currentdate' || $t['test'] == 'true'
- || ($t['test'] == 'header' && $t['type'] == 'regex' && $t['arg1'] == 'received')
- ) {
- unset($vacation_tests[$idx]);
- }
- }
-
- if ($date_extension) {
- foreach (array('start', 'end') as $var) {
- if ($dt = $data[$var]) {
- $vacation_tests[] = array(
- 'test' => 'currentdate',
- 'part' => 'iso8601',
- 'type' => 'value-' . ($var == 'start' ? 'ge' : 'le'),
- 'zone' => $dt->format('O'),
- 'arg' => str_replace('+00:00', 'Z', strtoupper($dt->format('c'))),
- );
- }
- }
- }
- else if ($regex_extension) {
- // Add date range rules if range specified
- if ($data['start'] && $data['end']) {
- if ($tests = self::build_regexp_tests($data['start'], $data['end'], $error)) {
- $vacation_tests = array_merge($vacation_tests, $tests);
- }
-
- if ($error) {
- $this->error = "Invalid dates specified or unsupported period length";
- return false;
- }
- }
- }
-
- if ($data['action'] == 'redirect' || $data['action'] == 'copy') {
- if (empty($data['target']) || !rcube_utils::check_email($data['target'])) {
- $this->error = "Invalid address in action taget: " . $data['target'];
- return false;
- }
- }
- else if ($data['action'] && $data['action'] != 'keep' && $data['action'] != 'discard') {
- $this->error = "Unsupported vacation action: " . $data['action'];
- return false;
- }
-
- if (empty($vacation_tests)) {
- $vacation_tests = $this->rc->config->get('managesieve_vacation_test', array(array('test' => 'true')));
- }
-
- $rule = $this->vacation;
- $rule['type'] = 'if';
- $rule['name'] = $rule['name'] ?: 'Out-of-Office';
- $rule['disabled'] = isset($data['enabled']) && !$data['enabled'];
- $rule['tests'] = $vacation_tests;
- $rule['join'] = $date_extension ? count($vacation_tests) > 1 : false;
- $rule['actions'] = array($vacation);
-
- if ($data['action'] && $data['action'] != 'keep') {
- $rule['actions'][] = array(
- 'type' => $data['action'] == 'discard' ? 'discard' : 'redirect',
- 'copy' => $data['action'] == 'copy',
- 'target' => $data['action'] != 'discard' ? $data['target'] : '',
- );
- }
-
- return $this->save_vacation_script($rule);
- }
-
- /**
- * API: connect to managesieve server
- */
- public function connect($username, $password)
- {
- if (!parent::connect($username, $password)) {
- return $this->load_script();
- }
- }
-
- /**
- * API: Returns last error
- *
- * @return string Error message
- */
- public function get_error()
- {
- return $this->error;
- }
-}
diff --git a/lib/plugins/managesieve/localization/ar_SA.inc b/lib/plugins/managesieve/localization/ar_SA.inc
deleted file mode 100644
index 88e8957..0000000
--- a/lib/plugins/managesieve/localization/ar_SA.inc
+++ /dev/null
@@ -1,188 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'تصفية';
-$labels['managefilters'] = 'ادارة تصفية البريد الوارد';
-$labels['filtername'] = 'اسم التصفية';
-$labels['newfilter'] = 'تصفية جديدة';
-$labels['filteradd'] = 'اضافة تصفية';
-$labels['filterdel'] = 'حذف تصفية';
-$labels['moveup'] = 'نقل الى الاعلى ';
-$labels['movedown'] = 'نقل الى الاسفل';
-$labels['filterallof'] = 'مطابقة جميع القواعد التالية';
-$labels['filteranyof'] = 'مطابقة اي القواعد التالية';
-$labels['filterany'] = 'كل الرسائل';
-$labels['filtercontains'] = 'محتوى';
-$labels['filternotcontains'] = 'بدون محتوى';
-$labels['filteris'] = 'مساوي الى';
-$labels['filterisnot'] = 'لا يساوي';
-$labels['filterexists'] = 'موجود';
-$labels['filternotexists'] = 'غير موجود';
-$labels['filtermatches'] = 'يطابق التعبير';
-$labels['filternotmatches'] = 'لا يطابق التعبير';
-$labels['filterregex'] = 'يطابق التعبير العادي';
-$labels['filternotregex'] = 'لا يطابق التعبير العادي';
-$labels['filterunder'] = 'تحت';
-$labels['filterover'] = 'خلال';
-$labels['addrule'] = 'اضافة قاعدة';
-$labels['delrule'] = 'حذف قاعدة';
-$labels['messagemoveto'] = 'نقل الرساله الى ';
-$labels['messageredirect'] = 'إعادة توجيه الرسالة الى ';
-$labels['messagecopyto'] = 'نسخ الرسالة الى ';
-$labels['messagesendcopy'] = 'ارسال نسخة من الرسالة الى ';
-$labels['messagereply'] = 'الرد مع رسالة';
-$labels['messagedelete'] = 'حذف الرسالة';
-$labels['messagediscard'] = 'تجاهل مع الرسالة';
-$labels['messagekeep'] = 'إبقاء الرسالة في علبة الوارد';
-$labels['messagesrules'] = 'للبريد الوارد:';
-$labels['messagesactions'] = '...تنفيذ المهام التالية:';
-$labels['add'] = 'إضافة';
-$labels['del'] = 'حذف';
-$labels['sender'] = 'المرسل';
-$labels['recipient'] = 'مستلم';
-$labels['vacationaddr'] = 'عناوين البريد الالكتروني(ـة) الاضافية:';
-$labels['vacationdays'] = 'في الغالب كم رسالة ترسل (بالايام):';
-$labels['vacationinterval'] = 'كم عدد الرسائل المرسلة عادةً:';
-$labels['vacationreason'] = 'نص الرسالة (بسبب الاجازة):';
-$labels['vacationsubject'] = 'موضوع الرسالة:';
-$labels['days'] = 'ايام';
-$labels['seconds'] = 'ثواني';
-$labels['rulestop'] = 'ايقاف تقييم القواعد';
-$labels['enable'] = 'تفعيل/تعطيل';
-$labels['filterset'] = 'مجموعة مصفياة';
-$labels['filtersets'] = 'مجموعة تصفية';
-$labels['filtersetadd'] = 'اضافة مجموعة تصفية';
-$labels['filtersetdel'] = 'حذف مجموعة التصفية الحالية';
-$labels['filtersetact'] = 'تفعيل مجموعة التصفية الحالية ';
-$labels['filtersetdeact'] = 'تعطيل مجموعة التصفية الحالية ';
-$labels['filterdef'] = 'تعريف التصفية ';
-$labels['filtersetname'] = 'اسم مجموعة التصفية';
-$labels['newfilterset'] = 'مجموعة تصفية جديدة';
-$labels['active'] = 'نشط';
-$labels['none'] = 'لاشيء';
-$labels['fromset'] = 'من مجموعة';
-$labels['fromfile'] = 'من ملف';
-$labels['filterdisabled'] = 'تعطيل التصفية';
-$labels['countisgreaterthan'] = 'العدد اكبر من ';
-$labels['countisgreaterthanequal'] = 'العدد اكبر من او يساوي ';
-$labels['countislessthan'] = 'العدد اقل من ';
-$labels['countislessthanequal'] = 'العدد اقل من او يساوي';
-$labels['countequals'] = 'العدد يساوي ';
-$labels['countnotequals'] = 'العدد لا يساوي';
-$labels['valueisgreaterthan'] = 'القيمة اكبر من ';
-$labels['valueisgreaterthanequal'] = 'القيمة اكبر من او تساوي';
-$labels['valueislessthan'] = 'القيمة اقل من ';
-$labels['valueislessthanequal'] = 'القيمة اقل من او يساوي';
-$labels['valueequals'] = 'القيمة تساوي';
-$labels['valuenotequals'] = 'القيمة لا تساوي';
-$labels['setflags'] = 'ضع وسم على هذه الرسالة ';
-$labels['addflags'] = 'اضف وسم على هذه الرسالة ';
-$labels['removeflags'] = 'احذف الوسم الموجود على هذه الرسالة ';
-$labels['flagread'] = 'قراءة ';
-$labels['flagdeleted'] = 'محذوف';
-$labels['flaganswered'] = 'مجابة';
-$labels['flagflagged'] = 'موسوم';
-$labels['flagdraft'] = 'مسودة';
-$labels['setvariable'] = 'تعيين متغير';
-$labels['setvarname'] = 'اسم المتغير:';
-$labels['setvarvalue'] = 'قيمة المتغير:';
-$labels['setvarmodifiers'] = 'تعديلات:';
-$labels['varquotewildcard'] = 'أقتبس أحرف خاصة';
-$labels['varlength'] = 'الطول';
-$labels['notify'] = 'ارسل تنبية';
-$labels['notifyimportance'] = 'اهمية:';
-$labels['notifyimportancelow'] = 'منخفض';
-$labels['notifyimportancenormal'] = 'عادي';
-$labels['notifyimportancehigh'] = 'مرتفع';
-$labels['filtercreate'] = 'انشئ تصفية';
-$labels['usedata'] = 'استخدم البيانات التالية في الفلتر:';
-$labels['nextstep'] = 'الخطوة التالية';
-$labels['...'] = '...';
-$labels['currdate'] = 'التاريخ الحالي';
-$labels['datetest'] = 'التاريخ';
-$labels['dateheader'] = 'الراس:';
-$labels['year'] = 'السنة';
-$labels['month'] = 'شهر';
-$labels['day'] = 'يوم';
-$labels['date'] = 'التاريخ (yyyy-mm-dd)';
-$labels['julian'] = 'التاريخ (يوليان)';
-$labels['hour'] = 'ساعات';
-$labels['minute'] = 'دقائق';
-$labels['second'] = 'ثواني';
-$labels['time'] = 'الوقت (hh:mm:ss)';
-$labels['iso8601'] = 'التاريخ (ISO8601)';
-$labels['std11'] = 'التاريخ (RFC2822)';
-$labels['zone'] = 'المنطقة الزمنية';
-$labels['weekday'] = 'ايام العمل (0-6)';
-$labels['advancedopts'] = 'خيارات متقدّمة';
-$labels['body'] = 'نص';
-$labels['address'] = 'العنوان';
-$labels['modifier'] = 'تعديل:';
-$labels['text'] = 'نص';
-$labels['contenttype'] = 'نوع المحتوى';
-$labels['modtype'] = 'نوع:';
-$labels['allparts'] = 'الكل';
-$labels['domain'] = 'المجال';
-$labels['localpart'] = 'الجزء المحلي';
-$labels['user'] = 'مستخدم';
-$labels['detail'] = 'تفاصيل';
-$labels['default'] = 'افتراضي';
-$labels['index'] = 'الوارد:';
-$labels['indexlast'] = 'تراجع';
-$labels['vacation'] = 'اجازة ';
-$labels['vacation.advanced'] = 'اعدادات متقدمة';
-$labels['vacation.subject'] = 'موضوع';
-$labels['vacation.body'] = 'محتوى ';
-$labels['vacation.status'] = 'الحالة ';
-$labels['vacation.on'] = 'تشغيل';
-$labels['vacation.off'] = 'ايقاف';
-$labels['vacation.addresses'] = 'عناوينني الاضافية';
-$labels['vacation.saving'] = 'يتم حفظ البيانات...';
-$messages['filterunknownerror'] = 'خطا غير معروف من الخادم.';
-$messages['filterconnerror'] = 'لا يمكن الاتصال بالخادم.';
-$messages['filterdeleteerror'] = 'لا يمكن حذف التصفية.خطا في الخادم.';
-$messages['filterdeleted'] = 'تم حذف التصفية بنجاح.';
-$messages['filtersaved'] = 'تم حفظ التصفية بنجاح.';
-$messages['filtersaveerror'] = 'لا يمكن حفظ التصفية.خطا في الخادم.';
-$messages['filterdeleteconfirm'] = 'هل تريد فعلاً حذف التصفية المحددة؟';
-$messages['ruledeleteconfirm'] = 'هل تريد فعلاً حذف القواعد المحددة؟';
-$messages['actiondeleteconfirm'] = 'هل تريد فعلاً حذف الاجراءات المحددة؟';
-$messages['forbiddenchars'] = 'احرف محظورة في هذا الحقل.';
-$messages['cannotbeempty'] = 'لا يمكن ترك الحقل فارغاً';
-$messages['ruleexist'] = 'اسم هذة التصفية موجود مسبقاً';
-$messages['setactivateerror'] = 'لا يمكن تفعيل مجموعة التصفية المحددة.خطا في الخادم.';
-$messages['setdeactivateerror'] = 'لا يمكن تعطيل مجموعة التصفية المحددة.خطا في الخادم.';
-$messages['setdeleteerror'] = 'لا يمكن حذف مجموعة التصفية المحددة.خطا في الخادم.';
-$messages['setactivated'] = 'تم تفعيل مجموعة التصفية بنجاح.';
-$messages['setdeactivated'] = 'تم تعطيل مجموعة التصفية بنجاح.';
-$messages['setdeleted'] = 'تم حذف مجموعة التصفية بنجاح.';
-$messages['setdeleteconfirm'] = 'هل تريد فعلاً حذف مجموعات التصفية المحددة؟';
-$messages['setcreateerror'] = 'لا يمكن انشاء مجموعة تصفية.خطا في الخادم.';
-$messages['setcreated'] = 'تم انشاء مجموعة التصفية بنجاح.';
-$messages['activateerror'] = 'لا يمكن تمكين التصفية(ـات) المحددة .خطا في الخادم.';
-$messages['deactivateerror'] = 'لا يمكن تعطيل التصفية(ـات) المحددة .خطا في الخادم.';
-$messages['deactivated'] = 'تم تعطيل المصفيـ(ـاة) بنجاح.';
-$messages['activated'] = 'تم تفعيل المصفيـ(ـاة) بنجاح.';
-$messages['moved'] = 'تم نقل التصفية بنجاح.';
-$messages['moveerror'] = 'لا يمكن نقل التصفياة المحددة.خطا في الخادم.';
-$messages['nametoolong'] = 'الإسم طويل جداً';
-$messages['setexist'] = 'المجموعة موجودة مسبقا.';
-$messages['nodata'] = 'يجب تحديد موضع واحد على الأقل!';
-$messages['invaliddateformat'] = 'تاريخ غير صحيح او يوجد خطا في تنسق اجزاء التاريخ';
-$messages['saveerror'] = 'لا يمكن حفظ البيانات. خطا في الخادم.';
-$messages['vacationsaved'] = 'تم حفظ تاريخ الاجازة بنجاح.';
-?>
diff --git a/lib/plugins/managesieve/localization/ast.inc b/lib/plugins/managesieve/localization/ast.inc
deleted file mode 100644
index e1c469b..0000000
--- a/lib/plugins/managesieve/localization/ast.inc
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtros';
-$labels['managefilters'] = 'Alministrar filtros de corréu entrante';
-$labels['filtername'] = 'Nome del filtru';
-$labels['newfilter'] = 'Filtru nuevu';
-$labels['filteradd'] = 'Amestar filtru';
-$labels['filterdel'] = 'Desaniciar filtru';
-$labels['moveup'] = 'Mover arriba';
-$labels['movedown'] = 'Mover abaxo';
-$labels['filterany'] = 'tolos mensaxes';
-$labels['filtercontains'] = 'contien';
-$labels['filternotcontains'] = 'nun contien';
-$labels['filteris'] = 'ye igual a';
-$labels['filterisnot'] = 'nun ye igual a';
-$labels['filterexists'] = 'esiste';
-$labels['filternotexists'] = 'nun esiste';
-$labels['filtermatches'] = 'espresiones que concasen';
-$labels['filternotmatches'] = 'espresiones que nun concasen';
-$labels['addrule'] = 'Amestar regla';
-$labels['delrule'] = 'Desaniciar regla';
-$labels['messagemoveto'] = 'Mover mensaxe a';
-$labels['messageredirect'] = 'Redireicionar mensaxe a';
-$labels['messagecopyto'] = 'Copiar mensaxe a';
-$labels['messagedelete'] = 'Desaniciar mensaxe';
-$labels['messagesrules'] = 'Pa corréu entrante:';
-$labels['messagesactions'] = '...executar les aiciones siguientes:';
-$labels['add'] = 'Amestar';
-$labels['del'] = 'Desaniciar';
-$labels['sender'] = 'Remitente';
-$labels['enable'] = 'Habilitar/Deshabilitar';
-$labels['flagread'] = 'Lleer';
-$labels['flagdeleted'] = 'Desaniciáu';
-$labels['flaganswered'] = 'Respondíu';
-?>
diff --git a/lib/plugins/managesieve/localization/az_AZ.inc b/lib/plugins/managesieve/localization/az_AZ.inc
deleted file mode 100644
index 8aec7e3..0000000
--- a/lib/plugins/managesieve/localization/az_AZ.inc
+++ /dev/null
@@ -1,188 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Süzgəclər';
-$labels['managefilters'] = 'Gələn məktub üçün süzgəclərin idarəsi';
-$labels['filtername'] = 'Süzgəcin adı';
-$labels['newfilter'] = 'Yeni süzgəc';
-$labels['filteradd'] = 'Süzgəc əlavə et';
-$labels['filterdel'] = 'Süzgəci sil';
-$labels['moveup'] = 'Yuxarı apar';
-$labels['movedown'] = 'Aşağı apar';
-$labels['filterallof'] = 'göstərilən bütün qaydalara uyur';
-$labels['filteranyof'] = 'verilmiş istənilən qaydaya uyur';
-$labels['filterany'] = 'bütün məktublar';
-$labels['filtercontains'] = 'daxildir';
-$labels['filternotcontains'] = 'daxil deyil';
-$labels['filteris'] = 'uyğundur';
-$labels['filterisnot'] = 'uyğun deyil';
-$labels['filterexists'] = 'mövcuddur';
-$labels['filternotexists'] = 'mövcud deyil';
-$labels['filtermatches'] = 'ifadə ilə üst-üstə düşür';
-$labels['filternotmatches'] = 'ifadə ilə üst-üstə düşmür';
-$labels['filterregex'] = 'daimi ifadənin nəticəsi ilə üst-üstə düşür';
-$labels['filternotregex'] = 'daimi ifadə ilə üst-üstə düşmür';
-$labels['filterunder'] = 'altında';
-$labels['filterover'] = 'yuxarıda';
-$labels['addrule'] = 'Qayda əlavə et';
-$labels['delrule'] = 'Qaydanı sil';
-$labels['messagemoveto'] = 'Məktubu köçür';
-$labels['messageredirect'] = 'Məktubu yolla';
-$labels['messagecopyto'] = 'Məktubu kopyala';
-$labels['messagesendcopy'] = 'Məktubun kopyasını göndər';
-$labels['messagereply'] = 'Məktubla cavab ver';
-$labels['messagedelete'] = 'Sil';
-$labels['messagediscard'] = 'Məktubla rədd et';
-$labels['messagekeep'] = 'Məktubu gələnlərdə saxla';
-$labels['messagesrules'] = 'Daxil olan məktub üçün:';
-$labels['messagesactions'] = '...növbəti hərəkəti yerinə yetir:';
-$labels['add'] = 'Əlavə et';
-$labels['del'] = 'Sil';
-$labels['sender'] = 'Göndərən';
-$labels['recipient'] = 'Qəbul edən';
-$labels['vacationaddr'] = 'Mənim əlavə e-poçt ünvan(lar)ım: ';
-$labels['vacationdays'] = 'Məktub neçə müddətdən bir göndərilsin (gündə):';
-$labels['vacationinterval'] = 'Məktublar nə qədər sıx göndərilsin:';
-$labels['vacationreason'] = 'Məktubun mətni (səbəb yoxdur):';
-$labels['vacationsubject'] = 'Məktubun mövzusu:';
-$labels['days'] = 'günlər';
-$labels['seconds'] = 'saniyələr';
-$labels['rulestop'] = 'Yerinə yetirməyi dayandır';
-$labels['enable'] = 'Yandır/Söndür';
-$labels['filterset'] = 'Süzgəc dəsti';
-$labels['filtersets'] = 'Süzgəc dəstləri';
-$labels['filtersetadd'] = 'Süzgəc dəsti əlavə et';
-$labels['filtersetdel'] = 'İndiki sücgəc dəstini sil';
-$labels['filtersetact'] = 'İndiki sücgəc dəstini yandır';
-$labels['filtersetdeact'] = 'İndiki süzgəc dəstini söndür';
-$labels['filterdef'] = 'Süzgəcin təsviri';
-$labels['filtersetname'] = 'Süzgəc dəstinin adı';
-$labels['newfilterset'] = 'Yeni süzgəc dəsti';
-$labels['active'] = 'aktiv';
-$labels['none'] = 'heç biri';
-$labels['fromset'] = 'dəstdən';
-$labels['fromfile'] = 'fayldan';
-$labels['filterdisabled'] = 'Süzgəci söndür';
-$labels['countisgreaterthan'] = 'sayı buradan daha çoxdur';
-$labels['countisgreaterthanequal'] = 'say çox və ya bərabərdir';
-$labels['countislessthan'] = 'say buradan azdır';
-$labels['countislessthanequal'] = 'say azdır və ya bərabərdir';
-$labels['countequals'] = 'say bərabərdir';
-$labels['countnotequals'] = 'say bərabər deyil';
-$labels['valueisgreaterthan'] = 'dəyər buradan daha böyükdür';
-$labels['valueisgreaterthanequal'] = 'dəyər çoxdur və ya bərabərdir';
-$labels['valueislessthan'] = 'dəyər buradan azdır';
-$labels['valueislessthanequal'] = 'dəyər azdır və ya bərabərdir';
-$labels['valueequals'] = 'dəyər bərabərdir';
-$labels['valuenotequals'] = 'dəyər bərabər deyil';
-$labels['setflags'] = 'Məktublara flaq quraşdır';
-$labels['addflags'] = 'Məktuba flaq əlavə et';
-$labels['removeflags'] = 'Məktubdan flaqları sil';
-$labels['flagread'] = 'Oxu';
-$labels['flagdeleted'] = 'Silindi';
-$labels['flaganswered'] = 'Cavab verilmiş';
-$labels['flagflagged'] = 'İşarəlilər';
-$labels['flagdraft'] = 'Qaralama';
-$labels['setvariable'] = 'Dəyişəni təyin et';
-$labels['setvarname'] = 'Dəyişənin adı:';
-$labels['setvarvalue'] = 'Dəyişənin dəyəri:';
-$labels['setvarmodifiers'] = 'Modifikatorlar';
-$labels['varlower'] = 'aşağı registr';
-$labels['varupper'] = 'yuxarı registr';
-$labels['varlowerfirst'] = 'aşağı registrdə birinci simvol';
-$labels['varupperfirst'] = 'yuxarı registrdə birinci simvol';
-$labels['varquotewildcard'] = 'dırnaq simvolu';
-$labels['varlength'] = 'uzunluq';
-$labels['notify'] = 'Bildiriş göndər';
-$labels['notifyimportance'] = 'Vaciblik';
-$labels['notifyimportancelow'] = 'aşağı';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'yuxarı';
-$labels['filtercreate'] = 'Süzgəc yarat';
-$labels['usedata'] = 'Süzgəcdə bu məlumatları istifadə et:';
-$labels['nextstep'] = 'Sonrakı';
-$labels['...'] = '...';
-$labels['currdate'] = 'Ä°ndiki tarix';
-$labels['datetest'] = 'Tarix';
-$labels['dateheader'] = 'başlıq:';
-$labels['year'] = 'il';
-$labels['month'] = 'ay';
-$labels['day'] = 'gün';
-$labels['date'] = 'tarix (iiii-aa-gg)';
-$labels['julian'] = 'tarix (yulian)';
-$labels['hour'] = 'saat';
-$labels['minute'] = 'dəqiqə';
-$labels['second'] = 'saniyə';
-$labels['time'] = 'saat (sa:dd:sn)';
-$labels['iso8601'] = 'tarix (ISO8601)';
-$labels['std11'] = 'tarix (RFC2822)';
-$labels['zone'] = 'saat-zona';
-$labels['weekday'] = 'həftənin günü (0-6)';
-$labels['advancedopts'] = 'Əlavə ayarlar';
-$labels['body'] = 'Məzmun';
-$labels['address'] = 'ünvan';
-$labels['envelope'] = 'zərf';
-$labels['modifier'] = 'modifikator:';
-$labels['text'] = 'mətn';
-$labels['undecoded'] = 'emal olunmamış (xammal)';
-$labels['contenttype'] = 'məzmun növü';
-$labels['modtype'] = 'növ:';
-$labels['allparts'] = 'hamısı';
-$labels['domain'] = 'domen';
-$labels['localpart'] = 'lokal hissə';
-$labels['user'] = 'istifadəçi';
-$labels['detail'] = 'təfsilat';
-$labels['comparator'] = 'komparator:';
-$labels['default'] = 'ön qurğulu';
-$labels['octet'] = 'ciddi (oktet)';
-$labels['asciicasemap'] = 'qeydiyyat üzrə müstəqil (ascii-casemap)';
-$labels['asciinumeric'] = 'ədədi (ascii-numeric)';
-$labels['index'] = 'indeks:';
-$labels['indexlast'] = 'arxaya';
-$messages['filterunknownerror'] = 'Serverin naməlum xətası.';
-$messages['filterconnerror'] = 'Serverə qoşulmaq alınmır';
-$messages['filterdeleteerror'] = 'Süzgəci silmək mümkün deyil. Server xətası.';
-$messages['filterdeleted'] = 'Süzgəc uğurla silindi.';
-$messages['filtersaved'] = 'Süzgəc uğurla saxlanıldı.';
-$messages['filtersaveerror'] = 'Süzgəci saxlamaq mümkün deyil. Server xətası.';
-$messages['filterdeleteconfirm'] = 'Siz həqiqətən süzgəci silmək istəyirsiniz?';
-$messages['ruledeleteconfirm'] = 'Bu qaydanı silməkdə əminsiniz?';
-$messages['actiondeleteconfirm'] = 'Bu hərəkəti silməkdə əminsiniz?';
-$messages['forbiddenchars'] = 'Sahədə qadağan edilən işarələr.';
-$messages['cannotbeempty'] = 'Sahə boş ola bilməz.';
-$messages['ruleexist'] = 'Bu adla süzgəc artıq mövcuddur.';
-$messages['setactivateerror'] = 'Seçilmiş süzgəcləri aktiv etmək mümkün deyil. Server xətası.';
-$messages['setdeactivateerror'] = 'Seçilmiş süzgəcləri deaktiv mümkün deyil. Server xətası.';
-$messages['setdeleteerror'] = 'Seçilmiş süzgəcləri silmək mümkün deyil. Server xətası.';
-$messages['setactivated'] = 'Süzgəc dəsti yandırıldı.';
-$messages['setdeactivated'] = 'Süzgəc dəsti söndürüldü.';
-$messages['setdeleted'] = 'Süzgəc dəsti silindi.';
-$messages['setdeleteconfirm'] = 'Bu süzgəc dəstini silməkdə əminsiniz?';
-$messages['setcreateerror'] = 'Süzgəcləri yaratmaq mümkün deyil. Server xətası.';
-$messages['setcreated'] = 'Süzgəc dəsti uğurla yaradıldı.';
-$messages['activateerror'] = 'Seçilmiş süzgəc(lər)i yandırmaq mümkün deyil. Server xətası.';
-$messages['deactivateerror'] = 'Seçilmiş süzgəc(lər)i söndürmək mümkün deyil. Server xətası.';
-$messages['deactivated'] = 'Süzgəc(lər) uğurla yandırıldı.';
-$messages['activated'] = 'Süzgəc(lər) uğurla söndürüldü.';
-$messages['moved'] = 'Süzgəc uğurla köçürüldü.';
-$messages['moveerror'] = 'Süzgəci köçürmək mümkün deyil. Server xətası.';
-$messages['nametoolong'] = 'Süzgəc dəstini yaratmaq mümkün deyil. Ad çox uzundur.';
-$messages['namereserved'] = 'Rezerv edilmiş ad.';
-$messages['setexist'] = 'Dəst artıq mövcuddur.';
-$messages['nodata'] = 'Heç olmasa bir mövqe tutmaq lazımdır!';
-$messages['invaliddateformat'] = 'Tarix və ya tarix formatının bir hissəsi səhvdir';
-?>
diff --git a/lib/plugins/managesieve/localization/be_BE.inc b/lib/plugins/managesieve/localization/be_BE.inc
deleted file mode 100644
index 5a691cd..0000000
--- a/lib/plugins/managesieve/localization/be_BE.inc
+++ /dev/null
@@ -1,188 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Фільтры';
-$labels['managefilters'] = 'Парадкаваць фільтры атрыманай пошты';
-$labels['filtername'] = 'Назва фільтра';
-$labels['newfilter'] = 'Новы фільтр';
-$labels['filteradd'] = 'Дадаць фільтр';
-$labels['filterdel'] = 'Выдаліць фільтр';
-$labels['moveup'] = 'Пасунуць уверх';
-$labels['movedown'] = 'Пасунуць уніз';
-$labels['filterallof'] = 'выконваюцца ўсе наступныя правілы';
-$labels['filteranyof'] = 'выконваецца любое з наступных правіл';
-$labels['filterany'] = 'усе паведамленні';
-$labels['filtercontains'] = 'змяшчае';
-$labels['filternotcontains'] = 'не змяшчае';
-$labels['filteris'] = 'роўна';
-$labels['filterisnot'] = 'не роўна';
-$labels['filterexists'] = 'існуе';
-$labels['filternotexists'] = 'не існуе';
-$labels['filtermatches'] = 'задавальняе выразу';
-$labels['filternotmatches'] = 'не задавальняе выразу';
-$labels['filterregex'] = 'задавальняе рэгулярнаму выразу';
-$labels['filternotregex'] = 'не задавальняе рэгулярнаму выразу';
-$labels['filterunder'] = 'менш';
-$labels['filterover'] = 'больш';
-$labels['addrule'] = 'Дадаць правіла';
-$labels['delrule'] = 'Выдаліць правіла';
-$labels['messagemoveto'] = 'Перамясціць паведамленне ў';
-$labels['messageredirect'] = 'Перанакіраваць паведамленне на';
-$labels['messagecopyto'] = 'Скапіяваць паведамленне ў';
-$labels['messagesendcopy'] = 'Даслаць копію на';
-$labels['messagereply'] = 'Адказаць наступнае';
-$labels['messagedelete'] = 'Выдаліць паведамленне';
-$labels['messagediscard'] = 'Скасаваць з паведамленнем';
-$labels['messagekeep'] = 'Пакінуць паведамленне ў Атрыманых';
-$labels['messagesrules'] = 'Для атрыманай пошты:';
-$labels['messagesactions'] = '...выконваць наступныя дзеянні:';
-$labels['add'] = 'Дадаць';
-$labels['del'] = 'Выдаліць';
-$labels['sender'] = 'Ад каго';
-$labels['recipient'] = 'Каму';
-$labels['vacationaddr'] = 'Дадатковы(я) адрасы эл. пошты:';
-$labels['vacationdays'] = 'Як часта дасылаць паведамленні (у днях):';
-$labels['vacationinterval'] = 'Як часта дасылаць паведамленні:';
-$labels['vacationreason'] = 'Цела паведамлення (прычына вакацый):';
-$labels['vacationsubject'] = 'Тэма паведамлення:';
-$labels['days'] = 'дзён';
-$labels['seconds'] = 'секунд';
-$labels['rulestop'] = 'Перастаць выконваць праверку правілаў';
-$labels['enable'] = 'Уключыць/Выключыць';
-$labels['filterset'] = 'Набор фільтраў';
-$labels['filtersets'] = 'Наборы фільтраў';
-$labels['filtersetadd'] = 'Дадаць набор фільтраў';
-$labels['filtersetdel'] = 'Выдаліць бягучы набор фільтраў';
-$labels['filtersetact'] = 'Актываваць бягучы набор фільтраў';
-$labels['filtersetdeact'] = 'Дэактываваць бягучы набор фільтраў';
-$labels['filterdef'] = 'Вызначэнне фільтра';
-$labels['filtersetname'] = 'Назва набору фільтраў';
-$labels['newfilterset'] = 'Новы набор фільтраў';
-$labels['active'] = 'актыўны';
-$labels['none'] = 'няма';
-$labels['fromset'] = 'з набору';
-$labels['fromfile'] = 'з файла';
-$labels['filterdisabled'] = 'Фільтр адключаны';
-$labels['countisgreaterthan'] = 'лік большы за';
-$labels['countisgreaterthanequal'] = 'лік большы за альбо роўны';
-$labels['countislessthan'] = 'лік меншы за';
-$labels['countislessthanequal'] = 'лік меншы за альбо роўны';
-$labels['countequals'] = 'лік роўны';
-$labels['countnotequals'] = 'лік не роўны';
-$labels['valueisgreaterthan'] = 'значэнне большае за';
-$labels['valueisgreaterthanequal'] = 'значэнне большае за альбо роўнае';
-$labels['valueislessthan'] = 'значэнне меншае за';
-$labels['valueislessthanequal'] = 'значэнне меншае за альбо роўнае';
-$labels['valueequals'] = 'значэнне роўнае';
-$labels['valuenotequals'] = 'значэнне не роўнае';
-$labels['setflags'] = 'Устанавіць флагі на паведамленне';
-$labels['addflags'] = 'Дадаць флагі да паведамлення';
-$labels['removeflags'] = 'Выдаліць флагі з паведамлення';
-$labels['flagread'] = 'Прачытана';
-$labels['flagdeleted'] = 'Выдалена';
-$labels['flaganswered'] = 'З адказам';
-$labels['flagflagged'] = 'Пазначана';
-$labels['flagdraft'] = 'Чарнавік';
-$labels['setvariable'] = 'Устанавіць зменную';
-$labels['setvarname'] = 'Імя зменнай:';
-$labels['setvarvalue'] = 'Значэнне зменнай:';
-$labels['setvarmodifiers'] = 'Мадыфікатары:';
-$labels['varlower'] = 'ніжні рэгістр';
-$labels['varupper'] = 'верхні рэгістр';
-$labels['varlowerfirst'] = 'першы знак у ніжнім рэгістры';
-$labels['varupperfirst'] = 'першы знак у верхнім рэгістры';
-$labels['varquotewildcard'] = 'службовыя знакі забіраць у апострафы';
-$labels['varlength'] = 'даўжыня';
-$labels['notify'] = 'Паслаць апавяшчэнне';
-$labels['notifyimportance'] = 'Важнасць:';
-$labels['notifyimportancelow'] = 'нізкая';
-$labels['notifyimportancenormal'] = 'звычайная';
-$labels['notifyimportancehigh'] = 'высокая';
-$labels['filtercreate'] = 'Стварыць фільтр';
-$labels['usedata'] = 'Ужываць наступныя дадзеныя ў фільтры:';
-$labels['nextstep'] = 'Наступны крок';
-$labels['...'] = '...';
-$labels['currdate'] = 'Бягучая дата';
-$labels['datetest'] = 'Дата';
-$labels['dateheader'] = 'загаловак:';
-$labels['year'] = 'год';
-$labels['month'] = 'месяц';
-$labels['day'] = 'дзень';
-$labels['date'] = 'дата (гггг-мм-дд)';
-$labels['julian'] = 'дата (юліянская)';
-$labels['hour'] = 'гадзіна';
-$labels['minute'] = 'мінута';
-$labels['second'] = 'секунда';
-$labels['time'] = 'час (гг:мм:сс)';
-$labels['iso8601'] = 'дата (ISO8601)';
-$labels['std11'] = 'дата (RFC2822)';
-$labels['zone'] = 'часавая зона';
-$labels['weekday'] = 'дзень тыдня (0-6)';
-$labels['advancedopts'] = 'Дадатковыя параметры';
-$labels['body'] = 'Цела';
-$labels['address'] = 'адрас';
-$labels['envelope'] = 'канверт';
-$labels['modifier'] = 'мадыфікатар:';
-$labels['text'] = 'тэкст';
-$labels['undecoded'] = 'неапрацаваны (сыры)';
-$labels['contenttype'] = 'тып змесціва';
-$labels['modtype'] = 'пошук у адрасах:';
-$labels['allparts'] = 'усюль';
-$labels['domain'] = 'у імені дамена';
-$labels['localpart'] = 'толькі ў імені карыстальніка, без дамена';
-$labels['user'] = 'у поўным імені карыстальніка';
-$labels['detail'] = 'у дадатковых звестках';
-$labels['comparator'] = 'спосаб параўнання:';
-$labels['default'] = 'стандартны';
-$labels['octet'] = 'строгі (octet)';
-$labels['asciicasemap'] = 'без уліку рэгістру (ascii-casemap)';
-$labels['asciinumeric'] = 'лікавы (ascii-numeric)';
-$labels['index'] = 'індэкс:';
-$labels['indexlast'] = 'назад';
-$messages['filterunknownerror'] = 'Невядомая памылка сервера.';
-$messages['filterconnerror'] = 'Не ўдалося злучыцца з серверам.';
-$messages['filterdeleteerror'] = 'Не ўдалося выдаліць фільтр. Памылка на серверы.';
-$messages['filterdeleted'] = 'Фільтр выдалены.';
-$messages['filtersaved'] = 'Фільтр захаваны.';
-$messages['filtersaveerror'] = 'Не ўдалося захаваць фільтр. Памылка на серверы.';
-$messages['filterdeleteconfirm'] = 'Напраўду выдаліць абраны фільтр?';
-$messages['ruledeleteconfirm'] = 'Напраўду выдаліць абранае правіла?';
-$messages['actiondeleteconfirm'] = 'Напраўду выдаліць абранае дзеянне?';
-$messages['forbiddenchars'] = 'Забароненыя знакі ў полі.';
-$messages['cannotbeempty'] = 'Поле не можа быць пустым.';
-$messages['ruleexist'] = 'Фільтр з гэтай назвай ужо існуе.';
-$messages['setactivateerror'] = 'Не ўдалося ўключыць абраны набор фільтраў. Памылка на серверы.';
-$messages['setdeactivateerror'] = 'Не ўдалося адключыць абраны набор фільтраў. Памылка на серверы.';
-$messages['setdeleteerror'] = 'Не ўдалося выдаліць абраны набор фільтраў. Памылка на серверы.';
-$messages['setactivated'] = 'Набор фільтраў актываваны.';
-$messages['setdeactivated'] = 'Набор фільтраў дэактываваны.';
-$messages['setdeleted'] = 'Набор фільтраў выдалены.';
-$messages['setdeleteconfirm'] = 'Напраўду выдаліць абраны набор фільтраў?';
-$messages['setcreateerror'] = 'Не ўдалося стварыць набор фільтраў. Памылка на серверы.';
-$messages['setcreated'] = 'Набор фільтраў створаны.';
-$messages['activateerror'] = 'Не ўдалося ўключыць абраны(я) фільтры. Памылка на серверы.';
-$messages['deactivateerror'] = 'Не ўдалося адключыць абраны(я) фільтры. Памылка на серверы.';
-$messages['deactivated'] = 'Фільтр(ы) адключаны.';
-$messages['activated'] = 'Фільтр(ы) уключаны.';
-$messages['moved'] = 'Фільтр перамешчаны.';
-$messages['moveerror'] = 'Не ўдалося перамясціць абраны фільтр. Памылка на серверы.';
-$messages['nametoolong'] = 'Задаўгая назва.';
-$messages['namereserved'] = 'Зарэзерваваная назва.';
-$messages['setexist'] = 'Набор ужо існуе.';
-$messages['nodata'] = 'Мінімум адна пазіцыя павінна быць вылучана!';
-$messages['invaliddateformat'] = 'Няслушная дата альбо фармат даты';
-?>
diff --git a/lib/plugins/managesieve/localization/bg_BG.inc b/lib/plugins/managesieve/localization/bg_BG.inc
deleted file mode 100644
index 432cb4f..0000000
--- a/lib/plugins/managesieve/localization/bg_BG.inc
+++ /dev/null
@@ -1,209 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Филтри';
-$labels['managefilters'] = 'Управление на филтри за входяща поща';
-$labels['filtername'] = 'Име на филтър';
-$labels['newfilter'] = 'Нов филтър';
-$labels['filteradd'] = 'Нов филтър';
-$labels['filterdel'] = 'Изтриване на филтър';
-$labels['moveup'] = 'Преместване нагоре';
-$labels['movedown'] = 'Преместване надолу';
-$labels['filterallof'] = 'която изпълнява всички условия';
-$labels['filteranyof'] = 'която изпълнява някое от условията';
-$labels['filterany'] = 'за всички писма';
-$labels['filtercontains'] = 'съдържа';
-$labels['filternotcontains'] = 'не съдържа';
-$labels['filteris'] = 'е равно на';
-$labels['filterisnot'] = 'не е равно на';
-$labels['filterexists'] = 'съществува';
-$labels['filternotexists'] = 'не съществува';
-$labels['filtermatches'] = 'съвпада с израз';
-$labels['filternotmatches'] = 'не съвпада с израз';
-$labels['filterregex'] = 'отговаря на регулярен израз';
-$labels['filternotregex'] = 'не отговаря на регулярен израз';
-$labels['filterunder'] = 'под';
-$labels['filterover'] = 'над';
-$labels['addrule'] = 'Ново условие';
-$labels['delrule'] = 'Изтриване на условие';
-$labels['messagemoveto'] = 'Премести писмото във';
-$labels['messageredirect'] = 'Пренасочи писмото до';
-$labels['messagecopyto'] = 'Копирай писмото във';
-$labels['messagesendcopy'] = 'Изпрати копие на писмото до';
-$labels['messagereply'] = 'Отговори с писмо';
-$labels['messagedelete'] = 'Изтрий писмото';
-$labels['messagediscard'] = 'Отхвърли със съобщение';
-$labels['messagekeep'] = 'Остави писмото във Вх. поща';
-$labels['messagesrules'] = 'При получаване на поща...';
-$labels['messagesactions'] = '...изпълни следните действия:';
-$labels['add'] = 'Добави';
-$labels['del'] = 'Изтрий';
-$labels['sender'] = 'Подател';
-$labels['recipient'] = 'Получател';
-$labels['vacationaddr'] = 'Мои допълнителни e-mail адреси:';
-$labels['vacationdays'] = 'Колко често да праща писма (в дни):';
-$labels['vacationinterval'] = 'Колко често да праща писма:';
-$labels['vacationreason'] = 'Текст на писмото (причина за ваканцията)';
-$labels['vacationsubject'] = 'Заглавие на писмото';
-$labels['days'] = 'дни';
-$labels['seconds'] = 'секунди';
-$labels['rulestop'] = 'Спри проверка на други условия';
-$labels['enable'] = 'Включи/Изключи';
-$labels['filterset'] = 'Набор филтри';
-$labels['filtersets'] = 'Набори филтри';
-$labels['filtersetadd'] = 'Нов набор филтри';
-$labels['filtersetdel'] = 'Изтриване на текущ набор филтри';
-$labels['filtersetact'] = 'Активиране на текущ набор филтри';
-$labels['filtersetdeact'] = 'Деактивиране на текущ набор филтри';
-$labels['filterdef'] = 'Дефиниране на филтър';
-$labels['filtersetname'] = 'Име на набор филтри';
-$labels['newfilterset'] = 'Нов набор филтри';
-$labels['active'] = 'активен';
-$labels['none'] = 'няма';
-$labels['fromset'] = 'от набор';
-$labels['fromfile'] = 'от файл';
-$labels['filterdisabled'] = 'Изключен филтър';
-$labels['countisgreaterthan'] = 'брой е по-голям от';
-$labels['countisgreaterthanequal'] = 'брой е по-голям или равен на';
-$labels['countislessthan'] = 'брой е по-малък от';
-$labels['countislessthanequal'] = 'брой е по-малък или равен на';
-$labels['countequals'] = 'брой е равен на';
-$labels['countnotequals'] = 'брой не е равен на';
-$labels['valueisgreaterthan'] = 'стойност е по-голяма от';
-$labels['valueisgreaterthanequal'] = 'стойност е по-голяма или равна на';
-$labels['valueislessthan'] = 'стойност е по-малка от';
-$labels['valueislessthanequal'] = 'стойност е по-малка или равна на';
-$labels['valueequals'] = 'стойност е равна на';
-$labels['valuenotequals'] = 'стойност не е равна на';
-$labels['setflags'] = 'Установи флагове на писмо';
-$labels['addflags'] = 'Добави флагове към писмо';
-$labels['removeflags'] = 'Премахни флагове от писмо';
-$labels['flagread'] = 'Прочетено';
-$labels['flagdeleted'] = 'Изтрито';
-$labels['flaganswered'] = 'Отговорено';
-$labels['flagflagged'] = 'Отбелязано';
-$labels['flagdraft'] = 'Чернова';
-$labels['setvariable'] = 'Установи променлива';
-$labels['setvarname'] = 'Име на променлива:';
-$labels['setvarvalue'] = 'Стойност на променлива:';
-$labels['setvarmodifiers'] = 'Модификатори:';
-$labels['varlower'] = 'малки букви';
-$labels['varupper'] = 'главни букви';
-$labels['varlowerfirst'] = 'първи знак с малка буква';
-$labels['varupperfirst'] = 'първи знак с главна буква';
-$labels['varquotewildcard'] = 'цитиране на специални знаци';
-$labels['varlength'] = 'дължина';
-$labels['notify'] = 'Изпрати известие';
-$labels['notifytarget'] = 'Известие към:';
-$labels['notifymessage'] = 'Съдържание на известие (опционално):';
-$labels['notifyoptions'] = 'Опции на известие (опционално):';
-$labels['notifyfrom'] = 'Известие от (опционално):';
-$labels['notifyimportance'] = 'Приоритет:';
-$labels['notifyimportancelow'] = 'нисък';
-$labels['notifyimportancenormal'] = 'нормален';
-$labels['notifyimportancehigh'] = 'висок';
-$labels['notifymethodmailto'] = 'Ел. поща';
-$labels['notifymethodtel'] = 'Телефон';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Използвай за нов филтър';
-$labels['usedata'] = 'Използвай следните данни във филтъра:';
-$labels['nextstep'] = 'Следваща стъпка';
-$labels['...'] = '...';
-$labels['currdate'] = 'Текуща дата';
-$labels['datetest'] = 'Дата';
-$labels['dateheader'] = 'заглавен блок:';
-$labels['year'] = 'година';
-$labels['month'] = 'месец';
-$labels['day'] = 'ден';
-$labels['date'] = 'дата (гггг-мм-дд)';
-$labels['julian'] = 'дата (юлианска)';
-$labels['hour'] = 'час';
-$labels['minute'] = 'минута';
-$labels['second'] = 'секунда';
-$labels['time'] = 'време (чч:мм:сс)';
-$labels['iso8601'] = 'дата (ISO8601)';
-$labels['std11'] = 'дата (RFC2822)';
-$labels['zone'] = 'часова зона';
-$labels['weekday'] = 'ден от седмицата (0-6)';
-$labels['advancedopts'] = 'Разширени настройки';
-$labels['body'] = 'Основен текст';
-$labels['address'] = 'адрес';
-$labels['envelope'] = 'плик';
-$labels['modifier'] = 'модификатор:';
-$labels['text'] = 'текст';
-$labels['undecoded'] = 'недекодиран (суров)';
-$labels['contenttype'] = 'тип на съдържанието';
-$labels['modtype'] = 'тип:';
-$labels['allparts'] = 'всичко';
-$labels['domain'] = 'домейн';
-$labels['localpart'] = 'локална част';
-$labels['user'] = 'потребител';
-$labels['detail'] = 'датайли';
-$labels['comparator'] = 'сравнител:';
-$labels['default'] = 'по подразбиране';
-$labels['octet'] = 'стриктно (октет)';
-$labels['asciicasemap'] = 'без значение малки/големи букви';
-$labels['asciinumeric'] = 'цифрово';
-$labels['index'] = 'индекс:';
-$labels['indexlast'] = 'наобратно';
-$labels['vacation'] = 'Отпуск';
-$labels['vacation.reply'] = 'Писмо отговор';
-$labels['vacation.advanced'] = 'Разширени настройки';
-$labels['vacation.subject'] = 'Относно';
-$labels['vacation.body'] = 'Съдържание';
-$labels['vacation.status'] = 'Статус';
-$labels['vacation.on'] = 'Вкл.';
-$labels['vacation.off'] = 'Изкл.';
-$labels['vacation.addresses'] = 'Моите допълнителни адреси';
-$labels['vacation.interval'] = 'Интервал на отговор';
-$labels['vacation.after'] = 'Постави правило за отпуск след';
-$labels['vacation.saving'] = 'Запис на данни...';
-$messages['filterunknownerror'] = 'Неизвестна сървърна грешка.';
-$messages['filterconnerror'] = 'Неуспешно свързване с managesieve сървъра.';
-$messages['filterdeleteerror'] = 'Невъзможно изтриване на филтъра. Възникна сървърна грешка.';
-$messages['filterdeleted'] = 'Филтърът е изтрит успешно.';
-$messages['filtersaved'] = 'Филтърът е записан успешно.';
-$messages['filtersaveerror'] = 'Невъзможно записване на филтъра. Възникна сървърна грешка.';
-$messages['filterdeleteconfirm'] = 'Наистина ли желаете да изтриете избрания филтър?';
-$messages['ruledeleteconfirm'] = 'Сигурни ли сте, че желаете да изтриете избраното условие?';
-$messages['actiondeleteconfirm'] = 'Сигурни ли сте, че желаете да изтриете избраното действие?';
-$messages['forbiddenchars'] = 'Забранени символи в полето.';
-$messages['cannotbeempty'] = 'Полето не може да бъде празно.';
-$messages['ruleexist'] = 'Вече има филтър с указаното име.';
-$messages['setactivateerror'] = 'Невъзможно активиране на избрания набор от филтри. Възникна сървърна грешка.';
-$messages['setdeactivateerror'] = 'Невъзможно деактивиране на избрания набор от филтри. Възникна сървърна грешка.';
-$messages['setdeleteerror'] = 'Невъзможно изтриване на избрания набор от филтри. Възникна сървърна грешка.';
-$messages['setactivated'] = 'Наборът от филтри е активиран успешно.';
-$messages['setdeactivated'] = 'Наборът от филтри е деактивиран успешно.';
-$messages['setdeleted'] = 'Наборът от филтри е изтрит успешно.';
-$messages['setdeleteconfirm'] = 'Сигурни ли сте, че желаете да изтриете избрания набор от филтри?';
-$messages['setcreateerror'] = 'Невъзможно създаване на набор от филтри. Възникна сървърна грешка.';
-$messages['setcreated'] = 'Наборът от филтри е създаден успешно.';
-$messages['activateerror'] = 'Невъзможно включване на филтъра. Възникна сървърна грешка.';
-$messages['deactivateerror'] = 'Невъзможно изключване на филтъра. Възникна сървърна грешка.';
-$messages['deactivated'] = 'Филтърът е изключен успешно.';
-$messages['activated'] = 'Филтърът е включен успешно.';
-$messages['moved'] = 'Филтърът е преместен успешно.';
-$messages['moveerror'] = 'Невъзможно преместване на филтъра. Възникна сървърна грешка.';
-$messages['nametoolong'] = 'Името е прекалено дълго.';
-$messages['namereserved'] = 'Резервирано име.';
-$messages['setexist'] = 'Вече има такъв набор филтри.';
-$messages['nodata'] = 'Поне една позиция трябва да е избрана!';
-$messages['invaliddateformat'] = 'невалидна дата или формат на част от дата';
-$messages['saveerror'] = 'Невъзможен запис на данни. Грешка при достъп до сървър.';
-$messages['vacationsaved'] = 'Данните за отпуск са записани успешно.';
-?>
diff --git a/lib/plugins/managesieve/localization/br.inc b/lib/plugins/managesieve/localization/br.inc
deleted file mode 100644
index c7d89f5..0000000
--- a/lib/plugins/managesieve/localization/br.inc
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'sil';
-$labels['newfilter'] = 'Sil nevez';
-$labels['filteradd'] = 'Ouzhpenan ur sil';
-$labels['filterdel'] = 'Dilemel ar sil';
-$labels['filterany'] = 'An holl postel';
-$labels['messagecopyto'] = 'eilan ar postel e';
-$labels['messagedelete'] = 'Dilemel ar postel';
-$labels['add'] = 'Ouzhpenan';
-$labels['del'] = 'Dilemel';
-$labels['sender'] = 'Kaser';
-$labels['recipient'] = 'Resever';
-$labels['vacationsubject'] = 'Sujed';
-?>
diff --git a/lib/plugins/managesieve/localization/bs_BA.inc b/lib/plugins/managesieve/localization/bs_BA.inc
deleted file mode 100644
index 84a85a3..0000000
--- a/lib/plugins/managesieve/localization/bs_BA.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filteri';
-$labels['managefilters'] = 'Upravljanje dolaznim email filterima';
-$labels['filtername'] = 'Naziv filtera';
-$labels['newfilter'] = 'Novi filter';
-$labels['filteradd'] = 'Dodaj filter';
-$labels['filterdel'] = 'Obriši filter';
-$labels['moveup'] = 'Pomjeri gore';
-$labels['movedown'] = 'Pomjeri dole';
-$labels['filterallof'] = 'poklapa se sa svim sljedećim pravilima';
-$labels['filteranyof'] = 'poklapa se sa bilo kojim od sljedećih pravila';
-$labels['filterany'] = 'sve poruke';
-$labels['filtercontains'] = 'sadrži';
-$labels['filternotcontains'] = 'ne sadrži';
-$labels['filteris'] = 'jednako';
-$labels['filterisnot'] = 'nije jednako';
-$labels['filterexists'] = 'postoji';
-$labels['filternotexists'] = 'ne postoji';
-$labels['filtermatches'] = 'poklapa se sa izrazom';
-$labels['filternotmatches'] = 'ne poklapa se sa izrazom';
-$labels['filterregex'] = 'poklapa se sa regularnim izrazom';
-$labels['filternotregex'] = 'ne poklapa se sa regularnim izrazom';
-$labels['filterunder'] = 'ispod';
-$labels['filterover'] = 'iznad';
-$labels['addrule'] = 'Dodaj pravilo';
-$labels['delrule'] = 'Obriši pravilo';
-$labels['messagemoveto'] = 'Premjesti poruku u';
-$labels['messageredirect'] = 'Preusmjeri poruku ka';
-$labels['messagecopyto'] = 'Kopiraj poruku u';
-$labels['messagesendcopy'] = 'Pošalji kopiju poruke';
-$labels['messagereply'] = 'Odgovori';
-$labels['messagedelete'] = 'Obriši poruku';
-$labels['messagediscard'] = 'Odbaci sa porukom';
-$labels['messagekeep'] = 'Zadrži poruku u sandučetu';
-$labels['messagesrules'] = 'Za dolazne emailove:';
-$labels['messagesactions'] = '...izvrši sljedeće akcije:';
-$labels['add'] = 'Dodaj';
-$labels['del'] = 'Obriši';
-$labels['sender'] = 'Pošiljaoc';
-$labels['recipient'] = 'Primaoc';
-$labels['vacationaddr'] = 'Moje dodatne email adrese:';
-$labels['vacationdays'] = 'Frekvencija slanja poruka (u danima):';
-$labels['vacationinterval'] = 'Frekvencija slanja poruka:';
-$labels['vacationreason'] = 'Tijelo poruke (razlog za odmor):';
-$labels['vacationsubject'] = 'Naslov poruke:';
-$labels['days'] = 'dana';
-$labels['seconds'] = 'sekundi';
-$labels['rulestop'] = 'Prestani procjenjivati pravila';
-$labels['enable'] = 'Omogući/Onemogući';
-$labels['filterset'] = 'Set filtera';
-$labels['filtersets'] = 'Setovi filtera';
-$labels['filtersetadd'] = 'Dodaj set filtera';
-$labels['filtersetdel'] = 'Obriši trenutni set filtera';
-$labels['filtersetact'] = 'Aktiviraj trenutni set filtera';
-$labels['filtersetdeact'] = 'Deaktiviraj trenutni set filtera';
-$labels['filterdef'] = 'Definicija filtera';
-$labels['filtersetname'] = 'Naziv seta filtera';
-$labels['newfilterset'] = 'Novi set filtera';
-$labels['active'] = 'aktivno';
-$labels['none'] = 'ništa';
-$labels['fromset'] = 'iz seta';
-$labels['fromfile'] = 'iz datoteke';
-$labels['filterdisabled'] = 'Filter je onemogućen';
-$labels['countisgreaterthan'] = 'brojač je veći od';
-$labels['countisgreaterthanequal'] = 'brojač je veći ili jednak';
-$labels['countislessthan'] = 'brojač je manji od';
-$labels['countislessthanequal'] = 'brojač je manji ili jednak';
-$labels['countequals'] = 'brojač je jednak';
-$labels['countnotequals'] = 'zbir nije jednak';
-$labels['valueisgreaterthan'] = 'vrijednost je veća od';
-$labels['valueisgreaterthanequal'] = 'vrijednost je veća ili jednaka';
-$labels['valueislessthan'] = 'vrijednost je manja od';
-$labels['valueislessthanequal'] = 'vrijednost je manja ili jednaka';
-$labels['valueequals'] = 'vrijednost je jednaka';
-$labels['valuenotequals'] = 'vrijednost nije jednaka';
-$labels['setflags'] = 'Postavi oznake za poruku';
-$labels['addflags'] = 'Dodaj oznake u poruku';
-$labels['removeflags'] = 'Ukloni oznake iz poruke';
-$labels['flagread'] = 'Pročitano';
-$labels['flagdeleted'] = 'Obrisano';
-$labels['flaganswered'] = 'Odgovoreno';
-$labels['flagflagged'] = 'Važno';
-$labels['flagdraft'] = 'Skica';
-$labels['setvariable'] = 'Postavi promjenjivu';
-$labels['setvarname'] = 'Naziv promjenjive:';
-$labels['setvarvalue'] = 'Vrijednost promjenjive:';
-$labels['setvarmodifiers'] = 'Parametri:';
-$labels['varlower'] = 'mala slova';
-$labels['varupper'] = 'velika slova';
-$labels['varlowerfirst'] = 'prvi znak malim slovom';
-$labels['varupperfirst'] = 'prvi znak velikim slovom';
-$labels['varquotewildcard'] = 'citiraj specijalne znakove';
-$labels['varlength'] = 'dužina';
-$labels['notify'] = 'Pošalji napomenu';
-$labels['notifytarget'] = 'Odredište napomene:';
-$labels['notifymessage'] = 'Poruka napomene (neobavezno):';
-$labels['notifyoptions'] = 'Opcije napomene (neobavezno):';
-$labels['notifyfrom'] = 'Pošiljalac napomene (neobavezno):';
-$labels['notifyimportance'] = 'Prioritet:';
-$labels['notifyimportancelow'] = 'mali';
-$labels['notifyimportancenormal'] = 'obični';
-$labels['notifyimportancehigh'] = 'veliki';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Telefon';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Kreiraj filter';
-$labels['usedata'] = 'Koristite sljedeće podatke u filteru:';
-$labels['nextstep'] = 'Sljedeći korak';
-$labels['...'] = '...';
-$labels['currdate'] = 'Trenutni datum';
-$labels['datetest'] = 'Datum';
-$labels['dateheader'] = 'zaglavlje:';
-$labels['year'] = 'godina';
-$labels['month'] = 'mjesec';
-$labels['day'] = 'dan';
-$labels['date'] = 'datum (gggg-mm-dd)';
-$labels['julian'] = 'datum (julijanski)';
-$labels['hour'] = 'sat';
-$labels['minute'] = 'minuta';
-$labels['second'] = 'sekunda';
-$labels['time'] = 'vrijeme (hh:mm:ss)';
-$labels['iso8601'] = 'datum (ISO8601)';
-$labels['std11'] = 'datum (RFC2822)';
-$labels['zone'] = 'vremenska zona';
-$labels['weekday'] = 'sedmica (0-6)';
-$labels['advancedopts'] = 'Napredne opcije';
-$labels['body'] = 'Tijelo';
-$labels['address'] = 'adresa';
-$labels['envelope'] = 'koverta';
-$labels['modifier'] = 'prilagođavanje:';
-$labels['text'] = 'tekst';
-$labels['undecoded'] = 'nekodiran (obični)';
-$labels['contenttype'] = 'vrsta sadržaja';
-$labels['modtype'] = 'vrsta:';
-$labels['allparts'] = 'sve';
-$labels['domain'] = 'domena';
-$labels['localpart'] = 'lokalni dio';
-$labels['user'] = 'korisnik';
-$labels['detail'] = 'detalji';
-$labels['comparator'] = 'upoređivač:';
-$labels['default'] = 'početno';
-$labels['octet'] = 'striktno (oktet)';
-$labels['asciicasemap'] = 'osjetljivo na velika/mala slova (ascii-casemap)';
-$labels['asciinumeric'] = 'numerički (ascii-numeric)';
-$labels['index'] = 'indeks:';
-$labels['indexlast'] = 'unazad';
-$labels['vacation'] = 'Odmor';
-$labels['vacation.reply'] = 'Poruka sa odgovorom';
-$labels['vacation.advanced'] = 'Napredmen postavke';
-$labels['vacation.subject'] = 'Naslov';
-$labels['vacation.body'] = 'Tijelo';
-$labels['vacation.start'] = 'Početak odmora';
-$labels['vacation.end'] = 'Kraj odmora';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.on'] = 'Uključeno';
-$labels['vacation.off'] = 'Isključeno';
-$labels['vacation.addresses'] = 'Moje dodatne adrese';
-$labels['vacation.interval'] = 'Interval odgovora';
-$labels['vacation.after'] = 'Pravilo za odmor stavi nakon';
-$labels['vacation.saving'] = 'Snimam podatke...';
-$labels['vacation.action'] = 'Akcija za dolazne poruke';
-$labels['vacation.keep'] = 'Zadrži';
-$labels['vacation.discard'] = 'Odbaci';
-$labels['vacation.redirect'] = 'Preusmeri ka';
-$labels['vacation.copy'] = 'Pošalji kopiju na';
-$labels['arialabelfiltersetactions'] = 'Akcije za filterske setove';
-$labels['arialabelfilteractions'] = 'Filterske akcije';
-$labels['arialabelfilterform'] = 'Svojstva filtera';
-$labels['ariasummaryfilterslist'] = 'Lista filtera';
-$labels['ariasummaryfiltersetslist'] = 'Lista filterskih setova';
-$labels['filterstitle'] = 'Uredi filtere za dolazni email';
-$labels['vacationtitle'] = 'Uredi pravila kada nisam na poslu';
-$messages['filterunknownerror'] = 'Nepoznata serverska greška.';
-$messages['filterconnerror'] = 'Nije se moguće povezati na server.';
-$messages['filterdeleteerror'] = 'Nije moguće obrisati filter. Desila se serverska greška.';
-$messages['filterdeleted'] = 'Filter je uspješno obrisan.';
-$messages['filtersaved'] = 'Filter je uspješno sačuvan.';
-$messages['filtersaveerror'] = 'Nije moguće sačuvati filter. Desila se serverska greška.';
-$messages['filterdeleteconfirm'] = 'Da li zaista želite obrisati označeni filter?';
-$messages['ruledeleteconfirm'] = 'Jeste li sigurni da želite obrisati označeno pravilo?';
-$messages['actiondeleteconfirm'] = 'Jeste li sigurni da želite obrisati označenu akciju?';
-$messages['forbiddenchars'] = 'U polje su uneseni nedozvoljeni znakovi.';
-$messages['cannotbeempty'] = 'Polje ne može biti prazno.';
-$messages['ruleexist'] = 'Filter s tim imenom već postoji.';
-$messages['setactivateerror'] = 'Nije moguće aktivirati označeni set filtera. Desila se serverska greška.';
-$messages['setdeactivateerror'] = 'Nije moguće deaktivirati označeni set filtera. Desila se serverska greška.';
-$messages['setdeleteerror'] = 'Nije moguće obrisati označeni set filtera. Desila se serverska greška.';
-$messages['setactivated'] = 'Set filtera je uspješno aktiviran.';
-$messages['setdeactivated'] = 'Set filtera je uspješno deaktiviran.';
-$messages['setdeleted'] = 'Set filtera je uspješno obrisan.';
-$messages['setdeleteconfirm'] = 'Jeste li sigurni da želite obrisati označeni set filtera?';
-$messages['setcreateerror'] = 'Nije moguće kreirati set filtera. Desila se serverska greška.';
-$messages['setcreated'] = 'Set filtera je uspješno kreiran.';
-$messages['activateerror'] = 'Nije moguće omogućiti označene filtere. Desila se serverska greška.';
-$messages['deactivateerror'] = 'Nije moguće onemogućiti označene filtere. Desila se serverska greška.';
-$messages['deactivated'] = 'Filteri su uspješno omogućeni.';
-$messages['activated'] = 'Filteri su uspješno onemogućeni.';
-$messages['moved'] = 'Filteri su uspješno premješteni.';
-$messages['moveerror'] = 'Nije moguće premjestiti označeni filter. Desila se serverska greška.';
-$messages['nametoolong'] = 'Ime je predugo.';
-$messages['namereserved'] = 'Ime je rezervisano.';
-$messages['setexist'] = 'Set već postoji.';
-$messages['nodata'] = 'Morate označiti barem jednu poziciju!';
-$messages['invaliddateformat'] = 'Netačan datum ili dio formata datuma';
-$messages['saveerror'] = 'Nije moguće snimiti podatke. Desila se serverska greška.';
-$messages['vacationsaved'] = 'Podaci o odmoru su uspješno snimljeni.';
-$messages['emptyvacationbody'] = 'Tijelo poruke za odmor je neophodno!';
-?>
diff --git a/lib/plugins/managesieve/localization/ca_ES.inc b/lib/plugins/managesieve/localization/ca_ES.inc
deleted file mode 100644
index 0dc6863..0000000
--- a/lib/plugins/managesieve/localization/ca_ES.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtres';
-$labels['managefilters'] = 'Gestiona els filtres dels missatges d\'entrada';
-$labels['filtername'] = 'Nom del filtre';
-$labels['newfilter'] = 'Filtre Nou';
-$labels['filteradd'] = 'Afegeix un filtre';
-$labels['filterdel'] = 'Suprimeix el filtre';
-$labels['moveup'] = 'Mou amunt';
-$labels['movedown'] = 'Mou avall';
-$labels['filterallof'] = 'que coincideixi amb totes les regles següents';
-$labels['filteranyof'] = 'que coincideixi amb qualsevol de les regles següents';
-$labels['filterany'] = 'tots els missatges';
-$labels['filtercontains'] = 'conté';
-$labels['filternotcontains'] = 'no conté';
-$labels['filteris'] = 'és igual a';
-$labels['filterisnot'] = 'és diferent de';
-$labels['filterexists'] = 'existeix';
-$labels['filternotexists'] = 'no existeix';
-$labels['filtermatches'] = 'coincideix amb l\'expressió';
-$labels['filternotmatches'] = 'no coincideix amb l\'expressió';
-$labels['filterregex'] = 'coincideix amb l\'expressió regular';
-$labels['filternotregex'] = 'no coincideix amb l\'expressió regular';
-$labels['filterunder'] = 'sota';
-$labels['filterover'] = 'sobre';
-$labels['addrule'] = 'Afegeix una regla';
-$labels['delrule'] = 'Suprimeix una regla';
-$labels['messagemoveto'] = 'Mou el missatge a';
-$labels['messageredirect'] = 'Redirigeix el missatge cap a';
-$labels['messagecopyto'] = 'Copia el missatge a';
-$labels['messagesendcopy'] = 'Envia una còpia del missatge a';
-$labels['messagereply'] = 'Respon amb un missatge';
-$labels['messagedelete'] = 'Suprimeix missatge';
-$labels['messagediscard'] = 'Descarta amb un missatge';
-$labels['messagekeep'] = 'Deixa el missatge a la bústia';
-$labels['messagesrules'] = 'Pels missatges entrants:';
-$labels['messagesactions'] = '..executa les següents accions:';
-$labels['add'] = 'Afegeix';
-$labels['del'] = 'Suprimeix';
-$labels['sender'] = 'Remitent';
-$labels['recipient'] = 'Destinatari';
-$labels['vacationaddr'] = 'Les meves adreces de correu addicionals:';
-$labels['vacationdays'] = 'Cada quan enviar un missatge (en dies):';
-$labels['vacationinterval'] = 'Amb quina freqüència s\'han d\'enviar els missatges:';
-$labels['vacationreason'] = 'Cos del missatge (raó de l\'absència):';
-$labels['vacationsubject'] = 'Assumpte del missatge:';
-$labels['days'] = 'dies';
-$labels['seconds'] = 'segons';
-$labels['rulestop'] = 'Deixa d\'avaluar regles';
-$labels['enable'] = 'Habilita/Deshabilita';
-$labels['filterset'] = 'Conjunt de filtres';
-$labels['filtersets'] = 'Conjunts de filtres';
-$labels['filtersetadd'] = 'Afegeix un conjunt de filtres';
-$labels['filtersetdel'] = 'Suprimeix el conjunt de filtres actual';
-$labels['filtersetact'] = 'Activa el conjunt de filtres actual';
-$labels['filtersetdeact'] = 'Desactiva el conjunt de filtres actual';
-$labels['filterdef'] = 'Definició del filtre';
-$labels['filtersetname'] = 'Nom del conjunt de filtres';
-$labels['newfilterset'] = 'Nou conjunt de filtres';
-$labels['active'] = 'actiu';
-$labels['none'] = 'cap';
-$labels['fromset'] = 'des del conjunt';
-$labels['fromfile'] = 'des del fitxer';
-$labels['filterdisabled'] = 'Filtre deshabilitat';
-$labels['countisgreaterthan'] = 'el recompte és més gran de';
-$labels['countisgreaterthanequal'] = 'el recompte és més gran o igual a';
-$labels['countislessthan'] = 'el recompte és menor de';
-$labels['countislessthanequal'] = 'el recompte és menor o igual a';
-$labels['countequals'] = 'el recompte és igual que';
-$labels['countnotequals'] = 'el recompte és diferent de';
-$labels['valueisgreaterthan'] = 'el valor és més gran de';
-$labels['valueisgreaterthanequal'] = 'el valor és major o igual que';
-$labels['valueislessthan'] = 'el valor és menor que';
-$labels['valueislessthanequal'] = 'el valor és menor o igual de';
-$labels['valueequals'] = 'el valor és igual a';
-$labels['valuenotequals'] = 'el valor és diferent de';
-$labels['setflags'] = 'Posa indicadors al missatge';
-$labels['addflags'] = 'Afegeix indicadors al missatge';
-$labels['removeflags'] = 'Suprimeix indicadors del missatge';
-$labels['flagread'] = 'Llegit';
-$labels['flagdeleted'] = 'Suprimit';
-$labels['flaganswered'] = 'Respost';
-$labels['flagflagged'] = 'Marcat';
-$labels['flagdraft'] = 'Esborrany';
-$labels['setvariable'] = 'Ajusta la variable';
-$labels['setvarname'] = 'Nom de la variable:';
-$labels['setvarvalue'] = 'Valor de la variable:';
-$labels['setvarmodifiers'] = 'Modificadors:';
-$labels['varlower'] = 'minúscules';
-$labels['varupper'] = 'majúscules';
-$labels['varlowerfirst'] = 'el primer caràcter en minúscula';
-$labels['varupperfirst'] = 'el primer caràcter en majúscula';
-$labels['varquotewildcard'] = 'engloba els caràcters especials amb cometes';
-$labels['varlength'] = 'llargada';
-$labels['notify'] = 'Envia notificació';
-$labels['notifytarget'] = 'Objectiu de la notificació:';
-$labels['notifymessage'] = 'Missatge de notificació (opcional):';
-$labels['notifyoptions'] = 'Opcions de notificació (opcional):';
-$labels['notifyfrom'] = 'Remitent de la notificació (opcional):';
-$labels['notifyimportance'] = 'Importància:';
-$labels['notifyimportancelow'] = 'baixa';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'alta';
-$labels['notifymethodmailto'] = 'Correu electrònic';
-$labels['notifymethodtel'] = 'Telèfon';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Crea filtre';
-$labels['usedata'] = 'Fes servir les següents dades al filtre:';
-$labels['nextstep'] = 'Següent pas';
-$labels['...'] = '...';
-$labels['currdate'] = 'Data actual';
-$labels['datetest'] = 'Data';
-$labels['dateheader'] = 'capçalera:';
-$labels['year'] = 'any';
-$labels['month'] = 'mes';
-$labels['day'] = 'dia';
-$labels['date'] = 'data (aaaa-mm-dd)';
-$labels['julian'] = 'data (calendari julià)';
-$labels['hour'] = 'hora';
-$labels['minute'] = 'minut';
-$labels['second'] = 'segon';
-$labels['time'] = 'hora (hh:mm:ss)';
-$labels['iso8601'] = 'data (ISO8601)';
-$labels['std11'] = 'data (RFC2822)';
-$labels['zone'] = 'fus horari';
-$labels['weekday'] = 'dia de la setmana (0-6)';
-$labels['advancedopts'] = 'Opcions avançades';
-$labels['body'] = 'Cos';
-$labels['address'] = 'adreça';
-$labels['envelope'] = 'sobre';
-$labels['modifier'] = 'modificador:';
-$labels['text'] = 'text';
-$labels['undecoded'] = 'descodificat (en brut)';
-$labels['contenttype'] = 'tipus de contingut';
-$labels['modtype'] = 'tipus:';
-$labels['allparts'] = 'tots';
-$labels['domain'] = 'domini';
-$labels['localpart'] = 'part local';
-$labels['user'] = 'usuari';
-$labels['detail'] = 'detall';
-$labels['comparator'] = 'comparador:';
-$labels['default'] = 'per defecte';
-$labels['octet'] = 'estricte (octet)';
-$labels['asciicasemap'] = 'No distingeix entre majúscules i minúscules (ascii-casemap)';
-$labels['asciinumeric'] = 'numèric (ascii-numeric)';
-$labels['index'] = 'índex:';
-$labels['indexlast'] = 'cap enrere';
-$labels['vacation'] = 'Vacances';
-$labels['vacation.reply'] = 'Missatge de resposta';
-$labels['vacation.advanced'] = 'Paràmetres avançats';
-$labels['vacation.subject'] = 'Assumpte';
-$labels['vacation.body'] = 'Cos';
-$labels['vacation.start'] = 'Inici de vacances';
-$labels['vacation.end'] = 'Finalització de vacances';
-$labels['vacation.status'] = 'Estat';
-$labels['vacation.on'] = 'Activat';
-$labels['vacation.off'] = 'Desactivat';
-$labels['vacation.addresses'] = 'Les meves adreces addicionals:';
-$labels['vacation.interval'] = 'Interval de resposta';
-$labels['vacation.after'] = 'Posa la regla de vacances després';
-$labels['vacation.saving'] = 'S\'estan desant les dades...';
-$labels['vacation.action'] = 'Acció pel missatge entrant';
-$labels['vacation.keep'] = 'Conserva';
-$labels['vacation.discard'] = 'Descarta';
-$labels['vacation.redirect'] = 'Redirigeix cap a';
-$labels['vacation.copy'] = 'Envia còpia a';
-$labels['arialabelfiltersetactions'] = 'Accions pel conjunt de filtres';
-$labels['arialabelfilteractions'] = 'Accions del filtre';
-$labels['arialabelfilterform'] = 'Propietats del filtre';
-$labels['ariasummaryfilterslist'] = 'Llistat de filtres';
-$labels['ariasummaryfiltersetslist'] = 'Llistat de conjunts de filtres';
-$labels['filterstitle'] = 'Edita els filtres pels missatges entrants';
-$labels['vacationtitle'] = 'Edita la norma "fora de l\'oficina"';
-$messages['filterunknownerror'] = 'Error desconegut al servidor.';
-$messages['filterconnerror'] = 'No s\'ha pogut connectar al servidor.';
-$messages['filterdeleteerror'] = 'No s\'ha pogut suprimir el filtre. Hi ha hagut un error al servidor.';
-$messages['filterdeleted'] = 'El filtre s\'ha suprimit correctament.';
-$messages['filtersaved'] = 'El filtre s\'ha desat correctament.';
-$messages['filtersaveerror'] = 'No s\'ha pogut desar el filtre. Hi ha hagut un error al servidor.';
-$messages['filterdeleteconfirm'] = 'Esteu segurs de voler suprimir el filtre seleccionat?';
-$messages['ruledeleteconfirm'] = 'Esteu segurs que voleu suprimir la regla seleccionada?';
-$messages['actiondeleteconfirm'] = 'Esteu segurs que voleu suprimir l\'acció seleccionada?';
-$messages['forbiddenchars'] = 'El camp conté caràcters prohibits.';
-$messages['cannotbeempty'] = 'El camp no pot estar buit.';
-$messages['ruleexist'] = 'Ja existeix un filtre amb aquest nom.';
-$messages['setactivateerror'] = 'No s\'ha pogut activar el conjunt de filtres seleccionat. Hi ha hagut un error al servidor.';
-$messages['setdeactivateerror'] = 'No s\'ha pogut desactivar el conjunt de filtres seleccionat. Hi ha hagut un error al servidor.';
-$messages['setdeleteerror'] = 'No s\'ha pogut suprimir el conjunt de filtres seleccionat. Hi ha hagut un error al servidor.';
-$messages['setactivated'] = 'El conjunt de filtres s\'ha activat correctament.';
-$messages['setdeactivated'] = 'El conjunt de filtres s\'ha desactivat correctament.';
-$messages['setdeleted'] = 'El conjunt de filtres s\'ha suprimit correctament.';
-$messages['setdeleteconfirm'] = 'Esteu segurs que voleu suprimir el conjunt de filtres seleccionats?';
-$messages['setcreateerror'] = 'No s\'ha pogut crear el conjunt de filtres. Hi ha hagut un error al servidor.';
-$messages['setcreated'] = 'S\'ha creat correctament el conjunt de filtres.';
-$messages['activateerror'] = 'No s\'ha pogut habilitar el(s) filtre(s) seleccionat(s). Hi ha hagut un error al servidor.';
-$messages['deactivateerror'] = 'No s\'ha pogut deshabilitar el(s) filtre(s) seleccionat(s). Hi ha hagut un error al servidor.';
-$messages['deactivated'] = 'Filtre(s) deshabilitat(s) correctament.';
-$messages['activated'] = 'Filtre(s) habilitat(s) correctament.';
-$messages['moved'] = 'S\'ha mogut correctament el filtre.';
-$messages['moveerror'] = 'No s\'ha pogut moure el filtre seleccionat. Hi ha hagut un error al servidor.';
-$messages['nametoolong'] = 'El nom és massa llarg.';
-$messages['namereserved'] = 'Nom reservat.';
-$messages['setexist'] = 'El conjunt ja existeix.';
-$messages['nodata'] = 'S\'ha de seleccionar com a mínim una posició!';
-$messages['invaliddateformat'] = 'data no vàlida o format no vàlid';
-$messages['saveerror'] = 'No s\'han pogut desar les dades. Hi ha hagut un error al servidor.';
-$messages['vacationsaved'] = 'Les dades de les vacances s\'han desat correctament.';
-$messages['emptyvacationbody'] = 'És obligatori definir el cos del missatge de vacances';
-?>
diff --git a/lib/plugins/managesieve/localization/cs_CZ.inc b/lib/plugins/managesieve/localization/cs_CZ.inc
deleted file mode 100644
index 6db6bac..0000000
--- a/lib/plugins/managesieve/localization/cs_CZ.inc
+++ /dev/null
@@ -1,218 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtry';
-$labels['managefilters'] = 'Nastavení filtrů';
-$labels['filtername'] = 'Název filtru';
-$labels['newfilter'] = 'Nový filtr';
-$labels['filteradd'] = 'Přidej filtr';
-$labels['filterdel'] = 'Smaž filtr';
-$labels['moveup'] = 'Posunout nahoru';
-$labels['movedown'] = 'Posunout dolů';
-$labels['filterallof'] = 'Odpovídají všechny pravidla';
-$labels['filteranyof'] = 'Odpovídá kterékoliv pravidlo';
-$labels['filterany'] = 'Všechny zprávy';
-$labels['filtercontains'] = 'obsahuje';
-$labels['filternotcontains'] = 'neobsahuje';
-$labels['filteris'] = 'odpovídá';
-$labels['filterisnot'] = 'neodpovídá';
-$labels['filterexists'] = 'existuje';
-$labels['filternotexists'] = 'neexistuje';
-$labels['filtermatches'] = 'odpovídá výrazu';
-$labels['filternotmatches'] = 'neodpovídá výrazu';
-$labels['filterregex'] = 'odpovídá regulárnímu výrazu';
-$labels['filternotregex'] = 'neodpovídá regulárnímu výrazu';
-$labels['filterunder'] = 'pod';
-$labels['filterover'] = 'nad';
-$labels['addrule'] = 'Přidej pravidlo';
-$labels['delrule'] = 'Smaž pravidlo';
-$labels['messagemoveto'] = 'Přesuň zprávu do';
-$labels['messageredirect'] = 'Přeposlat zprávu na';
-$labels['messagecopyto'] = 'Zkopírovat zprávu do';
-$labels['messagesendcopy'] = 'Odeslat kopii zprávy na';
-$labels['messagereply'] = 'Odpovědět se zprávou';
-$labels['messagedelete'] = 'Smazat zprávu';
-$labels['messagediscard'] = 'Smazat se zprávou';
-$labels['messagekeep'] = 'Ponechat zprávu v doručené poště';
-$labels['messagesrules'] = 'Pravidla pro příchozí zprávu:';
-$labels['messagesactions'] = '...vykonej následující akce:';
-$labels['add'] = 'Přidej';
-$labels['del'] = 'Smaž';
-$labels['sender'] = 'Odesílatel';
-$labels['recipient'] = 'Příjemce';
-$labels['vacationaddr'] = 'Moje další e-mailová adresa(y):';
-$labels['vacationdays'] = 'Počet dnů mezi automatickými odpověďmi:';
-$labels['vacationinterval'] = 'Prodleva mezi automatickými odpověďmi:';
-$labels['vacationreason'] = 'Zpráva (Důvod nepřítomnosti):';
-$labels['vacationsubject'] = 'Předmět zprávy:';
-$labels['days'] = 'dnů';
-$labels['seconds'] = 'sekund';
-$labels['rulestop'] = 'Zastavit pravidla';
-$labels['enable'] = 'Zapnout/Vypnout';
-$labels['filterset'] = 'Sada filtrů';
-$labels['filtersets'] = 'Sady filtrů';
-$labels['filtersetadd'] = 'Přidat sadu filtrů';
-$labels['filtersetdel'] = 'Odebrat tuto sadu filtrů';
-$labels['filtersetact'] = 'Activate current filters set';
-$labels['filtersetdeact'] = 'Vypnout tuto sadu filtrů';
-$labels['filterdef'] = 'Definice filtru';
-$labels['filtersetname'] = 'Nastavit název sady filtrů';
-$labels['newfilterset'] = 'Nová sada filtrů';
-$labels['active'] = 'aktivní';
-$labels['none'] = 'nic';
-$labels['fromset'] = 'ze sady';
-$labels['fromfile'] = 'ze souboru';
-$labels['filterdisabled'] = 'Filtr neaktivní';
-$labels['countisgreaterthan'] = 'počet je větší než';
-$labels['countisgreaterthanequal'] = 'počet je větší nebo roven';
-$labels['countislessthan'] = 'počet je nižší než';
-$labels['countislessthanequal'] = 'počet je nižší nebo roven';
-$labels['countequals'] = 'počet je roven';
-$labels['countnotequals'] = 'počet není roven';
-$labels['valueisgreaterthan'] = 'hodnota je větší než';
-$labels['valueisgreaterthanequal'] = 'hodnota je větší nebo stejná jako';
-$labels['valueislessthan'] = 'hodnota je nižší než';
-$labels['valueislessthanequal'] = 'hodnota je nižší nebo stejná jako';
-$labels['valueequals'] = 'hodnota odpovídá';
-$labels['valuenotequals'] = 'hodnota neodpovídá';
-$labels['setflags'] = 'Nastavit vlajky u zprávy';
-$labels['addflags'] = 'Přidat vlajky ke zprávě';
-$labels['removeflags'] = 'Odstranit vlajky ze zprávy';
-$labels['flagread'] = 'Přečteno';
-$labels['flagdeleted'] = 'Smazáno';
-$labels['flaganswered'] = 'Odpovězené';
-$labels['flagflagged'] = 'Označeno';
-$labels['flagdraft'] = 'Koncept';
-$labels['setvariable'] = 'Nastavit proměnnou';
-$labels['setvarname'] = 'Název proměnné:';
-$labels['setvarvalue'] = 'Hodnota proměnné:';
-$labels['setvarmodifiers'] = 'Modifikátory:';
-$labels['varlower'] = 'malá písmena';
-$labels['varupper'] = 'velká písmena';
-$labels['varlowerfirst'] = 'první písmeno malé';
-$labels['varupperfirst'] = 'první písmeno velké';
-$labels['varquotewildcard'] = 'uvodit speciální znaky uvozovkama';
-$labels['varlength'] = 'délka';
-$labels['notify'] = 'Odeslat oznámení';
-$labels['notifytarget'] = 'Cíl oznámení:';
-$labels['notifymessage'] = 'Zpráva oznámení (nepovinné):';
-$labels['notifyoptions'] = 'Možnosti oznámení (nepovinné):';
-$labels['notifyfrom'] = 'Odesílatel oznámení (nepovinné):';
-$labels['notifyimportance'] = 'Důležitost:';
-$labels['notifyimportancelow'] = 'nízká';
-$labels['notifyimportancenormal'] = 'normální';
-$labels['notifyimportancehigh'] = 'vysoká';
-$labels['notifymethodmailto'] = 'E-mail';
-$labels['notifymethodtel'] = 'Telefon';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Vytvořit filtr';
-$labels['usedata'] = 'Použít následující údaje ve filtru:';
-$labels['nextstep'] = 'Další krok';
-$labels['...'] = '...';
-$labels['currdate'] = 'Aktuální datum';
-$labels['datetest'] = 'Datum';
-$labels['dateheader'] = 'hlavička:';
-$labels['year'] = 'rok';
-$labels['month'] = 'měsíc';
-$labels['day'] = 'den';
-$labels['date'] = 'datum (rrrr-mm-dd)';
-$labels['julian'] = 'datum (juliánské)';
-$labels['hour'] = 'hodina';
-$labels['minute'] = 'minuta';
-$labels['second'] = 'sekunda';
-$labels['time'] = 'čas (hh:mm:ss)';
-$labels['iso8601'] = 'datum (ISO8601)';
-$labels['std11'] = 'datum (RFC2822)';
-$labels['zone'] = 'časová zóna';
-$labels['weekday'] = 'všední den (0-6)';
-$labels['advancedopts'] = 'Pokročilá nastavení';
-$labels['body'] = 'Tělo';
-$labels['address'] = 'adresa';
-$labels['envelope'] = 'obálka';
-$labels['modifier'] = 'měnič:';
-$labels['text'] = 'text';
-$labels['undecoded'] = 'nedekódované (surové)';
-$labels['contenttype'] = 'typ obsahu';
-$labels['modtype'] = 'typ:';
-$labels['allparts'] = 'vše';
-$labels['domain'] = 'doména';
-$labels['localpart'] = 'místní část';
-$labels['user'] = 'uživatel';
-$labels['detail'] = 'detail';
-$labels['comparator'] = 'porovnávač:';
-$labels['default'] = 'výchozí';
-$labels['octet'] = 'striktní (oktet)';
-$labels['asciicasemap'] = 'necitlivé na velikost písmen (ascii-casemap)';
-$labels['asciinumeric'] = 'číslené (ascii-numeric)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'pozpátku';
-$labels['vacation'] = 'Dovolená';
-$labels['vacation.reply'] = 'Odpověd';
-$labels['vacation.advanced'] = 'Pokročilá nastavení';
-$labels['vacation.subject'] = 'Předmět';
-$labels['vacation.body'] = 'Tělo';
-$labels['vacation.start'] = 'Začátek dovolené';
-$labels['vacation.end'] = 'Konec dovolené';
-$labels['vacation.status'] = 'Stav';
-$labels['vacation.on'] = 'Zapnuto';
-$labels['vacation.off'] = 'Vypnuto';
-$labels['vacation.addresses'] = 'Moje další adresy:';
-$labels['vacation.interval'] = 'Doba mezi odpověďmi';
-$labels['vacation.after'] = 'Uložit pravidlo o dovolené za';
-$labels['vacation.saving'] = 'Ukládám data...';
-$labels['vacation.keep'] = 'Zachovat';
-$labels['vacation.discard'] = 'Zrušit';
-$labels['vacation.copy'] = 'Odeslat kopii zprávy na';
-$labels['arialabelfilterform'] = 'Vlastnosti filtru';
-$labels['ariasummaryfilterslist'] = 'Seznam filtrů';
-$labels['ariasummaryfiltersetslist'] = 'Seznam sad filtrů';
-$messages['filterunknownerror'] = 'Neznámá chyba serveru';
-$messages['filterconnerror'] = 'Nebylo možné se připojit k sieve serveru';
-$messages['filterdeleteerror'] = 'Nebylo možné smazat filtr. Došlo k chybě serveru.';
-$messages['filterdeleted'] = 'Filtr byl smazán';
-$messages['filtersaved'] = 'Filtr byl uložen';
-$messages['filtersaveerror'] = 'Nebylo možné uložit filtr. Došlo k chybě serveru.';
-$messages['filterdeleteconfirm'] = 'Opravdu chcete smazat vybraný filtr?';
-$messages['ruledeleteconfirm'] = 'Jste si jisti, že chcete smazat vybrané pravidlo?';
-$messages['actiondeleteconfirm'] = 'Jste si jisti, že chcete smazat vybranou akci?';
-$messages['forbiddenchars'] = 'Zakázané znaky v poli';
-$messages['cannotbeempty'] = 'Pole nemůže být prázdné';
-$messages['ruleexist'] = 'Filtr s uvedeným názvem již existuje.';
-$messages['setactivateerror'] = 'Nelze zapnout vybranou sadu filtrů. Došlo k chybě serveru.';
-$messages['setdeactivateerror'] = 'Nelze vypnout vybranou sadu filtrů. Došlo k chybě serveru.';
-$messages['setdeleteerror'] = 'Nelze odstranit vybranou sadu filtrů. Došlo k chybě serveru.';
-$messages['setactivated'] = 'Sada filtrů úspěšně zapnuta.';
-$messages['setdeactivated'] = 'Sada filtrů úspěšně vypnuta.';
-$messages['setdeleted'] = 'Sada filtrů úspěšně odstraněna.';
-$messages['setdeleteconfirm'] = 'Opravdu si přejete odebrat vybranou sadu filtrů.';
-$messages['setcreateerror'] = 'Nelze vytvořit sadu filtrů. Došlo k chybě serveru.';
-$messages['setcreated'] = 'Sada filtrů úspěšně vytvořena.';
-$messages['activateerror'] = 'Nelze zapnout vybrané filtr/y. Došlo k chybě serveru.';
-$messages['deactivateerror'] = 'Nelze vypnout vybrané filtr/y. Došlo k chybě serveru.';
-$messages['deactivated'] = 'Filtr(y) úspěšně vypnuty.';
-$messages['activated'] = 'Filtr/y úspěšně zapnuty.';
-$messages['moved'] = 'Filtr byl úspěšně přesunut.';
-$messages['moveerror'] = 'Nelze přesunout vybraný filtr. Došlo k chybě serveru.';
-$messages['nametoolong'] = 'Příliš dlouhý název.';
-$messages['namereserved'] = 'Vyhrazený název.';
-$messages['setexist'] = 'Sada již existuje.';
-$messages['nodata'] = 'Musí být vybrána minimálně jedna pozice!';
-$messages['invaliddateformat'] = 'Neplatné datum nebo část data';
-$messages['saveerror'] = 'Nebylo možné uložit data. Došlo k chybě serveru.';
-$messages['vacationsaved'] = 'Data o dovolené byla uložena.';
-$messages['emptyvacationbody'] = 'Tělo zprávy';
-?>
diff --git a/lib/plugins/managesieve/localization/cy_GB.inc b/lib/plugins/managesieve/localization/cy_GB.inc
deleted file mode 100644
index 8d8d1a5..0000000
--- a/lib/plugins/managesieve/localization/cy_GB.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Hidlyddion';
-$labels['managefilters'] = 'Rheoli hidlyddion ebost i fewn';
-$labels['filtername'] = 'Enw hidlydd';
-$labels['newfilter'] = 'Hidlydd newydd';
-$labels['filteradd'] = 'Ychwanegu hidlydd';
-$labels['filterdel'] = 'Dileu hidlydd';
-$labels['moveup'] = 'Symud i fyny';
-$labels['movedown'] = 'Symud i lawr';
-$labels['filterallof'] = 'sy\'n cyfateb i\'r holl reolau canlynol';
-$labels['filteranyof'] = 'sy\'n cyfateb i unrhyw un i\'r rheolau canlynol';
-$labels['filterany'] = 'pob neges';
-$labels['filtercontains'] = 'yn cynnwys';
-$labels['filternotcontains'] = 'ddim yn cynnwys';
-$labels['filteris'] = 'yn hafal i';
-$labels['filterisnot'] = 'ddim yn hafal i';
-$labels['filterexists'] = 'yn bodoli';
-$labels['filternotexists'] = 'ddim yn bodoli';
-$labels['filtermatches'] = 'yn cyfateb i\'r mynegiant';
-$labels['filternotmatches'] = 'ddim yn cyfateb i\'r mynegiant';
-$labels['filterregex'] = 'yn cyfateb i\'r mynegiant rheolaidd';
-$labels['filternotregex'] = 'ddim yn cyfateb i\'r mynegiant rheolaidd';
-$labels['filterunder'] = 'o dan';
-$labels['filterover'] = 'dros';
-$labels['addrule'] = 'Ychwanegu rheol';
-$labels['delrule'] = 'Dileu rheol';
-$labels['messagemoveto'] = 'Symud neges i';
-$labels['messageredirect'] = 'Ail-gyfeirio neges i';
-$labels['messagecopyto'] = 'Copio neges i';
-$labels['messagesendcopy'] = 'Danfon copi o\'r neges i';
-$labels['messagereply'] = 'Ymateb gyda\'r neges';
-$labels['messagedelete'] = 'Dileu neges';
-$labels['messagediscard'] = 'Gwaredu gyda neges';
-$labels['messagekeep'] = 'Cadw\'r neges yn y Mewnflwch';
-$labels['messagesrules'] = 'Ar gyfer ebost i fewn:';
-$labels['messagesactions'] = '...rhedeg y gweithredoedd canlynol:';
-$labels['add'] = 'Ychwanegu';
-$labels['del'] = 'Dileu';
-$labels['sender'] = 'Anfonwr';
-$labels['recipient'] = 'Derbynnwr';
-$labels['vacationaddr'] = 'Fy nghyfeiriad(au) ebost ychwanegol:';
-$labels['vacationdays'] = 'Pa mor aml i ddanfon negeseuon (mewn dyddiau):';
-$labels['vacationinterval'] = 'Pa mor aml i ddanfon negeseuon:';
-$labels['vacationreason'] = 'Corff neges (rheswm ar wyliau):';
-$labels['vacationsubject'] = 'Pwnc neges:';
-$labels['days'] = 'dyddiau';
-$labels['seconds'] = 'eiliadau';
-$labels['rulestop'] = 'Stopio gwerthuso rheolau';
-$labels['enable'] = 'Galluogi/Analluogi';
-$labels['filterset'] = 'Set hidlyddion';
-$labels['filtersets'] = 'Setiau hidlyddion';
-$labels['filtersetadd'] = 'Ychwanegu set hidlyddion';
-$labels['filtersetdel'] = 'Dileu set hidlyddion cyfredol';
-$labels['filtersetact'] = 'Dileu set hidlyddion gweithredol';
-$labels['filtersetdeact'] = 'Analluogi set hidlyddion cyfredol';
-$labels['filterdef'] = 'Diffiniad hidlydd';
-$labels['filtersetname'] = 'Enw set hidlyddion';
-$labels['newfilterset'] = 'Set hidlyddion newydd';
-$labels['active'] = 'gweithredol';
-$labels['none'] = 'dim';
-$labels['fromset'] = 'o set';
-$labels['fromfile'] = 'o ffeil';
-$labels['filterdisabled'] = 'Analluogwyd hidlydd';
-$labels['countisgreaterthan'] = 'rhif yn fwy na';
-$labels['countisgreaterthanequal'] = 'rhif yn fwy na neu hafal i';
-$labels['countislessthan'] = 'rhif yn llai na';
-$labels['countislessthanequal'] = 'rhif yn llai na neu hafal i';
-$labels['countequals'] = 'rhif yn hafal i';
-$labels['countnotequals'] = 'rhif ddim yn hafal i';
-$labels['valueisgreaterthan'] = 'gwerth yn fwy na';
-$labels['valueisgreaterthanequal'] = 'gwerth yn fwy na neu hafal i';
-$labels['valueislessthan'] = 'gwerth yn llai na';
-$labels['valueislessthanequal'] = 'gwerth yn llai neu hafal i';
-$labels['valueequals'] = 'gwerth yn hafal i';
-$labels['valuenotequals'] = 'gwerth ddim yn hafal i';
-$labels['setflags'] = 'Rhoi fflag ar y neges';
-$labels['addflags'] = 'Ychwanegu fflag i\'r neges';
-$labels['removeflags'] = 'Dileu fflag o\'r neges';
-$labels['flagread'] = 'Darllen';
-$labels['flagdeleted'] = 'Dilewyd';
-$labels['flaganswered'] = 'Atebwyd';
-$labels['flagflagged'] = 'Nodwyd';
-$labels['flagdraft'] = 'Drafft';
-$labels['setvariable'] = 'Gosod newidyn';
-$labels['setvarname'] = 'Enw newidyn:';
-$labels['setvarvalue'] = 'Gwerth newidyn:';
-$labels['setvarmodifiers'] = 'Addasydd:';
-$labels['varlower'] = 'llythrennau bychain';
-$labels['varupper'] = 'priflythrennau';
-$labels['varlowerfirst'] = 'llythyren gyntaf yn fach';
-$labels['varupperfirst'] = 'llythyren gyntaf yn briflythyren';
-$labels['varquotewildcard'] = 'dyfynnu nodau arbennig';
-$labels['varlength'] = 'hyd';
-$labels['notify'] = 'Anfon hysbysiad';
-$labels['notifytarget'] = 'Target hysbysu:';
-$labels['notifymessage'] = 'Neges hysbysu (dewisol):';
-$labels['notifyoptions'] = 'Dewisiadau hysbysu (dewisol):';
-$labels['notifyfrom'] = 'Anfonwr hysbysiad (dewisol):';
-$labels['notifyimportance'] = 'Pwysigrwydd:';
-$labels['notifyimportancelow'] = 'isel';
-$labels['notifyimportancenormal'] = 'arferol';
-$labels['notifyimportancehigh'] = 'uchel';
-$labels['notifymethodmailto'] = 'Ebost';
-$labels['notifymethodtel'] = 'Ffôn';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Creu hidlydd';
-$labels['usedata'] = 'Defnyddio\'r wybodaeth ganlynol yn yr hidlydd:';
-$labels['nextstep'] = 'Cam nesaf';
-$labels['...'] = '...';
-$labels['currdate'] = 'Dyddiad cyfredol';
-$labels['datetest'] = 'Dyddiad';
-$labels['dateheader'] = 'pennawd:';
-$labels['year'] = 'blwyddyn';
-$labels['month'] = 'mis';
-$labels['day'] = 'dydd';
-$labels['date'] = 'dyddiad (bbbb-mm-dd)';
-$labels['julian'] = 'dyddiad (julian)';
-$labels['hour'] = 'awr';
-$labels['minute'] = 'munud';
-$labels['second'] = 'eiliad';
-$labels['time'] = 'amser (aa:mm:ee)';
-$labels['iso8601'] = 'dyddiad (ISO8601)';
-$labels['std11'] = 'dyddiad (RFC2822)';
-$labels['zone'] = 'parth-amser';
-$labels['weekday'] = 'dydd yr wythnos (0-6)';
-$labels['advancedopts'] = 'Dewisiadau uwch';
-$labels['body'] = 'Corff';
-$labels['address'] = 'cyfeiriad';
-$labels['envelope'] = 'amlen';
-$labels['modifier'] = 'newidydd:';
-$labels['text'] = 'testun';
-$labels['undecoded'] = 'heb ei ddatgodi (amrwd)';
-$labels['contenttype'] = 'math cynnwys';
-$labels['modtype'] = 'math:';
-$labels['allparts'] = 'popeth';
-$labels['domain'] = 'parth';
-$labels['localpart'] = 'darn lleol';
-$labels['user'] = 'defnyddiwr';
-$labels['detail'] = 'manylion';
-$labels['comparator'] = 'cymharydd';
-$labels['default'] = 'rhagosodiad';
-$labels['octet'] = 'llym (octet)';
-$labels['asciicasemap'] = 'maint llythrennau (ascii-casemap)';
-$labels['asciinumeric'] = 'rhifau (ascii-numeric)';
-$labels['index'] = 'mynegai:';
-$labels['indexlast'] = 'o chwith';
-$labels['vacation'] = 'Gwyliau';
-$labels['vacation.reply'] = 'Neges ymateb';
-$labels['vacation.advanced'] = 'Gosodiadau uwch';
-$labels['vacation.subject'] = 'Pwnc';
-$labels['vacation.body'] = 'Corff';
-$labels['vacation.start'] = 'Dechrau gwyliau';
-$labels['vacation.end'] = 'Diwedd gwyliau';
-$labels['vacation.status'] = 'Statws';
-$labels['vacation.on'] = 'Ymlaen';
-$labels['vacation.off'] = 'I ffwrdd';
-$labels['vacation.addresses'] = 'Fy nghyfeiriadau ychwanegol';
-$labels['vacation.interval'] = 'Cyfnod ymateb';
-$labels['vacation.after'] = 'Rhoi rheol gwyliau ar ôl';
-$labels['vacation.saving'] = 'Yn cadw\'r data...';
-$labels['vacation.action'] = 'Gweithred neges i fewn';
-$labels['vacation.keep'] = 'Cadw';
-$labels['vacation.discard'] = 'Gwaredu';
-$labels['vacation.redirect'] = 'Ailgyfeirio i';
-$labels['vacation.copy'] = 'Danfon copi i';
-$labels['arialabelfiltersetactions'] = 'Gweithrediadau set hidlydd';
-$labels['arialabelfilteractions'] = 'Gweithrediadau hidlydd';
-$labels['arialabelfilterform'] = 'Nodweddion hidlydd';
-$labels['ariasummaryfilterslist'] = 'Rhestr o hidlyddion';
-$labels['ariasummaryfiltersetslist'] = 'Rhestr o setiau hidlyddion';
-$labels['filterstitle'] = 'Golygu hidlyddion ebost i fewn';
-$labels['vacationtitle'] = 'Golygu rheol allan-o\'r-swyddfa';
-$messages['filterunknownerror'] = 'Gwall gweinydd anhysbys.';
-$messages['filterconnerror'] = 'Methwyd cysylltu a\'r gweinydd.';
-$messages['filterdeleteerror'] = 'Methwyd dileu hidlydd. Cafwydd gwall gweinydd.';
-$messages['filterdeleted'] = 'Dilëuwyd hidlydd yn llwyddiannus.';
-$messages['filtersaved'] = 'Cadwyd hidlydd yn llwyddiannus.';
-$messages['filtersaveerror'] = 'Methwyd cadw hidlydd. Cafwyd gwall gweinydd.';
-$messages['filterdeleteconfirm'] = 'Ydych chi wir am ddileu yr hidlydd ddewiswyd?';
-$messages['ruledeleteconfirm'] = 'Ydych chi\'n siwr eich bod am ddileu\'r rheol ddewiswyd?';
-$messages['actiondeleteconfirm'] = 'Ydych chi\'n siwr eich bod am ddileu\'r weithred ddewiswyd?';
-$messages['forbiddenchars'] = 'Llythrennau gwaharddedig yn y maes.';
-$messages['cannotbeempty'] = 'Ni all y maes fod yn wag.';
-$messages['ruleexist'] = 'Mae hidlydd gyda\'r enw yma yn bodoli\'n barod.';
-$messages['setactivateerror'] = 'Methwyd galluogi y hidlyddion dewiswyd. Cafwyd gwall gweinydd.';
-$messages['setdeactivateerror'] = 'Methwyd analluogi y hidlyddion dewiswyd. Cafwyd gwall gweinydd.';
-$messages['setdeleteerror'] = 'Methwyd dileu y set hidlyddion ddewiswyd. Cafwyd gwall gweinydd.';
-$messages['setactivated'] = 'Bywiogwyd y set hidlydd yn llwyddiannus.';
-$messages['setdeactivated'] = 'Dadfywiogwyd y set hidlydd yn llwyddiannus.';
-$messages['setdeleted'] = 'Dilëuwyd y set hidlydd yn llwyddiannus.';
-$messages['setdeleteconfirm'] = 'Ydych chi\'n siwr eich bod am ddileu\'r set hidlydd ddewiswyd?';
-$messages['setcreateerror'] = 'Methwyd creu set hidlydd. Cafwyd gwall gweinydd.';
-$messages['setcreated'] = 'Crëuwyd y set hidlydd yn llwyddiannus.';
-$messages['activateerror'] = 'Methwyd galluogi y hidlydd(ion) dewiswyd. Cafwyd gwall gweinydd.';
-$messages['deactivateerror'] = 'Methwyd analluogi y hidlydd(ion) dewiswyd. Cafwyd gwall gweinydd.';
-$messages['deactivated'] = 'Galluogwyd y hidlydd(ion) yn llwyddiannus.';
-$messages['activated'] = 'Analluogwyd y hidlydd(ion) yn llwyddiannus.';
-$messages['moved'] = 'Symudwyd y hidlydd yn llwyddiannus.';
-$messages['moveerror'] = 'Methwyd symud y hidlydd dewiswyd. Cafwyd gwall gweinydd.';
-$messages['nametoolong'] = 'Enw yn rhy hir.';
-$messages['namereserved'] = 'Enw neilltuedig.';
-$messages['setexist'] = 'Mae\'r set yn bodoli\'n barod.';
-$messages['nodata'] = 'Rhaid dewis o leia un safle!';
-$messages['invaliddateformat'] = 'Dyddiad neu fformat dyddiad annilys';
-$messages['saveerror'] = 'Methwyd cadw\'r data. Cafwyd gwall gweinydd.';
-$messages['vacationsaved'] = 'Cadwyd y data gwyliau yn llwyddiannus.';
-$messages['emptyvacationbody'] = 'Mae angen rhoi corff y neges wyliau!';
-?>
diff --git a/lib/plugins/managesieve/localization/da_DK.inc b/lib/plugins/managesieve/localization/da_DK.inc
deleted file mode 100644
index ebf1cb0..0000000
--- a/lib/plugins/managesieve/localization/da_DK.inc
+++ /dev/null
@@ -1,205 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtre';
-$labels['managefilters'] = 'Ændre indgående mail filtreing';
-$labels['filtername'] = 'Filter navn';
-$labels['newfilter'] = 'Nyt filter';
-$labels['filteradd'] = 'Tilføj filter';
-$labels['filterdel'] = 'Slet filter';
-$labels['moveup'] = 'Flyt op';
-$labels['movedown'] = 'Flyt ned';
-$labels['filterallof'] = 'matcher alle af de følgende regler';
-$labels['filteranyof'] = 'matcher en af følgende regler';
-$labels['filterany'] = 'alle meddelelser';
-$labels['filtercontains'] = 'indeholder';
-$labels['filternotcontains'] = 'indeholder ikke';
-$labels['filteris'] = 'er ens med';
-$labels['filterisnot'] = 'er ikke ens med';
-$labels['filterexists'] = 'findes';
-$labels['filternotexists'] = 'ikke eksisterer';
-$labels['filtermatches'] = 'matcher udtryk';
-$labels['filternotmatches'] = 'matcher ikke udtryk';
-$labels['filterregex'] = 'matcher regulært udtryk';
-$labels['filternotregex'] = 'matcher ikke regulært udtryk';
-$labels['filterunder'] = 'under';
-$labels['filterover'] = 'over';
-$labels['addrule'] = 'Tilføj regel';
-$labels['delrule'] = 'Slet regel';
-$labels['messagemoveto'] = 'Flyt besked til';
-$labels['messageredirect'] = 'Redirriger besked til';
-$labels['messagecopyto'] = 'Kopier besked til';
-$labels['messagesendcopy'] = 'Send kopi af besked til';
-$labels['messagereply'] = 'Svar med besked';
-$labels['messagedelete'] = 'Slet besked';
-$labels['messagediscard'] = 'Slet med besked';
-$labels['messagekeep'] = 'Behold besked i Inbox';
-$labels['messagesrules'] = 'For indkomne besked:';
-$labels['messagesactions'] = '...udfør følgende aktioner:';
-$labels['add'] = 'Tilføje';
-$labels['del'] = 'Fjern';
-$labels['sender'] = 'Afsender';
-$labels['recipient'] = 'Modtager';
-$labels['vacationaddr'] = 'Min(e) yderligere email-adresse(r):';
-$labels['vacationdays'] = 'Hvor tit skal besked sendes (i dage):';
-$labels['vacationinterval'] = 'Hvor tit skal besked sendes:';
-$labels['vacationreason'] = 'Besked (ved ferie):';
-$labels['vacationsubject'] = 'Besked emne:';
-$labels['days'] = 'dage';
-$labels['seconds'] = 'sekunder';
-$labels['rulestop'] = 'Stop behandling af regler';
-$labels['enable'] = 'Aktivér/Deaktivér';
-$labels['filterset'] = 'Filter sæt';
-$labels['filtersets'] = 'Filtre sæt';
-$labels['filtersetadd'] = 'Tilføj filter sæt';
-$labels['filtersetdel'] = 'Slet aktuel filter sæt';
-$labels['filtersetact'] = 'Aktiver nuværende filter sæt';
-$labels['filtersetdeact'] = 'Deaktiver nuværende filter sæt';
-$labels['filterdef'] = 'Filter definition';
-$labels['filtersetname'] = 'Filter sæt navn';
-$labels['newfilterset'] = 'Nyt filter sæt';
-$labels['active'] = 'aktiv';
-$labels['none'] = 'ingen';
-$labels['fromset'] = 'fra sæt';
-$labels['fromfile'] = 'fra fil';
-$labels['filterdisabled'] = 'Filter deaktiveret';
-$labels['countisgreaterthan'] = 'antal er større end';
-$labels['countisgreaterthanequal'] = 'antal er større end eller lig med';
-$labels['countislessthan'] = 'antal er mindre end';
-$labels['countislessthanequal'] = 'antal er mindre end eller lig med';
-$labels['countequals'] = 'antal er lig med';
-$labels['countnotequals'] = 'antal er ikke lig med';
-$labels['valueisgreaterthan'] = 'værdi er større end';
-$labels['valueisgreaterthanequal'] = 'værdi er større end eller lig med';
-$labels['valueislessthan'] = 'værdi er mindre end';
-$labels['valueislessthanequal'] = 'værdi er mindre end eller lig med';
-$labels['valueequals'] = 'værdi er lig med';
-$labels['valuenotequals'] = 'værdi er ikke lig med';
-$labels['setflags'] = 'Sæt flag i beskeden';
-$labels['addflags'] = 'Tilføj flag til beskeden';
-$labels['removeflags'] = 'Fjern flag fra beskeden';
-$labels['flagread'] = 'Læs';
-$labels['flagdeleted'] = 'Slettede';
-$labels['flaganswered'] = 'Besvaret';
-$labels['flagflagged'] = 'Markeret';
-$labels['flagdraft'] = 'Kladde';
-$labels['setvariable'] = 'Skriv variablen';
-$labels['setvarname'] = 'Variabel navn:';
-$labels['setvarvalue'] = 'Variabel værdi:';
-$labels['setvarmodifiers'] = 'Modifikator';
-$labels['varlower'] = 'små bogstaver';
-$labels['varupper'] = 'store bogstaver';
-$labels['varlowerfirst'] = 'første bogstav lille';
-$labels['varupperfirst'] = 'Første bogstav stort';
-$labels['varquotewildcard'] = 'Sæt specialle tegn i citationstegn ';
-$labels['varlength'] = 'længde';
-$labels['notify'] = 'Send meddelelse';
-$labels['notifyimportance'] = 'Vigtighed:';
-$labels['notifyimportancelow'] = 'lav';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'høj';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Telefon';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Opret filter';
-$labels['usedata'] = 'Brug følgende data i filteret:';
-$labels['nextstep'] = 'Næste trin';
-$labels['...'] = '...';
-$labels['currdate'] = 'Aktuel dato';
-$labels['datetest'] = 'Dato';
-$labels['dateheader'] = 'header:';
-$labels['year'] = 'Ã¥r';
-$labels['month'] = 'måned';
-$labels['day'] = 'dag';
-$labels['date'] = 'dato (åååå-mm-dd)';
-$labels['julian'] = 'dato (juliansk)';
-$labels['hour'] = 'time';
-$labels['minute'] = 'minut';
-$labels['second'] = 'sekund';
-$labels['time'] = 'tid (tt:mm:ss)';
-$labels['iso8601'] = 'dato (ISO8601)';
-$labels['std11'] = 'dato (RFC2822)';
-$labels['zone'] = 'tidszone';
-$labels['weekday'] = 'ugedag (0-6)';
-$labels['advancedopts'] = 'Advancerede muligheder';
-$labels['body'] = 'Brødtekst';
-$labels['address'] = 'adresse';
-$labels['envelope'] = 'kuvert';
-$labels['modifier'] = 'modificerer:';
-$labels['text'] = 'tekst';
-$labels['undecoded'] = 'udekodet (råt):';
-$labels['contenttype'] = 'indholdstype';
-$labels['modtype'] = 'type:';
-$labels['allparts'] = 'alle';
-$labels['domain'] = 'domæne';
-$labels['localpart'] = 'lokal del';
-$labels['user'] = 'bruger';
-$labels['detail'] = 'detalje';
-$labels['comparator'] = 'sammenligner:';
-$labels['default'] = 'standard';
-$labels['octet'] = 'præcis (oktet)';
-$labels['asciicasemap'] = 'store og små bogstaver (ascii-bogstaver)';
-$labels['asciinumeric'] = 'numerisk (ascii-numerisk)';
-$labels['index'] = 'indeks:';
-$labels['indexlast'] = 'baglends';
-$labels['vacation'] = 'Ferie';
-$labels['vacation.reply'] = 'Svar besked';
-$labels['vacation.advanced'] = 'Avanceret indstillinger ';
-$labels['vacation.subject'] = 'Emne';
-$labels['vacation.start'] = 'Ferie star';
-$labels['vacation.end'] = 'Ferie slut';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.saving'] = 'Gemmer data...';
-$labels['vacation.keep'] = 'Behold';
-$labels['vacation.discard'] = 'Kasser';
-$labels['vacation.redirect'] = 'Omdiriger til ';
-$labels['vacation.copy'] = 'Send kopi til';
-$messages['filterunknownerror'] = 'Ukendt server fejl.';
-$messages['filterconnerror'] = 'Kan ikke forbinde til server.';
-$messages['filterdeleteerror'] = 'Kunne ikke slette filter. Serverfejl opstod.';
-$messages['filterdeleted'] = 'Filter slettet.';
-$messages['filtersaved'] = 'Filter gemt.';
-$messages['filtersaveerror'] = 'Kunne ikke gemme filter. Serverfejl.';
-$messages['filterdeleteconfirm'] = 'Vil du slette det valgte filter?';
-$messages['ruledeleteconfirm'] = 'Er du sikker på at du vil slette den valgte regel?';
-$messages['actiondeleteconfirm'] = 'Er du sikker på du vil slette den valgte handling?';
-$messages['forbiddenchars'] = 'Ulovlige tegn i feltet';
-$messages['cannotbeempty'] = 'Feltet kan ikke være tomt.';
-$messages['ruleexist'] = 'Filter med dette navn eksisterer allerede.';
-$messages['setactivateerror'] = 'Kan ikke aktiverer valgt filter sæt. Server fejl.';
-$messages['setdeactivateerror'] = 'Kan ikke deaktivere valgt filter sæt. Server fejl.';
-$messages['setdeleteerror'] = 'Kan ikke slette valgt filter sæt. Server fejl.';
-$messages['setactivated'] = 'Filter sæt aktiveret.';
-$messages['setdeactivated'] = 'Filter sæt deaktiveret.';
-$messages['setdeleted'] = 'Filter sæt slettet.';
-$messages['setdeleteconfirm'] = 'Er du sikker på du vil slette valgt filter sæt?';
-$messages['setcreateerror'] = 'Kan ikke oprette filter sæt. Server fejl.';
-$messages['setcreated'] = 'Filter sæt oprettet.';
-$messages['activateerror'] = 'Kan ikke aktivere valgt filter sæt. Server fejl.';
-$messages['deactivateerror'] = 'Kan ikke deaktivere valgt filter sæt. Server fejl.';
-$messages['deactivated'] = 'Filter(filtre) aktiveret.';
-$messages['activated'] = 'Filter(filtre) deaktiveret.';
-$messages['moved'] = 'Filter flyttet.';
-$messages['moveerror'] = 'Kan ikke flytte valgt filter. Server fejl.';
-$messages['nametoolong'] = 'Navn er for langt.';
-$messages['namereserved'] = 'Reserveret navn.';
-$messages['setexist'] = 'Filterv sæt eksisterer allerede';
-$messages['nodata'] = 'Mindst en position skal vælges!';
-$messages['invaliddateformat'] = 'Ugyldigt dato- eller tidsformat';
-$messages['saveerror'] = 'Kunne ikke gemme data. Server fejl';
-$messages['vacationsaved'] = 'Ferie data gemt';
-?>
diff --git a/lib/plugins/managesieve/localization/de_CH.inc b/lib/plugins/managesieve/localization/de_CH.inc
deleted file mode 100644
index 13a4a67..0000000
--- a/lib/plugins/managesieve/localization/de_CH.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filter';
-$labels['managefilters'] = 'Verwalte eingehende Nachrichtenfilter';
-$labels['filtername'] = 'Filtername';
-$labels['newfilter'] = 'Neuer Filter';
-$labels['filteradd'] = 'Filter hinzufügen';
-$labels['filterdel'] = 'Filter löschen';
-$labels['moveup'] = 'Nach oben';
-$labels['movedown'] = 'Nach unten';
-$labels['filterallof'] = 'UND (alle Regeln müssen zutreffen)';
-$labels['filteranyof'] = 'ODER (eine der Regeln muss zutreffen';
-$labels['filterany'] = 'Für alle Nachrichten';
-$labels['filtercontains'] = 'enthält';
-$labels['filternotcontains'] = 'enthält nicht';
-$labels['filteris'] = 'ist gleich';
-$labels['filterisnot'] = 'ist ungleich';
-$labels['filterexists'] = 'ist vorhanden';
-$labels['filternotexists'] = 'nicht vorhanden';
-$labels['filtermatches'] = 'entspricht Ausdruck';
-$labels['filternotmatches'] = 'entspricht nicht Ausdruck';
-$labels['filterregex'] = 'trifft regulären Ausdruck';
-$labels['filternotregex'] = 'entspricht regulärem Ausdruck';
-$labels['filterunder'] = 'unter';
-$labels['filterover'] = 'über';
-$labels['addrule'] = 'Regel hinzufügen';
-$labels['delrule'] = 'Regel löschen';
-$labels['messagemoveto'] = 'Verschiebe Nachricht nach';
-$labels['messageredirect'] = 'Leite Nachricht um nach';
-$labels['messagecopyto'] = 'Kopiere Nachricht nach';
-$labels['messagesendcopy'] = 'Sende Kopie an';
-$labels['messagereply'] = 'Antworte mit Nachricht';
-$labels['messagedelete'] = 'Nachricht löschen';
-$labels['messagediscard'] = 'Discard with message';
-$labels['messagekeep'] = 'Im Posteingang behalten';
-$labels['messagesrules'] = 'Für eingehende Nachrichten:';
-$labels['messagesactions'] = 'Führe folgende Aktionen aus:';
-$labels['add'] = 'Hinzufügen';
-$labels['del'] = 'Löschen';
-$labels['sender'] = 'Absender';
-$labels['recipient'] = 'Empfänger';
-$labels['vacationaddr'] = 'Meine weiteren E-Mail-Adressen:';
-$labels['vacationdays'] = 'Antwort wird erneut gesendet nach (in Tagen):';
-$labels['vacationinterval'] = 'Wie oft senden:';
-$labels['vacationreason'] = 'Inhalt der Nachricht (Abwesenheitsgrund):';
-$labels['vacationsubject'] = 'Betreff';
-$labels['days'] = 'Tage';
-$labels['seconds'] = 'Sekunden';
-$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['setvariable'] = 'Setze Variable';
-$labels['setvarname'] = 'Variablenname:';
-$labels['setvarvalue'] = 'Variablenwert:';
-$labels['setvarmodifiers'] = 'Umwandler:';
-$labels['varlower'] = 'Kleinschreibung';
-$labels['varupper'] = 'Grossschreibung';
-$labels['varlowerfirst'] = 'Erster Buchstabe klein';
-$labels['varupperfirst'] = 'Erster Buchstabe gross';
-$labels['varquotewildcard'] = 'Sonderzeichen auszeichnen';
-$labels['varlength'] = 'Länge';
-$labels['notify'] = 'Mitteilung senden';
-$labels['notifytarget'] = 'Mitteilungsempfänger:';
-$labels['notifymessage'] = 'Mitteilungstext (optional):';
-$labels['notifyoptions'] = 'Mitteilungsoptionen (optional):';
-$labels['notifyfrom'] = 'Absender (optional):';
-$labels['notifyimportance'] = 'Wichtigkeit:';
-$labels['notifyimportancelow'] = 'tief';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'hoch';
-$labels['notifymethodmailto'] = 'E-Mail';
-$labels['notifymethodtel'] = 'Telefon';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Filter erstellen';
-$labels['usedata'] = 'Die folgenden Daten im Filter benutzen:';
-$labels['nextstep'] = 'Nächster Schritt';
-$labels['...'] = '...';
-$labels['currdate'] = 'Aktuelles Datum';
-$labels['datetest'] = 'Datum';
-$labels['dateheader'] = 'Kopfzeile:';
-$labels['year'] = 'Jahr';
-$labels['month'] = 'Monat';
-$labels['day'] = 'Tag';
-$labels['date'] = 'Datum (JJJJ-MM-TT)';
-$labels['julian'] = 'Datum (julianisch)';
-$labels['hour'] = 'Stunde';
-$labels['minute'] = 'Minute';
-$labels['second'] = 'Sekunde';
-$labels['time'] = 'Zeit (hh:mm:ss)';
-$labels['iso8601'] = 'Datum (ISO-8601)';
-$labels['std11'] = 'Datum (RFC 2822)';
-$labels['zone'] = 'Zeitzone';
-$labels['weekday'] = 'Wochentag (0-6)';
-$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)';
-$labels['index'] = 'Index:';
-$labels['indexlast'] = 'rückwärts';
-$labels['vacation'] = 'Abwesenheit';
-$labels['vacation.reply'] = 'Antworte mit Nachricht';
-$labels['vacation.advanced'] = 'Erweiterte Einstellungen';
-$labels['vacation.subject'] = 'Betreff';
-$labels['vacation.body'] = 'Inhalt';
-$labels['vacation.start'] = 'Beginn der Abwesenheit';
-$labels['vacation.end'] = 'Ende der Abwesenheit';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.on'] = 'Ein';
-$labels['vacation.off'] = 'Aus';
-$labels['vacation.addresses'] = 'Meine weiteren E-Mail-Adressen';
-$labels['vacation.interval'] = 'Antwort-Intervall';
-$labels['vacation.after'] = 'Abwesenheitsregel einfügen nach';
-$labels['vacation.saving'] = 'Speichere Daten...';
-$labels['vacation.action'] = 'Aktion für eingehende Nachrichten';
-$labels['vacation.keep'] = 'Behalten';
-$labels['vacation.discard'] = 'Verwerfen';
-$labels['vacation.redirect'] = 'Weiterleiten an';
-$labels['vacation.copy'] = 'Kopie an';
-$labels['arialabelfiltersetactions'] = 'Filtersatz-Aktionen';
-$labels['arialabelfilteractions'] = 'Filteraktionen';
-$labels['arialabelfilterform'] = 'Filtereigenschaften';
-$labels['ariasummaryfilterslist'] = 'Filterliste';
-$labels['ariasummaryfiltersetslist'] = 'Filtersatzliste';
-$labels['filterstitle'] = 'Eingehende Nachrichtenfilter bearbeiten';
-$labels['vacationtitle'] = 'Abwesenheitsregel bearbeiten';
-$messages['filterunknownerror'] = 'Unbekannter Serverfehler';
-$messages['filterconnerror'] = 'Kann nicht zum Sieve-Server verbinden';
-$messages['filterdeleteerror'] = 'Serverfehler beim Löschen des Filters.';
-$messages['filterdeleted'] = 'Filter erfolgreich gelöscht';
-$messages['filtersaved'] = 'Filter gespeichert';
-$messages['filtersaveerror'] = 'Serverfehler beim Speichern des Filters.';
-$messages['filterdeleteconfirm'] = 'Möchten Sie den Filter löschen ?';
-$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';
-$messages['ruleexist'] = 'Ein Filter mit dem angegebenen Namen existiert bereits.';
-$messages['setactivateerror'] = 'Serverfehler beim Aktivieren des gewählten Filtersatzes.';
-$messages['setdeactivateerror'] = 'Serverfehler beim Deaktivieren des gewählten Filtersatzes.';
-$messages['setdeleteerror'] = 'Serverfehler beim Löschen des gewählten Filtersatzes.';
-$messages['setactivated'] = 'Filtersatz erfolgreich aktiviert.';
-$messages['setdeactivated'] = 'Filtersatz erfolgreich deaktiviert.';
-$messages['setdeleted'] = 'Filtersatz erfolgreich gelöscht.';
-$messages['setdeleteconfirm'] = 'Sind Sie sicher, dass Sie den ausgewählten Filtersatz löschen möchten?';
-$messages['setcreateerror'] = 'Serverfehler beim Erstellen des Filtersatzes.';
-$messages['setcreated'] = 'Filter erfolgreich erstellt.';
-$messages['activateerror'] = 'Serverfehler beim Aktivieren des/der gewählten Filter(s).';
-$messages['deactivateerror'] = 'Serverfehler beim Deaktivieren des/der gewählten Filter(s).';
-$messages['deactivated'] = 'Filter erfolgreich aktiviert.';
-$messages['activated'] = 'Filter erfolgreich deaktiviert.';
-$messages['moved'] = 'Filter erfolgreich verschoben.';
-$messages['moveerror'] = 'Serverfehler beim Verschieben des gewählten Filters.';
-$messages['nametoolong'] = 'Filtersatz kann nicht erstellt werden. Name zu lang.';
-$messages['namereserved'] = 'Reservierter Name.';
-$messages['setexist'] = 'Filtersatz existiert bereits.';
-$messages['nodata'] = 'Mindestens eine Position muss ausgewählt werden!';
-$messages['invaliddateformat'] = 'Ungültiges Datumsformat';
-$messages['saveerror'] = 'Fehler beim Speichern (Serverfehler)';
-$messages['vacationsaved'] = 'Abwesenheitsnotiz erfolgreich gespeichert.';
-$messages['emptyvacationbody'] = 'Mitteilungstext ist erforderlich!';
-?>
diff --git a/lib/plugins/managesieve/localization/de_DE.inc b/lib/plugins/managesieve/localization/de_DE.inc
deleted file mode 100644
index f57ffa3..0000000
--- a/lib/plugins/managesieve/localization/de_DE.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filter';
-$labels['managefilters'] = 'Filter für eingehende Nachrichten verwalten';
-$labels['filtername'] = 'Filtername';
-$labels['newfilter'] = 'Neuer Filter';
-$labels['filteradd'] = 'Filter hinzufügen';
-$labels['filterdel'] = 'Filter löschen';
-$labels['moveup'] = 'Nach oben';
-$labels['movedown'] = 'Nach unten';
-$labels['filterallof'] = 'trifft auf alle folgenden Regeln zu';
-$labels['filteranyof'] = 'trifft auf eine der folgenden Regeln zu';
-$labels['filterany'] = 'alle Nachrichten';
-$labels['filtercontains'] = 'enthält';
-$labels['filternotcontains'] = 'enthält nicht';
-$labels['filteris'] = 'ist gleich';
-$labels['filterisnot'] = 'ist ungleich';
-$labels['filterexists'] = 'existiert';
-$labels['filternotexists'] = 'existiert nicht';
-$labels['filtermatches'] = 'trifft auf Ausdruck zu';
-$labels['filternotmatches'] = 'trifft nicht auf Ausdruck zu';
-$labels['filterregex'] = 'trifft auf regulären Ausdruck zu';
-$labels['filternotregex'] = 'trifft nicht auf regulären Ausdruck zu';
-$labels['filterunder'] = 'unter';
-$labels['filterover'] = 'über';
-$labels['addrule'] = 'Regel hinzufügen';
-$labels['delrule'] = 'Regel löschen';
-$labels['messagemoveto'] = '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['messagekeep'] = 'Behalte Nachricht im Posteingang';
-$labels['messagesrules'] = 'Für eingehende Nachrichten:';
-$labels['messagesactions'] = '...führe folgende Aktionen aus:';
-$labels['add'] = 'Hinzufügen';
-$labels['del'] = 'Löschen';
-$labels['sender'] = 'Absender';
-$labels['recipient'] = 'Empfänger';
-$labels['vacationaddr'] = 'Meine zusätzliche E-Mail-Adresse(n):';
-$labels['vacationdays'] = 'Wie oft sollen Nachrichten gesendet werden (in Tagen):';
-$labels['vacationinterval'] = 'Wie oft sollen Nachrichten gesendet werden:';
-$labels['vacationreason'] = 'Nachrichteninhalt (Abwesenheitsgrund):';
-$labels['vacationsubject'] = 'Nachrichtenbetreff';
-$labels['days'] = 'Tage';
-$labels['seconds'] = 'Sekunden';
-$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ößer als';
-$labels['countisgreaterthanequal'] = 'Anzahl ist gleich oder größer als';
-$labels['countislessthan'] = 'Anzahl ist kleiner als';
-$labels['countislessthanequal'] = 'Anzahl ist gleich oder kleiner als';
-$labels['countequals'] = 'Anzahl ist gleich';
-$labels['countnotequals'] = 'Anzahl ist nicht gleich';
-$labels['valueisgreaterthan'] = 'Wert ist größer als';
-$labels['valueisgreaterthanequal'] = 'Wert ist gleich oder größer als';
-$labels['valueislessthan'] = 'Wert ist kleiner';
-$labels['valueislessthanequal'] = 'Wert ist gleich oder kleiner als';
-$labels['valueequals'] = 'Wert ist gleich';
-$labels['valuenotequals'] = 'Wert ist nicht gleich';
-$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['setvariable'] = 'Variable setzen';
-$labels['setvarname'] = 'Name der Variable:';
-$labels['setvarvalue'] = 'Wert der Variable:';
-$labels['setvarmodifiers'] = 'Modifikatoren:';
-$labels['varlower'] = 'Kleinschreibung';
-$labels['varupper'] = 'Großschreibung';
-$labels['varlowerfirst'] = 'Erster Buchstabe kleingeschrieben';
-$labels['varupperfirst'] = 'Erster Buchstabe großgeschrieben';
-$labels['varquotewildcard'] = 'maskiere Sonderzeichen';
-$labels['varlength'] = 'Länge';
-$labels['notify'] = 'Sende Benachrichtigung';
-$labels['notifytarget'] = 'Benachrichtigungs-Empfänger:';
-$labels['notifymessage'] = 'Inhalt der Benachrichtigung (optional):';
-$labels['notifyoptions'] = 'Optionen für die Benachrichtigung (optional)';
-$labels['notifyfrom'] = 'Absender der Benachrichtigung (optional):';
-$labels['notifyimportance'] = 'Priorität:';
-$labels['notifyimportancelow'] = 'niedrig';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'hoch';
-$labels['notifymethodmailto'] = 'E-Mail';
-$labels['notifymethodtel'] = 'Telefon';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Filter erstellen';
-$labels['usedata'] = 'Die folgenden Daten im Filter benutzen:';
-$labels['nextstep'] = 'Nächster Schritt';
-$labels['...'] = '...';
-$labels['currdate'] = 'Aktuelles Datum';
-$labels['datetest'] = 'Datum';
-$labels['dateheader'] = 'Kopfzeile:';
-$labels['year'] = 'jahr';
-$labels['month'] = 'monat';
-$labels['day'] = 'tag';
-$labels['date'] = 'datum (yyyy-mm-dd)';
-$labels['julian'] = 'datum (julian)';
-$labels['hour'] = 'stunde';
-$labels['minute'] = 'minute';
-$labels['second'] = 'sekunde';
-$labels['time'] = 'zeit (hh:mm:ss)';
-$labels['iso8601'] = 'datum (ISO8601)';
-$labels['std11'] = 'datum (RFC2822)';
-$labels['zone'] = 'Zeitzone';
-$labels['weekday'] = 'wochentag (0-6)';
-$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)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'rückwärts';
-$labels['vacation'] = 'Urlaub';
-$labels['vacation.reply'] = 'Antwort';
-$labels['vacation.advanced'] = 'Erweiterte Einstellungen';
-$labels['vacation.subject'] = 'Betreff';
-$labels['vacation.body'] = 'Hauptteil';
-$labels['vacation.start'] = 'Beginn des Urlaubs';
-$labels['vacation.end'] = 'Ende des Urlaubs';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.on'] = 'An';
-$labels['vacation.off'] = 'Aus';
-$labels['vacation.addresses'] = 'Meine weiteren Adressen';
-$labels['vacation.interval'] = 'Antwort Intervall';
-$labels['vacation.after'] = 'Setze Urlaubsregel nach';
-$labels['vacation.saving'] = 'Speichere Daten...';
-$labels['vacation.action'] = 'Eingehende Nachrichtaktion';
-$labels['vacation.keep'] = 'Behalten';
-$labels['vacation.discard'] = 'Verwerfen';
-$labels['vacation.redirect'] = 'Weiterleiten an';
-$labels['vacation.copy'] = 'Kopie senden an';
-$labels['arialabelfiltersetactions'] = 'Aktionen für Filtersätze';
-$labels['arialabelfilteractions'] = 'Aktionen für Filter';
-$labels['arialabelfilterform'] = 'Filtereigenschaften';
-$labels['ariasummaryfilterslist'] = 'Liste von Filtern';
-$labels['ariasummaryfiltersetslist'] = 'Liste von Filtersätzen';
-$labels['filterstitle'] = 'Eingehende Mailfilter bearbeiten';
-$labels['vacationtitle'] = 'Abwesendheitsregel bearbeiten';
-$messages['filterunknownerror'] = 'Unbekannter Serverfehler';
-$messages['filterconnerror'] = 'Kann keine Verbindung mit Managesieve-Server herstellen';
-$messages['filterdeleteerror'] = 'Filter kann nicht gelöscht werden. Ein Serverfehler ist aufgetreten.';
-$messages['filterdeleted'] = 'Filter erfolgreich gelöscht';
-$messages['filtersaved'] = 'Filter erfolgreich gespeichert';
-$messages['filtersaveerror'] = 'Filter kann nicht gespeichert werden. Ein Serverfehler ist aufgetreten.';
-$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['ruleexist'] = 'Ein Filter mit dem angegebenen Namen existiert bereits.';
-$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'] = 'Erstellen von Filter Sätzen nicht möglich. Es ist ein Serverfehler aufgetreten.';
-$messages['setcreated'] = 'Filtersatz wurde erfolgreich erstellt';
-$messages['activateerror'] = 'Filter kann nicht aktiviert werden. Serverfehler.';
-$messages['deactivateerror'] = 'Filter kann nicht deaktiviert werden. Serverfehler.';
-$messages['deactivated'] = 'Filter erfolgreich deaktiviert.';
-$messages['activated'] = 'Filter erfolgreich aktiviert.';
-$messages['moved'] = 'Filter erfolgreich verschoben.';
-$messages['moveerror'] = 'Filter kann nicht verschoben werden. Serverfehler.';
-$messages['nametoolong'] = 'Kann Filtersatz nicht erstellen. Name zu lang';
-$messages['namereserved'] = 'Reservierter Name.';
-$messages['setexist'] = 'Filtersatz existiert bereits.';
-$messages['nodata'] = 'Mindestens eine Position muss ausgewählt werden!';
-$messages['invaliddateformat'] = 'Ungültiges Datum oder Teil-Format';
-$messages['saveerror'] = 'Ein Serverfehler ist aufgetreten, Speicherung war nicht möglich.';
-$messages['vacationsaved'] = 'Urlaubsdaten erfolgreich gespeichert.';
-$messages['emptyvacationbody'] = 'Inhalt der Abwesenheitsbenachrichtigung wird benötigt!';
-?>
diff --git a/lib/plugins/managesieve/localization/el_GR.inc b/lib/plugins/managesieve/localization/el_GR.inc
deleted file mode 100644
index d1c7833..0000000
--- a/lib/plugins/managesieve/localization/el_GR.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Φίλτρα';
-$labels['managefilters'] = 'Διαχείριση φίλτρων εισερχόμενων';
-$labels['filtername'] = 'Ονομασία φίλτρου';
-$labels['newfilter'] = 'Δημιουργία φίλτρου';
-$labels['filteradd'] = 'Προσθήκη φίλτρου';
-$labels['filterdel'] = 'Διαγραφή φίλτρου';
-$labels['moveup'] = 'Μετακίνηση πάνω';
-$labels['movedown'] = 'Μετακίνηση κάτω';
-$labels['filterallof'] = 'ταιριάζουν με όλους τους παρακάτω κανόνες';
-$labels['filteranyof'] = 'ταιριάζουν με οποιονδήποτε από τους παρακάτω κανόνες';
-$labels['filterany'] = 'όλα τα μηνύματα';
-$labels['filtercontains'] = 'περιέχει';
-$labels['filternotcontains'] = 'δεν περιέχει';
-$labels['filteris'] = 'είναι ίσο με';
-$labels['filterisnot'] = 'δεν είναι ίσο με';
-$labels['filterexists'] = 'υπάρχει';
-$labels['filternotexists'] = 'δεν υπάρχει';
-$labels['filtermatches'] = 'ταιριάζει με την έκφραση ';
-$labels['filternotmatches'] = 'Δεν ταιριάζει με την έκφραση';
-$labels['filterregex'] = 'ταιριάζει με κανονική έκφραση';
-$labels['filternotregex'] = 'δεν ταιριάζει με κανονική έκφραση';
-$labels['filterunder'] = 'κάτω';
-$labels['filterover'] = 'πάνω';
-$labels['addrule'] = 'Προσθήκη κανόνα';
-$labels['delrule'] = 'Διαγραφή κανόνα';
-$labels['messagemoveto'] = 'Μετακίνηση μηνύματος στο';
-$labels['messageredirect'] = 'Προώθηση μηνύματος στο';
-$labels['messagecopyto'] = 'Αντιγραφη μυνηματος σε';
-$labels['messagesendcopy'] = 'Αποστολη της αντιγραφης μυνηματος σε';
-$labels['messagereply'] = 'Απάντηση με μήνυμα';
-$labels['messagedelete'] = 'Διαγραφή μηνύματος';
-$labels['messagediscard'] = 'Απόρριψη με μήνυμα';
-$labels['messagekeep'] = 'Διατήρηση μηνύματος στα Εισερχόμενα';
-$labels['messagesrules'] = 'Για εισερχόμενα μηνύματα που:';
-$labels['messagesactions'] = '...εκτέλεση των παρακάτω ενεργειών:';
-$labels['add'] = 'Προσθήκη';
-$labels['del'] = 'Διαγραφή';
-$labels['sender'] = 'Αποστολέας';
-$labels['recipient'] = 'Παραλήπτης';
-$labels['vacationaddr'] = 'Πρόσθετες διευθύνσεις email:';
-$labels['vacationdays'] = 'Συχνότητα αποστολής μηνυμάτων (σε ημέρες):';
-$labels['vacationinterval'] = 'Συχνότητα αποστολής μηνυμάτων:';
-$labels['vacationreason'] = 'Σώμα μηνύματος (λόγος απουσίας):';
-$labels['vacationsubject'] = 'Θέμα μηνύματος: ';
-$labels['days'] = 'ημερες';
-$labels['seconds'] = 'δευτερόλεπτα';
-$labels['rulestop'] = 'Παύση επαλήθευσης κανόνων';
-$labels['enable'] = 'Ενεργοποιηση/Απενεργοποιηση';
-$labels['filterset'] = 'Φίλτρα';
-$labels['filtersets'] = 'Φίλτρο';
-$labels['filtersetadd'] = 'Προσθήκη φίλτρων';
-$labels['filtersetdel'] = 'Διαγραφή φίλτρων';
-$labels['filtersetact'] = 'Ενεργοποιηση φιλτρων';
-$labels['filtersetdeact'] = 'Απενεργοποιηση φιλτρων';
-$labels['filterdef'] = 'Ορισμος φιλτρου';
-$labels['filtersetname'] = 'Ονομασία φίλτρων';
-$labels['newfilterset'] = 'Νεα φιλτρα';
-$labels['active'] = 'ενεργο';
-$labels['none'] = 'κανένα';
-$labels['fromset'] = 'από το σύνολο ';
-$labels['fromfile'] = 'απο αρχειο';
-$labels['filterdisabled'] = 'Απενεργοποιημενο φιλτρο';
-$labels['countisgreaterthan'] = 'αρίθμηση είναι μεγαλύτερη από';
-$labels['countisgreaterthanequal'] = 'η μετρηση είναι μεγαλύτερη ή ίση προς';
-$labels['countislessthan'] = 'η μετρηση είναι μικρότερη απο';
-$labels['countislessthanequal'] = 'η μετρηση είναι μικρότερη ή ίση προς';
-$labels['countequals'] = 'η μέτρηση είναι ίση προς ';
-$labels['countnotequals'] = 'η μέτρηση δεν είναι ίση προς ';
-$labels['valueisgreaterthan'] = 'η τιμη είναι μεγαλύτερη από';
-$labels['valueisgreaterthanequal'] = 'η τιμη είναι μεγαλύτερη ή ίση προς';
-$labels['valueislessthan'] = 'η τιμη είναι μικρότερη απο';
-$labels['valueislessthanequal'] = 'η τιμη είναι μικρότερη ή ίση προς';
-$labels['valueequals'] = 'η τιμη είναι ίση με';
-$labels['valuenotequals'] = 'η τιμη δεν είναι ίση με';
-$labels['setflags'] = 'Ορισμός σημαίων στο μήνυμα';
-$labels['addflags'] = 'Προσθήκη σημαίων στο μήνυμα';
-$labels['removeflags'] = 'Αφαιρέση σημαίων από το μήνυμα';
-$labels['flagread'] = 'Αναγνωση';
-$labels['flagdeleted'] = 'Διεγραμμένο';
-$labels['flaganswered'] = 'Απαντήθηκε ';
-$labels['flagflagged'] = 'Σημειωμένο';
-$labels['flagdraft'] = 'Πρόχειρα';
-$labels['setvariable'] = 'Ορισμός μεταβλητής';
-$labels['setvarname'] = 'Όνομα μεταβλητης:';
-$labels['setvarvalue'] = 'Τιμη μεταβλητης:';
-$labels['setvarmodifiers'] = 'Τροποποιητές: ';
-$labels['varlower'] = 'Μικρογράμματη γραφή';
-$labels['varupper'] = 'κεφαλαία γράμματα ';
-$labels['varlowerfirst'] = 'πρώτος χαρακτήρας πεζός ';
-$labels['varupperfirst'] = 'πρώτος χαρακτήρας κεφαλαία γράμματα';
-$labels['varquotewildcard'] = 'παραθέση ειδικων χαρακτήρων';
-$labels['varlength'] = 'Μήκος';
-$labels['notify'] = 'Αποστολή ειδοποίησης ';
-$labels['notifytarget'] = 'Παραλήπτης ειδοποίησης:';
-$labels['notifymessage'] = 'Μήνυμα ειδοποίησης (προαιρετικά):';
-$labels['notifyoptions'] = 'Επιλογές ειδοποίησης (προαιρετικά):';
-$labels['notifyfrom'] = 'Αποστολέας ειδοποίησης (προαιρετικά):';
-$labels['notifyimportance'] = 'Σημασία: ';
-$labels['notifyimportancelow'] = 'Χαμηλή';
-$labels['notifyimportancenormal'] = 'Κανονική';
-$labels['notifyimportancehigh'] = 'Υψηλή';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Τηλέφωνο';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Δημιουργία φίλτρου';
-$labels['usedata'] = 'Χρησιμοποιηση ακολουθων δεδομενων στο φιλτρο:';
-$labels['nextstep'] = 'Επομενο βημα';
-$labels['...'] = '...';
-$labels['currdate'] = 'Τρέχουσα ημερομηνία';
-$labels['datetest'] = 'Ημερομηνία';
-$labels['dateheader'] = 'επικεφαλίδα:';
-$labels['year'] = 'χρονος';
-$labels['month'] = 'μηνας';
-$labels['day'] = 'ημερα';
-$labels['date'] = 'ημερομηνια (yyyy-mm-dd)';
-$labels['julian'] = 'ημερομηνια (julian)';
-$labels['hour'] = 'ωρα';
-$labels['minute'] = 'λεπτο';
-$labels['second'] = 'δευτερόλεπτο';
-$labels['time'] = 'ωρα (hh:mm:ss)';
-$labels['iso8601'] = 'ημερομηνια (ISO8601)';
-$labels['std11'] = 'ημερομηνια (RFC2822)';
-$labels['zone'] = 'Ζώνη Ώρας';
-$labels['weekday'] = 'ημέρα της εβδομάδας (0-6)';
-$labels['advancedopts'] = 'Προχωρημένες ρυθμίσεις';
-$labels['body'] = 'Σώμα';
-$labels['address'] = 'Διεύθυνση';
-$labels['envelope'] = 'φάκελος';
-$labels['modifier'] = 'Τροποποιηση: ';
-$labels['text'] = 'κειμενο';
-$labels['undecoded'] = 'αποκωδικοποιημένο (raw)';
-$labels['contenttype'] = 'Τύπος περιεχομένου ';
-$labels['modtype'] = 'τυπος:';
-$labels['allparts'] = 'Όλα';
-$labels['domain'] = 'τομέας';
-$labels['localpart'] = 'τοπικό τμήμα ';
-$labels['user'] = 'χρηστης';
-$labels['detail'] = 'λεπτομερειες';
-$labels['comparator'] = 'σύγκριση:';
-$labels['default'] = 'προεπιλογή';
-$labels['octet'] = 'αυστηρή (οκτάδα) ';
-$labels['asciicasemap'] = 'πεζά ή κεφαλαία (ascii-casemap)';
-$labels['asciinumeric'] = 'αριθμητικό (ascii-αριθμητικο)';
-$labels['index'] = 'ευρετήριο:';
-$labels['indexlast'] = 'προς τα πίσω';
-$labels['vacation'] = 'Διακοπές';
-$labels['vacation.reply'] = 'Μήνυμα απάντησης';
-$labels['vacation.advanced'] = 'Προηγμένες ρυθμίσεις';
-$labels['vacation.subject'] = 'Θέμα';
-$labels['vacation.body'] = 'Σώμα';
-$labels['vacation.start'] = 'Έναρξη διακοπών';
-$labels['vacation.end'] = 'Λήξη διακοπών';
-$labels['vacation.status'] = 'Κατάσταση';
-$labels['vacation.on'] = 'Ενεργό';
-$labels['vacation.off'] = 'Ανενεργό';
-$labels['vacation.addresses'] = 'Επιπλέον διευθύνσεις';
-$labels['vacation.interval'] = 'Διάστημα απάντησης';
-$labels['vacation.after'] = 'Εισαγωγή κανόνα διακοπών μετά από';
-$labels['vacation.saving'] = 'Αποθήκευση δεδομένων...';
-$labels['vacation.action'] = 'Ενέργεια εισερχόμενου μηνύματος';
-$labels['vacation.keep'] = 'Διατήρηση';
-$labels['vacation.discard'] = 'Διαγραφή';
-$labels['vacation.redirect'] = 'Ανακατεύθυνση σε';
-$labels['vacation.copy'] = 'Αποστολή αντιγράφου σε';
-$labels['arialabelfiltersetactions'] = 'Ενέργειες ομάδας φίλτρων';
-$labels['arialabelfilteractions'] = 'Ενέργειες φίλτρων';
-$labels['arialabelfilterform'] = 'Ιδιότητες φίλτρων';
-$labels['ariasummaryfilterslist'] = 'Λίστα φίλτρων';
-$labels['ariasummaryfiltersetslist'] = 'Λίστα ομάδων φίλτρων';
-$labels['filterstitle'] = 'Επεξεργασία φίλτρων εισερχόμενης αλληλογραφίας';
-$labels['vacationtitle'] = 'Επεξεργασία κανόνα εκτός-γραφείου';
-$messages['filterunknownerror'] = 'Άγνωστο σφάλμα διακομιστή';
-$messages['filterconnerror'] = 'Αδυναμία σύνδεσης στον διακομιστή managesieve';
-$messages['filterdeleteerror'] = 'Αδυναμία διαγραφής φίλτρου. Προέκυψε σφάλμα στον διακομιστή';
-$messages['filterdeleted'] = 'Το φίλτρο διαγράφηκε επιτυχώς';
-$messages['filtersaved'] = 'Το φίλτρο αποθηκεύτηκε επιτυχώς';
-$messages['filtersaveerror'] = 'Αδυναμία αποθήκευσης φίλτρου. Προέκυψε σφάλμα στον διακομιστή';
-$messages['filterdeleteconfirm'] = 'Είστε σίγουροι ότι θέλετε να διαγράψετε το επιλεγμένο φίλτρο? ';
-$messages['ruledeleteconfirm'] = 'Θέλετε όντως να διαγράψετε τον επιλεγμένο κανόνα;';
-$messages['actiondeleteconfirm'] = 'Θέλετε όντως να διαγράψετε την επιλεγμένη ενέργεια;';
-$messages['forbiddenchars'] = 'Μη επιτρεπτοί χαρακτήρες στο πεδίο';
-$messages['cannotbeempty'] = 'Το πεδίο δεν μπορεί να είναι κενό';
-$messages['ruleexist'] = 'Φιλτρο με αυτο το όνομα υπάρχει ήδη. ';
-$messages['setactivateerror'] = 'Αδυναμία ενεργοποίησης επιλεγμένων ομάδων φίλτρων. Προέκυψε σφάλμα στον διακομιστή.';
-$messages['setdeactivateerror'] = 'Αδυναμία απενεργοποίησης επιλεγμένων ομάδων φίλτρων. Προέκυψε σφάλμα στον διακομιστή.';
-$messages['setdeleteerror'] = 'Αδυναμία διαγραφής των επιλεγμένων ομάδων φίλτρων. Προέκυψε σφάλμα στον διακομιστή';
-$messages['setactivated'] = 'Φίλτρα ενεργοποιήθηκαν με επιτυχία.';
-$messages['setdeactivated'] = 'Φίλτρα απενεργοποιήθηκαν με επιτυχία.';
-$messages['setdeleted'] = 'Τα φίλτρα διαγράφηκαν επιτυχώς.';
-$messages['setdeleteconfirm'] = 'Θέλετε όντως να διαγράψετε τα επιλεγμένα φιλτρα?';
-$messages['setcreateerror'] = 'Αδυναμία δημιουργίας ομάδας φίλτρων. Προέκυψε σφάλμα στον διακομιστή.';
-$messages['setcreated'] = 'Τα φιλτρα δημιουργηθηκαν επιτυχως.';
-$messages['activateerror'] = 'Αδυναμία ενεργοποίησης επιλεγμένου φίλτρου(ων). Προέκυψε σφάλμα στον διακομιστή.';
-$messages['deactivateerror'] = 'Αδυναμία απενεργοποίησης επιλεγμένου φίλτρου(ων). Προέκυψε σφάλμα στον διακομιστή.';
-$messages['deactivated'] = 'Το φιλτρο(α) απενεργοποιηθηκαν επιτυχως.';
-$messages['activated'] = 'Το φίλτρο(α) ενεργοποιηθηκαν επιτυχώς.';
-$messages['moved'] = 'Το φίλτρο μετακινηθηκε επιτυχώς.';
-$messages['moveerror'] = 'Αδυναμία μετακίνησης επιλεγμένου φίλτρου. Προέκυψε σφάλμα στον διακομιστή.';
-$messages['nametoolong'] = 'Το όνομα είναι πολύ μεγάλο.';
-$messages['namereserved'] = 'Δεσμευμένο όνομα. ';
-$messages['setexist'] = 'Set υπάρχει ήδη. ';
-$messages['nodata'] = 'Τουλάχιστον μία θέση πρέπει να επιλεγεί!';
-$messages['invaliddateformat'] = 'Μη έγκυρη ημερομηνία ή η ημερομηνία μορφής τμήμα';
-$messages['saveerror'] = 'Αδύνατη η αποθήκευση δεδομένων. Προέκυψε σφάλμα στον διακομιστή';
-$messages['vacationsaved'] = 'Τα δεδομένα διακοπών αποθηκεύτηκαν επιτυχώς.';
-$messages['emptyvacationbody'] = 'Απαιτείται σώμα για το μήνυμα διακοπών!';
-?>
diff --git a/lib/plugins/managesieve/localization/en_CA.inc b/lib/plugins/managesieve/localization/en_CA.inc
deleted file mode 100644
index 400f835..0000000
--- a/lib/plugins/managesieve/localization/en_CA.inc
+++ /dev/null
@@ -1,209 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filters';
-$labels['managefilters'] = 'Manage incoming mail filters';
-$labels['filtername'] = 'Filter name';
-$labels['newfilter'] = 'New filter';
-$labels['filteradd'] = 'Add filter';
-$labels['filterdel'] = 'Delete filter';
-$labels['moveup'] = 'Move up';
-$labels['movedown'] = 'Move down';
-$labels['filterallof'] = 'matching all of the following rules';
-$labels['filteranyof'] = 'matching any of the following rules';
-$labels['filterany'] = 'all messages';
-$labels['filtercontains'] = 'contains';
-$labels['filternotcontains'] = 'not contains';
-$labels['filteris'] = 'is equal to';
-$labels['filterisnot'] = 'is not equal to';
-$labels['filterexists'] = 'exists';
-$labels['filternotexists'] = 'not exists';
-$labels['filtermatches'] = 'matches expression';
-$labels['filternotmatches'] = 'not matches expression';
-$labels['filterregex'] = 'matches regular expression';
-$labels['filternotregex'] = 'not matches regular expression';
-$labels['filterunder'] = 'under';
-$labels['filterover'] = 'over';
-$labels['addrule'] = 'Add rule';
-$labels['delrule'] = 'Delete rule';
-$labels['messagemoveto'] = 'Move message to';
-$labels['messageredirect'] = 'Redirect message to';
-$labels['messagecopyto'] = 'Copy message to';
-$labels['messagesendcopy'] = 'Send message copy to';
-$labels['messagereply'] = 'Reply with message';
-$labels['messagedelete'] = 'Delete message';
-$labels['messagediscard'] = 'Discard with message';
-$labels['messagekeep'] = 'Keep message in Inbox';
-$labels['messagesrules'] = 'For incoming mail:';
-$labels['messagesactions'] = '...execute the following actions:';
-$labels['add'] = 'Add';
-$labels['del'] = 'Delete';
-$labels['sender'] = 'Sender';
-$labels['recipient'] = 'Recipient';
-$labels['vacationaddr'] = 'My additional e-mail address(es):';
-$labels['vacationdays'] = 'How often send messages (in days):';
-$labels['vacationinterval'] = 'How often send messages:';
-$labels['vacationreason'] = 'Message body (vacation reason):';
-$labels['vacationsubject'] = 'Message subject:';
-$labels['days'] = 'days';
-$labels['seconds'] = 'seconds';
-$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['filterdef'] = 'Filter definition';
-$labels['filtersetname'] = 'Filters set name';
-$labels['newfilterset'] = 'New filters set';
-$labels['active'] = 'active';
-$labels['none'] = 'none';
-$labels['fromset'] = 'from set';
-$labels['fromfile'] = 'from file';
-$labels['filterdisabled'] = 'Filter disabled';
-$labels['countisgreaterthan'] = 'count is greater than';
-$labels['countisgreaterthanequal'] = 'count is greater than or equal to';
-$labels['countislessthan'] = 'count is less than';
-$labels['countislessthanequal'] = 'count is less than or equal to';
-$labels['countequals'] = 'count is equal to';
-$labels['countnotequals'] = 'count is not equal to';
-$labels['valueisgreaterthan'] = 'value is greater than';
-$labels['valueisgreaterthanequal'] = 'value is greater than or equal to';
-$labels['valueislessthan'] = 'value is less than';
-$labels['valueislessthanequal'] = 'value is less than or equal to';
-$labels['valueequals'] = 'value is equal to';
-$labels['valuenotequals'] = 'value is not equal to';
-$labels['setflags'] = 'Set flags to the message';
-$labels['addflags'] = 'Add flags to the message';
-$labels['removeflags'] = 'Remove flags from the message';
-$labels['flagread'] = 'Read';
-$labels['flagdeleted'] = 'Deleted';
-$labels['flaganswered'] = 'Answered';
-$labels['flagflagged'] = 'Flagged';
-$labels['flagdraft'] = 'Draft';
-$labels['setvariable'] = 'Set variable';
-$labels['setvarname'] = 'Variable name:';
-$labels['setvarvalue'] = 'Variable value:';
-$labels['setvarmodifiers'] = 'Modifiers:';
-$labels['varlower'] = 'lower-case';
-$labels['varupper'] = 'upper-case';
-$labels['varlowerfirst'] = 'first character lower-case';
-$labels['varupperfirst'] = 'first character upper-case';
-$labels['varquotewildcard'] = 'quote special characters';
-$labels['varlength'] = 'length';
-$labels['notify'] = 'Send notification';
-$labels['notifytarget'] = 'Notification target:';
-$labels['notifymessage'] = 'Notification message (optional):';
-$labels['notifyoptions'] = 'Notification options (optional):';
-$labels['notifyfrom'] = 'Notification sender (optional):';
-$labels['notifyimportance'] = 'Importance:';
-$labels['notifyimportancelow'] = 'low';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'high';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Phone';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Create filter';
-$labels['usedata'] = 'Use following data in the filter:';
-$labels['nextstep'] = 'Next Step';
-$labels['...'] = '...';
-$labels['currdate'] = 'Current date';
-$labels['datetest'] = 'Date';
-$labels['dateheader'] = 'header:';
-$labels['year'] = 'year';
-$labels['month'] = 'month';
-$labels['day'] = 'day';
-$labels['date'] = 'date (yyyy-mm-dd)';
-$labels['julian'] = 'date (julian)';
-$labels['hour'] = 'hour';
-$labels['minute'] = 'minute';
-$labels['second'] = 'second';
-$labels['time'] = 'time (hh:mm:ss)';
-$labels['iso8601'] = 'date (ISO8601)';
-$labels['std11'] = 'date (RFC2822)';
-$labels['zone'] = 'time-zone';
-$labels['weekday'] = 'weekday (0-6)';
-$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)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'backwards';
-$labels['vacation'] = 'Vacation';
-$labels['vacation.reply'] = 'Reply message';
-$labels['vacation.advanced'] = 'Advanced settings';
-$labels['vacation.subject'] = 'Subject';
-$labels['vacation.body'] = 'Body';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.on'] = 'On';
-$labels['vacation.off'] = 'Off';
-$labels['vacation.addresses'] = 'My additional addresses';
-$labels['vacation.interval'] = 'Reply interval';
-$labels['vacation.after'] = 'Put vacation rule after';
-$labels['vacation.saving'] = 'Saving data...';
-$messages['filterunknownerror'] = 'Unknown server error.';
-$messages['filterconnerror'] = 'Unable to connect to server.';
-$messages['filterdeleteerror'] = 'Unable to delete filter. Server error occurred.';
-$messages['filterdeleted'] = 'Filter deleted successfully.';
-$messages['filtersaved'] = 'Filter saved successfully.';
-$messages['filtersaveerror'] = 'Unable to save filter. Server error occurred.';
-$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['ruleexist'] = 'Filter with specified name already exists.';
-$messages['setactivateerror'] = 'Unable to activate selected filters set. Server error occurred.';
-$messages['setdeactivateerror'] = 'Unable to deactivate selected filters set. Server error occurred.';
-$messages['setdeleteerror'] = 'Unable to delete selected filters set. Server error occurred.';
-$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 occurred.';
-$messages['setcreated'] = 'Filters set created successfully.';
-$messages['activateerror'] = 'Unable to enable selected filter(s). Server error occurred.';
-$messages['deactivateerror'] = 'Unable to disable selected filter(s). Server error occurred.';
-$messages['deactivated'] = 'Filter(s) disabled successfully.';
-$messages['activated'] = 'Filter(s) enabled successfully.';
-$messages['moved'] = 'Filter moved successfully.';
-$messages['moveerror'] = 'Unable to move selected filter. Server error occurred.';
-$messages['nametoolong'] = 'Name too long.';
-$messages['namereserved'] = 'Reserved name.';
-$messages['setexist'] = 'Set already exists.';
-$messages['nodata'] = 'At least one position must be selected!';
-$messages['invaliddateformat'] = 'Invalid date or date part format';
-$messages['saveerror'] = 'Unable to save data. Server error occurred.';
-$messages['vacationsaved'] = 'Vacation data saved successfully.';
-?>
diff --git a/lib/plugins/managesieve/localization/en_GB.inc b/lib/plugins/managesieve/localization/en_GB.inc
deleted file mode 100644
index 0cc8872..0000000
--- a/lib/plugins/managesieve/localization/en_GB.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filters';
-$labels['managefilters'] = 'Manage incoming mail filters';
-$labels['filtername'] = 'Filter name';
-$labels['newfilter'] = 'New filter';
-$labels['filteradd'] = 'Add filter';
-$labels['filterdel'] = 'Delete filter';
-$labels['moveup'] = 'Move up';
-$labels['movedown'] = 'Move down';
-$labels['filterallof'] = 'matching all of the following rules';
-$labels['filteranyof'] = 'matching any of the following rules';
-$labels['filterany'] = 'all messages';
-$labels['filtercontains'] = 'contains';
-$labels['filternotcontains'] = 'not contains';
-$labels['filteris'] = 'is equal to';
-$labels['filterisnot'] = 'is not equal to';
-$labels['filterexists'] = 'exists';
-$labels['filternotexists'] = 'not exists';
-$labels['filtermatches'] = 'matches expression';
-$labels['filternotmatches'] = 'not matches expression';
-$labels['filterregex'] = 'matches regular expression';
-$labels['filternotregex'] = 'not matches regular expression';
-$labels['filterunder'] = 'under';
-$labels['filterover'] = 'over';
-$labels['addrule'] = 'Add rule';
-$labels['delrule'] = 'Delete rule';
-$labels['messagemoveto'] = 'Move message to';
-$labels['messageredirect'] = 'Redirect message to';
-$labels['messagecopyto'] = 'Copy message to';
-$labels['messagesendcopy'] = 'Send message copy to';
-$labels['messagereply'] = 'Reply with message';
-$labels['messagedelete'] = 'Delete message';
-$labels['messagediscard'] = 'Discard with message';
-$labels['messagekeep'] = 'Keep message in Inbox';
-$labels['messagesrules'] = 'For incoming mail:';
-$labels['messagesactions'] = '...execute the following actions:';
-$labels['add'] = 'Add';
-$labels['del'] = 'Delete';
-$labels['sender'] = 'Sender';
-$labels['recipient'] = 'Recipient';
-$labels['vacationaddr'] = 'My additional e-mail address(es):';
-$labels['vacationdays'] = 'How often send messages (in days):';
-$labels['vacationinterval'] = 'How often send messages:';
-$labels['vacationreason'] = 'Message body (vacation reason):';
-$labels['vacationsubject'] = 'Message subject:';
-$labels['days'] = 'days';
-$labels['seconds'] = 'seconds';
-$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['filterdef'] = 'Filter definition';
-$labels['filtersetname'] = 'Filters set name';
-$labels['newfilterset'] = 'New filters set';
-$labels['active'] = 'active';
-$labels['none'] = 'none';
-$labels['fromset'] = 'from set';
-$labels['fromfile'] = 'from file';
-$labels['filterdisabled'] = 'Filter disabled';
-$labels['countisgreaterthan'] = 'count is greater than';
-$labels['countisgreaterthanequal'] = 'count is greater than or equal to';
-$labels['countislessthan'] = 'count is less than';
-$labels['countislessthanequal'] = 'count is less than or equal to';
-$labels['countequals'] = 'count is equal to';
-$labels['countnotequals'] = 'count is not equal to';
-$labels['valueisgreaterthan'] = 'value is greater than';
-$labels['valueisgreaterthanequal'] = 'value is greater than or equal to';
-$labels['valueislessthan'] = 'value is less than';
-$labels['valueislessthanequal'] = 'value is less than or equal to';
-$labels['valueequals'] = 'value is equal to';
-$labels['valuenotequals'] = 'value is not equal to';
-$labels['setflags'] = 'Set flags to the message';
-$labels['addflags'] = 'Add flags to the message';
-$labels['removeflags'] = 'Remove flags from the message';
-$labels['flagread'] = 'Read';
-$labels['flagdeleted'] = 'Deleted';
-$labels['flaganswered'] = 'Answered';
-$labels['flagflagged'] = 'Flagged';
-$labels['flagdraft'] = 'Draft';
-$labels['setvariable'] = 'Set variable';
-$labels['setvarname'] = 'Variable name:';
-$labels['setvarvalue'] = 'Variable value:';
-$labels['setvarmodifiers'] = 'Modifiers:';
-$labels['varlower'] = 'lower-case';
-$labels['varupper'] = 'upper-case';
-$labels['varlowerfirst'] = 'first character lower-case';
-$labels['varupperfirst'] = 'first character upper-case';
-$labels['varquotewildcard'] = 'quote special characters';
-$labels['varlength'] = 'length';
-$labels['notify'] = 'Send notification';
-$labels['notifytarget'] = 'Notification target:';
-$labels['notifymessage'] = 'Notification message (optional):';
-$labels['notifyoptions'] = 'Notification options (optional):';
-$labels['notifyfrom'] = 'Notification sender (optional):';
-$labels['notifyimportance'] = 'Importance:';
-$labels['notifyimportancelow'] = 'low';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'high';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Phone';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Create filter';
-$labels['usedata'] = 'Use following data in the filter:';
-$labels['nextstep'] = 'Next Step';
-$labels['...'] = '...';
-$labels['currdate'] = 'Current date';
-$labels['datetest'] = 'Date';
-$labels['dateheader'] = 'header:';
-$labels['year'] = 'year';
-$labels['month'] = 'month';
-$labels['day'] = 'day';
-$labels['date'] = 'date (yyyy-mm-dd)';
-$labels['julian'] = 'date (julian)';
-$labels['hour'] = 'hour';
-$labels['minute'] = 'minute';
-$labels['second'] = 'second';
-$labels['time'] = 'time (hh:mm:ss)';
-$labels['iso8601'] = 'date (ISO8601)';
-$labels['std11'] = 'date (RFC2822)';
-$labels['zone'] = 'time-zone';
-$labels['weekday'] = 'weekday (0-6)';
-$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)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'backwards';
-$labels['vacation'] = 'Vacation';
-$labels['vacation.reply'] = 'Reply message';
-$labels['vacation.advanced'] = 'Advanced settings';
-$labels['vacation.subject'] = 'Subject';
-$labels['vacation.body'] = 'Body';
-$labels['vacation.start'] = 'Vacation start';
-$labels['vacation.end'] = 'Vacation end';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.on'] = 'On';
-$labels['vacation.off'] = 'Off';
-$labels['vacation.addresses'] = 'My additional addresses';
-$labels['vacation.interval'] = 'Reply interval';
-$labels['vacation.after'] = 'Put vacation rule after';
-$labels['vacation.saving'] = 'Saving data...';
-$labels['vacation.action'] = 'Incoming message action';
-$labels['vacation.keep'] = 'Keep';
-$labels['vacation.discard'] = 'Discard';
-$labels['vacation.redirect'] = 'Redirect to';
-$labels['vacation.copy'] = 'Send copy to';
-$labels['arialabelfiltersetactions'] = 'Filter set actions';
-$labels['arialabelfilteractions'] = 'Filter actions';
-$labels['arialabelfilterform'] = 'Filter properties';
-$labels['ariasummaryfilterslist'] = 'List of filters';
-$labels['ariasummaryfiltersetslist'] = 'List of filter sets';
-$labels['filterstitle'] = 'Edit incoming mail filters';
-$labels['vacationtitle'] = 'Edit out-of-office rule';
-$messages['filterunknownerror'] = 'Unknown server error';
-$messages['filterconnerror'] = 'Unable to connect to managesieve server';
-$messages['filterdeleteerror'] = 'Unable to delete filter. Server error occurred.';
-$messages['filterdeleted'] = 'Filter deleted successfully';
-$messages['filtersaved'] = 'Filter saved successfully';
-$messages['filtersaveerror'] = 'Unable to save filter. Server error occurred.';
-$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['ruleexist'] = 'Filter with specified name already exists.';
-$messages['setactivateerror'] = 'Unable to activate selected filters set. Server error occurred.';
-$messages['setdeactivateerror'] = 'Unable to deactivate selected filters set. Server error occurred.';
-$messages['setdeleteerror'] = 'Unable to delete selected filters set. Server error occurred.';
-$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 occurred.';
-$messages['setcreated'] = 'Filters set created successfully.';
-$messages['activateerror'] = 'Unable to enable selected filter(s). Server error occurred.';
-$messages['deactivateerror'] = 'Unable to disable selected filter(s). Server error occurred.';
-$messages['deactivated'] = 'Filter(s) disabled successfully.';
-$messages['activated'] = 'Filter(s) enabled successfully.';
-$messages['moved'] = 'Filter moved successfully.';
-$messages['moveerror'] = 'Unable to move selected filter. Server error occurred.';
-$messages['nametoolong'] = 'Name too long.';
-$messages['namereserved'] = 'Reserved name.';
-$messages['setexist'] = 'Set already exists.';
-$messages['nodata'] = 'At least one position must be selected!';
-$messages['invaliddateformat'] = 'Invalid date or date part format';
-$messages['saveerror'] = 'Unable to save data. Server error occurred.';
-$messages['vacationsaved'] = 'Vacation data saved successfully.';
-$messages['emptyvacationbody'] = 'Body of vacation message is required!';
-?>
diff --git a/lib/plugins/managesieve/localization/en_US.inc b/lib/plugins/managesieve/localization/en_US.inc
deleted file mode 100644
index f455d55..0000000
--- a/lib/plugins/managesieve/localization/en_US.inc
+++ /dev/null
@@ -1,229 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-
-
-$labels['filters'] = 'Filters';
-$labels['managefilters'] = 'Manage incoming mail filters';
-$labels['filtername'] = 'Filter name';
-$labels['newfilter'] = 'New filter';
-$labels['filteradd'] = 'Add filter';
-$labels['filterdel'] = 'Delete filter';
-$labels['moveup'] = 'Move up';
-$labels['movedown'] = 'Move down';
-$labels['filterallof'] = 'matching all of the following rules';
-$labels['filteranyof'] = 'matching any of the following rules';
-$labels['filterany'] = 'all messages';
-$labels['filtercontains'] = 'contains';
-$labels['filternotcontains'] = 'not contains';
-$labels['filteris'] = 'is equal to';
-$labels['filterisnot'] = 'is not equal to';
-$labels['filterexists'] = 'exists';
-$labels['filternotexists'] = 'not exists';
-$labels['filtermatches'] = 'matches expression';
-$labels['filternotmatches'] = 'not matches expression';
-$labels['filterregex'] = 'matches regular expression';
-$labels['filternotregex'] = 'not matches regular expression';
-$labels['filterunder'] = 'under';
-$labels['filterover'] = 'over';
-$labels['addrule'] = 'Add rule';
-$labels['delrule'] = 'Delete rule';
-$labels['messagemoveto'] = 'Move message to';
-$labels['messageredirect'] = 'Redirect message to';
-$labels['messagecopyto'] = 'Copy message to';
-$labels['messagesendcopy'] = 'Send message copy to';
-$labels['messagereply'] = 'Reply with message';
-$labels['messagedelete'] = 'Delete message';
-$labels['messagediscard'] = 'Discard with message';
-$labels['messagekeep'] = 'Keep message in Inbox';
-$labels['messagesrules'] = 'For incoming mail:';
-$labels['messagesactions'] = '...execute the following actions:';
-$labels['add'] = 'Add';
-$labels['del'] = 'Delete';
-$labels['sender'] = 'Sender';
-$labels['recipient'] = 'Recipient';
-$labels['vacationaddr'] = 'My additional e-mail address(es):';
-$labels['vacationdays'] = 'How often send messages (in days):';
-$labels['vacationinterval'] = 'How often send messages:';
-$labels['vacationreason'] = 'Message body (vacation reason):';
-$labels['vacationsubject'] = 'Message subject:';
-$labels['days'] = 'days';
-$labels['seconds'] = 'seconds';
-$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['filterdef'] = 'Filter definition';
-$labels['filtersetname'] = 'Filters set name';
-$labels['newfilterset'] = 'New filters set';
-$labels['active'] = 'active';
-$labels['none'] = 'none';
-$labels['fromset'] = 'from set';
-$labels['fromfile'] = 'from file';
-$labels['filterdisabled'] = 'Filter disabled';
-$labels['countisgreaterthan'] = 'count is greater than';
-$labels['countisgreaterthanequal'] = 'count is greater than or equal to';
-$labels['countislessthan'] = 'count is less than';
-$labels['countislessthanequal'] = 'count is less than or equal to';
-$labels['countequals'] = 'count is equal to';
-$labels['countnotequals'] = 'count is not equal to';
-$labels['valueisgreaterthan'] = 'value is greater than';
-$labels['valueisgreaterthanequal'] = 'value is greater than or equal to';
-$labels['valueislessthan'] = 'value is less than';
-$labels['valueislessthanequal'] = 'value is less than or equal to';
-$labels['valueequals'] = 'value is equal to';
-$labels['valuenotequals'] = 'value is not equal to';
-$labels['setflags'] = 'Set flags to the message';
-$labels['addflags'] = 'Add flags to the message';
-$labels['removeflags'] = 'Remove flags from the message';
-$labels['flagread'] = 'Read';
-$labels['flagdeleted'] = 'Deleted';
-$labels['flaganswered'] = 'Answered';
-$labels['flagflagged'] = 'Flagged';
-$labels['flagdraft'] = 'Draft';
-$labels['setvariable'] = 'Set variable';
-$labels['setvarname'] = 'Variable name:';
-$labels['setvarvalue'] = 'Variable value:';
-$labels['setvarmodifiers'] = 'Modifiers:';
-$labels['varlower'] = 'lower-case';
-$labels['varupper'] = 'upper-case';
-$labels['varlowerfirst'] = 'first character lower-case';
-$labels['varupperfirst'] = 'first character upper-case';
-$labels['varquotewildcard'] = 'quote special characters';
-$labels['varlength'] = 'length';
-$labels['notify'] = 'Send notification';
-$labels['notifytarget'] = 'Notification target:';
-$labels['notifymessage'] = 'Notification message (optional):';
-$labels['notifyoptions'] = 'Notification options (optional):';
-$labels['notifyfrom'] = 'Notification sender (optional):';
-$labels['notifyimportance'] = 'Importance:';
-$labels['notifyimportancelow'] = 'low';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'high';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Phone';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Create filter';
-$labels['usedata'] = 'Use following data in the filter:';
-$labels['nextstep'] = 'Next Step';
-$labels['...'] = '...';
-$labels['currdate'] = 'Current date';
-$labels['datetest'] = 'Date';
-$labels['dateheader'] = 'header:';
-$labels['year'] = 'year';
-$labels['month'] = 'month';
-$labels['day'] = 'day';
-$labels['date'] = 'date (yyyy-mm-dd)';
-$labels['julian'] = 'date (julian)';
-$labels['hour'] = 'hour';
-$labels['minute'] = 'minute';
-$labels['second'] = 'second';
-$labels['time'] = 'time (hh:mm:ss)';
-$labels['iso8601'] = 'date (ISO8601)';
-$labels['std11'] = 'date (RFC2822)';
-$labels['zone'] = 'time-zone';
-$labels['weekday'] = 'weekday (0-6)';
-$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)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'backwards';
-$labels['vacation'] = 'Vacation';
-$labels['vacation.reply'] = 'Reply message';
-$labels['vacation.advanced'] = 'Advanced settings';
-$labels['vacation.subject'] = 'Subject';
-$labels['vacation.body'] = 'Body';
-$labels['vacation.start'] = 'Vacation start';
-$labels['vacation.end'] = 'Vacation end';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.on'] = 'On';
-$labels['vacation.off'] = 'Off';
-$labels['vacation.addresses'] = 'My additional addresses';
-$labels['vacation.interval'] = 'Reply interval';
-$labels['vacation.after'] = 'Put vacation rule after';
-$labels['vacation.saving'] = 'Saving data...';
-$labels['vacation.action'] = 'Incoming message action';
-$labels['vacation.keep'] = 'Keep';
-$labels['vacation.discard'] = 'Discard';
-$labels['vacation.redirect'] = 'Redirect to';
-$labels['vacation.copy'] = 'Send copy to';
-$labels['arialabelfiltersetactions'] = 'Filter set actions';
-$labels['arialabelfilteractions'] = 'Filter actions';
-$labels['arialabelfilterform'] = 'Filter properties';
-$labels['ariasummaryfilterslist'] = 'List of filters';
-$labels['ariasummaryfiltersetslist'] = 'List of filter sets';
-$labels['filterstitle'] = 'Edit incoming mail filters';
-$labels['vacationtitle'] = 'Edit out-of-office rule';
-
-$messages = array();
-$messages['filterunknownerror'] = 'Unknown server error.';
-$messages['filterconnerror'] = 'Unable to connect to server.';
-$messages['filterdeleteerror'] = 'Unable to delete filter. Server error occurred.';
-$messages['filterdeleted'] = 'Filter deleted successfully.';
-$messages['filtersaved'] = 'Filter saved successfully.';
-$messages['filtersaveerror'] = 'Unable to save filter. Server error occurred.';
-$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['ruleexist'] = 'Filter with specified name already exists.';
-$messages['setactivateerror'] = 'Unable to activate selected filters set. Server error occurred.';
-$messages['setdeactivateerror'] = 'Unable to deactivate selected filters set. Server error occurred.';
-$messages['setdeleteerror'] = 'Unable to delete selected filters set. Server error occurred.';
-$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 occurred.';
-$messages['setcreated'] = 'Filters set created successfully.';
-$messages['activateerror'] = 'Unable to enable selected filter(s). Server error occurred.';
-$messages['deactivateerror'] = 'Unable to disable selected filter(s). Server error occurred.';
-$messages['deactivated'] = 'Filter(s) disabled successfully.';
-$messages['activated'] = 'Filter(s) enabled successfully.';
-$messages['moved'] = 'Filter moved successfully.';
-$messages['moveerror'] = 'Unable to move selected filter. Server error occurred.';
-$messages['nametoolong'] = 'Name too long.';
-$messages['namereserved'] = 'Reserved name.';
-$messages['setexist'] = 'Set already exists.';
-$messages['nodata'] = 'At least one position must be selected!';
-$messages['invaliddateformat'] = 'Invalid date or date part format';
-$messages['saveerror'] = 'Unable to save data. Server error occurred.';
-$messages['vacationsaved'] = 'Vacation data saved successfully.';
-$messages['emptyvacationbody'] = 'Body of vacation message is required!';
-
-?>
diff --git a/lib/plugins/managesieve/localization/eo.inc b/lib/plugins/managesieve/localization/eo.inc
deleted file mode 100644
index f613d92..0000000
--- a/lib/plugins/managesieve/localization/eo.inc
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtriloj';
-$labels['managefilters'] = 'Mastrumi filtrilojn pri enirantaj mesaĝoj';
-$labels['filtername'] = 'Nomo de filtrilo';
-$labels['newfilter'] = 'Nova filtrilo';
-$labels['filteradd'] = 'Aldoni filtrilon';
-$labels['filterdel'] = 'Forigi filtrilon';
-$labels['moveup'] = 'Movi supren';
-$labels['movedown'] = 'Movi malsupren';
-$labels['filterany'] = 'ĉiuj mesaĝoj';
-$labels['filtercontains'] = 'enhavas';
-$labels['filternotcontains'] = 'ne enhavas';
-$labels['filteris'] = 'egalas al';
-$labels['filterisnot'] = 'ne egalas al';
-$labels['filterexists'] = 'ekzistas';
-$labels['filternotexists'] = 'ne ekzistas';
-$labels['filtermatches'] = 'kongruas esprimon';
-$labels['filternotmatches'] = 'ne kongruas esprimon';
-$labels['filterregex'] = 'kongruas regularan esprimon';
-$labels['filternotregex'] = 'ne kongruas regularan esprimon';
-$labels['filterunder'] = 'sub';
-$labels['filterover'] = 'preter';
-$labels['addrule'] = 'Aldoni regulon';
-$labels['delrule'] = 'Forigi regulon';
-$labels['messagemoveto'] = 'Movi mesaĝon al';
-$labels['messageredirect'] = 'Aidirekti mesaĝon al';
-$labels['messagecopyto'] = 'Kopii mesaĝo en';
-$labels['messagesendcopy'] = 'Sendi kopion de mesaĝo al';
-$labels['messagereply'] = 'Respondi per mesaĝo';
-$labels['messagedelete'] = 'Forigi mesaĝon';
-$labels['add'] = 'Aldoni';
-$labels['del'] = 'Forigi';
-$labels['sender'] = 'Sendanto';
-$labels['recipient'] = 'Ricevanto';
-?>
diff --git a/lib/plugins/managesieve/localization/es_419.inc b/lib/plugins/managesieve/localization/es_419.inc
deleted file mode 100644
index 6131895..0000000
--- a/lib/plugins/managesieve/localization/es_419.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtros';
-$labels['managefilters'] = 'Administrar filtros de correos entrantes';
-$labels['filtername'] = 'Nombre del filtro';
-$labels['newfilter'] = 'Filtro nuevo';
-$labels['filteradd'] = 'Agregar filtro';
-$labels['filterdel'] = 'Eliminar filtro';
-$labels['moveup'] = 'Mover hacia arriba';
-$labels['movedown'] = 'Mover hacia abajo';
-$labels['filterallof'] = 'coincide con todas las reglas siguientes';
-$labels['filteranyof'] = 'coincide con cualquiera de las reglas siguientes';
-$labels['filterany'] = 'todos los mensajes';
-$labels['filtercontains'] = 'contiene';
-$labels['filternotcontains'] = 'no contiene';
-$labels['filteris'] = 'es igual a';
-$labels['filterisnot'] = 'no es igual a';
-$labels['filterexists'] = 'existe';
-$labels['filternotexists'] = 'no existe';
-$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['filterunder'] = 'bajo';
-$labels['filterover'] = 'sobre';
-$labels['addrule'] = 'Agregar regla';
-$labels['delrule'] = 'Eliminar regla';
-$labels['messagemoveto'] = 'Mover mensaje a';
-$labels['messageredirect'] = 'Redireccionar mensaje a';
-$labels['messagecopyto'] = 'Copiar mensaje a';
-$labels['messagesendcopy'] = 'Enviar una copia del mensaje a ';
-$labels['messagereply'] = 'Responder con el mensaje';
-$labels['messagedelete'] = 'Eliminar mensaje';
-$labels['messagediscard'] = 'Descartar el mensaje';
-$labels['messagekeep'] = 'Mantener mensaje en la bandeja de entrada';
-$labels['messagesrules'] = 'Para correo entrante:';
-$labels['messagesactions'] = '... ejecutar las siguientes acciones:';
-$labels['add'] = 'Agregar';
-$labels['del'] = 'Eliminar';
-$labels['sender'] = 'Remitente';
-$labels['recipient'] = 'Destinatario';
-$labels['vacationaddr'] = 'Mis direccion(es) adiconal(es):';
-$labels['vacationdays'] = 'Cuan a menudo enviar mensajes (en días):';
-$labels['vacationinterval'] = '¿Con qué frecuencia enviar mensajes?:';
-$labels['vacationreason'] = 'Cuerpo del mensaje (motivo de las vacaciones):';
-$labels['vacationsubject'] = 'Asunto del mensaje:';
-$labels['days'] = 'días';
-$labels['seconds'] = 'segundos';
-$labels['rulestop'] = 'Detener la evaluación de reglas';
-$labels['enable'] = 'Habilitar/Deshabilitar';
-$labels['filterset'] = 'Set de filtros';
-$labels['filtersets'] = 'Filtro acciona';
-$labels['filtersetadd'] = 'Agregar set de filtros';
-$labels['filtersetdel'] = 'Eliminar set de filtros actual';
-$labels['filtersetact'] = 'Activar set de filtros actual';
-$labels['filtersetdeact'] = 'Desactivar set de filtros actual';
-$labels['filterdef'] = 'Definición del filtro';
-$labels['filtersetname'] = 'Nombre del set de filtros';
-$labels['newfilterset'] = 'Nuevo set de filtros';
-$labels['active'] = 'activo';
-$labels['none'] = 'ninguno';
-$labels['fromset'] = 'desde set';
-$labels['fromfile'] = 'desde archivo';
-$labels['filterdisabled'] = 'filtro deshabilitado';
-$labels['countisgreaterthan'] = 'la cuenta es mayor a';
-$labels['countisgreaterthanequal'] = 'la cuenta es mayor o igual a ';
-$labels['countislessthan'] = 'la cuenta es menor que';
-$labels['countislessthanequal'] = 'la cuenta es menor o igual que';
-$labels['countequals'] = 'la cuenta es igual a ';
-$labels['countnotequals'] = 'la cuenta no es menor a';
-$labels['valueisgreaterthan'] = 'el valor es mayor que';
-$labels['valueisgreaterthanequal'] = 'el balor 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 a ';
-$labels['valuenotequals'] = 'el valor no es igual a';
-$labels['setflags'] = 'Colocar etiquetas al mensaje';
-$labels['addflags'] = 'Agrega etiquetas al mensaje';
-$labels['removeflags'] = 'Eliminar etiquetas al mensaje';
-$labels['flagread'] = 'Leido';
-$labels['flagdeleted'] = 'Eliminado';
-$labels['flaganswered'] = 'Respondido';
-$labels['flagflagged'] = 'Etiquetado';
-$labels['flagdraft'] = 'Borrador';
-$labels['setvariable'] = 'Establecer variable';
-$labels['setvarname'] = 'Nombre de la variable:';
-$labels['setvarvalue'] = 'Valor de la variable:';
-$labels['setvarmodifiers'] = 'Modificadores:';
-$labels['varlower'] = 'minúscula';
-$labels['varupper'] = 'mayúscula';
-$labels['varlowerfirst'] = 'primer carácter en minúscula';
-$labels['varupperfirst'] = 'primer carácter en mayúscula';
-$labels['varquotewildcard'] = 'citar carácteres especiales';
-$labels['varlength'] = 'largo';
-$labels['notify'] = 'Enviar notificación';
-$labels['notifytarget'] = 'Destinatario de la notificación:';
-$labels['notifymessage'] = 'Mensaje de notificación (opcional):';
-$labels['notifyoptions'] = 'Opciones de notificación (opcional):';
-$labels['notifyfrom'] = 'Remitente de la notificación (opcional):';
-$labels['notifyimportance'] = 'Importancia:';
-$labels['notifyimportancelow'] = 'baja';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'alta';
-$labels['notifymethodmailto'] = 'Correo electrónico';
-$labels['notifymethodtel'] = 'Teléfono';
-$labels['notifymethodsms'] = 'Mensaje de texto';
-$labels['filtercreate'] = 'Crear filtro';
-$labels['usedata'] = 'Usar los datos siguientes en el filtro:';
-$labels['nextstep'] = 'Paso siguiente';
-$labels['...'] = '...';
-$labels['currdate'] = 'Fecha actual';
-$labels['datetest'] = 'Fecha';
-$labels['dateheader'] = 'encabezado:';
-$labels['year'] = 'año';
-$labels['month'] = 'mes';
-$labels['day'] = 'día';
-$labels['date'] = 'fecha(aaaa-mm-dd)';
-$labels['julian'] = 'fecha (julian)';
-$labels['hour'] = 'hora';
-$labels['minute'] = 'minuto';
-$labels['second'] = 'segundo';
-$labels['time'] = 'hora (hh:mm:ss)';
-$labels['iso8601'] = 'fecha (ISO8601)';
-$labels['std11'] = 'fecha (RFC2822)';
-$labels['zone'] = 'zona horaria';
-$labels['weekday'] = 'día de la semana (0-6)';
-$labels['advancedopts'] = 'Opciones avanzadas';
-$labels['body'] = 'Cuerpo';
-$labels['address'] = 'dirección';
-$labels['envelope'] = 'sobre';
-$labels['modifier'] = 'modificador:';
-$labels['text'] = 'texto';
-$labels['undecoded'] = 'decodificado (crudo)';
-$labels['contenttype'] = 'tipo de contenido';
-$labels['modtype'] = 'tipo:';
-$labels['allparts'] = 'todo';
-$labels['domain'] = 'dominio';
-$labels['localpart'] = 'parte local';
-$labels['user'] = 'usuario';
-$labels['detail'] = 'detalle';
-$labels['comparator'] = 'comparador:';
-$labels['default'] = 'predeterminado';
-$labels['octet'] = 'estricto (octeto)';
-$labels['asciicasemap'] = 'no sensible a mayúsculas y minúsculas (mapero-ascii)';
-$labels['asciinumeric'] = 'numérico (ascii-numérico)';
-$labels['index'] = 'índice:';
-$labels['indexlast'] = 'hacia atrás';
-$labels['vacation'] = 'Vacaciones';
-$labels['vacation.reply'] = 'Responder mensaje';
-$labels['vacation.advanced'] = 'Opciones avanzadas';
-$labels['vacation.subject'] = 'Asunto';
-$labels['vacation.body'] = 'Cuerpo';
-$labels['vacation.start'] = 'Inicio de vacaciones';
-$labels['vacation.end'] = 'Final de vacaciones';
-$labels['vacation.status'] = 'Estado';
-$labels['vacation.on'] = 'Encendido';
-$labels['vacation.off'] = 'Apagado';
-$labels['vacation.addresses'] = 'Mis direcciones adicionales';
-$labels['vacation.interval'] = 'Intervalo de respuesta';
-$labels['vacation.after'] = 'Colocar regla de vacaciones luego';
-$labels['vacation.saving'] = 'Guardando información...';
-$labels['vacation.action'] = 'Acción para mensaje entrante';
-$labels['vacation.keep'] = 'Mantener';
-$labels['vacation.discard'] = 'Descartar';
-$labels['vacation.redirect'] = 'Redireccionar a';
-$labels['vacation.copy'] = 'Enviar una copia a';
-$labels['arialabelfiltersetactions'] = 'Acciones del set de filtros';
-$labels['arialabelfilteractions'] = 'Acciones de filtros';
-$labels['arialabelfilterform'] = 'Propiedades de filtros';
-$labels['ariasummaryfilterslist'] = 'Lista de filtros';
-$labels['ariasummaryfiltersetslist'] = 'Lista de set de filtros';
-$labels['filterstitle'] = 'Administrar filtros de correos entrantes';
-$labels['vacationtitle'] = 'Editar regla de fuera de oficina';
-$messages['filterunknownerror'] = 'Error de servidor desconocido.';
-$messages['filterconnerror'] = 'No se puede conectar al servidor.';
-$messages['filterdeleteerror'] = 'No se puede eliminar el filtro. Ocurrió un error de servidor.';
-$messages['filterdeleted'] = 'Filtro eliminado exitosamente.';
-$messages['filtersaved'] = 'Filtro guardado exitosamente.';
-$messages['filtersaveerror'] = 'No es posible guardar el filtro. Ha ocurrido un error de servidor.';
-$messages['filterdeleteconfirm'] = '¿Estás seguro que quieres eliminar el filtro seleccionado?';
-$messages['ruledeleteconfirm'] = '¿Estás seguro que quieres eliminar la regla seleccionada?';
-$messages['actiondeleteconfirm'] = '¿Estás seguro que queires eliminar la acción seleccionada?';
-$messages['forbiddenchars'] = 'Carácteres ilegales en el campo.';
-$messages['cannotbeempty'] = 'El campo no puede estar vacio.';
-$messages['ruleexist'] = 'Ya existe un filtro con el nombre especificado.';
-$messages['setactivateerror'] = 'No es posible activar el set de filtros seleccionado. Ha ocurrido un error de servidor.';
-$messages['setdeactivateerror'] = 'No es posible desactivar el set de filtros selecciona. Ha ocurrido un error de servidor.';
-$messages['setdeleteerror'] = 'No es posible eliminar el set de filtros seleccionado. Ha ocurrido un error de servidor.';
-$messages['setactivated'] = 'Set de filtros activado exitosamente.';
-$messages['setdeactivated'] = 'Set de filtros desactivado exitosamente.';
-$messages['setdeleted'] = 'Set de filtroseliminado exitosamente.';
-$messages['setdeleteconfirm'] = '¿Estas seguro que deseas eliminar el set de filtros seleccionado?';
-$messages['setcreateerror'] = 'No es posible crear el set de filtros. Ha ocurrido un error de servidor.';
-$messages['setcreated'] = 'Set de filtros creado exitosamente.';
-$messages['activateerror'] = 'No es posible habilitar los filtros seleccionados. Ha ocurrido un error de servidor.';
-$messages['deactivateerror'] = 'No es posible deshabilitar los filtros seleccionados. Ha ocurrido un error de servidor.';
-$messages['deactivated'] = 'Filtro(s) deshabilitado(s) exitosamente.';
-$messages['activated'] = 'Filtro(s) habilitado(s) exitosamente.';
-$messages['moved'] = 'Filtro movido exitosamente.';
-$messages['moveerror'] = 'No es posible mover los filtros seleccionados. Ha ocurrido un error de servidor.';
-$messages['nametoolong'] = 'Nombre demasiado largo.';
-$messages['namereserved'] = 'Nombre reservado.';
-$messages['setexist'] = 'Set ya existe.';
-$messages['nodata'] = 'Debes seleccionar al menos una posición.';
-$messages['invaliddateformat'] = 'Fecha o parte del formato no válido';
-$messages['saveerror'] = 'No es posible guardar la información. Ha ocurrido un error de servidor.';
-$messages['vacationsaved'] = 'Información de vacaciones guardada exitosamente.';
-$messages['emptyvacationbody'] = 'Cuerpo del mensaje de vacaciones es requerido!';
-?>
diff --git a/lib/plugins/managesieve/localization/es_AR.inc b/lib/plugins/managesieve/localization/es_AR.inc
deleted file mode 100644
index 6ac6533..0000000
--- a/lib/plugins/managesieve/localization/es_AR.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtros';
-$labels['managefilters'] = 'Administrar filtros de correo entrante';
-$labels['filtername'] = 'Nombre del filtro';
-$labels['newfilter'] = 'Nuevo filtro';
-$labels['filteradd'] = 'Agregar filtro';
-$labels['filterdel'] = 'Eliminar filtro';
-$labels['moveup'] = 'Mover arriba';
-$labels['movedown'] = 'Mover abajo';
-$labels['filterallof'] = 'coinidir con todas las reglas siguientes';
-$labels['filteranyof'] = 'coincidir con alguna de las reglas siguientes';
-$labels['filterany'] = 'todos los mensajes';
-$labels['filtercontains'] = 'contiene';
-$labels['filternotcontains'] = 'no contiene';
-$labels['filteris'] = 'es igual a';
-$labels['filterisnot'] = 'no es igual a';
-$labels['filterexists'] = 'existe';
-$labels['filternotexists'] = 'no existe';
-$labels['filtermatches'] = 'coincide con la expresión';
-$labels['filternotmatches'] = 'no coindice con la expresión';
-$labels['filterregex'] = 'coincide con la expresión regular';
-$labels['filternotregex'] = 'no coincide con la expresión regular';
-$labels['filterunder'] = 'bajo';
-$labels['filterover'] = 'sobre';
-$labels['addrule'] = 'Agregar regla';
-$labels['delrule'] = 'Eliminar regla';
-$labels['messagemoveto'] = 'Mover mensaje a';
-$labels['messageredirect'] = 'Redirigir mensaje a';
-$labels['messagecopyto'] = 'Copiar mensaje a';
-$labels['messagesendcopy'] = 'Enviar copia del mensaje a';
-$labels['messagereply'] = 'Responder con un mensaje';
-$labels['messagedelete'] = 'Eliminar mensaje';
-$labels['messagediscard'] = 'Descartar con un mensaje';
-$labels['messagekeep'] = 'Mantener mensajes en bandeja de entrada';
-$labels['messagesrules'] = 'Para el correo entrante:';
-$labels['messagesactions'] = '... ejecutar las siguientes acciones:';
-$labels['add'] = 'Agregar';
-$labels['del'] = 'Eliminar';
-$labels['sender'] = 'Remitente';
-$labels['recipient'] = 'Destinatario';
-$labels['vacationaddr'] = 'Mi(s) direccion(es) de e-mail adicional(es):';
-$labels['vacationdays'] = 'Cada cuanto enviar mensajes (en días):';
-$labels['vacationinterval'] = 'Enviar mensajes cada:';
-$labels['vacationreason'] = 'Cuerpo del mensaje (razón de vacaciones):';
-$labels['vacationsubject'] = 'Asunto del mensaje:';
-$labels['days'] = 'dias';
-$labels['seconds'] = 'segundos';
-$labels['rulestop'] = 'Parar de evaluar reglas';
-$labels['enable'] = 'Habilitar/Deshabilitar';
-$labels['filterset'] = 'Conjunto de filtros';
-$labels['filtersets'] = 'Filtro activa';
-$labels['filtersetadd'] = 'Agregar conjunto de filtros';
-$labels['filtersetdel'] = 'Eliminar conjunto de filtros';
-$labels['filtersetact'] = 'Activar conjunto de filtros';
-$labels['filtersetdeact'] = 'Deactivar conjunto de filtros';
-$labels['filterdef'] = 'Definicion del conjunto de filtros';
-$labels['filtersetname'] = 'Nombre del conjunto de filtros';
-$labels['newfilterset'] = 'Nuevo conjunto de filtros';
-$labels['active'] = 'Activar';
-$labels['none'] = 'none';
-$labels['fromset'] = 'desde conjunto';
-$labels['fromfile'] = 'desde archivo';
-$labels['filterdisabled'] = 'Filtro deshabilitado';
-$labels['countisgreaterthan'] = 'la cuenta es mayor a';
-$labels['countisgreaterthanequal'] = 'la cuenta es mayor o igual a';
-$labels['countislessthan'] = 'la cuenta es menor a';
-$labels['countislessthanequal'] = 'la cuenta es menor o igual a';
-$labels['countequals'] = 'la cuenta es igual a';
-$labels['countnotequals'] = 'la cuenta no es igual a';
-$labels['valueisgreaterthan'] = 'el valor es mayor a';
-$labels['valueisgreaterthanequal'] = 'el valor es mayor o igual a';
-$labels['valueislessthan'] = 'el valor es menor a';
-$labels['valueislessthanequal'] = 'el valor es menor o igual a';
-$labels['valueequals'] = 'el valor es igual a';
-$labels['valuenotequals'] = 'el valor no es igual a';
-$labels['setflags'] = 'Configurar marcas del mensaje';
-$labels['addflags'] = 'Agregar marcas al mensaje';
-$labels['removeflags'] = 'Eliminar marcas del mensaje';
-$labels['flagread'] = 'Leer';
-$labels['flagdeleted'] = 'Eliminado';
-$labels['flaganswered'] = 'Respondido';
-$labels['flagflagged'] = 'Marcado';
-$labels['flagdraft'] = 'Borrador';
-$labels['setvariable'] = 'Setear variable';
-$labels['setvarname'] = 'Nombre de variable:';
-$labels['setvarvalue'] = 'Valor de variable:';
-$labels['setvarmodifiers'] = 'Modificadores:';
-$labels['varlower'] = 'minúscula';
-$labels['varupper'] = 'mayúscula';
-$labels['varlowerfirst'] = 'primer caracter en minúscula';
-$labels['varupperfirst'] = 'primer caracter en mayúscula';
-$labels['varquotewildcard'] = 'citar caracteres especiales';
-$labels['varlength'] = 'longitud';
-$labels['notify'] = 'Enviar notificación';
-$labels['notifytarget'] = 'Objetivo de la notificación:';
-$labels['notifymessage'] = 'Mensaje de notificación (opcional):';
-$labels['notifyoptions'] = 'Opciones de notificación (opcional):';
-$labels['notifyfrom'] = 'Remitente de la notificación (opcional):';
-$labels['notifyimportance'] = 'Importancia:';
-$labels['notifyimportancelow'] = 'baja';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'alta';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Teléfono';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Crear filtro';
-$labels['usedata'] = 'Usar la siguiente información en el filtro:';
-$labels['nextstep'] = 'Siguiente paso';
-$labels['...'] = '...';
-$labels['currdate'] = 'Fecha actual';
-$labels['datetest'] = 'Fecha';
-$labels['dateheader'] = 'encabezado:';
-$labels['year'] = 'año';
-$labels['month'] = 'mes';
-$labels['day'] = 'dia';
-$labels['date'] = 'fecha (yyyy-mm-dd)';
-$labels['julian'] = 'fecha (juliano)';
-$labels['hour'] = 'hora';
-$labels['minute'] = 'minuto';
-$labels['second'] = 'segundo';
-$labels['time'] = 'hora (hh:mm:ss)';
-$labels['iso8601'] = 'fecha (ISO8601)';
-$labels['std11'] = 'fecha (RFC2822)';
-$labels['zone'] = 'zona horaria';
-$labels['weekday'] = 'día de la semana (0-6)';
-$labels['advancedopts'] = 'Opciones avanzadas';
-$labels['body'] = 'Cuerpo';
-$labels['address'] = 'dirección';
-$labels['envelope'] = 'envoltura';
-$labels['modifier'] = 'modificador:';
-$labels['text'] = 'texto';
-$labels['undecoded'] = 'sin decodificar (crudo)';
-$labels['contenttype'] = 'tipo de contenido';
-$labels['modtype'] = 'tipo:';
-$labels['allparts'] = 'todo';
-$labels['domain'] = 'dominio';
-$labels['localpart'] = 'parte local';
-$labels['user'] = 'usuario';
-$labels['detail'] = 'detalle';
-$labels['comparator'] = 'comparador:';
-$labels['default'] = 'por defecto';
-$labels['octet'] = 'estricto (octeto)';
-$labels['asciicasemap'] = 'no sensible a minúsculas o mayúsculas (ascii-casemap)';
-$labels['asciinumeric'] = 'numérico (ascii-numeric)';
-$labels['index'] = 'índice:';
-$labels['indexlast'] = 'hacia atrás';
-$labels['vacation'] = 'Vacaciones';
-$labels['vacation.reply'] = 'Responder mensaje';
-$labels['vacation.advanced'] = 'Opciones avanzdas';
-$labels['vacation.subject'] = 'Asunto';
-$labels['vacation.body'] = 'Cuerpo';
-$labels['vacation.start'] = 'Inicio de vacaciones';
-$labels['vacation.end'] = 'Final de vacaciones';
-$labels['vacation.status'] = 'Estado';
-$labels['vacation.on'] = 'On';
-$labels['vacation.off'] = 'Off';
-$labels['vacation.addresses'] = 'Mis direcciones adicionales';
-$labels['vacation.interval'] = 'Intervalo de respuesta';
-$labels['vacation.after'] = 'Colocar luego regla de vacaciones ';
-$labels['vacation.saving'] = 'Guardando información...';
-$labels['vacation.action'] = 'Acción para mensaje entrante';
-$labels['vacation.keep'] = 'Mantener';
-$labels['vacation.discard'] = 'Descartar';
-$labels['vacation.redirect'] = 'Reenviar a';
-$labels['vacation.copy'] = 'Enviar copia a';
-$labels['arialabelfiltersetactions'] = 'Acciones de conjunto de filtros';
-$labels['arialabelfilteractions'] = 'Filtrar acciones';
-$labels['arialabelfilterform'] = 'Filtrar propiedades';
-$labels['ariasummaryfilterslist'] = 'Listado de filtros';
-$labels['ariasummaryfiltersetslist'] = 'Listado de conjunto de filtros';
-$labels['filterstitle'] = 'Editar filtros para mensajes entrantes';
-$labels['vacationtitle'] = 'Editar reglas "fuera de la oficina"';
-$messages['filterunknownerror'] = 'Error desconocido de servidor';
-$messages['filterconnerror'] = 'Imposible conectar con el servidor managesieve';
-$messages['filterdeleteerror'] = 'Imposible borrar filtro. Ha ocurrido un error en el servidor';
-$messages['filterdeleted'] = 'Filtro borrado satisfactoriamente';
-$messages['filtersaved'] = 'Filtro guardado satisfactoriamente';
-$messages['filtersaveerror'] = 'Imposible guardar ell filtro. Ha ocurrido un error en el servidor';
-$messages['filterdeleteconfirm'] = '¿Realmente desea borrar el filtro seleccionado?';
-$messages['ruledeleteconfirm'] = '¿Está seguro de que desea borrar la regla seleccionada?';
-$messages['actiondeleteconfirm'] = '¿Está seguro de que desea borrar la acción seleccionada?';
-$messages['forbiddenchars'] = 'Caracteres prohibidos en el campo';
-$messages['cannotbeempty'] = 'El campo no puede estar vacío';
-$messages['ruleexist'] = 'El filtro con el nombre especificado ya existe.';
-$messages['setactivateerror'] = 'Imposible activar el conjunto de filtros. Error en el servidor.';
-$messages['setdeactivateerror'] = 'Imposible desactivar el conjunto de filtros. Error en el servidor.';
-$messages['setdeleteerror'] = 'Imposible eliminar el conjunto de filtros. Error en el servidor.';
-$messages['setactivated'] = 'Conjunto de filtros activados correctamente';
-$messages['setdeactivated'] = 'Conjunto de filtros desactivados correctamente';
-$messages['setdeleted'] = 'Conjunto de filtros eliminados correctamente';
-$messages['setdeleteconfirm'] = '¿Esta seguro, que quiere eliminar el conjunto de filtros seleccionado?';
-$messages['setcreateerror'] = 'Imposible crear el conjunto de filtros. Error en el servidor.';
-$messages['setcreated'] = 'Conjunto de filtros creados correctamente';
-$messages['activateerror'] = 'Imposible activar el conjunto de filtros. Error en el servidor.';
-$messages['deactivateerror'] = 'Imposible desactivar el conjunto de filtros. Error en el servidor.';
-$messages['deactivated'] = 'Filtro deshabilitado satisfactoriamente';
-$messages['activated'] = 'Filtro habilitado satisfactoriamente';
-$messages['moved'] = 'Filtro movido satisfactoriamente';
-$messages['moveerror'] = 'Imposible mover el filtro seleccionado. Ha ocurrido un error en el servidor.';
-$messages['nametoolong'] = 'El nombre es demasiado largo.';
-$messages['namereserved'] = 'Nombre reservado.';
-$messages['setexist'] = 'Conjunto ya existe.';
-$messages['nodata'] = 'Al menos una posición debe ser seleccionada!';
-$messages['invaliddateformat'] = 'Fecha o formato de fecha inválido';
-$messages['saveerror'] = 'Imposible guardar la información. Ha ocurrido un error con el servidor.';
-$messages['vacationsaved'] = 'Información de vacaciones guardada satisfactoriamente.';
-$messages['emptyvacationbody'] = '¡Se requiere un cuerpo para el mensaje por vacaciones!';
-?>
diff --git a/lib/plugins/managesieve/localization/es_ES.inc b/lib/plugins/managesieve/localization/es_ES.inc
deleted file mode 100644
index 62f357b..0000000
--- a/lib/plugins/managesieve/localization/es_ES.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtros';
-$labels['managefilters'] = 'Administrar filtros de correo entrante';
-$labels['filtername'] = 'Nombre del filtro';
-$labels['newfilter'] = 'Nuevo filtro';
-$labels['filteradd'] = 'Agregar filtro';
-$labels['filterdel'] = 'Eliminar filtro';
-$labels['moveup'] = 'Mover arriba';
-$labels['movedown'] = 'Mover abajo';
-$labels['filterallof'] = 'coincidir con todas las reglas siguientes';
-$labels['filteranyof'] = 'coincidir con alguna de las reglas siguientes';
-$labels['filterany'] = 'todos los mensajes';
-$labels['filtercontains'] = 'contiene';
-$labels['filternotcontains'] = 'no contiene';
-$labels['filteris'] = 'es igual a';
-$labels['filterisnot'] = 'no es igual a';
-$labels['filterexists'] = 'existe';
-$labels['filternotexists'] = 'no existe';
-$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['filterunder'] = 'bajo';
-$labels['filterover'] = 'sobre';
-$labels['addrule'] = 'Agregar regla';
-$labels['delrule'] = 'Eliminar regla';
-$labels['messagemoveto'] = 'Mover mensaje a';
-$labels['messageredirect'] = 'Redirigir mensaje a';
-$labels['messagecopyto'] = 'Copiar mensaje a';
-$labels['messagesendcopy'] = 'Enviar copia del mensaje a';
-$labels['messagereply'] = 'Responder con un mensaje';
-$labels['messagedelete'] = 'Eliminar mensaje';
-$labels['messagediscard'] = 'Descartar con un mensaje';
-$labels['messagekeep'] = 'Mantener el mensaje en la bandeja de entrada';
-$labels['messagesrules'] = 'Para el correo entrante:';
-$labels['messagesactions'] = '... ejecutar las siguientes acciones:';
-$labels['add'] = 'Agregar';
-$labels['del'] = 'Eliminar';
-$labels['sender'] = 'Remitente';
-$labels['recipient'] = 'Destinatario';
-$labels['vacationaddr'] = 'Mis direcciones adicionales de correo electrónico:';
-$labels['vacationdays'] = 'Cada cuánto enviar mensajes (en días):';
-$labels['vacationinterval'] = 'Cada cuánto enviar mensajes:';
-$labels['vacationreason'] = 'Cuerpo del mensaje (razón de vacaciones):';
-$labels['vacationsubject'] = 'Asunto del Mensaje:';
-$labels['days'] = 'días';
-$labels['seconds'] = 'segundos';
-$labels['rulestop'] = 'Parar de evaluar reglas';
-$labels['enable'] = 'Habilitar/Deshabilitar';
-$labels['filterset'] = 'Conjunto de filtros';
-$labels['filtersets'] = 'Conjuntos de filtros';
-$labels['filtersetadd'] = 'Agregar conjunto de filtros';
-$labels['filtersetdel'] = 'Eliminar conjunto de filtros actual';
-$labels['filtersetact'] = 'Activar conjunto de filtros actual';
-$labels['filtersetdeact'] = 'Desactivar conjunto de filtros actual';
-$labels['filterdef'] = 'Definición de filtros';
-$labels['filtersetname'] = 'Nombre del conjunto de filtros';
-$labels['newfilterset'] = 'Nuevo conjunto de filtros';
-$labels['active'] = 'activo';
-$labels['none'] = 'ninguno';
-$labels['fromset'] = 'de conjunto';
-$labels['fromfile'] = 'de archivo';
-$labels['filterdisabled'] = 'Filtro desactivado';
-$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'] = 'la cuenta no es igual a';
-$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 no es igual a';
-$labels['setflags'] = 'Etiquetar el mensaje';
-$labels['addflags'] = 'Agregar etiquetas al mensaje';
-$labels['removeflags'] = 'Eliminar etiquetas al mensaje';
-$labels['flagread'] = 'Leído';
-$labels['flagdeleted'] = 'Eliminado';
-$labels['flaganswered'] = 'Respondido';
-$labels['flagflagged'] = 'Marcado';
-$labels['flagdraft'] = 'Borrador';
-$labels['setvariable'] = 'Establecer variable';
-$labels['setvarname'] = 'Nombre de la variable:';
-$labels['setvarvalue'] = 'Valor de la variable:';
-$labels['setvarmodifiers'] = 'Modificadores';
-$labels['varlower'] = 'minúsculas';
-$labels['varupper'] = 'mayúsculas';
-$labels['varlowerfirst'] = 'inicial en minúsculas';
-$labels['varupperfirst'] = 'inicial en mayúsculas';
-$labels['varquotewildcard'] = 'entrecomillar caracteres especiales';
-$labels['varlength'] = 'longitud';
-$labels['notify'] = 'Enviar notificación';
-$labels['notifytarget'] = 'Destino de la notificación:';
-$labels['notifymessage'] = 'Mensaje de notificación (opcional):';
-$labels['notifyoptions'] = 'Opciones de notificación (opcional):';
-$labels['notifyfrom'] = 'Remitente de la notificación (opcional):';
-$labels['notifyimportance'] = 'Importancia:';
-$labels['notifyimportancelow'] = 'baja';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'alta';
-$labels['notifymethodmailto'] = 'Correo electrónico';
-$labels['notifymethodtel'] = 'Teléfono';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Crear Filtro';
-$labels['usedata'] = 'Usar los siguientes datos en el filtro:';
-$labels['nextstep'] = 'Siguiente paso';
-$labels['...'] = '...';
-$labels['currdate'] = 'Fecha actual';
-$labels['datetest'] = 'Fecha';
-$labels['dateheader'] = 'cabecera:';
-$labels['year'] = 'año';
-$labels['month'] = 'mes';
-$labels['day'] = 'día';
-$labels['date'] = 'fecha (aaaa-mm-dd)';
-$labels['julian'] = 'fecha (juliano)';
-$labels['hour'] = 'hora';
-$labels['minute'] = 'minuto';
-$labels['second'] = 'segundo';
-$labels['time'] = 'hora (hh:mm:ss)';
-$labels['iso8601'] = 'fecha (ISO8601)';
-$labels['std11'] = 'fecha (RFC2822)';
-$labels['zone'] = 'zona horaria';
-$labels['weekday'] = 'día de la semana (0-6)';
-$labels['advancedopts'] = 'Opciones avanzadas';
-$labels['body'] = 'Cuerpo del mensaje';
-$labels['address'] = 'dirección';
-$labels['envelope'] = 'envoltura';
-$labels['modifier'] = 'modificador:';
-$labels['text'] = 'texto';
-$labels['undecoded'] = 'decodificar (en bruto)';
-$labels['contenttype'] = 'tipo de contenido';
-$labels['modtype'] = 'tipo:';
-$labels['allparts'] = 'todo';
-$labels['domain'] = 'dominio';
-$labels['localpart'] = 'parte local';
-$labels['user'] = 'usuario';
-$labels['detail'] = 'detalle';
-$labels['comparator'] = 'comparador:';
-$labels['default'] = 'predeterminado';
-$labels['octet'] = 'estricto (octeto)';
-$labels['asciicasemap'] = 'no sensible a mayúsculas (ascii-casemap)';
-$labels['asciinumeric'] = 'numerico (ascii-numeric)';
-$labels['index'] = 'índice:';
-$labels['indexlast'] = 'hacia atrás';
-$labels['vacation'] = 'Vacaciones';
-$labels['vacation.reply'] = 'Mensaje de respuesta';
-$labels['vacation.advanced'] = 'Configuración avanzada';
-$labels['vacation.subject'] = 'Asunto';
-$labels['vacation.body'] = 'Cuerpo';
-$labels['vacation.start'] = 'Comienzo de las vacaciones';
-$labels['vacation.end'] = 'Final de las vacaciones';
-$labels['vacation.status'] = 'Estado';
-$labels['vacation.on'] = 'Activado';
-$labels['vacation.off'] = 'Desactivado';
-$labels['vacation.addresses'] = 'Mis direcciones adicionales';
-$labels['vacation.interval'] = 'Intervalo de respuesta';
-$labels['vacation.after'] = 'Poner regla de vacaciones después de';
-$labels['vacation.saving'] = 'Guardando datos...';
-$labels['vacation.action'] = 'Acción de mensaje entrante';
-$labels['vacation.keep'] = 'Mantener';
-$labels['vacation.discard'] = 'Descartar';
-$labels['vacation.redirect'] = 'Redireccionar a';
-$labels['vacation.copy'] = 'Enviar copia a';
-$labels['arialabelfiltersetactions'] = 'Acciones de un paquete de filtros';
-$labels['arialabelfilteractions'] = 'Acciones de filtro';
-$labels['arialabelfilterform'] = 'Propiedades de filtro';
-$labels['ariasummaryfilterslist'] = 'Lista de filtros';
-$labels['ariasummaryfiltersetslist'] = 'Lista de paquetes de filtros';
-$labels['filterstitle'] = 'Editar filtros de mensajes entrantes';
-$labels['vacationtitle'] = 'Editar la regla fuera-de-la-oficina';
-$messages['filterunknownerror'] = 'Error desconocido en el servidor.';
-$messages['filterconnerror'] = 'No se ha podido conectar con el servidor managesieve.';
-$messages['filterdeleteerror'] = 'No se ha podido borrar el filtro. Ha ocurrido un error en el servidor.';
-$messages['filterdeleted'] = 'Filtro borrado satisfactoriamente.';
-$messages['filtersaved'] = 'Filtro guardado satisfactoriamente.';
-$messages['filtersaveerror'] = 'No se ha podido guardar el filtro. Ha ocurrido un error en el servidor.';
-$messages['filterdeleteconfirm'] = '¿Realmente desea borrar el filtro seleccionado?';
-$messages['ruledeleteconfirm'] = '¿Está seguro de que desea borrar la regla seleccionada?';
-$messages['actiondeleteconfirm'] = '¿Está seguro de que desea borrar la acción seleccionada?';
-$messages['forbiddenchars'] = 'Caracteres prohibidos en el campo.';
-$messages['cannotbeempty'] = 'El campo no puede estar vacío.';
-$messages['ruleexist'] = 'Ya existe un filtro con el nombre especificado.';
-$messages['setactivateerror'] = 'No se ha podido activar el conjunto de filtros seleccionado. Ha ocurrido un error en el servidor.';
-$messages['setdeactivateerror'] = 'No se ha podido desactivar el conjunto de filtros seleccionado. Ha ocurrido un error en el servidor.';
-$messages['setdeleteerror'] = 'No se ha podido borrar el conjunto de filtros seleccionado. Ha ocurrido un error en el servidor.';
-$messages['setactivated'] = 'Conjunto de filtros activado satisfactoriamente.';
-$messages['setdeactivated'] = 'Conjunto de filtros desactivado satisfactoriamente.';
-$messages['setdeleted'] = 'Conjunto de filtros borrado satisfactoriamente.';
-$messages['setdeleteconfirm'] = '¿Está seguro de que desea borrar el conjunto de filtros seleccionado?';
-$messages['setcreateerror'] = 'No se ha podido crear el conjunto de filtros. Ha ocurrido un error en el servidor.';
-$messages['setcreated'] = 'Conjunto de filtros creado satisfactoriamente.';
-$messages['activateerror'] = 'No se han podido habilitar los filtros seleccionados. Ha ocurrido un error en el servidor.';
-$messages['deactivateerror'] = 'No se han podido deshabilitar los filtros seleccionados. Ha ocurrido un error en el servidor.';
-$messages['deactivated'] = 'Filtro(s) deshabilitado(s) correctamente.';
-$messages['activated'] = 'Filtro(s) habilitado(s) correctamente.';
-$messages['moved'] = 'Filtro movido correctamente.';
-$messages['moveerror'] = 'No se ha podido mover el filtro seleccionado. Ha ocurrido un error en el servidor.';
-$messages['nametoolong'] = 'Nombre demasiado largo.';
-$messages['namereserved'] = 'Nombre reservado.';
-$messages['setexist'] = 'El conjunto ya existe.';
-$messages['nodata'] = '¡Al menos una posición debe ser seleccionada!';
-$messages['invaliddateformat'] = 'Fecha o formato de parte de la fecha no válido';
-$messages['saveerror'] = 'No fue posible guardar los datos. Ha ocurrido un error en el servidor.';
-$messages['vacationsaved'] = 'Datos de vacaciones guardados correctamente.';
-$messages['emptyvacationbody'] = '¡Hace falta un texto en el mensaje de vacaciones!';
-?>
diff --git a/lib/plugins/managesieve/localization/et_EE.inc b/lib/plugins/managesieve/localization/et_EE.inc
deleted file mode 100644
index 3957dcb..0000000
--- a/lib/plugins/managesieve/localization/et_EE.inc
+++ /dev/null
@@ -1,177 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtrid';
-$labels['managefilters'] = 'Halda sisenevate kirjade filtreid';
-$labels['filtername'] = 'Filtri nimi';
-$labels['newfilter'] = 'Uus filter';
-$labels['filteradd'] = 'Lisa filter';
-$labels['filterdel'] = 'Kustuta filter';
-$labels['moveup'] = 'Liiguta üles';
-$labels['movedown'] = 'Liiguta alla';
-$labels['filterallof'] = 'vastab kõikidele järgnevatele reeglitele';
-$labels['filteranyof'] = 'vastab mõnele järgnevatest reeglitest';
-$labels['filterany'] = 'kõik kirjad';
-$labels['filtercontains'] = 'sisaldab';
-$labels['filternotcontains'] = 'ei sisalda';
-$labels['filteris'] = 'on võrdne kui';
-$labels['filterisnot'] = 'ei ole võrdne kui';
-$labels['filterexists'] = 'on olemas';
-$labels['filternotexists'] = 'pole olemas';
-$labels['filtermatches'] = 'vastab avaldisele';
-$labels['filternotmatches'] = 'ei vasta avaldisele';
-$labels['filterregex'] = 'vastab regulaaravaldisele';
-$labels['filternotregex'] = 'ei vasta regulaaravaldisele';
-$labels['filterunder'] = 'alt';
-$labels['filterover'] = 'üle';
-$labels['addrule'] = 'Lisa reegel';
-$labels['delrule'] = 'Kustuta reegel';
-$labels['messagemoveto'] = 'Liiguta kiri';
-$labels['messageredirect'] = 'Suuna kiri ümber';
-$labels['messagecopyto'] = 'Kopeeri kiri';
-$labels['messagesendcopy'] = 'Saada kirja koopia';
-$labels['messagereply'] = 'Vasta kirjaga';
-$labels['messagedelete'] = 'Kustuta kiri';
-$labels['messagediscard'] = 'Viska ära teatega';
-$labels['messagesrules'] = 'Siseneva kirja puhul, mis:';
-$labels['messagesactions'] = '...käivita järgnevad tegevused:';
-$labels['add'] = 'Lisa';
-$labels['del'] = 'Kustuta';
-$labels['sender'] = 'Saatja';
-$labels['recipient'] = 'Saaja';
-$labels['vacationdays'] = 'Kui tihti kirju saata (päevades):';
-$labels['vacationinterval'] = 'Kui tihti kirju saata:';
-$labels['vacationreason'] = 'Kirja sisu (puhkuse põhjus):';
-$labels['vacationsubject'] = 'Kirja teema:';
-$labels['days'] = 'päeva';
-$labels['seconds'] = 'sekundit';
-$labels['rulestop'] = 'Peata reeglite otsimine';
-$labels['enable'] = 'Luba/keela';
-$labels['filterset'] = 'Filtrite kogum';
-$labels['filtersets'] = 'Filtri kogum';
-$labels['filtersetadd'] = 'Lisa filtrite kogum';
-$labels['filtersetdel'] = 'Kustuta praegune filtrite kogum';
-$labels['filtersetact'] = 'Aktiveeri praegune filtrite kogum';
-$labels['filtersetdeact'] = 'De-aktiveeri praegune filtrite kogum';
-$labels['filterdef'] = 'Filtri definitsioon';
-$labels['filtersetname'] = 'Filtrite kogumi nimi';
-$labels['newfilterset'] = 'Uus filtrite kogum';
-$labels['active'] = 'aktiivne';
-$labels['none'] = 'puudub';
-$labels['fromset'] = 'kogumist';
-$labels['fromfile'] = 'failist';
-$labels['filterdisabled'] = 'Filter keelatud';
-$labels['countisgreaterthan'] = 'koguarv on suurem kui';
-$labels['countisgreaterthanequal'] = 'koguarv on suurem kui või võrdne';
-$labels['countislessthan'] = 'koguarv on väiksem';
-$labels['countislessthanequal'] = 'koguarv on väiksem kui või võrdne';
-$labels['countequals'] = 'koguarv on võrdne';
-$labels['countnotequals'] = 'summa ei ole võrdne';
-$labels['valueisgreaterthan'] = 'väärtus on suurem kui';
-$labels['valueisgreaterthanequal'] = 'väärtus on suurem kui või võrdne';
-$labels['valueislessthan'] = 'väärtus on väiksem kui';
-$labels['valueislessthanequal'] = 'väärtus on väiksem kui või võrdne';
-$labels['valueequals'] = 'väärtus on võrdne';
-$labels['valuenotequals'] = 'väärtus ei ole võrdne';
-$labels['setflags'] = 'Sea kirjale lipik';
-$labels['addflags'] = 'Lisa kirjale lipikuid';
-$labels['removeflags'] = 'Eemalda kirjalt lipikud';
-$labels['flagread'] = 'Loetud';
-$labels['flagdeleted'] = 'Kustutatud';
-$labels['flaganswered'] = 'Vastatud';
-$labels['flagflagged'] = 'Märgistatud';
-$labels['flagdraft'] = 'Mustand';
-$labels['setvariable'] = 'Määra muutuja';
-$labels['setvarname'] = 'Muutuja nimi:';
-$labels['setvarvalue'] = 'Muutuja väärtus:';
-$labels['setvarmodifiers'] = 'Muutjad:';
-$labels['varlower'] = 'väiketähed';
-$labels['varupper'] = 'suurtähed';
-$labels['varlowerfirst'] = 'esimene märk on väiketäht';
-$labels['varupperfirst'] = 'esimene märk on suurtäht';
-$labels['varquotewildcard'] = 'tsiteeri erimärke';
-$labels['varlength'] = 'pikkus';
-$labels['notify'] = 'Saada teavitus';
-$labels['notifyimportance'] = 'Tähtsus:';
-$labels['notifyimportancelow'] = 'madal';
-$labels['notifyimportancenormal'] = 'tavaline';
-$labels['notifyimportancehigh'] = 'kõrge';
-$labels['filtercreate'] = 'Loo filter';
-$labels['usedata'] = 'Kasuta filtris järgmisi andmeid:';
-$labels['nextstep'] = 'Järgmine samm';
-$labels['...'] = '…';
-$labels['currdate'] = 'Praegune kuupäev';
-$labels['datetest'] = 'Kuupäev';
-$labels['dateheader'] = 'päis:';
-$labels['year'] = 'aasta';
-$labels['month'] = 'kuu';
-$labels['day'] = 'päev';
-$labels['date'] = 'kuupäev (aaaa-kk-pp)';
-$labels['julian'] = 'kuupäev (Juliuse)';
-$labels['hour'] = 'tund';
-$labels['minute'] = 'minut';
-$labels['second'] = 'sekund';
-$labels['time'] = 'aeg (tt:mm:ss)';
-$labels['iso8601'] = 'kuupäev (ISO8601)';
-$labels['std11'] = 'kuupäev (RCF2822)';
-$labels['zone'] = 'ajatsoon';
-$labels['weekday'] = 'nädalapäev (0-6)';
-$labels['advancedopts'] = 'Lisaseadistused';
-$labels['body'] = 'Põhitekst';
-$labels['address'] = 'aadress';
-$labels['envelope'] = 'ümbrik';
-$labels['modifier'] = 'muutja:';
-$labels['text'] = 'tekst';
-$labels['undecoded'] = 'kodeerimata (toor)';
-$labels['contenttype'] = 'sisu tüüp';
-$labels['modtype'] = 'tüüp:';
-$labels['allparts'] = 'kõik';
-$labels['domain'] = 'domeen';
-$labels['localpart'] = 'kohalik osa';
-$labels['user'] = 'kasutaja';
-$labels['detail'] = 'detail';
-$labels['comparator'] = 'võrdleja:';
-$labels['default'] = 'vaikimisi';
-$labels['octet'] = 'range (octet)';
-$labels['asciicasemap'] = 'tõstutundetu (ascii-casemap)';
-$labels['asciinumeric'] = 'numbriline (ascii-numeric)';
-$labels['index'] = 'indeks:';
-$labels['indexlast'] = 'tagasisuunas';
-$messages['filterunknownerror'] = 'Tundmatu serveri tõrge';
-$messages['filterconnerror'] = 'Managesieve serveriga ühendumine nurjus';
-$messages['filterdeleted'] = 'Filter edukalt kustutatud';
-$messages['filtersaved'] = 'Filter edukalt salvestatud';
-$messages['filterdeleteconfirm'] = 'Soovid valitud filtri kustutada?';
-$messages['ruledeleteconfirm'] = 'Soovid valitud reegli kustutada?';
-$messages['actiondeleteconfirm'] = 'Soovid valitud tegevuse kustutada?';
-$messages['forbiddenchars'] = 'Väljal on lubamatu märk';
-$messages['cannotbeempty'] = 'Väli ei või tühi olla';
-$messages['ruleexist'] = 'Määratud nimega filter on juba olemas';
-$messages['setactivated'] = 'Filtrite kogumi aktiveerimine õnnestus.';
-$messages['setdeactivated'] = 'Filtrite kogumi deaktiveerimine õnnestus.';
-$messages['setdeleted'] = 'Filtrite kogumi kustutamine õnnestus.';
-$messages['setdeleteconfirm'] = 'Oled kindel, et soovid valitud filtrite kogumi kustutada?';
-$messages['setcreated'] = 'Filtrite kogumi loomine õnnestus.';
-$messages['deactivated'] = 'Filter edukalt lubatud.';
-$messages['activated'] = 'Filter edukalt keelatud.';
-$messages['moved'] = 'Filter edukalt liigutatud.';
-$messages['nametoolong'] = 'Nimi on liiga pikk.';
-$messages['namereserved'] = 'Nimi on reserveeritud.';
-$messages['setexist'] = 'Kogum on juba olemas.';
-$messages['nodata'] = 'Valitud peab olema vähemalt üks asukoht!';
-$messages['invaliddateformat'] = 'Vigane kuupäev või kuupäeva formaat';
-?>
diff --git a/lib/plugins/managesieve/localization/eu_ES.inc b/lib/plugins/managesieve/localization/eu_ES.inc
deleted file mode 100644
index c9a39dc..0000000
--- a/lib/plugins/managesieve/localization/eu_ES.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Iragazkiak';
-$labels['managefilters'] = 'Kudeatu sarrerako posta-iragazkiak';
-$labels['filtername'] = 'Iragazkiaren izena';
-$labels['newfilter'] = 'Iragazki berria';
-$labels['filteradd'] = 'Gehitu iragazkia';
-$labels['filterdel'] = 'Ezabatu iragazkia';
-$labels['moveup'] = 'Mugitu gora';
-$labels['movedown'] = 'Mugitu behera';
-$labels['filterallof'] = 'datozen arau guztiak parekatzen';
-$labels['filteranyof'] = 'datozen arauetako batzuk parekatzen';
-$labels['filterany'] = 'mezu guztiak';
-$labels['filtercontains'] = 'badu';
-$labels['filternotcontains'] = 'ez du';
-$labels['filteris'] = 'honen berdina da';
-$labels['filterisnot'] = 'ez da honen berdina';
-$labels['filterexists'] = 'badago';
-$labels['filternotexists'] = 'ez dago';
-$labels['filtermatches'] = 'bat datorren espresioa';
-$labels['filternotmatches'] = 'bat ez datorren espresioa';
-$labels['filterregex'] = 'bat datozen adierazpen erregularra';
-$labels['filternotregex'] = 'bat ez datorren espresio erregularra';
-$labels['filterunder'] = 'azpian';
-$labels['filterover'] = 'gainean';
-$labels['addrule'] = 'Gehitu araua';
-$labels['delrule'] = 'Ezabatu araua';
-$labels['messagemoveto'] = 'Mugitu mezua hona';
-$labels['messageredirect'] = 'Birbideratu mezua hona ';
-$labels['messagecopyto'] = 'Kopiatu mezua hona';
-$labels['messagesendcopy'] = 'Bidali mezuaren kopia hona';
-$labels['messagereply'] = 'Erantzun mezuarekin';
-$labels['messagedelete'] = 'Ezabatu mezua';
-$labels['messagediscard'] = 'Baztertu mezuarekin';
-$labels['messagekeep'] = 'Mantendu mezua Sarrera-ontzian';
-$labels['messagesrules'] = 'Sarrerako postarako:';
-$labels['messagesactions'] = '...exekutatu datozen ekintzak:';
-$labels['add'] = 'Gehitu';
-$labels['del'] = 'Ezabatu';
-$labels['sender'] = 'Bidaltzailea';
-$labels['recipient'] = 'Hartzailea';
-$labels['vacationaddr'] = 'Nire helbide elektroniko osagarria(k):';
-$labels['vacationdays'] = 'Zenbatero bidali mezuak (egunak)';
-$labels['vacationinterval'] = 'Zenbatero bidali mezuak:';
-$labels['vacationreason'] = 'Mezuaren gorputza (oporrak direla medio):';
-$labels['vacationsubject'] = 'Mezuaren gaia:';
-$labels['days'] = 'egun';
-$labels['seconds'] = 'segundo';
-$labels['rulestop'] = 'Gelditu arauak ebaluatzen';
-$labels['enable'] = 'Gaitu/Ezgaitu';
-$labels['filterset'] = 'Iragazki-paketea';
-$labels['filtersets'] = 'Iragazki-paketeak';
-$labels['filtersetadd'] = 'Gehitu iragazki-paketea';
-$labels['filtersetdel'] = 'Ezabatu uneko iragazki-paketea';
-$labels['filtersetact'] = 'Gaitu uneko iragazki-paketea';
-$labels['filtersetdeact'] = 'Ezgaitu uneko iragazki-paketea';
-$labels['filterdef'] = 'Iragazkiaren definizioa';
-$labels['filtersetname'] = 'Iragazki-paketearen izena';
-$labels['newfilterset'] = 'Iragazki-pakete berria';
-$labels['active'] = 'aktiboa';
-$labels['none'] = 'Bat ere ez';
-$labels['fromset'] = 'paketetik';
-$labels['fromfile'] = 'fitxategitik';
-$labels['filterdisabled'] = 'Iragazki ezgaitua';
-$labels['countisgreaterthan'] = 'kopurua handiagoa da hau baino';
-$labels['countisgreaterthanequal'] = 'kopurua hau baino handiagoa edo berdina da';
-$labels['countislessthan'] = 'kopurua hau baino txikiagoa da';
-$labels['countislessthanequal'] = 'kopurua hau baino txikiagoa edo berdina da';
-$labels['countequals'] = 'kopurua honen berdina da';
-$labels['countnotequals'] = 'kopurua ez da honen berdina';
-$labels['valueisgreaterthan'] = 'balioa hau baino handiagoa da';
-$labels['valueisgreaterthanequal'] = 'balioa hau baino handiagoa edo berdina da';
-$labels['valueislessthan'] = 'balioa hau baino txikiagoa da';
-$labels['valueislessthanequal'] = 'balioa hau baino txikiagoa edo berdina da';
-$labels['valueequals'] = 'balioa honen berdina da';
-$labels['valuenotequals'] = 'balioa ez da honen berdina';
-$labels['setflags'] = 'Jarri banderak mezuarik';
-$labels['addflags'] = 'Gehitu banderak mezuari';
-$labels['removeflags'] = 'Ezabatu banderak mezutik';
-$labels['flagread'] = 'Irakurri';
-$labels['flagdeleted'] = 'Ezabatuta';
-$labels['flaganswered'] = 'Erantzunda';
-$labels['flagflagged'] = 'Bandera jarrita';
-$labels['flagdraft'] = 'Ziriborroa';
-$labels['setvariable'] = 'Ezarri aldagaia';
-$labels['setvarname'] = 'Aldagaiaren izena:';
-$labels['setvarvalue'] = 'Aldagaiaren balioa:';
-$labels['setvarmodifiers'] = 'Modifikatzaileak:';
-$labels['varlower'] = 'minuskulan';
-$labels['varupper'] = 'maiuskulan';
-$labels['varlowerfirst'] = 'lehenengo karakterea minuskulan';
-$labels['varupperfirst'] = 'lehenengo karakterea maiuskulan';
-$labels['varquotewildcard'] = 'aipatu karaktere bereziak';
-$labels['varlength'] = 'luzera';
-$labels['notify'] = 'Bidali jakinarazpena';
-$labels['notifytarget'] = 'Jakinarazpenaren xedea:';
-$labels['notifymessage'] = 'Jakinarazpenaren mezua (aukerakoa):';
-$labels['notifyoptions'] = 'Jakinarazpenaren aukerak (aukerakoa):';
-$labels['notifyfrom'] = 'Jakinarazpenaren bidaltzailea (aukerakoa):';
-$labels['notifyimportance'] = 'Garrantzia:';
-$labels['notifyimportancelow'] = 'baxua';
-$labels['notifyimportancenormal'] = 'normala';
-$labels['notifyimportancehigh'] = 'altua';
-$labels['notifymethodmailto'] = 'Helbide elektronikoa';
-$labels['notifymethodtel'] = 'Telefonoa';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Sortu iragazkia';
-$labels['usedata'] = 'Erabili datorren data iragazkian:';
-$labels['nextstep'] = 'Hurrengo urratsa';
-$labels['...'] = '...';
-$labels['currdate'] = 'Uneko data';
-$labels['datetest'] = 'Data';
-$labels['dateheader'] = 'goiburua:';
-$labels['year'] = 'urte';
-$labels['month'] = 'hilabete';
-$labels['day'] = 'egun';
-$labels['date'] = 'data (yyyy-mm-dd)';
-$labels['julian'] = 'data (juliarra)';
-$labels['hour'] = 'ordu';
-$labels['minute'] = 'minutu';
-$labels['second'] = 'segundo';
-$labels['time'] = 'ordua (hh:mm:ss)';
-$labels['iso8601'] = 'data (ISO8601)';
-$labels['std11'] = 'data (RFC2822)';
-$labels['zone'] = 'ordu-zona';
-$labels['weekday'] = 'asteguna (0-6)';
-$labels['advancedopts'] = 'Aukera aurreratuak';
-$labels['body'] = 'Gorputza';
-$labels['address'] = 'helbidea';
-$labels['envelope'] = 'gutun-azala';
-$labels['modifier'] = 'modifikatzailea:';
-$labels['text'] = 'testua';
-$labels['undecoded'] = 'kodetu gabe (gordina)';
-$labels['contenttype'] = 'eduki mota';
-$labels['modtype'] = 'mota:';
-$labels['allparts'] = 'denak';
-$labels['domain'] = 'domeinua';
-$labels['localpart'] = 'zati lokala';
-$labels['user'] = 'erabiltzailea';
-$labels['detail'] = 'xehetasuna';
-$labels['comparator'] = 'alderatzailea:';
-$labels['default'] = 'lehenetsia';
-$labels['octet'] = 'zorrotza (zortzikotea)';
-$labels['asciicasemap'] = 'minuskulak eta maiuskulak (ascii-casemap)';
-$labels['asciinumeric'] = 'numerikoa (ascii-numeric)';
-$labels['index'] = 'indexatu:';
-$labels['indexlast'] = 'atzeraka';
-$labels['vacation'] = 'Oporraldia';
-$labels['vacation.reply'] = 'Erantzun mezua';
-$labels['vacation.advanced'] = 'Ezarpen aurreratuak';
-$labels['vacation.subject'] = 'Gaia';
-$labels['vacation.body'] = 'Gorputza';
-$labels['vacation.start'] = 'Oporraldiaren hasiera';
-$labels['vacation.end'] = 'Oporraldiaren bukaera';
-$labels['vacation.status'] = 'Egoera';
-$labels['vacation.on'] = 'Piztuta';
-$labels['vacation.off'] = 'Itzalita';
-$labels['vacation.addresses'] = 'Nire helbide osagarriak';
-$labels['vacation.interval'] = 'Erantzun tartea';
-$labels['vacation.after'] = 'Jarri oporren erregela honen ondoren';
-$labels['vacation.saving'] = 'Datuak gordetzen...';
-$labels['vacation.action'] = 'Sarrerako mezuaren ekintza';
-$labels['vacation.keep'] = 'Mantendu';
-$labels['vacation.discard'] = 'Baztertu';
-$labels['vacation.redirect'] = 'Birbideratu hona';
-$labels['vacation.copy'] = 'Bidali kopia hona';
-$labels['arialabelfiltersetactions'] = 'Iragazki-paketearen ekintzak';
-$labels['arialabelfilteractions'] = 'Iragazki-ekintzak';
-$labels['arialabelfilterform'] = 'Iragazkiaren ezaugarriak';
-$labels['ariasummaryfilterslist'] = 'Iragazkien zerrenda';
-$labels['ariasummaryfiltersetslist'] = 'Iragazki-paketeen zerrenda';
-$labels['filterstitle'] = 'Editatu postaren sarrera-iragazkiak';
-$labels['vacationtitle'] = 'Bulegotik-kanpo -erantzun automatiko- araua';
-$messages['filterunknownerror'] = 'Zerbitzari ezezaguna errorea';
-$messages['filterconnerror'] = 'Ezin da konektatu zerbitzariarekin.';
-$messages['filterdeleteerror'] = 'Ezin da ezabatu iragazkia. Errore bat gertatu da zerbitzarian.';
-$messages['filterdeleted'] = 'Iragazkia ongi ezabatu da.';
-$messages['filtersaved'] = 'Iragazkia ongi ezabatu da.';
-$messages['filtersaveerror'] = 'Ezin da gorde iragazkia. Zerbitzarian errore bat gertatu da.';
-$messages['filterdeleteconfirm'] = 'Seguru zaude hautatutako iragazkiak ezabatu nahi dituzula?';
-$messages['ruledeleteconfirm'] = 'Seguru zaude hautatutako arauak ezabatu nahi dituzula?';
-$messages['actiondeleteconfirm'] = 'Seguru zaude hautatutako ekintzak ezabatu nahi dituzula?';
-$messages['forbiddenchars'] = 'Debekatutako karaktereak eremuan.';
-$messages['cannotbeempty'] = 'Eremua ezin da hutsik egon.';
-$messages['ruleexist'] = 'Lehendik badago izen hori duen iragazki bat.';
-$messages['setactivateerror'] = 'Ezin da aktibatu hautatutako iragazki paketea. Zerbitzarian errore bat gertatu da.';
-$messages['setdeactivateerror'] = 'Ezin da ezgaitu hautatutako iragazki-paketea. Zerbitzarian errore bat gertatu da.';
-$messages['setdeleteerror'] = 'Ezin da ezabatu hautatutako iragazki-paketea. Zerbitzarian errore bat gertatu da.';
-$messages['setactivated'] = 'Iragazki paketea ongi aktibatu da.';
-$messages['setdeactivated'] = 'Iragazki paketea ongi desaktibatu da.';
-$messages['setdeleted'] = 'Iragazki paketea ongi ezabatu da.';
-$messages['setdeleteconfirm'] = 'Seguru zaude hautatutako iragazki paketea ezabatu nahi duzula?';
-$messages['setcreateerror'] = 'Ezin da iragazki-paketea sortu. Zerbitzarian errore bat gertatu da.';
-$messages['setcreated'] = 'Iragazki paketea ongi sortu da.';
-$messages['activateerror'] = 'Ezin da gaitu hautatutako iragazkia(k). Zerbitzarian errore bat gertatu da.';
-$messages['deactivateerror'] = 'Ezin da ezgaitu hautatutako iragazkia(k). Zerbitzarian errore bat gertatu da.';
-$messages['deactivated'] = 'Iragazkia(k) ongi ezgaitu da.';
-$messages['activated'] = 'Iragazkia(k) ongi gaitu da.';
-$messages['moved'] = 'Iragazkia ongi mugitu da.';
-$messages['moveerror'] = 'Ezin da mugitu hautatutako iragazkia. Zerbitzarian errore bat gertatu da.';
-$messages['nametoolong'] = 'Izen luzeegia.';
-$messages['namereserved'] = 'Izen erreserbatua.';
-$messages['setexist'] = 'Lehendik badago pakete hori.';
-$messages['nodata'] = 'Gutxienez posizio bat hautatu behar da!';
-$messages['invaliddateformat'] = 'Dataren edo dataren zati baten formatua ez da baliozkoa ';
-$messages['saveerror'] = 'Ezin dira datuak gorde. Errorea gertatu da zerbitzarian.';
-$messages['vacationsaved'] = 'Oporren data ongi gorde da.';
-$messages['emptyvacationbody'] = 'Beharrezkoa da oporraldiko mezua jartzea!';
-?>
diff --git a/lib/plugins/managesieve/localization/fa_IR.inc b/lib/plugins/managesieve/localization/fa_IR.inc
deleted file mode 100644
index 65f2d0d..0000000
--- a/lib/plugins/managesieve/localization/fa_IR.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'پالایه‌ها';
-$labels['managefilters'] = 'مدیریت پالایه‌های نامه ورودی';
-$labels['filtername'] = 'نام پالایه';
-$labels['newfilter'] = 'پالایه جدید';
-$labels['filteradd'] = 'افزودن پالایه';
-$labels['filterdel'] = 'حذف پالایه';
-$labels['moveup'] = 'انتقال به بالا';
-$labels['movedown'] = 'انتقال به پایین';
-$labels['filterallof'] = 'مطابقت همه قوانین ذیل';
-$labels['filteranyof'] = 'مطابقت هر کدام از قوانین ذیل';
-$labels['filterany'] = 'همه پیغام ها';
-$labels['filtercontains'] = 'دربرگیرنده';
-$labels['filternotcontains'] = 'بدون';
-$labels['filteris'] = 'برابر است با';
-$labels['filterisnot'] = 'برابر نیست با';
-$labels['filterexists'] = 'وجود دارد';
-$labels['filternotexists'] = 'وجود ندارد';
-$labels['filtermatches'] = 'با عبارت تطابق دارد';
-$labels['filternotmatches'] = 'با عبارت تطابق ندارد';
-$labels['filterregex'] = 'با عبارت عمومی تطابق دارد';
-$labels['filternotregex'] = 'با عبارت عمومی تطابق ندارد';
-$labels['filterunder'] = 'زیر';
-$labels['filterover'] = 'بالا';
-$labels['addrule'] = 'افزودن قانون';
-$labels['delrule'] = 'حذف قانون';
-$labels['messagemoveto'] = 'انتقال پیغام به';
-$labels['messageredirect'] = 'بازگردانی پیغام به';
-$labels['messagecopyto'] = 'رونوشت پیغام به';
-$labels['messagesendcopy'] = 'ارسال رونوشت پیغام به';
-$labels['messagereply'] = 'پاسخ همراه پیغام';
-$labels['messagedelete'] = 'حذف پیغام';
-$labels['messagediscard'] = 'دور ریختن با پیغام';
-$labels['messagekeep'] = 'پیغام را در صندوق ورودی نگه دار';
-$labels['messagesrules'] = 'برای صندوق ورودی:';
-$labels['messagesactions'] = '...انجام اعمال ذیل:';
-$labels['add'] = 'افزودن';
-$labels['del'] = 'حذف';
-$labels['sender'] = 'فرستنده';
-$labels['recipient'] = 'گیرنده';
-$labels['vacationaddr'] = 'نشانی(های) رایانامه دیگر من:';
-$labels['vacationdays'] = 'پیغام ها در چه مواقعی فرستاده شدند (در روزهای):';
-$labels['vacationinterval'] = 'مواقعی که پیغام‌ها ارسال می‌شوند:';
-$labels['vacationreason'] = 'بدنه پیغام (علت مسافرت):';
-$labels['vacationsubject'] = 'موضوع پیغام:';
-$labels['days'] = 'روزها';
-$labels['seconds'] = 'ثانیه‌ها';
-$labels['rulestop'] = 'توقف قوانین ارزیابی';
-$labels['enable'] = 'فعال/غیرفعال‌سازی';
-$labels['filterset'] = 'مجموعه پالایه‌ها';
-$labels['filtersets'] = 'مجموعه‌های پالایه‌ها';
-$labels['filtersetadd'] = 'افزودن مجموعه پالایه‌ها';
-$labels['filtersetdel'] = 'حذف مجموعه پالایه‌های جاری';
-$labels['filtersetact'] = 'فعال کردن مجموعه پالایه‌های جاری';
-$labels['filtersetdeact'] = 'غیرفعال کردن مجموعه پالایه‌های جاری';
-$labels['filterdef'] = 'تعریف پالایه';
-$labels['filtersetname'] = 'نام مجموعه پالایه‌ها';
-$labels['newfilterset'] = 'مجموعه پالایه‌های جدید';
-$labels['active'] = 'فعال';
-$labels['none'] = 'هیچ‌کدام';
-$labels['fromset'] = 'از مجموعه';
-$labels['fromfile'] = 'از پرونده';
-$labels['filterdisabled'] = 'پالایه غیرفعال شد';
-$labels['countisgreaterthan'] = 'تعداد بیشتر است از';
-$labels['countisgreaterthanequal'] = 'تعداد بیشتر یا مساوی است با';
-$labels['countislessthan'] = 'تعداد کمتر است از';
-$labels['countislessthanequal'] = 'تعداد کمتر یا مساوی است با';
-$labels['countequals'] = 'تعداد مساوی است با';
-$labels['countnotequals'] = 'تعداد برابر نیست با';
-$labels['valueisgreaterthan'] = 'مقدار بیشتر است از';
-$labels['valueisgreaterthanequal'] = 'مقدار بیشتر یا مساوی است با';
-$labels['valueislessthan'] = 'مقدار کمتر است از';
-$labels['valueislessthanequal'] = 'مقدار کمتر یا مساوی است با';
-$labels['valueequals'] = 'مقدار مساوی است با';
-$labels['valuenotequals'] = 'مقدار برابر نیست با';
-$labels['setflags'] = 'انتخاب پرچم‌ها برای پیغام';
-$labels['addflags'] = 'افزودن پرچم‌ها برای پیغام';
-$labels['removeflags'] = 'حذف پرچم‌ها از پیغام';
-$labels['flagread'] = 'خوانده‌‌شده';
-$labels['flagdeleted'] = 'حذف شده';
-$labels['flaganswered'] = 'جواب داده شده';
-$labels['flagflagged'] = 'پرچم‌دار';
-$labels['flagdraft'] = 'پیش‌نویس';
-$labels['setvariable'] = 'تنظیم متغیر';
-$labels['setvarname'] = 'نام متغییر';
-$labels['setvarvalue'] = 'مقدار متغیر:';
-$labels['setvarmodifiers'] = 'اصلاح:';
-$labels['varlower'] = 'حروف کوچک';
-$labels['varupper'] = 'حروف بزرگ';
-$labels['varlowerfirst'] = 'حرف اول کوچک';
-$labels['varupperfirst'] = 'حرف اول بزرگ';
-$labels['varquotewildcard'] = 'نقل قول کاراکترهای خاص';
-$labels['varlength'] = 'طول';
-$labels['notify'] = 'ارسال تذکر';
-$labels['notifytarget'] = 'مقصد آگاه‌سازی:';
-$labels['notifymessage'] = 'متن آگاه‌سازی (تختیاری):';
-$labels['notifyoptions'] = 'گزینه‌های آگاه‌سازی (اختیاری):';
-$labels['notifyfrom'] = 'فرستنده آگاه‌سازی (اختیاری):';
-$labels['notifyimportance'] = 'اهمیت:';
-$labels['notifyimportancelow'] = 'کم';
-$labels['notifyimportancenormal'] = 'معمولی';
-$labels['notifyimportancehigh'] = 'زیاد';
-$labels['notifymethodmailto'] = 'رایانامه';
-$labels['notifymethodtel'] = 'تلفن';
-$labels['notifymethodsms'] = 'پیامک';
-$labels['filtercreate'] = 'ایجاد پالایه';
-$labels['usedata'] = 'استفاده از داده ذیل در پالایه:';
-$labels['nextstep'] = 'مرحله بعدی';
-$labels['...'] = '...';
-$labels['currdate'] = 'تاریخ جاری';
-$labels['datetest'] = 'تاریخ';
-$labels['dateheader'] = 'سربرگ:';
-$labels['year'] = 'سال';
-$labels['month'] = 'ماه';
-$labels['day'] = 'روز';
-$labels['date'] = 'تاریخ (yyyy-mm-dd)';
-$labels['julian'] = 'تاریخ (میلادی)';
-$labels['hour'] = 'ساعت';
-$labels['minute'] = 'دقیقه';
-$labels['second'] = 'ثانیه';
-$labels['time'] = 'ساعت (hh:mm:ss)';
-$labels['iso8601'] = 'تاریخ (ISO8601)';
-$labels['std11'] = 'تاریخ (RFC2822)';
-$labels['zone'] = 'منطقه زمانی';
-$labels['weekday'] = 'روز هفته (0-6)';
-$labels['advancedopts'] = 'گزینه‌های پیشرفته';
-$labels['body'] = 'بدنه';
-$labels['address'] = 'نشانی';
-$labels['envelope'] = 'پاکت';
-$labels['modifier'] = 'تغییر دهنده:';
-$labels['text'] = 'متن‌';
-$labels['undecoded'] = 'کد نشده (خام)';
-$labels['contenttype'] = 'نوع محتوا';
-$labels['modtype'] = 'نوع';
-$labels['allparts'] = 'همه';
-$labels['domain'] = 'دامنه';
-$labels['localpart'] = 'قسمت محلی';
-$labels['user'] = 'کاربر';
-$labels['detail'] = 'جزئیات';
-$labels['comparator'] = 'مقایسه:';
-$labels['default'] = 'پیش‌فرض';
-$labels['octet'] = 'سخت (octet)';
-$labels['asciicasemap'] = 'حساس به حروه کوچک و بزرگ (ascii-casemap)';
-$labels['asciinumeric'] = 'عددی (ascii-numeric)';
-$labels['index'] = 'فهرست:';
-$labels['indexlast'] = 'به عقب';
-$labels['vacation'] = 'مسافرت';
-$labels['vacation.reply'] = 'پاسخ به یغام';
-$labels['vacation.advanced'] = 'تنظیمات پیشرفته';
-$labels['vacation.subject'] = 'موضوع';
-$labels['vacation.body'] = 'بدنه';
-$labels['vacation.start'] = 'شروع تعطیلی';
-$labels['vacation.end'] = 'پایان تعطیلی';
-$labels['vacation.status'] = 'وضعیت';
-$labels['vacation.on'] = 'روشن';
-$labels['vacation.off'] = 'خاموش';
-$labels['vacation.addresses'] = 'نشانی‌های دیگر من';
-$labels['vacation.interval'] = 'فاصله پاسخ';
-$labels['vacation.after'] = 'قرار دادن قانون مسافرت بعد از';
-$labels['vacation.saving'] = 'ذخیره داده‌ها...';
-$labels['vacation.action'] = 'کنش عملکرد ورودی';
-$labels['vacation.keep'] = 'نگه داشتن';
-$labels['vacation.discard'] = 'دور انداختن';
-$labels['vacation.redirect'] = 'بازگردانی به';
-$labels['vacation.copy'] = 'ارسال رونوشت به';
-$labels['arialabelfiltersetactions'] = 'کنش‌های مجموعه پالایه';
-$labels['arialabelfilteractions'] = 'کنش‌های پالایه';
-$labels['arialabelfilterform'] = 'خصوصیات پالایه';
-$labels['ariasummaryfilterslist'] = 'فهرست پالایه‌ها';
-$labels['ariasummaryfiltersetslist'] = 'فهرست مجموعه پالایه‌ها';
-$labels['filterstitle'] = 'ویرایش پالایه‌های پست ورودی';
-$labels['vacationtitle'] = 'ویرایش نقش بیرون از دفتر';
-$messages['filterunknownerror'] = 'خطای سرور نامعلوم.';
-$messages['filterconnerror'] = 'ناتوانی در اتصال به سرور.';
-$messages['filterdeleteerror'] = 'ناتوانی در حذف پالایه. خطای سرور رخ داد.';
-$messages['filterdeleted'] = 'پالایه با کام‌یابی حذف شد.';
-$messages['filtersaved'] = 'پالایه با کام‌یابی ذخیره شد.';
-$messages['filtersaveerror'] = 'ناتوانی در ذخیره فیلتر. خطای سرور رخ داد.';
-$messages['filterdeleteconfirm'] = 'آیا مطمئن به حذف پالایه انتخاب شده هستید؟';
-$messages['ruledeleteconfirm'] = 'آیا مطمئن هستید که می خواهید قانون انتخاب شده را حذف کنید؟';
-$messages['actiondeleteconfirm'] = 'آیا مطمئن هستید که می خواهید عمل انتخاب شده را حذف کنید.';
-$messages['forbiddenchars'] = 'حروف ممنوعه در فیلد.';
-$messages['cannotbeempty'] = 'فیلد نمی تواند خالی باشد.';
-$messages['ruleexist'] = 'پالایه با این نام مشخص وجود دارد.';
-$messages['setactivateerror'] = 'ناتوان در فعال کردن مجموعه پالایه‌ها انتخاب شده. خطای سرور رخ داد.';
-$messages['setdeactivateerror'] = 'ناتوان در غیرفعال کردن مجموعه پالایه‌ها انتخاب شده. خطای سرور رخ داد.';
-$messages['setdeleteerror'] = 'ناتوان در حذف مجموعه پالایه‌ها انتخاب شده. خطای سرور رخ داد.';
-$messages['setactivated'] = 'مجموعه پالایه‌ها با کام‌یابی فعال شد.';
-$messages['setdeactivated'] = 'مجموعه پالایه‌ها با کام‌یابی غیرفعال شد.';
-$messages['setdeleted'] = 'مجموعه پالایه‌ها با کام‌یابی حذف شد.';
-$messages['setdeleteconfirm'] = 'آیا مطمئن هستید که می‌خواهید مجموعه پالایه‌ها انتخاب شده را حذف کنید؟';
-$messages['setcreateerror'] = 'ناتوانی در ایجاد مجموعه پالایه‌ها. خطای سرور رخ داد.';
-$messages['setcreated'] = 'مجموعه پالایه‌ها با کام‌یابی ایجاد شد.';
-$messages['activateerror'] = 'ناتوانی در فعال کردن پالایه(های) انتخاب شده. خطای سرور رخ داد.';
-$messages['deactivateerror'] = 'ناتوانی در غیرفعال کردن پالایه(های) انتخاب شده. خطای سرور رخ داد.';
-$messages['deactivated'] = 'پالایه(ها) با کام‌یابی فعال شدند.';
-$messages['activated'] = 'پالایه(ها) با کام‌یابی غیرفعال شدند.';
-$messages['moved'] = 'پالایه با کام‌یابی منتقل شد.';
-$messages['moveerror'] = 'ناتوانی در انتقال پالایه انتخاب شده. خطای سرور رخ داد.';
-$messages['nametoolong'] = 'نام خیلی بلند.';
-$messages['namereserved'] = 'نام رزرو شده.';
-$messages['setexist'] = 'مجموعه در حال حاضر موجود است.';
-$messages['nodata'] = 'حداقل باید یک موقعیت باید انتخاب شود.';
-$messages['invaliddateformat'] = 'قالب تاریخ اشتباه';
-$messages['saveerror'] = 'ناتوانی در ذخیره اطلاعات. خطای سرور رخ داد.';
-$messages['vacationsaved'] = 'اطلاعات مسافرت با کام‌یابی ذخیره شد.';
-$messages['emptyvacationbody'] = 'متن پیغام تعطیلی لازم است!';
-?>
diff --git a/lib/plugins/managesieve/localization/fi_FI.inc b/lib/plugins/managesieve/localization/fi_FI.inc
deleted file mode 100644
index ba10b1f..0000000
--- a/lib/plugins/managesieve/localization/fi_FI.inc
+++ /dev/null
@@ -1,183 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Suodattimet';
-$labels['managefilters'] = 'Hallitse saapuvan sähköpostin suodattimia';
-$labels['filtername'] = 'Suodattimen nimi';
-$labels['newfilter'] = 'Uusi suodatin';
-$labels['filteradd'] = 'Lisää suodatin';
-$labels['filterdel'] = 'Poista suodatin';
-$labels['moveup'] = 'Siirrä ylös';
-$labels['movedown'] = 'Siirrä alas';
-$labels['filterallof'] = 'Täsmää kaikkiin seuraaviin sääntöihin';
-$labels['filteranyof'] = 'Täsmää mihin tahansa seuraavista säännöistä';
-$labels['filterany'] = 'Kaikki viestit';
-$labels['filtercontains'] = 'Sisältää';
-$labels['filternotcontains'] = 'Ei sisällä';
-$labels['filteris'] = 'on samanlainen kuin';
-$labels['filterisnot'] = 'ei ole samanlainen kuin';
-$labels['filterexists'] = 'on olemassa';
-$labels['filternotexists'] = 'ei ole olemassa';
-$labels['filtermatches'] = 'vastaa lauseketta';
-$labels['filternotmatches'] = 'ei vastaa lauseketta';
-$labels['filterregex'] = 'vastaa säännöllistä lauseketta';
-$labels['filternotregex'] = 'ei vastaa säännöllistä lauseketta';
-$labels['filterunder'] = 'alle';
-$labels['filterover'] = 'yli';
-$labels['addrule'] = 'Lisää sääntö';
-$labels['delrule'] = 'Poista sääntö';
-$labels['messagemoveto'] = 'Siirrä viesti';
-$labels['messageredirect'] = 'Lähetä viesti edelleen';
-$labels['messagecopyto'] = 'Kopioi viesti';
-$labels['messagesendcopy'] = 'Lähetä kopio viestistä';
-$labels['messagereply'] = 'Vastaa viestillä';
-$labels['messagedelete'] = 'Poista viesti';
-$labels['messagediscard'] = 'Hylkää viestillä';
-$labels['messagekeep'] = 'Säilytä viesti saapuneissa';
-$labels['messagesrules'] = 'Saapuville viesteille:';
-$labels['messagesactions'] = '...suorita seuraavat toiminnot:';
-$labels['add'] = 'Lisää';
-$labels['del'] = 'Poista';
-$labels['sender'] = 'Lähettäjä';
-$labels['recipient'] = 'Vastaanottaja';
-$labels['vacationaddr'] = 'Muut sähköpostiosoitteeni:';
-$labels['vacationreason'] = 'Viestin runko (loman syy):';
-$labels['vacationsubject'] = 'Viestin aihe:';
-$labels['days'] = 'päivää';
-$labels['seconds'] = 'sekuntia';
-$labels['rulestop'] = 'Lopeta sääntöjen arviointi';
-$labels['enable'] = 'Ota käyttöön/poista käytöstä';
-$labels['filterset'] = 'Suodattimien asetus';
-$labels['filtersets'] = 'Suodattimen asetus';
-$labels['filtersetadd'] = 'Lisää suodatinasetus';
-$labels['filtersetdel'] = 'Poista nykyiset suodatinasetukset';
-$labels['filtersetact'] = 'Aktivoi nykyinen suodattimien asetus';
-$labels['filtersetdeact'] = 'Poista käytöstä nykyinen suodattimien asetus';
-$labels['filterdef'] = 'Suodattimen määrittely';
-$labels['filtersetname'] = 'Suodattimien asetuksen nimi';
-$labels['active'] = 'aktiivinen';
-$labels['none'] = 'Ei mikään';
-$labels['fromset'] = 'sarjasta';
-$labels['fromfile'] = 'tiedostosta';
-$labels['filterdisabled'] = 'Suodatin poistettu käytöstä';
-$labels['countisgreaterthan'] = 'määrä on suurempi kuin';
-$labels['countisgreaterthanequal'] = 'määrä on suurempi tai yhtä suuri kuin';
-$labels['countislessthan'] = 'määrä on vähemmän kuin';
-$labels['countislessthanequal'] = 'määrä on vähemmän tai yhtä suuri kuin';
-$labels['countequals'] = 'määrä on yhtä suuri kuin';
-$labels['countnotequals'] = 'määrä ei ole yhtä suuri kuin';
-$labels['valueisgreaterthan'] = 'arvo on suurempi kuin';
-$labels['valueisgreaterthanequal'] = 'arvo on suurempi kuin tai yhtä suuri kuin';
-$labels['valueislessthan'] = 'arvo on vähemmän kuin';
-$labels['valueislessthanequal'] = 'määrä on vähemmän tai yhtä suuri kuin';
-$labels['valueequals'] = 'arvo on yhtä suuri kuin';
-$labels['valuenotequals'] = 'arvo ei ole yhtä suuri kuin';
-$labels['setflags'] = 'Aseta liput viestiin';
-$labels['addflags'] = 'Lisää liput viestiin';
-$labels['removeflags'] = 'Poista liput viestistä';
-$labels['flagread'] = 'Lue';
-$labels['flagdeleted'] = 'Poistettu';
-$labels['flaganswered'] = 'Vastattu';
-$labels['flagflagged'] = 'Liputettu';
-$labels['flagdraft'] = 'Luonnos';
-$labels['setvariable'] = 'Aseta muuttuja';
-$labels['setvarname'] = 'Muuttujan nimi:';
-$labels['setvarvalue'] = 'Muuttujan arvo:';
-$labels['setvarmodifiers'] = 'Muuntimet:';
-$labels['varlower'] = 'pienellä kirjoitettu';
-$labels['varupper'] = 'isolla kirjoitettu';
-$labels['varlowerfirst'] = 'ensimmäinen merkki pienellä kirjoitettuna';
-$labels['varupperfirst'] = 'ensimmäinen merkki isolla kirjoitettuna';
-$labels['varquotewildcard'] = 'lainaa erikoismerkit';
-$labels['varlength'] = 'pituus';
-$labels['notify'] = 'Lähetä ilmoitus';
-$labels['notifytarget'] = 'Ilmoituksen kohde:';
-$labels['notifymessage'] = 'Ilmoituksen viesti (valinnainen):';
-$labels['notifyoptions'] = 'Ilmoituksen valinnat (valinnainen)';
-$labels['notifyfrom'] = 'Ilmoituksen lähettäjä (valinnainen):';
-$labels['notifyimportance'] = 'Tärkeysaste:';
-$labels['notifyimportancelow'] = 'matala';
-$labels['notifyimportancenormal'] = 'normaali';
-$labels['notifyimportancehigh'] = 'korkea';
-$labels['notifymethodmailto'] = 'Sähköposti';
-$labels['notifymethodtel'] = 'Puhelin';
-$labels['notifymethodsms'] = 'Tekstiviesti';
-$labels['filtercreate'] = 'Luo suodatin';
-$labels['usedata'] = 'Käytä seuraavaa dataa suodattimessa:';
-$labels['nextstep'] = 'Seuraava vaihe';
-$labels['...'] = '...';
-$labels['currdate'] = 'Nykyinen päivämäärä';
-$labels['datetest'] = 'Päivämäärä';
-$labels['dateheader'] = 'otsikko:';
-$labels['year'] = 'vuosi';
-$labels['month'] = 'kuukausi';
-$labels['day'] = 'päivä';
-$labels['date'] = 'päivämäärä (vvvv-kk-pp)';
-$labels['julian'] = 'päivämäärä (juliaaninen)';
-$labels['hour'] = 'tunti';
-$labels['minute'] = 'minuutti';
-$labels['second'] = 'sekunti';
-$labels['time'] = 'aika (hh:mm:ss)';
-$labels['iso8601'] = 'päivämäärä (ISO8601)';
-$labels['std11'] = 'päivämäärä (RFC2882)';
-$labels['zone'] = 'aikavyöhyke';
-$labels['weekday'] = 'viikonpäivä (0-6)';
-$labels['advancedopts'] = 'Lisävalinnat';
-$labels['body'] = 'Runko';
-$labels['address'] = 'osoite';
-$labels['envelope'] = 'kirjekuori';
-$labels['modifier'] = 'muuntaja:';
-$labels['text'] = 'teksti';
-$labels['undecoded'] = 'dekoodaamaton (raaka)';
-$labels['contenttype'] = 'sisällön tyyppi';
-$labels['modtype'] = 'tyyppi:';
-$labels['allparts'] = 'kaikki';
-$labels['domain'] = 'domain';
-$labels['localpart'] = 'paikallinen osa';
-$labels['user'] = 'käyttäjä';
-$labels['detail'] = 'yksityiskohta';
-$labels['comparator'] = 'vertailija:';
-$labels['default'] = 'oletus';
-$labels['vacation'] = 'Loma';
-$labels['vacation.reply'] = 'Vastausviesti';
-$labels['vacation.advanced'] = 'Lisäasetukset';
-$labels['vacation.subject'] = 'Aihe';
-$labels['vacation.body'] = 'Sisältö';
-$labels['vacation.status'] = 'Tila';
-$labels['vacation.on'] = 'Päällä';
-$labels['vacation.off'] = 'Pois';
-$labels['vacation.saving'] = 'Tallennetaan tietoja...';
-$labels['vacation.action'] = 'Toiminto saapuvalle viestille';
-$labels['vacation.keep'] = 'Säilytä';
-$labels['vacation.discard'] = 'Hylkää';
-$labels['vacation.redirect'] = 'Ohjaa uudelleen osoitteeseen';
-$labels['vacation.copy'] = 'Lähetä kopio osoitteeseen';
-$messages['filterunknownerror'] = 'Tuntematon palvelinvirhe.';
-$messages['filterconnerror'] = 'Yhteys palvelimeen epäonnistui.';
-$messages['filterdeleted'] = 'Suodatin poistettu onnistuneesti.';
-$messages['filtersaved'] = 'Suodatin tallennettu onnistuneesti.';
-$messages['filtersaveerror'] = 'Suodattimen tallennus epäonnistui palvelinvirheen vuoksi.';
-$messages['filterdeleteconfirm'] = 'Haluatko varmasti poistaa valitun suodattimen?';
-$messages['forbiddenchars'] = 'Virheellisiä merkkejä kentässä.';
-$messages['cannotbeempty'] = 'Kenttä ei voi olla tyhjä.';
-$messages['ruleexist'] = 'Suodatin samalla nimellä on jo olemassa.';
-$messages['moved'] = 'Suodatin siirretty onnistuneesti.';
-$messages['nametoolong'] = 'Nimi on liian pitkä.';
-$messages['saveerror'] = 'Tietojen tallennus epäonnistui palvelinvirheen vuoksi.';
-$messages['vacationsaved'] = 'Lomatiedot tallennettu onnistuneesti.';
-$messages['emptyvacationbody'] = 'Lomaviestin sisältö vaaditaan!';
-?>
diff --git a/lib/plugins/managesieve/localization/fr_FR.inc b/lib/plugins/managesieve/localization/fr_FR.inc
deleted file mode 100644
index 6377d12..0000000
--- a/lib/plugins/managesieve/localization/fr_FR.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtres';
-$labels['managefilters'] = 'Gérer les filtres de courriels entrants';
-$labels['filtername'] = 'Nom du filtre';
-$labels['newfilter'] = 'Nouveau filtre';
-$labels['filteradd'] = 'Ajouter un filtre';
-$labels['filterdel'] = 'Supprimer le filtre';
-$labels['moveup'] = 'Monter';
-$labels['movedown'] = 'Descendre';
-$labels['filterallof'] = 'correspondant à toutes les règles suivantes';
-$labels['filteranyof'] = 'valident au moins une des conditions suivantes';
-$labels['filterany'] = 'tous les messages';
-$labels['filtercontains'] = 'contient';
-$labels['filternotcontains'] = 'ne contient pas';
-$labels['filteris'] = 'est égal à';
-$labels['filterisnot'] = 'est différent de';
-$labels['filterexists'] = 'existe';
-$labels['filternotexists'] = 'n\'existe pas';
-$labels['filtermatches'] = 'correspond à l\'expression';
-$labels['filternotmatches'] = 'ne correspond pas à l\'expression';
-$labels['filterregex'] = 'correspond à l\'expression rationnelle';
-$labels['filternotregex'] = 'ne correspond pas à l\'expression rationnelle';
-$labels['filterunder'] = 'plus petit que';
-$labels['filterover'] = 'plus grand que';
-$labels['addrule'] = 'Ajouter une règle';
-$labels['delrule'] = 'Supprimer une règle';
-$labels['messagemoveto'] = 'Déplacer le message vers';
-$labels['messageredirect'] = 'Rediriger le message à';
-$labels['messagecopyto'] = 'Copier le message vers';
-$labels['messagesendcopy'] = 'Envoyer une copie du message à';
-$labels['messagereply'] = 'Répondre avec le message';
-$labels['messagedelete'] = 'Supprimer le message';
-$labels['messagediscard'] = 'Rejeter avec le message';
-$labels['messagekeep'] = 'Conserver le message dans la boîte de réception';
-$labels['messagesrules'] = 'Pour les courriels entrants :';
-$labels['messagesactions'] = '...exécuter les actions suivantes :';
-$labels['add'] = 'Ajouter';
-$labels['del'] = 'Supprimer';
-$labels['sender'] = 'Expéditeur';
-$labels['recipient'] = 'Destinataire';
-$labels['vacationaddr'] = 'Mes adresses courriel additionnelles :';
-$labels['vacationdays'] = 'Fréquence d\'envoi des messages (en jours) :';
-$labels['vacationinterval'] = 'Fréquence d\'envoi des messages :';
-$labels['vacationreason'] = 'Corps du message (raison de l\'absence) :';
-$labels['vacationsubject'] = 'Objet du message :';
-$labels['days'] = 'jours';
-$labels['seconds'] = 'secondes';
-$labels['rulestop'] = 'Arrêter l\'évaluation des règles';
-$labels['enable'] = 'Activer/désactiver';
-$labels['filterset'] = 'Jeu de filtres';
-$labels['filtersets'] = 'Jeux de filtres';
-$labels['filtersetadd'] = 'Ajouter un jeu de filtres';
-$labels['filtersetdel'] = 'Supprimer le jeu de filtres actuel';
-$labels['filtersetact'] = 'Activer le jeu de filtres actuel';
-$labels['filtersetdeact'] = 'Désactiver le jeu de filtres actuel';
-$labels['filterdef'] = 'Définition du filtre';
-$labels['filtersetname'] = 'Nom du jeu de filtres';
-$labels['newfilterset'] = 'Nouveau jeu de filtres';
-$labels['active'] = 'activer';
-$labels['none'] = 'aucun';
-$labels['fromset'] = 'à partir du jeu';
-$labels['fromfile'] = 'à partir du fichier';
-$labels['filterdisabled'] = 'Filtre désactivé';
-$labels['countisgreaterthan'] = 'total supérieur à';
-$labels['countisgreaterthanequal'] = 'total supérieur ou égal à';
-$labels['countislessthan'] = 'total inférieur à';
-$labels['countislessthanequal'] = 'total inférieur ou égal à';
-$labels['countequals'] = 'total égal à';
-$labels['countnotequals'] = 'le nombre n\'est pas égal à';
-$labels['valueisgreaterthan'] = 'valeur supérieure à';
-$labels['valueisgreaterthanequal'] = 'valeur supérieure ou égale à';
-$labels['valueislessthan'] = 'valeur inférieure à';
-$labels['valueislessthanequal'] = 'valeur inférieure ou égale à';
-$labels['valueequals'] = 'valeur égale à';
-$labels['valuenotequals'] = 'la valeur n\'est pas égale à';
-$labels['setflags'] = 'Définir les drapeaux pour le message';
-$labels['addflags'] = 'Ajouter les drapeaux au message';
-$labels['removeflags'] = 'Supprimer les drapeaux du message';
-$labels['flagread'] = 'Lu';
-$labels['flagdeleted'] = 'Supprimé';
-$labels['flaganswered'] = 'Réponse envoyée';
-$labels['flagflagged'] = 'Signalé';
-$labels['flagdraft'] = 'Brouillon';
-$labels['setvariable'] = 'Définir une variable';
-$labels['setvarname'] = 'Nom de la variable :';
-$labels['setvarvalue'] = 'Valeur de la variable :';
-$labels['setvarmodifiers'] = 'Modificateurs :';
-$labels['varlower'] = 'minuscule';
-$labels['varupper'] = 'majuscule';
-$labels['varlowerfirst'] = 'premier caractère en minuscule';
-$labels['varupperfirst'] = 'premier caractère en majuscule';
-$labels['varquotewildcard'] = 'citer les caractères spéciaux';
-$labels['varlength'] = 'longueur';
-$labels['notify'] = 'Envoyer la notification';
-$labels['notifytarget'] = 'Cible de la notification :';
-$labels['notifymessage'] = 'Message de notification (optionnel) :';
-$labels['notifyoptions'] = 'Options de notification (optionnel) :';
-$labels['notifyfrom'] = 'Expéditeur de la notification (optionnel) :';
-$labels['notifyimportance'] = 'Importance :';
-$labels['notifyimportancelow'] = 'faible';
-$labels['notifyimportancenormal'] = 'normale';
-$labels['notifyimportancehigh'] = 'haute';
-$labels['notifymethodmailto'] = 'Courriel';
-$labels['notifymethodtel'] = 'Téléphone';
-$labels['notifymethodsms'] = 'Message texte';
-$labels['filtercreate'] = 'Créer un filtre';
-$labels['usedata'] = 'Utiliser les données suivantes dans le filtre :';
-$labels['nextstep'] = 'Étape suivante';
-$labels['...'] = '...';
-$labels['currdate'] = 'Date actuelle';
-$labels['datetest'] = 'Date';
-$labels['dateheader'] = 'en-tête :';
-$labels['year'] = 'année';
-$labels['month'] = 'mois';
-$labels['day'] = 'jour';
-$labels['date'] = 'date (aaaa-mm-jj)';
-$labels['julian'] = 'date (julien)';
-$labels['hour'] = 'heure';
-$labels['minute'] = 'minute';
-$labels['second'] = 'seconde';
-$labels['time'] = 'heure (hh:mm:ss)';
-$labels['iso8601'] = 'date (ISO8601)';
-$labels['std11'] = 'date (RFC2822)';
-$labels['zone'] = 'fuseau horaire';
-$labels['weekday'] = 'jour de la semaine (0-6)';
-$labels['advancedopts'] = 'Options avancées';
-$labels['body'] = 'Corps';
-$labels['address'] = 'adresse';
-$labels['envelope'] = 'enveloppe';
-$labels['modifier'] = 'modificateur :';
-$labels['text'] = 'texte';
-$labels['undecoded'] = 'non décodé (brut)';
-$labels['contenttype'] = 'type de contenu';
-$labels['modtype'] = 'type :';
-$labels['allparts'] = 'tout';
-$labels['domain'] = 'domaine';
-$labels['localpart'] = 'partie locale';
-$labels['user'] = 'utilisateur';
-$labels['detail'] = 'détail';
-$labels['comparator'] = 'comparateur :';
-$labels['default'] = 'par défaut';
-$labels['octet'] = 'strict (octet)';
-$labels['asciicasemap'] = 'insensible à la casse (ascii-casemap)';
-$labels['asciinumeric'] = 'numérique (ascii-numeric)';
-$labels['index'] = 'index :';
-$labels['indexlast'] = 'à l\'envers';
-$labels['vacation'] = 'Vacances';
-$labels['vacation.reply'] = 'Message de réponse';
-$labels['vacation.advanced'] = 'Paramètres avancés';
-$labels['vacation.subject'] = 'Objet';
-$labels['vacation.body'] = 'Corps';
-$labels['vacation.start'] = 'Début de vacances';
-$labels['vacation.end'] = 'Fin de vacances';
-$labels['vacation.status'] = 'État';
-$labels['vacation.on'] = 'Arrêt';
-$labels['vacation.off'] = 'Marche';
-$labels['vacation.addresses'] = 'Mes adresses supplémentaires';
-$labels['vacation.interval'] = 'Plage de réponse';
-$labels['vacation.after'] = 'Mettre en place la règle de vacances après';
-$labels['vacation.saving'] = 'Enregistrement des données...';
-$labels['vacation.action'] = 'Action pour message entrant';
-$labels['vacation.keep'] = 'Garder';
-$labels['vacation.discard'] = 'Rejeter';
-$labels['vacation.redirect'] = 'Réacheminer à';
-$labels['vacation.copy'] = 'Envoyer une copie à';
-$labels['arialabelfiltersetactions'] = 'Actions des jeux de filtrage';
-$labels['arialabelfilteractions'] = 'Actions de filtrage';
-$labels['arialabelfilterform'] = 'Propriété du filtrage';
-$labels['ariasummaryfilterslist'] = 'Liste des filtres';
-$labels['ariasummaryfiltersetslist'] = 'Liste des jeux de filtrage';
-$labels['filterstitle'] = 'Modifier les filtres de courriels entrants';
-$labels['vacationtitle'] = 'Modifier la règle d\'absence du bureau';
-$messages['filterunknownerror'] = 'Erreur de serveur inconnue';
-$messages['filterconnerror'] = 'Connexion au serveur impossible.';
-$messages['filterdeleteerror'] = 'Impossible de supprimer le filtre. Une erreur de serveur est survenue.';
-$messages['filterdeleted'] = 'Le filtre a été supprimé avec succès.';
-$messages['filtersaved'] = 'Le filtre a été enregistré avec succès.';
-$messages['filtersaveerror'] = 'Impossible d\'enregistrer le filtre. Une erreur de serveur est survenue.';
-$messages['filterdeleteconfirm'] = 'Voulez-vous vraiment supprimer le filtre sélectionné ?';
-$messages['ruledeleteconfirm'] = 'Voulez-vous vraiment supprimer la règle sélectionnée ?';
-$messages['actiondeleteconfirm'] = 'Voulez-vous vraiment supprimer l\'action sélectionnée ?';
-$messages['forbiddenchars'] = 'Caractères interdits dans le champ';
-$messages['cannotbeempty'] = 'Le champ ne peut pas être vide';
-$messages['ruleexist'] = 'Un filtre existe déjà avec ce nom.';
-$messages['setactivateerror'] = 'Impossible d\'activer le jeu de filtres sélectionné. Une erreur de serveur est survenue.';
-$messages['setdeactivateerror'] = 'Impossible de désactiver le jeu de filtres sélectionné. Une erreur de serveur est survenue.';
-$messages['setdeleteerror'] = 'Impossible de supprimer le jeu de filtres sélectionné. Une erreur de serveur est survenue.';
-$messages['setactivated'] = 'Le jeu de filtres a été activé avec succès.';
-$messages['setdeactivated'] = 'Le jeu de filtres a été désactivé avec succès.';
-$messages['setdeleted'] = 'Le jeu de filtres a été supprimé avec succès.';
-$messages['setdeleteconfirm'] = 'Voulez vous vraiment supprimer le jeu de filtres sélectionné ?';
-$messages['setcreateerror'] = 'Impossible de créer un jeu de filtres. Une erreur de serveur est survenue.';
-$messages['setcreated'] = 'Le jeu de filtres a été créé avec succès.';
-$messages['activateerror'] = 'Impossible d\'activer le/les filtre(s) sélectionné(s). Une erreur de serveur est survenue.';
-$messages['deactivateerror'] = 'Impossible de désactiver le/les filtre(s) sélectionné(s). Une erreur de serveur est survenue.';
-$messages['deactivated'] = 'Filtre(s) désactivé(s) avec succès.';
-$messages['activated'] = 'Filtre(s) activé(s) avec succès.';
-$messages['moved'] = 'Filtre déplacé avec succès.';
-$messages['moveerror'] = 'Impossible de déplacer le filtre sélectionné. Une erreur de serveur est survenue.';
-$messages['nametoolong'] = 'Nom trop long.';
-$messages['namereserved'] = 'Nom réservé.';
-$messages['setexist'] = 'Le jeu existe déjà.';
-$messages['nodata'] = 'Au moins un élément doit être sélectionné !';
-$messages['invaliddateformat'] = 'Format de date ou d\'une partie de la date invalide';
-$messages['saveerror'] = 'Impossible d\'enregistrer les données. Une erreur du serveur est survenue.';
-$messages['vacationsaved'] = 'Les données de vacances ont été enregistrées avec succès.';
-$messages['emptyvacationbody'] = 'Le corps du message de vacances est nécessaire !';
-?>
diff --git a/lib/plugins/managesieve/localization/gl_ES.inc b/lib/plugins/managesieve/localization/gl_ES.inc
deleted file mode 100644
index cbe45ca..0000000
--- a/lib/plugins/managesieve/localization/gl_ES.inc
+++ /dev/null
@@ -1,206 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtros';
-$labels['managefilters'] = 'Xestionar os filtros de correo entrante';
-$labels['filtername'] = 'Nome do filtro';
-$labels['newfilter'] = 'Novo filtro';
-$labels['filteradd'] = 'Engadir filtro';
-$labels['filterdel'] = 'Eliminar filtro';
-$labels['moveup'] = 'Mover arriba';
-$labels['movedown'] = 'Mover abaixo';
-$labels['filterallof'] = 'coincidir con todas as regras seguintes';
-$labels['filteranyof'] = 'coincidir con algunha das regras seguintes';
-$labels['filterany'] = 'todas as mensaxes';
-$labels['filtercontains'] = 'contén';
-$labels['filternotcontains'] = 'non contén';
-$labels['filteris'] = 'é igual a';
-$labels['filterisnot'] = 'non é igual a';
-$labels['filterexists'] = 'existe';
-$labels['filternotexists'] = 'non existe';
-$labels['filtermatches'] = 'casa coa expresión';
-$labels['filternotmatches'] = 'non casa coa expresión';
-$labels['filterregex'] = 'casa coa expresión regular';
-$labels['filternotregex'] = 'non casa coa expresión regular';
-$labels['filterunder'] = 'baixo';
-$labels['filterover'] = 'sobre';
-$labels['addrule'] = 'Engadir regra';
-$labels['delrule'] = 'Eliminar regra';
-$labels['messagemoveto'] = 'Mover a mensaxe a';
-$labels['messageredirect'] = 'Redirixir a mensaxe a';
-$labels['messagecopyto'] = 'Copiar a mensaxe a';
-$labels['messagesendcopy'] = 'Enviar copia da mensaxe a';
-$labels['messagereply'] = 'Respostar con unha mensaxe';
-$labels['messagedelete'] = 'Eliminar a mensaxe';
-$labels['messagediscard'] = 'Descartar con unha mensaxe';
-$labels['messagekeep'] = 'Manter mensaxe na caixa de entrada';
-$labels['messagesrules'] = 'Para o correo entrante:';
-$labels['messagesactions'] = '... executar as seguintes accións:';
-$labels['add'] = 'Engadir';
-$labels['del'] = 'Eliminar';
-$labels['sender'] = 'Remite';
-$labels['recipient'] = 'Persoa destinataria';
-$labels['vacationaddr'] = 'O(s) meu(s) outro (s) enderezo(s) de correo:';
-$labels['vacationdays'] = 'Cada canto enviar mensaxes (en días):';
-$labels['vacationinterval'] = 'Con que frecuencia se van enviar mensaxes:';
-$labels['vacationreason'] = 'Corpo da mensaxe (por vacacións):';
-$labels['vacationsubject'] = 'Asunto da mensaxe:';
-$labels['days'] = 'días';
-$labels['seconds'] = 'segundos';
-$labels['rulestop'] = 'Parar de avaliar regras';
-$labels['enable'] = 'Activar/Desactivar';
-$labels['filterset'] = 'Conxunto de filtros';
-$labels['filtersets'] = 'Conxunto de filtros';
-$labels['filtersetadd'] = 'Engadir un conxunto de filtros';
-$labels['filtersetdel'] = 'Eliminar o conxunto de filtros actual';
-$labels['filtersetact'] = 'Activar o conxunto de filtros actual';
-$labels['filtersetdeact'] = 'Desactivar o conxunto de filtros actual';
-$labels['filterdef'] = 'Definición de filtros';
-$labels['filtersetname'] = 'Nome do conxunto de filtros';
-$labels['newfilterset'] = 'Novo conxunto de filtros';
-$labels['active'] = 'activo';
-$labels['none'] = 'ningún';
-$labels['fromset'] = 'de conxunto';
-$labels['fromfile'] = 'de arquivo';
-$labels['filterdisabled'] = 'Filtro desactivado';
-$labels['countisgreaterthan'] = 'a conta é maior que';
-$labels['countisgreaterthanequal'] = 'a conta é maior ou igual a';
-$labels['countislessthan'] = 'a conta é menor que';
-$labels['countislessthanequal'] = 'a conta é menor ou igual a';
-$labels['countequals'] = 'a conta é igual a';
-$labels['countnotequals'] = 'a conta non é igual a';
-$labels['valueisgreaterthan'] = 'o valor é meirande que ';
-$labels['valueisgreaterthanequal'] = 'o valor é maior ou igual a';
-$labels['valueislessthan'] = 'o valor é menor que';
-$labels['valueislessthanequal'] = 'o valor é menor ou igual a';
-$labels['valueequals'] = 'o valor é igual a';
-$labels['valuenotequals'] = 'o valor non é igual a';
-$labels['setflags'] = 'Marcar a mensaxe';
-$labels['addflags'] = 'Engadir marcas á mensaxe';
-$labels['removeflags'] = 'Desmarcar as mensaxes';
-$labels['flagread'] = 'Lidas';
-$labels['flagdeleted'] = 'Eliminadas';
-$labels['flaganswered'] = 'Respostadas';
-$labels['flagflagged'] = 'Marcadas';
-$labels['flagdraft'] = 'Borrador';
-$labels['setvariable'] = 'Estabelecer variábel';
-$labels['setvarname'] = 'Nome da variábel:';
-$labels['setvarvalue'] = 'Valor da variábel:';
-$labels['setvarmodifiers'] = 'Modificadores:';
-$labels['varlower'] = 'minúscula';
-$labels['varupper'] = 'maiúscula';
-$labels['varlowerfirst'] = 'primeira letra minúscula';
-$labels['varupperfirst'] = 'primeira letra maiúscula';
-$labels['varquotewildcard'] = 'poñer entre aspas caracteres especiais';
-$labels['varlength'] = 'lonxitude';
-$labels['notify'] = 'Enviar notificación';
-$labels['notifyimportance'] = 'Importancia:';
-$labels['notifyimportancelow'] = 'baixa';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'alta';
-$labels['notifymethodmailto'] = 'Correo electrónico';
-$labels['notifymethodtel'] = 'Teléfono';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Crear filtro';
-$labels['usedata'] = 'Usar os seguintes datos no filtro:';
-$labels['nextstep'] = 'Seguinte paso';
-$labels['...'] = '...';
-$labels['currdate'] = 'Data actual';
-$labels['datetest'] = 'Data';
-$labels['dateheader'] = 'cabeceira:';
-$labels['year'] = 'ano';
-$labels['month'] = 'mes';
-$labels['day'] = 'día';
-$labels['date'] = 'data (aaaa-mm-dd)';
-$labels['julian'] = 'data (xuliano)';
-$labels['hour'] = 'hora';
-$labels['minute'] = 'minuto';
-$labels['second'] = 'segundo';
-$labels['time'] = 'tempo (hh:mm:ss)';
-$labels['iso8601'] = 'data (ISO8601)';
-$labels['std11'] = 'data (RFC2822)';
-$labels['zone'] = 'fuso-horario';
-$labels['weekday'] = 'día da semana (0-6)';
-$labels['advancedopts'] = 'Opcións avanzadas';
-$labels['body'] = 'Corpo';
-$labels['address'] = 'enderezo';
-$labels['envelope'] = 'sobre';
-$labels['modifier'] = 'modificador:';
-$labels['text'] = 'texto';
-$labels['undecoded'] = 'sen codificar (en bruto)';
-$labels['contenttype'] = 'tipo de contido';
-$labels['modtype'] = 'tipo:';
-$labels['allparts'] = 'todos';
-$labels['domain'] = 'dominio';
-$labels['localpart'] = 'parte local';
-$labels['user'] = 'utente';
-$labels['detail'] = 'detalle';
-$labels['comparator'] = 'comparador:';
-$labels['default'] = 'predeterminado';
-$labels['octet'] = 'estricto (octeto)';
-$labels['asciicasemap'] = 'non sensíbel a maiúsculas/minúsculas (ascii-casemap)';
-$labels['asciinumeric'] = 'numérico (ascii-numerico)';
-$labels['index'] = 'índice:';
-$labels['indexlast'] = 'atrás';
-$labels['vacation.reply'] = 'Respostar á mensaxe';
-$labels['vacation.advanced'] = 'Opcións avanzadas';
-$labels['vacation.subject'] = 'Asunto';
-$labels['vacation.body'] = 'Corpo';
-$labels['vacation.status'] = 'Estado';
-$labels['vacation.on'] = 'Activar';
-$labels['vacation.off'] = 'Desactivar';
-$labels['vacation.saving'] = 'Gardando datos...';
-$labels['vacation.keep'] = 'Manter';
-$labels['vacation.discard'] = 'Descartar';
-$labels['vacation.redirect'] = 'Redirixir a';
-$labels['vacation.copy'] = 'Enviar copia a';
-$labels['arialabelfilteractions'] = 'Accións de filtrado';
-$labels['arialabelfilterform'] = 'Propiedades dos filtros';
-$labels['ariasummaryfilterslist'] = 'Lista de filtros';
-$messages['filterunknownerror'] = 'Erro descoñecido do servidor';
-$messages['filterconnerror'] = 'Imposíbel conectar co servidor.';
-$messages['filterdeleteerror'] = 'Non se pode eliminar filtro. Produciuse un erro de servidor.';
-$messages['filterdeleted'] = 'Filtro borrado con éxito';
-$messages['filtersaved'] = 'Filtro gardado con éxito';
-$messages['filtersaveerror'] = 'Non se puido gardar filtro. Produciuse un erro de servidor.';
-$messages['filterdeleteconfirm'] = 'Realmente queres eliminar o filtro seleccionado?';
-$messages['ruledeleteconfirm'] = 'Seguro que queres eliminar a regra seleccionada?';
-$messages['actiondeleteconfirm'] = 'Seguro que queres eliminar a acción seleccionada?';
-$messages['forbiddenchars'] = 'Caracteres non permitidos no campo';
-$messages['cannotbeempty'] = 'O campo non pode estar baleiro';
-$messages['ruleexist'] = 'Xa existe un filtro co nome especificado.';
-$messages['setactivateerror'] = 'Non se poden activar os filtros seleccionados. Produciuse un erro de servidor.';
-$messages['setdeactivateerror'] = 'Non foi posíbel desactivar os filtros seleccionados. Produciuse un erro de servidor.';
-$messages['setdeleteerror'] = 'Non é posíbel eliminar os filtros seleccionados. Produciuse un erro de servidor.';
-$messages['setactivated'] = 'O conxunto de filtros activouse con éxito';
-$messages['setdeactivated'] = 'O conxunto de filtros desactivouse con éxito';
-$messages['setdeleted'] = 'O Conxunto de filtros borrouse con éxito';
-$messages['setdeleteconfirm'] = 'Seguro que queres eliminar o conxunto de filtros seleccionado?';
-$messages['setcreateerror'] = 'Non é posíbel crear filtros. Produciuse un erro de servidor.';
-$messages['setcreated'] = 'Conxunto de filtros creado con éxito';
-$messages['activateerror'] = 'Non é posíbel activar o(s) filtro(s) seleccionado(s). Produciuse un erro de servidor.';
-$messages['deactivateerror'] = 'Incapaz de desactivar filtro(s) seleccionado(s). Produciuse un erro de servidor.';
-$messages['deactivated'] = 'Desactiváronse os filtros correctamente.';
-$messages['activated'] = 'Activáronse os filtros correctamente';
-$messages['moved'] = 'Moveuse correctamente o filtro.';
-$messages['moveerror'] = 'Non se pode mover o filtro seleccionado. Produciuse un erro de servidor.';
-$messages['nametoolong'] = 'Imposíbel crear o conxunto de filtros. O nome é longo de máis';
-$messages['namereserved'] = 'Nome reservado';
-$messages['setexist'] = 'Xa existe o conxunto';
-$messages['nodata'] = 'É preciso seleccionar polo menos unha posición!';
-$messages['invaliddateformat'] = 'Formato de data ou parte dos datos non válidos';
-?>
diff --git a/lib/plugins/managesieve/localization/he_IL.inc b/lib/plugins/managesieve/localization/he_IL.inc
deleted file mode 100644
index 4e7b597..0000000
--- a/lib/plugins/managesieve/localization/he_IL.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'מסננים';
-$labels['managefilters'] = 'ניהול מסננים לדואר נכנס';
-$labels['filtername'] = 'שם המסנן';
-$labels['newfilter'] = 'מסנן חדש';
-$labels['filteradd'] = 'הוספת מסנן';
-$labels['filterdel'] = 'מחיקת מסנן';
-$labels['moveup'] = 'הזזה מעלה';
-$labels['movedown'] = 'הזזה מטה';
-$labels['filterallof'] = 'תאימות לכל הכללים שלהלן';
-$labels['filteranyof'] = 'תאימות לחלק מהכללים שלהלן';
-$labels['filterany'] = 'כל ההודעות';
-$labels['filtercontains'] = 'מכיל';
-$labels['filternotcontains'] = 'לא מכיל';
-$labels['filteris'] = 'שווה ערך ל-';
-$labels['filterisnot'] = 'אינו שווה ערך ל-';
-$labels['filterexists'] = 'קיים';
-$labels['filternotexists'] = 'לא קיים';
-$labels['filtermatches'] = 'תואם ביטוי';
-$labels['filternotmatches'] = 'לא תואם ביטוי';
-$labels['filterregex'] = 'תואם ביטוי מורכב';
-$labels['filternotregex'] = 'לא תואם ביטוי מורכב';
-$labels['filterunder'] = 'תחת';
-$labels['filterover'] = 'מעל';
-$labels['addrule'] = 'הוספת כלל';
-$labels['delrule'] = 'מחיקת כלל';
-$labels['messagemoveto'] = 'העברת הודעה אל';
-$labels['messageredirect'] = 'השמה חדשה של ההודעה אל';
-$labels['messagecopyto'] = 'העתקת ההודעה אל';
-$labels['messagesendcopy'] = 'משלוח העתק מההודעה אל';
-$labels['messagereply'] = 'מענה עם הודעה';
-$labels['messagedelete'] = 'מחיקת הודעה';
-$labels['messagediscard'] = 'ביטול ההודעה';
-$labels['messagekeep'] = 'שמירת הודעה בדואר נכנס';
-$labels['messagesrules'] = 'עבור דואר נכנס:';
-$labels['messagesactions'] = '...מבצע הפעולות הבאות:';
-$labels['add'] = 'הוספה';
-$labels['del'] = 'מחיקה';
-$labels['sender'] = 'השולח';
-$labels['recipient'] = 'הנמען';
-$labels['vacationaddr'] = 'כתובות דוא"ל נוספות:';
-$labels['vacationdays'] = 'באיזו תדירות ( בימים ) לשלוח הודעות:';
-$labels['vacationinterval'] = 'באיזו תדירות לשלוח ההודעה';
-$labels['vacationreason'] = 'גוף ההודעה (סיבת החופשה):';
-$labels['vacationsubject'] = 'נושא ההודעה:';
-$labels['days'] = 'ימים';
-$labels['seconds'] = 'שניות';
-$labels['rulestop'] = 'עצירה של בחינת הכללים';
-$labels['enable'] = 'אפשור/ניטרול';
-$labels['filterset'] = 'קבוצת מסננים';
-$labels['filtersets'] = 'קבוצות מסננים';
-$labels['filtersetadd'] = 'הוספה של קבוצת מסננים';
-$labels['filtersetdel'] = 'מחיקה של מסננים נוכחיים';
-$labels['filtersetact'] = 'הפעלה של מסננים נוכחיים';
-$labels['filtersetdeact'] = 'השבתה של מסננים נוכחיים';
-$labels['filterdef'] = 'הגדרת מסנן';
-$labels['filtersetname'] = 'שם של קבוצת מסננים';
-$labels['newfilterset'] = 'קבוצת מסננים חדשה';
-$labels['active'] = 'פעיל';
-$labels['none'] = 'אף אחד מאלה';
-$labels['fromset'] = 'מקבוצה';
-$labels['fromfile'] = 'מקובץ';
-$labels['filterdisabled'] = 'מסנן מושבת';
-$labels['countisgreaterthan'] = 'המספר גדול מ-';
-$labels['countisgreaterthanequal'] = 'המספר גדול או שווה ל-';
-$labels['countislessthan'] = 'המספר קטן מ-';
-$labels['countislessthanequal'] = 'המספר קטן או שווה ל-';
-$labels['countequals'] = 'המספר שווה ל-';
-$labels['countnotequals'] = 'המספר אינו שווה ל ';
-$labels['valueisgreaterthan'] = 'הערך גדול מ-';
-$labels['valueisgreaterthanequal'] = 'הערך גדול או שווה ל-';
-$labels['valueislessthan'] = 'הערך קטן מ-';
-$labels['valueislessthanequal'] = 'הערך קטן או שווה ל-';
-$labels['valueequals'] = 'הערך שווה ל-';
-$labels['valuenotequals'] = 'הערך אינו שוה ל ';
-$labels['setflags'] = 'סימון דגלים להודעה';
-$labels['addflags'] = 'הוספת דגלים להודעה';
-$labels['removeflags'] = 'הסרת דגלים מההודעה';
-$labels['flagread'] = 'נקרא';
-$labels['flagdeleted'] = 'נמחק';
-$labels['flaganswered'] = 'נענה';
-$labels['flagflagged'] = 'סומן בדגל';
-$labels['flagdraft'] = 'טיוטה';
-$labels['setvariable'] = 'הגדרת משתנה';
-$labels['setvarname'] = 'שם המשתנה:';
-$labels['setvarvalue'] = 'ערך המשתנה:';
-$labels['setvarmodifiers'] = 'גורם משנה:';
-$labels['varlower'] = 'אותיות קטנות';
-$labels['varupper'] = 'אותיות גדולות';
-$labels['varlowerfirst'] = 'התו הראשון אות קטנה';
-$labels['varupperfirst'] = 'התו הראשון אות גדולה';
-$labels['varquotewildcard'] = 'תו מיוחד יש לשים בין מרכאות';
-$labels['varlength'] = 'אורך';
-$labels['notify'] = 'משלוח התראה';
-$labels['notifytarget'] = 'יעד התראה:';
-$labels['notifymessage'] = 'הודעת התראה (רשות):';
-$labels['notifyoptions'] = 'אפשרויות התראה (רשות):';
-$labels['notifyfrom'] = 'שולח התראה (רשות):';
-$labels['notifyimportance'] = 'חשיובת:';
-$labels['notifyimportancelow'] = 'נמוכה';
-$labels['notifyimportancenormal'] = 'רגילה';
-$labels['notifyimportancehigh'] = 'גבוהה';
-$labels['notifymethodmailto'] = 'דוא״ל';
-$labels['notifymethodtel'] = 'טלפון';
-$labels['notifymethodsms'] = 'מסרון';
-$labels['filtercreate'] = 'יצירת מסנן';
-$labels['usedata'] = 'שימוש במידע שלהלן ליצירת המסנן:';
-$labels['nextstep'] = 'הצעד הבא';
-$labels['...'] = '...';
-$labels['currdate'] = 'תאריך נוכחי';
-$labels['datetest'] = 'תאריך';
-$labels['dateheader'] = 'כותרת:';
-$labels['year'] = 'שנה';
-$labels['month'] = 'חודש';
-$labels['day'] = 'יום';
-$labels['date'] = 'תאריך (שנה-חודש-יום)';
-$labels['julian'] = 'תאריך (יוליאני)';
-$labels['hour'] = 'שעה';
-$labels['minute'] = 'דקה';
-$labels['second'] = 'שניה';
-$labels['time'] = 'זמן (שעה:דקה:שניה)';
-$labels['iso8601'] = 'תאריך (ISO8601)';
-$labels['std11'] = 'תאריך (RFC2822)';
-$labels['zone'] = 'איזור זמן';
-$labels['weekday'] = 'יום בשבוע (0-6)';
-$labels['advancedopts'] = 'אפשרויות מתקדמות';
-$labels['body'] = 'גוף ההודעה';
-$labels['address'] = 'כתובת';
-$labels['envelope'] = 'מעטפה';
-$labels['modifier'] = 'גורם שינוי:';
-$labels['text'] = 'תמליל';
-$labels['undecoded'] = 'לא מקודד ( גולמי )';
-$labels['contenttype'] = 'סוג התוכן';
-$labels['modtype'] = 'סוג:';
-$labels['allparts'] = 'הכל';
-$labels['domain'] = 'מתחם';
-$labels['localpart'] = 'חלק מקומי';
-$labels['user'] = 'משתמש';
-$labels['detail'] = 'פרטים';
-$labels['comparator'] = 'משווה:';
-$labels['default'] = 'ברירת מחדל';
-$labels['octet'] = 'strict (octet)';
-$labels['asciicasemap'] = 'case insensitive (ascii-casemap)';
-$labels['asciinumeric'] = 'numeric (ascii-numeric)';
-$labels['index'] = 'אינדקס:';
-$labels['indexlast'] = 'בחזרה';
-$labels['vacation'] = 'חופשה';
-$labels['vacation.reply'] = 'הודעת תשובה';
-$labels['vacation.advanced'] = 'הגדרות מתקדמות';
-$labels['vacation.subject'] = 'נושא';
-$labels['vacation.body'] = 'גוף ההודעה';
-$labels['vacation.start'] = 'תאריך התחלה';
-$labels['vacation.end'] = 'תאריך סיום';
-$labels['vacation.status'] = 'מצב';
-$labels['vacation.on'] = 'מופעל';
-$labels['vacation.off'] = 'כבוי';
-$labels['vacation.addresses'] = 'כתובות נוספות שלי';
-$labels['vacation.interval'] = 'מרווח בין תשובות';
-$labels['vacation.after'] = 'העתקת סרגל החופשה אחרי';
-$labels['vacation.saving'] = 'שמירת מידע...';
-$labels['vacation.action'] = 'פעולה על הודעה נכנסת';
-$labels['vacation.keep'] = 'להשאיר';
-$labels['vacation.discard'] = 'להפטר';
-$labels['vacation.redirect'] = 'הפניה אל';
-$labels['vacation.copy'] = 'שליחת העתק אל';
-$labels['arialabelfiltersetactions'] = 'פעולות על קבוצה של חוקי סינון';
-$labels['arialabelfilteractions'] = 'פעולות מסנן';
-$labels['arialabelfilterform'] = 'מאפייני מסנן';
-$labels['ariasummaryfilterslist'] = 'רשימה של מסננים';
-$labels['ariasummaryfiltersetslist'] = 'רשימת קבוצות של חוקי סינון';
-$labels['filterstitle'] = 'ערוך מסנני דואר נכנס';
-$labels['vacationtitle'] = 'ערוך כלל מחוץ-אל-משרדי';
-$messages['filterunknownerror'] = 'שגיאת שרת בלתי מוכרת.';
-$messages['filterconnerror'] = 'לא ניתן להתחבר לשרת.';
-$messages['filterdeleteerror'] = 'לא ניתן למחוק סינון. שגיאת שרת.';
-$messages['filterdeleted'] = 'המסנן נמחק בהצלחה.';
-$messages['filtersaved'] = 'המסנן נשמר בהצלחה.';
-$messages['filtersaveerror'] = 'לא ניתן לשמור סינון. שגיאת שרת.';
-$messages['filterdeleteconfirm'] = 'האם אכן ברצונך למחוק את המסנן הנבחר?';
-$messages['ruledeleteconfirm'] = 'האם אכן ברצונך למחוק את הכלל הנבחר?';
-$messages['actiondeleteconfirm'] = 'האם אכן ברצונך למחוק את הפעולה הנבחרת?';
-$messages['forbiddenchars'] = 'תווים אסורים בשדה.';
-$messages['cannotbeempty'] = 'השדה לא יכול להישאר ריק.';
-$messages['ruleexist'] = 'כבר קיים מסנן בשם כזה.';
-$messages['setactivateerror'] = 'לא ניתן להפעיל את ערכת המסננים הנבחרת. אירעה שגיאה בצד השרת.';
-$messages['setdeactivateerror'] = 'לא ניתן להשבית רשימת מסננים שנבחרה. שגיאת שרת.';
-$messages['setdeleteerror'] = 'לא ניתן למחוק רשימת מסננים שנבחרה. שגיאת שרת.';
-$messages['setactivated'] = 'ערכת המסננים הופעלה בהצלחה.';
-$messages['setdeactivated'] = 'ערכת המסננים נוטרלה בהצלחה.';
-$messages['setdeleted'] = 'ערכת המסננים נמחקה בהצלחה.';
-$messages['setdeleteconfirm'] = 'האם אכן ברצונך למחוק את ערכת המסננים הנבחרת?';
-$messages['setcreateerror'] = 'לא ניתן ליצור ערכת מסננים. אירעה שגיאה בצד השרת.';
-$messages['setcreated'] = 'ערכת המסננים נוצרה בהצלחה.';
-$messages['activateerror'] = 'לא ניתן להפעיל את המסננים הנבחרים. אירעה שגיאה בצד השרת.';
-$messages['deactivateerror'] = 'לא ניתן לנטרל את המסננים הנבחרים. אירעה שגיאה בצד השרת.';
-$messages['deactivated'] = 'המסננים הופעלו בהצלחה.';
-$messages['activated'] = 'המסננים נוטרלו בהצלחה.';
-$messages['moved'] = 'המסנן הועבר בהצלחה.';
-$messages['moveerror'] = 'לא ניתן להעביר את המסנן הנבחר. אירעה שגיאה בצד השרת.';
-$messages['nametoolong'] = 'השם ארוך מדי.';
-$messages['namereserved'] = 'השם הזה שמור.';
-$messages['setexist'] = 'הערכה כבר קיימת.';
-$messages['nodata'] = 'חובה לבחור במיקום אחד לפחות!';
-$messages['invaliddateformat'] = 'תאריך לא חוקי אן פורמט לא תקין';
-$messages['saveerror'] = 'לא ניתן לשמור המידע בשל שגיאה של השרת';
-$messages['vacationsaved'] = 'הודעת החופשה נשמרה בהצלחה';
-$messages['emptyvacationbody'] = 'גוף של הודעת חופשה נדרש!';
-?>
diff --git a/lib/plugins/managesieve/localization/hr_HR.inc b/lib/plugins/managesieve/localization/hr_HR.inc
deleted file mode 100644
index efcd4da..0000000
--- a/lib/plugins/managesieve/localization/hr_HR.inc
+++ /dev/null
@@ -1,194 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filteri';
-$labels['managefilters'] = 'Uredi filtere za pristiglu poštu';
-$labels['filtername'] = 'Naziv filtera';
-$labels['newfilter'] = 'Novi filter';
-$labels['filteradd'] = 'Dodaj filter';
-$labels['filterdel'] = 'Obriši filter';
-$labels['moveup'] = 'Pomakni gore';
-$labels['movedown'] = 'Pomakni dolje';
-$labels['filterallof'] = 'koje odgovaraju svim sljedećim pravilima';
-$labels['filteranyof'] = 'koje odgovaraju bilo kojem od sljedećih pravila';
-$labels['filterany'] = 'sve poruke';
-$labels['filtercontains'] = 'sadrži';
-$labels['filternotcontains'] = 'ne sadrži';
-$labels['filteris'] = 'jednako je';
-$labels['filterisnot'] = 'nije jednako';
-$labels['filterexists'] = 'postoji';
-$labels['filternotexists'] = 'ne postoji';
-$labels['filtermatches'] = 'odgovara izrazu';
-$labels['filternotmatches'] = 'ne odgovara izrazu';
-$labels['filterregex'] = 'odgovara regularnom izrazu';
-$labels['filternotregex'] = 'ne odgovara regularnom izrazu';
-$labels['filterunder'] = 'ispod';
-$labels['filterover'] = 'iznad';
-$labels['addrule'] = 'Dodaj pravilo';
-$labels['delrule'] = 'Obriši pravilo';
-$labels['messagemoveto'] = 'Premjesti poruku u';
-$labels['messageredirect'] = 'Preusmjeri poruku na';
-$labels['messagecopyto'] = 'Kopiraju poruku u';
-$labels['messagesendcopy'] = 'Pošalji kopiju poruke na';
-$labels['messagereply'] = 'Odgovori sa porukom';
-$labels['messagedelete'] = 'Obriši poruku';
-$labels['messagediscard'] = 'Otkaži sa porukom';
-$labels['messagekeep'] = 'Zadrži poruku u mapi Inbox';
-$labels['messagesrules'] = 'Za pristigle poruke:';
-$labels['messagesactions'] = '...primijeni sljedeće akcije:';
-$labels['add'] = 'Dodaj';
-$labels['del'] = 'Obriši';
-$labels['sender'] = 'Pošiljatelj';
-$labels['recipient'] = 'Primatelj';
-$labels['vacationaddr'] = 'Dodatna e-mail adresa(e):';
-$labels['vacationdays'] = 'Koliko često slati poruku (u danima):';
-$labels['vacationinterval'] = 'Koliko često slati poruku:';
-$labels['vacationreason'] = 'Tijelo poruke (razlog odmora):';
-$labels['vacationsubject'] = 'Naslov poruke:';
-$labels['days'] = 'dana';
-$labels['seconds'] = 'sekundi';
-$labels['rulestop'] = 'Prekini izvođenje filtera';
-$labels['enable'] = 'Omogući/Onemogući';
-$labels['filterset'] = 'Grupa filtera';
-$labels['filtersets'] = 'Filteri';
-$labels['filtersetadd'] = 'Dodaj grupu filtera';
-$labels['filtersetdel'] = 'Obriši odabranu grupu filtera';
-$labels['filtersetact'] = 'Aktiviraj odabranu grupu filtera';
-$labels['filtersetdeact'] = 'Deaktiviraj odabranu grupu filtera';
-$labels['filterdef'] = 'Definicije filtera';
-$labels['filtersetname'] = 'Naziv grupe filtera';
-$labels['newfilterset'] = 'Nova grupa filtera';
-$labels['active'] = 'aktivan';
-$labels['none'] = 'nijedan';
-$labels['fromset'] = 'iz grupe';
-$labels['fromfile'] = 'iz datoteke';
-$labels['filterdisabled'] = 'Deaktiviraj filter';
-$labels['countisgreaterthan'] = 'brojač je veći od';
-$labels['countisgreaterthanequal'] = 'brojač je veći ili jednak od';
-$labels['countislessthan'] = 'brojač je manji od';
-$labels['countislessthanequal'] = 'brojač je manji ili jednak od';
-$labels['countequals'] = 'brojač je jednak';
-$labels['countnotequals'] = 'brojač nije jednak';
-$labels['valueisgreaterthan'] = 'vrijednost je veća od';
-$labels['valueisgreaterthanequal'] = 'vrijednost je veća ili jednaka od';
-$labels['valueislessthan'] = 'vrijednost je manja od';
-$labels['valueislessthanequal'] = 'vrijednost je manja ili jednaka od';
-$labels['valueequals'] = 'vrijednost je jednaka';
-$labels['valuenotequals'] = 'vrijednost nije jednaka';
-$labels['setflags'] = 'Postavi oznake na poruku';
-$labels['addflags'] = 'Dodaj oznake na poruku';
-$labels['removeflags'] = 'Ukloni oznake sa poruke';
-$labels['flagread'] = 'Pročitana';
-$labels['flagdeleted'] = 'Obrisana';
-$labels['flaganswered'] = 'Odgovorena';
-$labels['flagflagged'] = 'Označena';
-$labels['flagdraft'] = 'Predložak';
-$labels['setvariable'] = 'Postavi varijablu';
-$labels['setvarname'] = 'Ime varijable:';
-$labels['setvarvalue'] = 'Vrijednost varijable:';
-$labels['setvarmodifiers'] = 'Modifikatori:';
-$labels['varlower'] = 'mala slova';
-$labels['varupper'] = 'velika slova';
-$labels['varlowerfirst'] = 'prvo slovo malo';
-$labels['varupperfirst'] = 'prvo slovo veliko';
-$labels['varquotewildcard'] = 'Citiraj specijalne znakove';
-$labels['varlength'] = 'duljina';
-$labels['notify'] = 'Pošalji obavijest';
-$labels['notifyimportance'] = 'Važnost:';
-$labels['notifyimportancelow'] = 'niska';
-$labels['notifyimportancenormal'] = 'normalna';
-$labels['notifyimportancehigh'] = 'visoka';
-$labels['filtercreate'] = 'Stvori filter';
-$labels['usedata'] = 'Koristi podatke za filter:';
-$labels['nextstep'] = 'Idući korak';
-$labels['...'] = '…';
-$labels['currdate'] = 'Današnji datum';
-$labels['datetest'] = 'Datum';
-$labels['dateheader'] = 'zaglavlje:';
-$labels['year'] = 'godina';
-$labels['month'] = 'mjesec';
-$labels['day'] = 'dan';
-$labels['date'] = 'datum (yyyy-mm-dd)';
-$labels['julian'] = 'datum (julijanski)';
-$labels['hour'] = 'sat';
-$labels['minute'] = 'minute';
-$labels['second'] = 'sekunde';
-$labels['time'] = 'vrijeme (hh:mm:ss)';
-$labels['iso8601'] = 'datum (ISO8601)';
-$labels['std11'] = 'datum (RFC2822)';
-$labels['zone'] = 'vremenska zona';
-$labels['weekday'] = 'dan u tjednu (0-6)';
-$labels['advancedopts'] = 'Napredne postavke';
-$labels['body'] = 'Tijelo poruke';
-$labels['address'] = 'adresa';
-$labels['envelope'] = 'omotnica';
-$labels['modifier'] = 'modificirao:';
-$labels['text'] = 'tekst';
-$labels['undecoded'] = 'nedekodirano (raw)';
-$labels['contenttype'] = 'tip sadržaja';
-$labels['modtype'] = 'tip:';
-$labels['allparts'] = 'sve';
-$labels['domain'] = 'domena';
-$labels['localpart'] = 'lokalni dio';
-$labels['user'] = 'korisnik';
-$labels['detail'] = 'detalj';
-$labels['comparator'] = 'usporedio:';
-$labels['default'] = 'preddefinirano';
-$labels['octet'] = 'strogo (oktet)';
-$labels['asciicasemap'] = 'neosjetljivo na veličinu slova (ascii-casemap)';
-$labels['asciinumeric'] = 'numerički (ascii-numeric)';
-$labels['index'] = 'indeks:';
-$labels['indexlast'] = 'unatrag';
-$labels['vacation.advanced'] = 'Napredne postavke';
-$labels['vacation.subject'] = 'Naslov';
-$labels['vacation.body'] = 'Tijelo poruke';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.saving'] = 'Spremanje podataka...';
-$messages['filterunknownerror'] = 'Nepoznata greška na poslužitelju';
-$messages['filterconnerror'] = 'Nemoguće spajanje na poslužitelj (managesieve)';
-$messages['filterdeleteerror'] = 'Nemoguće brisanje filtera. Greška na poslužitelju.';
-$messages['filterdeleted'] = 'Filter je uspješno obrisan';
-$messages['filtersaved'] = 'Filter je uspješno spremljen';
-$messages['filtersaveerror'] = 'Nemoguće spremiti filter. Greška na poslužitelju.';
-$messages['filterdeleteconfirm'] = 'Sigurno želite obrisati odabrani filter?';
-$messages['ruledeleteconfirm'] = 'Jeste li sigurni da želite obrisati odabrana pravila?';
-$messages['actiondeleteconfirm'] = 'Jeste li sigurni da želite obrisati odabrane akcije?';
-$messages['forbiddenchars'] = 'Nedozvoljeni znakovi u polju';
-$messages['cannotbeempty'] = 'Polje nesmije biti prazno';
-$messages['ruleexist'] = 'Filter sa zadanim imenom već postoji.';
-$messages['setactivateerror'] = 'Nemoguće aktivirati odabranu grupu filtera. Greška na poslužitelju.';
-$messages['setdeactivateerror'] = 'Nemoguće deaktivirati odabranu grupu filtera. Greška na poslužitelju.';
-$messages['setdeleteerror'] = 'Nemoguće obrisati odabranu grupu filtera. Greška na poslužitelju.';
-$messages['setactivated'] = 'Grupa filtera je uspješno aktivirana';
-$messages['setdeactivated'] = 'Grupa filtera je uspješno deaktivirana';
-$messages['setdeleted'] = 'Grupa filtera je uspješno obrisana';
-$messages['setdeleteconfirm'] = 'Jeste li sigurni da želite obrisati odabranu grupu filtera?';
-$messages['setcreateerror'] = 'Nemoguće stvoriti grupu filtera. Greška na poslužitelju.';
-$messages['setcreated'] = 'Grupa filtera je uspješno stvorena';
-$messages['activateerror'] = 'Nije moguće omogućiti odabrani filter(e). Greška poslužitelja.';
-$messages['deactivateerror'] = 'Nije moguće onemogućiti odabrane filter(e). Greška poslužitelja.';
-$messages['deactivated'] = 'Filter(i) omogućen(i) uspješno.';
-$messages['activated'] = 'Filter(i) onemogućen(i) uspješno.';
-$messages['moved'] = 'Filter uspješno premješten.';
-$messages['moveerror'] = 'Nije moguće premjestiti odabrani filter. Greška poslužitelja.';
-$messages['nametoolong'] = 'Nemoguće napraviti grupu filtera. Naziv je predugačak';
-$messages['namereserved'] = 'Rezervirano ime.';
-$messages['setexist'] = 'Skup već postoji.';
-$messages['nodata'] = 'Barem jedan pozicija mora biti odabrana!';
-$messages['invaliddateformat'] = 'Neispravan datum ili dio datuma';
-$messages['saveerror'] = 'Nemoguće spremiti podatke. Greška na poslužitelju.';
-?>
diff --git a/lib/plugins/managesieve/localization/hu_HU.inc b/lib/plugins/managesieve/localization/hu_HU.inc
deleted file mode 100644
index eae7650..0000000
--- a/lib/plugins/managesieve/localization/hu_HU.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Üzenetszűrők';
-$labels['managefilters'] = 'Bejövő üzenetek szűrői';
-$labels['filtername'] = 'Szűrő neve';
-$labels['newfilter'] = 'Új szűrő';
-$labels['filteradd'] = 'Szűrő hozzáadása';
-$labels['filterdel'] = 'Szűrő törlése';
-$labels['moveup'] = 'Mozgatás felfelé';
-$labels['movedown'] = 'Mozgatás lefelé';
-$labels['filterallof'] = 'A következők szabályok mind illeszkedjenek';
-$labels['filteranyof'] = 'A következő szabályok bármelyike illeszkedjen';
-$labels['filterany'] = 'Minden üzenet illeszkedjen';
-$labels['filtercontains'] = 'tartalmazza';
-$labels['filternotcontains'] = 'nem tartalmazza';
-$labels['filteris'] = 'megegyezik';
-$labels['filterisnot'] = 'nem egyezik meg';
-$labels['filterexists'] = 'létezik';
-$labels['filternotexists'] = 'nem létezik';
-$labels['filtermatches'] = 'kifejezéssel egyezők';
-$labels['filternotmatches'] = 'kifejezéssel nem egyezők';
-$labels['filterregex'] = 'reguláris kifejezéssel egyezők';
-$labels['filternotregex'] = 'reguláris kifejezéssel nem egyezők';
-$labels['filterunder'] = 'alatta';
-$labels['filterover'] = 'felette';
-$labels['addrule'] = 'Szabály hozzáadása';
-$labels['delrule'] = 'Szabály törlése';
-$labels['messagemoveto'] = 'Üzenet áthelyezése ide:';
-$labels['messageredirect'] = 'Üzenet továbbítása ide:';
-$labels['messagecopyto'] = 'Üzenet másolása';
-$labels['messagesendcopy'] = 'Másolat kűldése az üzenetből';
-$labels['messagereply'] = 'Válaszüzenet küldése (autoreply)';
-$labels['messagedelete'] = 'Üzenet törlése';
-$labels['messagediscard'] = 'Válaszüzenet küldése, a levél törlése';
-$labels['messagekeep'] = 'Tartsa az üzenetet a beérkező leveleknél';
-$labels['messagesrules'] = 'Az adott tulajdonságú beérkezett üzenetekre:';
-$labels['messagesactions'] = '... a következő műveletek végrehajtása:';
-$labels['add'] = 'Hozzáadás';
-$labels['del'] = 'Törlés';
-$labels['sender'] = 'Feladó';
-$labels['recipient'] = 'Címzett';
-$labels['vacationaddr'] = 'További e-mail címeim:';
-$labels['vacationdays'] = 'Válaszüzenet küldése ennyi naponként:';
-$labels['vacationinterval'] = 'Milyen gyakran küld üzeneteket:';
-$labels['vacationreason'] = 'Levél szövege (automatikus válasz):';
-$labels['vacationsubject'] = 'Üzenet tárgya:';
-$labels['days'] = 'napok';
-$labels['seconds'] = 'másodpercek';
-$labels['rulestop'] = 'Műveletek végrehajtásának befejezése';
-$labels['enable'] = 'Bekapcsol/Kikapcsol';
-$labels['filterset'] = 'Szűrök készlet';
-$labels['filtersets'] = 'Szűrő készletek';
-$labels['filtersetadd'] = 'Szűrő hozzáadása a készlethez';
-$labels['filtersetdel'] = 'Az aktuális szűrő készlet törlése';
-$labels['filtersetact'] = 'Az aktuális szűrő készlet engedélyezése';
-$labels['filtersetdeact'] = 'Az aktuális szűrő készlet tiltása';
-$labels['filterdef'] = 'Szűrő definíció';
-$labels['filtersetname'] = 'Szűrő készlet neve';
-$labels['newfilterset'] = 'Új szűrő készlet';
-$labels['active'] = 'aktív';
-$labels['none'] = 'nincs';
-$labels['fromset'] = 'készletből';
-$labels['fromfile'] = 'fájlból';
-$labels['filterdisabled'] = 'Szűrő kikapcsolása';
-$labels['countisgreaterthan'] = 'a számláló nagyobb mint';
-$labels['countisgreaterthanequal'] = 'a számláló nagyobb vagy egyenlő';
-$labels['countislessthan'] = 'a számláló kissebb mint';
-$labels['countislessthanequal'] = 'a számláló kissebb vagy egyenlő';
-$labels['countequals'] = 'a számláló egyenlő';
-$labels['countnotequals'] = 'össze számolva nem egyenlő';
-$labels['valueisgreaterthan'] = 'az érték nagyobb mint';
-$labels['valueisgreaterthanequal'] = 'az érték nagyobb vagy egyenlő';
-$labels['valueislessthan'] = 'az érték kisebb mint';
-$labels['valueislessthanequal'] = 'az érték kisebb vagy egyenlő';
-$labels['valueequals'] = 'az érték megegyzik';
-$labels['valuenotequals'] = 'az értéke nem azonos';
-$labels['setflags'] = 'Jelzők beállítása az üzeneten';
-$labels['addflags'] = 'Jelző hozzáadása az üzenethez';
-$labels['removeflags'] = 'Jelzők eltávolítása az üzenetből';
-$labels['flagread'] = 'Olvasás';
-$labels['flagdeleted'] = 'Törölt';
-$labels['flaganswered'] = 'Megválaszolt';
-$labels['flagflagged'] = 'Megjelölt';
-$labels['flagdraft'] = 'Vázlat';
-$labels['setvariable'] = 'Változó beállítása';
-$labels['setvarname'] = 'Változó neve:';
-$labels['setvarvalue'] = 'Változó értéke:';
-$labels['setvarmodifiers'] = 'Módosítók';
-$labels['varlower'] = 'kisbetű';
-$labels['varupper'] = 'nagybetű';
-$labels['varlowerfirst'] = 'első karakter kisbetű';
-$labels['varupperfirst'] = 'első karakter nagybetű';
-$labels['varquotewildcard'] = 'speciális karakterek idézése';
-$labels['varlength'] = 'hossz';
-$labels['notify'] = 'Értesítés küldése';
-$labels['notifytarget'] = 'Értesítés célja:';
-$labels['notifymessage'] = 'Értesítési üzenet (opcionális):';
-$labels['notifyoptions'] = 'Értesítés opcióik (opcionális):';
-$labels['notifyfrom'] = 'Értesítés feladója (opcionális):';
-$labels['notifyimportance'] = 'Fontosság:';
-$labels['notifyimportancelow'] = 'alacsony';
-$labels['notifyimportancenormal'] = 'normál';
-$labels['notifyimportancehigh'] = 'magas';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Telefonszám';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Szűrő létrehozása';
-$labels['usedata'] = 'A következő adatok használata a szűrőben';
-$labels['nextstep'] = 'Következő lépés';
-$labels['...'] = '…';
-$labels['currdate'] = 'Mai dátum';
-$labels['datetest'] = 'Dátum';
-$labels['dateheader'] = 'fejléc:';
-$labels['year'] = 'év';
-$labels['month'] = 'hónap';
-$labels['day'] = 'nap';
-$labels['date'] = 'dátum (éééé-hh-nn)';
-$labels['julian'] = 'dátum ( julián)';
-$labels['hour'] = 'óra';
-$labels['minute'] = 'perc';
-$labels['second'] = 'másodperc';
-$labels['time'] = 'idő (óó:pp:ms)';
-$labels['iso8601'] = 'dátum (ISO8601)';
-$labels['std11'] = 'dátum (RFC2822)';
-$labels['zone'] = 'idő-zóna';
-$labels['weekday'] = 'hét napjai (0-6)';
-$labels['advancedopts'] = 'Haladó beállítások';
-$labels['body'] = 'Levéltörzs';
-$labels['address'] = 'cím';
-$labels['envelope'] = 'boriték';
-$labels['modifier'] = 'módosító:';
-$labels['text'] = 'szöveg';
-$labels['undecoded'] = 'kódolatlan(nyers)';
-$labels['contenttype'] = 'tartalom tipusa';
-$labels['modtype'] = 'típus:';
-$labels['allparts'] = 'összes';
-$labels['domain'] = 'domain';
-$labels['localpart'] = 'név rész';
-$labels['user'] = 'felhasználó';
-$labels['detail'] = 'részlet';
-$labels['comparator'] = 'összehasonlító';
-$labels['default'] = 'alapértelmezett';
-$labels['octet'] = 'strict (octet)';
-$labels['asciicasemap'] = 'kis-nagybetüre nem érzékeny (ascii-casemap)';
-$labels['asciinumeric'] = 'számszerü (ascii-numeric)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'visszafelé';
-$labels['vacation'] = 'Vakáció';
-$labels['vacation.reply'] = 'Válasz az üzenetre';
-$labels['vacation.advanced'] = 'Haladó beállítások';
-$labels['vacation.subject'] = 'Tárgy';
-$labels['vacation.body'] = 'Törzs';
-$labels['vacation.start'] = 'Szünidő kezdete';
-$labels['vacation.end'] = 'Szünidő vége';
-$labels['vacation.status'] = 'Állapot';
-$labels['vacation.on'] = 'Be';
-$labels['vacation.off'] = 'Ki';
-$labels['vacation.addresses'] = 'További címeim';
-$labels['vacation.interval'] = 'Válasz intervallum';
-$labels['vacation.after'] = 'Rakd a szabadság szabályt ez után ';
-$labels['vacation.saving'] = 'Adatok mentése...';
-$labels['vacation.action'] = 'Beérkező üzenet akció';
-$labels['vacation.keep'] = 'Megtartás';
-$labels['vacation.discard'] = 'Érvénytelenít';
-$labels['vacation.redirect'] = 'Átírányítás ide';
-$labels['vacation.copy'] = 'Másolat kűldése ide';
-$labels['arialabelfiltersetactions'] = 'Szűrő készlet müveletek';
-$labels['arialabelfilteractions'] = 'Szűrő müveletek';
-$labels['arialabelfilterform'] = 'Szűrő tulajdonságai';
-$labels['ariasummaryfilterslist'] = 'Szűrők listája';
-$labels['ariasummaryfiltersetslist'] = 'Szűrő készletek listája';
-$labels['filterstitle'] = 'Bejövő üzenetek szűrőinek szerkesztése';
-$labels['vacationtitle'] = 'Irodán kiívül szabász szerkesztése';
-$messages['filterunknownerror'] = 'Ismeretlen szerverhiba';
-$messages['filterconnerror'] = 'Nem tudok a szűrőszerverhez kapcsolódni';
-$messages['filterdeleteerror'] = 'A szűrőt nem lehet törölni. Szerverhiba történt';
-$messages['filterdeleted'] = 'A szűrő törlése sikeres';
-$messages['filtersaved'] = 'A szűrő mentése sikeres';
-$messages['filtersaveerror'] = 'A szűrő mentése sikertelen. Szerverhiba történt';
-$messages['filterdeleteconfirm'] = 'Biztosan törli ezt a szűrőt?';
-$messages['ruledeleteconfirm'] = 'Biztosan törli ezt a szabályt?';
-$messages['actiondeleteconfirm'] = 'Biztosan törli ezt a műveletet?';
-$messages['forbiddenchars'] = 'Érvénytelen karakter a mezőben';
-$messages['cannotbeempty'] = 'A mező nem lehet üres';
-$messages['ruleexist'] = 'Már van ilyen névvel elmentett szűrő.';
-$messages['setactivateerror'] = 'A kiválasztott szűrő készletet nem sikerült engedélyezni. Szerver hiba történt.';
-$messages['setdeactivateerror'] = 'A kiválasztott szűrő készletet nem sikerült tiltani. Szerver hiba történt.';
-$messages['setdeleteerror'] = 'Nem sikerült a kiválasztott szűrő készletet törölni. Szerver hiba történt.';
-$messages['setactivated'] = 'A filter készlet engedélyezése sikeresen végrehajtódott.';
-$messages['setdeactivated'] = 'A filter készlet tiltása sikeresen végrehajtódott.';
-$messages['setdeleted'] = 'A filter készlet törlése sikeresen végrehajtódott.';
-$messages['setdeleteconfirm'] = 'Biztosan törölni szeretnéd a kiválasztott szűrő készleteket?';
-$messages['setcreateerror'] = 'Nem sikerült létrehozni a szűrő készletet. Szerver hiba történt.';
-$messages['setcreated'] = 'A szűrő készlet sikeresen létrejött.';
-$messages['activateerror'] = 'Nem sikerült engedélyezni a kiválasztott szűrö(k)et. Szerver hiba történt.';
-$messages['deactivateerror'] = 'Nem sikerült kikapcsolni a kiválasztott szűrő(ke)t. Szerver hiba történt.';
-$messages['deactivated'] = 'Szűrő(k) sikeresen bekapcsolva.';
-$messages['activated'] = 'Szűrő(k) sikeresen kikapcsolva.';
-$messages['moved'] = 'A szűrő sikeresen áthelyezve.';
-$messages['moveerror'] = 'Az áthelyezés nem sikerült. Szerver hiba történt.';
-$messages['nametoolong'] = 'Túll hosszu név';
-$messages['namereserved'] = 'Nem használható (foglalt) név-';
-$messages['setexist'] = 'A készlet már létezik.';
-$messages['nodata'] = 'Legalább egyet ki kell választani.';
-$messages['invaliddateformat'] = 'hibás dátum formátum';
-$messages['saveerror'] = 'Az adat mentése sikertelen. Szerverhiba történt';
-$messages['vacationsaved'] = 'Vakáció adatai sikeresen elmentve.';
-$messages['emptyvacationbody'] = 'A vakácíó üzenet szövegtörzse kötelező!';
-?>
diff --git a/lib/plugins/managesieve/localization/hy_AM.inc b/lib/plugins/managesieve/localization/hy_AM.inc
deleted file mode 100644
index 5a520f4..0000000
--- a/lib/plugins/managesieve/localization/hy_AM.inc
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Զտիչներ';
-$labels['managefilters'] = 'Կառավարել ստացվող նամակների զտիչները';
-$labels['filtername'] = 'Զտիչի անուն';
-$labels['newfilter'] = 'Նոր զտիչ';
-$labels['filteradd'] = 'Ավելացնել զտիչ';
-$labels['filterdel'] = 'Ջնջել զտիչը';
-$labels['moveup'] = 'Բարձրացնել';
-$labels['movedown'] = 'Իջեցնել';
-$labels['filterallof'] = 'հետևյալ բոլոր պահանջներին համապատասխանող';
-$labels['filteranyof'] = 'հետևյալ պահանջներից ցանկացածին համապատասխանող';
-$labels['filterany'] = 'բոլոր հաղորդագրությունները';
-$labels['filtercontains'] = 'պարունակում է';
-$labels['filternotcontains'] = 'չի պարունակում';
-$labels['filteris'] = 'հավասար է';
-$labels['filterisnot'] = 'հավասար չէ';
-$labels['filterexists'] = 'գոյություն ունի';
-$labels['filternotexists'] = 'գոյություն չունի';
-$labels['filtermatches'] = 'բավարարում է արտահայտությանը';
-$labels['filternotmatches'] = 'չի բավարարում արտահայտությանը';
-$labels['filterregex'] = 'բավարարում է կանոնավոր արտահայտությանը';
-$labels['filternotregex'] = 'չի բավարարում կանոնավոր արտահայտությանը';
-$labels['filterunder'] = 'Õ¿Õ¡Õ¯';
-$labels['filterover'] = 'վրա';
-$labels['addrule'] = 'Ավելացնել պայմանը';
-$labels['delrule'] = 'Ջնջել պայմանը';
-$labels['messagemoveto'] = 'Տեղափոխել հաղորդագրությունը';
-$labels['messageredirect'] = 'Վերահասցեվորել հաղորդագրությունը';
-$labels['messagecopyto'] = 'Պատճենել հաղորդագրությունը';
-$labels['messagesendcopy'] = 'Ուղարկել հաղորդագրության պատճեն';
-$labels['messagereply'] = 'Պատասխանել հաղորդագրությամբ';
-$labels['messagedelete'] = 'Ջնջել հաղորդագրությունը';
-$labels['messagediscard'] = 'Հեռացնել, հաղորդագրությամբ';
-$labels['messagesrules'] = 'Ստացվող հաղորդագրությունների համար';
-$labels['messagesactions'] = '…կատարել հետևյալ գործողությունները.';
-$labels['add'] = 'Ավելացնել';
-$labels['del'] = 'Ջնջել';
-$labels['sender'] = 'Ուղարկող';
-$labels['recipient'] = 'Ստացող';
-$labels['vacationdays'] = 'Ինչ հաճախությամբ ուղարկել հաղորդագրությունները (օրեր)`';
-$labels['vacationreason'] = 'Հաղորդագրության բովանդակություն (արձակուրդի պատճառ)`';
-$labels['vacationsubject'] = 'Հաղորդագրության վերնագիր`';
-$labels['rulestop'] = 'Դադարել պայմանների ստուգումը';
-$labels['enable'] = 'Միացնել/Անջատել';
-$labels['filterset'] = 'Զտիչների համալիր';
-$labels['filtersets'] = 'Զտիչների համալիրներ';
-$labels['filtersetadd'] = 'Ավելացնել զտիչների համալիր';
-$labels['filtersetdel'] = 'Ջնջել առկա զտիչների համալիրը';
-$labels['filtersetact'] = 'Միացնել առկա զտիչների համալիրը';
-$labels['filtersetdeact'] = 'Անջատել առկա զտիչների համալիրը';
-$labels['filterdef'] = 'Զտիչի սահմանում';
-$labels['filtersetname'] = 'Զտիչների համալիրի անուն';
-$labels['newfilterset'] = 'Նոր զտիչների համալիր';
-$labels['active'] = 'Õ¡Õ¯Õ¿Õ«Õ¾';
-$labels['none'] = 'Õ¸Õ¹ Õ´Õ¥Õ¯Õ¨';
-$labels['fromset'] = 'համալիրից';
-$labels['fromfile'] = 'ֆայլից';
-$labels['filterdisabled'] = 'Ô¶Õ¿Õ«Õ¹Õ¨ Õ¡Õ¶Õ»Õ¡Õ¿Õ¾Õ¡Õ® Õ§';
-$labels['countisgreaterthan'] = 'քանակը գերազանցում է';
-$labels['countisgreaterthanequal'] = 'քանակը գերազանցում է կամ հավասար է';
-$labels['countislessthan'] = 'քանակը պակաս է';
-$labels['countislessthanequal'] = 'քանակը պակաս է կամ հավասար է';
-$labels['countequals'] = 'քանակը հավասար է';
-$labels['valueisgreaterthan'] = 'արժեքը գերազանցում է';
-$labels['valueisgreaterthanequal'] = 'արժեքը գերազանցում է կամ հավասար է';
-$labels['valueislessthan'] = 'արժեքը պակաս է';
-$labels['valueislessthanequal'] = 'արժեքը պակաս է կամ հավասար է';
-$labels['valueequals'] = 'արժեքը հավասար է';
-$labels['setflags'] = 'Հաղորդագրությունը նշել որպես';
-$labels['addflags'] = 'Ավելացնել նշաններ հաղորդագրությանը';
-$labels['removeflags'] = 'Հեռացնել նշաններ հաղորդագրությունից';
-$labels['flagread'] = 'Ընթերցված';
-$labels['flagdeleted'] = 'Ջնջված';
-$labels['flaganswered'] = 'Պատասխանված';
-$labels['flagflagged'] = 'Նշված';
-$labels['flagdraft'] = 'Սևագիր';
-$labels['filtercreate'] = 'Ստեղծել զտիչ';
-$labels['usedata'] = 'Զտիչում օգտագործել հետևյալ տեղեկությունը.';
-$labels['nextstep'] = 'Հաջորդ քայլ';
-$labels['...'] = '…';
-$labels['advancedopts'] = 'Հավելյալ ընտրանքներ';
-$labels['body'] = 'Մարմին';
-$labels['address'] = 'հասցե';
-$labels['envelope'] = 'ծրար';
-$labels['modifier'] = 'փոփոխիչ`';
-$labels['text'] = 'տեքստ';
-$labels['undecoded'] = 'մաքուր';
-$labels['contenttype'] = 'բովանդակության տիպ';
-$labels['modtype'] = 'Õ¿Õ«Õº`';
-$labels['allparts'] = 'բոլորը';
-$labels['domain'] = 'տիրույթ';
-$labels['localpart'] = 'Õ¬Õ¸Õ¯Õ¡Õ¬ Õ´Õ¡Õ½';
-$labels['user'] = 'օգտվող';
-$labels['detail'] = 'Õ´Õ¡Õ½';
-$labels['comparator'] = 'Õ°Õ¡Õ´Õ¥Õ´Õ¡Õ¿Õ«Õ¹`';
-$labels['default'] = 'լռակյաց';
-$labels['octet'] = 'անփոփոխ (օկտետ)';
-$labels['asciicasemap'] = 'case insensitive (ascii-casemap)';
-$labels['asciinumeric'] = 'numeric (ascii-numeric)';
-$messages['filterunknownerror'] = 'Սերվերի անհայտ սխալ';
-$messages['filterconnerror'] = 'Սերվերի հետ կապի խնդիր։';
-$messages['filterdeleted'] = 'Զտիչը ջնջվեց։';
-$messages['filtersaved'] = 'Զտիչը պահպանվեց։';
-$messages['filterdeleteconfirm'] = 'Դուք իսկապե՞ս ցանկանում եք ջնջել նշված զտիչը։';
-$messages['ruledeleteconfirm'] = 'Դուք իսկապե՞ս ցանկանում եք ջնջել նշված պայմանը։';
-$messages['actiondeleteconfirm'] = 'Դուք իսկապե՞ս ցանկանում եք ջնջել նշված գործողությունը։';
-$messages['forbiddenchars'] = 'Դաշտում առկա են արգելված նիշեր։';
-$messages['cannotbeempty'] = 'Դաշտը դատարկ չի կարող լինել։';
-$messages['ruleexist'] = 'Տրված անունով զտիչ արդեն գոյություն ունի։';
-$messages['setactivated'] = 'Զտիչների համալիրը միացված է։';
-$messages['setdeactivated'] = 'Զտիչների համալիրը անջատված է։';
-$messages['setdeleted'] = 'Զտիչների համալիրը ջնջված է։';
-$messages['setdeleteconfirm'] = 'Դուք իսկապե՞ս ցանկանում եք ջնջել նշված զտիչների համալիրը։';
-$messages['setcreated'] = 'Զտիչների համալիրը ստեղծված է։';
-$messages['deactivated'] = 'Զտիչի միացված է։';
-$messages['activated'] = 'Զտիչի անջատված է։';
-$messages['moved'] = 'Զտիչի տեղափոխված է։';
-$messages['nametoolong'] = 'Անունը չափազանց երկար է։';
-$messages['namereserved'] = 'Անթույլատրելի անուն։';
-$messages['setexist'] = 'Համալիրը արդեն գոյություն ունի։';
-$messages['nodata'] = 'Պահանջվում է նշել գոնե մեկ դիրք։';
-?>
diff --git a/lib/plugins/managesieve/localization/ia.inc b/lib/plugins/managesieve/localization/ia.inc
deleted file mode 100644
index c0177d0..0000000
--- a/lib/plugins/managesieve/localization/ia.inc
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtros';
-$labels['filteradd'] = 'Adder filtro';
-$labels['filterdel'] = 'Deler filtro';
-?>
diff --git a/lib/plugins/managesieve/localization/id_ID.inc b/lib/plugins/managesieve/localization/id_ID.inc
deleted file mode 100644
index b445ef6..0000000
--- a/lib/plugins/managesieve/localization/id_ID.inc
+++ /dev/null
@@ -1,221 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filter';
-$labels['managefilters'] = 'Atur filter email masuk';
-$labels['filtername'] = 'Nama filter';
-$labels['newfilter'] = 'Filter baru';
-$labels['filteradd'] = 'Tambah filter';
-$labels['filterdel'] = 'Hapus filter';
-$labels['moveup'] = 'Pindah ke atas';
-$labels['movedown'] = 'Pindah ke bawah';
-$labels['filterallof'] = 'cocok dengan semua aturan berikut ini';
-$labels['filteranyof'] = 'cocok dengan aturan manapun';
-$labels['filterany'] = 'semua pesan';
-$labels['filtercontains'] = 'berisi';
-$labels['filternotcontains'] = 'tidak berisi';
-$labels['filteris'] = 'sama dengan';
-$labels['filterisnot'] = 'tidak sama dengan';
-$labels['filterexists'] = 'ada';
-$labels['filternotexists'] = 'tidak ada';
-$labels['filtermatches'] = 'ekspresi yg cocok';
-$labels['filternotmatches'] = 'ekspresi yg tidak cocok';
-$labels['filterregex'] = 'cocok dengan ekspresi reguler';
-$labels['filternotregex'] = 'tidak cocok dengan ekspresi reguler';
-$labels['filterunder'] = 'di bawah';
-$labels['filterover'] = 'di atas';
-$labels['addrule'] = 'Tambah aturan';
-$labels['delrule'] = 'Hapus aturan';
-$labels['messagemoveto'] = 'Pindah pesan ke';
-$labels['messageredirect'] = 'Alihkan pesan ke';
-$labels['messagecopyto'] = 'Salin pesan ke';
-$labels['messagesendcopy'] = 'Kirim salinan pesan ke';
-$labels['messagereply'] = 'balas dengan pesan';
-$labels['messagedelete'] = 'Hapus pesan';
-$labels['messagediscard'] = 'Buang dengan pesan';
-$labels['messagekeep'] = 'Biarkan pesan tetap didalam kotak surat';
-$labels['messagesrules'] = 'Untuk email masuk:';
-$labels['messagesactions'] = '...lakukan tindakan berikut';
-$labels['add'] = 'Tambah';
-$labels['del'] = 'Hapus';
-$labels['sender'] = 'Pengirim';
-$labels['recipient'] = 'Penerima';
-$labels['vacationaddr'] = 'Alamat email tambahan saya:';
-$labels['vacationdays'] = 'Seberapa sering mengirim pesan (dalam hari):';
-$labels['vacationinterval'] = 'Seberapa sering untuk pengiriman pesan:';
-$labels['vacationreason'] = 'Isi pesan (alasan liburan):';
-$labels['vacationsubject'] = 'Judul pesan:';
-$labels['days'] = 'hari';
-$labels['seconds'] = 'detik';
-$labels['rulestop'] = 'Berhenti mengevaluasi aturan';
-$labels['enable'] = 'Aktifkan/Non-Aktifkan';
-$labels['filterset'] = 'Himpunan filter';
-$labels['filtersets'] = 'Himpunan banyak filter';
-$labels['filtersetadd'] = 'Tambahkan himpunan filter';
-$labels['filtersetdel'] = 'Hapus himpunan filter yang sekarang';
-$labels['filtersetact'] = 'Aktifkan himpunan filter ayng sekarang';
-$labels['filtersetdeact'] = 'Matikan himpunan filter ayng sekarang';
-$labels['filterdef'] = 'Definisi filter';
-$labels['filtersetname'] = 'Nama himpunan filter';
-$labels['newfilterset'] = 'Himpunan filter baru';
-$labels['active'] = 'aktif';
-$labels['none'] = 'nihil';
-$labels['fromset'] = 'dari himpunan';
-$labels['fromfile'] = 'dari berkas';
-$labels['filterdisabled'] = 'Filter dimatikan';
-$labels['countisgreaterthan'] = 'penghitungan lebih besar dari';
-$labels['countisgreaterthanequal'] = 'penghitungan lebih besa dari atau sama dengan';
-$labels['countislessthan'] = 'penghitungan lebih kecil dari';
-$labels['countislessthanequal'] = 'penghitungan lebih kecil dari atau sama dengan';
-$labels['countequals'] = 'penghitungan sama dengan';
-$labels['countnotequals'] = 'penghitungan tidak sama dengan';
-$labels['valueisgreaterthan'] = 'nilai lebih besar dari';
-$labels['valueisgreaterthanequal'] = 'nilai lebih besar dari atau sama dengan';
-$labels['valueislessthan'] = 'nilai lebih kecil dari';
-$labels['valueislessthanequal'] = 'nilai lebih kecil dari atau sama dengan';
-$labels['valueequals'] = 'nilai sama dengan';
-$labels['valuenotequals'] = 'nilai tidak sadengan';
-$labels['setflags'] = 'Atur tanda pada pesan';
-$labels['addflags'] = 'Berikan tanda pada pesan';
-$labels['removeflags'] = 'Cabut tanda dari pesan';
-$labels['flagread'] = 'Baca';
-$labels['flagdeleted'] = 'Terhapus';
-$labels['flaganswered'] = 'Terjawab';
-$labels['flagflagged'] = 'Ditandai';
-$labels['flagdraft'] = 'Konsep';
-$labels['setvariable'] = 'Set variabel';
-$labels['setvarname'] = 'Nama variabel:';
-$labels['setvarvalue'] = 'Nilai variabel';
-$labels['setvarmodifiers'] = 'Pengubah';
-$labels['varlower'] = 'huruf kecil';
-$labels['varupper'] = 'huruf besar';
-$labels['varlowerfirst'] = 'karakter pertama huruf kecil';
-$labels['varupperfirst'] = 'karakter pertama huruf besar';
-$labels['varquotewildcard'] = 'kutip karakter khusus';
-$labels['varlength'] = 'panjang';
-$labels['notify'] = 'Kirim pemberitahuan';
-$labels['notifytarget'] = 'Pemberitahuan yang dituju:';
-$labels['notifymessage'] = 'Pemberitahuan pesan (pilihan):';
-$labels['notifyoptions'] = 'Pemberitahuan untuk beberapa pilihan (pilihan):';
-$labels['notifyfrom'] = 'Pemberitahuan ke pengirim (tidak harus):';
-$labels['notifyimportance'] = 'Tingkat kepentingan:';
-$labels['notifyimportancelow'] = 'rendah';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'tinggi';
-$labels['notifymethodmailto'] = 'Surat Elektronik / Email';
-$labels['notifymethodtel'] = 'Telepon';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Buat filter';
-$labels['usedata'] = 'Gunakan data berikut dalam filter:';
-$labels['nextstep'] = 'Langkah Selanjutnya';
-$labels['...'] = '...';
-$labels['currdate'] = 'Tanggal sekarang';
-$labels['datetest'] = 'Tanggal';
-$labels['dateheader'] = 'header / tajuk:';
-$labels['year'] = 'tahun';
-$labels['month'] = 'bulan';
-$labels['day'] = 'hari';
-$labels['date'] = 'tanggal (yyyy-mm-dd)';
-$labels['julian'] = 'tanggal (kalender julian)';
-$labels['hour'] = 'jam';
-$labels['minute'] = 'menit';
-$labels['second'] = 'detik';
-$labels['time'] = 'waktu :(hh:mm:ss)';
-$labels['iso8601'] = 'tanggal (ISO8601)';
-$labels['std11'] = 'tanggal (RFC2822)';
-$labels['zone'] = 'zona-waktu';
-$labels['weekday'] = 'hari kerja (0-6)';
-$labels['advancedopts'] = 'Pilihan lanjutan';
-$labels['body'] = 'Isi';
-$labels['address'] = 'alamat';
-$labels['envelope'] = 'amplop';
-$labels['modifier'] = 'peubah:';
-$labels['text'] = 'teks';
-$labels['undecoded'] = 'praterjemahan (mentah)';
-$labels['contenttype'] = 'tipe isi';
-$labels['modtype'] = 'tipe:';
-$labels['allparts'] = 'semua';
-$labels['domain'] = 'domain';
-$labels['localpart'] = 'bagian lokal';
-$labels['user'] = 'pengguna';
-$labels['detail'] = 'rinci';
-$labels['comparator'] = 'pembanding:';
-$labels['default'] = 'standar';
-$labels['octet'] = 'ketat (oktet)';
-$labels['asciicasemap'] = 'case insensitive (ascii-casemap)';
-$labels['asciinumeric'] = 'numeric (ascii-numeric)';
-$labels['index'] = 'indeks:';
-$labels['indexlast'] = 'mundur:';
-$labels['vacation'] = 'Liburan';
-$labels['vacation.reply'] = 'Balas pesan';
-$labels['vacation.advanced'] = 'Pengaturan Lanjutan';
-$labels['vacation.subject'] = 'Judul';
-$labels['vacation.body'] = 'Isi';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.on'] = 'Nyala';
-$labels['vacation.off'] = 'Mati';
-$labels['vacation.addresses'] = 'Alamat email tambahan saya';
-$labels['vacation.interval'] = 'Balas secara interval';
-$labels['vacation.after'] = 'Atur untuk pengaturan cuti setelah';
-$labels['vacation.saving'] = 'Menyimpan data...';
-$labels['vacation.action'] = 'Tindakan untuk pesan masuk';
-$labels['vacation.keep'] = 'Simpan';
-$labels['vacation.discard'] = 'Buang';
-$labels['vacation.redirect'] = 'Alihkan ke';
-$labels['vacation.copy'] = 'Kirim salinan ke';
-$labels['arialabelfiltersetactions'] = 'Tindakan untuk penyaringan';
-$labels['arialabelfilteractions'] = 'Tindakan penyaringan';
-$labels['arialabelfilterform'] = 'Properti untuk penyaringan';
-$labels['ariasummaryfilterslist'] = 'Daftar penyaringan';
-$labels['ariasummaryfiltersetslist'] = 'Daftar penyaringan yang telah di set';
-$labels['filterstitle'] = 'Ubah penyaringan untuk email masuk';
-$labels['vacationtitle'] = 'Ubah aturan untuk sedang-diluar-kantor';
-$messages['filterunknownerror'] = 'Error pada server tak dikenali.';
-$messages['filterconnerror'] = 'Tidak dapat menyambung ke server.';
-$messages['filterdeleteerror'] = 'Tidak dapat menghapus penyaringan. Terjadi kesalahan pada server.';
-$messages['filterdeleted'] = 'Penyaringan berhasil dihapus.';
-$messages['filtersaved'] = 'Penyaringan berhasil disimpan.';
-$messages['filtersaveerror'] = 'Tidak dapat menyimpan penyaringan. Terjadi kesalahan pada server.';
-$messages['filterdeleteconfirm'] = 'Yakin untuk menghapus penyaringan terpilih?';
-$messages['ruledeleteconfirm'] = 'Yakin untuk menghapus aturan terpilih?';
-$messages['actiondeleteconfirm'] = 'Yakin untuk menghapus tindakan terpilih?';
-$messages['forbiddenchars'] = 'Karakter terlarang pada isian.';
-$messages['cannotbeempty'] = 'Isian tidak bisa kosong.';
-$messages['ruleexist'] = 'Penyaringan dengan nama tersebut sudah ada.';
-$messages['setactivateerror'] = 'Tidak dapat mengaktivkan kumpulan penyaringan terpilih. Terjadi kesalahan pada server.';
-$messages['setdeactivateerror'] = 'Tidak bisa mematikan kumpulan penyaringan terpilih. Terjadi kesalahan pada server.';
-$messages['setdeleteerror'] = 'Tidak dapat menghapus kumpulan penyaringan terpilih. Terjadi kesalahan pada server.';
-$messages['setactivated'] = 'Kumpulan penyaringan berhasil dihidupkan.';
-$messages['setdeactivated'] = 'Kumpulan penyaringan berhasil dimatikan.';
-$messages['setdeleted'] = 'Kumpulan penyaringan berhasil dihapus.';
-$messages['setdeleteconfirm'] = 'Yakin ingin menghapus kumpulan penyaringan terpilih?';
-$messages['setcreateerror'] = 'Tidak bisa membuat kumpulan penyaringan. Terjadi kesalahan pada server';
-$messages['setcreated'] = 'Kumpulan penyaringan berhasul dibuat.';
-$messages['activateerror'] = 'Tidak dapat mengaktifkan penyaringan terpilih. Terjadi kesalahan pada server';
-$messages['deactivateerror'] = 'Tidak dapat mematikan penyaringan terpilih. Terjadi kesalahan pada server';
-$messages['deactivated'] = 'Berhasil menghidupkan penyaringan.';
-$messages['activated'] = 'Berhasil mematikan penyaringan.';
-$messages['moved'] = 'Berhasil memindahkan penyaringan.';
-$messages['moveerror'] = 'Tidak bisa memindahkan penyaringan terpilih. Ada kesalahan di server.';
-$messages['nametoolong'] = 'Nama terlalu panjang.';
-$messages['namereserved'] = 'Nama sudah terpesan.';
-$messages['setexist'] = 'Kumpulan sudah ada.';
-$messages['nodata'] = 'Setidaknya satu posisi harus dipilih!';
-$messages['invaliddateformat'] = 'Format tanggal atau bagian dari tanggal salah';
-$messages['saveerror'] = 'Tidak dapat menyimpan data. Terjadi kesalahan pada server.';
-$messages['vacationsaved'] = 'Data untuk cuti berhasil disimpan.';
-?>
diff --git a/lib/plugins/managesieve/localization/it_IT.inc b/lib/plugins/managesieve/localization/it_IT.inc
deleted file mode 100644
index b97fde8..0000000
--- a/lib/plugins/managesieve/localization/it_IT.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtri';
-$labels['managefilters'] = 'Gestione dei filtri per la posta in arrivo';
-$labels['filtername'] = 'Nome del filtro';
-$labels['newfilter'] = 'Nuovo filtro';
-$labels['filteradd'] = 'Aggiungi filtro';
-$labels['filterdel'] = 'Elimina filtro';
-$labels['moveup'] = 'Sposta sopra';
-$labels['movedown'] = 'Sposta sotto';
-$labels['filterallof'] = 'che soddisfa tutte le regole seguenti';
-$labels['filteranyof'] = 'che soddisfa una qualsiasi delle regole seguenti';
-$labels['filterany'] = 'tutti i messaggi';
-$labels['filtercontains'] = 'contiene';
-$labels['filternotcontains'] = 'non contiene';
-$labels['filteris'] = 'è uguale a';
-$labels['filterisnot'] = 'è diverso da';
-$labels['filterexists'] = 'esiste';
-$labels['filternotexists'] = 'non esiste';
-$labels['filtermatches'] = 'matcha l\'espressione';
-$labels['filternotmatches'] = 'non matcha l\'espressione';
-$labels['filterregex'] = 'matcha l\'espressione regolare';
-$labels['filternotregex'] = 'non matcha l\'espressione regolare';
-$labels['filterunder'] = 'sotto';
-$labels['filterover'] = 'sopra';
-$labels['addrule'] = 'Aggiungi regola';
-$labels['delrule'] = 'Elimina regola';
-$labels['messagemoveto'] = 'Sposta il messaggio in';
-$labels['messageredirect'] = 'Inoltra il messaggio a';
-$labels['messagecopyto'] = 'copia a';
-$labels['messagesendcopy'] = 'Invia copia a';
-$labels['messagereply'] = 'Rispondi con il messaggio';
-$labels['messagedelete'] = 'Elimina il messaggio';
-$labels['messagediscard'] = 'Rifiuta con messaggio';
-$labels['messagekeep'] = 'Mantieni il messaggio in Posta ricevuta';
-$labels['messagesrules'] = 'Per la posta in arrivo';
-$labels['messagesactions'] = '...esegui le seguenti azioni:';
-$labels['add'] = 'Aggiungi';
-$labels['del'] = 'Elimina';
-$labels['sender'] = 'Mittente';
-$labels['recipient'] = 'Destinatario';
-$labels['vacationaddr'] = 'Account email aggiuntivo(i):';
-$labels['vacationdays'] = 'Ogni quanti giorni ribadire il messaggio allo stesso mittente';
-$labels['vacationinterval'] = 'Ogni quanto tempo inviare i messaggi:';
-$labels['vacationreason'] = 'Corpo del messaggio (dettagli relativi all\'assenza):';
-$labels['vacationsubject'] = 'Oggetto del messaggio';
-$labels['days'] = 'giorni';
-$labels['seconds'] = 'secondi';
-$labels['rulestop'] = 'Non valutare le regole successive';
-$labels['enable'] = 'Abilita/disabilita';
-$labels['filterset'] = 'Gruppi di filtri';
-$labels['filtersets'] = 'gruppo di filtri';
-$labels['filtersetadd'] = 'Aggiungi gruppo';
-$labels['filtersetdel'] = 'Cancella gruppo selezionato';
-$labels['filtersetact'] = 'Attiva gruppo selezionato';
-$labels['filtersetdeact'] = 'Disattiva gruppo selezionato';
-$labels['filterdef'] = 'Definizione del filtro';
-$labels['filtersetname'] = 'Nome del Gruppo di filtri';
-$labels['newfilterset'] = 'Nuovo gruppo di filri';
-$labels['active'] = 'attivo';
-$labels['none'] = 'nessuno';
-$labels['fromset'] = 'dal set';
-$labels['fromfile'] = 'dal file';
-$labels['filterdisabled'] = 'Filtro disabilitato';
-$labels['countisgreaterthan'] = 'somma maggiore di';
-$labels['countisgreaterthanequal'] = 'somma maggiore uguale a';
-$labels['countislessthan'] = 'somma minore di';
-$labels['countislessthanequal'] = 'somma minore o uguale a';
-$labels['countequals'] = 'somma uguale a';
-$labels['countnotequals'] = 'il conteggio non è uguale a';
-$labels['valueisgreaterthan'] = 'valore maggiore di';
-$labels['valueisgreaterthanequal'] = 'valore maggiore uguale a';
-$labels['valueislessthan'] = 'valore minore di';
-$labels['valueislessthanequal'] = 'valore minore uguale di';
-$labels['valueequals'] = 'valore uguale a';
-$labels['valuenotequals'] = 'il valore non è uguale a';
-$labels['setflags'] = 'Contrassegna il messaggio';
-$labels['addflags'] = 'aggiungi flag al messaggio';
-$labels['removeflags'] = 'togli flag dal messaggio';
-$labels['flagread'] = 'Letto';
-$labels['flagdeleted'] = 'Cancellato';
-$labels['flaganswered'] = 'Risposto';
-$labels['flagflagged'] = 'Contrassegna';
-$labels['flagdraft'] = 'Bozza';
-$labels['setvariable'] = 'Imposta variabile';
-$labels['setvarname'] = 'Nome variabile:';
-$labels['setvarvalue'] = 'Valore variabile:';
-$labels['setvarmodifiers'] = 'Modificatori:';
-$labels['varlower'] = 'minuscole';
-$labels['varupper'] = 'maiuscole';
-$labels['varlowerfirst'] = 'primo carattere minuscolo';
-$labels['varupperfirst'] = 'primo carattere maiuscolo';
-$labels['varquotewildcard'] = 'caratteri speciali di quoting';
-$labels['varlength'] = 'lunghezza';
-$labels['notify'] = 'Invia notifica';
-$labels['notifytarget'] = 'Destinatario della notifica';
-$labels['notifymessage'] = 'Messaggio di notifica (opzionale):';
-$labels['notifyoptions'] = 'Opzioni di notifica (opzionale):';
-$labels['notifyfrom'] = 'Mittente della notifica (opzionale):';
-$labels['notifyimportance'] = 'Importanza:';
-$labels['notifyimportancelow'] = 'bassa';
-$labels['notifyimportancenormal'] = 'normale';
-$labels['notifyimportancehigh'] = 'alta';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Telefono';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Crea filtro';
-$labels['usedata'] = 'utilizza i seguenti dati nel filtro';
-$labels['nextstep'] = 'passo successivo';
-$labels['...'] = '...';
-$labels['currdate'] = 'Data attuale';
-$labels['datetest'] = 'Data';
-$labels['dateheader'] = 'intestazione:';
-$labels['year'] = 'anno';
-$labels['month'] = 'mese';
-$labels['day'] = 'giorno';
-$labels['date'] = 'data (aaaa-mm-gg)';
-$labels['julian'] = 'data (Giuliana)';
-$labels['hour'] = 'ora';
-$labels['minute'] = 'minuto';
-$labels['second'] = 'secondo';
-$labels['time'] = 'tempo (hh:mm:ss)';
-$labels['iso8601'] = 'data (ISO8601)';
-$labels['std11'] = 'data (RFC2822)';
-$labels['zone'] = 'fuso orario';
-$labels['weekday'] = 'giorno della settimana (0-6)';
-$labels['advancedopts'] = 'Opzioni avanzate';
-$labels['body'] = 'Corpo';
-$labels['address'] = 'indirizzo';
-$labels['envelope'] = 'busta';
-$labels['modifier'] = 'modificatore:';
-$labels['text'] = 'testo';
-$labels['undecoded'] = 'non decodificato (raw)';
-$labels['contenttype'] = 'content type';
-$labels['modtype'] = 'tipo:';
-$labels['allparts'] = 'tutto';
-$labels['domain'] = 'dominio';
-$labels['localpart'] = 'parte locale';
-$labels['user'] = 'user';
-$labels['detail'] = 'dettaglio';
-$labels['comparator'] = 'comparatore';
-$labels['default'] = 'predefinito';
-$labels['octet'] = 'strict (octet)';
-$labels['asciicasemap'] = 'non differenziare maiuscole/minuscole (ascii-casemap)';
-$labels['asciinumeric'] = 'numerico';
-$labels['index'] = 'indice:';
-$labels['indexlast'] = 'indietro';
-$labels['vacation'] = 'Vacanza';
-$labels['vacation.reply'] = 'Messaggio di risposta';
-$labels['vacation.advanced'] = 'Impostazioni avanzate';
-$labels['vacation.subject'] = 'Oggetto';
-$labels['vacation.body'] = 'Testo';
-$labels['vacation.start'] = 'Inizio vacanza';
-$labels['vacation.end'] = 'Fine vacanza';
-$labels['vacation.status'] = 'Stato';
-$labels['vacation.on'] = 'Attivato';
-$labels['vacation.off'] = 'Disattivato';
-$labels['vacation.addresses'] = 'I miei indirizzi aggiuntivi';
-$labels['vacation.interval'] = 'Intervallo di risposta';
-$labels['vacation.after'] = 'Imposta regola di vacanza dopo';
-$labels['vacation.saving'] = 'Salvataggio...';
-$labels['vacation.action'] = 'Azione messaggio in arrivo';
-$labels['vacation.keep'] = 'Mantieni';
-$labels['vacation.discard'] = 'Elimina';
-$labels['vacation.redirect'] = 'Ridireziona a';
-$labels['vacation.copy'] = 'Invia copia a';
-$labels['arialabelfiltersetactions'] = 'Azione settaggio dei filtri ';
-$labels['arialabelfilteractions'] = 'Azione Filtri';
-$labels['arialabelfilterform'] = 'Proprietà filtri';
-$labels['ariasummaryfilterslist'] = 'Lista dei filtri';
-$labels['ariasummaryfiltersetslist'] = 'Lista settaggio dei filtri';
-$labels['filterstitle'] = 'Modifica filtri dei messaggio in arrivo';
-$labels['vacationtitle'] = 'Modifica le regole del Risponditore automatico';
-$messages['filterunknownerror'] = 'Errore sconosciuto del server';
-$messages['filterconnerror'] = 'Collegamento al server managesieve fallito';
-$messages['filterdeleteerror'] = 'Eliminazione del filtro fallita. Si è verificato un errore nel server.';
-$messages['filterdeleted'] = 'Filtro eliminato con successo';
-$messages['filtersaved'] = 'Filtro salvato con successo';
-$messages['filtersaveerror'] = 'Salvataggio del filtro fallito. Si è verificato un errore nel server.';
-$messages['filterdeleteconfirm'] = 'Vuoi veramente eliminare il filtro selezionato?';
-$messages['ruledeleteconfirm'] = 'Sei sicuro di voler eliminare la regola selezionata?';
-$messages['actiondeleteconfirm'] = 'Sei sicuro di voler eliminare l\'azione selezionata?';
-$messages['forbiddenchars'] = 'Caratteri non consentiti nel campo';
-$messages['cannotbeempty'] = 'Il campo non può essere vuoto';
-$messages['ruleexist'] = 'Esiste già un filtro con questo nome';
-$messages['setactivateerror'] = 'Impossibile attivare il filtro. Errore del server.';
-$messages['setdeactivateerror'] = 'Impossibile disattivare i filtri selezionati. Errore del server.';
-$messages['setdeleteerror'] = 'Impossibile cancellare i filtri selezionati. Errore del server.';
-$messages['setactivated'] = 'Filtro attivato';
-$messages['setdeactivated'] = 'Filtro disattivato';
-$messages['setdeleted'] = 'Filtro cancellato';
-$messages['setdeleteconfirm'] = 'Sei sicuro di voler cancellare il gruppo di filtri';
-$messages['setcreateerror'] = 'Impossibile creare il gruppo di filtri. Errore del server.';
-$messages['setcreated'] = 'Gruppo di filtri creato';
-$messages['activateerror'] = 'Impossibile abilitare i filtri selzionati. Errore del server.';
-$messages['deactivateerror'] = 'impossibile disabilitare i filtri selezionati. Errore del server.';
-$messages['deactivated'] = 'filtro abilitato';
-$messages['activated'] = 'filtro disabilitato';
-$messages['moved'] = 'filtro spostato';
-$messages['moveerror'] = 'impossibile spostare il filtro selezionato. Errore del server.';
-$messages['nametoolong'] = 'Impossibile creare il gruppo: Nome troppo lungo';
-$messages['namereserved'] = 'nome riservato';
-$messages['setexist'] = 'Il gruppo esiste già';
-$messages['nodata'] = 'selezionare almeno una posizione';
-$messages['invaliddateformat'] = 'Formato della data non valido';
-$messages['saveerror'] = 'Impossibile salvare i dati. Errore del server.';
-$messages['vacationsaved'] = 'Dati di vacanza salvati correttamente.';
-$messages['emptyvacationbody'] = 'Il testo del messaggio non puo\' essere vuoto!';
-?>
diff --git a/lib/plugins/managesieve/localization/ja_JP.inc b/lib/plugins/managesieve/localization/ja_JP.inc
deleted file mode 100644
index db04084..0000000
--- a/lib/plugins/managesieve/localization/ja_JP.inc
+++ /dev/null
@@ -1,214 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'フィルター';
-$labels['managefilters'] = '受信メールのフィルターを管理';
-$labels['filtername'] = 'フィルター名';
-$labels['newfilter'] = '新しいフィルター';
-$labels['filteradd'] = 'フィルターを追加';
-$labels['filterdel'] = 'フィルターを削除';
-$labels['moveup'] = '上に移動';
-$labels['movedown'] = '下に移動';
-$labels['filterallof'] = '次のルールのすべてに一致';
-$labels['filteranyof'] = '次のルールのいずれかに一致';
-$labels['filterany'] = 'すべてのメッセージ';
-$labels['filtercontains'] = '含む';
-$labels['filternotcontains'] = '含まない';
-$labels['filteris'] = '次に等しい';
-$labels['filterisnot'] = '次に等しくない';
-$labels['filterexists'] = 'が存在';
-$labels['filternotexists'] = 'が存在しない';
-$labels['filtermatches'] = '次の式に一致';
-$labels['filternotmatches'] = '次の式に一致しない';
-$labels['filterregex'] = '次の正規表現に一致';
-$labels['filternotregex'] = '次の正規表現に一致しない';
-$labels['filterunder'] = 'より下';
-$labels['filterover'] = 'より上';
-$labels['addrule'] = 'ルールを追加';
-$labels['delrule'] = 'ルールを削除';
-$labels['messagemoveto'] = '次にメッセージを移動';
-$labels['messageredirect'] = '次のメールアドレスに転送';
-$labels['messagecopyto'] = '次にメッセージをコピー';
-$labels['messagesendcopy'] = '次にメッセージのコピーを送信';
-$labels['messagereply'] = 'メッセージを返信';
-$labels['messagedelete'] = 'メッセージを削除';
-$labels['messagediscard'] = 'メッセージを破棄';
-$labels['messagekeep'] = 'Keep message in Inbox';
-$labels['messagesrules'] = '受信したメールの処理:';
-$labels['messagesactions'] = '以下の操作を実行:';
-$labels['add'] = '追加';
-$labels['del'] = '削除';
-$labels['sender'] = '送信者';
-$labels['recipient'] = '宛先';
-$labels['vacationaddr'] = 'My additional e-mail address(es):';
-$labels['vacationdays'] = 'メッセージを(1日に)送信する頻度:';
-$labels['vacationinterval'] = 'メッセージを送信する頻度:';
-$labels['vacationreason'] = 'メッセージ本体(休暇の理由):';
-$labels['vacationsubject'] = 'メッセージの件名:';
-$labels['days'] = '日';
-$labels['seconds'] = '秒';
-$labels['rulestop'] = 'ルールの評価を停止';
-$labels['enable'] = '有効/無効';
-$labels['filterset'] = 'フィルターセット';
-$labels['filtersets'] = 'フィルターセット';
-$labels['filtersetadd'] = 'フィルターセットを追加';
-$labels['filtersetdel'] = '現在のフィルターセットを削除';
-$labels['filtersetact'] = '現在のフィルター セットを有効';
-$labels['filtersetdeact'] = '現在のフィルター セットを無効';
-$labels['filterdef'] = 'フィルターの定義';
-$labels['filtersetname'] = 'フィルターセットの名前';
-$labels['newfilterset'] = '新しいフィルターセット';
-$labels['active'] = '有効';
-$labels['none'] = 'なし';
-$labels['fromset'] = 'セットから';
-$labels['fromfile'] = 'ファイルから';
-$labels['filterdisabled'] = 'フィルターを無効にしました。';
-$labels['countisgreaterthan'] = 'より大きい回数';
-$labels['countisgreaterthanequal'] = '以上の回数';
-$labels['countislessthan'] = '未満の回数';
-$labels['countislessthanequal'] = '以下の回数';
-$labels['countequals'] = '次と等しい回数';
-$labels['countnotequals'] = 'count is not equal to';
-$labels['valueisgreaterthan'] = 'より大きい値';
-$labels['valueisgreaterthanequal'] = '以上の値';
-$labels['valueislessthan'] = '未満の値';
-$labels['valueislessthanequal'] = '以下の値';
-$labels['valueequals'] = '次と等しい値';
-$labels['valuenotequals'] = 'value is not equal to';
-$labels['setflags'] = 'メッセージにフラグを設定';
-$labels['addflags'] = 'メッセージにフラグを追加';
-$labels['removeflags'] = 'メッセージからフラグを削除';
-$labels['flagread'] = '既読';
-$labels['flagdeleted'] = '削除済み';
-$labels['flaganswered'] = '返信済み';
-$labels['flagflagged'] = 'フラグ付き';
-$labels['flagdraft'] = '下書き';
-$labels['setvariable'] = '変数を設定';
-$labels['setvarname'] = '変数の名前:';
-$labels['setvarvalue'] = '変数の値:';
-$labels['setvarmodifiers'] = '修飾子:';
-$labels['varlower'] = '小文字';
-$labels['varupper'] = '大文字';
-$labels['varlowerfirst'] = '最初の文字を小文字';
-$labels['varupperfirst'] = '最初の文字を大文字';
-$labels['varquotewildcard'] = '特殊文字を引用処理';
-$labels['varlength'] = '長さ';
-$labels['notify'] = '通知を送信';
-$labels['notifytarget'] = '通知の対象:';
-$labels['notifymessage'] = '通知のメッセージ(任意):';
-$labels['notifyoptions'] = '通知のオプション(任意):';
-$labels['notifyfrom'] = '通知の送信者(任意):';
-$labels['notifyimportance'] = '重要度:';
-$labels['notifyimportancelow'] = '低';
-$labels['notifyimportancenormal'] = '通常';
-$labels['notifyimportancehigh'] = '高';
-$labels['notifymethodmailto'] = '電子メール';
-$labels['notifymethodtel'] = '電話';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'フィルターを作成';
-$labels['usedata'] = 'フィルターで次のデータを使用';
-$labels['nextstep'] = '次のステップ';
-$labels['...'] = '...';
-$labels['currdate'] = 'Current date';
-$labels['datetest'] = 'Date';
-$labels['dateheader'] = 'header:';
-$labels['year'] = 'year';
-$labels['month'] = 'month';
-$labels['day'] = 'day';
-$labels['date'] = 'date (yyyy-mm-dd)';
-$labels['julian'] = 'date (julian)';
-$labels['hour'] = 'hour';
-$labels['minute'] = 'minute';
-$labels['second'] = 'second';
-$labels['time'] = 'time (hh:mm:ss)';
-$labels['iso8601'] = 'date (ISO8601)';
-$labels['std11'] = 'date (RFC2822)';
-$labels['zone'] = 'time-zone';
-$labels['weekday'] = 'weekday (0-6)';
-$labels['advancedopts'] = '高度なオプション';
-$labels['body'] = '本文';
-$labels['address'] = 'メールアドレス';
-$labels['envelope'] = 'エンベロープ';
-$labels['modifier'] = '修正:';
-$labels['text'] = 'テキスト';
-$labels['undecoded'] = '未デコード(そのまま)';
-$labels['contenttype'] = 'Content Type';
-$labels['modtype'] = '種類:';
-$labels['allparts'] = 'すべて';
-$labels['domain'] = 'ドメイン';
-$labels['localpart'] = 'ローカルパート';
-$labels['user'] = 'ユーザー';
-$labels['detail'] = '詳細';
-$labels['comparator'] = '比較器:';
-$labels['default'] = '初期値';
-$labels['octet'] = '厳密(オクテット)';
-$labels['asciicasemap'] = '大文字小文字を区別しない(ascii-casemap)';
-$labels['asciinumeric'] = '数値(ascii-numeric)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'backwards';
-$labels['vacation'] = '休暇';
-$labels['vacation.reply'] = '返信のメッセージ';
-$labels['vacation.advanced'] = '詳細な設定';
-$labels['vacation.subject'] = '件名';
-$labels['vacation.body'] = '本文';
-$labels['vacation.status'] = '状態';
-$labels['vacation.on'] = 'オン';
-$labels['vacation.off'] = 'オフ';
-$labels['vacation.addresses'] = '追加のアドレス';
-$labels['vacation.interval'] = '返信の間隔';
-$labels['vacation.after'] = '後に休暇のルールを記入';
-$labels['vacation.saving'] = 'データを保存中...';
-$labels['arialabelfiltersetactions'] = 'フィルターセットの動作';
-$labels['arialabelfilteractions'] = 'フィルターの動作';
-$labels['arialabelfilterform'] = 'フィルターの特性';
-$labels['ariasummaryfilterslist'] = 'フィルターの一覧';
-$labels['ariasummaryfiltersetslist'] = 'フィルターセットの一覧';
-$messages['filterunknownerror'] = '不明なサーバーのエラーです。';
-$messages['filterconnerror'] = 'サーバに接続できません。';
-$messages['filterdeleteerror'] = 'フィルターを削除できません。サーバーでエラーが発生しました。';
-$messages['filterdeleted'] = 'フィルターを削除しました。';
-$messages['filtersaved'] = 'フィルターを保存しました。';
-$messages['filtersaveerror'] = 'フィルターの保存できません。サーバーでエラーが発生しました。';
-$messages['filterdeleteconfirm'] = '本当に選択したフィルターを削除しますか?';
-$messages['ruledeleteconfirm'] = '本当に選択したルールを削除しますか?';
-$messages['actiondeleteconfirm'] = '本当に選択した操作を削除しますか?';
-$messages['forbiddenchars'] = '項目に禁止している文字が含まれています。';
-$messages['cannotbeempty'] = '項目は空欄にできません。';
-$messages['ruleexist'] = '指定した名前のフィルターが既に存在します。';
-$messages['setactivateerror'] = '選択したフィルターセットを有効にできません。サーバーでエラーが発生しました。';
-$messages['setdeactivateerror'] = '選択したフィルターセットを無効にできません。サーバーでエラーが発生しました。';
-$messages['setdeleteerror'] = '選択したフィルターセットを削除できません。サーバーでエラーが発生しました。';
-$messages['setactivated'] = 'フィルターセットを有効にしました。';
-$messages['setdeactivated'] = 'フィルターセットを無効にしました。';
-$messages['setdeleted'] = 'フィルターセットを削除しました。';
-$messages['setdeleteconfirm'] = '本当に選択したフィルターセットを削除しますか?';
-$messages['setcreateerror'] = 'フィルターセットを作成できません。サーバーでエラーが発生しました。';
-$messages['setcreated'] = 'フィルターセットを作成しました。';
-$messages['activateerror'] = '選択したフィルターを有効にできません。サーバーでエラーが発生しました。';
-$messages['deactivateerror'] = '選択したフィルターを無効にできません。サーバーでエラーが発生しました。';
-$messages['deactivated'] = 'フィルターを有効にしました。';
-$messages['activated'] = 'フィルターを無効にしました。';
-$messages['moved'] = 'フィルターを移動しました。';
-$messages['moveerror'] = 'Unable to move selected filter. Server error occurred.';
-$messages['nametoolong'] = '名前が長すぎます。';
-$messages['namereserved'] = '予約されている名前です。';
-$messages['setexist'] = 'フィルターセットが既に存在します。';
-$messages['nodata'] = '少なくとも1つの場所を選択しなければなりません!';
-$messages['invaliddateformat'] = '無効な日付または日付部分の書式';
-$messages['saveerror'] = 'フィルターの保存できません。サーバーでエラーが発生しました。';
-$messages['vacationsaved'] = '休暇のデータを保存しました。';
-?>
diff --git a/lib/plugins/managesieve/localization/km_KH.inc b/lib/plugins/managesieve/localization/km_KH.inc
deleted file mode 100644
index 9d3de70..0000000
--- a/lib/plugins/managesieve/localization/km_KH.inc
+++ /dev/null
@@ -1,116 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'តម្រង';
-$labels['managefilters'] = 'គ្រប់គ្រង​តម្រប​សំបុត្រ​ចូល';
-$labels['filtername'] = 'ឈ្មោះ​តម្រង';
-$labels['newfilter'] = 'តម្រង​ថ្មី';
-$labels['filteradd'] = 'បន្ថែម​តម្រង';
-$labels['filterdel'] = 'លុប​តម្រង';
-$labels['moveup'] = 'រុញ​ទៅ​លើ';
-$labels['movedown'] = 'រុញ​ចុះ​ក្រោម';
-$labels['filterallof'] = 'ត្រូវ​គ្នា​ទៅ​នឹង​លក្ខខណ្ឌ​ទាំង​នេះ';
-$labels['filteranyof'] = 'ត្រូវ​គ្នា​ទៅ​នឹង​លក្ខខណ្ឌ​ណាមួយ';
-$labels['filterany'] = 'សារ​ទាំង​អស់';
-$labels['filtercontains'] = 'មាន​ផ្ទុក';
-$labels['filternotcontains'] = 'មិន​មាន';
-$labels['filteris'] = 'ស្មើ​នឹង';
-$labels['filterisnot'] = 'មិន​ស្មើ​នឹង';
-$labels['filterexists'] = 'មាន';
-$labels['filternotexists'] = 'មិន​មាន';
-$labels['filtermatches'] = 'សញ្ញាណ​ដែល​ត្រូវ';
-$labels['filterunder'] = 'ក្រោម';
-$labels['filterover'] = 'លើ';
-$labels['addrule'] = 'បន្ថែម​លក្ខខណ្ឌ';
-$labels['delrule'] = 'លុប​លក្ខខណ្ឌ';
-$labels['messagemoveto'] = 'ផ្លាស់​ទី​សារ​ទៅ';
-$labels['messageredirect'] = 'ប្ដូរ​ទិសដៅ​សារ​ទៅ';
-$labels['messagecopyto'] = 'ចម្លង​សារ​ទៅ';
-$labels['messagesendcopy'] = 'ផ្ញើ​ការ​ចម្លង​សារ​ទៅ';
-$labels['messagereply'] = 'ឆ្លើយ​តប​ជាមួយ​សារ';
-$labels['messagedelete'] = 'លុប​សារ';
-$labels['messagediscard'] = 'បោះបង់​ជាមួយ​នឹង​សារ';
-$labels['messagesrules'] = 'សម្រាប់​សំបុត្រ​ចូល៖';
-$labels['messagesactions'] = '...ប្រតិបត្តិ​សកម្មភាព​ទាំង​នេះ៖';
-$labels['add'] = 'បន្ថែម';
-$labels['del'] = 'លុប';
-$labels['sender'] = 'អ្នក​ផ្ញើ';
-$labels['recipient'] = 'អ្នក​ទទួល';
-$labels['vacationdays'] = 'តើ​ផ្ញើ​សារ​ញឹកញាប់​ប៉ុណ្ណា (ក្នុង​មួយ​ថ្ងៃ)៖';
-$labels['vacationreason'] = 'តួ​សារ (ហេតុផល​វិស្សមកាល)៖';
-$labels['vacationsubject'] = 'ប្រធានបទ​សារ៖';
-$labels['days'] = 'ថ្ងៃ';
-$labels['seconds'] = 'វិនាទី';
-$labels['rulestop'] = 'ឈប់​គិត​ទៅ​លើ​លក្ខខណ្ឌ';
-$labels['enable'] = 'បើក/បិទ';
-$labels['filterdef'] = 'អត្ថន័យ​តម្រង';
-$labels['active'] = 'សកម្ម';
-$labels['none'] = 'គ្មាន';
-$labels['fromfile'] = 'ពី​ឯកសារ';
-$labels['filterdisabled'] = 'បាន​បិទ​តម្រង';
-$labels['valuenotequals'] = 'តម្លៃ​មិន​ស្មើ​នឹង';
-$labels['flagread'] = 'បាន​អាន';
-$labels['flagdeleted'] = 'បាន​លុប';
-$labels['flaganswered'] = 'បាន​ឆ្លើយ';
-$labels['flagflagged'] = 'បាន​ដាក់​ទង់';
-$labels['flagdraft'] = 'ការ​ព្រាង';
-$labels['setvariable'] = 'កំណត់​អថេរ';
-$labels['setvarname'] = 'ឈ្មោះ​អថេរ៖';
-$labels['setvarvalue'] = 'តម្លៃ​អថេរ៖';
-$labels['varlower'] = 'អក្សរ​តូច';
-$labels['varupper'] = 'អក្សរ​ធំ';
-$labels['varlength'] = 'ប្រវែង';
-$labels['notify'] = 'ផ្ញើ​ការ​ជូន​ដំណឹង';
-$labels['notifyimportance'] = 'សំខាន់៖';
-$labels['notifyimportancelow'] = 'ទាប';
-$labels['notifyimportancenormal'] = 'ធម្មតា';
-$labels['notifyimportancehigh'] = 'ខ្ពស់';
-$labels['filtercreate'] = 'បង្កើត​តម្រង';
-$labels['usedata'] = 'ប្រើ​ទិន្នន័យ​ទាំង​នេះ​ក្នុង​តម្រង៖';
-$labels['nextstep'] = 'ជំហាន​បន្ទាប់';
-$labels['...'] = '...';
-$labels['currdate'] = 'កាលបរិច្ឆេទ​បច្ចុប្បន្ន';
-$labels['datetest'] = 'កាលបរិច្ឆេទ';
-$labels['dateheader'] = 'ក្បាល៖';
-$labels['year'] = 'ឆ្នាំ';
-$labels['month'] = 'ខែ';
-$labels['day'] = 'ថ្ងៃ';
-$labels['date'] = 'កាល​បរិច្ឆេទ (yyyy-mm-dd)';
-$labels['julian'] = 'កាល​បរិច្ឆេទ (julian)';
-$labels['hour'] = 'ម៉ោង';
-$labels['minute'] = 'នាទី';
-$labels['second'] = 'វិនាទី';
-$labels['time'] = 'ម៉ោង (hh:mm:ss)';
-$labels['iso8601'] = 'កាល​បរិច្ឆេទ (ISO8601)';
-$labels['std11'] = 'កាល​បរិច្ឆេទ (RFC2822)';
-$labels['zone'] = 'តំបន់​ម៉ោង';
-$labels['weekday'] = 'ថ្ងៃ​សប្ដាហ៍ (0-6)';
-$labels['advancedopts'] = 'ជម្រើស​កម្រិត​ខ្ពស់';
-$labels['body'] = 'តួ';
-$labels['address'] = 'អាសយដ្ឋាន';
-$labels['envelope'] = 'ស្រោម​សំបុត្រ';
-$labels['text'] = 'អត្ថបទ';
-$labels['contenttype'] = 'ប្រភេទ​មាតិកា';
-$labels['modtype'] = 'ប្រភេទ៖';
-$labels['allparts'] = 'ទាំងអស់';
-$labels['domain'] = 'ដូមេន';
-$labels['localpart'] = 'ផ្នែក​មូលដ្ឋាន';
-$labels['user'] = 'អ្នកប្រើ';
-$labels['detail'] = 'លម្អិត';
-$labels['index'] = 'លិបិក្រម៖';
-$labels['indexlast'] = 'បកក្រោយ';
-?>
diff --git a/lib/plugins/managesieve/localization/ko_KR.inc b/lib/plugins/managesieve/localization/ko_KR.inc
deleted file mode 100644
index e9497e7..0000000
--- a/lib/plugins/managesieve/localization/ko_KR.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = '필터';
-$labels['managefilters'] = '수신 메일 필터 관리';
-$labels['filtername'] = '필터명';
-$labels['newfilter'] = '새로운 필터';
-$labels['filteradd'] = '필터 추가';
-$labels['filterdel'] = '필터 삭제';
-$labels['moveup'] = '위로 이동';
-$labels['movedown'] = '아래로 이동';
-$labels['filterallof'] = '다음 모든 규칙과 일치함';
-$labels['filteranyof'] = '다음 규칙 중 하나라도 일치함';
-$labels['filterany'] = '모든 메시지';
-$labels['filtercontains'] = '다음을 포함함';
-$labels['filternotcontains'] = '다음을 포함하지 않음';
-$labels['filteris'] = '다음과 일치함';
-$labels['filterisnot'] = '다음과 일치하지 않음';
-$labels['filterexists'] = '다음이 존재함';
-$labels['filternotexists'] = '다음이 존재하지 않음';
-$labels['filtermatches'] = '다음 표현식과 일치함';
-$labels['filternotmatches'] = '다음 표현식과 일치하지 않음';
-$labels['filterregex'] = '다음 정규 표현식과 일치함';
-$labels['filternotregex'] = '다음 정규 표현식과 일치하지 않음';
-$labels['filterunder'] = '다음보다 아래임';
-$labels['filterover'] = '다음보다 위임';
-$labels['addrule'] = '규칙 추가';
-$labels['delrule'] = '규칙 삭제';
-$labels['messagemoveto'] = '메시지를 다음 위치로 이동';
-$labels['messageredirect'] = '메시지를 다음 주소로 재전송';
-$labels['messagecopyto'] = '메시지를 다음 위치로 복사';
-$labels['messagesendcopy'] = '메시지 사본을 다음 대상에게 보내기';
-$labels['messagereply'] = '다음 메시지로 회신';
-$labels['messagedelete'] = '메시지 삭제';
-$labels['messagediscard'] = '다음 메시지와 함께 폐기';
-$labels['messagekeep'] = '메시지를 받은 편지함에 보관';
-$labels['messagesrules'] = '해당 받은 메일:';
-$labels['messagesactions'] = '...다음 동작을 실행:';
-$labels['add'] = '추가';
-$labels['del'] = '삭제';
-$labels['sender'] = '발송자';
-$labels['recipient'] = '수신자';
-$labels['vacationaddr'] = '나의 추가적인 이메일 주소:';
-$labels['vacationdays'] = '메시지 발신 주기 (일):';
-$labels['vacationinterval'] = '메시지 발신 주기:';
-$labels['vacationreason'] = '메시지 본문 (휴가 사유):';
-$labels['vacationsubject'] = '메시지 제목:';
-$labels['days'] = '일';
-$labels['seconds'] = '초';
-$labels['rulestop'] = '규칙 평가를 중단';
-$labels['enable'] = '활성화/비활성화';
-$labels['filterset'] = '필터 세트';
-$labels['filtersets'] = '필터 세트';
-$labels['filtersetadd'] = '필터 세트 추가';
-$labels['filtersetdel'] = '현재 필터 세트를 삭제';
-$labels['filtersetact'] = '현재 필터 세트 활성화';
-$labels['filtersetdeact'] = '현재 필터 세트 비활성화';
-$labels['filterdef'] = '필터 정의';
-$labels['filtersetname'] = '필터 세트명';
-$labels['newfilterset'] = '새 필터 세트';
-$labels['active'] = '활성화됨';
-$labels['none'] = '없음';
-$labels['fromset'] = '세트로부터';
-$labels['fromfile'] = '파일로부터';
-$labels['filterdisabled'] = '필터가 비활성화됨';
-$labels['countisgreaterthan'] = '개수가 다음보다 큼';
-$labels['countisgreaterthanequal'] = '개수가 다음보다 크거나 같음';
-$labels['countislessthan'] = '개수가 다음보다 작음';
-$labels['countislessthanequal'] = '개수가 작거나 같음';
-$labels['countequals'] = '개수가 다음과 같음';
-$labels['countnotequals'] = '개수가 다음과 일치하지 않음';
-$labels['valueisgreaterthan'] = '값이 다음보다 큼';
-$labels['valueisgreaterthanequal'] = '값이 다음보다 크거나 같음';
-$labels['valueislessthan'] = '값이 다음보다 작음';
-$labels['valueislessthanequal'] = '값이 다음보다 작거나 같음';
-$labels['valueequals'] = '값이 다음과 같음';
-$labels['valuenotequals'] = '값이 다음과 일치하지 않음';
-$labels['setflags'] = '메시지를 깃발로 표시';
-$labels['addflags'] = '메시지에 깃발을 추가';
-$labels['removeflags'] = '메시지에서 깃발을 제거';
-$labels['flagread'] = '읽음';
-$labels['flagdeleted'] = '삭제됨';
-$labels['flaganswered'] = '응답함';
-$labels['flagflagged'] = '깃발로 표시함';
-$labels['flagdraft'] = '임시 보관함';
-$labels['setvariable'] = '변수 설정';
-$labels['setvarname'] = '변수명:';
-$labels['setvarvalue'] = '변수 값:';
-$labels['setvarmodifiers'] = '수식자:';
-$labels['varlower'] = '소문자';
-$labels['varupper'] = '대문자';
-$labels['varlowerfirst'] = '첫 문자를 소문자로';
-$labels['varupperfirst'] = '첫 문자를 대문자로';
-$labels['varquotewildcard'] = '특수 기호를 인용';
-$labels['varlength'] = '길이';
-$labels['notify'] = '알림 메시지 보내기';
-$labels['notifytarget'] = '알림 대상:';
-$labels['notifymessage'] = '알림 메시지(옵션):';
-$labels['notifyoptions'] = '알림 옵션(옵션):';
-$labels['notifyfrom'] = '알림 발송자(옵션):';
-$labels['notifyimportance'] = '중요도:';
-$labels['notifyimportancelow'] = '낮음';
-$labels['notifyimportancenormal'] = '보통';
-$labels['notifyimportancehigh'] = '높음';
-$labels['notifymethodmailto'] = '이메일';
-$labels['notifymethodtel'] = '전화';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = '필터 생성';
-$labels['usedata'] = '필터에서 다음 데이터를 사용:';
-$labels['nextstep'] = '다음 단계';
-$labels['...'] = '...';
-$labels['currdate'] = '오늘 날짜';
-$labels['datetest'] = '날짜';
-$labels['dateheader'] = '머리글:';
-$labels['year'] = '년';
-$labels['month'] = '월';
-$labels['day'] = '일';
-$labels['date'] = '날짜 (yyyy-mm-dd)';
-$labels['julian'] = '날짜 (율리우스력)';
-$labels['hour'] = '시';
-$labels['minute'] = '분';
-$labels['second'] = '초';
-$labels['time'] = '시간 (hh:mm:ss)';
-$labels['iso8601'] = '날짜 (ISO8601)';
-$labels['std11'] = '날짜 (RFC2822)';
-$labels['zone'] = '시간대';
-$labels['weekday'] = '주중 (0-6)';
-$labels['advancedopts'] = '고급 설정';
-$labels['body'] = '본문';
-$labels['address'] = '주소';
-$labels['envelope'] = '봉투';
-$labels['modifier'] = '수식자:';
-$labels['text'] = '텍스트';
-$labels['undecoded'] = '암호화되지 않음(원상태)';
-$labels['contenttype'] = '내용 유형';
-$labels['modtype'] = '유형:';
-$labels['allparts'] = '모두';
-$labels['domain'] = '도메인';
-$labels['localpart'] = '로컬 부분';
-$labels['user'] = '사용자';
-$labels['detail'] = '세부사항';
-$labels['comparator'] = '비교기:';
-$labels['default'] = '기본';
-$labels['octet'] = '엄격 (8진수)';
-$labels['asciicasemap'] = '대/소문자 구분 (ascii-casemap)';
-$labels['asciinumeric'] = '숫자 (ascii-numeric)';
-$labels['index'] = '색인:';
-$labels['indexlast'] = '역방향';
-$labels['vacation'] = '휴가';
-$labels['vacation.reply'] = '메시지 회신';
-$labels['vacation.advanced'] = '고급 설정';
-$labels['vacation.subject'] = '제목';
-$labels['vacation.body'] = '본문';
-$labels['vacation.start'] = '휴가 시작';
-$labels['vacation.end'] = '휴가 끝';
-$labels['vacation.status'] = '상태';
-$labels['vacation.on'] = '켬';
-$labels['vacation.off'] = '끔';
-$labels['vacation.addresses'] = '내 추가적인 주소';
-$labels['vacation.interval'] = '회신 주기';
-$labels['vacation.after'] = '다음 이후에 휴가 규칙을 위치함';
-$labels['vacation.saving'] = '데이터를 저장하는 중...';
-$labels['vacation.action'] = '수신 메시지 동작';
-$labels['vacation.keep'] = '보관';
-$labels['vacation.discard'] = '폐기';
-$labels['vacation.redirect'] = '재전송';
-$labels['vacation.copy'] = '사본을 다음 대상에게 전송';
-$labels['arialabelfiltersetactions'] = '필터 세트 동작';
-$labels['arialabelfilteractions'] = '필터 동작';
-$labels['arialabelfilterform'] = '필터 속성';
-$labels['ariasummaryfilterslist'] = '필터 목록';
-$labels['ariasummaryfiltersetslist'] = '필터 세트 목록';
-$labels['filterstitle'] = '수신 메일 필터 편집';
-$labels['vacationtitle'] = '자리비움 규칙 편집';
-$messages['filterunknownerror'] = '알수 없는 서버 오류.';
-$messages['filterconnerror'] = '서버에 연결할 수 없습니다.';
-$messages['filterdeleteerror'] = '필터를 삭제할 수 없습니다. 서버 오류가 발생했습니다.';
-$messages['filterdeleted'] = '필터가 성공적으로 삭제됨.';
-$messages['filtersaved'] = '필터가 성공적으로 저장됨.';
-$messages['filtersaveerror'] = '필터를 저장할 수 없습니다. 서버 오류가 발생했습니다.';
-$messages['filterdeleteconfirm'] = '정말로 선택한 필터를 삭제하시겠습니까?';
-$messages['ruledeleteconfirm'] = '정말로 선택한 규칙을 삭제하시겠습니까?';
-$messages['actiondeleteconfirm'] = '정말로 선택한 동작을 삭제하시겠습니까?';
-$messages['forbiddenchars'] = '필드에 금지된 문자가 존재합니다.';
-$messages['cannotbeempty'] = '필드는 비어둘 수 없습니다.';
-$messages['ruleexist'] = '지정한 이름의 필터가 이미 존재합니다.';
-$messages['setactivateerror'] = '선택한 필터 세트를 활성화할 수 없습니다. 서버 오류가 발생했습니다.';
-$messages['setdeactivateerror'] = '선택한 필터 세트를 비활성화할 수 없습니다. 서버 오류가 발생했습니다.';
-$messages['setdeleteerror'] = '선택한 필터 세트를 삭제할 수 없습니다. 서버 오류가 발생했습니다.';
-$messages['setactivated'] = '필터 세트가 성공적으로 활성화됨.';
-$messages['setdeactivated'] = '필터 세트가 성공적으로 비활성화됨.';
-$messages['setdeleted'] = '필터 세트가 성공적으로 삭제됨.';
-$messages['setdeleteconfirm'] = '정말로 선택한 필터 세트를 삭제하시겠습니까?';
-$messages['setcreateerror'] = '선택한 필터 세트를 생성할 수 없습니다. 서버 오류가 발생했습니다.';
-$messages['setcreated'] = '필터 세트가 성공적으로 생성됨.';
-$messages['activateerror'] = '선택한 필터를 활성화할 수 없습니다. 서버 오류가 발생했습니다.';
-$messages['deactivateerror'] = '선택한 필터를 비활성화할 수 없습니다. 서버 오류가 발생했습니다.';
-$messages['deactivated'] = '필터가 성공적으로 비활성화됨.';
-$messages['activated'] = '필터가 성공적으로 활성화됨.';
-$messages['moved'] = '필터가 성공적으로 이동되었습니다.';
-$messages['moveerror'] = '선택한 필터를 이동할 수 없습니다. 서버 오류가 발생했습니다.';
-$messages['nametoolong'] = '이름이 너무 깁니다.';
-$messages['namereserved'] = '예약된 이름입니다.';
-$messages['setexist'] = '세트가 이미 존재합니다.';
-$messages['nodata'] = '최소 하나의 위치가 선택되어야 합니다!';
-$messages['invaliddateformat'] = '유효하지 않은 날짜 또는 날짜 일부 형식';
-$messages['saveerror'] = '데이터를 저장할 수 없습니다.. 서버 오류가 발생했습니다.';
-$messages['vacationsaved'] = '휴가 데이터가 성공적으로 저장됨.';
-$messages['emptyvacationbody'] = '휴가 메시지의 본문이 필요합니다!';
-?>
diff --git a/lib/plugins/managesieve/localization/lb_LU.inc b/lib/plugins/managesieve/localization/lb_LU.inc
deleted file mode 100644
index 621fff8..0000000
--- a/lib/plugins/managesieve/localization/lb_LU.inc
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filteren';
-$labels['managefilters'] = 'Filtere geréieren fir Mailen déi erakommen';
-$labels['filtername'] = 'Numm vum Filter';
-$labels['newfilter'] = 'Neie Filter';
-$labels['filteradd'] = 'Filter dobäisetzen';
-$labels['filterdel'] = 'Filter läschen';
-$labels['moveup'] = 'Eropréckelen';
-$labels['movedown'] = 'Erofréckelen';
-$labels['filterallof'] = 'all dës Reegele mussen zoutreffen';
-$labels['filteranyof'] = 'just eng vun de Reegele muss zoutreffen';
-$labels['filterany'] = 'all d\'Messagen';
-$labels['filtercontains'] = 'enthält';
-$labels['filternotcontains'] = 'enthält net';
-$labels['filteris'] = 'ass gläich';
-$labels['filterisnot'] = 'ass net gläich';
-$labels['filterexists'] = 'existéiert';
-$labels['filternotexists'] = 'existéiert net';
-$labels['filterunder'] = 'ënner';
-$labels['filterover'] = 'iwwer';
-$labels['addrule'] = 'Reegel dobäisetzen';
-$labels['delrule'] = 'Reegel läschen';
-$labels['messagemoveto'] = 'Message verréckelen an';
-$labels['messageredirect'] = 'Message ëmleeden an';
-$labels['messagecopyto'] = 'Message kopéieren an';
-$labels['messagesendcopy'] = 'Kopie vum Message schécken un';
-$labels['messagereply'] = 'Mat dësem Message äntweren';
-$labels['messagedelete'] = 'Message läschen';
-$labels['add'] = 'Dobäisetzen';
-$labels['del'] = 'Läschen';
-$labels['sender'] = 'Ofsender';
-$labels['recipient'] = 'Empfänger';
-?>
diff --git a/lib/plugins/managesieve/localization/lt_LT.inc b/lib/plugins/managesieve/localization/lt_LT.inc
deleted file mode 100644
index 575e43c..0000000
--- a/lib/plugins/managesieve/localization/lt_LT.inc
+++ /dev/null
@@ -1,221 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtrai';
-$labels['managefilters'] = 'Tvarkyti gaunamų laiškų filtrus';
-$labels['filtername'] = 'Filtro pavadinimas';
-$labels['newfilter'] = 'Naujas filtras';
-$labels['filteradd'] = 'Pridėti filtrą';
-$labels['filterdel'] = 'Pašalinti filtrą';
-$labels['moveup'] = 'Pakelti aukštyn';
-$labels['movedown'] = 'Nuleisti žemyn';
-$labels['filterallof'] = 'atitinka visas Å¡ias taisykles';
-$labels['filteranyof'] = 'atitinka bet kurią šių taisyklių';
-$labels['filterany'] = 'visi laiškai';
-$labels['filtercontains'] = 'savyje turi';
-$labels['filternotcontains'] = 'savyje neturi';
-$labels['filteris'] = 'yra lygus';
-$labels['filterisnot'] = 'nėra lygus';
-$labels['filterexists'] = 'egzistuoja';
-$labels['filternotexists'] = 'neegzistuoja';
-$labels['filtermatches'] = 'atitinka šabloną';
-$labels['filternotmatches'] = 'neatitinka Å¡ablono';
-$labels['filterregex'] = 'atitinka reguliarųjį reiškinį';
-$labels['filternotregex'] = 'neatitinka reguliariojo reiškinio';
-$labels['filterunder'] = 'nesiekia';
-$labels['filterover'] = 'viršija';
-$labels['addrule'] = 'Pridėti taisyklę';
-$labels['delrule'] = 'Pašalinti taisyklę';
-$labels['messagemoveto'] = 'Perkelti laišką į';
-$labels['messageredirect'] = 'Peradresuoti laišką';
-$labels['messagecopyto'] = 'Kopijuoti laišką į';
-$labels['messagesendcopy'] = 'Nusiųsti laiško kopiją';
-$labels['messagereply'] = 'Atsakyti laišku';
-$labels['messagedelete'] = 'Pašalinti laišką';
-$labels['messagediscard'] = 'Panaikinti su laišku';
-$labels['messagekeep'] = 'Palikti laišką gautųjų aplanke';
-$labels['messagesrules'] = 'Gaunamiems laiškams:';
-$labels['messagesactions'] = '…vykdyti šiuos veiksmus:';
-$labels['add'] = 'Pridėti';
-$labels['del'] = 'Pašalinti';
-$labels['sender'] = 'Siuntėjas';
-$labels['recipient'] = 'Gavėjas';
-$labels['vacationaddr'] = 'Papildomas gavėjų adresų sąrašas:';
-$labels['vacationdays'] = 'Kaip dažnai išsiųsti laiškus (dienomis):';
-$labels['vacationinterval'] = 'Kaip dažnai siųsti laiškus:';
-$labels['vacationreason'] = 'Laiško tekstas';
-$labels['vacationsubject'] = 'Laiško tema:';
-$labels['days'] = 'd.';
-$labels['seconds'] = 'sek.';
-$labels['rulestop'] = 'Nutraukti taisyklių vykdymą';
-$labels['enable'] = 'Įjungti / išjungti';
-$labels['filterset'] = 'Filtrų rinkinys';
-$labels['filtersets'] = 'Filtrų rinkiniai';
-$labels['filtersetadd'] = 'Pridėti filtrų rinkinį';
-$labels['filtersetdel'] = 'Pašalinti šį filtrų rinkinį';
-$labels['filtersetact'] = 'Įgalinti šį filtrų rinkinį';
-$labels['filtersetdeact'] = 'Išjungti šį filtrų rinkinį';
-$labels['filterdef'] = 'Filtro aprašas';
-$labels['filtersetname'] = 'Filtrų rinkinio pavadinimas';
-$labels['newfilterset'] = 'Naujas filtrų rinkinys';
-$labels['active'] = 'aktyvus';
-$labels['none'] = 'joks';
-$labels['fromset'] = 'iš rinkinio';
-$labels['fromfile'] = 'iš failo';
-$labels['filterdisabled'] = 'Filtras išjungtas';
-$labels['countisgreaterthan'] = 'kiekis didesnis nei';
-$labels['countisgreaterthanequal'] = 'kiekis didesnis arba lygus';
-$labels['countislessthan'] = 'kiekis mažesnis nei';
-$labels['countislessthanequal'] = 'kiekis mažesnis arba lygus';
-$labels['countequals'] = 'kiekis lygus';
-$labels['countnotequals'] = 'kiekis nėra lygus';
-$labels['valueisgreaterthan'] = 'reikšmė didesnė nei';
-$labels['valueisgreaterthanequal'] = 'reikšmė didesnė arba lygi';
-$labels['valueislessthan'] = 'reikšmė mažesnė nei';
-$labels['valueislessthanequal'] = 'reikšmė mažesnė arba lygi';
-$labels['valueequals'] = 'reikšmė lygi';
-$labels['valuenotequals'] = 'reikšmė nėra lygi';
-$labels['setflags'] = 'Nustatyti laiško požymius';
-$labels['addflags'] = 'Pridėti laiško požymius';
-$labels['removeflags'] = 'Pašalinti laiško požymius';
-$labels['flagread'] = 'Skaitytas';
-$labels['flagdeleted'] = 'Pašalintas';
-$labels['flaganswered'] = 'Atsakytas';
-$labels['flagflagged'] = 'Pažymėtas gairele';
-$labels['flagdraft'] = 'Juodraštis';
-$labels['setvariable'] = 'Nustatyti kintamąjį';
-$labels['setvarname'] = 'Kintamojo vardas:';
-$labels['setvarvalue'] = 'Kintamojo vertė:';
-$labels['setvarmodifiers'] = 'Modifikatoriai:';
-$labels['varlower'] = 'mažosios raidės';
-$labels['varupper'] = 'didžiosios raidės';
-$labels['varlowerfirst'] = 'pirmoji raidė mažoji';
-$labels['varupperfirst'] = 'pirmoji raidė didžioji';
-$labels['varquotewildcard'] = 'cituoti specialius simbolius';
-$labels['varlength'] = 'ilgis';
-$labels['notify'] = 'Siųsti priminimą';
-$labels['notifytarget'] = 'Priminimo gavėjas:';
-$labels['notifymessage'] = 'Priminimo laiškas (nebūtina):';
-$labels['notifyoptions'] = 'Priminimo nustatymai (nebūtina):';
-$labels['notifyfrom'] = 'Priminimo siuntėjas (nebūtina):';
-$labels['notifyimportance'] = 'Svarbumas';
-$labels['notifyimportancelow'] = 'žemas';
-$labels['notifyimportancenormal'] = 'normalus';
-$labels['notifyimportancehigh'] = 'aukštas';
-$labels['notifymethodmailto'] = 'El. paštas';
-$labels['notifymethodtel'] = 'Telefono numeris';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Kurti filtrą';
-$labels['usedata'] = 'Filtrui naudoti Å¡iuos duomenis:';
-$labels['nextstep'] = 'Kitas žingsnis';
-$labels['...'] = '…';
-$labels['currdate'] = 'Å iandienos data';
-$labels['datetest'] = 'Data';
-$labels['dateheader'] = 'antraštė:';
-$labels['year'] = 'metai';
-$labels['month'] = 'mėnuo';
-$labels['day'] = 'diena';
-$labels['date'] = 'data (yyyy-mm-dd)';
-$labels['julian'] = 'data (Julijaus)';
-$labels['hour'] = 'valanda';
-$labels['minute'] = 'minutė';
-$labels['second'] = 'sekundė';
-$labels['time'] = 'laikas (hh:mm:ss)';
-$labels['iso8601'] = 'data (ISO8601)';
-$labels['std11'] = 'data (RFC2822)';
-$labels['zone'] = 'laiko-zona';
-$labels['weekday'] = 'savaitės diena (0-6)';
-$labels['advancedopts'] = 'Papildomi nustatymai';
-$labels['body'] = 'Laiško tekstas';
-$labels['address'] = 'adresas';
-$labels['envelope'] = 'vokas';
-$labels['modifier'] = 'midifikatorius:';
-$labels['text'] = 'tekstas';
-$labels['undecoded'] = 'neiškoduotas (pirminis) tekstas';
-$labels['contenttype'] = 'turinio tipas';
-$labels['modtype'] = 'tipas:';
-$labels['allparts'] = 'visi';
-$labels['domain'] = 'sritis';
-$labels['localpart'] = 'vietinė adreso dalis';
-$labels['user'] = 'naudotojas';
-$labels['detail'] = 'detalė';
-$labels['comparator'] = 'palyginimo algoritmas:';
-$labels['default'] = 'numatytasis';
-$labels['octet'] = 'griežtas („octet“)';
-$labels['asciicasemap'] = 'nepaisantis raidžių registro („ascii-casemap“)';
-$labels['asciinumeric'] = 'skaitinis („ascii-numeric“)';
-$labels['index'] = 'turinys:';
-$labels['indexlast'] = 'atbulai';
-$labels['vacation'] = 'Atostogos';
-$labels['vacation.reply'] = 'Atsakyti laišku';
-$labels['vacation.advanced'] = 'Papildomos nuostatos';
-$labels['vacation.subject'] = 'Tema';
-$labels['vacation.body'] = 'Laiško tekstas';
-$labels['vacation.status'] = 'BÅ«sena';
-$labels['vacation.on'] = 'Įjungta';
-$labels['vacation.off'] = 'IÅ¡jungta';
-$labels['vacation.addresses'] = 'Mano papildomi adresai';
-$labels['vacation.interval'] = 'Atsakymo intervalas';
-$labels['vacation.after'] = 'Atostogų taisyklę pastatyti po';
-$labels['vacation.saving'] = 'IÅ¡saugomi duomenys...';
-$labels['vacation.action'] = 'Veiksmas su gaunamais laiškais';
-$labels['vacation.keep'] = 'Palikti';
-$labels['vacation.discard'] = 'Panaikinti';
-$labels['vacation.redirect'] = 'Peradresuoti kam';
-$labels['vacation.copy'] = 'Siųsti kopiją kam';
-$labels['arialabelfiltersetactions'] = 'Filtrų rinkinio veiksmai';
-$labels['arialabelfilteractions'] = 'Filtro veiksmai';
-$labels['arialabelfilterform'] = 'Filtro nustatymai';
-$labels['ariasummaryfilterslist'] = 'Filtrų sąrašas';
-$labels['ariasummaryfiltersetslist'] = 'Filtrų rinkinių sąrašas';
-$labels['filterstitle'] = 'Tvarkyti gaunamų laiškų filtrus';
-$labels['vacationtitle'] = 'Redaguoti ne-biure taisyklę';
-$messages['filterunknownerror'] = 'Nežinoma serverio klaida.';
-$messages['filterconnerror'] = 'Neįmanoma užmegzti ryšio su serveriu.';
-$messages['filterdeleteerror'] = 'Nepavyksta ištrinti filtro. Įvyko serverio klaida.';
-$messages['filterdeleted'] = 'Filtras panaikintas sėkmingai.';
-$messages['filtersaved'] = 'Filtras sėkmingai išsaugotas';
-$messages['filtersaveerror'] = 'Nepavyksta išsaugoti filtro. Įvyko serverio klaida.';
-$messages['filterdeleteconfirm'] = 'Ar jūs esate įsitikinęs, jog norite panaikinti pasirinktus filtrus(-ą)?';
-$messages['ruledeleteconfirm'] = 'Ar jūs įsitikinęs, jog norite panaikinti pasirinktą taisyklę?';
-$messages['actiondeleteconfirm'] = 'Ar jūs įsitikinęs, jog norite panaikinti pasirinktą veiksmą?';
-$messages['forbiddenchars'] = 'Laukelyje yra draudžiamų simbolių.';
-$messages['cannotbeempty'] = 'Laukelis negali būti tuščias';
-$messages['ruleexist'] = 'Filtras tokiu vardu jau yra.';
-$messages['setactivateerror'] = 'Neįmanoma aktyvuoti pasirinkto filtrų rinkinio. Įvyko serverio klaida.';
-$messages['setdeactivateerror'] = 'Neįmanoma išjungti pasirinkto filtrų rinkinio. Įvyko serverio klaida.';
-$messages['setdeleteerror'] = 'Neįmanoma panaikinti pasirinkto filtrų rinkinio. Įvyko serverio klaida.';
-$messages['setactivated'] = 'Filtrų rinkinys sėkmingai aktyvuotas.';
-$messages['setdeactivated'] = 'Filtrų rinkinys sėkmingai deaktyvuotas.';
-$messages['setdeleted'] = 'Filtrų rinkinys sėkmingai panaikintas.';
-$messages['setdeleteconfirm'] = 'Ar jūs esate tikri, jog norite panaikinti pasirinktą filtrų rinkinį?';
-$messages['setcreateerror'] = 'Neįmanoma sukurti filtrų rinkinio. Įvyko serverio klaida.';
-$messages['setcreated'] = 'Filtrų rinkinys sėkmingai sukurtas.';
-$messages['activateerror'] = 'Neįmanoma įjungti pasirinktų filtrų(-o). Įvyko serverio klaida.';
-$messages['deactivateerror'] = 'Neįmanoma išjungti pasirinktų filtrų(-o). Įvyko serverio klaida.';
-$messages['deactivated'] = 'Filtras(-as) sėkmingai išjungti.';
-$messages['activated'] = 'Filtras(-as) sėkmingai įjungti.';
-$messages['moved'] = 'Filtrai perkelti sėkmingai.';
-$messages['moveerror'] = 'Pasirinkto filtro perkelti neįmanoma. Įvyko serverio klaida.';
-$messages['nametoolong'] = 'Vardas per ilgas.';
-$messages['namereserved'] = 'Rezervuotas vardas.';
-$messages['setexist'] = 'Rinkinys jau yra sukurtas.';
-$messages['nodata'] = 'Būtina pasirinkti bent vieną poziciją!';
-$messages['invaliddateformat'] = 'Neteisingas datos ar jos dalies formatas';
-$messages['saveerror'] = 'Nepavyksta išsaugoti duomenų. Įvyko serverio klaida.';
-$messages['vacationsaved'] = 'Sėkmingai išsaugoti atostogų duomenys.';
-?>
diff --git a/lib/plugins/managesieve/localization/lv_LV.inc b/lib/plugins/managesieve/localization/lv_LV.inc
deleted file mode 100644
index 33c000e..0000000
--- a/lib/plugins/managesieve/localization/lv_LV.inc
+++ /dev/null
@@ -1,188 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Vēstuļu filtri';
-$labels['managefilters'] = 'Pārvaldīt ienākošo vēstuļu filtrus';
-$labels['filtername'] = 'Filtra nosaukums';
-$labels['newfilter'] = 'Jauns filtrs';
-$labels['filteradd'] = 'Pievienot filtru';
-$labels['filterdel'] = 'Dzēst filtru';
-$labels['moveup'] = 'Pārvietot augšup';
-$labels['movedown'] = 'Pārvietot lejup';
-$labels['filterallof'] = 'jāatbilst visiem sekojošajiem nosacījumiem';
-$labels['filteranyof'] = 'jāatbilst jebkuram no sekojošajiem 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['filtermatches'] = 'jāatbilst izteiksmei';
-$labels['filternotmatches'] = 'neatbilst izteiksmei';
-$labels['filterregex'] = 'jāatbilst regulārai izteiksmei';
-$labels['filternotregex'] = 'neatbilst regulārai izteiksmei';
-$labels['filterunder'] = 'zem';
-$labels['filterover'] = 'virs';
-$labels['addrule'] = 'Pievienot nosacījumu';
-$labels['delrule'] = 'Dzēst nosacījumu';
-$labels['messagemoveto'] = 'Pārvietot vēstuli uz';
-$labels['messageredirect'] = 'Pāradresēt vēstuli uz';
-$labels['messagecopyto'] = 'Kopēt vēstuli uz';
-$labels['messagesendcopy'] = 'Pārsūtīt vēstules kopiju uz';
-$labels['messagereply'] = 'Atbildēt ar vēstuli';
-$labels['messagedelete'] = 'Dzēst vēstuli';
-$labels['messagediscard'] = 'Dzēst vēstuli un atbildēt';
-$labels['messagekeep'] = 'Paturēt ziņu Iesūtnē';
-$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['vacationaddr'] = 'Mana(s) papildus e-pasta adrese(s):';
-$labels['vacationdays'] = 'Cik bieži sūtī ziņojumus (dienās):';
-$labels['vacationinterval'] = 'Cik bieži sūtīt vēstules:';
-$labels['vacationreason'] = 'Atvaļinājuma paziņojuma teksts:';
-$labels['vacationsubject'] = 'Vēstules tēma:';
-$labels['days'] = 'dienas';
-$labels['seconds'] = 'sekundes';
-$labels['rulestop'] = 'Apturēt nosacījumu pārbaudi';
-$labels['enable'] = 'Ieslēgt/Izslēgt';
-$labels['filterset'] = 'Filtru kopa';
-$labels['filtersets'] = 'Filtru kopas';
-$labels['filtersetadd'] = 'Pievienot filtru kopu';
-$labels['filtersetdel'] = 'Dzē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['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 kā';
-$labels['countisgreaterthanequal'] = 'skaits ir vienāds vai lielāks kā';
-$labels['countislessthan'] = 'skaits ir mazāks kā';
-$labels['countislessthanequal'] = 'skaits ir vienāds vai mazāks kā';
-$labels['countequals'] = 'skaits ir vienāds ar';
-$labels['countnotequals'] = 'skaits nav vienāds ar';
-$labels['valueisgreaterthan'] = 'vērtība ir lielāka kā';
-$labels['valueisgreaterthanequal'] = 'vērtība ir vienāda vai lielāka kā';
-$labels['valueislessthan'] = 'vērtība ir mazāka kā';
-$labels['valueislessthanequal'] = 'vērtība ir vienāda vai mazāka kā';
-$labels['valueequals'] = 'vērtība ir vienāda ar';
-$labels['valuenotequals'] = 'vērtība nav vienāda ar';
-$labels['setflags'] = 'Marķēt vēstuli';
-$labels['addflags'] = 'Pievienot vēstulei marķierus';
-$labels['removeflags'] = 'Noņemt vēstulei marķierus';
-$labels['flagread'] = 'Lasītas';
-$labels['flagdeleted'] = 'Dzēstas';
-$labels['flaganswered'] = 'Atbildētas';
-$labels['flagflagged'] = 'Marķētas';
-$labels['flagdraft'] = 'Melnraksts';
-$labels['setvariable'] = 'Iestatīt mainīgo';
-$labels['setvarname'] = 'Mainīgā nosaukums:';
-$labels['setvarvalue'] = 'Mainīgā vērtība:';
-$labels['setvarmodifiers'] = 'Modifikatori:';
-$labels['varlower'] = 'mazie burti';
-$labels['varupper'] = 'lielie burti';
-$labels['varlowerfirst'] = 'pirmais burts kā mazais burts';
-$labels['varupperfirst'] = 'pirmais burts kā lielais burts';
-$labels['varquotewildcard'] = '"citēt" speciālās rakstzīmes';
-$labels['varlength'] = 'garums';
-$labels['notify'] = 'Sūtīt paziņojumus';
-$labels['notifyimportance'] = 'Svarīgums:';
-$labels['notifyimportancelow'] = 'zems';
-$labels['notifyimportancenormal'] = 'parasts';
-$labels['notifyimportancehigh'] = 'augsts';
-$labels['filtercreate'] = 'Izveidot filtru';
-$labels['usedata'] = 'Filtrā izmantot sekojošus datus';
-$labels['nextstep'] = 'Nākamais solis';
-$labels['...'] = '...';
-$labels['currdate'] = 'Pašreizējais datums';
-$labels['datetest'] = 'Datums';
-$labels['dateheader'] = 'galvene:';
-$labels['year'] = 'gads';
-$labels['month'] = 'mēnesis';
-$labels['day'] = 'diena';
-$labels['date'] = 'datums (gggg-mm-dd)';
-$labels['julian'] = 'datums (Jūlija kalendārs)';
-$labels['hour'] = 'stunda';
-$labels['minute'] = 'minūte';
-$labels['second'] = 'sekunde';
-$labels['time'] = 'laiks (hh:mm:ss)';
-$labels['iso8601'] = 'datums (ISO8601)';
-$labels['std11'] = 'datums (RFC2822)';
-$labels['zone'] = 'laikajosla';
-$labels['weekday'] = 'nedēļas diena (0-6)';
-$labels['advancedopts'] = 'Paplašinātie iestatījumi';
-$labels['body'] = 'Pamatteksts';
-$labels['address'] = 'adresāts';
-$labels['envelope'] = 'aploksne';
-$labels['modifier'] = 'modifikators:';
-$labels['text'] = 'teksts';
-$labels['undecoded'] = 'neatkodēts (neapstrādāti dati)';
-$labels['contenttype'] = 'satura tips';
-$labels['modtype'] = 'tips:';
-$labels['allparts'] = 'viss';
-$labels['domain'] = 'domēns';
-$labels['localpart'] = 'lokālā daļa';
-$labels['user'] = 'lietotājs';
-$labels['detail'] = 'detaļas';
-$labels['comparator'] = 'salīdzinātājs';
-$labels['default'] = 'noklusētā vērtība';
-$labels['octet'] = 'precīzs (oktets)';
-$labels['asciicasemap'] = 'reģistrnejutīgs (ascii tabula)';
-$labels['asciinumeric'] = 'skaitļu (ascii skaitļu)';
-$labels['index'] = 'indekss:';
-$labels['indexlast'] = 'atpakaļ';
-$messages['filterunknownerror'] = 'Nezināma servera kļūda.';
-$messages['filterconnerror'] = 'Neizdevās pieslēgties ManageSieve serverim.';
-$messages['filterdeleteerror'] = 'Neizdevās izdzēst filtru - atgadījās 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 - atgadījās servera iekšējā kļūda.';
-$messages['filterdeleteconfirm'] = 'Vai Jūs tiešām vēlaties dzēst atzīmēto filtru?';
-$messages['ruledeleteconfirm'] = 'Vai Jūs tiešām vēlaties dzēst atzīmēto nosacījumu?';
-$messages['actiondeleteconfirm'] = 'Vai Jūs 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['ruleexist'] = 'Filtrs ar tādu nosaukumu jau pastāv.';
-$messages['setactivateerror'] = 'Neizdevās aktivizēt atzīmēto filtru kopu - atgadījās servera iekšējā kļūda.';
-$messages['setdeactivateerror'] = 'Neizdevās deaktivizēt atzīmēto filtru kopu - atgadījās servera iekšējā kļūda.';
-$messages['setdeleteerror'] = 'Neizdevās izdzēst atzīmēto filtru kopu - atgadījās servera ieksē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 Jūs vēlaties dzēst atzīmēto filtru kopu?';
-$messages['setcreateerror'] = 'Neizdevās izveidot filtru kopu - atgadījās servera iekšējā kļūda.';
-$messages['setcreated'] = 'Filtru kopa veiksmīgi izveidota.';
-$messages['activateerror'] = 'Nav iespējams ieslēgt izvēlēto(s) filtru(s) - atgadījās servera iekšējā kļūda.';
-$messages['deactivateerror'] = 'Nav iespējams atslēgt izvēlēto(s) filtru(s) - atgadījās servera iekšējā kļūda.';
-$messages['deactivated'] = 'Filtrs(i) veiksmīgi atslēgts(i).';
-$messages['activated'] = 'Filtrs(i) veiksmīgi ieslēgts(i).';
-$messages['moved'] = 'Filtrs veiksmīgi pārvietots.';
-$messages['moveerror'] = 'Nav iespējams pārvietot izvēlēto filtru - atgadījās servera iekšējā kļūda.';
-$messages['nametoolong'] = 'Neizdevās izveidot filtru kopu. Pārāk garš kopas nosaukums.';
-$messages['namereserved'] = 'Rezervētais nosaukums.';
-$messages['setexist'] = 'Kopa jau eksistē.';
-$messages['nodata'] = 'Ir jābūt atzīmētai vismaz vienai pozīcijai!';
-$messages['invaliddateformat'] = 'Nederīgs datums vai datuma formāts';
-?>
diff --git a/lib/plugins/managesieve/localization/ml_IN.inc b/lib/plugins/managesieve/localization/ml_IN.inc
deleted file mode 100644
index 613695c..0000000
--- a/lib/plugins/managesieve/localization/ml_IN.inc
+++ /dev/null
@@ -1,148 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'അരിപ്പകള്‍';
-$labels['managefilters'] = 'അകത്തോട്ടുള്ള ഇമെയില്‍ അരിപ്പകള്‍ ക്രമീകരിക്കുക';
-$labels['filtername'] = 'അരിപ്പയുടെ പേര്';
-$labels['newfilter'] = 'പുതിയ അരിപ്പ';
-$labels['filteradd'] = 'അരിപ്പ ചേര്‍ക്കുക';
-$labels['filterdel'] = 'അരിപ്പ നീക്കംചെയ്യുക';
-$labels['moveup'] = 'മുകളിലേക്ക് നീക്കുക';
-$labels['movedown'] = 'താഴേക്ക് നീക്കുക';
-$labels['filterallof'] = 'കീഴ്പറഞ്ഞ എല്ലാ നിയമങ്ങളും പാലിക്കുന്നവ';
-$labels['filteranyof'] = 'കീഴ്പറഞ്ഞ ഏതെങ്കിലും നിയമം പാലിക്കുന്നവ';
-$labels['filterany'] = 'എല്ലാ സന്ദേശങ്ങളും';
-$labels['filtercontains'] = 'അടങ്ങുന്നത്';
-$labels['filternotcontains'] = 'ല്‍ അടങ്ങുന്നില്ല';
-$labels['filteris'] = 'ന് തുല്യം';
-$labels['filterisnot'] = 'ന് തുല്യമല്ല';
-$labels['filterexists'] = 'നിലവിലുണ്ട്';
-$labels['filternotexists'] = 'നിലവിലില്ല';
-$labels['filtermatches'] = 'എക്സ്പ്രഷന്‍ ചേരുന്നുണ്ട്';
-$labels['filternotmatches'] = 'എക്സ്പ്രഷന്‍ ചേരുന്നില്ല';
-$labels['filterregex'] = 'റെഗുലര്‍ എക്സ്പ്രഷന്‍ ചേരുന്നുണ്ട്';
-$labels['filternotregex'] = 'റെഗുലര്‍ എക്സ്പ്രഷന്‍ ചേരുന്നില്ല';
-$labels['filterunder'] = 'കീഴില്‍';
-$labels['filterover'] = 'മുകളില്‍';
-$labels['addrule'] = 'നിയമം ചേര്‍ക്കുക';
-$labels['delrule'] = 'നിയമം നീക്കം ചെയ്യുക';
-$labels['messagemoveto'] = 'സന്ദേശം നിക്കു :';
-$labels['messageredirect'] = 'സന്ദേശം മാറ്റിവിടു :';
-$labels['messagecopyto'] = 'സന്ദേശം പകര്‍ത്തു :';
-$labels['messagesendcopy'] = 'സന്ദേശത്തിന്റെ പകര്‍പ്പ് അയക്കു :';
-$labels['messagereply'] = 'സന്ദേശം വെച്ച് മറുപടി അയക്കു';
-$labels['messagedelete'] = 'സന്ദേശം മായ്ക്കു';
-$labels['messagediscard'] = 'സന്ദേശത്തോടെ നിരാകരിക്കുക';
-$labels['messagekeep'] = 'സന്ദേശം ഇൻബോക്സിൽ സൂക്ഷിക്കുക';
-$labels['messagesrules'] = 'ആഗമന സന്ദേശങ്ങള്‍ക്ക്:';
-$labels['messagesactions'] = '...ഈ പ്രവര്‍ത്തനങ്ങള്‍ ചെയ്യുക:';
-$labels['add'] = 'ചേര്‍ക്കു';
-$labels['del'] = 'നീക്കം ചെയ്യുക';
-$labels['sender'] = 'അയചയാള്‍';
-$labels['recipient'] = 'സ്വീകര്‍ത്താവ്';
-$labels['vacationaddr'] = 'എന്റെ മറ്റ് ഈമെയിൽ വിലാസങ്ങൾ:';
-$labels['vacationdays'] = 'എത്ര ഭിവസം കൂടുമ്പോള്‍ സന്ദേശം അയക്കണം:';
-$labels['vacationinterval'] = 'എത്ര സമയം കൂടുമ്പോൾ സന്ദേശങ്ങൾ അയയ്ക്കണം:';
-$labels['vacationreason'] = 'സന്ദേശത്തിന്റെ ഉള്ളടക്കം (അവധിയുടെ കാരണം):';
-$labels['vacationsubject'] = 'സന്ദേശത്തിന്റെ വിഷയം:';
-$labels['days'] = 'ദിവസങ്ങൾ';
-$labels['seconds'] = 'സെക്കന്റുകൾ';
-$labels['rulestop'] = 'നിയമങ്ങള്‍ വിലയിരുത്തുന്നത് നിര്‍ത്തുക';
-$labels['enable'] = 'പ്രവര്‍ത്തനസജ്ജം/രഹിതം';
-$labels['filterset'] = 'അരിപ്പകളുടെ കൂട്ടം';
-$labels['filtersets'] = 'അരിപ്പകളുടെ കൂട്ടങ്ങള്‍';
-$labels['filtersetadd'] = 'അരിപ്പകളുടെ കൂട്ടം ചേര്‍ക്കുക';
-$labels['filtersetdel'] = 'ഇപ്പോഴത്തെ അരിപ്പകളുടെ കൂട്ടം മായ്ക്കുക';
-$labels['filtersetact'] = 'ഇപ്പോഴത്തെ അരിപ്പകളുടെ കൂട്ടം പ്രവര്‍ത്തിപ്പിക്കുക';
-$labels['filtersetdeact'] = 'ഇപ്പോഴത്തെ അരിപ്പകളുടെ കൂട്ടം പ്രവര്‍ത്തനം അവസാനിപ്പിക്കുക';
-$labels['filterdef'] = 'അരിപ്പയുടെ നിര്‍വ്വചനം';
-$labels['filtersetname'] = 'അരിപ്പകളുടെ കൂട്ടത്തിന്റെ പേര്';
-$labels['newfilterset'] = 'പുതിയ അരിപ്പയുട കൂട്ടം';
-$labels['active'] = 'സജീവം';
-$labels['none'] = 'ഒന്നുമില്ല';
-$labels['fromset'] = 'സെറ്റില്‍ നിന്ന്';
-$labels['fromfile'] = 'ഫയലില്‍ നിന്ന്';
-$labels['filterdisabled'] = 'അരിപ്പ പ്രവര്‍ത്തനരഹിതമാക്കി';
-$labels['countisgreaterthan'] = 'എണ്ണം ഇതിനെക്കാള്‍ കുടുതല്‍';
-$labels['countisgreaterthanequal'] = 'എണ്ണം ഇതിനെക്കാള്‍ കൂടുതല്‍ ഇല്ലെങ്കില്‍ സമം';
-$labels['countislessthan'] = 'എണ്ണം ഇതിനെക്കാള്‍ കുറവ്';
-$labels['countislessthanequal'] = 'എണ്ണം ഇതിനെക്കാള്‍ കൂറവ് ഇല്ലെങ്കില്‍ സമം';
-$labels['countequals'] = 'എണ്ണം ഇതിനോട് സമം';
-$labels['countnotequals'] = 'എണ്ണം ഇതിനോട് തുല്യമല്ല';
-$labels['valueisgreaterthan'] = 'മൂല്യം ഇതിനെക്കാള്‍ കുടുതല്‍';
-$labels['valueisgreaterthanequal'] = 'മുല്യം ഇതിനെക്കാള്‍ കൂടുതല്‍ ഇല്ലെങ്കില്‍ സമം';
-$labels['valueislessthan'] = 'മൂല്യം ഇതിനെക്കാള്‍ കുറവ്';
-$labels['valueislessthanequal'] = 'മൂല്യം ഇതിനെക്കാള്‍ കൂറവ് ഇല്ലെങ്കില്‍ തുല്യം';
-$labels['valueequals'] = 'മൂല്യം ഇതിനോട് സമം';
-$labels['valuenotequals'] = 'മൂല്യം ഇതിനോട് തുല്യമല്ല';
-$labels['setflags'] = 'സന്ദേശത്തില്‍ അടയാളമിടുക';
-$labels['addflags'] = 'സന്ദേശത്തില്‍ അടയാളം ചേര്‍ക്കുക';
-$labels['removeflags'] = 'സന്ദേശത്തില്‍ നിന്നും അടയാളം മാറ്റുക';
-$labels['flagread'] = 'വായിച്ചവ';
-$labels['flagdeleted'] = 'നീക്കം ചെയ്തവ';
-$labels['flaganswered'] = 'മറുപടി നല്‍കിയവ';
-$labels['flagflagged'] = 'അടയാളപ്പെടുത്തിയവ';
-$labels['flagdraft'] = 'കരട്';
-$labels['setvariable'] = 'വേരിയബിൾ സ്ഥിരപ്പെടുത്തുക';
-$labels['setvarname'] = 'വേരിയബിളിന്റെ പേര്';
-$labels['setvarvalue'] = 'വേരിയബിളിന്റെ മൂല്യം';
-$labels['filtercreate'] = 'അരിപ്പ ഉണ്ടാക്കുക';
-$labels['usedata'] = 'ഈ വിവരങ്ങള്‍ അരിപ്പയില്‍ ഉപയോഗിക്കുക:';
-$labels['nextstep'] = 'അടുത്ത പടി';
-$labels['...'] = '...';
-$labels['advancedopts'] = 'വിപുലീക്രിതമായ ക്രമീകരണങ്ങള്‍';
-$labels['body'] = 'ഉള്ളടക്കം';
-$labels['address'] = 'മേല്‍വിലാസം';
-$labels['envelope'] = 'എന്‍വലപ്പ്';
-$labels['modifier'] = 'മോഡിഫയര്‍:';
-$labels['text'] = 'വാചകം';
-$labels['undecoded'] = 'ഡീക്കോഡ് ചെയ്യാത്തത് (റോ)';
-$labels['contenttype'] = 'ഉള്ളടക്കത്തിന്റെ തരം';
-$labels['modtype'] = 'തരം:';
-$labels['allparts'] = 'എല്ലാം';
-$labels['domain'] = 'ഡൊമൈന്‍';
-$labels['localpart'] = 'പ്രാദേശിക ഭാഗം';
-$labels['user'] = 'ഉപയോക്താവു്';
-$labels['detail'] = 'വിശദാംശം';
-$labels['comparator'] = 'താരതമ്യകന്‍:';
-$labels['default'] = 'സഹജമായ';
-$labels['octet'] = 'കര്‍ശനം (octet)';
-$labels['asciicasemap'] = 'വലിയ-ചെറിയക്ഷരങ്ങള്‍ തമ്മില്‍ വ്യത്യാസമില്ലാത്ത (ascii-casemap)';
-$labels['asciinumeric'] = 'സംഖ്യകള്‍ (ascii-numeric)';
-$messages['filterunknownerror'] = 'അജ്ഞാതമായ സെര്‍വ്വര്‍ പിശക്.';
-$messages['filterconnerror'] = 'സെര്‍വ്വറുമായി ബന്ധപ്പെടാന്‍ സാധിക്കുന്നില്ല.';
-$messages['filterdeleted'] = 'അരിപ്പ വിജകരമായി മായ്ച്ചു.';
-$messages['filtersaved'] = 'അരിപ്പ വിജകരമായി സൂക്ഷിച്ചു.';
-$messages['filterdeleteconfirm'] = 'തെരഞ്ഞെടുത്ത അരിപ്പ നീക്കം ചെയ്യണമെന്ന് ഉറപ്പാണോ?';
-$messages['ruledeleteconfirm'] = 'തെരഞ്ഞെടുത്ത നിയമം നീക്കം ചെയ്യണമെന്ന് ഉറപ്പാണോ?';
-$messages['actiondeleteconfirm'] = 'തെരഞ്ഞെടുത്ത പ്രവര്‍ത്തി നീക്കം ചെയ്യണമെന്ന് ഉറപ്പാണോ?';
-$messages['forbiddenchars'] = 'ഫില്‍ഡില്‍ സാധുവല്ലാത്ത അക്ഷരങ്ങള്‍.';
-$messages['cannotbeempty'] = 'ഫീല്‍ഡ് ശൂന്യമാകാന്‍ പാടില്ല.';
-$messages['ruleexist'] = 'ഈ പേരിലുള്ള അരിപ്പ ഇപ്പോള്‍ തന്നെ ഉണ്ട്.';
-$messages['setactivated'] = 'അരിപ്പകളുടെ കൂട്ടത്തെ വിജയകരമായി പ്രവര്‍ത്തനസജ്ജമാക്കി.';
-$messages['setdeactivated'] = 'അരിപ്പകളുടെ കൂട്ടത്തെ വിജയകരമായി പ്രവര്‍ത്തനരഹിതമാക്കി.';
-$messages['setdeleted'] = 'അരിപ്പകളുടെ കൂട്ടത്തെ വിജയകരമായി മായ്ച്ചു.';
-$messages['setdeleteconfirm'] = 'തെരഞ്ഞെടുത്ത അരിപ്പകളുടെ കൂട്ടത്തെ നീക്കം ചെയ്യണമെന്ന് ഉറപ്പാണോ?';
-$messages['setcreated'] = 'അരിപ്പകളുടെ കൂട്ടത്തെ വിജയകരമായി നിര്‍മ്മിച്ചു.';
-$messages['deactivated'] = 'അരിപ്പ വിജകരമായി പ്രവര്‍ത്തനസജ്ജമാക്കി.';
-$messages['activated'] = 'അരിപ്പകള്‍ നിര്‍വീര്യം ആക്കപ്പെട്ടിരിക്കുന്നു';
-$messages['moved'] = 'അരിപ്പ വിജകരമായി മാറ്റി.';
-$messages['nametoolong'] = 'പേരിന് നീളം കൂടുതല്‍.';
-$messages['namereserved'] = 'നീക്കിവെച്ച വാക്ക്.';
-$messages['setexist'] = 'കൂട്ടം നേരത്തെ തന്നെ ഉണ്ട്.';
-$messages['nodata'] = 'ഒരു സ്ഥാനമെങ്കിലും തെരഞ്ഞെടുക്കണം!';
-?>
diff --git a/lib/plugins/managesieve/localization/mr_IN.inc b/lib/plugins/managesieve/localization/mr_IN.inc
deleted file mode 100644
index 88edb92..0000000
--- a/lib/plugins/managesieve/localization/mr_IN.inc
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'चाळण्या';
-$labels['moveup'] = 'वर हलवा';
-$labels['movedown'] = 'खाली हलवा';
-$labels['filterallof'] = 'खालील सर्व नियम जुळत आहेत';
-$labels['filterany'] = 'सर्व संदेश';
-$labels['filteris'] = 'च्या बरोबर आहे';
-$labels['filterisnot'] = 'च्या बरोबर नाही';
-$labels['filterexists'] = 'अस्तित्वात आहे';
-$labels['filternotexists'] = 'अस्तित्वात नाही';
-$labels['filterunder'] = 'खाली';
-$labels['filterover'] = 'वरती';
-$labels['messagedelete'] = 'संदेश काढून टाका';
-$labels['messagesactions'] = 'खालील कृती आमलात आणा :';
-$labels['add'] = 'समावेश करा';
-$labels['del'] = 'नष्ट करा';
-$labels['sender'] = 'प्रेषक';
-?>
diff --git a/lib/plugins/managesieve/localization/nb_NO.inc b/lib/plugins/managesieve/localization/nb_NO.inc
deleted file mode 100644
index c9224ae..0000000
--- a/lib/plugins/managesieve/localization/nb_NO.inc
+++ /dev/null
@@ -1,188 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtre';
-$labels['managefilters'] = 'Rediger filter for innkommende e-post';
-$labels['filtername'] = 'Filternavn';
-$labels['newfilter'] = 'Nytt filter';
-$labels['filteradd'] = 'Legg til filter';
-$labels['filterdel'] = 'Slett filter';
-$labels['moveup'] = 'Flytt opp';
-$labels['movedown'] = 'Flytt ned';
-$labels['filterallof'] = 'som treffer alle følgende regler';
-$labels['filteranyof'] = 'som treffer en av følgende regler';
-$labels['filterany'] = 'alle meldinger';
-$labels['filtercontains'] = 'inneholder';
-$labels['filternotcontains'] = 'ikke inneholder';
-$labels['filteris'] = 'er lik';
-$labels['filterisnot'] = 'er ulik';
-$labels['filterexists'] = 'eksisterer';
-$labels['filternotexists'] = 'ikke eksisterer';
-$labels['filtermatches'] = 'treffer uttrykk';
-$labels['filternotmatches'] = 'ikke treffer uttrykk';
-$labels['filterregex'] = 'treffer regulært uttrykk';
-$labels['filternotregex'] = 'ikke treffer regulært uttrykk';
-$labels['filterunder'] = 'under';
-$labels['filterover'] = 'over';
-$labels['addrule'] = 'Legg til regel';
-$labels['delrule'] = 'Slett regel';
-$labels['messagemoveto'] = 'Flytt meldingen til';
-$labels['messageredirect'] = 'Videresend meldingen til';
-$labels['messagecopyto'] = 'Kopier meldingen til';
-$labels['messagesendcopy'] = 'Send en kopi av meldingen til';
-$labels['messagereply'] = 'Svar med melding';
-$labels['messagedelete'] = 'Slett melding';
-$labels['messagediscard'] = 'Avvis med melding';
-$labels['messagekeep'] = 'Behold melding i innboks';
-$labels['messagesrules'] = 'For innkommende e-post';
-$labels['messagesactions'] = '... gjør følgende:';
-$labels['add'] = 'Legg til';
-$labels['del'] = 'Slett';
-$labels['sender'] = 'Avsender';
-$labels['recipient'] = 'Mottaker';
-$labels['vacationaddr'] = 'Tilleggs epost-adresse(r):';
-$labels['vacationdays'] = 'Periode mellom meldinger (i dager):';
-$labels['vacationinterval'] = 'Periode mellom meldinger:';
-$labels['vacationreason'] = 'Innhold (begrunnelse for fravær)';
-$labels['vacationsubject'] = 'Meldingsemne:';
-$labels['days'] = 'dager';
-$labels['seconds'] = 'sekunder';
-$labels['rulestop'] = 'Stopp evaluering av regler';
-$labels['enable'] = 'Aktiver/Deaktiver';
-$labels['filterset'] = 'Filtersett';
-$labels['filtersets'] = 'Filtersett';
-$labels['filtersetadd'] = 'Nytt filtersett';
-$labels['filtersetdel'] = 'Slett gjeldende filtersett';
-$labels['filtersetact'] = 'Aktiver gjeldende filtersett';
-$labels['filtersetdeact'] = 'Deaktiver gjeldende filtersett';
-$labels['filterdef'] = 'Filterdefinisjon';
-$labels['filtersetname'] = 'Navn på filtersett';
-$labels['newfilterset'] = 'Nytt filtersett';
-$labels['active'] = 'aktiv';
-$labels['none'] = 'ingen';
-$labels['fromset'] = 'fra sett';
-$labels['fromfile'] = 'fra fil';
-$labels['filterdisabled'] = 'Filter deaktivert';
-$labels['countisgreaterthan'] = 'antall er flere enn';
-$labels['countisgreaterthanequal'] = 'antall er flere enn eller lik';
-$labels['countislessthan'] = 'antall er færre enn';
-$labels['countislessthanequal'] = 'antall er færre enn eller lik';
-$labels['countequals'] = 'antall er lik';
-$labels['countnotequals'] = 'tallet er ikke det samme som';
-$labels['valueisgreaterthan'] = 'verdien er høyrere enn';
-$labels['valueisgreaterthanequal'] = 'verdien er høyere eller lik';
-$labels['valueislessthan'] = 'verdien er lavere enn';
-$labels['valueislessthanequal'] = 'verdien er lavere eller lik';
-$labels['valueequals'] = 'verdien er lik';
-$labels['valuenotequals'] = 'verdien er ikke den samme som';
-$labels['setflags'] = 'Sett meldingsflagg';
-$labels['addflags'] = 'Legg til flagg på meldingen';
-$labels['removeflags'] = 'Fjern flagg fra meldingen';
-$labels['flagread'] = 'Lese';
-$labels['flagdeleted'] = 'Slettet';
-$labels['flaganswered'] = 'Besvart';
-$labels['flagflagged'] = 'Flagget';
-$labels['flagdraft'] = 'Utkast';
-$labels['setvariable'] = 'Set variabel';
-$labels['setvarname'] = 'Variabelnavn:';
-$labels['setvarvalue'] = 'Variabel verdi:';
-$labels['setvarmodifiers'] = 'Modifikator:';
-$labels['varlower'] = 'med små bokstaver';
-$labels['varupper'] = 'med store bokstaver';
-$labels['varlowerfirst'] = 'første tegn liten bokstav';
-$labels['varupperfirst'] = 'første tegn stor bokstav';
-$labels['varquotewildcard'] = 'sitér spesialtegn';
-$labels['varlength'] = 'lengde';
-$labels['notify'] = 'Send melding';
-$labels['notifyimportance'] = 'Viktighet:';
-$labels['notifyimportancelow'] = 'lav';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'høy';
-$labels['filtercreate'] = 'Opprett filter';
-$labels['usedata'] = 'Bruk følgende data i filteret:';
-$labels['nextstep'] = 'Neste steg';
-$labels['...'] = '…';
-$labels['currdate'] = 'Nåværende dato';
-$labels['datetest'] = 'Dato';
-$labels['dateheader'] = 'header:';
-$labels['year'] = 'Ã¥r';
-$labels['month'] = 'måned';
-$labels['day'] = 'dag';
-$labels['date'] = 'dato (yyyy-mm-dd)';
-$labels['julian'] = 'dato (juliansk)';
-$labels['hour'] = 'time';
-$labels['minute'] = 'minutt';
-$labels['second'] = 'sekund';
-$labels['time'] = 'tid (hh:mm:ss)';
-$labels['iso8601'] = 'dato (ISO8601)';
-$labels['std11'] = 'dato (RFC2822)';
-$labels['zone'] = 'tidssone';
-$labels['weekday'] = 'ukedag (0-6)';
-$labels['advancedopts'] = 'Avanserte alternativer';
-$labels['body'] = 'Meldingstekst';
-$labels['address'] = 'adresse';
-$labels['envelope'] = 'konvolutt';
-$labels['modifier'] = 'modifikator:';
-$labels['text'] = 'tekst';
-$labels['undecoded'] = 'ikke dekodet (rå)';
-$labels['contenttype'] = 'innholdstype';
-$labels['modtype'] = 'type:';
-$labels['allparts'] = 'alle';
-$labels['domain'] = 'domene';
-$labels['localpart'] = 'lokal del (local part)';
-$labels['user'] = 'bruker';
-$labels['detail'] = 'detalj';
-$labels['comparator'] = 'sammenligning:';
-$labels['default'] = 'standard';
-$labels['octet'] = 'streng (oktett)';
-$labels['asciicasemap'] = 'ikke skill store og små bokstaver (ascii-casemap)';
-$labels['asciinumeric'] = 'numerisk (ascii-numeric)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'baklengs';
-$messages['filterunknownerror'] = 'Ukjent problem med tjener.';
-$messages['filterconnerror'] = 'Kunne ikke koble til tjeneren.';
-$messages['filterdeleteerror'] = 'Kunne ikke slette filter. Fikk feilmelding fra server.';
-$messages['filterdeleted'] = 'Filteret er blitt slettet.';
-$messages['filtersaved'] = 'Filteret er blitt lagret.';
-$messages['filtersaveerror'] = 'Kunne ikke lagre filter. Fikk feilmelding fra server.';
-$messages['filterdeleteconfirm'] = 'Vil du virkelig slette det valgte filteret?';
-$messages['ruledeleteconfirm'] = 'Er du sikker på at du vil slette valgte regel?';
-$messages['actiondeleteconfirm'] = 'Er du sikker på at du vil slette valgte hendelse?';
-$messages['forbiddenchars'] = 'Ugyldige tegn i felt.';
-$messages['cannotbeempty'] = 'Feltet kan ikke stå tomt.';
-$messages['ruleexist'] = 'Det finnes allerede et filter med dette navnet.';
-$messages['setactivateerror'] = 'Kunne ikke aktivere valgte filtersett. Fikk feilmelding fra server.';
-$messages['setdeactivateerror'] = 'Kunne ikke deaktivere valgte filtersett. Fikk feilmelding fra server.';
-$messages['setdeleteerror'] = 'Kunne ikke slette valgte filtersett. Fikk feilmelding fra server.';
-$messages['setactivated'] = 'Filtersett aktivert.';
-$messages['setdeactivated'] = 'Filtersett deaktivert.';
-$messages['setdeleted'] = 'Filtersett slettet.';
-$messages['setdeleteconfirm'] = 'Er du sikker på at du vil slette det valgte filtersettet?';
-$messages['setcreateerror'] = 'Kunne ikke opprette filtersett. Fikk feilmelding fra server.';
-$messages['setcreated'] = 'Filtersett opprettet.';
-$messages['activateerror'] = 'Kunne ikke aktivere valgte filter(e). Fikk feilmelding fra server.';
-$messages['deactivateerror'] = 'Kunne ikke deaktivere valgte filter(e). Fikk feilmelding fra server.';
-$messages['deactivated'] = 'Filter skrudd på.';
-$messages['activated'] = 'Filter skrudd av.';
-$messages['moved'] = 'Filter ble flyttet.';
-$messages['moveerror'] = 'Kunne ikke flytte valgte filter. Fikk feilmelding fra server.';
-$messages['nametoolong'] = 'Navnet er for langt.';
-$messages['namereserved'] = 'Navnet er reservert.';
-$messages['setexist'] = 'Settet eksisterer allerede.';
-$messages['nodata'] = 'Du må velge minst én posisjon!';
-$messages['invaliddateformat'] = 'Ugyldig dato eller datoformat';
-?>
diff --git a/lib/plugins/managesieve/localization/nl_NL.inc b/lib/plugins/managesieve/localization/nl_NL.inc
deleted file mode 100644
index b84b87e..0000000
--- a/lib/plugins/managesieve/localization/nl_NL.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filters';
-$labels['managefilters'] = 'Beheer filters voor inkomende e-mail';
-$labels['filtername'] = 'Filternaam';
-$labels['newfilter'] = 'Nieuw filter';
-$labels['filteradd'] = 'Filter toevoegen';
-$labels['filterdel'] = 'Verwijder filter';
-$labels['moveup'] = 'Verplaats omhoog';
-$labels['movedown'] = 'Verplaats omlaag';
-$labels['filterallof'] = 'die voldoet aan alle volgende regels';
-$labels['filteranyof'] = 'die voldoet aan één van de volgende regels';
-$labels['filterany'] = 'alle berichten';
-$labels['filtercontains'] = 'bevat';
-$labels['filternotcontains'] = 'bevat niet';
-$labels['filteris'] = 'is gelijk aan';
-$labels['filterisnot'] = 'is niet gelijk aan';
-$labels['filterexists'] = 'bestaat';
-$labels['filternotexists'] = 'bestaat niet';
-$labels['filtermatches'] = 'komt overeen met expressie';
-$labels['filternotmatches'] = 'komt niet overeen met expressie';
-$labels['filterregex'] = 'komt overeen met de reguliere expressie';
-$labels['filternotregex'] = 'komt niet overeen met de reguliere expressie';
-$labels['filterunder'] = 'onder';
-$labels['filterover'] = 'over';
-$labels['addrule'] = 'Regel toevoegen';
-$labels['delrule'] = 'Regel verwijderen';
-$labels['messagemoveto'] = 'Verplaats bericht naar';
-$labels['messageredirect'] = 'Bericht doorsturen naar';
-$labels['messagecopyto'] = 'Kopieer bericht naar';
-$labels['messagesendcopy'] = 'Verstuur een kopie naar';
-$labels['messagereply'] = 'Beantwoord met bericht';
-$labels['messagedelete'] = 'Verwijder bericht';
-$labels['messagediscard'] = 'Met bericht negeren';
-$labels['messagekeep'] = 'Bewaar bericht in Postvak IN';
-$labels['messagesrules'] = 'Voor binnenkomende e-mail:';
-$labels['messagesactions'] = '...voer de volgende acties uit';
-$labels['add'] = 'Toevoegen';
-$labels['del'] = 'Verwijderen';
-$labels['sender'] = 'Afzender';
-$labels['recipient'] = 'Ontvanger';
-$labels['vacationaddr'] = 'Mijn extra e-mailadres(sen):';
-$labels['vacationdays'] = 'Hoe vaak moet een bericht verstuurd worden (in dagen):';
-$labels['vacationinterval'] = 'Hoe vaak moet een bericht verstuurd worden:';
-$labels['vacationreason'] = 'Bericht (vakantiereden):';
-$labels['vacationsubject'] = 'Onderwerp:';
-$labels['days'] = 'dagen';
-$labels['seconds'] = 'seconden';
-$labels['rulestop'] = 'Stop met regels uitvoeren';
-$labels['enable'] = 'In-/uitschakelen';
-$labels['filterset'] = 'Filterset';
-$labels['filtersets'] = 'Filtersets';
-$labels['filtersetadd'] = 'Nieuwe filterset';
-$labels['filtersetdel'] = 'Verwijder huidige filterset';
-$labels['filtersetact'] = 'Huidige filterset activeren';
-$labels['filtersetdeact'] = 'Huidige filterset uitschakelen';
-$labels['filterdef'] = 'Filterdefinitie';
-$labels['filtersetname'] = 'Filtersetnaam';
-$labels['newfilterset'] = 'Nieuwe filterset';
-$labels['active'] = 'actief';
-$labels['none'] = 'geen';
-$labels['fromset'] = 'van set';
-$labels['fromfile'] = 'van bestand';
-$labels['filterdisabled'] = 'Filter uitgeschakeld';
-$labels['countisgreaterthan'] = 'aantal is groter dan';
-$labels['countisgreaterthanequal'] = 'aantal is groter dan of gelijk aan';
-$labels['countislessthan'] = 'aantal is kleiner dan';
-$labels['countislessthanequal'] = 'aantal is kleiner dan of gelijk aan';
-$labels['countequals'] = 'aantal is gelijk aan';
-$labels['countnotequals'] = 'aantal is niet gelijk aan';
-$labels['valueisgreaterthan'] = 'waarde is groter dan';
-$labels['valueisgreaterthanequal'] = 'waarde is groter dan of gelijk aan';
-$labels['valueislessthan'] = 'waarde is minder dan';
-$labels['valueislessthanequal'] = 'waarde is minder dan of gelijk aan';
-$labels['valueequals'] = 'waarde is gelijk aan';
-$labels['valuenotequals'] = 'waarde is niet gelijk aan';
-$labels['setflags'] = 'Stel markeringen in op bericht';
-$labels['addflags'] = 'Voeg markeringen toe aan bericht';
-$labels['removeflags'] = 'Verwijder markeringen van bericht';
-$labels['flagread'] = 'Lezen';
-$labels['flagdeleted'] = 'Verwijderd';
-$labels['flaganswered'] = 'Beantwoord';
-$labels['flagflagged'] = 'Gemarkeerd';
-$labels['flagdraft'] = 'Concept';
-$labels['setvariable'] = 'Variabele instellen';
-$labels['setvarname'] = 'Naam variabele:';
-$labels['setvarvalue'] = 'Waarde:';
-$labels['setvarmodifiers'] = 'Waarde wijzigen:';
-$labels['varlower'] = 'kleine letters';
-$labels['varupper'] = 'hoofdletters';
-$labels['varlowerfirst'] = 'eerste karakter als kleine letter';
-$labels['varupperfirst'] = 'eerste karakter als hoofdletter';
-$labels['varquotewildcard'] = 'speciale karakters quoten';
-$labels['varlength'] = 'lengte';
-$labels['notify'] = 'Stuur melding';
-$labels['notifytarget'] = 'Meldingsdoel:';
-$labels['notifymessage'] = 'Meldingsbericht (optioneel):';
-$labels['notifyoptions'] = 'Meldingsopties (optioneel):';
-$labels['notifyfrom'] = 'Meldingsafzender (optioneel):';
-$labels['notifyimportance'] = 'Prioriteit:';
-$labels['notifyimportancelow'] = 'laag';
-$labels['notifyimportancenormal'] = 'normaal';
-$labels['notifyimportancehigh'] = 'hoog';
-$labels['notifymethodmailto'] = 'E-mail';
-$labels['notifymethodtel'] = 'Telefoon';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Filter aanmaken';
-$labels['usedata'] = 'Gebruik de volgende gegevens in het filter:';
-$labels['nextstep'] = 'Volgende stap';
-$labels['...'] = '...';
-$labels['currdate'] = 'Huidige datum';
-$labels['datetest'] = 'Datum';
-$labels['dateheader'] = 'header:';
-$labels['year'] = 'jaar';
-$labels['month'] = 'maand';
-$labels['day'] = 'dag';
-$labels['date'] = 'datum (jjjj-mm-dd)';
-$labels['julian'] = 'datum (juliaanse kalender)';
-$labels['hour'] = 'uur';
-$labels['minute'] = 'minuut';
-$labels['second'] = 'seconde';
-$labels['time'] = 'tijd (uu:mm:ss)';
-$labels['iso8601'] = 'datum (ISO-8601)';
-$labels['std11'] = 'datum (RFC 2822)';
-$labels['zone'] = 'tijdzone';
-$labels['weekday'] = 'weekdag (0-6)';
-$labels['advancedopts'] = 'Geavanceerde opties';
-$labels['body'] = 'Inhoud';
-$labels['address'] = 'adres';
-$labels['envelope'] = 'envelope';
-$labels['modifier'] = 'toets op:';
-$labels['text'] = 'tekst';
-$labels['undecoded'] = 'undecoded (raw)';
-$labels['contenttype'] = 'content type';
-$labels['modtype'] = 'type:';
-$labels['allparts'] = 'Alle';
-$labels['domain'] = 'domein';
-$labels['localpart'] = 'lokaal gedeelte';
-$labels['user'] = 'gebruiker';
-$labels['detail'] = 'detail';
-$labels['comparator'] = 'vergelijkingswijze:';
-$labels['default'] = 'standaard';
-$labels['octet'] = 'strikt (octet)';
-$labels['asciicasemap'] = 'hoofdletterongevoelig (ascii-casemap)';
-$labels['asciinumeric'] = 'numeriek (ascii-numeriek)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'terugwaarts';
-$labels['vacation'] = 'Vakantie';
-$labels['vacation.reply'] = 'Antwoordbericht';
-$labels['vacation.advanced'] = 'Geavanceerde instellingen';
-$labels['vacation.subject'] = 'Onderwerp';
-$labels['vacation.body'] = 'Inhoud';
-$labels['vacation.start'] = 'Begin van vakantie';
-$labels['vacation.end'] = 'Einde van vakantie';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.on'] = 'Aan';
-$labels['vacation.off'] = 'Uit';
-$labels['vacation.addresses'] = 'Mijn extra e-mailadressen';
-$labels['vacation.interval'] = 'Antwoordinterval';
-$labels['vacation.after'] = 'Voeg een vakantieregel toe na';
-$labels['vacation.saving'] = 'Gegevens worden opgeslagen...';
-$labels['vacation.action'] = 'Actie voor inkomend bericht';
-$labels['vacation.keep'] = 'Bewaren';
-$labels['vacation.discard'] = 'Weggooien';
-$labels['vacation.redirect'] = 'Doorsturen naar';
-$labels['vacation.copy'] = 'Kopie sturen naar';
-$labels['arialabelfiltersetactions'] = 'Filtersetacties';
-$labels['arialabelfilteractions'] = 'Filteracties';
-$labels['arialabelfilterform'] = 'Filtereigenschappen';
-$labels['ariasummaryfilterslist'] = 'Filterlijst';
-$labels['ariasummaryfiltersetslist'] = 'Lijst met filtersets';
-$labels['filterstitle'] = 'Bewerk filters voor inkomende berichten';
-$labels['vacationtitle'] = 'Bewerk vakantieregel';
-$messages['filterunknownerror'] = 'Onbekende fout';
-$messages['filterconnerror'] = 'Kan geen verbinding maken met de managesieve server';
-$messages['filterdeleteerror'] = 'Kan filter niet verwijderen. Er trad een serverfout op.';
-$messages['filterdeleted'] = 'Filter succesvol verwijderd';
-$messages['filtersaved'] = 'Filter succesvol opgeslagen';
-$messages['filtersaveerror'] = 'Kan filter niet opslaan. Er trad een serverfout op.';
-$messages['filterdeleteconfirm'] = 'Weet je zeker dat je het geselecteerde filter wilt verwijderen?';
-$messages['ruledeleteconfirm'] = 'Weet je zeker dat je de geselecteerde regel wilt verwijderen?';
-$messages['actiondeleteconfirm'] = 'Weet je zeker dat je de geselecteerde actie wilt verwijderen?';
-$messages['forbiddenchars'] = 'Verboden karakters in het veld';
-$messages['cannotbeempty'] = 'Veld mag niet leeg zijn';
-$messages['ruleexist'] = 'Er bestaat al een filter met deze naam.';
-$messages['setactivateerror'] = 'Filterset kon niet geactiveerd worden. Er trad een serverfout op.';
-$messages['setdeactivateerror'] = 'Filterset kon niet gedeactiveerd worden. Er trad een serverfout op.';
-$messages['setdeleteerror'] = 'Filterset kon niet verwijderd worden. Er trad een serverfout op.';
-$messages['setactivated'] = 'Filterset succesvol geactiveerd.';
-$messages['setdeactivated'] = 'Filterset succesvol gedeactiveerd.';
-$messages['setdeleted'] = 'Filterset succesvol verwijderd.';
-$messages['setdeleteconfirm'] = 'Weet u zeker dat u de geselecteerde filterset wilt verwijderen?';
-$messages['setcreateerror'] = 'Filterset kon niet aangemaakt worden. Er trad een serverfout op.';
-$messages['setcreated'] = 'Filterset succesvol aangemaakt.';
-$messages['activateerror'] = 'Geselecteerde filter(s) konden niet ingeschakeld worden. Er trad een serverfout op.';
-$messages['deactivateerror'] = 'Geselecteerde filter(s) konden niet uitgeschakeld worden. Er trad een serverfout op.';
-$messages['deactivated'] = 'Filter(s) succesvol ingeschakeld.';
-$messages['activated'] = 'Filter(s) succesvol uitgeschakeld.';
-$messages['moved'] = 'Filter succesvol verplaatst.';
-$messages['moveerror'] = 'Het geselecteerde filter kon niet verplaatst worden. Er trad een serverfout op.';
-$messages['nametoolong'] = 'Naam is te lang.';
-$messages['namereserved'] = 'Gereserveerde naam.';
-$messages['setexist'] = 'Filterset bestaat al.';
-$messages['nodata'] = 'Tenminste één positie moet geselecteerd worden!';
-$messages['invaliddateformat'] = 'Ongeldige datum of datumformaat';
-$messages['saveerror'] = 'Opslaan van de gegevens is mislukt. Er trad een serverfout op.';
-$messages['vacationsaved'] = 'Vakantiegegevens succesvol opgeslagen.';
-$messages['emptyvacationbody'] = 'Inhoud van vakantiebericht is verplicht!';
-?>
diff --git a/lib/plugins/managesieve/localization/nn_NO.inc b/lib/plugins/managesieve/localization/nn_NO.inc
deleted file mode 100644
index 2dc68e6..0000000
--- a/lib/plugins/managesieve/localization/nn_NO.inc
+++ /dev/null
@@ -1,152 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filter';
-$labels['managefilters'] = 'Rediger filter for innkommande e-post';
-$labels['filtername'] = 'Filternamn';
-$labels['newfilter'] = 'Nytt filter';
-$labels['filteradd'] = 'Legg til filter';
-$labels['filterdel'] = 'Slett filter';
-$labels['moveup'] = 'Flytt opp';
-$labels['movedown'] = 'Flytt ned';
-$labels['filterallof'] = 'som treffer alle følgjande regler';
-$labels['filteranyof'] = 'som treffer ein av følgjande regler';
-$labels['filterany'] = 'alle meldingar';
-$labels['filtercontains'] = 'inneheld';
-$labels['filternotcontains'] = 'ikkje inneheld';
-$labels['filteris'] = 'er lik';
-$labels['filterisnot'] = 'er ikkje lik';
-$labels['filterexists'] = 'eksisterer';
-$labels['filternotexists'] = 'ikkje eksisterer';
-$labels['filtermatches'] = 'treffer uttrykk';
-$labels['filternotmatches'] = 'ikkje treffer uttrykk';
-$labels['filterregex'] = 'treffer regulært uttrykk';
-$labels['filternotregex'] = 'ikkje treffer regulært uttrykk';
-$labels['filterunder'] = 'under';
-$labels['filterover'] = 'over';
-$labels['addrule'] = 'Legg til regel';
-$labels['delrule'] = 'Slett regel';
-$labels['messagemoveto'] = 'Flytt meldinga til';
-$labels['messageredirect'] = 'Vidaresend meldinga til';
-$labels['messagecopyto'] = 'Kopier meldinga til';
-$labels['messagesendcopy'] = 'Send ein kopi av meldinga til';
-$labels['messagereply'] = 'Svar med melding';
-$labels['messagedelete'] = 'Slett melding';
-$labels['messagediscard'] = 'Avvis med melding';
-$labels['messagesrules'] = 'For innkommande e-post';
-$labels['messagesactions'] = '…gjer følgjande:';
-$labels['add'] = 'Legg til';
-$labels['del'] = 'Slett';
-$labels['sender'] = 'Avsendar';
-$labels['recipient'] = 'Mottakar';
-$labels['vacationdays'] = 'Periode mellom meldingar (i dagar):';
-$labels['vacationreason'] = 'Innhald (grunngjeving for fråvær)';
-$labels['vacationsubject'] = 'Meldingsemne:';
-$labels['rulestop'] = 'Stopp evaluering av regler';
-$labels['enable'] = 'Aktiver/Deaktiver';
-$labels['filterset'] = 'Filtersett';
-$labels['filtersets'] = 'Filtersett';
-$labels['filtersetadd'] = 'Nytt filtersett';
-$labels['filtersetdel'] = 'Slett gjeldande filtersett';
-$labels['filtersetact'] = 'Aktiver gjeldande filtersett';
-$labels['filtersetdeact'] = 'Deaktiver gjeldande filtersett';
-$labels['filterdef'] = 'Filterdefinisjon';
-$labels['filtersetname'] = 'Namn på filtersett';
-$labels['newfilterset'] = 'Nytt filtersett';
-$labels['active'] = 'aktiv';
-$labels['none'] = 'ingen';
-$labels['fromset'] = 'frå sett';
-$labels['fromfile'] = 'frå fil';
-$labels['filterdisabled'] = 'Filter deaktivert';
-$labels['countisgreaterthan'] = 'mengd er fleire enn';
-$labels['countisgreaterthanequal'] = 'mengd er fleire enn eller lik';
-$labels['countislessthan'] = 'mengd er færre enn';
-$labels['countislessthanequal'] = 'mengd er færre enn eller lik';
-$labels['countequals'] = 'mengd er lik';
-$labels['valueisgreaterthan'] = 'verdien er høgare enn';
-$labels['valueisgreaterthanequal'] = 'verdien er høgare eller lik';
-$labels['valueislessthan'] = 'verdien er lågare enn';
-$labels['valueislessthanequal'] = 'verdien er lågare eller lik';
-$labels['valueequals'] = 'verdien er lik';
-$labels['setflags'] = 'Sett meldingsflagg';
-$labels['addflags'] = 'Legg til flagg på meldinga';
-$labels['removeflags'] = 'Fjern flagg fra meldinga';
-$labels['flagread'] = 'Lese';
-$labels['flagdeleted'] = 'Sletta';
-$labels['flaganswered'] = 'Svart på';
-$labels['flagflagged'] = 'Flagga';
-$labels['flagdraft'] = 'Skisse';
-$labels['setvariable'] = 'Sett variabel:';
-$labels['setvarname'] = 'Variabelnamn:';
-$labels['setvarvalue'] = 'Variabelverdi:';
-$labels['setvarmodifiers'] = 'Modifikator:';
-$labels['varlower'] = 'med små bokstavar';
-$labels['varupper'] = 'med store bokstavar';
-$labels['varlowerfirst'] = 'med liten forbokstav';
-$labels['varupperfirst'] = 'med stor forbokstav';
-$labels['varlength'] = 'lengde';
-$labels['notify'] = 'Send varsel';
-$labels['notifyimportance'] = 'Betyding:';
-$labels['notifyimportancelow'] = 'låg';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'høg';
-$labels['filtercreate'] = 'Opprett filter';
-$labels['usedata'] = 'Bruk følgande data i filteret:';
-$labels['nextstep'] = 'Neste steg';
-$labels['...'] = '…';
-$labels['advancedopts'] = 'Avanserte val';
-$labels['body'] = 'Meldingstekst';
-$labels['address'] = 'adresse';
-$labels['envelope'] = 'konvolutt';
-$labels['modifier'] = 'modifikator:';
-$labels['text'] = 'tekst';
-$labels['undecoded'] = 'ikkje dekoda (rå)';
-$labels['contenttype'] = 'innhaldstype';
-$labels['modtype'] = 'type:';
-$labels['allparts'] = 'alle';
-$labels['domain'] = 'domene';
-$labels['localpart'] = 'lokal del (local part)';
-$labels['user'] = 'brukar';
-$labels['detail'] = 'detalj';
-$labels['comparator'] = 'samanlikning:';
-$labels['default'] = 'standard';
-$labels['octet'] = 'streng (oktett)';
-$labels['asciicasemap'] = 'ikkje skil mellom store og små bokstavar (ascii-casemap)';
-$labels['asciinumeric'] = 'numerisk (ascii-numeric)';
-$messages['filterunknownerror'] = 'Ukjent problem med tenar.';
-$messages['filterconnerror'] = 'Kunne ikkje kople til tenaren.';
-$messages['filterdeleted'] = 'Filteret er blitt sletta.';
-$messages['filtersaved'] = 'Filteret er blitt lagra.';
-$messages['filterdeleteconfirm'] = 'Vil du verkeleg slette det valde filteret?';
-$messages['ruledeleteconfirm'] = 'Er du sikker på at du vil slette vald regel?';
-$messages['actiondeleteconfirm'] = 'Er du sikker på at du vil slette vald hending?';
-$messages['forbiddenchars'] = 'Ugyldige teikn i felt.';
-$messages['cannotbeempty'] = 'Feltet kan ikkje stå tomt.';
-$messages['ruleexist'] = 'Det finst alt eit filter med dette namnet.';
-$messages['setactivated'] = 'Filtersett aktivert.';
-$messages['setdeactivated'] = 'Filtersett deaktivert.';
-$messages['setdeleted'] = 'Filtersett sletta.';
-$messages['setdeleteconfirm'] = 'Er du sikker på at du vil slette det valde filtersettet?';
-$messages['setcreated'] = 'Filtersett oppretta.';
-$messages['deactivated'] = 'Filter skrudd på.';
-$messages['activated'] = 'Filter skrudd av.';
-$messages['moved'] = 'Filter vart flytta.';
-$messages['nametoolong'] = 'Namnet er for langt.';
-$messages['namereserved'] = 'Namnet er reservert.';
-$messages['setexist'] = 'Settet eksisterer alt.';
-$messages['nodata'] = 'Du må velje minst éin posisjon!';
-?>
diff --git a/lib/plugins/managesieve/localization/pl_PL.inc b/lib/plugins/managesieve/localization/pl_PL.inc
deleted file mode 100644
index 06c0a79..0000000
--- a/lib/plugins/managesieve/localization/pl_PL.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtry';
-$labels['managefilters'] = 'Zarządzanie filtrami poczty przychodzącej';
-$labels['filtername'] = 'Nazwa filtru';
-$labels['newfilter'] = 'Nowy filtr';
-$labels['filteradd'] = 'Dodaj filtr';
-$labels['filterdel'] = 'Usuń filtr';
-$labels['moveup'] = 'W górę';
-$labels['movedown'] = 'W dół';
-$labels['filterallof'] = 'spełniających wszystkie poniższe kryteria';
-$labels['filteranyof'] = 'spełniających dowolne z poniższych kryteriów';
-$labels['filterany'] = 'wszystkich';
-$labels['filtercontains'] = 'zawiera';
-$labels['filternotcontains'] = 'nie zawiera';
-$labels['filteris'] = 'jest równe';
-$labels['filterisnot'] = 'nie jest równe';
-$labels['filterexists'] = 'istnieje';
-$labels['filternotexists'] = 'nie istnieje';
-$labels['filtermatches'] = 'pasuje do wyrażenia';
-$labels['filternotmatches'] = 'nie pasuje do wyrażenia';
-$labels['filterregex'] = 'pasuje do wyrażenia regularnego';
-$labels['filternotregex'] = 'nie pasuje do wyrażenia regularnego';
-$labels['filterunder'] = 'poniżej';
-$labels['filterover'] = 'ponad';
-$labels['addrule'] = 'Dodaj regułę';
-$labels['delrule'] = 'Usuń regułę';
-$labels['messagemoveto'] = 'Przenieś wiadomość do';
-$labels['messageredirect'] = 'Przekaż wiadomość na konto';
-$labels['messagecopyto'] = 'Skopiuj wiadomość do';
-$labels['messagesendcopy'] = 'Wyślij kopię do';
-$labels['messagereply'] = 'Odpowiedz wiadomością o treści';
-$labels['messagedelete'] = 'Usuń wiadomość';
-$labels['messagediscard'] = 'Odrzuć z komunikatem';
-$labels['messagekeep'] = 'Zachowaj wiadomość w Odebranych';
-$labels['messagesrules'] = 'W stosunku do przychodzącej poczty:';
-$labels['messagesactions'] = '...wykonaj następujące czynności:';
-$labels['add'] = 'Dodaj';
-$labels['del'] = 'Usuń';
-$labels['sender'] = 'Nadawca';
-$labels['recipient'] = 'Odbiorca';
-$labels['vacationaddr'] = 'Moje dodatkowe adresy email:';
-$labels['vacationdays'] = 'Częstotliwość wysyłania wiadomości (w dniach):';
-$labels['vacationinterval'] = 'Jak często wysyłać wiadomości:';
-$labels['vacationreason'] = 'Treść (przyczyna nieobecności):';
-$labels['vacationsubject'] = 'Temat wiadomości:';
-$labels['days'] = 'dni';
-$labels['seconds'] = 'sekundy';
-$labels['rulestop'] = 'Przerwij przetwarzanie reguł';
-$labels['enable'] = 'Włącz/Wyłącz';
-$labels['filterset'] = 'Zbiór filtrów';
-$labels['filtersets'] = 'Zbiory fitrów';
-$labels['filtersetadd'] = 'Dodaj zbiór filtrów';
-$labels['filtersetdel'] = 'Usuń bieżący zbiór filtrów';
-$labels['filtersetact'] = 'Aktywuj bieżący zbiór filtrów';
-$labels['filtersetdeact'] = 'Deaktywuj bieżący zbiór filtrów';
-$labels['filterdef'] = 'Definicja filtra';
-$labels['filtersetname'] = 'Nazwa zbioru';
-$labels['newfilterset'] = 'Nowy zbiór filtrów';
-$labels['active'] = 'aktywny';
-$labels['none'] = 'brak';
-$labels['fromset'] = 'ze zbioru';
-$labels['fromfile'] = 'z pliku';
-$labels['filterdisabled'] = 'Filtr wyłączony';
-$labels['countisgreaterthan'] = 'ilość jest większa od';
-$labels['countisgreaterthanequal'] = 'ilość jest równa lub większa od';
-$labels['countislessthan'] = 'ilość jest mniejsza od';
-$labels['countislessthanequal'] = 'ilość jest równa lub mniejsza od';
-$labels['countequals'] = 'ilość jest równa';
-$labels['countnotequals'] = 'ilość nie jest równa';
-$labels['valueisgreaterthan'] = 'wartość jest większa od';
-$labels['valueisgreaterthanequal'] = 'wartość jest równa lub większa od';
-$labels['valueislessthan'] = 'wartość jest mniejsza od';
-$labels['valueislessthanequal'] = 'wartość jest równa lub mniejsza od';
-$labels['valueequals'] = 'wartość jest równa';
-$labels['valuenotequals'] = 'wartość nie jest równa';
-$labels['setflags'] = 'Ustaw flagi wiadomości';
-$labels['addflags'] = 'Dodaj flagi do wiadomości';
-$labels['removeflags'] = 'Usuń flagi wiadomości';
-$labels['flagread'] = 'Przeczytana';
-$labels['flagdeleted'] = 'Usunięta';
-$labels['flaganswered'] = 'Z odpowiedzią';
-$labels['flagflagged'] = 'Oflagowana';
-$labels['flagdraft'] = 'Szkic';
-$labels['setvariable'] = 'Ustaw zmienną';
-$labels['setvarname'] = 'Nazwa zmiennej:';
-$labels['setvarvalue'] = 'Wartość zmiennej:';
-$labels['setvarmodifiers'] = 'Modyfikatory:';
-$labels['varlower'] = 'małe litery';
-$labels['varupper'] = 'wielkie litery';
-$labels['varlowerfirst'] = 'pierwsza mała litera';
-$labels['varupperfirst'] = 'pierwsza wielka litera';
-$labels['varquotewildcard'] = 'zamień znaki specjalne';
-$labels['varlength'] = 'długość';
-$labels['notify'] = 'Wyślij powiadomienie';
-$labels['notifytarget'] = 'Odbiorca powiadomienia:';
-$labels['notifymessage'] = 'Wiadomość powiadomienia (opcjonalne):';
-$labels['notifyoptions'] = 'Opcje powiadomienia (opcjonalne):';
-$labels['notifyfrom'] = 'Nadawca powiadomienia (opcjonalne):';
-$labels['notifyimportance'] = 'Priorytet:';
-$labels['notifyimportancelow'] = 'niski';
-$labels['notifyimportancenormal'] = 'normalny';
-$labels['notifyimportancehigh'] = 'wysoki';
-$labels['notifymethodmailto'] = 'E-Mail';
-$labels['notifymethodtel'] = 'Telefon';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Utwórz filtr';
-$labels['usedata'] = 'Użyj następujących danych do utworzenia filtra:';
-$labels['nextstep'] = 'Następny krok';
-$labels['...'] = '...';
-$labels['currdate'] = 'Bieżąca data';
-$labels['datetest'] = 'Data';
-$labels['dateheader'] = 'nagłówek:';
-$labels['year'] = 'rok';
-$labels['month'] = 'miesiąc';
-$labels['day'] = 'dzień';
-$labels['date'] = 'data (rrrr-mm-dd)';
-$labels['julian'] = 'data (kalendarz juliański)';
-$labels['hour'] = 'godzina';
-$labels['minute'] = 'minuta';
-$labels['second'] = 'sekunda';
-$labels['time'] = 'czas (gg:mm:ss)';
-$labels['iso8601'] = 'data (ISO8601)';
-$labels['std11'] = 'data (RFC2822)';
-$labels['zone'] = 'Strefa czasowa';
-$labels['weekday'] = 'dzień tygodnia (0-6)';
-$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)';
-$labels['index'] = 'indeks:';
-$labels['indexlast'] = 'wstecz';
-$labels['vacation'] = 'Nieobecność';
-$labels['vacation.reply'] = 'Odpowiedź';
-$labels['vacation.advanced'] = 'Ustawienia zaawansowane';
-$labels['vacation.subject'] = 'Temat';
-$labels['vacation.body'] = 'Treść';
-$labels['vacation.start'] = 'Początek nieobecności';
-$labels['vacation.end'] = 'Koniec nieobecności';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.on'] = 'włączone';
-$labels['vacation.off'] = 'wyłączone';
-$labels['vacation.addresses'] = 'Moje dodatkowe adresy';
-$labels['vacation.interval'] = 'Częstotliwość odpowiedzi';
-$labels['vacation.after'] = 'Umieść regułę odpowiedzi po';
-$labels['vacation.saving'] = 'Zapisywanie danych...';
-$labels['vacation.action'] = 'Akcje wiadomości przychodzących';
-$labels['vacation.keep'] = 'Zachowaj';
-$labels['vacation.discard'] = 'Odrzuć';
-$labels['vacation.redirect'] = 'Przekaż do';
-$labels['vacation.copy'] = 'Wyślij kopię do';
-$labels['arialabelfiltersetactions'] = 'Zbiór filtrów akcji';
-$labels['arialabelfilteractions'] = 'Akcje filtrów';
-$labels['arialabelfilterform'] = 'Ustawienia filtrów';
-$labels['ariasummaryfilterslist'] = 'Spis filtrów';
-$labels['ariasummaryfiltersetslist'] = 'Lista zbiorów filtrów';
-$labels['filterstitle'] = 'Zarządzaj filtrami wiadomości przychodzących';
-$labels['vacationtitle'] = 'Zarządzaj asystentem nieobecności';
-$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['filtersaved'] = 'Filtr został zapisany pomyślnie.';
-$messages['filtersaveerror'] = 'Nie można zapisać filtra. Wystąpił błąd serwera.';
-$messages['filterdeleteconfirm'] = 'Czy na pewno chcesz usunąć wybrany filtr?';
-$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['ruleexist'] = 'Filtr o podanej nazwie już istnieje.';
-$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['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['deactivated'] = 'Filtr(y) włączono pomyślnie.';
-$messages['activated'] = 'Filtr(y) wyłą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.';
-$messages['nodata'] = 'Należy wybrać co najmniej jedną pozycję!';
-$messages['invaliddateformat'] = 'Nieprawidłowy format daty lub fragmentu daty';
-$messages['saveerror'] = 'Nie można zapisać danych. Wystąpił błąd serwera.';
-$messages['vacationsaved'] = 'Dane nieobecności zapisano pomyślnie.';
-$messages['emptyvacationbody'] = 'Treść wiadomości jest wymagana!';
-?>
diff --git a/lib/plugins/managesieve/localization/pt_BR.inc b/lib/plugins/managesieve/localization/pt_BR.inc
deleted file mode 100644
index b0ccaf6..0000000
--- a/lib/plugins/managesieve/localization/pt_BR.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtros';
-$labels['managefilters'] = 'Gerenciar filtros de entrada de e-mail';
-$labels['filtername'] = 'Nome do filtro';
-$labels['newfilter'] = 'Novo filtro';
-$labels['filteradd'] = 'Adicionar filtro';
-$labels['filterdel'] = 'Excluir filtro';
-$labels['moveup'] = 'Mover para cima';
-$labels['movedown'] = 'Mover para baixo';
-$labels['filterallof'] = 'casando todas as seguintes regras';
-$labels['filteranyof'] = 'casando qualquer das seguintes regras';
-$labels['filterany'] = 'todas as mensagens';
-$labels['filtercontains'] = 'contem';
-$labels['filternotcontains'] = 'não contem';
-$labels['filteris'] = 'é igual a';
-$labels['filterisnot'] = 'não é igual a';
-$labels['filterexists'] = 'existe';
-$labels['filternotexists'] = 'não existe';
-$labels['filtermatches'] = 'expressão combina';
-$labels['filternotmatches'] = 'expressão não combina';
-$labels['filterregex'] = 'combina com expressão regular';
-$labels['filternotregex'] = 'não combina com a expressão regular';
-$labels['filterunder'] = 'inferior a';
-$labels['filterover'] = 'superior a';
-$labels['addrule'] = 'Adicionar regra';
-$labels['delrule'] = 'Excluir regra';
-$labels['messagemoveto'] = 'Mover mensagem para';
-$labels['messageredirect'] = 'Redirecionar mensagem para';
-$labels['messagecopyto'] = 'Copiar mensagem para';
-$labels['messagesendcopy'] = 'Enviar cópia da mensagem para';
-$labels['messagereply'] = 'Responder com mensagem';
-$labels['messagedelete'] = 'Excluir mensagem';
-$labels['messagediscard'] = 'Descartar com mensagem';
-$labels['messagekeep'] = 'Manter mensagens na caixa';
-$labels['messagesrules'] = 'Para e-mails recebidos:';
-$labels['messagesactions'] = '...execute as seguintes ações:';
-$labels['add'] = 'Adicionar';
-$labels['del'] = 'Excluir';
-$labels['sender'] = 'Remetente';
-$labels['recipient'] = 'Destinatário';
-$labels['vacationaddr'] = 'Meu endereço de e-mail adicional:';
-$labels['vacationdays'] = 'Enviar mensagens com que frequência (em dias):';
-$labels['vacationinterval'] = 'Como geralmente enviam mensagens:';
-$labels['vacationreason'] = 'Corpo da mensagem (motivo de férias):';
-$labels['vacationsubject'] = 'Título da mensagem:';
-$labels['days'] = 'dias';
-$labels['seconds'] = 'segundos';
-$labels['rulestop'] = 'Parar de avaliar regras';
-$labels['enable'] = 'Habilitar/Desabilitar';
-$labels['filterset'] = 'Conjunto de filtros';
-$labels['filtersets'] = 'Conjuntos de filtro';
-$labels['filtersetadd'] = 'Adicionar conjunto de filtros';
-$labels['filtersetdel'] = 'Excluir conjunto de filtros atual';
-$labels['filtersetact'] = 'Ativar conjunto de filtros atual';
-$labels['filtersetdeact'] = 'Desativar conjunto de filtros atual';
-$labels['filterdef'] = 'Definição de filtro';
-$labels['filtersetname'] = 'Nome do conjunto de filtros';
-$labels['newfilterset'] = 'Novo conjunto de filtros';
-$labels['active'] = 'ativo';
-$labels['none'] = 'nenhum';
-$labels['fromset'] = 'Do conjunto';
-$labels['fromfile'] = 'Do arquivo';
-$labels['filterdisabled'] = 'Filtro desativado';
-$labels['countisgreaterthan'] = 'contagem é maior que';
-$labels['countisgreaterthanequal'] = 'contagem é maior ou igual a';
-$labels['countislessthan'] = 'contagem é menor que';
-$labels['countislessthanequal'] = 'contagem é menor ou igual a';
-$labels['countequals'] = 'contagem é igual a';
-$labels['countnotequals'] = 'contagem não é igual a';
-$labels['valueisgreaterthan'] = 'valor é maior que';
-$labels['valueisgreaterthanequal'] = 'valor é maior ou igual a';
-$labels['valueislessthan'] = 'valor é menor que';
-$labels['valueislessthanequal'] = 'valor é menor ou igual a';
-$labels['valueequals'] = 'valor é igual a';
-$labels['valuenotequals'] = 'valor não é igual a';
-$labels['setflags'] = 'Definir marcadores à mensagem';
-$labels['addflags'] = 'Adicionar marcadores à mensagem';
-$labels['removeflags'] = 'Remover marcadores da mensagem';
-$labels['flagread'] = 'Lida';
-$labels['flagdeleted'] = 'Excluída';
-$labels['flaganswered'] = 'Respondida';
-$labels['flagflagged'] = 'Marcada';
-$labels['flagdraft'] = 'Rascunho';
-$labels['setvariable'] = 'Definir variável';
-$labels['setvarname'] = 'Nome da variável:';
-$labels['setvarvalue'] = 'Valor da variável:';
-$labels['setvarmodifiers'] = 'Modificadores:';
-$labels['varlower'] = 'minúsculas';
-$labels['varupper'] = 'maiúsculas';
-$labels['varlowerfirst'] = 'primeiro caractere minúsculo';
-$labels['varupperfirst'] = 'primeiro caractere maiúsculo';
-$labels['varquotewildcard'] = 'caracteres especiais de citação';
-$labels['varlength'] = 'tamanho';
-$labels['notify'] = 'Enviar notificação';
-$labels['notifytarget'] = 'Destino da notificação:';
-$labels['notifymessage'] = 'Mensagem de notificação (opcional):';
-$labels['notifyoptions'] = 'Opções de notificação (opcional):';
-$labels['notifyfrom'] = 'Remetente da notificação (opcional):';
-$labels['notifyimportance'] = 'Importância';
-$labels['notifyimportancelow'] = 'baixa';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'alta';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Telefone';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Criar filtro';
-$labels['usedata'] = 'Usar os seguintes dados no filtro:';
-$labels['nextstep'] = 'Próximo Passo';
-$labels['...'] = '...';
-$labels['currdate'] = 'Data atual';
-$labels['datetest'] = 'Data';
-$labels['dateheader'] = 'cabeçalho:';
-$labels['year'] = 'ano';
-$labels['month'] = 'mês';
-$labels['day'] = 'dia';
-$labels['date'] = 'data (aaaa-mm-dd)';
-$labels['julian'] = 'data (calendário juliano)';
-$labels['hour'] = 'hora';
-$labels['minute'] = 'minuto';
-$labels['second'] = 'segundo';
-$labels['time'] = 'hora (hh:mm:ss)';
-$labels['iso8601'] = 'data (ISO8601)';
-$labels['std11'] = 'data (RFC2822)';
-$labels['zone'] = 'fuso horário';
-$labels['weekday'] = 'dia da semana (0-6)';
-$labels['advancedopts'] = 'Opções avançadas';
-$labels['body'] = 'Corpo';
-$labels['address'] = 'endereço';
-$labels['envelope'] = 'envelope';
-$labels['modifier'] = 'modificador:';
-$labels['text'] = 'texto';
-$labels['undecoded'] = 'decodificado (bruto)';
-$labels['contenttype'] = 'tipo de conteúdo';
-$labels['modtype'] = 'tipo:';
-$labels['allparts'] = 'todas';
-$labels['domain'] = 'domínio';
-$labels['localpart'] = 'parte local';
-$labels['user'] = 'usuário';
-$labels['detail'] = 'detalhes';
-$labels['comparator'] = 'comparador:';
-$labels['default'] = 'padrão';
-$labels['octet'] = 'estrito (octeto)';
-$labels['asciicasemap'] = 'caso insensível (mapa de caracteres ascii)';
-$labels['asciinumeric'] = 'numérico (ascii-numeric)';
-$labels['index'] = 'índice:';
-$labels['indexlast'] = 'retroceder';
-$labels['vacation'] = 'Férias';
-$labels['vacation.reply'] = 'Responder mensagem';
-$labels['vacation.advanced'] = 'Opções avançadas';
-$labels['vacation.subject'] = 'Assunto';
-$labels['vacation.body'] = 'Conteúdo';
-$labels['vacation.start'] = 'Início das férias';
-$labels['vacation.end'] = 'Término das férias';
-$labels['vacation.status'] = 'Estado';
-$labels['vacation.on'] = 'Ligado';
-$labels['vacation.off'] = 'Desligado';
-$labels['vacation.addresses'] = 'Meus endereços de e-mail adicionais';
-$labels['vacation.interval'] = 'Intervalo de resposta';
-$labels['vacation.after'] = 'Colocar regra de férias após';
-$labels['vacation.saving'] = 'Salvando dados...';
-$labels['vacation.action'] = 'Ações para mensagens recebidas';
-$labels['vacation.keep'] = 'Manter';
-$labels['vacation.discard'] = 'Descartar';
-$labels['vacation.redirect'] = 'Redirecionar para';
-$labels['vacation.copy'] = 'Enviar cópia para';
-$labels['arialabelfiltersetactions'] = 'Ações do grupo de filtros';
-$labels['arialabelfilteractions'] = 'Ações do filtro';
-$labels['arialabelfilterform'] = 'Propriedades do filtro';
-$labels['ariasummaryfilterslist'] = 'Lista dos filtros';
-$labels['ariasummaryfiltersetslist'] = 'Lista de grupo de filtros';
-$labels['filterstitle'] = 'Editar filtro dos e-mails recebidos';
-$labels['vacationtitle'] = 'Editar regra de ausência';
-$messages['filterunknownerror'] = 'Erro desconhecido de servidor';
-$messages['filterconnerror'] = 'Não foi possível conectar ao servidor managesieve';
-$messages['filterdeleteerror'] = 'Impossível excluir o filtro. Ocorreu um erro no servidor.';
-$messages['filterdeleted'] = 'Filtro excluído com sucesso';
-$messages['filtersaved'] = 'Filtro gravado com sucesso';
-$messages['filtersaveerror'] = 'Impossível salvar o filtro. Ocorreu um erro no servidor.';
-$messages['filterdeleteconfirm'] = 'Deseja realmente excluir o filtro selecionado?';
-$messages['ruledeleteconfirm'] = 'Deseja realmente excluir a regra selecionada?';
-$messages['actiondeleteconfirm'] = 'Deseja realmente excluir a ação selecionada?';
-$messages['forbiddenchars'] = 'Caracteres não permitidos no campo';
-$messages['cannotbeempty'] = 'Campo não pode ficar em branco';
-$messages['ruleexist'] = 'O filtro com o nome especificado já existe.';
-$messages['setactivateerror'] = 'Impossível ativar o conjunto de filtros selecionados. Ocorreu um erro no servidor.';
-$messages['setdeactivateerror'] = 'Impossível desativar o conjunto de filtros selecionados. Ocorreu um erro no servidor.';
-$messages['setdeleteerror'] = 'Impossível excluir o conjunto de filtros selecionados. Ocorreu um erro no servidor.';
-$messages['setactivated'] = 'Conjunto de filtros ativados com sucesso.';
-$messages['setdeactivated'] = 'Conjunto de filtros desativados com sucesso.';
-$messages['setdeleted'] = 'Conjunto de filtros excluídos com sucesso.';
-$messages['setdeleteconfirm'] = 'Você está certo que deseja excluir o conjunto de filtros selecionados?';
-$messages['setcreateerror'] = 'Impossível criar o conjunto de filtros. Ocorreu um erro no servidor.';
-$messages['setcreated'] = 'Conjunto de filtros criado com sucesso.';
-$messages['activateerror'] = 'Impossível habilitar o(s) filtro(s) selecionado(s). Ocorreu um erro no servidor.';
-$messages['deactivateerror'] = 'Impossível desabilitar o(s) filtro(s) selecionado(s). Ocorreu um erro no servidor.';
-$messages['deactivated'] = 'Filtro(s) habilitado(s) com sucesso.';
-$messages['activated'] = 'Filtro(s) desabilitado(s) com sucesso.';
-$messages['moved'] = 'Filtro movido com sucesso.';
-$messages['moveerror'] = 'Impossível mover o filtro selecionado. Ocorreu um erro no servidor.';
-$messages['nametoolong'] = 'Nome muito longo.';
-$messages['namereserved'] = 'Nome reservado.';
-$messages['setexist'] = 'Conjunto já existe.';
-$messages['nodata'] = 'Pelo menos uma posição precisa ser selecionada!';
-$messages['invaliddateformat'] = 'Data inválida';
-$messages['saveerror'] = 'Impossível salvar dados. Ocorreu um erro no servidor.';
-$messages['vacationsaved'] = 'Dados de férias salvos com sucesso.';
-$messages['emptyvacationbody'] = 'Conteúdo da mensagem de férias necessário!';
-?>
diff --git a/lib/plugins/managesieve/localization/pt_PT.inc b/lib/plugins/managesieve/localization/pt_PT.inc
deleted file mode 100644
index ec39542..0000000
--- a/lib/plugins/managesieve/localization/pt_PT.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtros';
-$labels['managefilters'] = 'Gerir filtros';
-$labels['filtername'] = 'Nome do filtro';
-$labels['newfilter'] = 'Novo filtro';
-$labels['filteradd'] = 'Adicionar filtro';
-$labels['filterdel'] = 'Eliminar filtro';
-$labels['moveup'] = 'Mover para cima';
-$labels['movedown'] = 'Mover para baixo';
-$labels['filterallof'] = 'corresponde a todas as seguintes regras';
-$labels['filteranyof'] = 'corresponde a uma das seguintes regras';
-$labels['filterany'] = 'todas as mensagens';
-$labels['filtercontains'] = 'contém';
-$labels['filternotcontains'] = 'não contém';
-$labels['filteris'] = 'é igual a';
-$labels['filterisnot'] = 'é diferente de';
-$labels['filterexists'] = 'existe';
-$labels['filternotexists'] = 'não existe';
-$labels['filtermatches'] = 'expressão corresponde';
-$labels['filternotmatches'] = 'expressão não corresponde';
-$labels['filterregex'] = 'corresponde à expressão';
-$labels['filternotregex'] = 'não corresponde à expressão';
-$labels['filterunder'] = 'é inferior a';
-$labels['filterover'] = 'é superior a';
-$labels['addrule'] = 'Adicionar regra';
-$labels['delrule'] = 'Eliminar regra';
-$labels['messagemoveto'] = 'Mover mensagem para';
-$labels['messageredirect'] = 'Redirecionar mensagem para';
-$labels['messagecopyto'] = 'Copiar mensagem para';
-$labels['messagesendcopy'] = 'Enviar cópia da mensagem para';
-$labels['messagereply'] = 'Responder com a mensagem';
-$labels['messagedelete'] = 'Eliminar mensagem';
-$labels['messagediscard'] = 'Rejeitar mensagem';
-$labels['messagekeep'] = 'Manter mensagem na Caixa de entrada';
-$labels['messagesrules'] = 'Regras para Filtros';
-$labels['messagesactions'] = 'Acções para Filtros';
-$labels['add'] = 'Adicionar';
-$labels['del'] = 'Eliminar';
-$labels['sender'] = 'Remetente';
-$labels['recipient'] = 'Destinatário';
-$labels['vacationaddr'] = 'Os meus endereços de e-mail adicionais:';
-$labels['vacationdays'] = 'Enviar mensagens com que frequência (em dias):';
-$labels['vacationinterval'] = 'Com que frequência envia mensagens:';
-$labels['vacationreason'] = 'Conteúdo da mensagem (motivo da ausência):';
-$labels['vacationsubject'] = 'Assunto da mensagem:';
-$labels['days'] = 'dias';
-$labels['seconds'] = 'segundos';
-$labels['rulestop'] = 'Parar de avaliar regras';
-$labels['enable'] = 'Activar/Desactivar';
-$labels['filterset'] = 'Filtros definidos';
-$labels['filtersets'] = 'Filtros definidos';
-$labels['filtersetadd'] = 'Adicionar definição de filtros';
-$labels['filtersetdel'] = 'Eliminar definição de filtros actuais';
-$labels['filtersetact'] = 'Activar definição de filtros actuais';
-$labels['filtersetdeact'] = 'Desactivar definição de filtros actuais';
-$labels['filterdef'] = 'Definição de filtros';
-$labels['filtersetname'] = 'Nome da definição de filtros';
-$labels['newfilterset'] = 'Nova definição de filtros';
-$labels['active'] = 'activo';
-$labels['none'] = 'nehnum';
-$labels['fromset'] = 'definição de';
-$labels['fromfile'] = 'a partir do ficheiro';
-$labels['filterdisabled'] = 'Filtro desactivado';
-$labels['countisgreaterthan'] = 'contagem é maior que';
-$labels['countisgreaterthanequal'] = 'contagem é maior ou igual a';
-$labels['countislessthan'] = 'contagem é menor que';
-$labels['countislessthanequal'] = 'contagem é menor ou igual a';
-$labels['countequals'] = 'contagem é igual a';
-$labels['countnotequals'] = 'a contagem não é igual a';
-$labels['valueisgreaterthan'] = 'valor é maior que';
-$labels['valueisgreaterthanequal'] = 'valor é maior ou igual a';
-$labels['valueislessthan'] = 'valor é menor que';
-$labels['valueislessthanequal'] = 'valor é menor ou igual a';
-$labels['valueequals'] = 'valor é igual a';
-$labels['valuenotequals'] = 'o valor não é igual a';
-$labels['setflags'] = 'Definir indicadores para a mensagem';
-$labels['addflags'] = 'Adicionar indicadores para a mensagem';
-$labels['removeflags'] = 'Eliminar indicadores da mensagem';
-$labels['flagread'] = 'Lida';
-$labels['flagdeleted'] = 'Eliminada';
-$labels['flaganswered'] = 'Respondida';
-$labels['flagflagged'] = 'Marcada';
-$labels['flagdraft'] = 'Rascunho';
-$labels['setvariable'] = 'Definir variável';
-$labels['setvarname'] = 'Nome da Variável:';
-$labels['setvarvalue'] = 'Valor da Variável:';
-$labels['setvarmodifiers'] = 'Modificadores:';
-$labels['varlower'] = 'minúscula';
-$labels['varupper'] = 'maiúscula';
-$labels['varlowerfirst'] = 'primeira letra em minúscula';
-$labels['varupperfirst'] = 'primeira letra em maiúscula';
-$labels['varquotewildcard'] = 'citar caracteres especiais';
-$labels['varlength'] = 'tamanho';
-$labels['notify'] = 'Enviar notificação';
-$labels['notifytarget'] = 'Destino da notificação:';
-$labels['notifymessage'] = 'Mensagem de notificação (opcional):';
-$labels['notifyoptions'] = 'Opções de notificação (opcional):';
-$labels['notifyfrom'] = 'Remetente da notificação (opcional):';
-$labels['notifyimportance'] = 'Importância:';
-$labels['notifyimportancelow'] = 'baixa';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'alta';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Telefone';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Criar filtro';
-$labels['usedata'] = 'Usar os seguintes dados no filtro:';
-$labels['nextstep'] = 'Próximo passo';
-$labels['...'] = '...';
-$labels['currdate'] = 'Data atual';
-$labels['datetest'] = 'Data';
-$labels['dateheader'] = 'cabeçalho:';
-$labels['year'] = 'ano';
-$labels['month'] = 'mês';
-$labels['day'] = 'dia';
-$labels['date'] = 'data (yyyy-mm-dd)';
-$labels['julian'] = 'data (juliano)';
-$labels['hour'] = 'hora';
-$labels['minute'] = 'minuto';
-$labels['second'] = 'segundo';
-$labels['time'] = 'hora (hh:mm:ss)';
-$labels['iso8601'] = 'data (ISO8601)';
-$labels['std11'] = 'data (RFC2822)';
-$labels['zone'] = 'fuso horário';
-$labels['weekday'] = 'dia da semana (0-6)';
-$labels['advancedopts'] = 'Opções avançadas';
-$labels['body'] = 'Corpo';
-$labels['address'] = 'endereço';
-$labels['envelope'] = 'envelope';
-$labels['modifier'] = 'modificador:';
-$labels['text'] = 'Texto';
-$labels['undecoded'] = 'não descodificado (raw)';
-$labels['contenttype'] = 'tipo de conteúdo';
-$labels['modtype'] = 'tipo:';
-$labels['allparts'] = 'todos';
-$labels['domain'] = 'domínio';
-$labels['localpart'] = 'parte local';
-$labels['user'] = 'utilizador';
-$labels['detail'] = 'detalhe';
-$labels['comparator'] = 'Comparador';
-$labels['default'] = 'predefinido';
-$labels['octet'] = 'estrito (octeto)';
-$labels['asciicasemap'] = 'não sensível a maiúsculas/minúsculas (caracteres ascii)';
-$labels['asciinumeric'] = 'numérico (numérico ascii)';
-$labels['index'] = 'índice:';
-$labels['indexlast'] = 'retroceder';
-$labels['vacation'] = 'Férias';
-$labels['vacation.reply'] = 'Mensagem de resposta';
-$labels['vacation.advanced'] = 'Definições avançadas';
-$labels['vacation.subject'] = 'Assunto';
-$labels['vacation.body'] = 'Corpo da mensagem';
-$labels['vacation.start'] = 'Início de férias';
-$labels['vacation.end'] = 'Fim de férias';
-$labels['vacation.status'] = 'Estado';
-$labels['vacation.on'] = 'Ligar';
-$labels['vacation.off'] = 'Desligar';
-$labels['vacation.addresses'] = 'Meus endereços adicionais';
-$labels['vacation.interval'] = 'Intervalo de resposta';
-$labels['vacation.after'] = 'Coloque regra de férias depois';
-$labels['vacation.saving'] = 'A guardar dados...';
-$labels['vacation.action'] = 'Acção para mensagem recebida';
-$labels['vacation.keep'] = 'Manter';
-$labels['vacation.discard'] = 'Rejeitar';
-$labels['vacation.redirect'] = 'Redireccionar para';
-$labels['vacation.copy'] = 'Enviar cópia para';
-$labels['arialabelfiltersetactions'] = 'Acções do conjunto de filtros';
-$labels['arialabelfilteractions'] = 'Acções dos filtros';
-$labels['arialabelfilterform'] = 'Propriedades dos filtro';
-$labels['ariasummaryfilterslist'] = 'Lista de filtros';
-$labels['ariasummaryfiltersetslist'] = 'Lista de conjuntos de filtros';
-$labels['filterstitle'] = 'Editar filtros de mensagens recebidas';
-$labels['vacationtitle'] = 'Editar regra de ausência do escritório';
-$messages['filterunknownerror'] = 'Erro de servidor desconhecido';
-$messages['filterconnerror'] = 'Não é possível ligar ao servidor Sieve';
-$messages['filterdeleteerror'] = 'Não foi possível eliminar o filtro. Ocorreu um erro no servidor.';
-$messages['filterdeleted'] = 'Filtro eliminado com sucesso';
-$messages['filtersaved'] = 'Filtro guardado com sucesso';
-$messages['filtersaveerror'] = 'Não foi possível guardar o filtro. Ocorreu um erro no servidor.';
-$messages['filterdeleteconfirm'] = 'Tem a certeza que pretende eliminar este filtro?';
-$messages['ruledeleteconfirm'] = 'Tem a certeza que pretende eliminar esta regra?';
-$messages['actiondeleteconfirm'] = 'Tem a certeza que pretende eliminar esta acção?';
-$messages['forbiddenchars'] = 'Caracteres inválidos no campo.';
-$messages['cannotbeempty'] = 'Este campo não pode estar vazio.';
-$messages['ruleexist'] = 'Já existe um Filtro com o nome especificado.';
-$messages['setactivateerror'] = 'Não foi possível ativar os filtros selecionados. Ocorreu um erro no servidor.';
-$messages['setdeactivateerror'] = 'Não foi possível desativar os filtros selecionados. Ocorreu um erro no servidor.';
-$messages['setdeleteerror'] = 'Não foi possível eliminar os filtros selecionados. Ocorreu um erro no servidor.';
-$messages['setactivated'] = 'Filtros ativados com sucesso.';
-$messages['setdeactivated'] = 'Filtros desativados com sucesso.';
-$messages['setdeleted'] = 'Filtros eliminados com sucesso.';
-$messages['setdeleteconfirm'] = 'Tem a certeza que pretende eliminar os filtros selecionados?';
-$messages['setcreateerror'] = 'Não foi possível criar o conjunto de filtros. Ocorreu um erro no servidor.';
-$messages['setcreated'] = 'Conjunto de filtros criado com sucesso.';
-$messages['activateerror'] = 'Não foi possível ativar os filtros selecionados. Ocorreu um erro no servidor.';
-$messages['deactivateerror'] = 'Não foi possível desativar os filtros selecionados. Ocorreu um erro no servidor.';
-$messages['deactivated'] = 'Filtro(s) ativado(s) com sucesso.';
-$messages['activated'] = 'Filtro(s) desativado(s) com sucesso.';
-$messages['moved'] = 'Filtro movido com sucesso.';
-$messages['moveerror'] = 'Não foi possível mover o filtro selecionado. Ocorreu um erro no servidor.';
-$messages['nametoolong'] = 'Nome demasiado longo.';
-$messages['namereserved'] = 'Nome invertido.';
-$messages['setexist'] = 'O conjunto já existe.';
-$messages['nodata'] = 'Deve selecionar pelo menos uma posição.';
-$messages['invaliddateformat'] = 'Data ou formato de data inválido.';
-$messages['saveerror'] = 'Não foi possível guardar os dados. Ocorreu um erro no servidor.';
-$messages['vacationsaved'] = 'Dados de férias guardados com sucesso.';
-$messages['emptyvacationbody'] = 'É necessário o corpo da mensagem de férias!';
-?>
diff --git a/lib/plugins/managesieve/localization/ro_RO.inc b/lib/plugins/managesieve/localization/ro_RO.inc
deleted file mode 100644
index 017320e..0000000
--- a/lib/plugins/managesieve/localization/ro_RO.inc
+++ /dev/null
@@ -1,202 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtre';
-$labels['managefilters'] = 'Administreaza filtrele pentru mesaje primite.';
-$labels['filtername'] = 'Nume filtru';
-$labels['newfilter'] = 'Filtru nou';
-$labels['filteradd'] = 'Adauga un filtru';
-$labels['filterdel'] = 'Sterge filtru.';
-$labels['moveup'] = 'Muta mai sus';
-$labels['movedown'] = 'Muta mai jos';
-$labels['filterallof'] = 'se potriveste cu toate regulile urmatoare';
-$labels['filteranyof'] = 'se potriveste cu oricare din regulile urmatoare';
-$labels['filterany'] = 'toate mesajele';
-$labels['filtercontains'] = 'contine';
-$labels['filternotcontains'] = 'nu contine';
-$labels['filteris'] = 'este egal cu';
-$labels['filterisnot'] = 'este diferit de';
-$labels['filterexists'] = 'exista';
-$labels['filternotexists'] = 'nu exista';
-$labels['filtermatches'] = 'se potriveste cu expresia';
-$labels['filternotmatches'] = 'nu se potriveste cu expresia';
-$labels['filterregex'] = 'se potriveste cu expresia regulata';
-$labels['filternotregex'] = 'nu se potriveste cu expresia regulata';
-$labels['filterunder'] = 'sub';
-$labels['filterover'] = 'peste';
-$labels['addrule'] = 'Adauga regula';
-$labels['delrule'] = 'Sterge regula';
-$labels['messagemoveto'] = 'Muta mesajul in';
-$labels['messageredirect'] = 'Redirectioneaza mesajul catre';
-$labels['messagecopyto'] = 'Copiaza mesajul in';
-$labels['messagesendcopy'] = 'Trimite o copie a mesajului catre';
-$labels['messagereply'] = 'Raspunde cu mesajul';
-$labels['messagedelete'] = 'Sterge mesajul';
-$labels['messagediscard'] = 'Respinge cu mesajul';
-$labels['messagekeep'] = 'Pastreaza mesajele in Inbox';
-$labels['messagesrules'] = 'Pentru e-mail primit:';
-$labels['messagesactions'] = '...executa urmatoarele actiuni:';
-$labels['add'] = 'Adauga';
-$labels['del'] = 'Sterge';
-$labels['sender'] = 'Expeditor';
-$labels['recipient'] = 'Destinatar';
-$labels['vacationaddr'] = 'Adresele mele de e-mail (adiţionale)';
-$labels['vacationdays'] = 'Cat de des sa trimit mesajele (in zile):';
-$labels['vacationinterval'] = 'Cât de des să trimit mesaje:';
-$labels['vacationreason'] = 'Corpul mesajului (motivul vacantei):';
-$labels['vacationsubject'] = 'Subiectul mesajului:';
-$labels['days'] = 'zile';
-$labels['seconds'] = 'secunde';
-$labels['rulestop'] = 'Nu mai evalua reguli';
-$labels['enable'] = 'Activeaza/Dezactiveaza';
-$labels['filterset'] = 'Filtre setate';
-$labels['filtersets'] = 'Filtrul seteaza';
-$labels['filtersetadd'] = 'Adauga set de filtre';
-$labels['filtersetdel'] = 'Sterge setul curent de filtre';
-$labels['filtersetact'] = 'Activeaza setul curent de filtre';
-$labels['filtersetdeact'] = 'Dezactiveaza setul curent de filtre';
-$labels['filterdef'] = 'Definiţie filtru';
-$labels['filtersetname'] = 'Nume set filtre';
-$labels['newfilterset'] = 'Set filtre nou';
-$labels['active'] = 'activ';
-$labels['none'] = 'niciunul';
-$labels['fromset'] = 'din setul';
-$labels['fromfile'] = 'din fişier';
-$labels['filterdisabled'] = 'Filtru dezactivat';
-$labels['countisgreaterthan'] = 'numărul este mai mare ca';
-$labels['countisgreaterthanequal'] = 'numărul este mai mare sau egal cu';
-$labels['countislessthan'] = 'numărul este mai mic decât';
-$labels['countislessthanequal'] = 'numărul este mai mic sau egal cu';
-$labels['countequals'] = 'numărul este egal cu';
-$labels['countnotequals'] = 'numaratoarea nu este egala cu';
-$labels['valueisgreaterthan'] = 'valoarea este egală cu';
-$labels['valueisgreaterthanequal'] = 'valoarea este mai mare sau egala cu';
-$labels['valueislessthan'] = 'valoarea este mai mică decât';
-$labels['valueislessthanequal'] = 'valoarea este mai mică sau egală cu';
-$labels['valueequals'] = 'valoarea este egală cu';
-$labels['valuenotequals'] = 'valoarea nu este egala cu';
-$labels['setflags'] = 'Pune marcaje mesajului';
-$labels['addflags'] = 'Adaugă marcaje mesajului';
-$labels['removeflags'] = 'Şterge marcajele mesajului';
-$labels['flagread'] = 'Citit';
-$labels['flagdeleted'] = 'Șters';
-$labels['flaganswered'] = 'Răspuns';
-$labels['flagflagged'] = 'Marcat';
-$labels['flagdraft'] = 'Schiță';
-$labels['setvariable'] = 'Setare variabilă';
-$labels['setvarname'] = 'Nume variabilă:';
-$labels['setvarvalue'] = 'Valoare variabilă:';
-$labels['setvarmodifiers'] = 'Modificatori:';
-$labels['varlower'] = 'cu litere mici';
-$labels['varupper'] = 'cu litere mari';
-$labels['varlowerfirst'] = 'primul caracter cu litre mici';
-$labels['varupperfirst'] = 'primul caracter cu litre mari';
-$labels['varquotewildcard'] = 'caracterele speciale in citat';
-$labels['varlength'] = 'lungime';
-$labels['notify'] = 'Notificare trimitere';
-$labels['notifyimportance'] = 'Importanța:';
-$labels['notifyimportancelow'] = 'mică';
-$labels['notifyimportancenormal'] = 'normală';
-$labels['notifyimportancehigh'] = 'mare';
-$labels['filtercreate'] = 'Crează filtru';
-$labels['usedata'] = 'Foloseşte următoarele date în filtru:';
-$labels['nextstep'] = 'Următorul Pas';
-$labels['...'] = '...';
-$labels['currdate'] = 'Data curenta';
-$labels['datetest'] = 'Data';
-$labels['dateheader'] = 'header:';
-$labels['year'] = 'an';
-$labels['month'] = 'luna';
-$labels['day'] = 'zi';
-$labels['date'] = 'data (AAAA-LL-ZZ)';
-$labels['julian'] = 'data (calendar iulian)';
-$labels['hour'] = 'ora';
-$labels['minute'] = 'minut';
-$labels['second'] = 'secunda';
-$labels['time'] = 'ora (hh:mm:ss)';
-$labels['iso8601'] = 'data (ISO8601)';
-$labels['std11'] = 'data (RFC2822)';
-$labels['zone'] = 'fus orar';
-$labels['weekday'] = 'zi saptamana (0-6)';
-$labels['advancedopts'] = 'Opţiuni avansate';
-$labels['body'] = 'Corp';
-$labels['address'] = 'adresă';
-$labels['envelope'] = 'plic';
-$labels['modifier'] = 'modificator:';
-$labels['text'] = 'text';
-$labels['undecoded'] = 'nedecodat (brut)';
-$labels['contenttype'] = 'tip conţinut';
-$labels['modtype'] = 'tip:';
-$labels['allparts'] = 'toate';
-$labels['domain'] = 'domeniu';
-$labels['localpart'] = 'partea locală';
-$labels['user'] = 'utilizator';
-$labels['detail'] = 'detaliu';
-$labels['comparator'] = 'comparator:';
-$labels['default'] = 'implicit';
-$labels['octet'] = 'strict (octet)';
-$labels['asciicasemap'] = 'ignoră majusculele (ascii-casemap)';
-$labels['asciinumeric'] = 'numeric (ascii-numeric)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'invers';
-$labels['vacation'] = 'Vacanta';
-$labels['vacation.reply'] = 'Raspunde mesajului';
-$labels['vacation.advanced'] = 'Setari avansate';
-$labels['vacation.subject'] = 'Subiect';
-$labels['vacation.body'] = 'Corp';
-$labels['vacation.status'] = 'Statut';
-$labels['vacation.on'] = 'Pe';
-$labels['vacation.off'] = 'De pe';
-$labels['vacation.addresses'] = 'Adresa mea aditionala';
-$labels['vacation.interval'] = 'Interval de raspundere';
-$labels['vacation.after'] = 'Pune regula de vacanta dupa';
-$labels['vacation.saving'] = 'Salvez datele...';
-$messages['filterunknownerror'] = 'Eroare necunoscută la server:';
-$messages['filterconnerror'] = 'Nu mă pot conecta la server.';
-$messages['filterdeleteerror'] = 'Nu pot şterge filtrul. S-a produs o eroare la server.';
-$messages['filterdeleted'] = 'Filtrul a fost şters cu succes.';
-$messages['filtersaved'] = 'Filtrul a fost salvat cu succes.';
-$messages['filtersaveerror'] = 'Nu am putut salva filtrul. S-a produs o eroare la server.';
-$messages['filterdeleteconfirm'] = 'Chiar vrei să ştergi filtrul selectat?';
-$messages['ruledeleteconfirm'] = 'Eşti sigur că vrei să ştergi regula selectată?';
-$messages['actiondeleteconfirm'] = 'Eşti sigur că vrei să ştergi acţiunea selectată?';
-$messages['forbiddenchars'] = 'Caractere nepermise în câmp.';
-$messages['cannotbeempty'] = 'Câmpul nu poate fi gol.';
-$messages['ruleexist'] = 'Filtrul cu numele specificat există deja.';
-$messages['setactivateerror'] = 'Nu pot activa setul de filtre selectat. S-a produs o eroare la server.';
-$messages['setdeactivateerror'] = 'Nu pot dezactiva setul de filtre selectat. S-a produs o eroare la server.';
-$messages['setdeleteerror'] = 'Nu pot şterge setul de filtre selectat. S-a produs o eroare la server.';
-$messages['setactivated'] = 'Setul de filtre activat cu succes.';
-$messages['setdeactivated'] = 'Setul de filtre dezactivat cu succes.';
-$messages['setdeleted'] = 'Setul de filtre şters cu succes.';
-$messages['setdeleteconfirm'] = 'Eşti sigur(ă) că vrei să ştergi setul de filtre selectat?';
-$messages['setcreateerror'] = 'Nu am putut crea setul de filtre. S-a produs o eroare la server.';
-$messages['setcreated'] = 'Setul de filtre creat cu succes.';
-$messages['activateerror'] = 'Nu am putut activa filtrul (filtrele) selectate. S-a produs o eroare la server.';
-$messages['deactivateerror'] = 'Nu am putut dezactiva filtrele (filtrele) selectate. S-a produs o eroare la server.';
-$messages['deactivated'] = 'Filtrele au fost activate cu succes.';
-$messages['activated'] = 'Filtrele au fost dezactivate cu succes.';
-$messages['moved'] = 'Filtrele au fost mutate cu succes.';
-$messages['moveerror'] = 'Nu am putut muta filtrul selectat. S-a produs o eroare la server.';
-$messages['nametoolong'] = 'Numele este prea lung.';
-$messages['namereserved'] = 'Nume rezervat.';
-$messages['setexist'] = 'Setul există deja.';
-$messages['nodata'] = 'Trebuie selectată cel putin o poziţie!';
-$messages['invaliddateformat'] = 'Data sau parte din data in format invalid';
-$messages['saveerror'] = 'Nu am putut salva datele. A aparut o eroare de server.';
-$messages['vacationsaved'] = 'Data de vacanta salvata cu succes';
-?>
diff --git a/lib/plugins/managesieve/localization/ru_RU.inc b/lib/plugins/managesieve/localization/ru_RU.inc
deleted file mode 100644
index 6714c4c..0000000
--- a/lib/plugins/managesieve/localization/ru_RU.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Фильтры';
-$labels['managefilters'] = 'Управление фильтрами для входящей почты';
-$labels['filtername'] = 'Название фильтра';
-$labels['newfilter'] = 'Новый фильтр';
-$labels['filteradd'] = 'Добавить фильтр';
-$labels['filterdel'] = 'Удалить фильтр';
-$labels['moveup'] = 'Сдвинуть вверх';
-$labels['movedown'] = 'Сдвинуть вниз';
-$labels['filterallof'] = 'соответствует всем указанным правилам';
-$labels['filteranyof'] = 'соответствует любому из указанных правил';
-$labels['filterany'] = 'все сообщения';
-$labels['filtercontains'] = 'содержит';
-$labels['filternotcontains'] = 'не содержит';
-$labels['filteris'] = 'соответствует';
-$labels['filterisnot'] = 'не соответствует';
-$labels['filterexists'] = 'существует';
-$labels['filternotexists'] = 'не существует';
-$labels['filtermatches'] = 'совпадает с выражением';
-$labels['filternotmatches'] = 'не совпадает с выражением';
-$labels['filterregex'] = 'совпадает с регулярным выражением';
-$labels['filternotregex'] = 'не совпадает с регулярным выражением';
-$labels['filterunder'] = 'меньше';
-$labels['filterover'] = 'больше';
-$labels['addrule'] = 'Добавить правило';
-$labels['delrule'] = 'Удалить правило';
-$labels['messagemoveto'] = 'Переместить сообщение в';
-$labels['messageredirect'] = 'Перенаправить сообщение на';
-$labels['messagecopyto'] = 'Скопировать сообщение в';
-$labels['messagesendcopy'] = 'Отправить копию сообщения на';
-$labels['messagereply'] = 'Ответить с сообщением';
-$labels['messagedelete'] = 'Удалить сообщение';
-$labels['messagediscard'] = 'Отбросить с сообщением';
-$labels['messagekeep'] = 'Оставить сообщение во Входящих';
-$labels['messagesrules'] = 'Для входящей почты:';
-$labels['messagesactions'] = '...выполнить следующие действия:';
-$labels['add'] = 'Добавить';
-$labels['del'] = 'Удалить';
-$labels['sender'] = 'Отправитель';
-$labels['recipient'] = 'Получатель';
-$labels['vacationaddr'] = 'Мой дополнительный адрес(а):';
-$labels['vacationdays'] = 'Как часто отправлять сообщения (в днях):';
-$labels['vacationinterval'] = 'Как часто отправлять сообщения:';
-$labels['vacationreason'] = 'Текст сообщения (причина отсутствия):';
-$labels['vacationsubject'] = 'Тема сообщения:';
-$labels['days'] = 'дней';
-$labels['seconds'] = 'секунд';
-$labels['rulestop'] = 'Закончить выполнение';
-$labels['enable'] = 'Включить/Выключить';
-$labels['filterset'] = 'Набор фильтров';
-$labels['filtersets'] = 'Наборы фильтров';
-$labels['filtersetadd'] = 'Добавить набор фильтров';
-$labels['filtersetdel'] = 'Удалить текущий набор фильтров';
-$labels['filtersetact'] = 'Включить текущий набор фильтров';
-$labels['filtersetdeact'] = 'Отключить текущий набор фильтров';
-$labels['filterdef'] = 'Описание фильтра';
-$labels['filtersetname'] = 'Название набора фильтров';
-$labels['newfilterset'] = 'Новый набор фильтров';
-$labels['active'] = 'используется';
-$labels['none'] = 'нет';
-$labels['fromset'] = 'из набора';
-$labels['fromfile'] = 'из файла';
-$labels['filterdisabled'] = 'Отключить фильтр';
-$labels['countisgreaterthan'] = 'количество больше, чем';
-$labels['countisgreaterthanequal'] = 'количество больше или равно';
-$labels['countislessthan'] = 'количество меньше, чем';
-$labels['countislessthanequal'] = 'количество меньше или равно';
-$labels['countequals'] = 'количество равно';
-$labels['countnotequals'] = 'количество не равно';
-$labels['valueisgreaterthan'] = 'значение больше, чем';
-$labels['valueisgreaterthanequal'] = 'значение больше или равно';
-$labels['valueislessthan'] = 'значение меньше, чем';
-$labels['valueislessthanequal'] = 'значение меньше или равно';
-$labels['valueequals'] = 'значение равно';
-$labels['valuenotequals'] = 'значение не равно';
-$labels['setflags'] = 'Установить флаги на сообщение';
-$labels['addflags'] = 'Добавить флаги к сообщению';
-$labels['removeflags'] = 'Убрать флаги из сообщения';
-$labels['flagread'] = 'Прочитано';
-$labels['flagdeleted'] = 'Удалено';
-$labels['flaganswered'] = 'Отвечено';
-$labels['flagflagged'] = 'Помечено';
-$labels['flagdraft'] = 'Черновик';
-$labels['setvariable'] = 'Задать переменную';
-$labels['setvarname'] = 'Имя переменной:';
-$labels['setvarvalue'] = 'Значение переменной:';
-$labels['setvarmodifiers'] = 'Модификаторы:';
-$labels['varlower'] = 'нижний регистр';
-$labels['varupper'] = 'верхний регистр';
-$labels['varlowerfirst'] = 'первый символ в нижнем регистре';
-$labels['varupperfirst'] = 'первый символ в верхнем регистре';
-$labels['varquotewildcard'] = 'символ кавычек';
-$labels['varlength'] = 'длина';
-$labels['notify'] = 'Отправить уведомление';
-$labels['notifytarget'] = 'Объект уведомления:';
-$labels['notifymessage'] = 'Сообщение уведомления (не обязательно):';
-$labels['notifyoptions'] = 'Параметры уведомления (не обязательно):';
-$labels['notifyfrom'] = 'Отправитель уведомления (не обязательно):';
-$labels['notifyimportance'] = 'Важность:';
-$labels['notifyimportancelow'] = 'низкая';
-$labels['notifyimportancenormal'] = 'нормальная';
-$labels['notifyimportancehigh'] = 'высокая';
-$labels['notifymethodmailto'] = 'Email';
-$labels['notifymethodtel'] = 'Телефон';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Создать фильтр';
-$labels['usedata'] = 'Использовать следующие данные в фильтре:';
-$labels['nextstep'] = 'Далее';
-$labels['...'] = '...';
-$labels['currdate'] = 'Текущая дата';
-$labels['datetest'] = 'Дата';
-$labels['dateheader'] = 'заголовок:';
-$labels['year'] = 'год';
-$labels['month'] = 'месяц';
-$labels['day'] = 'день';
-$labels['date'] = 'дата (гггг-мм-дд)';
-$labels['julian'] = 'дата (юлианская)';
-$labels['hour'] = 'час';
-$labels['minute'] = 'минута';
-$labels['second'] = 'секунда';
-$labels['time'] = 'время (чч:мм:сс)';
-$labels['iso8601'] = 'дата (ISO8601)';
-$labels['std11'] = 'дата (RFC2822)';
-$labels['zone'] = 'часовой пояс';
-$labels['weekday'] = 'день недели (0-6)';
-$labels['advancedopts'] = 'Дополнительные параметры';
-$labels['body'] = 'Тело письма';
-$labels['address'] = 'адрес';
-$labels['envelope'] = 'конверт';
-$labels['modifier'] = 'модификатор области поиска:';
-$labels['text'] = 'текст';
-$labels['undecoded'] = 'необработанный (сырой)';
-$labels['contenttype'] = 'тип содержимого';
-$labels['modtype'] = 'поиск в адресах:';
-$labels['allparts'] = 'везде';
-$labels['domain'] = 'в имени домена';
-$labels['localpart'] = 'только в имени пользователя, без домена';
-$labels['user'] = 'в полном имени пользователя';
-$labels['detail'] = 'в дополнительных сведениях';
-$labels['comparator'] = 'способ сравнения:';
-$labels['default'] = 'по умолчанию';
-$labels['octet'] = 'Строгий (octet)';
-$labels['asciicasemap'] = 'Регистронезависимый (ascii-casemap)';
-$labels['asciinumeric'] = 'Числовой (ascii-numeric)';
-$labels['index'] = 'индекс:';
-$labels['indexlast'] = 'наоборот';
-$labels['vacation'] = 'Отпуск';
-$labels['vacation.reply'] = 'Ответное сообщение';
-$labels['vacation.advanced'] = 'Дополнительные настройки';
-$labels['vacation.subject'] = 'Тема';
-$labels['vacation.body'] = 'Тело письма';
-$labels['vacation.start'] = 'Начало отпуска';
-$labels['vacation.end'] = 'Конец отпуска';
-$labels['vacation.status'] = 'Состояние';
-$labels['vacation.on'] = 'Вкл.';
-$labels['vacation.off'] = 'Выкл.';
-$labels['vacation.addresses'] = 'Мои дополнительные адреса';
-$labels['vacation.interval'] = 'Интервал ответа';
-$labels['vacation.after'] = 'Поместить правило отпуска после';
-$labels['vacation.saving'] = 'Сохранение данных...';
-$labels['vacation.action'] = 'Действия с входящим сообщением';
-$labels['vacation.keep'] = 'Оставить';
-$labels['vacation.discard'] = 'Отменить';
-$labels['vacation.redirect'] = 'Перенаправить на';
-$labels['vacation.copy'] = 'Отправить копию на';
-$labels['arialabelfiltersetactions'] = 'Действия набора фильтров';
-$labels['arialabelfilteractions'] = 'Действия фильтра';
-$labels['arialabelfilterform'] = 'Свойства фильтра';
-$labels['ariasummaryfilterslist'] = 'Список фильтров';
-$labels['ariasummaryfiltersetslist'] = 'Список набора фильтров';
-$labels['filterstitle'] = 'Редактировать фильтры для входящей почты';
-$labels['vacationtitle'] = 'Изменить правило "Не в офисе"';
-$messages['filterunknownerror'] = 'Неизвестная ошибка сервера.';
-$messages['filterconnerror'] = 'Невозможно подключиться к серверу.';
-$messages['filterdeleteerror'] = 'Невозможно удалить фильтр. Ошибка сервера.';
-$messages['filterdeleted'] = 'Фильтр успешно удалён.';
-$messages['filtersaved'] = 'Фильтр успешно сохранён.';
-$messages['filtersaveerror'] = 'Невозможно сохранить фильтр. Ошибка сервера.';
-$messages['filterdeleteconfirm'] = 'Вы действительно хотите удалить выделенный фильтр?';
-$messages['ruledeleteconfirm'] = 'Вы уверенны, что хотите удалить выделенное правило?';
-$messages['actiondeleteconfirm'] = 'Вы уверенны, что хотите удалить выделенное действие?';
-$messages['forbiddenchars'] = 'Недопустимые символы в поле.';
-$messages['cannotbeempty'] = 'Поле не может быть пустым.';
-$messages['ruleexist'] = 'Фильтр с таким именем уже существует.';
-$messages['setactivateerror'] = 'Невозможно включить выбранный набор фильтров. Ошибка сервера.';
-$messages['setdeactivateerror'] = 'Невозможно отключить выбранный набор фильтров. Ошибка сервера.';
-$messages['setdeleteerror'] = 'Невозможно удалить выбранный набор фильтров. Ошибка сервера.';
-$messages['setactivated'] = 'Набор фильтров успешно включён.';
-$messages['setdeactivated'] = 'Набор фильтров успешно отключён.';
-$messages['setdeleted'] = 'Набор фильтров успешно удалён.';
-$messages['setdeleteconfirm'] = 'Вы уверены в том, что хотите удалить выбранный набор фильтров?';
-$messages['setcreateerror'] = 'Невозможно создать набор фильтров. Ошибка сервера.';
-$messages['setcreated'] = 'Набор фильтров успешно создан.';
-$messages['activateerror'] = 'Невозможно включить выбранный(е) фильтр(ы). Ошибка сервера.';
-$messages['deactivateerror'] = 'Невозможно выключить выбранный(е) фильтр(ы). Ошибка сервера.';
-$messages['deactivated'] = 'Фильтр(ы) успешно отключен(ы).';
-$messages['activated'] = 'Фильтр(ы) успешно включен(ы).';
-$messages['moved'] = 'Фильтр успешно перемещён.';
-$messages['moveerror'] = 'Невозможно переместить фильтр. Ошибка сервера.';
-$messages['nametoolong'] = 'Слишком длинное имя.';
-$messages['namereserved'] = 'Зарезервированное имя.';
-$messages['setexist'] = 'Набор уже существует.';
-$messages['nodata'] = 'Нужно выбрать хотя бы одну позицию!';
-$messages['invaliddateformat'] = 'Неверная дата или формат части даты';
-$messages['saveerror'] = 'Невозможно сохранить данные. Ошибка сервера.';
-$messages['vacationsaved'] = 'Данные об отпуске успешно сохранены.';
-$messages['emptyvacationbody'] = 'Сообщение о причине отсутствия не может быть пустым!';
-?>
diff --git a/lib/plugins/managesieve/localization/si_LK.inc b/lib/plugins/managesieve/localization/si_LK.inc
deleted file mode 100644
index 6537ed5..0000000
--- a/lib/plugins/managesieve/localization/si_LK.inc
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'පෙරහණ';
-$labels['moveup'] = 'ඉහළට ගෙනයන්න';
-$labels['movedown'] = 'පහළට ගෙනයන්න';
-$labels['filterany'] = 'සියලු පණිවිඩ';
-$labels['filtercontains'] = 'අඩංගු';
-$labels['messagedelete'] = 'පණිවිඩය මකන්න';
-$labels['add'] = 'එක් කරන්න';
-$labels['del'] = 'මකන්න';
-$labels['sender'] = 'යවන්නා';
-$labels['recipient'] = 'ලබන්නා';
-$labels['vacationsubject'] = 'පණිවිඩයේ මාතෘකාව:';
-$labels['enable'] = 'සක්‍රීය කරන්න/අක්‍රීය කරන්න';
-$labels['active'] = 'සක්‍රීය';
-$labels['none'] = 'කිසිවක් නැත';
-$labels['flagread'] = 'කියවන්න';
-$labels['flagdeleted'] = 'මකන ලදී';
-$labels['flagdraft'] = 'කටු සටහන';
-$labels['nextstep'] = 'මීලග පියවර';
-$labels['...'] = '...';
-$labels['address'] = 'ලිපිනය';
-$labels['envelope'] = 'ලියුම් කවරය';
-$labels['modtype'] = 'වර්ගය:';
-$labels['allparts'] = 'සියල්ල';
-$messages['nametoolong'] = 'නම දිග වැඩිය.';
-?>
diff --git a/lib/plugins/managesieve/localization/sk_SK.inc b/lib/plugins/managesieve/localization/sk_SK.inc
deleted file mode 100644
index 4cad13f..0000000
--- a/lib/plugins/managesieve/localization/sk_SK.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtre';
-$labels['managefilters'] = 'Správa filtrov prichádzajúcej pošty';
-$labels['filtername'] = 'Názov filtra';
-$labels['newfilter'] = 'Nový filter';
-$labels['filteradd'] = 'Pridať filter';
-$labels['filterdel'] = 'Vymazať filter';
-$labels['moveup'] = 'Presunúť nahor';
-$labels['movedown'] = 'Presunúť nadol';
-$labels['filterallof'] = 'vyhovujúca všetkým z nasledujúcich pravidiel';
-$labels['filteranyof'] = 'vyhovujúca ľubovoľnému z nasledujúcich pravidiel';
-$labels['filterany'] = 'všetky správy';
-$labels['filtercontains'] = 'obsahuje';
-$labels['filternotcontains'] = 'neobsahuje';
-$labels['filteris'] = 'sa rovná';
-$labels['filterisnot'] = 'sa nerovná';
-$labels['filterexists'] = 'existuje';
-$labels['filternotexists'] = 'neexistuje';
-$labels['filtermatches'] = 'vyhovuje výrazu';
-$labels['filternotmatches'] = 'nevyhovuje výrazu';
-$labels['filterregex'] = 'vyhovuje regulárnemu výrazu';
-$labels['filternotregex'] = 'nevyhovuje regulárnemu výrazu';
-$labels['filterunder'] = 'pod';
-$labels['filterover'] = 'nad';
-$labels['addrule'] = 'Pridať pravidlo';
-$labels['delrule'] = 'Vymazať pravidlo';
-$labels['messagemoveto'] = 'Presunúť správu do';
-$labels['messageredirect'] = 'Presmerovať správu na';
-$labels['messagecopyto'] = 'Kopírovať správu do';
-$labels['messagesendcopy'] = 'Poslať kópiu správy na adresu';
-$labels['messagereply'] = 'Odpovedať správou';
-$labels['messagedelete'] = 'Vymazať správu';
-$labels['messagediscard'] = 'Vymazať a poslať správu na';
-$labels['messagekeep'] = 'Ponechať správu v Doručenej pošte';
-$labels['messagesrules'] = 'Pre prichádzajúcu poštu:';
-$labels['messagesactions'] = '...vykonať tieto akcie:';
-$labels['add'] = 'Pridať';
-$labels['del'] = 'Vymazať';
-$labels['sender'] = 'Odosielateľ';
-$labels['recipient'] = 'Príjemca';
-$labels['vacationaddr'] = 'Iná moja e-mailová adresa (adresy):';
-$labels['vacationdays'] = 'Ako často odosielať správy (v dňoch):';
-$labels['vacationinterval'] = 'Ako často odosielať správy:';
-$labels['vacationreason'] = 'Telo správy (dôvod neprítomnosti):';
-$labels['vacationsubject'] = 'Predmet správy:';
-$labels['days'] = 'dní';
-$labels['seconds'] = 'sekúnd';
-$labels['rulestop'] = 'Koniec pravidiel';
-$labels['enable'] = 'Zapnúť/vypnúť';
-$labels['filterset'] = 'Súprava filtrov';
-$labels['filtersets'] = 'Súpravy filtrov';
-$labels['filtersetadd'] = 'Pridať súpravu filtrov';
-$labels['filtersetdel'] = 'Vymazať aktuálnu súpravu filtrov';
-$labels['filtersetact'] = 'Aktivovať aktuálnu súpravu filtrov';
-$labels['filtersetdeact'] = 'Deaktivovať aktuálnu súpravu filtrov';
-$labels['filterdef'] = 'Definícia filtra';
-$labels['filtersetname'] = 'Názov súpravy filtrov';
-$labels['newfilterset'] = 'Nová súprava filtrov';
-$labels['active'] = 'aktívna';
-$labels['none'] = 'žiadne';
-$labels['fromset'] = 'zo súpravy';
-$labels['fromfile'] = 'zo súboru';
-$labels['filterdisabled'] = 'Filter vypnutý';
-$labels['countisgreaterthan'] = 'počet je väčší ako';
-$labels['countisgreaterthanequal'] = 'počet je väčší alebo rovný ako';
-$labels['countislessthan'] = 'počet je menší ako';
-$labels['countislessthanequal'] = 'počet je menší alebo rovný ako';
-$labels['countequals'] = 'počet je rovný';
-$labels['countnotequals'] = 'počet sa nerovná';
-$labels['valueisgreaterthan'] = 'hodnota je väčšia ako';
-$labels['valueisgreaterthanequal'] = 'hodnota je väčšia alebo rovná ako';
-$labels['valueislessthan'] = 'hodnota je menšia ako';
-$labels['valueislessthanequal'] = 'hodnota je menšia alebo rovná ako';
-$labels['valueequals'] = 'hodnota je rovná ako';
-$labels['valuenotequals'] = 'hodnota sa nerovná';
-$labels['setflags'] = 'Nastaviť príznaky správy';
-$labels['addflags'] = 'Pridať príznaky správy';
-$labels['removeflags'] = 'Odstrániť príznaky zo správy';
-$labels['flagread'] = 'Prečítané';
-$labels['flagdeleted'] = 'Vymazané';
-$labels['flaganswered'] = 'Odpovedané';
-$labels['flagflagged'] = 'Označené príznakom';
-$labels['flagdraft'] = 'Koncept';
-$labels['setvariable'] = 'Nastaviť premennú';
-$labels['setvarname'] = 'Názov premennej:';
-$labels['setvarvalue'] = 'Hodnota premennej:';
-$labels['setvarmodifiers'] = 'Modifikátory:';
-$labels['varlower'] = 'malé písmená';
-$labels['varupper'] = 'VEĽKÉ PÍSMENÁ';
-$labels['varlowerfirst'] = 'prvé písmeno malé';
-$labels['varupperfirst'] = 'prvé písmeno veľké';
-$labels['varquotewildcard'] = 'k špeciálnym znakom pridať úvodzovky';
-$labels['varlength'] = 'dĺžka';
-$labels['notify'] = 'Odoslať oznámenie';
-$labels['notifytarget'] = 'Cieľ notifikácie:';
-$labels['notifymessage'] = 'Notifikačná správa (voliteľne):';
-$labels['notifyoptions'] = 'Nastavenia notifikácie (voliteľné):';
-$labels['notifyfrom'] = 'Odosielateľ notifikácie (voliteľne):';
-$labels['notifyimportance'] = 'Priorita:';
-$labels['notifyimportancelow'] = 'nízka';
-$labels['notifyimportancenormal'] = 'normálna';
-$labels['notifyimportancehigh'] = 'vysoká';
-$labels['notifymethodmailto'] = 'E-mail';
-$labels['notifymethodtel'] = 'Telefón';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Vytvoriť filter';
-$labels['usedata'] = 'Použiť tieto údaje vo filtri:';
-$labels['nextstep'] = 'Ďalší krok';
-$labels['...'] = '...';
-$labels['currdate'] = 'Aktuálny dátum';
-$labels['datetest'] = 'Dátum';
-$labels['dateheader'] = 'záhlavie:';
-$labels['year'] = 'rok';
-$labels['month'] = 'mesiac';
-$labels['day'] = 'deň';
-$labels['date'] = 'dátum (rrrr-mm-dd)';
-$labels['julian'] = 'dátum (podľa Juliánskeho kalendára)';
-$labels['hour'] = 'hod.';
-$labels['minute'] = 'min.';
-$labels['second'] = 'sek.';
-$labels['time'] = 'čas (hh:mm:ss)';
-$labels['iso8601'] = 'dátum (ISO8601)';
-$labels['std11'] = 'dátum (RFC2822)';
-$labels['zone'] = 'časové pásmo';
-$labels['weekday'] = 'deň v týždni (0-6)';
-$labels['advancedopts'] = 'Rozšírené nastavenia';
-$labels['body'] = 'Telo';
-$labels['address'] = 'adresa';
-$labels['envelope'] = 'obálka';
-$labels['modifier'] = 'modifikátor:';
-$labels['text'] = 'text';
-$labels['undecoded'] = 'nedekódované (raw)';
-$labels['contenttype'] = 'typ obsahu';
-$labels['modtype'] = 'typ:';
-$labels['allparts'] = 'všetko';
-$labels['domain'] = 'doména';
-$labels['localpart'] = 'lokálna časť';
-$labels['user'] = 'používateľ';
-$labels['detail'] = 'detail';
-$labels['comparator'] = 'porovnávač:';
-$labels['default'] = 'predvolené';
-$labels['octet'] = 'striktný (osmičkový)';
-$labels['asciicasemap'] = 'nerozlišuje veľké a malé písmená (ascii tabuľka znakov)';
-$labels['asciinumeric'] = 'numerické (ascii čísla)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'dozadu';
-$labels['vacation'] = 'Dovolenka';
-$labels['vacation.reply'] = 'Odpoveď na správu';
-$labels['vacation.advanced'] = 'Pokročilé nastavenia';
-$labels['vacation.subject'] = 'Predmet';
-$labels['vacation.body'] = 'Telo';
-$labels['vacation.start'] = 'Začiatok dovolenky';
-$labels['vacation.end'] = 'Koniec dovolenky';
-$labels['vacation.status'] = 'Stav';
-$labels['vacation.on'] = 'Zap.';
-$labels['vacation.off'] = 'Vyp.';
-$labels['vacation.addresses'] = 'Moje ďalšie adresy';
-$labels['vacation.interval'] = 'Interval odpovedania';
-$labels['vacation.after'] = 'Nastaviť pravidlo pre dovolenku po';
-$labels['vacation.saving'] = 'Ukladanie údajov...';
-$labels['vacation.action'] = 'Akcia pre prichádzajúcu správu';
-$labels['vacation.keep'] = 'Zachovať';
-$labels['vacation.discard'] = 'Vyhodiť do koša';
-$labels['vacation.redirect'] = 'Presmerovať na';
-$labels['vacation.copy'] = 'Poslať kópiu na';
-$labels['arialabelfiltersetactions'] = 'Akcie zo súpravy filtrov';
-$labels['arialabelfilteractions'] = 'Akcie filtra';
-$labels['arialabelfilterform'] = 'Nastavenia filtra';
-$labels['ariasummaryfilterslist'] = 'Zoznam filtrov';
-$labels['ariasummaryfiltersetslist'] = 'Zoznam súprav s filtrami';
-$labels['filterstitle'] = 'Upraviť filtre prichádzajúcich e-mailov';
-$labels['vacationtitle'] = 'Upraviť pravidlo pre čas mimo kancelárie';
-$messages['filterunknownerror'] = 'Neznáma chyba servera.';
-$messages['filterconnerror'] = 'Nepodarilo sa pripojiť k serveru.';
-$messages['filterdeleteerror'] = 'Nemožno vymazať filter. Nastala chyba servera.';
-$messages['filterdeleted'] = 'Filter bol úspešne vymazaný.';
-$messages['filtersaved'] = 'Filter bol úspešne uložený.';
-$messages['filtersaveerror'] = 'Nemožno uložiť filter. Nastala chyba servera.';
-$messages['filterdeleteconfirm'] = 'Naozaj chcete vymazať vybraný filter?';
-$messages['ruledeleteconfirm'] = 'Naozaj chcete vymazať vybrané pravidlo?';
-$messages['actiondeleteconfirm'] = 'Naozaj chcete vymazať vybranú akciu?';
-$messages['forbiddenchars'] = 'Pole obsahuje nepovolené znaky.';
-$messages['cannotbeempty'] = 'Pole nemôže byť prázdne.';
-$messages['ruleexist'] = 'Filter so zadaným názvom už existuje.';
-$messages['setactivateerror'] = 'Nemožno aktivovať vybranú súpravu filtrov. Nastala chyba servera.';
-$messages['setdeactivateerror'] = 'Nemožno deaktivovať vybranú súpravu filtrov. Nastala chyba servera.';
-$messages['setdeleteerror'] = 'Nemožno vymazať vybranú súpravu filtrov. Nastala chyba servera.';
-$messages['setactivated'] = 'Súprava filtrov bola úspešne aktivovaná.';
-$messages['setdeactivated'] = 'Súprava filtrov bola úspešne deaktivovaná.';
-$messages['setdeleted'] = 'Súprava filtrov bola úspešne vymazaná.';
-$messages['setdeleteconfirm'] = 'Naozaj chcete vymazať vybranú súpravu filtrov?';
-$messages['setcreateerror'] = 'Nemožno vytvoriť súpravu filtrov. Nastala chyba servera.';
-$messages['setcreated'] = 'Súprava filtrov bola úspešne vytvorená.';
-$messages['activateerror'] = 'Nemožno aktivovať vybraný filter (vybrané filtre). Nastala chyba servera.';
-$messages['deactivateerror'] = 'Nemožno vypnúť vybraný filter (vybrané filtre). Nastala chyba servera.';
-$messages['deactivated'] = 'Filtre boli úspešne vypnuté.';
-$messages['activated'] = 'Filtre boli úspešne zapnuté.';
-$messages['moved'] = 'Filter bol úspešne presunutý.';
-$messages['moveerror'] = 'Nemožno presunúť vybraný filter. Nastala chyba servera.';
-$messages['nametoolong'] = 'Názov je príliš dlhý.';
-$messages['namereserved'] = 'Rezervovaný názov.';
-$messages['setexist'] = 'Súprava už existuje.';
-$messages['nodata'] = 'Aspoň jedna pozícia musí byť zvolená!';
-$messages['invaliddateformat'] = 'Neplatný formát dátumu alebo časti dátumu';
-$messages['saveerror'] = 'Údaje nemožno uložiť. Nastala chyba servera.';
-$messages['vacationsaved'] = 'Údaje o dovolenke boli úspešne uložené.';
-$messages['emptyvacationbody'] = 'Musíte zadať telo správy, zobrazovanej v čase neprítomnosti!';
-?>
diff --git a/lib/plugins/managesieve/localization/sl_SI.inc b/lib/plugins/managesieve/localization/sl_SI.inc
deleted file mode 100644
index f0e5159..0000000
--- a/lib/plugins/managesieve/localization/sl_SI.inc
+++ /dev/null
@@ -1,188 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtri';
-$labels['managefilters'] = 'Uredi filtre za dohodno pošto';
-$labels['filtername'] = 'Ime filtra';
-$labels['newfilter'] = 'Nov filter';
-$labels['filteradd'] = 'Dodaj filter';
-$labels['filterdel'] = 'Izbriši filter';
-$labels['moveup'] = 'Pomakni se navzgor';
-$labels['movedown'] = 'Pomakni se navzdol';
-$labels['filterallof'] = 'izpolnjeni morajo biti vsi pogoji';
-$labels['filteranyof'] = 'izpolnjen mora biti vsaj eden od navedenih pogojev';
-$labels['filterany'] = 'pogoj velja za vsa sporočila';
-$labels['filtercontains'] = 'vsebuje';
-$labels['filternotcontains'] = 'ne vsebuje';
-$labels['filteris'] = 'je enak/a';
-$labels['filterisnot'] = 'ni enak/a';
-$labels['filterexists'] = 'obstaja';
-$labels['filternotexists'] = 'ne obstaja';
-$labels['filtermatches'] = 'ustreza izrazu';
-$labels['filternotmatches'] = 'ne ustreza izrazu';
-$labels['filterregex'] = 'ustreza regularnemu izrazu';
-$labels['filternotregex'] = 'ne ustreza regularnemu izrazu';
-$labels['filterunder'] = 'pod';
-$labels['filterover'] = 'nad';
-$labels['addrule'] = 'Dodaj pravilo';
-$labels['delrule'] = 'Izbriši pravilo';
-$labels['messagemoveto'] = 'Premakni sporočilo v';
-$labels['messageredirect'] = 'Preusmeri sporočilo v';
-$labels['messagecopyto'] = 'Kopiraj sporočila na';
-$labels['messagesendcopy'] = 'Pošlji kopijo sporočila na';
-$labels['messagereply'] = 'Odgovori s sporočilom';
-$labels['messagedelete'] = 'Izbriši sporočilo';
-$labels['messagediscard'] = 'Zavrži s sporočilom';
-$labels['messagekeep'] = 'Ohrani sporočila v mapi Prejeto';
-$labels['messagesrules'] = 'Določi pravila za dohodno pošto:';
-$labels['messagesactions'] = '...izvrši naslednja dejanja:';
-$labels['add'] = 'Dodaj';
-$labels['del'] = 'Izbriši';
-$labels['sender'] = 'Pošiljatelj';
-$labels['recipient'] = 'Prejemnik';
-$labels['vacationaddr'] = 'Moji dodatni e-naslovi';
-$labels['vacationdays'] = 'Kako pogosto naj bodo sporočila poslana (v dnevih):';
-$labels['vacationinterval'] = 'Sporočila pošlji na:';
-$labels['vacationreason'] = 'Vsebina sporočila (vzrok za odsotnost):';
-$labels['vacationsubject'] = 'Zadeva sporočila';
-$labels['days'] = 'dni';
-$labels['seconds'] = 'sekund';
-$labels['rulestop'] = 'Prekini z izvajanjem pravil';
-$labels['enable'] = 'Omogoči/Onemogoči';
-$labels['filterset'] = 'Nastavitev filtrov';
-$labels['filtersets'] = 'Nastavitve filtrov';
-$labels['filtersetadd'] = 'Dodaj nastavitev filtrov';
-$labels['filtersetdel'] = 'Izbriši trenutne nastavitve filtriranja';
-$labels['filtersetact'] = 'Vključi trenutno nastavitev filtriranja';
-$labels['filtersetdeact'] = 'Onemogoči trenutno nastavitev filtriranja';
-$labels['filterdef'] = 'Opis filtra';
-$labels['filtersetname'] = 'Ime filtra';
-$labels['newfilterset'] = 'Nov filter';
-$labels['active'] = 'aktiven';
-$labels['none'] = 'brez';
-$labels['fromset'] = 'iz nastavitve';
-$labels['fromfile'] = 'iz dokumenta';
-$labels['filterdisabled'] = 'Filter onemogočen';
-$labels['countisgreaterthan'] = 'seštevek je večji od';
-$labels['countisgreaterthanequal'] = 'seštevek je večji ali enak';
-$labels['countislessthan'] = 'seštevek je manjši od';
-$labels['countislessthanequal'] = 'seštevel je manjši ali enak';
-$labels['countequals'] = 'seštevek je enak';
-$labels['countnotequals'] = 'vsota ne ustreza';
-$labels['valueisgreaterthan'] = 'vrednost je večja od';
-$labels['valueisgreaterthanequal'] = 'vrednost je večja ali enaka';
-$labels['valueislessthan'] = 'vrednost je manjša od';
-$labels['valueislessthanequal'] = 'vrednost je manjša ali enaka';
-$labels['valueequals'] = 'vrednost je enaka';
-$labels['valuenotequals'] = 'vrednost ni enaka';
-$labels['setflags'] = 'Označi sporočilo';
-$labels['addflags'] = 'Označi sporočilo';
-$labels['removeflags'] = 'Odstrani zaznamke s sporočil';
-$labels['flagread'] = 'Prebrano';
-$labels['flagdeleted'] = 'Izbrisano';
-$labels['flaganswered'] = 'Odgovorjeno';
-$labels['flagflagged'] = 'Označeno';
-$labels['flagdraft'] = 'Osnutek';
-$labels['setvariable'] = 'Nastavi spremenljivko';
-$labels['setvarname'] = 'Ime spremenljivke:';
-$labels['setvarvalue'] = 'Vrednost spremenljivke:';
-$labels['setvarmodifiers'] = 'Modifikator:';
-$labels['varlower'] = 'majhne črke';
-$labels['varupper'] = 'velike črke';
-$labels['varlowerfirst'] = 'prvi znak velika začetnica';
-$labels['varupperfirst'] = 'prvi znak velika začetnica';
-$labels['varquotewildcard'] = 'citiraj posebne znake';
-$labels['varlength'] = 'dolžina';
-$labels['notify'] = 'Poštlji obvestilo';
-$labels['notifyimportance'] = 'Pomembnost:';
-$labels['notifyimportancelow'] = 'nizko';
-$labels['notifyimportancenormal'] = 'običajno';
-$labels['notifyimportancehigh'] = 'visoko';
-$labels['filtercreate'] = 'Ustvari filter';
-$labels['usedata'] = 'Pri stvarjanju filtra uporabi naslednje podatke';
-$labels['nextstep'] = 'Naslednji korak';
-$labels['...'] = '...';
-$labels['currdate'] = 'Današnji datum';
-$labels['datetest'] = 'Datum';
-$labels['dateheader'] = 'glava:';
-$labels['year'] = 'leto';
-$labels['month'] = 'mesec';
-$labels['day'] = 'dan';
-$labels['date'] = 'datum(yyyy-mm-dd)';
-$labels['julian'] = 'datum (julijanski)';
-$labels['hour'] = 'ura';
-$labels['minute'] = 'minuta';
-$labels['second'] = 'sekunda';
-$labels['time'] = 'čas';
-$labels['iso8601'] = 'datum (ISO8601)';
-$labels['std11'] = 'datum (RFC2822)';
-$labels['zone'] = 'časovni pas';
-$labels['weekday'] = 'dan v tednu (0-6)';
-$labels['advancedopts'] = 'Dodatne možnosti';
-$labels['body'] = 'Vsebina';
-$labels['address'] = 'naslov';
-$labels['envelope'] = 'ovojnica';
-$labels['modifier'] = 'modifikator';
-$labels['text'] = 'besedilo';
-$labels['undecoded'] = 'neobdelano';
-$labels['contenttype'] = 'tip vsebine';
-$labels['modtype'] = 'tip';
-$labels['allparts'] = 'vse';
-$labels['domain'] = 'domena';
-$labels['localpart'] = 'lokalni del';
-$labels['user'] = 'uporabnik';
-$labels['detail'] = 'podrobnosti';
-$labels['comparator'] = 'primerjalnik';
-$labels['default'] = 'privzeto';
-$labels['octet'] = 'strict (octet)';
-$labels['asciicasemap'] = 'ni občutljiv na velike/male črke (ascii-casemap)';
-$labels['asciinumeric'] = 'numerično (ascii-numeric)';
-$labels['index'] = 'indeks:';
-$labels['indexlast'] = 'obraten vrstni red';
-$messages['filterunknownerror'] = 'Prišlo je do neznane napake.';
-$messages['filterconnerror'] = 'Povezave s strežnikom (managesieve) ni bilo mogoče vzpostaviti';
-$messages['filterdeleteerror'] = 'Pravila ni bilo mogoče izbrisati. Prišlo je do napake.';
-$messages['filterdeleted'] = 'Pravilo je bilo uspešno izbrisano.';
-$messages['filtersaved'] = 'Pravilo je bilo uspešno shranjeno';
-$messages['filtersaveerror'] = 'Pravila ni bilo mogoče shraniti. Prišlo je do napake.';
-$messages['filterdeleteconfirm'] = 'Ste prepričani, da želite izbrisati izbrano pravilo?';
-$messages['ruledeleteconfirm'] = 'Ste prepričani, da želite izbrisati izbrano pravilo?';
-$messages['actiondeleteconfirm'] = 'Ste prepričani, da želite izbrisati izbrano dejanje?';
-$messages['forbiddenchars'] = 'V polju so neveljavni znaki';
-$messages['cannotbeempty'] = 'Polje ne sme biti prazno';
-$messages['ruleexist'] = 'Filer s tem imenom že obstaja';
-$messages['setactivateerror'] = 'Izbranih filtrov ni bilo mogoče vključiti. Prišlo je do napake na strežniku.';
-$messages['setdeactivateerror'] = 'Izbranih filtrov ni bilo mogoče izključiti. Prišlo je do napake na strežniku.';
-$messages['setdeleteerror'] = 'Izbranih filtrov ni bilo mogoče izbrisati. Prišlo je do napake na strežniku.';
-$messages['setactivated'] = 'Filter je bil uspešno vključen.';
-$messages['setdeactivated'] = 'Filter je bil uspešno onemogočen.';
-$messages['setdeleted'] = 'Filter je bil uspešno izbrisan.';
-$messages['setdeleteconfirm'] = 'Ste prepričani, da želite izbrisati ta filter?';
-$messages['setcreateerror'] = 'Nabora filtrov ni bilo mogoče ustvariti. Prišlo je do napake na strežniku.';
-$messages['setcreated'] = 'Filter je bil uspešno ustvarjen.';
-$messages['activateerror'] = 'Izbranega/ih filtra/ov ni bilo mogoče vključiti. Prišlo je do napake na strežniku.';
-$messages['deactivateerror'] = 'Izbranega/ih fitra/ov ni bilo mogoče izključiti. Prišlo je do napake na strežniku.';
-$messages['deactivated'] = 'Filtri so bili uspešno omogočeni.';
-$messages['activated'] = 'Filtri so bili uspešno onemogočeni.';
-$messages['moved'] = 'Filter je bil uspešno premaknjen.';
-$messages['moveerror'] = 'Izbranega filtra ni bilo mogoče premakniti. Prišlo je do napake na strežniku.';
-$messages['nametoolong'] = 'Ime je predolgo.';
-$messages['namereserved'] = 'Rezervirano ime.';
-$messages['setexist'] = 'Nastavitev filtra že obstaja.';
-$messages['nodata'] = 'Izbrana mora biti vsaj ena nastavitev!';
-$messages['invaliddateformat'] = 'Neveljaven datum ali oblika zapisa datuma';
-?>
diff --git a/lib/plugins/managesieve/localization/sv_SE.inc b/lib/plugins/managesieve/localization/sv_SE.inc
deleted file mode 100644
index ede13cb..0000000
--- a/lib/plugins/managesieve/localization/sv_SE.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filter';
-$labels['managefilters'] = 'Administrera filter';
-$labels['filtername'] = 'Filternamn';
-$labels['newfilter'] = 'Nytt filter';
-$labels['filteradd'] = 'Nytt filter';
-$labels['filterdel'] = 'Ta bort filter';
-$labels['moveup'] = 'Flytta upp filter';
-$labels['movedown'] = 'Flytta ner filter';
-$labels['filterallof'] = 'Filtrera på alla följande regler';
-$labels['filteranyof'] = 'Filtrera på någon av följande regler';
-$labels['filterany'] = 'Filtrera alla meddelanden';
-$labels['filtercontains'] = 'innehåller';
-$labels['filternotcontains'] = 'inte innehåller';
-$labels['filteris'] = 'är lika med';
-$labels['filterisnot'] = 'är inte lika med';
-$labels['filterexists'] = 'finns';
-$labels['filternotexists'] = 'inte finns';
-$labels['filtermatches'] = 'matchar uttryck';
-$labels['filternotmatches'] = 'inte matchar uttryck';
-$labels['filterregex'] = 'matchar reguljärt uttryck';
-$labels['filternotregex'] = 'inte matchar reguljärt uttryck';
-$labels['filterunder'] = 'under';
-$labels['filterover'] = 'över';
-$labels['addrule'] = 'Lägg till regel';
-$labels['delrule'] = 'Ta bort regel';
-$labels['messagemoveto'] = 'Flytta meddelande till';
-$labels['messageredirect'] = 'Ändra mottagare till';
-$labels['messagecopyto'] = 'Kopiera meddelande till';
-$labels['messagesendcopy'] = 'Skicka kopia av meddelande till';
-$labels['messagereply'] = 'Besvara meddelande';
-$labels['messagedelete'] = 'Ta bort meddelande';
-$labels['messagediscard'] = 'Avböj med felmeddelande';
-$labels['messagekeep'] = 'Behåll meddelande i Inkorg';
-$labels['messagesrules'] = 'För inkommande meddelande';
-$labels['messagesactions'] = 'Utför följande åtgärd';
-$labels['add'] = 'Lägg till';
-$labels['del'] = 'Ta bort';
-$labels['sender'] = 'Avsändare';
-$labels['recipient'] = 'Mottagare';
-$labels['vacationaddr'] = 'Ytterligare mottagaradresser:';
-$labels['vacationdays'] = 'Antal dagar mellan auto-svar:';
-$labels['vacationinterval'] = 'Tid mellan auto-svar:';
-$labels['vacationreason'] = 'Meddelandetext (frånvaroanledning):';
-$labels['vacationsubject'] = 'Meddelandeämne:';
-$labels['days'] = 'Dagar';
-$labels['seconds'] = 'Sekunder';
-$labels['rulestop'] = 'Avsluta filtrering';
-$labels['enable'] = 'Aktivera/deaktivera';
-$labels['filterset'] = 'Filtergrupp';
-$labels['filtersets'] = 'Filtergrupper';
-$labels['filtersetadd'] = 'Ny filtergrupp';
-$labels['filtersetdel'] = 'Ta bort filtergrupp';
-$labels['filtersetact'] = 'Aktivera filtergrupp';
-$labels['filtersetdeact'] = 'Deaktivera filtergrupp';
-$labels['filterdef'] = 'Filterdefinition';
-$labels['filtersetname'] = 'Filtergruppsnamn';
-$labels['newfilterset'] = 'Ny filtergrupp';
-$labels['active'] = 'aktiv';
-$labels['none'] = 'ingen';
-$labels['fromset'] = 'från grupp';
-$labels['fromfile'] = 'från fil';
-$labels['filterdisabled'] = 'Filter deaktiverat';
-$labels['countisgreaterthan'] = 'antal är större än';
-$labels['countisgreaterthanequal'] = 'antal är större än eller lika med';
-$labels['countislessthan'] = 'antal är mindre än';
-$labels['countislessthanequal'] = 'antal är mindre än eller lika med';
-$labels['countequals'] = 'antal är lika med';
-$labels['countnotequals'] = 'antal är inte lika med';
-$labels['valueisgreaterthan'] = 'värde är större än';
-$labels['valueisgreaterthanequal'] = 'värde är större än eller lika med';
-$labels['valueislessthan'] = 'värde är mindre än';
-$labels['valueislessthanequal'] = 'värde är mindre än eller lika med';
-$labels['valueequals'] = 'värde är lika med';
-$labels['valuenotequals'] = 'värde är inte lika med';
-$labels['setflags'] = 'Flagga meddelande';
-$labels['addflags'] = 'Lägg till meddelandeflaggor';
-$labels['removeflags'] = 'Ta bort meddelandeflaggor';
-$labels['flagread'] = 'Läst';
-$labels['flagdeleted'] = 'Borttaget';
-$labels['flaganswered'] = 'Besvarat';
-$labels['flagflagged'] = 'Flaggat';
-$labels['flagdraft'] = 'Utkast';
-$labels['setvariable'] = 'Sätt variabel';
-$labels['setvarname'] = 'Variabelnamn:';
-$labels['setvarvalue'] = 'Variabelvärde:';
-$labels['setvarmodifiers'] = 'Modifierare:';
-$labels['varlower'] = 'Gemener';
-$labels['varupper'] = 'Versaler';
-$labels['varlowerfirst'] = 'Första tecken gement';
-$labels['varupperfirst'] = 'Första tecken versalt';
-$labels['varquotewildcard'] = 'Koda specialtecken';
-$labels['varlength'] = 'Längd';
-$labels['notify'] = 'Skicka avisering';
-$labels['notifytarget'] = 'Aviseringsmål:';
-$labels['notifymessage'] = 'Aviseringsmeddelande (valfritt):';
-$labels['notifyoptions'] = 'Aviseringstillval (valfritt):';
-$labels['notifyfrom'] = 'Aviseringsavsändare (valfri):';
-$labels['notifyimportance'] = 'Prioritet:';
-$labels['notifyimportancelow'] = 'LÃ¥g';
-$labels['notifyimportancenormal'] = 'Normal';
-$labels['notifyimportancehigh'] = 'Hög';
-$labels['notifymethodmailto'] = 'E-post';
-$labels['notifymethodtel'] = 'Telefon';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Skapa filter';
-$labels['usedata'] = 'Använd följande information i filtret:';
-$labels['nextstep'] = 'Nästa steg';
-$labels['...'] = '...';
-$labels['currdate'] = 'Dagens datum';
-$labels['datetest'] = 'Datum';
-$labels['dateheader'] = 'huvud:';
-$labels['year'] = 'Ã¥r';
-$labels['month'] = 'månad';
-$labels['day'] = 'dag';
-$labels['date'] = 'datum (åååå-mm-dd)';
-$labels['julian'] = 'datum (Julianskt)';
-$labels['hour'] = 'timme';
-$labels['minute'] = 'minut';
-$labels['second'] = 'sekund';
-$labels['time'] = 'tid (hh:mm:ss)';
-$labels['iso8601'] = 'datum (ISO 8601)';
-$labels['std11'] = 'datum (RFC 2822)';
-$labels['zone'] = 'tidszon';
-$labels['weekday'] = 'veckodag (0-6)';
-$labels['advancedopts'] = 'Avancerade inställningar';
-$labels['body'] = 'Meddelandeinnehåll';
-$labels['address'] = 'adress';
-$labels['envelope'] = 'kuvert';
-$labels['modifier'] = 'modifierare:';
-$labels['text'] = 'text';
-$labels['undecoded'] = 'obearbetat (rå)';
-$labels['contenttype'] = 'innehållstyp';
-$labels['modtype'] = 'typ:';
-$labels['allparts'] = 'allt';
-$labels['domain'] = 'domän';
-$labels['localpart'] = 'lokal del';
-$labels['user'] = 'användare';
-$labels['detail'] = 'detalj';
-$labels['comparator'] = 'jämförelse:';
-$labels['default'] = 'standard';
-$labels['octet'] = 'strikt (oktalt)';
-$labels['asciicasemap'] = 'teckenlägesokänslig (ascii-casemap)';
-$labels['asciinumeric'] = 'numerisk (ascii-numeric)';
-$labels['index'] = 'index:';
-$labels['indexlast'] = 'omvänd';
-$labels['vacation'] = 'Frånvaro';
-$labels['vacation.reply'] = 'Besvara meddelande';
-$labels['vacation.advanced'] = 'Avancerade inställningar';
-$labels['vacation.subject'] = 'Ämne';
-$labels['vacation.body'] = 'Innehåll';
-$labels['vacation.start'] = 'Frånvaron börjar';
-$labels['vacation.end'] = 'Frånvaron slutar';
-$labels['vacation.status'] = 'Status';
-$labels['vacation.on'] = 'PÃ¥';
-$labels['vacation.off'] = 'Av';
-$labels['vacation.addresses'] = 'Ytterligare mottagaradresser';
-$labels['vacation.interval'] = 'Svarsintervall';
-$labels['vacation.after'] = 'Placera frånvaroregel efter';
-$labels['vacation.saving'] = 'Sparar data...';
-$labels['vacation.action'] = 'Hantering av inkommande meddelanden';
-$labels['vacation.keep'] = 'Behåll';
-$labels['vacation.discard'] = 'Förkasta';
-$labels['vacation.redirect'] = 'Ändra mottagare till';
-$labels['vacation.copy'] = 'Skicka kopia till';
-$labels['arialabelfiltersetactions'] = 'Hantera filtergrupper';
-$labels['arialabelfilteractions'] = 'Hantera filter';
-$labels['arialabelfilterform'] = 'Filteregenskaper';
-$labels['ariasummaryfilterslist'] = 'Lista med filter';
-$labels['ariasummaryfiltersetslist'] = 'Lista med filtergrupper';
-$labels['filterstitle'] = 'Ändra filter för inkommande meddelanden';
-$labels['vacationtitle'] = 'Ändra regel för frånvaromeddelande';
-$messages['filterunknownerror'] = 'Okänt serverfel';
-$messages['filterconnerror'] = 'Anslutning till serverns filtertjänst misslyckades';
-$messages['filterdeleteerror'] = 'Filtret kunde inte tas bort på grund av serverfel';
-$messages['filterdeleted'] = 'Filtret är borttaget';
-$messages['filtersaved'] = 'Filtret har sparats';
-$messages['filtersaveerror'] = 'Filtret kunde inte sparas på grund av serverfel';
-$messages['filterdeleteconfirm'] = 'Vill du ta bort det markerade filtret?';
-$messages['ruledeleteconfirm'] = 'Vill du ta bort filterregeln?';
-$messages['actiondeleteconfirm'] = 'Vill du ta bort filteråtgärden?';
-$messages['forbiddenchars'] = 'Otillåtet tecken i fältet';
-$messages['cannotbeempty'] = 'Fältet kan inte lämnas tomt';
-$messages['ruleexist'] = 'Ett filter med angivet namn finns redan.';
-$messages['setactivateerror'] = 'Filtergruppen kunde inte aktiveras på grund av serverfel';
-$messages['setdeactivateerror'] = 'Filtergruppen kunde inte deaktiveras på grund av serverfel';
-$messages['setdeleteerror'] = 'Filtergruppen kunde inte tas bort på grund av serverfel';
-$messages['setactivated'] = 'Filtergruppen är aktiverad';
-$messages['setdeactivated'] = 'Filtergruppen är deaktiverad';
-$messages['setdeleted'] = 'Filtergruppen är borttagen';
-$messages['setdeleteconfirm'] = 'Vill du ta bort filtergruppen?';
-$messages['setcreateerror'] = 'Filtergruppen kunde inte läggas till på grund av serverfel';
-$messages['setcreated'] = 'Filtergruppen har lagts till';
-$messages['activateerror'] = 'Kunde inte aktivera filter på grund av serverfel.';
-$messages['deactivateerror'] = 'Kunde inte deaktivera filter på grund av serverfel.';
-$messages['deactivated'] = 'Filter aktiverat.';
-$messages['activated'] = 'Filter deaktiverat.';
-$messages['moved'] = 'Filter flyttat.';
-$messages['moveerror'] = 'Kunde inte flytta filter på grund av serverfel.';
-$messages['nametoolong'] = 'För långt namn.';
-$messages['namereserved'] = 'Reserverat namn.';
-$messages['setexist'] = 'Filtergrupp finns redan.';
-$messages['nodata'] = 'Minst en position måste väljas!';
-$messages['invaliddateformat'] = 'Ogiltigt datum eller del av datumformat';
-$messages['saveerror'] = 'Datan kunde inte sparas på grund av serverfel.';
-$messages['vacationsaved'] = 'Frånvarodatan har sparats.';
-$messages['emptyvacationbody'] = 'Text för frånvaromeddelande saknas!';
-?>
diff --git a/lib/plugins/managesieve/localization/th_TH.inc b/lib/plugins/managesieve/localization/th_TH.inc
deleted file mode 100644
index c2d041c..0000000
--- a/lib/plugins/managesieve/localization/th_TH.inc
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'ตัวกรองข้อมูล';
-$labels['filtername'] = 'ชื่อตัวกรองข้อมูล';
-$labels['newfilter'] = 'สร้างตัวกรองข้อมูลใหม่';
-$labels['filteradd'] = 'เพิ่มตัวกรองข้อมูล';
-$labels['filterdel'] = 'ลบตัวกรองข้อมูล';
-$labels['moveup'] = 'เลื่อนขึ้น';
-$labels['movedown'] = 'เลื่อนลง';
-$labels['filterany'] = 'ข้อความทั้งหมด';
-$labels['filtercontains'] = 'ที่มีคำว่า';
-$labels['filternotcontains'] = 'ไม่มีคำว่า';
-$labels['filteris'] = 'ที่มีค่าเท่ากับ';
-$labels['filterisnot'] = 'ที่มีค่าไม่เท่ากับ';
-$labels['addrule'] = 'เพิ่มกฏ';
-$labels['delrule'] = 'ลบกฏ';
-$labels['messagemoveto'] = 'ย้ายข้อความไปที่';
-$labels['messageredirect'] = 'เปลียนเส้นทางข้อความไปที่';
-$labels['messagecopyto'] = 'คัดลอกข้อความไปที่';
-$labels['messagesendcopy'] = 'ส่งข้อความคัดลอกไปที่';
-$labels['messagedelete'] = 'ลบข้อความ';
-$labels['messagediscard'] = 'ยกเลิกข้อความ';
-$labels['messagesrules'] = 'สำหรับอีเมลขาเข้า:';
-$labels['add'] = 'เพิ่ม';
-$labels['del'] = 'ลบ';
-$labels['sender'] = 'ผู้ส่ง';
-$labels['recipient'] = 'ผู้รับ';
-$labels['vacationsubject'] = 'หัวเรื่องข้อความ:';
-$labels['enable'] = 'เปิดใช้งาน/ปิดใช้งาน';
-?>
diff --git a/lib/plugins/managesieve/localization/tr_TR.inc b/lib/plugins/managesieve/localization/tr_TR.inc
deleted file mode 100644
index c618386..0000000
--- a/lib/plugins/managesieve/localization/tr_TR.inc
+++ /dev/null
@@ -1,224 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Filtreler';
-$labels['managefilters'] = 'Gelen e-posta filtrelerini yönet';
-$labels['filtername'] = 'Filtre adı';
-$labels['newfilter'] = 'Yeni filtre';
-$labels['filteradd'] = 'Filtre ekle';
-$labels['filterdel'] = 'Filtre Sil';
-$labels['moveup'] = 'Yukarı taşı';
-$labels['movedown'] = 'Aşağı taşı';
-$labels['filterallof'] = 'Aşağıdaki kuralların hepsine uyan';
-$labels['filteranyof'] = 'Aşağıdaki kuralların herhangi birine uyan';
-$labels['filterany'] = 'Tüm mesajlar';
-$labels['filtercontains'] = 'içeren';
-$labels['filternotcontains'] = 'içermeyen';
-$labels['filteris'] = 'eşittir';
-$labels['filterisnot'] = 'eşit değildir';
-$labels['filterexists'] = 'mevcut';
-$labels['filternotexists'] = 'mevcut değil';
-$labels['filtermatches'] = 'ifadeye uyan';
-$labels['filternotmatches'] = 'ifadeye uymayan';
-$labels['filterregex'] = 'düzenli ifadeye uyan';
-$labels['filternotregex'] = 'düzenli ifadeye uymayan';
-$labels['filterunder'] = 'altında';
-$labels['filterover'] = 'üzerinde';
-$labels['addrule'] = 'Kural ekle';
-$labels['delrule'] = 'Kuralı sil';
-$labels['messagemoveto'] = 'mesajı taşı';
-$labels['messageredirect'] = 'mesajı yönlendir';
-$labels['messagecopyto'] = 'Mesajı kopyala';
-$labels['messagesendcopy'] = 'mesajın kopyasını gönder';
-$labels['messagereply'] = 'mesajla birlikte cevap ver';
-$labels['messagedelete'] = 'Mesajı sil';
-$labels['messagediscard'] = 'mesajı yok say';
-$labels['messagekeep'] = 'Mesajı Gelen Kutusunda tut.';
-$labels['messagesrules'] = 'Gelen e-postalar için:';
-$labels['messagesactions'] = '... aşağıdaki aksiyonları çalıştır:';
-$labels['add'] = 'Ekle';
-$labels['del'] = 'Sil';
-$labels['sender'] = 'Gönderici';
-$labels['recipient'] = 'Alıcı';
-$labels['vacationaddr'] = 'Ek e-posta adres(ler)im:';
-$labels['vacationdays'] = 'Ne sıklıkla mesajlar gönderilir(gün)';
-$labels['vacationinterval'] = 'Ne kadar sıklıkla mesaj gönderirsiniz:';
-$labels['vacationreason'] = 'Mesaj gövdesi(tatil sebebi):';
-$labels['vacationsubject'] = 'Mesaj konusu:';
-$labels['days'] = 'günler';
-$labels['seconds'] = 'saniyeler';
-$labels['rulestop'] = 'Kuralları değerlendirmeyi bitir';
-$labels['enable'] = 'Etkinleştir/Etkisiz Kıl';
-$labels['filterset'] = 'Filtre seti';
-$labels['filtersets'] = 'Filtre setleri';
-$labels['filtersetadd'] = 'Filtre seti ekle';
-$labels['filtersetdel'] = 'Mevcut filtre setini sil';
-$labels['filtersetact'] = 'Mevcut filtre setini etkinleştir';
-$labels['filtersetdeact'] = 'Mevcut filtre setini etkinsizleştir';
-$labels['filterdef'] = 'Filtre tanımı';
-$labels['filtersetname'] = 'Filtre seti adı';
-$labels['newfilterset'] = 'Yeni filtre seti';
-$labels['active'] = 'etkin';
-$labels['none'] = 'hiçbiri';
-$labels['fromset'] = 'gönderici seti';
-$labels['fromfile'] = 'gönderici dosya';
-$labels['filterdisabled'] = 'Filtre iptal edildi';
-$labels['countisgreaterthan'] = 'toplamı büyük';
-$labels['countisgreaterthanequal'] = 'toplamı büyük veya eşit';
-$labels['countislessthan'] = 'toplamı az';
-$labels['countislessthanequal'] = 'toplamı daha az veya eşit';
-$labels['countequals'] = 'toplamı eşit';
-$labels['countnotequals'] = 'toplamı eşit değil';
-$labels['valueisgreaterthan'] = 'değeri büyük';
-$labels['valueisgreaterthanequal'] = 'değeri büyük veya eşit';
-$labels['valueislessthan'] = 'değer az';
-$labels['valueislessthanequal'] = 'değer daha az veya eşit';
-$labels['valueequals'] = 'değer eşit';
-$labels['valuenotequals'] = 'değer eşit değil';
-$labels['setflags'] = 'bayrakları mesaja set et';
-$labels['addflags'] = 'Bayrakları mesaja ekle';
-$labels['removeflags'] = 'Bayrakları mesajdan sil';
-$labels['flagread'] = 'Oku';
-$labels['flagdeleted'] = 'Silindi';
-$labels['flaganswered'] = 'Cevaplanmış';
-$labels['flagflagged'] = 'İşaretli';
-$labels['flagdraft'] = 'Taslak';
-$labels['setvariable'] = 'Değişken tanımla';
-$labels['setvarname'] = 'Değişken adı:';
-$labels['setvarvalue'] = 'Değişken değeri:';
-$labels['setvarmodifiers'] = 'Değiştiriciler:';
-$labels['varlower'] = 'küçük harf';
-$labels['varupper'] = 'büyük harf';
-$labels['varlowerfirst'] = 'İlk karakter küçük harf';
-$labels['varupperfirst'] = 'İlk karakter büyük harf';
-$labels['varquotewildcard'] = 'özel karakterleri tırnak içine al';
-$labels['varlength'] = 'uzunluk';
-$labels['notify'] = 'Bildirim gönder';
-$labels['notifytarget'] = 'Bildirim hedefi:';
-$labels['notifymessage'] = 'Bildirim mesajı (tercihe bağlı):';
-$labels['notifyoptions'] = 'Bildirim tercihleri (tercihe bağlı):';
-$labels['notifyfrom'] = 'Bildirim göndericisi (tercihe bağlı):';
-$labels['notifyimportance'] = 'Önem derecesi:';
-$labels['notifyimportancelow'] = 'düşük';
-$labels['notifyimportancenormal'] = 'normal';
-$labels['notifyimportancehigh'] = 'yüksek';
-$labels['notifymethodmailto'] = 'E-posta';
-$labels['notifymethodtel'] = 'Telefon';
-$labels['notifymethodsms'] = 'SMS';
-$labels['filtercreate'] = 'Süzgeç oluştur';
-$labels['usedata'] = 'Aşağıdaki verileri süzgeçte kullan';
-$labels['nextstep'] = 'Sonraki adım';
-$labels['...'] = '...';
-$labels['currdate'] = 'Mevcut tarih';
-$labels['datetest'] = 'Tarih';
-$labels['dateheader'] = 'Başlık';
-$labels['year'] = 'yıl';
-$labels['month'] = 'ay';
-$labels['day'] = 'gün';
-$labels['date'] = 'tarih (yyyy-aa-gg)';
-$labels['julian'] = 'tarih (julian)';
-$labels['hour'] = 'saat';
-$labels['minute'] = 'dakika';
-$labels['second'] = 'saniye';
-$labels['time'] = 'saat (ss:dd:ss)';
-$labels['iso8601'] = 'tarih (ISO8601)';
-$labels['std11'] = 'tarih (RFC2822)';
-$labels['zone'] = 'saat-dilimi';
-$labels['weekday'] = 'Hafta günleri (0-6)';
-$labels['advancedopts'] = 'Gelişmiş seçenekler';
-$labels['body'] = 'Gövde';
-$labels['address'] = 'adres';
-$labels['envelope'] = 'zarf';
-$labels['modifier'] = 'değiştirici';
-$labels['text'] = 'metin';
-$labels['undecoded'] = 'çözülmemiş(ham)';
-$labels['contenttype'] = 'içerik türü';
-$labels['modtype'] = 'tip:';
-$labels['allparts'] = 'hepsi';
-$labels['domain'] = 'alan adı';
-$labels['localpart'] = 'yerel parça';
-$labels['user'] = 'kullanıcı';
-$labels['detail'] = 'detay';
-$labels['comparator'] = 'karşılaştırıcı';
-$labels['default'] = 'öntanımlı';
-$labels['octet'] = 'sıkı(oktet)';
-$labels['asciicasemap'] = 'büyük küçük harf duyarsız(ascii-casemap)';
-$labels['asciinumeric'] = 'sayı (ascii-numeric)';
-$labels['index'] = 'indeks:';
-$labels['indexlast'] = 'geriye yönelik';
-$labels['vacation'] = 'Tatil';
-$labels['vacation.reply'] = 'Cevap mesajı';
-$labels['vacation.advanced'] = 'Gelişmiş seçenekler';
-$labels['vacation.subject'] = 'Konu';
-$labels['vacation.body'] = 'Gövde';
-$labels['vacation.start'] = 'Tatil başlangıcı';
-$labels['vacation.end'] = 'Tatil bitişi';
-$labels['vacation.status'] = 'Durum';
-$labels['vacation.on'] = 'Etkin';
-$labels['vacation.off'] = 'Devre dışı';
-$labels['vacation.addresses'] = 'Ek adresler';
-$labels['vacation.interval'] = 'Cevap aralığı';
-$labels['vacation.after'] = 'Şundan sonra tatil kuralı koy';
-$labels['vacation.saving'] = 'Veri kaydediliyor...';
-$labels['vacation.action'] = 'Gelen mesaj aksiyonu';
-$labels['vacation.keep'] = 'Koru';
-$labels['vacation.discard'] = 'Yoksay';
-$labels['vacation.redirect'] = 'Şuraya yönlendir';
-$labels['vacation.copy'] = 'Şuraya kopya gönder';
-$labels['arialabelfiltersetactions'] = 'Filtre seti aksiyonları';
-$labels['arialabelfilteractions'] = 'Filtre aksiyonları';
-$labels['arialabelfilterform'] = 'Filtre özellikleri';
-$labels['ariasummaryfilterslist'] = 'Filtre listesi';
-$labels['ariasummaryfiltersetslist'] = 'Filtre seti listesi';
-$labels['filterstitle'] = 'Gelen e-posta filtrelerini düzenle';
-$labels['vacationtitle'] = 'Ofis dışında kuralını düzenle';
-$messages['filterunknownerror'] = 'Bilinmeyen sunucu hatası.';
-$messages['filterconnerror'] = 'Sunucuya bağlanamıyor.';
-$messages['filterdeleteerror'] = 'Filtre silinemedi. Sunucuda hata oluştu.';
-$messages['filterdeleted'] = 'Filtre başarıyla silindi.';
-$messages['filtersaved'] = 'Filtre başarıyla kaydedildi.';
-$messages['filtersaveerror'] = 'Filtre kaydedilemedi. Sunucuda hata oluştu.';
-$messages['filterdeleteconfirm'] = 'Seçilen filtreleri gerçekten silmek istiyor musun?';
-$messages['ruledeleteconfirm'] = 'Seçili kuralları silmek istediğinizden emin misiniz?';
-$messages['actiondeleteconfirm'] = 'Seçili aksiyonları silmek istediğinizden emin misiniz?';
-$messages['forbiddenchars'] = 'Alanda izin verilmeyen karakterler var.';
-$messages['cannotbeempty'] = 'Alan boş olmaz';
-$messages['ruleexist'] = 'Belirtilen isimde bir filtre zaten var.';
-$messages['setactivateerror'] = 'Seçilen filtreler etkinleştirilemedi. Sunucuda hata oluştu.';
-$messages['setdeactivateerror'] = 'Seçilen filtreler pasifleştirilemedi. Sunucuda hata oluştu.';
-$messages['setdeleteerror'] = 'Seçilen filtreler silinemedi. Sunucuda hata oluştu.';
-$messages['setactivated'] = 'Filtreler başarıyla etkinleştirilemedi.';
-$messages['setdeactivated'] = 'Filtreler başarıyla pasifleştirildi.';
-$messages['setdeleted'] = 'Filtre seti başarıyla silindi.';
-$messages['setdeleteconfirm'] = 'Seçilen filtre setlerini silmek istediğinizden emin misiniz?';
-$messages['setcreateerror'] = 'Filtre setleri oluşturulamadı. Sunucuda hata oluştu.';
-$messages['setcreated'] = 'Filtre setleri başarıyla oluşturuldu.';
-$messages['activateerror'] = 'Seçilen filtre(ler) etkinleştirilemedi. Sunucuda hata oluştu.';
-$messages['deactivateerror'] = 'Seçilen filtre(ler) pasifleştirilemedi. Sunucuda hata oluştu.';
-$messages['deactivated'] = 'Filtre(ler) başarıyla etkinleştirildi.';
-$messages['activated'] = 'Filtre(ler) başarıyla iptal edildi.';
-$messages['moved'] = 'Filtre başarıyla taşındı.';
-$messages['moveerror'] = 'Seçilen filtre taşınamadı. Sunucuda hata oluştu.';
-$messages['nametoolong'] = 'İsim çok uzun.';
-$messages['namereserved'] = 'rezerve edilmiş isim.';
-$messages['setexist'] = 'Set zaten var.';
-$messages['nodata'] = 'En az bir pozisyon seçilmelidir.';
-$messages['invaliddateformat'] = 'geçersiz tarih veya tarih biçimi';
-$messages['saveerror'] = 'Veri kaydedilemedi. Sunucuda hata oluştu.';
-$messages['vacationsaved'] = 'Tatil verisi başarıyla kaydedildi.';
-$messages['emptyvacationbody'] = 'Tatil mesajı metni gerekmektedir.';
-?>
diff --git a/lib/plugins/managesieve/localization/uk_UA.inc b/lib/plugins/managesieve/localization/uk_UA.inc
deleted file mode 100644
index fce7867..0000000
--- a/lib/plugins/managesieve/localization/uk_UA.inc
+++ /dev/null
@@ -1,140 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Фільтри';
-$labels['managefilters'] = 'Керування фільтрами вхідної пошти';
-$labels['filtername'] = 'Назва фільтру';
-$labels['newfilter'] = 'Новий фільтр';
-$labels['filteradd'] = 'Додати фільтр';
-$labels['filterdel'] = 'Видалити фільтр';
-$labels['moveup'] = 'Пересунути вгору';
-$labels['movedown'] = 'Пересунути вниз';
-$labels['filterallof'] = 'задовольняє усім наступним умовам';
-$labels['filteranyof'] = 'задовольняє будь-якій з умов';
-$labels['filterany'] = 'всі повідомлення';
-$labels['filtercontains'] = 'містить';
-$labels['filternotcontains'] = 'не містить';
-$labels['filteris'] = 'ідентичний до';
-$labels['filterisnot'] = 'не ідентичний до';
-$labels['filterexists'] = 'існує';
-$labels['filternotexists'] = 'не існує';
-$labels['filterunder'] = 'менше, ніж';
-$labels['filterover'] = 'більше, ніж';
-$labels['addrule'] = 'Додати правило';
-$labels['delrule'] = 'Видалити правило';
-$labels['messagemoveto'] = 'Пересунути повідомлення до';
-$labels['messageredirect'] = 'Перенаправити повідомлення до';
-$labels['messagecopyto'] = 'Копіювати листа до';
-$labels['messagesendcopy'] = 'Надсилати копію листа на';
-$labels['messagereply'] = 'Автовідповідач';
-$labels['messagedelete'] = 'Видалити повідомлення';
-$labels['messagediscard'] = 'Відхилити з повідомленням';
-$labels['messagekeep'] = 'Залишити лист у Вхідних';
-$labels['messagesrules'] = 'Для вхідної пошти';
-$labels['messagesactions'] = '... виконати дію:';
-$labels['add'] = 'Додати';
-$labels['del'] = 'Видалити';
-$labels['sender'] = 'Відправник';
-$labels['recipient'] = 'Отримувач';
-$labels['vacationaddr'] = 'Додаткова адреса(и):';
-$labels['vacationdays'] = 'Як часто повторювати (у днях):';
-$labels['vacationreason'] = 'Текст повідомлення:';
-$labels['vacationsubject'] = 'Тема листа:';
-$labels['days'] = 'днів';
-$labels['seconds'] = 'секунд';
-$labels['rulestop'] = 'Зупинити перевірку правил';
-$labels['enable'] = 'Увімкнути/Вимкнуни';
-$labels['filterset'] = 'Набір фільтрів';
-$labels['filtersetadd'] = 'Додати набір фільтрів';
-$labels['filtersetdel'] = 'Видалити поточний набір';
-$labels['filtersetact'] = 'Активувати поточний набір';
-$labels['filterdef'] = 'Параметри фільтру';
-$labels['filtersetname'] = 'Назва набору фільтрів';
-$labels['newfilterset'] = 'Новий набір фільтрів';
-$labels['active'] = 'активний';
-$labels['none'] = 'нічого';
-$labels['fromset'] = 'з набору';
-$labels['fromfile'] = 'з файлу';
-$labels['filterdisabled'] = 'Фільтр вимкнено';
-$labels['countisgreaterthan'] = 'лічильник більший за';
-$labels['countisgreaterthanequal'] = 'лічильник більший або рівний ';
-$labels['countislessthan'] = 'лічильник менший';
-$labels['countislessthanequal'] = 'льчильник менший або рівний';
-$labels['countequals'] = 'лічильник рівний';
-$labels['countnotequals'] = 'лічильник рівний';
-$labels['valueisgreaterthan'] = 'значення більше за';
-$labels['valueisgreaterthanequal'] = 'значення більше або рівне';
-$labels['valueislessthan'] = 'значення менше за';
-$labels['valueislessthanequal'] = 'значення менше або рівне';
-$labels['valueequals'] = 'значення рівне';
-$labels['valuenotequals'] = 'значення не рівне';
-$labels['flagdraft'] = 'Чернетка';
-$labels['setvariable'] = 'Встановити змінну';
-$labels['setvarname'] = 'Назва змінної:';
-$labels['setvarvalue'] = 'Значення змінної:';
-$labels['setvarmodifiers'] = 'Модифікатори:';
-$labels['varlower'] = 'нижній регістр';
-$labels['varupper'] = 'верхній регістр';
-$labels['varlowerfirst'] = 'перший символ в нижньому регістрі';
-$labels['varupperfirst'] = 'перший символ в верхньому регістрі';
-$labels['varlength'] = 'довжина';
-$labels['notify'] = 'Надсилати сповіщення';
-$labels['filtercreate'] = 'Створити фільтр';
-$labels['nextstep'] = 'Наступний крок';
-$labels['...'] = '...';
-$labels['currdate'] = 'Поточна дата';
-$labels['datetest'] = 'Дата';
-$labels['dateheader'] = 'шапка:';
-$labels['year'] = 'рік';
-$labels['month'] = 'місяць';
-$labels['day'] = 'день';
-$labels['date'] = 'дата (рррр-мм-дд)';
-$labels['hour'] = 'година';
-$labels['minute'] = 'хвилина';
-$labels['second'] = 'секунда';
-$labels['time'] = 'час (гг:хх:сс)';
-$labels['iso8601'] = 'дата (ISO8601)';
-$labels['std11'] = 'дата (RFC2822)';
-$labels['zone'] = 'часовий пояс';
-$labels['advancedopts'] = 'Розширені параметри';
-$labels['body'] = 'Тіло';
-$labels['address'] = 'адреса';
-$labels['text'] = 'текст';
-$labels['modtype'] = 'тип:';
-$labels['allparts'] = 'все';
-$labels['domain'] = 'домен';
-$labels['localpart'] = 'локальна частина';
-$labels['user'] = 'користувач';
-$labels['detail'] = 'деталь';
-$labels['default'] = 'типово';
-$labels['index'] = 'індекс:';
-$messages['filterunknownerror'] = 'Невідома помилка сервера';
-$messages['filterconnerror'] = 'Неможливо з\'єднатися з сервером';
-$messages['filterdeleted'] = 'Фільтр успішно видалено';
-$messages['filtersaved'] = 'Фільтр успішно збережено';
-$messages['filterdeleteconfirm'] = 'Ви дійсно хочете видалити обраний фільтр?';
-$messages['ruledeleteconfirm'] = 'Ви дійсно хочете видалити обране правило?';
-$messages['actiondeleteconfirm'] = 'Ви дійсно хочете видалити обрану дію?';
-$messages['forbiddenchars'] = 'Введено заборонений символ';
-$messages['cannotbeempty'] = 'Поле не може бути пустим';
-$messages['setactivated'] = 'Набір фільтрів активовано успішно';
-$messages['setdeleted'] = 'Набір фільтрів видалено успішно';
-$messages['setdeleteconfirm'] = 'Ви впевнені, що хочете видалити обраний набір?';
-$messages['setcreated'] = 'Набір фільтрів створено успішно';
-$messages['moveerror'] = 'Неможливо перемістити обраний фільтр. Помилка сервера.';
-$messages['nametoolong'] = 'Не вдалося створити набір. Занадто довга назва';
-?>
diff --git a/lib/plugins/managesieve/localization/vi_VN.inc b/lib/plugins/managesieve/localization/vi_VN.inc
deleted file mode 100644
index d22ff7e..0000000
--- a/lib/plugins/managesieve/localization/vi_VN.inc
+++ /dev/null
@@ -1,209 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = 'Bộ lọc';
-$labels['managefilters'] = 'Quản lý bộ lọc thư đến';
-$labels['filtername'] = 'Lọc tên';
-$labels['newfilter'] = 'Bộ lọc mới';
-$labels['filteradd'] = 'Thêm bộ lọc';
-$labels['filterdel'] = 'Xóa bộ lọc';
-$labels['moveup'] = 'Chuyển lên';
-$labels['movedown'] = 'Chuyển xuống';
-$labels['filterallof'] = 'Phù hợp với tất cả các qui luật sau đây';
-$labels['filteranyof'] = 'Phù hợp với bất kỳ qui luật nào sau đây';
-$labels['filterany'] = 'Tất cả tin nhắn';
-$labels['filtercontains'] = 'Bao gồm';
-$labels['filternotcontains'] = 'Không bao gồm';
-$labels['filteris'] = 'Bằng với';
-$labels['filterisnot'] = 'Không bằng với';
-$labels['filterexists'] = 'Tồn tại';
-$labels['filternotexists'] = 'Không tồn tại';
-$labels['filtermatches'] = 'Tương ứng với cách diễn đạt';
-$labels['filternotmatches'] = 'Không tương ứng với cách diễn đạt';
-$labels['filterregex'] = 'Tương ứng với cách diễn đạt thông thường';
-$labels['filternotregex'] = 'Không phù hợp với cách diễn đạt thông thường';
-$labels['filterunder'] = 'Dưới';
-$labels['filterover'] = 'HÆ¡n';
-$labels['addrule'] = 'Thêm qui luật';
-$labels['delrule'] = 'Xóa qui luật';
-$labels['messagemoveto'] = 'Chuyển tin nhắn tới';
-$labels['messageredirect'] = 'Gửi lại tin nhắn tới';
-$labels['messagecopyto'] = 'Sao chép tin nhắn tới';
-$labels['messagesendcopy'] = 'Gửi bản sao chép tin nhắn tới';
-$labels['messagereply'] = 'Trả lời tin nhắn';
-$labels['messagedelete'] = 'Xóa thư';
-$labels['messagediscard'] = 'Loại bỏ với tin nhắn';
-$labels['messagekeep'] = 'Giữ thư ở Hộp thư chính';
-$labels['messagesrules'] = 'Với thư đến';
-$labels['messagesactions'] = 'Thực hiện các hành động sau:';
-$labels['add'] = 'Thêm';
-$labels['del'] = 'Xoá';
-$labels['sender'] = 'Người gửi';
-$labels['recipient'] = 'Người nhận';
-$labels['vacationaddr'] = '(Các) Địa chỉ email bổ sung của tôi:';
-$labels['vacationdays'] = 'Số lần gửi thư (trong ngày)';
-$labels['vacationinterval'] = 'Tần suất gửi thư:';
-$labels['vacationreason'] = 'Nội dung chính';
-$labels['vacationsubject'] = 'Tiêu đề thư';
-$labels['days'] = 'ngày';
-$labels['seconds'] = 'giây';
-$labels['rulestop'] = 'Ngừng đánh giá qui luật';
-$labels['enable'] = 'Kích hoạt/Không kích hoạt';
-$labels['filterset'] = 'Đặt các bộ lọc';
-$labels['filtersets'] = 'Thiết lập bộ lọc';
-$labels['filtersetadd'] = 'Thêm bộ lọc';
-$labels['filtersetdel'] = 'Xóa bộ lọc hiện tại';
-$labels['filtersetact'] = 'Kích hoạt bộ lọc hiện tại';
-$labels['filtersetdeact'] = 'Ngừng kích hoạt bộ lọc hiện tai';
-$labels['filterdef'] = 'Định nghĩa bộ lọc';
-$labels['filtersetname'] = 'Tên bộ lọc';
-$labels['newfilterset'] = 'Thiết lập bộ lọc mới';
-$labels['active'] = 'Kích hoạt';
-$labels['none'] = 'Không có';
-$labels['fromset'] = 'Từ thiết lập';
-$labels['fromfile'] = 'Từ hồ sơ';
-$labels['filterdisabled'] = 'Bộ lọc được ngừng hoạt động';
-$labels['countisgreaterthan'] = 'Đếm lớn hơn';
-$labels['countisgreaterthanequal'] = 'Đếm lớn hơn hoặc bằng';
-$labels['countislessthan'] = 'Đếm ít hơn';
-$labels['countislessthanequal'] = 'Đếm ít hơn hoặc bằng';
-$labels['countequals'] = 'Đếm bằng';
-$labels['countnotequals'] = 'đếm không bằng với';
-$labels['valueisgreaterthan'] = 'Giá trị lớn hơn';
-$labels['valueisgreaterthanequal'] = 'Giá trị lớn hơn hoặc bằng';
-$labels['valueislessthan'] = 'Giá trị nhỏ hơn';
-$labels['valueislessthanequal'] = 'Giá trị nhỏ hơn hoặc bằng';
-$labels['valueequals'] = 'Giá trị bằng';
-$labels['valuenotequals'] = 'giá trị không bằng với';
-$labels['setflags'] = 'Thiết lập đánh dấu cho thư';
-$labels['addflags'] = 'Thêm đánh dấu cho thư';
-$labels['removeflags'] = 'Bỏ đánh dấu khỏi thư';
-$labels['flagread'] = 'Đọc';
-$labels['flagdeleted'] = 'Đã được xóa';
-$labels['flaganswered'] = 'Đã trả lời';
-$labels['flagflagged'] = 'Đã đánh dấu';
-$labels['flagdraft'] = 'Nháp';
-$labels['setvariable'] = 'Đặt biến';
-$labels['setvarname'] = 'Tên biến:';
-$labels['setvarvalue'] = 'Giá trị biến:';
-$labels['setvarmodifiers'] = 'Bộ chia:';
-$labels['varlower'] = 'viết thường';
-$labels['varupper'] = 'viết hoa';
-$labels['varlowerfirst'] = 'chữ cái đầu viết thường';
-$labels['varupperfirst'] = 'chữ cái đầu viết hoa';
-$labels['varquotewildcard'] = 'trích dẫn ký tự đặc biệt';
-$labels['varlength'] = 'độ dài';
-$labels['notify'] = 'Gửi thông báo';
-$labels['notifytarget'] = 'Mục tiêu thông báo:';
-$labels['notifymessage'] = 'Nội dung thông báo (tuỳ chọn):';
-$labels['notifyoptions'] = 'Lựa chọn thông báo (tuỳ chọn):';
-$labels['notifyfrom'] = 'Người gửi thông báo (tuỳ chọn):';
-$labels['notifyimportance'] = 'Mức độ quan trọng:';
-$labels['notifyimportancelow'] = 'thấp';
-$labels['notifyimportancenormal'] = 'vừa phải';
-$labels['notifyimportancehigh'] = 'cao';
-$labels['notifymethodmailto'] = 'Thư điện tử';
-$labels['notifymethodtel'] = 'Điện thoại';
-$labels['notifymethodsms'] = 'Tin nhắn';
-$labels['filtercreate'] = 'Tạo bộ lọc';
-$labels['usedata'] = 'Dùng dữ liệu trong bộ lọc sau:';
-$labels['nextstep'] = 'Bước tiếp theo';
-$labels['...'] = '…';
-$labels['currdate'] = 'Ngày hiện tại';
-$labels['datetest'] = 'Ngày';
-$labels['dateheader'] = 'tiêu đề:';
-$labels['year'] = 'năm';
-$labels['month'] = 'tháng';
-$labels['day'] = 'ngày';
-$labels['date'] = 'ngày (cú pháp: năm-tháng-ngày)';
-$labels['julian'] = 'ngày (theo kiểu Julian)';
-$labels['hour'] = 'giờ';
-$labels['minute'] = 'phút';
-$labels['second'] = 'giây';
-$labels['time'] = 'giờ (cú pháp: giờ:phút:giây)';
-$labels['iso8601'] = 'ngày (theo chuẩn ISO 8601)';
-$labels['std11'] = 'ngày (theo chuẩn RFC 2822)';
-$labels['zone'] = 'vùng thời gian';
-$labels['weekday'] = 'ngày trog tuần (0-6)';
-$labels['advancedopts'] = 'Tùy chọn tính năng cao hơn';
-$labels['body'] = 'Nội dung';
-$labels['address'] = 'Địa chỉ';
-$labels['envelope'] = 'Phong bì';
-$labels['modifier'] = 'Bổ nghĩa';
-$labels['text'] = 'Văn bản';
-$labels['undecoded'] = 'Chưa được giải mã (nguyên bản)';
-$labels['contenttype'] = 'Kiểu mẫu nội dung';
-$labels['modtype'] = 'Kiểu:';
-$labels['allparts'] = 'Tất cả';
-$labels['domain'] = 'Phạm vi';
-$labels['localpart'] = 'Phần nội bộ';
-$labels['user'] = 'Người dùng';
-$labels['detail'] = 'Chi tiết';
-$labels['comparator'] = 'Vật so sánh';
-$labels['default'] = 'Mặc định';
-$labels['octet'] = 'Khắt khe';
-$labels['asciicasemap'] = 'Không phân biệt chữ hoa chữ thường';
-$labels['asciinumeric'] = 'Bảng mã ASCII';
-$labels['index'] = 'chỉ mục:';
-$labels['indexlast'] = 'ngược';
-$labels['vacation'] = 'Thiết lập tự động trả lời trong kỳ nghỉ';
-$labels['vacation.reply'] = 'Trả lời thư';
-$labels['vacation.advanced'] = 'Tùy chọn tính năng cao hơn';
-$labels['vacation.subject'] = 'Tiêu đề';
-$labels['vacation.body'] = 'Nội dung thư';
-$labels['vacation.status'] = 'Trạng thái';
-$labels['vacation.on'] = 'Bật';
-$labels['vacation.off'] = 'Tắt';
-$labels['vacation.addresses'] = 'Các địa chỉ bổ sung của tôi';
-$labels['vacation.interval'] = 'Khoảng thời gian trả lời';
-$labels['vacation.after'] = 'Đặt quy định kỳ nghỉ sau';
-$labels['vacation.saving'] = 'Lưu lại dữ liệu...';
-$messages['filterunknownerror'] = 'Không tìm được lỗi máy chủ';
-$messages['filterconnerror'] = 'Không kết nối được với máy chủ.';
-$messages['filterdeleteerror'] = 'Không thể xóa bộ lọc. Xuất hiện lỗi ở máy chủ';
-$messages['filterdeleted'] = 'Xóa bộ lọc thành công';
-$messages['filtersaved'] = 'Lưu bộ lọc thành công';
-$messages['filtersaveerror'] = 'Không thể lưu bộ lọc. Xuất hiện lỗi ở máy chủ';
-$messages['filterdeleteconfirm'] = 'Bạn có thực sự muốn xóa bộ lọc được chọn?';
-$messages['ruledeleteconfirm'] = 'Bạn có chắc chắn muốn xóa qui luật được chọn?';
-$messages['actiondeleteconfirm'] = 'Bạn có chắc chắn muốn xóa hành động được chọn?';
-$messages['forbiddenchars'] = 'Ký tự bị cấm trong ô';
-$messages['cannotbeempty'] = 'Ô không thể bị bỏ trống';
-$messages['ruleexist'] = 'Đã tồn tại bộ lọc với tên cụ thế';
-$messages['setactivateerror'] = 'Không thể kích hoạt bộ lọc được lựa chọn. Xuất hiện lỗi ở máy chủ';
-$messages['setdeactivateerror'] = 'Không thể tắt bộ lọc được lựa chọn. Xuất hiện lỗi ở máy chủ';
-$messages['setdeleteerror'] = 'Không thể xóa bộ lọc được lựa chọn. Xuất hiện lỗi ở máy chủ.';
-$messages['setactivated'] = 'Bộ lọc được khởi động thành công';
-$messages['setdeactivated'] = 'Ngừng kích hoạt bộ lọc thành công';
-$messages['setdeleted'] = 'Xóa bộ lọc thành công';
-$messages['setdeleteconfirm'] = 'Bạn có chắc bạn muốn xóa thiết lập bộ lọc được chọn?';
-$messages['setcreateerror'] = 'Không thể tạo thiết lập bộ lọc. Có lỗi xuất hiện ở máy chủ';
-$messages['setcreated'] = 'Thiết lập bộ lọc được tạo thành công';
-$messages['activateerror'] = 'Không thể khởi động (các) bộ lọc được chọn. Có lỗi xuất hiện ở máy chủ';
-$messages['deactivateerror'] = 'Không thể tắt (các) bộ lọc đã chọn. Có lỗi xuất hiện ở máy chủ';
-$messages['deactivated'] = 'Bộ lọc được khởi động thành công';
-$messages['activated'] = 'Bộ lọc được tắt thành công';
-$messages['moved'] = 'Bộ lọc được chuyển đi thành công';
-$messages['moveerror'] = 'Không thể chuyển bộ lọc đã chọn. Có lỗi xuất hiện ở máy chủ.';
-$messages['nametoolong'] = 'Tên quá dài';
-$messages['namereserved'] = 'Tên đã được bảo vệ';
-$messages['setexist'] = 'Thiết lập đã tồn tại';
-$messages['nodata'] = 'Ít nhất một vị trí phải được chọn';
-$messages['invaliddateformat'] = 'Lỗi không đúng cú pháp ngày hoặc nhập ngày sai';
-$messages['saveerror'] = 'Không thể lưu trữ dữ liệu. Xuất hiện lỗi ở máy chủ.';
-$messages['vacationsaved'] = 'Thiết lập kỳ nghỉ đã được lưu lại thành công.';
-?>
diff --git a/lib/plugins/managesieve/localization/zh_CN.inc b/lib/plugins/managesieve/localization/zh_CN.inc
deleted file mode 100644
index a39b312..0000000
--- a/lib/plugins/managesieve/localization/zh_CN.inc
+++ /dev/null
@@ -1,166 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = '过滤器';
-$labels['managefilters'] = '管理邮件过滤规则';
-$labels['filtername'] = '过滤规则名称';
-$labels['newfilter'] = '新建过滤规则';
-$labels['filteradd'] = '添加过滤规则';
-$labels['filterdel'] = '删除过滤规则';
-$labels['moveup'] = '上移';
-$labels['movedown'] = '下移';
-$labels['filterallof'] = '匹配所有规则';
-$labels['filteranyof'] = '匹配任意一条规则';
-$labels['filterany'] = '所有邮件';
-$labels['filtercontains'] = '包含';
-$labels['filternotcontains'] = '不包含';
-$labels['filteris'] = '等于';
-$labels['filterisnot'] = '不等于';
-$labels['filterexists'] = '存在';
-$labels['filternotexists'] = '不存在';
-$labels['filtermatches'] = '匹配表达式';
-$labels['filternotmatches'] = '不匹配表达式';
-$labels['filterregex'] = '匹配正则表达式';
-$labels['filternotregex'] = '不匹配正则表达式';
-$labels['filterunder'] = '小于';
-$labels['filterover'] = '大于';
-$labels['addrule'] = '新建规则';
-$labels['delrule'] = '删除规则';
-$labels['messagemoveto'] = '将邮件移至';
-$labels['messageredirect'] = '将邮件转发至';
-$labels['messagecopyto'] = '复制邮件至';
-$labels['messagesendcopy'] = '发送复制邮件至';
-$labels['messagereply'] = '回复以下内容';
-$labels['messagedelete'] = '删除邮件';
-$labels['messagediscard'] = '舍弃邮件并回复以下内容';
-$labels['messagesrules'] = '对新收取的邮件应用规则:';
-$labels['messagesactions'] = '执行以下操作:';
-$labels['add'] = '添加';
-$labels['del'] = '删除';
-$labels['sender'] = '发件人';
-$labels['recipient'] = '收件人';
-$labels['vacationdays'] = '发送邮件频率(单位:天):';
-$labels['vacationinterval'] = '发送邮件频率:';
-$labels['vacationreason'] = '邮件正文(假期原因)';
-$labels['vacationsubject'] = '邮件主题';
-$labels['days'] = '天';
-$labels['seconds'] = '秒';
-$labels['rulestop'] = '停止评价规则';
-$labels['enable'] = '启用/禁用';
-$labels['filterset'] = '过滤器设置';
-$labels['filtersets'] = '过滤器设置集';
-$labels['filtersetadd'] = '增加过滤器设置集';
-$labels['filtersetdel'] = '删除当前的过滤器设置集';
-$labels['filtersetact'] = '激活当前的过滤器设置集';
-$labels['filtersetdeact'] = '停用当前的过滤器设置集';
-$labels['filterdef'] = '过滤器定义';
-$labels['filtersetname'] = '过滤器集的名称';
-$labels['newfilterset'] = '新的过滤器集';
-$labels['active'] = '启用';
-$labels['none'] = '无';
-$labels['fromset'] = '从设置集';
-$labels['fromfile'] = '从文件';
-$labels['filterdisabled'] = '过滤器已禁用';
-$labels['countisgreaterthan'] = '计数大于';
-$labels['countisgreaterthanequal'] = '计数大于或等于';
-$labels['countislessthan'] = '计数小于';
-$labels['countislessthanequal'] = '计数小于或等于';
-$labels['countequals'] = '计数等于';
-$labels['valueisgreaterthan'] = '值大于';
-$labels['valueisgreaterthanequal'] = '值大于或等于';
-$labels['valueislessthan'] = '值小于';
-$labels['valueislessthanequal'] = '值小于或等于';
-$labels['valueequals'] = '值等于';
-$labels['setflags'] = '设定邮件的标识';
-$labels['addflags'] = '增加邮件的标识';
-$labels['removeflags'] = '删除邮件的标识';
-$labels['flagread'] = '读取';
-$labels['flagdeleted'] = '删除';
-$labels['flaganswered'] = '已答复';
-$labels['flagflagged'] = '已标记';
-$labels['flagdraft'] = '草稿';
-$labels['setvariable'] = '设置变量';
-$labels['setvarname'] = '变量名:';
-$labels['setvarvalue'] = '值:';
-$labels['setvarmodifiers'] = '修改:';
-$labels['varlower'] = '小写';
-$labels['varupper'] = '大写';
-$labels['varlowerfirst'] = '首字母小写';
-$labels['varupperfirst'] = '首字母大写';
-$labels['varquotewildcard'] = '引用特殊字符';
-$labels['varlength'] = '长度';
-$labels['notify'] = '发送通知';
-$labels['notifyimportance'] = '优先级:';
-$labels['notifyimportancelow'] = '低';
-$labels['notifyimportancenormal'] = '中';
-$labels['notifyimportancehigh'] = '高';
-$labels['filtercreate'] = '创建过滤规则';
-$labels['usedata'] = '在过滤器中使用下列数据';
-$labels['nextstep'] = '下一步';
-$labels['...'] = '...';
-$labels['currdate'] = '当前日期';
-$labels['datetest'] = '日期';
-$labels['year'] = 'å¹´';
-$labels['month'] = '月';
-$labels['day'] = '天';
-$labels['date'] = '日期 (年-月-日)';
-$labels['hour'] = '小时';
-$labels['minute'] = '分钟';
-$labels['second'] = '秒';
-$labels['zone'] = '时区';
-$labels['advancedopts'] = '高级选项';
-$labels['body'] = '正文';
-$labels['address'] = '地址';
-$labels['envelope'] = '信封';
-$labels['modifier'] = '修饰符:';
-$labels['text'] = '文本';
-$labels['undecoded'] = '未解码(RAW)';
-$labels['contenttype'] = '内容类型';
-$labels['modtype'] = '类型:';
-$labels['allparts'] = '全部';
-$labels['domain'] = '域';
-$labels['localpart'] = '本地部份';
-$labels['user'] = '用户';
-$labels['detail'] = '细节';
-$labels['comparator'] = '比较:';
-$labels['default'] = '默认';
-$labels['octet'] = '严格模式(字节)';
-$labels['asciicasemap'] = '不区分大小写(ascii 字符)';
-$labels['asciinumeric'] = '数字类型(ascii 数字)';
-$messages['filterunknownerror'] = '未知的服务器错误';
-$messages['filterconnerror'] = '无法连接至服务器';
-$messages['filterdeleted'] = '过滤器已成功删除';
-$messages['filtersaved'] = '过滤器已成功保存。';
-$messages['filterdeleteconfirm'] = '您确定要删除所选择的过滤器吗?';
-$messages['ruledeleteconfirm'] = '您确定要删除所选择的规则吗?';
-$messages['actiondeleteconfirm'] = '您确定要删除所选择的操作吗?';
-$messages['forbiddenchars'] = '内容包含禁用字符';
-$messages['cannotbeempty'] = '内容不能为空';
-$messages['ruleexist'] = '指定过滤器名称已存在。';
-$messages['setactivated'] = '启用过滤器集成功。';
-$messages['setdeactivated'] = '禁用过滤器集成功。';
-$messages['setdeleted'] = '删除过滤器成功。';
-$messages['setdeleteconfirm'] = '您确定要删除指定的过滤器吗?';
-$messages['setcreated'] = '过滤器成功创建。';
-$messages['deactivated'] = '启用过滤器成功。';
-$messages['activated'] = '禁用过滤器成功。';
-$messages['moved'] = '移动过滤器成功。';
-$messages['nametoolong'] = '无法创建过滤器集,名称太长。';
-$messages['namereserved'] = '保留名称。';
-$messages['setexist'] = '设置已存在。';
-$messages['nodata'] = '至少选择一个位置!';
-?>
diff --git a/lib/plugins/managesieve/localization/zh_TW.inc b/lib/plugins/managesieve/localization/zh_TW.inc
deleted file mode 100644
index b21310c..0000000
--- a/lib/plugins/managesieve/localization/zh_TW.inc
+++ /dev/null
@@ -1,160 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | plugins/managesieve/localization/<lang>.inc |
- | |
- | Localization file of the Roundcube Webmail Managesieve plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- +-----------------------------------------------------------------------+
-
- For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-managesieve/
-*/
-$labels['filters'] = '篩選器';
-$labels['managefilters'] = '設定篩選器';
-$labels['filtername'] = '篩選器名稱';
-$labels['newfilter'] = '建立新篩選器';
-$labels['filteradd'] = '增加篩選器';
-$labels['filterdel'] = '刪除篩選器';
-$labels['moveup'] = '上移';
-$labels['movedown'] = '下移';
-$labels['filterallof'] = '符合所有規則';
-$labels['filteranyof'] = '符合任一條規則';
-$labels['filterany'] = '所有信件';
-$labels['filtercontains'] = '包含';
-$labels['filternotcontains'] = '不包含';
-$labels['filteris'] = '等於';
-$labels['filterisnot'] = '不等於';
-$labels['filterexists'] = '存在';
-$labels['filternotexists'] = '不存在';
-$labels['filtermatches'] = '符合表達式';
-$labels['filternotmatches'] = '不符合表達式';
-$labels['filterregex'] = '符合正規表達式';
-$labels['filternotregex'] = '不符合正規表達式';
-$labels['filterunder'] = '小於';
-$labels['filterover'] = '大於';
-$labels['addrule'] = '新增規則';
-$labels['delrule'] = '刪除規則';
-$labels['messagemoveto'] = '將信件移至';
-$labels['messageredirect'] = '將信件轉寄至';
-$labels['messagecopyto'] = '複製訊息至';
-$labels['messagesendcopy'] = '寄送訊息複本至';
-$labels['messagereply'] = '以下列內容回覆';
-$labels['messagedelete'] = '刪除信件';
-$labels['messagediscard'] = '刪除信件並以下列內容回覆';
-$labels['messagekeep'] = '在收件匣保留郵件';
-$labels['messagesrules'] = '對新收到的信件:';
-$labels['messagesactions'] = '執行下列動作:';
-$labels['add'] = '新增';
-$labels['del'] = '刪除';
-$labels['sender'] = '寄件者';
-$labels['recipient'] = '收件者';
-$labels['vacationdays'] = '多久回覆一次(單位:天):';
-$labels['vacationreason'] = '信件內容(休假原因):';
-$labels['vacationsubject'] = '訊息主旨:';
-$labels['rulestop'] = '停止評估規則';
-$labels['enable'] = '啟用/停用';
-$labels['filterset'] = '篩選器集合';
-$labels['filtersets'] = '篩選器集合';
-$labels['filtersetadd'] = '加入篩選器集合';
-$labels['filtersetdel'] = '刪除目前的篩選器集合';
-$labels['filtersetact'] = '啟用目前的篩選器集合';
-$labels['filtersetdeact'] = '停用目前的篩選器集合';
-$labels['filterdef'] = '篩選器定義';
-$labels['filtersetname'] = '篩選器集合名稱';
-$labels['newfilterset'] = '建立篩選器集合';
-$labels['active'] = '啟用';
-$labels['none'] = '無';
-$labels['fromset'] = '從集合';
-$labels['fromfile'] = '重檔案';
-$labels['filterdisabled'] = '篩選器已停用';
-$labels['countisgreaterthan'] = '計數大於';
-$labels['countisgreaterthanequal'] = '計數大於或等於';
-$labels['countislessthan'] = '計數小於';
-$labels['countislessthanequal'] = '數量小於或等於';
-$labels['countequals'] = '數量等於';
-$labels['valueisgreaterthan'] = '值大於';
-$labels['valueisgreaterthanequal'] = '值大於等於';
-$labels['valueislessthan'] = '值小於';
-$labels['valueislessthanequal'] = '值小於或等於';
-$labels['valueequals'] = '值等於';
-$labels['setflags'] = '設定標幟';
-$labels['addflags'] = '新增標記到訊息';
-$labels['removeflags'] = '移除訊息標記';
-$labels['flagread'] = '讀取';
-$labels['flagdeleted'] = '刪除';
-$labels['flaganswered'] = '已經回覆';
-$labels['flagflagged'] = '已加標記的郵件';
-$labels['flagdraft'] = '草稿';
-$labels['setvariable'] = '設定變數';
-$labels['setvarname'] = '變數名稱:';
-$labels['setvarvalue'] = '變數值:';
-$labels['setvarmodifiers'] = '修改:';
-$labels['varlower'] = '低於';
-$labels['varupper'] = '高於';
-$labels['varlowerfirst'] = '第一個字低於';
-$labels['varupperfirst'] = '第一個字高於';
-$labels['varquotewildcard'] = '跳脫字元';
-$labels['varlength'] = '長度';
-$labels['notify'] = '寄送通知';
-$labels['notifyimportance'] = '重要性:';
-$labels['notifyimportancelow'] = '低';
-$labels['notifyimportancenormal'] = '一般';
-$labels['notifyimportancehigh'] = '高';
-$labels['filtercreate'] = '建立郵件規則';
-$labels['usedata'] = '於規則中使用轉寄時間';
-$labels['nextstep'] = '下一步';
-$labels['...'] = '…';
-$labels['date'] = '日期 (yyyy-mm-dd)';
-$labels['julian'] = '日期 (Julian Day)';
-$labels['time'] = '時間 (hh:mm:ss)';
-$labels['iso8601'] = '日期 (ISO8601)';
-$labels['std11'] = '日期 (RFC2822)';
-$labels['zone'] = '時區';
-$labels['advancedopts'] = '進階選項';
-$labels['body'] = '內文';
-$labels['address'] = '郵件位址';
-$labels['envelope'] = '信封';
-$labels['modifier'] = '修改:';
-$labels['text'] = '文字';
-$labels['undecoded'] = '未解碼(raw)';
-$labels['contenttype'] = '內容類型';
-$labels['modtype'] = '型態:';
-$labels['allparts'] = '全部';
-$labels['domain'] = '網域';
-$labels['localpart'] = '本機連接埠';
-$labels['user'] = '使用者';
-$labels['detail'] = '細節';
-$labels['comparator'] = '比較:';
-$labels['default'] = '預設';
-$labels['octet'] = '嚴謹模式(八位元組)';
-$labels['asciicasemap'] = '不區分大小寫(採用ASCII-Casemap)';
-$labels['asciinumeric'] = '數字類型(ascii-numeric)';
-$messages['filterunknownerror'] = '未知的伺服器錯誤';
-$messages['filterconnerror'] = '無法與伺服器連線';
-$messages['filterdeleted'] = '成功刪除篩選器';
-$messages['filtersaved'] = '成功儲存篩選器。';
-$messages['filterdeleteconfirm'] = '您確定要刪除選擇的郵件規則嗎?';
-$messages['ruledeleteconfirm'] = '您確定要刪除選的規則嗎?';
-$messages['actiondeleteconfirm'] = '您確定要刪除選擇的動作嗎?';
-$messages['forbiddenchars'] = '內容包含禁用字元';
-$messages['cannotbeempty'] = '內容不能為空白';
-$messages['ruleexist'] = '規則名稱重複';
-$messages['setactivated'] = '篩選器集合成功啟用';
-$messages['setdeactivated'] = '篩選器集合成功停用';
-$messages['setdeleted'] = '篩選器集合成功刪除';
-$messages['setdeleteconfirm'] = '你確定要刪除選擇的篩選器集合嗎?';
-$messages['setcreated'] = '篩選器集合成功建立';
-$messages['deactivated'] = '篩選器已啟用';
-$messages['activated'] = '篩選器已停用';
-$messages['moved'] = '篩選器已移動';
-$messages['nametoolong'] = '名稱太長。';
-$messages['namereserved'] = '保留名稱.';
-$messages['setexist'] = '設定已存在';
-$messages['nodata'] = '至少要選擇一個位置';
-?>
diff --git a/lib/plugins/managesieve/managesieve.js b/lib/plugins/managesieve/managesieve.js
deleted file mode 100644
index 4d60833..0000000
--- a/lib/plugins/managesieve/managesieve.js
+++ /dev/null
@@ -1,1031 +0,0 @@
-/**
- * (Manage)Sieve Filters plugin
- *
- * @licstart The following is the entire license notice for the
- * JavaScript code in this file.
- *
- * Copyright (c) 2012-2014, The Roundcube Dev Team
- *
- * The JavaScript code in this page is free software: you can redistribute it
- * and/or modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * @licend The above is the entire license notice
- * for the JavaScript code in this file.
- */
-
-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);
- }
-
- if (rcmail.env.task == 'mail' || rcmail.env.action.startsWith('plugin.managesieve')) {
- // 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);
- }
- }
-
- // 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.startsWith('plugin.managesieve')) {
- if (rcmail.gui_objects.sieveform) {
- rcmail.enable_command('plugin.managesieve-save', true);
- sieve_form_init();
- }
- else {
- rcmail.enable_command('plugin.managesieve-add', 'plugin.managesieve-setadd', !rcmail.env.sieveconnerror);
- }
-
- var setcnt, set = rcmail.env.currentset;
-
- if (rcmail.gui_objects.filterslist) {
- rcmail.filters_list = new rcube_list_widget(rcmail.gui_objects.filterslist,
- {multiselect:false, draggable:true, keyboard:true});
-
- rcmail.filters_list
- .addEventListener('select', function(e) { rcmail.managesieve_select(e); })
- .addEventListener('dragstart', function(e) { rcmail.managesieve_dragstart(e); })
- .addEventListener('dragend', function(e) { rcmail.managesieve_dragend(e); })
- .addEventListener('initrow', function(row) {
- row.obj.onmouseover = function() { rcmail.managesieve_focus_filter(row); };
- row.obj.onmouseout = function() { rcmail.managesieve_unfocus_filter(row); };
- })
- .init();
- }
-
- if (rcmail.gui_objects.filtersetslist) {
- rcmail.filtersets_list = new rcube_list_widget(rcmail.gui_objects.filtersetslist,
- {multiselect:false, draggable:false, keyboard:true});
-
- rcmail.filtersets_list.init().focus();
-
- if (set != null) {
- set = rcmail.managesieve_setid(set);
- rcmail.filtersets_list.select(set);
- }
-
- // attach select event after initial record was selected
- rcmail.filtersets_list.addEventListener('select', function(e) { rcmail.managesieve_setselect(e); });
-
- 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);
-
- // Fix dragging filters over sets list
- $('tr', rcmail.gui_objects.filtersetslist).each(function (i, e) { rcmail.managesieve_fixdragend(e); });
- }
- }
-
- if (rcmail.gui_objects.sieveform && rcmail.env.rule_disabled)
- $('#disabled').attr('checked', true);
- });
-};
-
-/*********************************************************/
-/********* Managesieve UI methods *********/
-/*********************************************************/
-
-rcube_webmail.prototype.managesieve_add = function()
-{
- this.load_managesieveframe();
- this.filters_list.clear_selection();
-};
-
-rcube_webmail.prototype.managesieve_del = function()
-{
- var id = this.filters_list.get_single_selection();
- if (confirm(this.get_label('managesieve.filterdeleteconfirm'))) {
- var lock = this.set_busy(true, 'loading');
- this.http_post('plugin.managesieve-action',
- '_act=delete&_fid='+this.filters_list.rows[id].uid, lock);
- }
-};
-
-rcube_webmail.prototype.managesieve_act = function()
-{
- var id = this.filters_list.get_single_selection(),
- lock = this.set_busy(true, 'loading');
-
- this.http_post('plugin.managesieve-action',
- '_act=act&_fid='+this.filters_list.rows[id].uid, lock);
-};
-
-// Filter selection
-rcube_webmail.prototype.managesieve_select = function(list)
-{
- 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)
-{
- var i, rows = this.filters_list.rows;
-
- for (i in rows)
- if (rows[i] != null && rows[i].uid == id)
- return i;
-};
-
-// 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-action', '_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-action&_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-action', '_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-action', '_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-action&_framed=1&_newset=1&_unlock='+lock;
- }
-};
-
-rcube_webmail.prototype.managesieve_updatelist = function(action, o)
-{
- this.set_busy(true);
-
- switch (action) {
-
- // Delete filter row
- case 'del':
- var id = o.id, list = this.filters_list;
-
- 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);
-
- // filter identifiers changed, fix the list
- $('tr', this.filters_list.list).each(function() {
- // remove hidden (deleted) rows
- if (this.style.display == 'none') {
- $(this).detach();
- return;
- }
-
- var rowid = this.id.substr(6);
-
- // remove all attached events
- $(this).unbind();
-
- // update row id
- if (rowid > id)
- $(this).attr('id', 'rcmrow' + (rowid-1));
- });
- list.init();
-
- break;
-
- // Update filter row
- case 'update':
- var i, row = $('#rcmrow'+this.managesieve_rowid(o.id));
-
- if (o.name)
- $('td', row).text(o.name);
- if (o.disabled)
- row.addClass('disabled');
- else
- row.removeClass('disabled');
-
- $('#disabled', $('iframe').contents()).prop('checked', o.disabled);
-
- break;
-
- // Add filter row to the list
- case 'add':
- var list = this.filters_list,
- row = $('<tr><td class="name"></td></tr>');
-
- $('td', row).text(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);
-
- 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).text(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;
-
- // 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
- row.addClass('disabled');
-
- break;
-
- // Delete set row
- case 'setdel':
- var id = this.managesieve_setid(o.name);
-
- 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);
-
- 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).text(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);
-
- // Fix dragging filters over sets list
- this.managesieve_fixdragend(row);
-
- break;
- }
-
- this.set_busy(false);
-};
-
-// load filter frame
-rcube_webmail.prototype.load_managesieveframe = function(id)
-{
- 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-action&_framed=1'
- +(has_id ? '&_fid='+id : '')+'&_unlock='+msgid;
- }
-};
-
-// load filter frame
-rcube_webmail.prototype.managesieve_dragstart = function(list)
-{
- var id = this.filters_list.get_single_selection();
-
- 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-action', '_act=move&_fid='+this.drag_filter
- +'&_to='+this.drag_filter_target, lock);
- }
- this.drag_active = false;
- }
-};
-
-// Fixes filters dragging over sets list
-// @TODO: to be removed after implementing copying filters
-rcube_webmail.prototype.managesieve_fixdragend = function(elem)
-{
- var p = this;
- $(elem).bind('mouseup' + ((bw.iphone || bw.ipad) ? ' touchend' : ''), function(e) {
- if (p.drag_active)
- p.filters_list.drag_mouse_up(e);
- });
-};
-
-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 (this.env.action == 'plugin.managesieve-vacation') {
- var data = $(this.gui_objects.sieveform).serialize();
- this.http_post('plugin.managesieve-vacation', data, this.display_message(this.get_label('managesieve.vacation.saving'), 'loading'));
- return;
- }
-
- 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
-rcube_webmail.prototype.managesieve_ruleadd = function(id)
-{
- this.http_post('plugin.managesieve-action', '_act=ruleadd&_rid='+id);
-};
-
-rcube_webmail.prototype.managesieve_rulefill = function(content, id, after)
-{
- if (content != '') {
- // create new element
- var div = document.getElementById('rules'),
- row = document.createElement('div');
-
- this.managesieve_insertrow(div, row, after);
- // fill row after inserting (for IE)
- row.setAttribute('id', 'rulerow'+id);
- row.className = 'rulerow';
- row.innerHTML = content;
-
- // initialize smart list inputs
- $('textarea[data-type="list"]', row).each(function() {
- smart_field_init(this);
- });
-
- this.managesieve_formbuttons(div);
- }
-};
-
-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);
- this.managesieve_formbuttons(document.getElementById('rules'));
- }
-};
-
-rcube_webmail.prototype.managesieve_actionadd = function(id)
-{
- this.http_post('plugin.managesieve-action', '_act=actionadd&_aid='+id);
-};
-
-rcube_webmail.prototype.managesieve_actionfill = function(content, id, after)
-{
- if (content != '') {
- var div = document.getElementById('actions'),
- row = document.createElement('div');
-
- this.managesieve_insertrow(div, row, after);
- // fill row after inserting (for IE)
- row.className = 'actionrow';
- row.setAttribute('id', 'actionrow'+id);
- row.innerHTML = content;
-
- // initialize smart list inputs
- $('textarea[data-type="list"]', row).each(function() {
- smart_field_init(this);
- });
-
- this.managesieve_formbuttons(div);
- }
-};
-
-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);
- this.managesieve_formbuttons(document.getElementById('actions'));
- }
-};
-
-// insert rule/action row in specified place on the list
-rcube_webmail.prototype.managesieve_insertrow = function(div, row, after)
-{
- for (var i=0; i<div.childNodes.length; i++) {
- if (div.childNodes[i].id == (div.id == 'rules' ? 'rulerow' : 'actionrow') + after)
- break;
- }
-
- if (div.childNodes[i+1])
- div.insertBefore(row, div.childNodes[i+1]);
- else
- div.appendChild(row);
-};
-
-// update Delete buttons status
-rcube_webmail.prototype.managesieve_formbuttons = function(div)
-{
- var i, button, buttons = [];
-
- // count and get buttons
- for (i=0; i<div.childNodes.length; i++) {
- if (div.id == 'rules' && div.childNodes[i].id) {
- if (/rulerow/.test(div.childNodes[i].id))
- buttons.push('ruledel' + div.childNodes[i].id.replace(/rulerow/, ''));
- }
- else if (div.childNodes[i].id) {
- if (/actionrow/.test(div.childNodes[i].id))
- buttons.push( 'actiondel' + div.childNodes[i].id.replace(/actionrow/, ''));
- }
- }
-
- for (i=0; i<buttons.length; i++) {
- button = document.getElementById(buttons[i]);
- if (i>0 || buttons.length>1) {
- $(button).removeClass('disabled');
- }
- else {
- $(button).addClass('disabled');
- }
- }
-};
-
-function rule_header_select(id)
-{
- var obj = document.getElementById('header' + id),
- size = document.getElementById('rule_size' + id),
- op = document.getElementById('rule_op' + id),
- header = document.getElementById('custom_header' + id + '_list'),
- mod = document.getElementById('rule_mod' + id),
- trans = document.getElementById('rule_trans' + id),
- comp = document.getElementById('rule_comp' + id),
- datepart = document.getElementById('rule_date_part' + id),
- dateheader = document.getElementById('rule_date_header_div' + id),
- h = obj.value;
-
- if (h == 'size') {
- size.style.display = 'inline';
- $.each([op, header, mod, trans, comp], function() { this.style.display = 'none'; });
- }
- else {
- header.style.display = h != '...' ? 'none' : 'inline-block';
- size.style.display = 'none';
- op.style.display = 'inline';
- comp.style.display = '';
- mod.style.display = h == 'body' || h == 'currentdate' || h == 'date' ? 'none' : 'block';
- trans.style.display = h == 'body' ? 'block' : 'none';
- }
-
- if (datepart)
- datepart.style.display = h == 'currentdate' || h == 'date' ? 'inline' : 'none';
- if (dateheader)
- dateheader.style.display = h == 'date' ? '' : 'none';
-
- rule_op_select(op, id, h);
- rule_mod_select(id, h);
- obj.style.width = h == '...' ? '40px' : '';
-};
-
-function rule_op_select(obj, id, header)
-{
- var target = document.getElementById('rule_target' + id + '_list');
-
- if (!header)
- header = document.getElementById('header' + id).value;
-
- target.style.display = obj.value == 'exists' || obj.value == 'notexists' || header == 'size' ? 'none' : 'inline-block';
-};
-
-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, header)
-{
- var obj = document.getElementById('rule_mod_op' + id),
- target = document.getElementById('rule_mod_type' + id),
- index = document.getElementById('rule_index_div' + id);
-
- if (!header)
- header = document.getElementById('header' + id).value;
-
- target.style.display = obj.value != 'address' && obj.value != 'envelope' ? 'none' : 'inline';
-
- if (index)
- index.style.display = header != 'body' && header != 'currentdate' && header != 'size' && obj.value != 'envelope' ? '' : 'none';
-};
-
-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),
- v = obj.value, enabled = {},
- elems = {
- mailbox: document.getElementById('action_mailbox' + id),
- target: document.getElementById('redirect_target' + id),
- target_area: document.getElementById('action_target_area' + id),
- flags: document.getElementById('action_flags' + id),
- vacation: document.getElementById('action_vacation' + id),
- set: document.getElementById('action_set' + id),
- notify: document.getElementById('action_notify' + id)
- };
-
- if (v == 'fileinto' || v == 'fileinto_copy') {
- enabled.mailbox = 1;
- }
- else if (v == 'redirect' || v == 'redirect_copy') {
- enabled.target = 1;
- }
- else if (v.match(/^reject|ereject$/)) {
- enabled.target_area = 1;
- }
- else if (v.match(/^(add|set|remove)flag$/)) {
- enabled.flags = 1;
- }
- else if (v == 'vacation') {
- enabled.vacation = 1;
- }
- else if (v == 'set') {
- enabled.set = 1;
- }
- else if (v == 'notify') {
- enabled.notify = 1;
- }
-
- for (var x in elems) {
- elems[x].style.display = !enabled[x] ? 'none' : 'inline';
- }
-};
-
-function vacation_action_select()
-{
- var selected = $('#vacation_action').val();
-
- $('#action_target_span')[selected == 'discard' || selected == 'keep' ? 'hide' : 'show']();
-};
-
-// Inititalizes smart list input
-function smart_field_init(field)
-{
- var id = field.id + '_list',
- area = $('<span class="listarea"></span>'),
- list = field.value ? field.value.split("\n") : [''];
-
- if ($('#'+id).length)
- return;
-
- // add input rows
- $.each(list, function(i, v) {
- area.append(smart_field_row(v, field.name, i, $(field).data('size')));
- });
-
- area.attr('id', id);
- field = $(field);
-
- if (field.attr('disabled'))
- area.hide();
- // disable the original field anyway, we don't want it in POST
- else
- field.prop('disabled', true);
-
- field.after(area);
-
- if (field.hasClass('error')) {
- area.addClass('error');
- rcmail.managesieve_tip_register([[id, field.data('tip')]]);
- }
-};
-
-function smart_field_row(value, name, idx, size)
-{
- // build row element content
- var input, content = '<span class="listelement">'
- + '<span class="reset"></span><input type="text"></span>',
- elem = $(content),
- attrs = {value: value, name: name + '[]'};
-
- if (size)
- attrs.size = size;
-
- input = $('input', elem).attr(attrs).keydown(function(e) {
- var input = $(this);
-
- // element creation event (on Enter)
- if (e.which == 13) {
- var name = input.attr('name').replace(/\[\]$/, ''),
- dt = (new Date()).getTime(),
- elem = smart_field_row('', name, dt, size);
-
- input.parent().after(elem);
- $('input', elem).focus();
- }
- // backspace or delete: remove input, focus previous one
- else if ((e.which == 8 || e.which == 46) && input.val() == '') {
-
- var parent = input.parent(), siblings = parent.parent().children();
-
- if (siblings.length > 1) {
- if (parent.prev().length)
- parent.prev().children('input').focus();
- else
- parent.next().children('input').focus();
-
- parent.remove();
- return false;
- }
- }
- });
-
- // element deletion event
- $('span[class="reset"]', elem).click(function() {
- var span = $(this.parentNode);
-
- if (span.parent().children().length > 1)
- span.remove();
- else
- $('input', span).val('').focus();
- });
-
- return elem;
-}
-
-// 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])
- .data('tip', tips[n][1])
- .bind('mouseenter', function(e) {
- var elem = $(this),
- offset = elem.offset(),
- left = offset.left,
- top = offset.top - 12,
- minwidth = elem.width();
-
- if (framed) {
- offset = $((rcmail.env.task == 'mail' ? '#sievefilterform > iframe' : '#filter-box'), parent.document).offset();
- top += offset.top;
- left += offset.left;
- }
-
- tip.html(elem.data('tip'));
- top -= tip.height();
-
- tip.css({left: left, top: top, minWidth: (minwidth-2) + 'px'}).show();
- })
- .bind('mouseleave', function(e) { tip.hide(); });
- }
-};
-
-// format time string
-function sieve_formattime(hour, minutes)
-{
- var i, c, h, time = '', format = rcmail.env.time_format || 'H:i';
-
- for (i=0; i<format.length; i++) {
- c = format.charAt(i);
- switch (c) {
- case 'a': time += hour > 12 ? 'am' : 'pm'; break;
- case 'A': time += hour > 12 ? 'AM' : 'PM'; break;
- case 'g':
- case 'h':
- h = hour == 0 ? 12 : hour > 12 ? hour - 12 : hour;
- time += (c == 'h' && hour < 10 ? '0' : '') + hour;
- break;
- case 'G': time += hour; break;
- case 'H': time += (hour < 10 ? '0' : '') + hour; break;
- case 'i': time += (minutes < 10 ? '0' : '') + minutes; break;
- case 's': time += '00';
- default: time += c;
- }
- }
-
- return time;
-}
-
-function sieve_form_init()
-{
- // 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();
-
- // initialize smart list inputs
- $('textarea[data-type="list"]', rcmail.gui_objects.sieveform).each(function() {
- smart_field_init(this);
- });
-
- // enable date pickers on date fields
- if ($.datepicker && rcmail.env.date_format) {
- $.datepicker.setDefaults({
- dateFormat: rcmail.env.date_format,
- changeMonth: true,
- showOtherMonths: true,
- selectOtherMonths: true,
- onSelect: function(dateText) { $(this).focus().val(dateText); }
- });
- $('input.datepicker').datepicker();
- }
-
- // configure drop-down menu on time input fields based on jquery UI autocomplete
- $('#vacation_timefrom, #vacation_timeto')
- .attr('autocomplete', "off")
- .autocomplete({
- delay: 100,
- minLength: 1,
- source: function(p, callback) {
- var h, result = [];
- for (h = 0; h < 24; h++)
- result.push(sieve_formattime(h, 0));
- result.push(sieve_formattime(23, 59));
-
- return callback(result);
- },
- open: function(event, ui) {
- // scroll to current time
- var $this = $(this), val = $this.val(),
- widget = $this.autocomplete('widget').css('width', '10em'),
- menu = $this.data('ui-autocomplete').menu;
-
- if (val && val.length)
- widget.children().each(function() {
- var li = $(this);
- if (li.text().indexOf(val) == 0)
- menu._scrollIntoView(li);
- });
- },
- select: function(event, ui) {
- $(this).val(ui.item.value);
- return false;
- }
- })
- .click(function() { // show drop-down upon clicks
- $(this).autocomplete('search', $(this).val() || ' ');
- })
-}
-
-
-/*********************************************************/
-/********* Mail UI methods *********/
-/*********************************************************/
-
-rcube_webmail.prototype.managesieve_create = function(force)
-{
- if (!force && this.env.action != 'show') {
- var uid = this.message_list.get_single_selection(),
- lock = this.set_busy(true, 'loading');
-
- this.http_post('plugin.managesieve-action', {_uid: uid}, lock);
- return;
- }
-
- if (!this.env.sieve_headers || !this.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 this.env.sieve_headers)
- html += '<li><input type="checkbox" name="headers[]" id="sievehdr'+i+'" value="'+i+'" checked="checked" />'
- +'<label for="sievehdr'+i+'">'+this.env.sieve_headers[i][0]+':</label> '+this.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('widget').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: true,
- closeOnEscape: !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 = $('fieldset:first', o).width(), // fieldset width is more appropriate here
- 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']); // works in a separate call only (!?)
-}
diff --git a/lib/plugins/managesieve/managesieve.php b/lib/plugins/managesieve/managesieve.php
deleted file mode 100644
index f41394e..0000000
--- a/lib/plugins/managesieve/managesieve.php
+++ /dev/null
@@ -1,274 +0,0 @@
-<?php
-
-/**
- * Managesieve (Sieve Filters)
- *
- * Plugin that adds a possibility to manage Sieve filters in Thunderbird's style.
- * It's clickable interface which operates on text scripts and communicates
- * with server using managesieve protocol. Adds Filters tab in Settings.
- *
- * @version @package_version@
- * @author Aleksander Machniak <alec@alec.pl>
- *
- * Configuration (see config.inc.php.dist)
- *
- * Copyright (C) 2008-2013, The Roundcube Dev Team
- * Copyright (C) 2011-2013, 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 as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-class managesieve extends rcube_plugin
-{
- public $task = 'mail|settings';
- private $rc;
- private $engine;
-
- function init()
- {
- $this->rc = rcube::get_instance();
-
- // register actions
- $this->register_action('plugin.managesieve', array($this, 'managesieve_actions'));
- $this->register_action('plugin.managesieve-action', array($this, 'managesieve_actions'));
- $this->register_action('plugin.managesieve-vacation', array($this, 'managesieve_actions'));
- $this->register_action('plugin.managesieve-save', array($this, 'managesieve_save'));
-
- if ($this->rc->task == 'settings') {
- $this->add_hook('settings_actions', array($this, 'settings_actions'));
- $this->init_ui();
- }
- else if ($this->rc->task == 'mail') {
- // register message hook
- if ($this->rc->action == 'show') {
- $this->add_hook('message_headers_output', array($this, 'mail_headers'));
- }
-
- // inject Create Filter popup stuff
- if (empty($this->rc->action) || $this->rc->action == 'show'
- || strpos($this->rc->action, 'plugin.managesieve') === 0
- ) {
- $this->mail_task_handler();
- }
- }
- }
-
- /**
- * Initializes plugin's UI (localization, js script)
- */
- function init_ui()
- {
- if ($this->ui_initialized) {
- return;
- }
-
- // load localization
- $this->add_texts('localization/');
-
- $sieve_action = strpos($this->rc->action, 'plugin.managesieve') === 0;
-
- if ($this->rc->task == 'mail' || $sieve_action) {
- $this->include_script('managesieve.js');
- }
-
- // include styles
- $skin_path = $this->local_skin_path();
- if ($this->rc->task == 'settings' || $sieve_action) {
- $this->include_stylesheet("$skin_path/managesieve.css");
- }
- else {
- $this->include_stylesheet("$skin_path/managesieve_mail.css");
- }
-
- $this->ui_initialized = true;
- }
-
- /**
- * Adds Filters section in Settings
- */
- function settings_actions($args)
- {
- $this->load_config();
-
- $vacation_mode = (int) $this->rc->config->get('managesieve_vacation');
-
- // register Filters action
- if ($vacation_mode != 2) {
- $args['actions'][] = array(
- 'action' => 'plugin.managesieve',
- 'class' => 'filter',
- 'label' => 'filters',
- 'domain' => 'managesieve',
- 'title' => 'filterstitle',
- );
- }
-
- // register Vacation action
- if ($vacation_mode > 0) {
- $args['actions'][] = array(
- 'action' => 'plugin.managesieve-vacation',
- 'class' => 'vacation',
- 'label' => 'vacation',
- 'domain' => 'managesieve',
- 'title' => 'vacationtitle',
- );
- }
-
- return $args;
- }
-
- /**
- * Add UI elements to the 'mailbox view' and 'show message' UI.
- */
- function mail_task_handler()
- {
- // make sure we're not in ajax request
- if ($this->rc->output->type != 'html') {
- return;
- }
-
- // use jQuery for popup window
- $this->require_plugin('jqueryui');
-
- // include js script and localization
- $this->init_ui();
-
- // 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' => 'icon filterlink active',
- 'class' => 'icon filterlink',
- 'innerclass' => 'icon 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)
- {
- // this hook can be executed many times
- if ($this->mail_headers_done) {
- return $args;
- }
-
- $this->mail_headers_done = true;
-
- $headers = $this->parse_headers($args['headers']);
-
- if ($this->rc->action == 'preview')
- $this->rc->output->command('parent.set_env', array('sieve_headers' => $headers));
- else
- $this->rc->output->set_env('sieve_headers', $headers);
-
- return $args;
- }
-
- /**
- * Plugin action handler
- */
- function managesieve_actions()
- {
- // handle fetching email headers for the new filter form
- if ($uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST)) {
- $uids = rcmail::get_uids();
- $mailbox = key($uids);
- $message = new rcube_message($uids[$mailbox][0], $mailbox);
- $headers = $this->parse_headers($message->headers);
-
- $this->rc->output->set_env('sieve_headers', $headers);
- $this->rc->output->command('managesieve_create', true);
- $this->rc->output->send();
- }
-
- // handle other actions
- $engine_type = $this->rc->action == 'plugin.managesieve-vacation' ? 'vacation' : '';
- $engine = $this->get_engine($engine_type);
-
- $this->init_ui();
- $engine->actions();
- }
-
- /**
- * Forms save action handler
- */
- 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');
- }
-
- $engine = $this->get_engine();
- $engine->save();
- }
-
- /**
- * Initializes engine object
- */
- public function get_engine($type = null)
- {
- if (!$this->engine) {
- $this->load_config();
-
- // Add include path for internal classes
- $include_path = $this->home . '/lib' . PATH_SEPARATOR;
- $include_path .= ini_get('include_path');
- set_include_path($include_path);
-
- $class_name = 'rcube_sieve_' . ($type ? $type : 'engine');
- $this->engine = new $class_name($this);
- }
-
- return $this->engine;
- }
-
- /**
- * Extract mail headers for new filter form
- */
- private function parse_headers($headers)
- {
- $result = array();
-
- if ($headers->subject)
- $result[] = array('Subject', rcube_mime::decode_header($headers->subject));
-
- // @TODO: List-Id, others?
- foreach (array('From', 'To') as $h) {
- $hl = strtolower($h);
- if ($headers->$hl) {
- $list = rcube_mime::decode_address_list($headers->$hl);
- foreach ($list as $item) {
- if ($item['mailto']) {
- $result[] = array($h, $item['mailto']);
- }
- }
- }
- }
-
- return $result;
- }
-}
diff --git a/lib/plugins/managesieve/skins/classic/images/add.png b/lib/plugins/managesieve/skins/classic/images/add.png
deleted file mode 100644
index 97a6422..0000000
Binary files a/lib/plugins/managesieve/skins/classic/images/add.png and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/classic/images/del.png b/lib/plugins/managesieve/skins/classic/images/del.png
deleted file mode 100644
index 518905b..0000000
Binary files a/lib/plugins/managesieve/skins/classic/images/del.png and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/classic/images/down_small.gif b/lib/plugins/managesieve/skins/classic/images/down_small.gif
deleted file mode 100644
index f865893..0000000
Binary files a/lib/plugins/managesieve/skins/classic/images/down_small.gif and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/classic/images/erase.png b/lib/plugins/managesieve/skins/classic/images/erase.png
deleted file mode 100644
index ddd3a97..0000000
Binary files a/lib/plugins/managesieve/skins/classic/images/erase.png and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/classic/images/filter.png b/lib/plugins/managesieve/skins/classic/images/filter.png
deleted file mode 100644
index a79ba10..0000000
Binary files a/lib/plugins/managesieve/skins/classic/images/filter.png and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/classic/images/up_small.gif b/lib/plugins/managesieve/skins/classic/images/up_small.gif
deleted file mode 100644
index 40deb89..0000000
Binary files a/lib/plugins/managesieve/skins/classic/images/up_small.gif and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/classic/managesieve.css b/lib/plugins/managesieve/skins/classic/managesieve.css
deleted file mode 100644
index 836e16d..0000000
--- a/lib/plugins/managesieve/skins/classic/managesieve.css
+++ /dev/null
@@ -1,430 +0,0 @@
-#filtersetslistbox
-{
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- width: 195px;
- border: 1px solid #999999;
- background-color: #F9F9F9;
- overflow: hidden;
- /* css hack for IE */
- height: expression(parseInt(this.parentNode.offsetHeight)+'px');
-}
-
-#filtersscreen
-{
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 205px;
- /* css hack for IE */
- height: expression(parseInt(this.parentNode.offsetHeight)+'px');
-}
-
-#filterslistbox
-{
- 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');
-}
-
-#filterslist,
-#filtersetslist
-{
- width: 100%;
- table-layout: fixed;
-}
-
-#filterslist tbody td,
-#filtersetslist tbody td
-{
- cursor: default;
- text-overflow: ellipsis;
- -o-text-overflow: ellipsis;
-}
-
-#filterslist tbody tr.disabled td,
-#filtersetslist tbody tr.disabled td
-{
- color: #999999;
-}
-
-#filtersetslist tbody td
-{
- font-weight: bold;
-}
-/*
-#filtersetslist tr.selected
-{
- background-color: #929292;
- border-bottom: 1px solid #898989;
- color: #FFF;
- font-weight: bold;
-}
-*/
-
-#filterslist tbody tr.filtermoveup td
-{
- border-top: 2px dotted #555;
- padding-top: 0px;
-}
-
-#filterslist tbody tr.filtermovedown td
-{
- border-bottom: 2px dotted #555;
- padding-bottom: 1px;
-}
-
-#filter-box
-{
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- border: 1px solid #999999;
- overflow: hidden;
- /* css hack for IE */
- width: expression((parseInt(this.parentNode.offsetWidth)-20-parseInt(document.getElementById('filterslistbox').offsetWidth))+'px');
- height: expression(parseInt(this.parentNode.offsetHeight)+'px');
-}
-
-#filter-frame
-{
- border: none;
-}
-
-body.iframe
-{
- min-width: 620px;
- width: expression(Math.max(620, document.documentElement.clientWidth)+'px');
- background-color: #F2F2F2;
-}
-
-#filter-form
-{
- min-width: 550px;
- width: expression(Math.max(550, document.documentElement.clientWidth)+'px');
- white-space: nowrap;
- padding: 20px 10px 10px 10px;
-}
-
-#filter-form legend, #filter-form label
-{
- color: #666666;
-}
-
-#rules, #actions
-{
- margin-top: 5px;
- padding: 0;
- border-collapse: collapse;
-}
-
-div.rulerow, div.actionrow
-{
- width: auto;
- padding: 2px;
- white-space: nowrap;
- border: 1px solid #F2F2F2;
-}
-
-div.rulerow:hover, div.actionrow:hover
-{
- padding: 2px;
- white-space: nowrap;
- background: #F9F9F9;
- border: 1px solid silver;
-}
-
-div.rulerow table, div.actionrow table
-{
- padding: 0px;
- 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
-{
- text-align: right;
- white-space: nowrap;
- width: 1%;
-}
-
-td.rowactions
-{
- white-space: nowrap;
- width: 1%;
- padding-top: 2px;
-}
-
-td.rowtargets
-{
- white-space: nowrap;
- width: 98%;
- padding-left: 3px;
- padding-top: 2px;
-}
-
-td.rowtargets > div
-{
- vertical-align: top;
- margin-top: 2px;
-}
-
-td.rowtargets div.adv
-{
- padding-top: 3px;
-}
-
-td.rowtargets div.adv span.label
-{
- display: inline-block;
- padding-right: 10px;
- min-width: 65px;
-}
-
-html.mozilla #filter-form select
-{
- padding-top: 3px;
- padding-bottom: 3px;
-}
-
-input.disabled, input.disabled:hover
-{
- color: #999999;
-}
-
-input.error, textarea.error
-{
- background-color: #FFFF88;
-}
-
-input.box,
-input.radio
-{
- border: 0;
- margin-top: 0;
-}
-
-select.operator_selector
-{
- width: 200px;
- vertical-align: top;
-}
-
-td.rowtargets span,
-span.label
-{
- color: #666666;
- font-size: 10px;
- white-space: nowrap;
-}
-
-td.rowtargets label
-{
- color: black;
-}
-
-#footer
-{
- padding-top: 5px;
- width: 100%;
-}
-
-#footer .footerleft
-{
- padding-left: 2px;
- white-space: nowrap;
- float: left;
-}
-
-#footer .footerright
-{
- padding-right: 2px;
- white-space: nowrap;
- text-align: right;
- float: right;
-}
-
-.itemlist
-{
- line-height: 25px;
-}
-
-.itemlist input
-{
- vertical-align: middle;
-}
-
-span.sieve.error
-{
- color: red;
-}
-
-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;
- vertical-align: middle;
-}
-
-/* smart multi-row input field */
-.listarea
-{
- border: 1px solid #666;
- margin: 0;
- padding: 1px;
- display: inline-block;
- max-height: 67px;
- overflow-y: auto;
-}
-
-td.rowtargets > span.listarea
-{
- vertical-align: top;
- margin-top: 2px;
-}
-
-.listelement
-{
- display: block;
- white-space: nowrap;
- background-color: #fff;
- border-top: 1px solid #e2e2e2;
- height: 16px;
- padding: 0;
- margin: 0;
- overflow: hidden;
- line-height: 16px;
-}
-
-.listarea.error .listelement
-{
- background-color: #FFFFC4;
-}
-
-.listelement:first-child
-{
- border-top: none;
-}
-
-#filter-form .listelement input
-{
- border: none;
- border-radius: 0;
- box-shadow: none;
- outline: none;
- vertical-align: top;
- height: 16px;
- padding-top: 0;
- padding-bottom: 0;
- line-height: 16px;
- background-color: transparent;
-}
-
-.listelement input:focus
-{
- box-shadow: none;
-}
-
-.listelement .reset
-{
- display: inline-block;
- width: 16px;
- height: 16px;
- background: url(images/erase.png) -1px 0 no-repeat #eee;
- cursor: pointer;
-}
-
-
-/* fixes for popup window */
-
-body.iframe.mail
-{
- margin: 0;
- padding: 0;
-}
-
-body.iframe.mail #filter-form
-{
- padding: 10px 5px 5px 5px;
-}
-
-#vacationform .listarea {
- max-height: 75px;
-}
-
-#vacationform .listelement,
-#vacationform .listelement .reset {
- height: 18px;
-}
-
-#vacationform .listelement .reset {
- background-position: -1px 1px;
-}
-
-#vacationform .listelement input {
- vertical-align: top;
- border: 0;
-}
diff --git a/lib/plugins/managesieve/skins/classic/managesieve_mail.css b/lib/plugins/managesieve/skins/classic/managesieve_mail.css
deleted file mode 100644
index 1ade4f7..0000000
--- a/lib/plugins/managesieve/skins/classic/managesieve_mail.css
+++ /dev/null
@@ -1,62 +0,0 @@
-#messagemenu li a.filterlink {
- background-image: url(images/filter.png);
- background-position: 7px 1px;
-}
-
-#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
-{
- z-index: 100000;
-}
-
-span.sieve.error
-{
- color: red;
-}
diff --git a/lib/plugins/managesieve/skins/classic/templates/filteredit.html b/lib/plugins/managesieve/skins/classic/templates/filteredit.html
deleted file mode 100644
index 8cef816..0000000
--- a/lib/plugins/managesieve/skins/classic/templates/filteredit.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<title><roundcube:object name="pagetitle" /></title>
-<roundcube:include file="/includes/links.html" />
-</head>
-<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" />
-</div>
-<div class="footerright">
-<label for="disabled"><roundcube:label name="managesieve.filterdisabled" /></label>
-<input type="checkbox" id="disabled" name="_disabled" value="1" />
-</div>
-</div>
-<roundcube:endif />
-
-</form>
-</div>
-
-</body>
-</html>
diff --git a/lib/plugins/managesieve/skins/classic/templates/managesieve.html b/lib/plugins/managesieve/skins/classic/templates/managesieve.html
deleted file mode 100644
index 6489d23..0000000
--- a/lib/plugins/managesieve/skins/classic/templates/managesieve.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<title><roundcube:object name="pagetitle" /></title>
-<roundcube:include file="/includes/links.html" />
-<script type="text/javascript" src="/functions.js"></script>
-<script type="text/javascript" src="/splitter.js"></script>
-
-<style type="text/css">
-#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; }
-#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; }
-</style>
-
-</head>
-<body>
-
-<roundcube:include file="/includes/taskbar.html" />
-<roundcube:include file="/includes/header.html" />
-<roundcube:include file="/includes/settingstabs.html" />
-
-<div id="mainscreen">
-
-<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>
-
-<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 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" />
-</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>
-
-<script type="text/javascript">
-rcube_init_mail_ui();
-</script>
-
-</body>
-</html>
diff --git a/lib/plugins/managesieve/skins/classic/templates/setedit.html b/lib/plugins/managesieve/skins/classic/templates/setedit.html
deleted file mode 100644
index c1010ca..0000000
--- a/lib/plugins/managesieve/skins/classic/templates/setedit.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<title><roundcube:object name="pagetitle" /></title>
-<roundcube:include file="/includes/links.html" />
-</head>
-<body class="iframe">
-
-<div id="filter-title" class="boxtitle"><roundcube:label name="managesieve.newfilterset" /></div>
-
-<div id="filter-form" class="boxcontent">
-<roundcube:object name="filtersetform" />
-
-<p>
-<roundcube:button command="plugin.managesieve-save" type="input" class="button mainaction" label="save" />
-</p>
-
-</form>
-</div>
-
-
-</body>
-</html>
diff --git a/lib/plugins/managesieve/skins/classic/templates/vacation.html b/lib/plugins/managesieve/skins/classic/templates/vacation.html
deleted file mode 100644
index 26e408e..0000000
--- a/lib/plugins/managesieve/skins/classic/templates/vacation.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<title><roundcube:object name="pagetitle" /></title>
-<roundcube:include file="/includes/links.html" />
-<script type="text/javascript" src="/functions.js"></script>
-</head>
-<body>
-
-<roundcube:include file="/includes/taskbar.html" />
-<roundcube:include file="/includes/header.html" />
-<roundcube:include file="/includes/settingstabs.html" />
-
-<div id="mainscreen">
- <div class="box" style="height: 100%; overflow: auto">
- <div id="prefs-title" class="boxtitle"><roundcube:label name="managesieve.vacation" /></div>
- <roundcube:object name="vacationform" id="vacationform" style="margin: 10px 10px 0 10px" />
- <div id="formfooter" style="padding: 0 10px">
- <div class="footerleft">
- <roundcube:button command="plugin.managesieve-save" type="input" class="button mainaction" label="save" />
- </div>
- </div>
- </div>
-</div>
-
-<script type="text/javascript">
-rcube_init_mail_ui();
-</script>
-
-</body>
-</html>
diff --git a/lib/plugins/managesieve/skins/larry/images/add.png b/lib/plugins/managesieve/skins/larry/images/add.png
deleted file mode 100644
index 97a6422..0000000
Binary files a/lib/plugins/managesieve/skins/larry/images/add.png and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/larry/images/del.png b/lib/plugins/managesieve/skins/larry/images/del.png
deleted file mode 100644
index 518905b..0000000
Binary files a/lib/plugins/managesieve/skins/larry/images/del.png and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/larry/images/down_small.gif b/lib/plugins/managesieve/skins/larry/images/down_small.gif
deleted file mode 100644
index f865893..0000000
Binary files a/lib/plugins/managesieve/skins/larry/images/down_small.gif and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/larry/images/erase.png b/lib/plugins/managesieve/skins/larry/images/erase.png
deleted file mode 100644
index ddd3a97..0000000
Binary files a/lib/plugins/managesieve/skins/larry/images/erase.png and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/larry/images/up_small.gif b/lib/plugins/managesieve/skins/larry/images/up_small.gif
deleted file mode 100644
index 40deb89..0000000
Binary files a/lib/plugins/managesieve/skins/larry/images/up_small.gif and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/larry/images/vacation_icons.png b/lib/plugins/managesieve/skins/larry/images/vacation_icons.png
deleted file mode 100644
index f8933d4..0000000
Binary files a/lib/plugins/managesieve/skins/larry/images/vacation_icons.png and /dev/null differ
diff --git a/lib/plugins/managesieve/skins/larry/managesieve.css b/lib/plugins/managesieve/skins/larry/managesieve.css
deleted file mode 100644
index 47e992c..0000000
--- a/lib/plugins/managesieve/skins/larry/managesieve.css
+++ /dev/null
@@ -1,450 +0,0 @@
-#filtersetslistbox
-{
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- width: 150px;
-}
-
-#filtersscreen
-{
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 162px;
-}
-
-#filterslistbox
-{
- position: absolute;
- left: 0;
- top: 0;
- bottom: 0;
- width: 180px;
-}
-
-#filter-box
-{
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 192px;
-}
-
-#filter-frame
-{
- border-radius: 4px;
-}
-
-#filterslist,
-#filtersetslist
-{
- width: 100%;
- table-layout: fixed;
-}
-
-#filterslist tbody td,
-#filtersetslist tbody td
-{
- width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-#filterslist tbody tr.disabled td,
-#filtersetslist tbody tr.disabled td
-{
- color: #87A3AA;
-}
-
-#filtersetslist tbody td
-{
- font-weight: bold;
-}
-
-#filterslist tbody tr.filtermoveup td
-{
- border-top: 2px dotted #555;
- padding-top: 5px;
-}
-
-#filterslist tbody tr.filtermovedown td
-{
- border-bottom: 2px dotted #555;
- padding-bottom: 4px;
-}
-
-body.iframe
-{
- min-width: 620px;
-}
-
-#filter-form
-{
- min-width: 550px;
- white-space: nowrap;
- padding: 20px 10px 10px 10px;
-}
-
-#filter-form legend, #filter-form label
-{
- color: #666666;
-}
-
-#rules, #actions
-{
- margin-top: 5px;
- padding: 0;
- border-collapse: collapse;
-}
-
-div.rulerow, div.actionrow
-{
- width: auto;
- padding: 2px;
- white-space: nowrap;
- border: 1px solid white;
-}
-
-div.rulerow:hover, div.actionrow:hover
-{
- padding: 2px;
- white-space: nowrap;
- background-color: #D9ECF4;
- border: 1px solid #BBD3DA;
- border-radius: 4px;
-}
-
-div.rulerow table, div.actionrow table
-{
- padding: 0px;
- min-width: 600px;
-}
-
-#filter-form 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
-{
- text-align: right;
- white-space: nowrap;
- width: 1%;
-}
-
-td.rowactions
-{
- white-space: nowrap;
- width: 1%;
- padding-top: 2px;
-}
-
-td.rowtargets
-{
- white-space: nowrap;
- width: 98%;
- padding-left: 3px;
- padding-top: 2px;
-}
-
-td.rowtargets > div
-{
- vertical-align: top;
- margin-top: 2px;
-}
-
-td.rowtargets div.adv
-{
- padding-top: 3px;
- font-size: 10px;
-}
-
-td.rowtargets div.adv span.label
-{
- display: inline-block;
- padding-right: 5px;
- min-width: 70px;
-}
-
-input.disabled, input.disabled:hover
-{
- color: #999999;
-}
-
-input.error, textarea.error
-{
- background-color: #FFFFC4;
-}
-
-input.box,
-input.radio
-{
- border: 0;
- margin-top: 0;
-}
-
-input.radio
-{
- vertical-align: middle;
-}
-
-select.operator_selector
-{
- width: 200px;
- vertical-align: top;
-}
-
-td.rowtargets span,
-span.label
-{
- color: #666666;
- font-size: 10px;
- white-space: nowrap;
-}
-
-td.rowtargets label
-{
- color: black;
-}
-
-#footer
-{
- padding-top: 5px;
- width: 100%;
-}
-
-#footer .footerleft label
-{
- margin-left: 40px;
- white-space: nowrap;
-}
-
-.itemlist
-{
- line-height: 25px;
-}
-
-.itemlist input
-{
- vertical-align: middle;
-}
-
-span.sieve.error
-{
- color: red;
- white-space: nowrap;
-}
-
-#managesieve-tip
-{
- padding: 3px;
- background-color: #eee;
-}
-
-a.button
-{
- margin: 0;
- padding: 0;
-}
-
-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;
- padding: 1px;
- vertical-align: middle;
- max-width: 280px;
-}
-
-/* revert larry style button */
-#filter-form input.button
-{
- padding: inherit;
-}
-
-fieldset
-{
- border-radius: 4px;
-}
-
-/* smart multi-row input field */
-.listarea
-{
- border: 1px solid #B2B2B2;
- border-radius: 4px;
- box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1);
- -webkit-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1);
- margin: 0;
- padding: 2px;
- display: inline-block;
- max-height: 59px;
- overflow-y: auto;
-}
-
-td.rowtargets > span.listarea
-{
- vertical-align: top;
- margin-top: 2px;
-}
-
-.listelement
-{
- display: block;
- white-space: nowrap;
- background-color: #fff;
- border-top: 1px solid #e2e2e2;
- height: 14px;
- padding: 0;
- margin: 0;
- overflow: hidden;
- line-height: 14px;
-}
-
-.listarea.error .listelement
-{
- background-color: #FFFFC4;
-}
-
-.listelement:first-child
-{
- border-top: none;
-}
-
-#filter-form .listelement input
-{
- border: none;
- border-radius: 0;
- box-shadow: none;
- outline: none;
- vertical-align: top;
- height: 14px;
- padding-top: 0;
- padding-bottom: 0;
- line-height: 14px;
- background-color: transparent;
-}
-
-.listelement input:focus
-{
- box-shadow: none;
-}
-
-.listelement .reset
-{
- display: inline-block;
- width: 16px;
- height: 16px;
- background: url(images/erase.png) -1px -1px no-repeat #eee;
- cursor: pointer;
-}
-
-
-/* fixes for popup window */
-
-body.iframe.mail
-{
- margin: 0;
- padding: 0;
-}
-
-body.iframe.mail #filter-form
-{
- padding: 10px 5px 5px 5px;
-}
-
-
-/* vacation form */
-#settings-sections .vacation a {
- background-image: url(images/vacation_icons.png);
- background-repeat: no-repeat;
- background-position: 7px 1px;
-}
-
-#settings-sections .vacation.selected a {
- background-position: 7px -23px;
-}
-
-#managesieve-vacation {
- position: absolute;
- top: 0;
- left: 212px;
- right: 0;
- bottom: 0;
- overflow: auto;
-}
-
-#vacationform .listarea {
- max-height: 91px;
-}
-
-#vacationform .listelement,
-#vacationform .listelement .reset {
- height: 22px;
-}
-
-#vacationform .listelement .reset {
- background-position: -1px 3px;
-}
-
-#vacationform .listelement input {
- vertical-align: top;
- border: 0;
- box-shadow: none;
-}
-
-#vacationform td.vacation {
- white-space: nowrap;
-}
diff --git a/lib/plugins/managesieve/skins/larry/managesieve_mail.css b/lib/plugins/managesieve/skins/larry/managesieve_mail.css
deleted file mode 100644
index 855aa8e..0000000
--- a/lib/plugins/managesieve/skins/larry/managesieve_mail.css
+++ /dev/null
@@ -1,62 +0,0 @@
-ul.toolbarmenu li span.filterlink {
- background-position: 0 -2174px;
-}
-
-#sievefilterform {
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- padding: 0;
- overflow: hidden;
-}
-
-#sievefilterform iframe {
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- width: 100%;
- min-height: 100%; /* Chrome 14 bug */
- border: 0;
- padding: 0;
- margin: 0;
-}
-
-#sievefilterform ul {
- list-style: none;
- padding: 0;
- margin: 0;
- margin-top: 5px;
-}
-
-#sievefilterform fieldset {
- margin: 5px;
- border-radius: 4px;
-}
-
-#sievefilterform ul li {
- margin-bottom: 5px;
- white-space: nowrap;
-}
-
-#sievefilterform ul li input {
- margin-right: 5px;
-}
-
-#sievefilterform label {
- font-weight: bold;
-}
-
-#managesieve-tip
-{
- z-index: 100000;
- padding: 3px;
- background-color: #eee;
-}
-
-span.sieve.error
-{
- color: red;
- white-space: nowrap;
-}
diff --git a/lib/plugins/managesieve/skins/larry/templates/filteredit.html b/lib/plugins/managesieve/skins/larry/templates/filteredit.html
deleted file mode 100644
index 1933b58..0000000
--- a/lib/plugins/managesieve/skins/larry/templates/filteredit.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<roundcube:object name="doctype" value="html5" />
-<html>
-<head>
-<title><roundcube:object name="pagetitle" /></title>
-<roundcube:include file="/includes/links.html" />
-</head>
-<body class="iframe<roundcube:exp expression="env:task != 'mail' ? ' floatingbuttons' : ' 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 formbuttons floating">
-<roundcube:button command="plugin.managesieve-save" type="input" class="button mainaction" label="save" />
-<label for="disabled">
-<input type="checkbox" id="disabled" name="_disabled" value="1" />
-<roundcube:label name="managesieve.filterdisabled" />
-</label>
-</div>
-</div>
-<roundcube:endif />
-
-</form>
-</div>
-
-</body>
-</html>
diff --git a/lib/plugins/managesieve/skins/larry/templates/managesieve.html b/lib/plugins/managesieve/skins/larry/templates/managesieve.html
deleted file mode 100644
index 494af6a..0000000
--- a/lib/plugins/managesieve/skins/larry/templates/managesieve.html
+++ /dev/null
@@ -1,79 +0,0 @@
-<roundcube:object name="doctype" value="html5" />
-<html>
-<head>
-<title><roundcube:object name="pagetitle" /></title>
-<roundcube:include file="/includes/links.html" />
-</head>
-<roundcube:if condition="env:extwin" /><body class="noscroll extwin"><roundcube:else /><body class="noscroll"><roundcube:endif />
-
-<roundcube:include file="/includes/header.html" />
-
-<h1 class="voice"><roundcube:label name="settings" /> : <roundcube:label name="managesieve.filters" /></h1>
-
-<div id="mainscreen" class="offset">
-
-<roundcube:include file="/includes/settingstabs.html" />
-
-<div id="settings-right" role="main">
-<div id="filtersetslistbox" class="uibox listbox" aria-labelledby="aria-label-filtersets">
-<h2 class="boxtitle" id="aria-label-filtersets"><roundcube:label name="managesieve.filtersets" /></h2>
-<div class="scroller withfooter">
- <roundcube:object name="filtersetslist" id="filtersetslist" class="listing" summary="managesieve.ariasummaryfiltersetslist" type="list" noheader="true" role="listbox" />
-</div>
-<div class="boxfooter">
- <roundcube:button command="plugin.managesieve-setadd" type="link" title="managesieve.filtersetadd" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" content="+" /><roundcube:button name="filtersetmenulink" id="filtersetmenulink" type="link" title="moreactions" class="listbutton groupactions" onclick="return UI.toggle_popup('filtersetmenu', event)" innerClass="inner" content="&#9881;" aria-haspopup="true" aria-expanded="false" aria-owns="filtersetmenu-menu" />
-</div>
-</div>
-
-<div id="filtersscreen">
-<div id="filterslistbox" class="uibox listbox" aria-labelledby="aria-label-filters">
-<h2 class="boxtitle" id="aria-label-filters"><roundcube:label name="managesieve.filters" /></h2>
-<div class="scroller withfooter">
- <roundcube:object name="filterslist" id="filterslist" class="listing" summary="managesieve.ariasummaryfilterslist" noheader="true" role="listbox" />
-</div>
-<div class="boxfooter">
- <roundcube:button command="plugin.managesieve-add" type="link" title="managesieve.filteradd" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" content="+" /><roundcube:button name="filtermenulink" id="filtermenulink" type="link" title="moreactions" class="listbutton groupactions" onclick="return UI.toggle_popup('filtermenu', event)" innerClass="inner" content="&#9881;" aria-haspopup="true" aria-expanded="false" aria-owns="filtermenu-menu" />
-</div>
-</div>
-
-<div id="filter-box" class="uibox contentbox">
- <div class="iframebox" role="complementary" aria-labelledby="aria-label-filterform">
- <h2 id="aria-label-filterframe" class="voice"><roundcube:label name="managesieve.arialabelfilterform" /></h2>
- <roundcube:object name="filterframe" id="filter-frame" style="width:100%; height:100%" frameborder="0" src="/watermark.html" title="managesieve.arialabelfilterform" />
- </div>
-</div>
-
-</div>
-</div>
-</div>
-
-<div id="filtersetmenu" class="popupmenu" aria-hidden="true">
- <h3 id="aria-label-setactions" class="voice"><roundcube:label name="managesieve.arialabelfiltersetactions" /></h3>
- <ul class="toolbarmenu" id="filtersetmenu-menu" role="menu" aria-labelledby="aria-label-setactions">
- <li role="menuitem"><roundcube:button command="plugin.managesieve-setact" label="managesieve.enable" classAct="active" /></li>
- <li role="menuitem"><roundcube:button command="plugin.managesieve-setdel" label="delete" classAct="active" /></li>
- <li role="menuitem" 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" aria-hidden="true">
- <h3 id="aria-label-filteractions" class="voice"><roundcube:label name="managesieve.arialabelfilteractions" /></h3>
- <ul class="toolbarmenu" id="filtermenu-menu" role="menu" aria-labelledby="aria-label-filteractions">
- <li role="menuitem"><roundcube:button command="plugin.managesieve-act" label="managesieve.enable" classAct="active" /></li>
- <li role="menuitem"><roundcube:button command="plugin.managesieve-del" label="delete" classAct="active" /></li>
- <roundcube:container name="filteroptions" id="filtermenu" />
- </ul>
-</div>
-
-<roundcube:include file="/includes/footer.html" />
-
-<script type="text/javascript">
- new rcube_splitter({ id:'managesievesplitter1', p1:'#filtersetslistbox', p2:'#filtersscreen',
- orientation:'v', relative:true, start:156, min:120, size:12 }).init();
- new rcube_splitter({ id:'managesievesplitter2', p1:'#filterslistbox', p2:'#filter-box',
- orientation:'v', relative:true, start:186, min:120, size:12 }).init();
-</script>
-
-</body>
-</html>
diff --git a/lib/plugins/managesieve/skins/larry/templates/setedit.html b/lib/plugins/managesieve/skins/larry/templates/setedit.html
deleted file mode 100644
index 3b8f98b..0000000
--- a/lib/plugins/managesieve/skins/larry/templates/setedit.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<roundcube:object name="doctype" value="html5" />
-<html>
-<head>
-<title><roundcube:object name="pagetitle" /></title>
-<roundcube:include file="/includes/links.html" />
-</head>
-<body class="iframe floatingbuttons">
-
-<div id="filter-title" class="boxtitle"><roundcube:label name="managesieve.newfilterset" /></div>
-
-<div id="filter-form" class="boxcontent">
-<roundcube:object name="filtersetform" />
-
-<div id="footer">
-<div class="footerleft formbuttons floating">
-<roundcube:button command="plugin.managesieve-save" type="input" class="button mainaction" label="save" />
-</div>
-</div>
-
-</form>
-</div>
-
-</body>
-</html>
diff --git a/lib/plugins/managesieve/skins/larry/templates/vacation.html b/lib/plugins/managesieve/skins/larry/templates/vacation.html
deleted file mode 100644
index 26dd202..0000000
--- a/lib/plugins/managesieve/skins/larry/templates/vacation.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<roundcube:object name="doctype" value="html5" />
-<html>
-<head>
-<title><roundcube:object name="pagetitle" /></title>
-<roundcube:include file="/includes/links.html" />
-</head>
-<body class="noscroll">
-
-<roundcube:include file="/includes/header.html" />
-
-<div id="mainscreen" class="offset">
-
-<h1 class="voice"><roundcube:label name="settings" /> : <roundcube:label name="managesieve.vacation" /></h1>
-
-<roundcube:include file="/includes/settingstabs.html" />
-
-<div id="managesieve-vacation" class="uibox contentbox" role="main" aria-labelledby="aria-label-vacationform">
- <div>
- <h2 class="boxtitle" id="aria-label-vacationform"><roundcube:label name="managesieve.vacation" /></h2>
- <roundcube:object name="vacationform" id="vacationform" class="propform boxcontent tabbed" />
- </div>
- <div class="footerleft formbuttons">
- <roundcube:button command="plugin.managesieve-save" type="input" class="button mainaction" label="save" />
- </div>
-</div>
-
-</div>
-
-<roundcube:include file="/includes/footer.html" />
-
-</body>
-</html>
diff --git a/lib/plugins/managesieve/tests/Managesieve.php b/lib/plugins/managesieve/tests/Managesieve.php
deleted file mode 100644
index 6e930b8..0000000
--- a/lib/plugins/managesieve/tests/Managesieve.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-
-class Managesieve_Plugin extends PHPUnit_Framework_TestCase
-{
-
- function setUp()
- {
- include_once __DIR__ . '/../managesieve.php';
- }
-
- /**
- * Plugin object construction test
- */
- function test_constructor()
- {
- $rcube = rcube::get_instance();
- $plugin = new managesieve($rcube->api);
-
- $this->assertInstanceOf('managesieve', $plugin);
- $this->assertInstanceOf('rcube_plugin', $plugin);
- }
-}
-
diff --git a/lib/plugins/managesieve/tests/Parser.php b/lib/plugins/managesieve/tests/Parser.php
deleted file mode 100644
index 33edce0..0000000
--- a/lib/plugins/managesieve/tests/Parser.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-
-class Parser extends PHPUnit_Framework_TestCase
-{
-
- function setUp()
- {
- include_once __DIR__ . '/../lib/Roundcube/rcube_sieve_script.php';
- }
-
- /**
- * Sieve script parsing
- *
- * @dataProvider data_parser
- */
- function test_parser($input, $output, $message)
- {
- // get capabilities list from the script
- $caps = array();
- if (preg_match('/require \[([a-z0-9", ]+)\]/', $input, $m)) {
- foreach (explode(',', $m[1]) as $cap) {
- $caps[] = trim($cap, '" ');
- }
- }
-
- $script = new rcube_sieve_script($input, $caps);
- $result = $script->as_text();
-
- $this->assertEquals(trim($result), trim($output), $message);
- }
-
- /**
- * Data provider for test_parser()
- */
- function data_parser()
- {
- $dir_path = realpath(__DIR__ . '/src');
- $dir = opendir($dir_path);
- $result = array();
-
- while ($file = readdir($dir)) {
- if (preg_match('/^[a-z0-9_]+$/', $file)) {
- $input = file_get_contents($dir_path . '/' . $file);
-
- if (file_exists($dir_path . '/' . $file . '.out')) {
- $output = file_get_contents($dir_path . '/' . $file . '.out');
- }
- else {
- $output = $input;
- }
-
- $result[] = array(
- 'input' => $input,
- 'output' => $output,
- 'message' => "Error in parsing '$file' file",
- );
- }
- }
-
- return $result;
- }
-}
diff --git a/lib/plugins/managesieve/tests/Tokenizer.php b/lib/plugins/managesieve/tests/Tokenizer.php
deleted file mode 100644
index f50ed75..0000000
--- a/lib/plugins/managesieve/tests/Tokenizer.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-class Tokenizer extends PHPUnit_Framework_TestCase
-{
-
- function setUp()
- {
- include_once __DIR__ . '/../lib/Roundcube/rcube_sieve_script.php';
- }
-
- function data_tokenizer()
- {
- return array(
- array(1, "text: #test\nThis is test ; message;\nMulti line\n.\n;\n", '"This is test ; message;\nMulti line"'),
- array(0, '["test1","test2"]', '[["test1","test2"]]'),
- array(1, '["test"]', '["test"]'),
- array(1, '"te\\"st"', '"te\\"st"'),
- array(0, 'test #comment', '["test"]'),
- array(0, "text:\ntest\n.\ntext:\ntest\n.\n", '["test","test"]'),
- array(1, '"\\a\\\\\\"a"', '"a\\\\\\"a"'),
- );
- }
-
- /**
- * @dataProvider data_tokenizer
- */
- function test_tokenizer($num, $input, $output)
- {
- $res = json_encode(rcube_sieve_script::tokenize($input, $num));
-
- $this->assertEquals(trim($res), trim($output));
- }
-}
diff --git a/lib/plugins/managesieve/tests/Vacation.php b/lib/plugins/managesieve/tests/Vacation.php
deleted file mode 100644
index 942525c..0000000
--- a/lib/plugins/managesieve/tests/Vacation.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-class Managesieve_Vacation extends PHPUnit_Framework_TestCase
-{
-
- function setUp()
- {
- include_once __DIR__ . '/../lib/Roundcube/rcube_sieve_engine.php';
- include_once __DIR__ . '/../lib/Roundcube/rcube_sieve_vacation.php';
- }
-
- /**
- * Plugin object construction test
- */
- function test_constructor()
- {
- $vacation = new rcube_sieve_vacation(true);
-
- $this->assertInstanceOf('rcube_sieve_vacation', $vacation);
- }
-
- function test_build_regexp_tests()
- {
- $tests = rcube_sieve_vacation::build_regexp_tests('2014-02-20', '2014-03-05', $error);
-
- $this->assertCount(2, $tests);
- $this->assertSame('header', $tests[0]['test']);
- $this->assertSame('regex', $tests[0]['type']);
- $this->assertSame('received', $tests[0]['arg1']);
- $this->assertSame('(20|21|22|23|24|25|26|27|28) Feb 2014', $tests[0]['arg2']);
- $this->assertSame('header', $tests[1]['test']);
- $this->assertSame('regex', $tests[1]['type']);
- $this->assertSame('received', $tests[1]['arg1']);
- $this->assertSame('([ 0]1|[ 0]2|[ 0]3|[ 0]4|[ 0]5) Mar 2014', $tests[1]['arg2']);
-
- $tests = rcube_sieve_vacation::build_regexp_tests('2014-02-20', '2014-01-05', $error);
-
- $this->assertSame(null, $tests);
- $this->assertSame('managesieve.invaliddateformat', $error);
- }
-
- function test_parse_regexp_tests()
- {
- $tests = array(
- array(
- 'test' => 'header',
- 'type' => 'regex',
- 'arg1' => 'received',
- 'arg2' => '(20|21|22|23|24|25|26|27|28) Feb 2014',
- ),
- array(
- 'test' => 'header',
- 'type' => 'regex',
- 'arg1' => 'received',
- 'arg2' => '([ 0]1|[ 0]2|[ 0]3|[ 0]4|[ 0]5) Mar 2014',
- )
- );
-
- $result = rcube_sieve_vacation::parse_regexp_tests($tests);
-
- $this->assertCount(2, $result);
- $this->assertSame('20 Feb 2014', $result['from']);
- $this->assertSame('05 Mar 2014', $result['to']);
- }
-}
-
diff --git a/lib/plugins/managesieve/tests/src/parser b/lib/plugins/managesieve/tests/src/parser
deleted file mode 100644
index c99b498..0000000
--- a/lib/plugins/managesieve/tests/src/parser
+++ /dev/null
@@ -1,52 +0,0 @@
-require ["fileinto","reject","envelope"];
-# rule:[spam]
-if anyof (header :contains "X-DSPAM-Result" "Spam")
-{
- fileinto "Spam";
- stop;
-}
-# rule:[test1]
-if anyof (header :contains :comparator "i;ascii-casemap" ["From","To"] "test@domain.tld")
-{
- discard;
- stop;
-}
-# rule:[test2]
-if anyof (not header :contains :comparator "i;octet" ["Subject"] "[test]", header :contains "Subject" "[test2]")
-{
- fileinto "test";
- stop;
-}
-# rule:[comments]
-if anyof (true) /* comment
- * "comment" #comment */ {
- /* comment */ stop;
-# comment
-}
-# rule:[reject]
-if size :over 5000K {
- 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;
-}
-fileinto "Test";
-# rule:[address test]
-if address :all :is "From" "nagios@domain.tld"
-{
- fileinto "domain.tld";
- stop;
-}
-# rule:[envelope test]
-if envelope :domain :is "From" "domain.tld"
-{
- fileinto "domain.tld";
- stop;
-}
diff --git a/lib/plugins/managesieve/tests/src/parser.out b/lib/plugins/managesieve/tests/src/parser.out
deleted file mode 100644
index 796343d..0000000
--- a/lib/plugins/managesieve/tests/src/parser.out
+++ /dev/null
@@ -1,52 +0,0 @@
-require ["envelope","fileinto","reject"];
-# rule:[spam]
-if header :contains "X-DSPAM-Result" "Spam"
-{
- fileinto "Spam";
- stop;
-}
-# rule:[test1]
-if header :contains ["From","To"] "test@domain.tld"
-{
- discard;
- stop;
-}
-# rule:[test2]
-if anyof (not header :contains :comparator "i;octet" "Subject" "[test]", header :contains "Subject" "[test2]")
-{
- fileinto "test";
- stop;
-}
-# rule:[comments]
-if true
-{
- stop;
-}
-# rule:[reject]
-if size :over 5000K
-{
- reject "Message over 5MB size limit. Please contact me before sending this.";
-}
-# rule:[false]
-if false # size :over 5000K
-{
- stop;
-}
-# rule:[true]
-if true
-{
- stop;
-}
-fileinto "Test";
-# rule:[address test]
-if address :is "From" "nagios@domain.tld"
-{
- fileinto "domain.tld";
- stop;
-}
-# rule:[envelope test]
-if envelope :domain :is "From" "domain.tld"
-{
- fileinto "domain.tld";
- stop;
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_body b/lib/plugins/managesieve/tests/src/parser_body
deleted file mode 100644
index bd142ed..0000000
--- a/lib/plugins/managesieve/tests/src/parser_body
+++ /dev/null
@@ -1,17 +0,0 @@
-require ["body","fileinto"];
-if body :raw :contains "MAKE MONEY FAST"
-{
- stop;
-}
-if body :content "text" :contains ["missile","coordinates"]
-{
- fileinto "secrets";
-}
-if body :content "audio/mp3" :contains ""
-{
- fileinto "jukebox";
-}
-if body :text :contains "project schedule"
-{
- fileinto "project/schedule";
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_date b/lib/plugins/managesieve/tests/src/parser_date
deleted file mode 100644
index 06b0033..0000000
--- a/lib/plugins/managesieve/tests/src/parser_date
+++ /dev/null
@@ -1,21 +0,0 @@
-require ["comparator-i;ascii-numeric","date","fileinto","relational"];
-# rule:[date]
-if allof (date :originalzone :value "ge" :comparator "i;ascii-numeric" "date" "hour" "09")
-{
- fileinto "urgent";
-}
-# rule:[date-weekday]
-if date :is "received" "weekday" "0"
-{
- fileinto "weekend";
-}
-# rule:[date-zone]
-if date :zone "-0500" :value "gt" :comparator "i;ascii-numeric" "received" "iso8601" "2007-02-26T09:00:00-05:00"
-{
- stop;
-}
-# rule:[currentdate]
-if anyof (currentdate :is "weekday" "0", currentdate :value "lt" :comparator "i;ascii-numeric" "hour" "09", currentdate :value "ge" :comparator "i;ascii-numeric" "date" "2007-06-30")
-{
- stop;
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_enotify_a b/lib/plugins/managesieve/tests/src/parser_enotify_a
deleted file mode 100644
index 68a9ef5..0000000
--- a/lib/plugins/managesieve/tests/src/parser_enotify_a
+++ /dev/null
@@ -1,19 +0,0 @@
-require ["enotify","variables"];
-# rule:[notify1]
-if header :contains "from" "boss@example.org"
-{
- notify :importance "1" :message "This is probably very important" "mailto:alm@example.com";
- stop;
-}
-# rule:[subject]
-if header :matches "Subject" "*"
-{
- set "subject" "${1}";
-}
-# rule:[from notify2]
-if header :matches "From" "*"
-{
- set "from" "${1}";
- notify :importance "3" :message "${from}: ${subject}" "mailto:alm@example.com";
-}
-
diff --git a/lib/plugins/managesieve/tests/src/parser_enotify_b b/lib/plugins/managesieve/tests/src/parser_enotify_b
deleted file mode 100644
index a3011ba..0000000
--- a/lib/plugins/managesieve/tests/src/parser_enotify_b
+++ /dev/null
@@ -1,18 +0,0 @@
-require ["enotify","envelope","variables"];
-# rule:[from]
-if envelope :matches "from" "*"
-{
- set "env_from" " [really: ${1}]";
-}
-# rule:[subject]
-if header :matches "Subject" "*"
-{
- set "subject" "${1}";
-}
-# rule:[from notify]
-if address :matches "from" "*"
-{
- set "from_addr" "${1}";
- notify :message "${from_addr}${env_from}: ${subject}" "mailto:alm@example.com";
-}
-
diff --git a/lib/plugins/managesieve/tests/src/parser_imapflags b/lib/plugins/managesieve/tests/src/parser_imapflags
deleted file mode 100644
index e67bf7c..0000000
--- a/lib/plugins/managesieve/tests/src/parser_imapflags
+++ /dev/null
@@ -1,7 +0,0 @@
-require ["imap4flags"];
-# rule:[imapflags]
-if header :matches "Subject" "^Test$"
-{
- setflag "\\Seen";
- addflag ["\\Answered","\\Deleted"];
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_include b/lib/plugins/managesieve/tests/src/parser_include
deleted file mode 100644
index b5585a4..0000000
--- a/lib/plugins/managesieve/tests/src/parser_include
+++ /dev/null
@@ -1,7 +0,0 @@
-require ["include"];
-include "script.sieve";
-# rule:[two]
-if true
-{
- include :optional "second.sieve";
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_index b/lib/plugins/managesieve/tests/src/parser_index
deleted file mode 100644
index ca9f86d..0000000
--- a/lib/plugins/managesieve/tests/src/parser_index
+++ /dev/null
@@ -1,24 +0,0 @@
-require ["comparator-i;ascii-numeric","date","fileinto","index","relational"];
-# rule:[index-header1]
-if header :index 1 :last :contains "X-DSPAM-Result" "Spam"
-{
- fileinto "Spam";
- stop;
-}
-# rule:[index-header2]
-if header :index 2 :contains ["From","To"] "test@domain.tld"
-{
- discard;
- stop;
-}
-# rule:[index-address]
-if address :index 1 :is "From" "nagios@domain.tld"
-{
- fileinto "domain.tld";
- stop;
-}
-# rule:[index-date]
-if date :index 1 :last :zone "-0500" :value "gt" :comparator "i;ascii-numeric" "received" "iso8601" "2007-02-26T09:00:00-05:00"
-{
- stop;
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_kep14 b/lib/plugins/managesieve/tests/src/parser_kep14
deleted file mode 100644
index 1ded8d8..0000000
--- a/lib/plugins/managesieve/tests/src/parser_kep14
+++ /dev/null
@@ -1,2 +0,0 @@
-# EDITOR Roundcube
-# EDITOR_VERSION 123
diff --git a/lib/plugins/managesieve/tests/src/parser_kep14.out b/lib/plugins/managesieve/tests/src/parser_kep14.out
deleted file mode 100644
index cb7faa7..0000000
--- a/lib/plugins/managesieve/tests/src/parser_kep14.out
+++ /dev/null
@@ -1,3 +0,0 @@
-require ["variables"];
-set "EDITOR" "Roundcube";
-set "EDITOR_VERSION" "123";
diff --git a/lib/plugins/managesieve/tests/src/parser_notify_a b/lib/plugins/managesieve/tests/src/parser_notify_a
deleted file mode 100644
index e51e2aa..0000000
--- a/lib/plugins/managesieve/tests/src/parser_notify_a
+++ /dev/null
@@ -1,18 +0,0 @@
-require ["notify","variables"];
-# rule:[notify1]
-if header :contains "from" "boss@example.org"
-{
- notify :low :message "This is probably very important";
- stop;
-}
-# rule:[subject]
-if header :matches "Subject" "*"
-{
- set "subject" "${1}";
-}
-# rule:[from notify2]
-if header :matches "From" "*"
-{
- set "from" "${1}";
- notify :high :method "mailto" :options "test@example.org" :message "${from}: ${subject}";
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_notify_b b/lib/plugins/managesieve/tests/src/parser_notify_b
deleted file mode 100644
index f942e15..0000000
--- a/lib/plugins/managesieve/tests/src/parser_notify_b
+++ /dev/null
@@ -1,17 +0,0 @@
-require ["envelope","notify","variables"];
-# rule:[from]
-if envelope :matches "from" "*"
-{
- set "env_from" " [really: ${1}]";
-}
-# rule:[subject]
-if header :matches "Subject" "*"
-{
- set "subject" "${1}";
-}
-# rule:[from notify]
-if address :matches "from" "*"
-{
- set "from_addr" "${1}";
- notify :method "sms" :options "1234567890" :message "${from_addr}${env_from}: ${subject}";
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_prefix b/lib/plugins/managesieve/tests/src/parser_prefix
deleted file mode 100644
index 9f6a33a..0000000
--- a/lib/plugins/managesieve/tests/src/parser_prefix
+++ /dev/null
@@ -1,5 +0,0 @@
-# this is a comment
-# and the second line
-
-require ["variables"];
-set "b" "c";
diff --git a/lib/plugins/managesieve/tests/src/parser_relational b/lib/plugins/managesieve/tests/src/parser_relational
deleted file mode 100644
index 92c5e1a..0000000
--- a/lib/plugins/managesieve/tests/src/parser_relational
+++ /dev/null
@@ -1,6 +0,0 @@
-require ["comparator-i;ascii-numeric","relational"];
-# rule:[redirect]
-if header :value "ge" :comparator "i;ascii-numeric" "X-Spam-score" "14"
-{
- redirect "test@test.tld";
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_subaddress b/lib/plugins/managesieve/tests/src/parser_subaddress
deleted file mode 100644
index e445550..0000000
--- a/lib/plugins/managesieve/tests/src/parser_subaddress
+++ /dev/null
@@ -1,11 +0,0 @@
-require ["envelope","fileinto","subaddress"];
-if envelope :user "To" "postmaster"
-{
- fileinto "postmaster";
- stop;
-}
-if envelope :detail :is "To" "mta-filters"
-{
- fileinto "mta-filters";
- stop;
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_vacation b/lib/plugins/managesieve/tests/src/parser_vacation
deleted file mode 100644
index 93026db..0000000
--- a/lib/plugins/managesieve/tests/src/parser_vacation
+++ /dev/null
@@ -1,12 +0,0 @@
-require ["vacation"];
-# rule:[test-vacation]
-if header :contains "Subject" "vacation"
-{
- vacation :days 1 text:
-# test
-test test /* test */
-test
-.
-;
- stop;
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_vacation_seconds b/lib/plugins/managesieve/tests/src/parser_vacation_seconds
deleted file mode 100644
index 75cbcae..0000000
--- a/lib/plugins/managesieve/tests/src/parser_vacation_seconds
+++ /dev/null
@@ -1,12 +0,0 @@
-require ["vacation-seconds"];
-# rule:[test-vacation]
-if header :contains "Subject" "vacation"
-{
- vacation :seconds 0 text:
-# test
-test test /* test */
-test
-.
-;
- stop;
-}
diff --git a/lib/plugins/managesieve/tests/src/parser_variables b/lib/plugins/managesieve/tests/src/parser_variables
deleted file mode 100644
index bd5941c..0000000
--- a/lib/plugins/managesieve/tests/src/parser_variables
+++ /dev/null
@@ -1,12 +0,0 @@
-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*";

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 9:56 AM (1 d, 19 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
6e/f0/7cb7e8b87b445ea85f0d279039bf
Default Alt Text
(2 MB)

Event Timeline