diff --git a/rainloop/VERSION b/rainloop/VERSION index 9b9a2442..090ea9da 100755 --- a/rainloop/VERSION +++ b/rainloop/VERSION @@ -1 +1 @@ -6.0.2 +6.0.3 diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/AES.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/AES.php deleted file mode 100644 index 6b1f9daa..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/AES.php +++ /dev/null @@ -1,207 +0,0 @@ - - * setKey('abcdefghijklmnop'); - * - * $size = 10 * 1024; - * $plaintext = ''; - * for ($i = 0; $i < $size; $i++) { - * $plaintext.= 'a'; - * } - * - * echo $aes->decrypt($aes->encrypt($plaintext)); - * ?> - * - * - * 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. - * - * @category Crypt - * @package Crypt_AES - * @author Jim Wigginton - * @copyright 2008 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Crypt_Rijndael - */ -if (!class_exists('Crypt_Rijndael')) { - include_once 'Rijndael.php'; -} - -/**#@+ - * @access public - * @see Crypt_AES::encrypt() - * @see Crypt_AES::decrypt() - */ -/** - * Encrypt / decrypt using the Counter mode. - * - * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 - */ -define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR); -/** - * Encrypt / decrypt using the Electronic Code Book mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 - */ -define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB); -/** - * Encrypt / decrypt using the Code Book Chaining mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - */ -define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 - */ -define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 - */ -define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_Base::Crypt_Base() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - -/** - * Pure-PHP implementation of AES. - * - * @package Crypt_AES - * @author Jim Wigginton - * @access public - */ -class Crypt_AES extends Crypt_Rijndael -{ - /** - * The namespace used by the cipher for its constants. - * - * @see Crypt_Base::const_namespace - * @var String - * @access private - */ - var $const_namespace = 'AES'; - - /** - * Dummy function - * - * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything. - * - * @see Crypt_Rijndael::setBlockLength() - * @access public - * @param Integer $length - */ - function setBlockLength($length) - { - return; - } - - /** - * Sets the key length - * - * Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to - * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. - * - * @see Crypt_Rijndael:setKeyLength() - * @access public - * @param Integer $length - */ - function setKeyLength($length) - { - switch ($length) { - case 160: - $length = 192; - break; - case 224: - $length = 256; - } - parent::setKeyLength($length); - } - - /** - * Sets the key. - * - * Rijndael supports five different key lengths, AES only supports three. - * - * @see Crypt_Rijndael:setKey() - * @see setKeyLength() - * @access public - * @param String $key - */ - function setKey($key) - { - parent::setKey($key); - - if (!$this->explicit_key_length) { - $length = strlen($key); - switch (true) { - case $length <= 16: - $this->key_size = 16; - break; - case $length <= 24: - $this->key_size = 24; - break; - default: - $this->key_size = 32; - } - $this->_setupEngine(); - } - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Base.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Base.php deleted file mode 100644 index 4df2a2db..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Base.php +++ /dev/null @@ -1,2011 +0,0 @@ - - * @author Hans-Juergen Petrich - * @copyright 2007 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/**#@+ - * @access public - * @see Crypt_Base::encrypt() - * @see Crypt_Base::decrypt() - */ -/** - * Encrypt / decrypt using the Counter mode. - * - * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 - */ -define('CRYPT_MODE_CTR', -1); -/** - * Encrypt / decrypt using the Electronic Code Book mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 - */ -define('CRYPT_MODE_ECB', 1); -/** - * Encrypt / decrypt using the Code Book Chaining mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - */ -define('CRYPT_MODE_CBC', 2); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 - */ -define('CRYPT_MODE_CFB', 3); -/** - * Encrypt / decrypt using the Output Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 - */ -define('CRYPT_MODE_OFB', 4); -/** - * Encrypt / decrypt using streaming mode. - * - */ -define('CRYPT_MODE_STREAM', 5); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_Base::Crypt_Base() - */ -/** - * Base value for the internal implementation $engine switch - */ -define('CRYPT_MODE_INTERNAL', 1); -/** - * Base value for the mcrypt implementation $engine switch - */ -define('CRYPT_MODE_MCRYPT', 2); -/**#@-*/ - -/** - * Base Class for all Crypt_* cipher classes - * - * @package Crypt_Base - * @author Jim Wigginton - * @author Hans-Juergen Petrich - * @access public - */ -class Crypt_Base -{ - /** - * The Encryption Mode - * - * @see Crypt_Base::Crypt_Base() - * @var Integer - * @access private - */ - var $mode; - - /** - * The Block Length of the block cipher - * - * @var Integer - * @access private - */ - var $block_size = 16; - - /** - * The Key - * - * @see Crypt_Base::setKey() - * @var String - * @access private - */ - var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - - /** - * The Initialization Vector - * - * @see Crypt_Base::setIV() - * @var String - * @access private - */ - var $iv; - - /** - * A "sliding" Initialization Vector - * - * @see Crypt_Base::enableContinuousBuffer() - * @see Crypt_Base::_clearBuffers() - * @var String - * @access private - */ - var $encryptIV; - - /** - * A "sliding" Initialization Vector - * - * @see Crypt_Base::enableContinuousBuffer() - * @see Crypt_Base::_clearBuffers() - * @var String - * @access private - */ - var $decryptIV; - - /** - * Continuous Buffer status - * - * @see Crypt_Base::enableContinuousBuffer() - * @var Boolean - * @access private - */ - var $continuousBuffer = false; - - /** - * Encryption buffer for CTR, OFB and CFB modes - * - * @see Crypt_Base::encrypt() - * @see Crypt_Base::_clearBuffers() - * @var Array - * @access private - */ - var $enbuffer; - - /** - * Decryption buffer for CTR, OFB and CFB modes - * - * @see Crypt_Base::decrypt() - * @see Crypt_Base::_clearBuffers() - * @var Array - * @access private - */ - var $debuffer; - - /** - * mcrypt resource for encryption - * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_Base::encrypt() - * @var Resource - * @access private - */ - var $enmcrypt; - - /** - * mcrypt resource for decryption - * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_Base::decrypt() - * @var Resource - * @access private - */ - var $demcrypt; - - /** - * Does the enmcrypt resource need to be (re)initialized? - * - * @see Crypt_Twofish::setKey() - * @see Crypt_Twofish::setIV() - * @var Boolean - * @access private - */ - var $enchanged = true; - - /** - * Does the demcrypt resource need to be (re)initialized? - * - * @see Crypt_Twofish::setKey() - * @see Crypt_Twofish::setIV() - * @var Boolean - * @access private - */ - var $dechanged = true; - - /** - * mcrypt resource for CFB mode - * - * mcrypt's CFB mode, in (and only in) buffered context, - * is broken, so phpseclib implements the CFB mode by it self, - * even when the mcrypt php extension is available. - * - * In order to do the CFB-mode work (fast) phpseclib - * use a separate ECB-mode mcrypt resource. - * - * @link http://phpseclib.sourceforge.net/cfb-demo.phps - * @see Crypt_Base::encrypt() - * @see Crypt_Base::decrypt() - * @see Crypt_Base::_setupMcrypt() - * @var Resource - * @access private - */ - var $ecb; - - /** - * Optimizing value while CFB-encrypting - * - * Only relevant if $continuousBuffer enabled - * and $engine == CRYPT_MODE_MCRYPT - * - * It's faster to re-init $enmcrypt if - * $buffer bytes > $cfb_init_len than - * using the $ecb resource furthermore. - * - * This value depends of the chosen cipher - * and the time it would be needed for it's - * initialization [by mcrypt_generic_init()] - * which, typically, depends on the complexity - * on its internaly Key-expanding algorithm. - * - * @see Crypt_Base::encrypt() - * @var Integer - * @access private - */ - var $cfb_init_len = 600; - - /** - * Does internal cipher state need to be (re)initialized? - * - * @see setKey() - * @see setIV() - * @see disableContinuousBuffer() - * @var Boolean - * @access private - */ - var $changed = true; - - /** - * Padding status - * - * @see Crypt_Base::enablePadding() - * @var Boolean - * @access private - */ - var $padding = true; - - /** - * Is the mode one that is paddable? - * - * @see Crypt_Base::Crypt_Base() - * @var Boolean - * @access private - */ - var $paddable = false; - - /** - * Holds which crypt engine internaly should be use, - * which will be determined automatically on __construct() - * - * Currently available $engines are: - * - CRYPT_MODE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required) - * - CRYPT_MODE_INTERNAL (slower, pure php-engine, no php-extension required) - * - * In the pipeline... maybe. But currently not available: - * - CRYPT_MODE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required) - * - * If possible, CRYPT_MODE_MCRYPT will be used for each cipher. - * Otherwise CRYPT_MODE_INTERNAL - * - * @see Crypt_Base::encrypt() - * @see Crypt_Base::decrypt() - * @var Integer - * @access private - */ - var $engine; - - /** - * The mcrypt specific name of the cipher - * - * Only used if $engine == CRYPT_MODE_MCRYPT - * - * @link http://www.php.net/mcrypt_module_open - * @link http://www.php.net/mcrypt_list_algorithms - * @see Crypt_Base::_setupMcrypt() - * @var String - * @access private - */ - var $cipher_name_mcrypt; - - /** - * The default password key_size used by setPassword() - * - * @see Crypt_Base::setPassword() - * @var Integer - * @access private - */ - var $password_key_size = 32; - - /** - * The default salt used by setPassword() - * - * @see Crypt_Base::setPassword() - * @var String - * @access private - */ - var $password_default_salt = 'phpseclib/salt'; - - /** - * The namespace used by the cipher for its constants. - * - * ie: AES.php is using CRYPT_AES_MODE_* for its constants - * so $const_namespace is AES - * - * DES.php is using CRYPT_DES_MODE_* for its constants - * so $const_namespace is DES... and so on - * - * All CRYPT_<$const_namespace>_MODE_* are aliases of - * the generic CRYPT_MODE_* constants, so both could be used - * for each cipher. - * - * Example: - * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode - * $aes = new Crypt_AES(CRYPT_MODE_CFB); // identical - * - * @see Crypt_Base::Crypt_Base() - * @var String - * @access private - */ - var $const_namespace; - - /** - * The name of the performance-optimized callback function - * - * Used by encrypt() / decrypt() - * only if $engine == CRYPT_MODE_INTERNAL - * - * @see Crypt_Base::encrypt() - * @see Crypt_Base::decrypt() - * @see Crypt_Base::_setupInlineCrypt() - * @see Crypt_Base::$use_inline_crypt - * @var Callback - * @access private - */ - var $inline_crypt; - - /** - * Holds whether performance-optimized $inline_crypt() can/should be used. - * - * @see Crypt_Base::encrypt() - * @see Crypt_Base::decrypt() - * @see Crypt_Base::inline_crypt - * @var mixed - * @access private - */ - var $use_inline_crypt; - - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_MODE_ECB - * - * - CRYPT_MODE_CBC - * - * - CRYPT_MODE_CTR - * - * - CRYPT_MODE_CFB - * - * - CRYPT_MODE_OFB - * - * (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...) - * - * If not explicitly set, CRYPT_MODE_CBC will be used. - * - * @param optional Integer $mode - * @access public - */ - function Crypt_Base($mode = CRYPT_MODE_CBC) - { - $const_crypt_mode = 'CRYPT_' . $this->const_namespace . '_MODE'; - - // Determining the availibility of mcrypt support for the cipher - if (!defined($const_crypt_mode)) { - switch (true) { - case extension_loaded('mcrypt') && in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms()): - define($const_crypt_mode, CRYPT_MODE_MCRYPT); - break; - default: - define($const_crypt_mode, CRYPT_MODE_INTERNAL); - } - } - - // Determining which internal $engine should be used. - // The fastes possible first. - switch (true) { - case empty($this->cipher_name_mcrypt): // The cipher module has no mcrypt-engine support at all so we force CRYPT_MODE_INTERNAL - $this->engine = CRYPT_MODE_INTERNAL; - break; - case constant($const_crypt_mode) == CRYPT_MODE_MCRYPT: - $this->engine = CRYPT_MODE_MCRYPT; - break; - default: - $this->engine = CRYPT_MODE_INTERNAL; - } - - // $mode dependent settings - switch ($mode) { - case CRYPT_MODE_ECB: - $this->paddable = true; - $this->mode = $mode; - break; - case CRYPT_MODE_CTR: - case CRYPT_MODE_CFB: - case CRYPT_MODE_OFB: - case CRYPT_MODE_STREAM: - $this->mode = $mode; - break; - case CRYPT_MODE_CBC: - default: - $this->paddable = true; - $this->mode = CRYPT_MODE_CBC; - } - - // Determining whether inline crypting can be used by the cipher - if ($this->use_inline_crypt !== false && function_exists('create_function')) { - $this->use_inline_crypt = true; - } - } - - /** - * Sets the initialization vector. (optional) - * - * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explicitly set, it'll be assumed - * to be all zero's. - * - * Note: Could, but not must, extend by the child Crypt_* class - * - * @access public - * @param String $iv - */ - function setIV($iv) - { - if ($this->mode == CRYPT_MODE_ECB) { - return; - } - - $this->iv = $iv; - $this->changed = true; - } - - /** - * Sets the key. - * - * The min/max length(s) of the key depends on the cipher which is used. - * If the key not fits the length(s) of the cipher it will paded with null bytes - * up to the closest valid key length. If the key is more than max length, - * we trim the excess bits. - * - * If the key is not explicitly set, it'll be assumed to be all null bytes. - * - * Note: Could, but not must, extend by the child Crypt_* class - * - * @access public - * @param String $key - */ - function setKey($key) - { - $this->key = $key; - $this->changed = true; - } - - /** - * Sets the password. - * - * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: - * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1: - * $hash, $salt, $count, $dkLen - * - * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php - * - * Note: Could, but not must, extend by the child Crypt_* class - * - * @see Crypt/Hash.php - * @param String $password - * @param optional String $method - * @return Boolean - * @access public - */ - function setPassword($password, $method = 'pbkdf2') - { - $key = ''; - - switch ($method) { - default: // 'pbkdf2' or 'pbkdf1' - $func_args = func_get_args(); - - // Hash function - $hash = isset($func_args[2]) ? $func_args[2] : 'sha1'; - - // WPA and WPA2 use the SSID as the salt - $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt; - - // RFC2898#section-4.2 uses 1,000 iterations by default - // WPA and WPA2 use 4,096. - $count = isset($func_args[4]) ? $func_args[4] : 1000; - - // Keylength - if (isset($func_args[5])) { - $dkLen = $func_args[5]; - } else { - $dkLen = $method == 'pbkdf1' ? 2 * $this->password_key_size : $this->password_key_size; - } - - switch (true) { - case $method == 'pbkdf1': - if (!class_exists('Crypt_Hash')) { - include_once 'Crypt/Hash.php'; - } - $hashObj = new Crypt_Hash(); - $hashObj->setHash($hash); - if ($dkLen > $hashObj->getLength()) { - user_error('Derived key too long'); - return false; - } - $t = $password . $salt; - for ($i = 0; $i < $count; ++$i) { - $t = $hashObj->hash($t); - } - $key = substr($t, 0, $dkLen); - - $this->setKey(substr($key, 0, $dkLen >> 1)); - $this->setIV(substr($key, $dkLen >> 1)); - - return true; - // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable - case !function_exists('hash_pbkdf2'): - case !function_exists('hash_algos'): - case !in_array($hash, hash_algos()): - if (!class_exists('Crypt_Hash')) { - include_once 'Crypt/Hash.php'; - } - $i = 1; - while (strlen($key) < $dkLen) { - $hmac = new Crypt_Hash(); - $hmac->setHash($hash); - $hmac->setKey($password); - $f = $u = $hmac->hash($salt . pack('N', $i++)); - for ($j = 2; $j <= $count; ++$j) { - $u = $hmac->hash($u); - $f^= $u; - } - $key.= $f; - } - $key = substr($key, 0, $dkLen); - break; - default: - $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true); - } - } - - $this->setKey($key); - - return true; - } - - /** - * Encrypts a message. - * - * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher - * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's - * necessary are discussed in the following - * URL: - * - * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} - * - * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. - * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that - * length. - * - * Note: Could, but not must, extend by the child Crypt_* class - * - * @see Crypt_Base::decrypt() - * @access public - * @param String $plaintext - * @return String $cipertext - */ - function encrypt($plaintext) - { - if ($this->engine == CRYPT_MODE_MCRYPT) { - if ($this->changed) { - $this->_setupMcrypt(); - $this->changed = false; - } - if ($this->enchanged) { - mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); - $this->enchanged = false; - } - - // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} - // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's - // rewritten CFB implementation the above outputs the same thing twice. - if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) { - $block_size = $this->block_size; - $iv = &$this->encryptIV; - $pos = &$this->enbuffer['pos']; - $len = strlen($plaintext); - $ciphertext = ''; - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = $block_size - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - $ciphertext = substr($iv, $orig_pos) ^ $plaintext; - $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); - $this->enbuffer['enmcrypt_init'] = true; - } - if ($len >= $block_size) { - if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) { - if ($this->enbuffer['enmcrypt_init'] === true) { - mcrypt_generic_init($this->enmcrypt, $this->key, $iv); - $this->enbuffer['enmcrypt_init'] = false; - } - $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size)); - $iv = substr($ciphertext, -$block_size); - $len%= $block_size; - } else { - while ($len >= $block_size) { - $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size); - $ciphertext.= $iv; - $len-= $block_size; - $i+= $block_size; - } - } - } - - if ($len) { - $iv = mcrypt_generic($this->ecb, $iv); - $block = $iv ^ substr($plaintext, -$len); - $iv = substr_replace($iv, $block, 0, $len); - $ciphertext.= $block; - $pos = $len; - } - - return $ciphertext; - } - - if ($this->paddable) { - $plaintext = $this->_pad($plaintext); - } - - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); - } - - return $ciphertext; - } - - if ($this->changed) { - $this->_setup(); - $this->changed = false; - } - if ($this->use_inline_crypt) { - $inline = $this->inline_crypt; - return $inline('encrypt', $this, $plaintext); - } - if ($this->paddable) { - $plaintext = $this->_pad($plaintext); - } - - $buffer = &$this->enbuffer; - $block_size = $this->block_size; - $ciphertext = ''; - switch ($this->mode) { - case CRYPT_MODE_ECB: - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size)); - } - break; - case CRYPT_MODE_CBC: - $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $block = substr($plaintext, $i, $block_size); - $block = $this->_encryptBlock($block ^ $xor); - $xor = $block; - $ciphertext.= $block; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - } - break; - case CRYPT_MODE_CTR: - $xor = $this->encryptIV; - if (strlen($buffer['encrypted'])) { - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $block = substr($plaintext, $i, $block_size); - if (strlen($block) > strlen($buffer['encrypted'])) { - $buffer['encrypted'].= $this->_encryptBlock($this->_generateXor($xor, $block_size)); - } - $key = $this->_stringShift($buffer['encrypted'], $block_size); - $ciphertext.= $block ^ $key; - } - } else { - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $block = substr($plaintext, $i, $block_size); - $key = $this->_encryptBlock($this->_generateXor($xor, $block_size)); - $ciphertext.= $block ^ $key; - } - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - if ($start = strlen($plaintext) % $block_size) { - $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; - } - } - break; - case CRYPT_MODE_CFB: - // cfb loosely routines inspired by openssl's: - // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} - if ($this->continuousBuffer) { - $iv = &$this->encryptIV; - $pos = &$buffer['pos']; - } else { - $iv = $this->encryptIV; - $pos = 0; - } - $len = strlen($plaintext); - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = $block_size - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize - $ciphertext = substr($iv, $orig_pos) ^ $plaintext; - $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); - } - while ($len >= $block_size) { - $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size); - $ciphertext.= $iv; - $len-= $block_size; - $i+= $block_size; - } - if ($len) { - $iv = $this->_encryptBlock($iv); - $block = $iv ^ substr($plaintext, $i); - $iv = substr_replace($iv, $block, 0, $len); - $ciphertext.= $block; - $pos = $len; - } - break; - case CRYPT_MODE_OFB: - $xor = $this->encryptIV; - if (strlen($buffer['xor'])) { - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $block = substr($plaintext, $i, $block_size); - if (strlen($block) > strlen($buffer['xor'])) { - $xor = $this->_encryptBlock($xor); - $buffer['xor'].= $xor; - } - $key = $this->_stringShift($buffer['xor'], $block_size); - $ciphertext.= $block ^ $key; - } - } else { - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $xor = $this->_encryptBlock($xor); - $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor; - } - $key = $xor; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - if ($start = strlen($plaintext) % $block_size) { - $buffer['xor'] = substr($key, $start) . $buffer['xor']; - } - } - break; - case CRYPT_MODE_STREAM: - $ciphertext = $this->_encryptBlock($plaintext); - break; - } - - return $ciphertext; - } - - /** - * Decrypts a message. - * - * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until - * it is. - * - * Note: Could, but not must, extend by the child Crypt_* class - * - * @see Crypt_Base::encrypt() - * @access public - * @param String $ciphertext - * @return String $plaintext - */ - function decrypt($ciphertext) - { - if ($this->engine == CRYPT_MODE_MCRYPT) { - $block_size = $this->block_size; - if ($this->changed) { - $this->_setupMcrypt(); - $this->changed = false; - } - if ($this->dechanged) { - mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); - $this->dechanged = false; - } - - if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) { - $iv = &$this->decryptIV; - $pos = &$this->debuffer['pos']; - $len = strlen($ciphertext); - $plaintext = ''; - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = $block_size - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize - $plaintext = substr($iv, $orig_pos) ^ $ciphertext; - $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); - } - if ($len >= $block_size) { - $cb = substr($ciphertext, $i, $len - $len % $block_size); - $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; - $iv = substr($cb, -$block_size); - $len%= $block_size; - } - if ($len) { - $iv = mcrypt_generic($this->ecb, $iv); - $plaintext.= $iv ^ substr($ciphertext, -$len); - $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); - $pos = $len; - } - - return $plaintext; - } - - if ($this->paddable) { - // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}: - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0)); - } - - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); - } - - return $this->paddable ? $this->_unpad($plaintext) : $plaintext; - } - - if ($this->changed) { - $this->_setup(); - $this->changed = false; - } - if ($this->use_inline_crypt) { - $inline = $this->inline_crypt; - return $inline('decrypt', $this, $ciphertext); - } - - $block_size = $this->block_size; - if ($this->paddable) { - // we pad with chr(0) since that's what mcrypt_generic does [...] - $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0)); - } - - $buffer = &$this->debuffer; - $plaintext = ''; - switch ($this->mode) { - case CRYPT_MODE_ECB: - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size)); - } - break; - case CRYPT_MODE_CBC: - $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $block = substr($ciphertext, $i, $block_size); - $plaintext.= $this->_decryptBlock($block) ^ $xor; - $xor = $block; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - } - break; - case CRYPT_MODE_CTR: - $xor = $this->decryptIV; - if (strlen($buffer['ciphertext'])) { - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $block = substr($ciphertext, $i, $block_size); - if (strlen($block) > strlen($buffer['ciphertext'])) { - $buffer['ciphertext'].= $this->_encryptBlock($this->_generateXor($xor, $block_size)); - } - $key = $this->_stringShift($buffer['ciphertext'], $block_size); - $plaintext.= $block ^ $key; - } - } else { - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $block = substr($ciphertext, $i, $block_size); - $key = $this->_encryptBlock($this->_generateXor($xor, $block_size)); - $plaintext.= $block ^ $key; - } - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - if ($start = strlen($ciphertext) % $block_size) { - $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; - } - } - break; - case CRYPT_MODE_CFB: - if ($this->continuousBuffer) { - $iv = &$this->decryptIV; - $pos = &$buffer['pos']; - } else { - $iv = $this->decryptIV; - $pos = 0; - } - $len = strlen($ciphertext); - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = $block_size - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize - $plaintext = substr($iv, $orig_pos) ^ $ciphertext; - $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); - } - while ($len >= $block_size) { - $iv = $this->_encryptBlock($iv); - $cb = substr($ciphertext, $i, $block_size); - $plaintext.= $iv ^ $cb; - $iv = $cb; - $len-= $block_size; - $i+= $block_size; - } - if ($len) { - $iv = $this->_encryptBlock($iv); - $plaintext.= $iv ^ substr($ciphertext, $i); - $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len); - $pos = $len; - } - break; - case CRYPT_MODE_OFB: - $xor = $this->decryptIV; - if (strlen($buffer['xor'])) { - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $block = substr($ciphertext, $i, $block_size); - if (strlen($block) > strlen($buffer['xor'])) { - $xor = $this->_encryptBlock($xor); - $buffer['xor'].= $xor; - } - $key = $this->_stringShift($buffer['xor'], $block_size); - $plaintext.= $block ^ $key; - } - } else { - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $xor = $this->_encryptBlock($xor); - $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor; - } - $key = $xor; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - if ($start = strlen($ciphertext) % $block_size) { - $buffer['xor'] = substr($key, $start) . $buffer['xor']; - } - } - break; - case CRYPT_MODE_STREAM: - $plaintext = $this->_decryptBlock($ciphertext); - break; - } - return $this->paddable ? $this->_unpad($plaintext) : $plaintext; - } - - /** - * Pad "packets". - * - * Block ciphers working by encrypting between their specified [$this->]block_size at a time - * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to - * pad the input so that it is of the proper length. - * - * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH, - * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping - * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is - * transmitted separately) - * - * @see Crypt_Base::disablePadding() - * @access public - */ - function enablePadding() - { - $this->padding = true; - } - - /** - * Do not pad packets. - * - * @see Crypt_Base::enablePadding() - * @access public - */ - function disablePadding() - { - $this->padding = false; - } - - /** - * Treat consecutive "packets" as if they are a continuous buffer. - * - * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets - * will yield different outputs: - * - * - * echo $rijndael->encrypt(substr($plaintext, 0, 16)); - * echo $rijndael->encrypt(substr($plaintext, 16, 16)); - * - * - * echo $rijndael->encrypt($plaintext); - * - * - * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates - * another, as demonstrated with the following: - * - * - * $rijndael->encrypt(substr($plaintext, 0, 16)); - * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); - * - * - * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); - * - * - * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different - * outputs. The reason is due to the fact that the initialization vector's change after every encryption / - * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. - * - * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each - * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that - * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), - * however, they are also less intuitive and more likely to cause you problems. - * - * Note: Could, but not must, extend by the child Crypt_* class - * - * @see Crypt_Base::disableContinuousBuffer() - * @access public - */ - function enableContinuousBuffer() - { - if ($this->mode == CRYPT_MODE_ECB) { - return; - } - - $this->continuousBuffer = true; - } - - /** - * Treat consecutive packets as if they are a discontinuous buffer. - * - * The default behavior. - * - * Note: Could, but not must, extend by the child Crypt_* class - * - * @see Crypt_Base::enableContinuousBuffer() - * @access public - */ - function disableContinuousBuffer() - { - if ($this->mode == CRYPT_MODE_ECB) { - return; - } - if (!$this->continuousBuffer) { - return; - } - - $this->continuousBuffer = false; - $this->changed = true; - } - - /** - * Encrypts a block - * - * Note: Must extend by the child Crypt_* class - * - * @access private - * @param String $in - * @return String - */ - function _encryptBlock($in) - { - user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); - } - - /** - * Decrypts a block - * - * Note: Must extend by the child Crypt_* class - * - * @access private - * @param String $in - * @return String - */ - function _decryptBlock($in) - { - user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); - } - - /** - * Setup the key (expansion) - * - * Only used if $engine == CRYPT_MODE_INTERNAL - * - * Note: Must extend by the child Crypt_* class - * - * @see Crypt_Base::_setup() - * @access private - */ - function _setupKey() - { - user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR); - } - - /** - * Setup the CRYPT_MODE_INTERNAL $engine - * - * (re)init, if necessary, the internal cipher $engine and flush all $buffers - * Used (only) if $engine == CRYPT_MODE_INTERNAL - * - * _setup() will be called each time if $changed === true - * typically this happens when using one or more of following public methods: - * - * - setKey() - * - * - setIV() - * - * - disableContinuousBuffer() - * - * - First run of encrypt() / decrypt() with no init-settings - * - * Internally: _setup() is called always before(!) en/decryption. - * - * Note: Could, but not must, extend by the child Crypt_* class - * - * @see setKey() - * @see setIV() - * @see disableContinuousBuffer() - * @access private - */ - function _setup() - { - $this->_clearBuffers(); - $this->_setupKey(); - - if ($this->use_inline_crypt) { - $this->_setupInlineCrypt(); - } - } - - /** - * Setup the CRYPT_MODE_MCRYPT $engine - * - * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers - * Used (only) if $engine = CRYPT_MODE_MCRYPT - * - * _setupMcrypt() will be called each time if $changed === true - * typically this happens when using one or more of following public methods: - * - * - setKey() - * - * - setIV() - * - * - disableContinuousBuffer() - * - * - First run of encrypt() / decrypt() - * - * - * Note: Could, but not must, extend by the child Crypt_* class - * - * @see setKey() - * @see setIV() - * @see disableContinuousBuffer() - * @access private - */ - function _setupMcrypt() - { - $this->_clearBuffers(); - $this->enchanged = $this->dechanged = true; - - if (!isset($this->enmcrypt)) { - static $mcrypt_modes = array( - CRYPT_MODE_CTR => 'ctr', - CRYPT_MODE_ECB => MCRYPT_MODE_ECB, - CRYPT_MODE_CBC => MCRYPT_MODE_CBC, - CRYPT_MODE_CFB => 'ncfb', - CRYPT_MODE_OFB => MCRYPT_MODE_NOFB, - CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM, - ); - - $this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); - $this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); - - // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer() - // to workaround mcrypt's broken ncfb implementation in buffered mode - // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} - if ($this->mode == CRYPT_MODE_CFB) { - $this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, ''); - } - - } // else should mcrypt_generic_deinit be called? - - if ($this->mode == CRYPT_MODE_CFB) { - mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size)); - } - } - - /** - * Pads a string - * - * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize. - * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to - * chr($this->block_size - (strlen($text) % $this->block_size) - * - * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless - * and padding will, hence forth, be enabled. - * - * @see Crypt_Base::_unpad() - * @param String $text - * @access private - * @return String - */ - function _pad($text) - { - $length = strlen($text); - - if (!$this->padding) { - if ($length % $this->block_size == 0) { - return $text; - } else { - user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})"); - $this->padding = true; - } - } - - $pad = $this->block_size - ($length % $this->block_size); - - return str_pad($text, $length + $pad, chr($pad)); - } - - /** - * Unpads a string. - * - * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong - * and false will be returned. - * - * @see Crypt_Base::_pad() - * @param String $text - * @access private - * @return String - */ - function _unpad($text) - { - if (!$this->padding) { - return $text; - } - - $length = ord($text[strlen($text) - 1]); - - if (!$length || $length > $this->block_size) { - return false; - } - - return substr($text, 0, -$length); - } - - /** - * Clears internal buffers - * - * Clearing/resetting the internal buffers is done everytime - * after disableContinuousBuffer() or on cipher $engine (re)init - * ie after setKey() or setIV() - * - * Note: Could, but not must, extend by the child Crypt_* class - * - * @access public - */ - function _clearBuffers() - { - $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); - $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); - - // mcrypt's handling of invalid's $iv: - // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size); - $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0"); - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @access private - * @return String - */ - function _stringShift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; - } - - /** - * Generate CTR XOR encryption key - * - * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the - * plaintext / ciphertext in CTR mode. - * - * @see Crypt_Base::decrypt() - * @see Crypt_Base::encrypt() - * @param String $iv - * @param Integer $length - * @access private - * @return String $xor - */ - function _generateXor(&$iv, $length) - { - $xor = ''; - $block_size = $this->block_size; - $num_blocks = floor(($length + ($block_size - 1)) / $block_size); - for ($i = 0; $i < $num_blocks; $i++) { - $xor.= $iv; - for ($j = 4; $j <= $block_size; $j+= 4) { - $temp = substr($iv, -$j, 4); - switch ($temp) { - case "\xFF\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); - break; - case "\x7F\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); - break 2; - default: - extract(unpack('Ncount', $temp)); - $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); - break 2; - } - } - } - - return $xor; - } - - /** - * Setup the performance-optimized function for de/encrypt() - * - * Stores the created (or existing) callback function-name - * in $this->inline_crypt - * - * Internally for phpseclib developers: - * - * _setupInlineCrypt() would be called only if: - * - * - $engine == CRYPT_MODE_INTERNAL and - * - * - $use_inline_crypt === true - * - * - each time on _setup(), after(!) _setupKey() - * - * - * This ensures that _setupInlineCrypt() has always a - * full ready2go initializated internal cipher $engine state - * where, for example, the keys allready expanded, - * keys/block_size calculated and such. - * - * It is, each time if called, the responsibility of _setupInlineCrypt(): - * - * - to set $this->inline_crypt to a valid and fully working callback function - * as a (faster) replacement for encrypt() / decrypt() - * - * - NOT to create unlimited callback functions (for memory reasons!) - * no matter how often _setupInlineCrypt() would be called. At some - * point of amount they must be generic re-useable. - * - * - the code of _setupInlineCrypt() it self, - * and the generated callback code, - * must be, in following order: - * - 100% safe - * - 100% compatible to encrypt()/decrypt() - * - using only php5+ features/lang-constructs/php-extensions if - * compatibility (down to php4) or fallback is provided - * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-) - * - >= 10% faster than encrypt()/decrypt() [which is, by the way, - * the reason for the existence of _setupInlineCrypt() :-)] - * - memory-nice - * - short (as good as possible) - * - * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code. - * - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class. - * - The following variable names are reserved: - * - $_* (all variable names prefixed with an underscore) - * - $self (object reference to it self. Do not use $this, but $self instead) - * - $in (the content of $in has to en/decrypt by the generated code) - * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only - * - * - * @see Crypt_Base::_setup() - * @see Crypt_Base::_createInlineCryptFunction() - * @see Crypt_Base::encrypt() - * @see Crypt_Base::decrypt() - * @access private - */ - function _setupInlineCrypt() - { - // If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt() - - // If, for any reason, an extending Crypt_Base() Crypt_* class - // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false - // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class, - // in the constructor at object instance-time - // or, if it's runtime-specific, at runtime - - $this->use_inline_crypt = false; - } - - /** - * Creates the performance-optimized function for en/decrypt() - * - * Internally for phpseclib developers: - * - * _createInlineCryptFunction(): - * - * - merge the $cipher_code [setup'ed by _setupInlineCrypt()] - * with the current [$this->]mode of operation code - * - * - create the $inline function, which called by encrypt() / decrypt() - * as its replacement to speed up the en/decryption operations. - * - * - return the name of the created $inline callback function - * - * - used to speed up en/decryption - * - * - * - * The main reason why can speed up things [up to 50%] this way are: - * - * - using variables more effective then regular. - * (ie no use of expensive arrays but integers $k_0, $k_1 ... - * or even, for example, the pure $key[] values hardcoded) - * - * - avoiding 1000's of function calls of ie _encryptBlock() - * but inlining the crypt operations. - * in the mode of operation for() loop. - * - * - full loop unroll the (sometimes key-dependent) rounds - * avoiding this way ++$i counters and runtime-if's etc... - * - * The basic code architectur of the generated $inline en/decrypt() - * lambda function, in pseudo php, is: - * - * - * +----------------------------------------------------------------------------------------------+ - * | callback $inline = create_function: | - * | lambda_function_0001_crypt_ECB($action, $text) | - * | { | - * | INSERT PHP CODE OF: | - * | $cipher_code['init_crypt']; // general init code. | - * | // ie: $sbox'es declarations used for | - * | // encrypt and decrypt'ing. | - * | | - * | switch ($action) { | - * | case 'encrypt': | - * | INSERT PHP CODE OF: | - * | $cipher_code['init_encrypt']; // encrypt sepcific init code. | - * | ie: specified $key or $box | - * | declarations for encrypt'ing. | - * | | - * | foreach ($ciphertext) { | - * | $in = $block_size of $ciphertext; | - * | | - * | INSERT PHP CODE OF: | - * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: | - * | // strlen($in) == $this->block_size | - * | // here comes the cipher algorithm in action | - * | // for encryption. | - * | // $cipher_code['encrypt_block'] has to | - * | // encrypt the content of the $in variable | - * | | - * | $plaintext .= $in; | - * | } | - * | return $plaintext; | - * | | - * | case 'decrypt': | - * | INSERT PHP CODE OF: | - * | $cipher_code['init_decrypt']; // decrypt sepcific init code | - * | ie: specified $key or $box | - * | declarations for decrypt'ing. | - * | foreach ($plaintext) { | - * | $in = $block_size of $plaintext; | - * | | - * | INSERT PHP CODE OF: | - * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always | - * | // strlen($in) == $this->block_size | - * | // here comes the cipher algorithm in action | - * | // for decryption. | - * | // $cipher_code['decrypt_block'] has to | - * | // decrypt the content of the $in variable | - * | $ciphertext .= $in; | - * | } | - * | return $ciphertext; | - * | } | - * | } | - * +----------------------------------------------------------------------------------------------+ - * - * - * See also the Crypt_*::_setupInlineCrypt()'s for - * productive inline $cipher_code's how they works. - * - * Structure of: - * - * $cipher_code = array( - * 'init_crypt' => (string) '', // optional - * 'init_encrypt' => (string) '', // optional - * 'init_decrypt' => (string) '', // optional - * 'encrypt_block' => (string) '', // required - * 'decrypt_block' => (string) '' // required - * ); - * - * - * @see Crypt_Base::_setupInlineCrypt() - * @see Crypt_Base::encrypt() - * @see Crypt_Base::decrypt() - * @param Array $cipher_code - * @access private - * @return String (the name of the created callback function) - */ - function _createInlineCryptFunction($cipher_code) - { - $block_size = $this->block_size; - - // optional - $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : ''; - $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : ''; - $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : ''; - // required - $encrypt_block = $cipher_code['encrypt_block']; - $decrypt_block = $cipher_code['decrypt_block']; - - // Generating mode of operation inline code, - // merged with the $cipher_code algorithm - // for encrypt- and decryption. - switch ($this->mode) { - case CRYPT_MODE_ECB: - $encrypt = $init_encrypt . ' - $_ciphertext = ""; - $_text = $self->_pad($_text); - $_plaintext_len = strlen($_text); - - for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { - $in = substr($_text, $_i, '.$block_size.'); - '.$encrypt_block.' - $_ciphertext.= $in; - } - - return $_ciphertext; - '; - - $decrypt = $init_decrypt . ' - $_plaintext = ""; - $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); - $_ciphertext_len = strlen($_text); - - for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { - $in = substr($_text, $_i, '.$block_size.'); - '.$decrypt_block.' - $_plaintext.= $in; - } - - return $self->_unpad($_plaintext); - '; - break; - case CRYPT_MODE_CTR: - $encrypt = $init_encrypt . ' - $_ciphertext = ""; - $_plaintext_len = strlen($_text); - $_xor = $self->encryptIV; - $_buffer = &$self->enbuffer; - - if (strlen($_buffer["encrypted"])) { - for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { - $_block = substr($_text, $_i, '.$block_size.'); - if (strlen($_block) > strlen($_buffer["encrypted"])) { - $in = $self->_generateXor($_xor, '.$block_size.'); - '.$encrypt_block.' - $_buffer["encrypted"].= $in; - } - $_key = $self->_stringShift($_buffer["encrypted"], '.$block_size.'); - $_ciphertext.= $_block ^ $_key; - } - } else { - for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { - $_block = substr($_text, $_i, '.$block_size.'); - $in = $self->_generateXor($_xor, '.$block_size.'); - '.$encrypt_block.' - $_key = $in; - $_ciphertext.= $_block ^ $_key; - } - } - if ($self->continuousBuffer) { - $self->encryptIV = $_xor; - if ($_start = $_plaintext_len % '.$block_size.') { - $_buffer["encrypted"] = substr($_key, $_start) . $_buffer["encrypted"]; - } - } - - return $_ciphertext; - '; - - $decrypt = $init_encrypt . ' - $_plaintext = ""; - $_ciphertext_len = strlen($_text); - $_xor = $self->decryptIV; - $_buffer = &$self->debuffer; - - if (strlen($_buffer["ciphertext"])) { - for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { - $_block = substr($_text, $_i, '.$block_size.'); - if (strlen($_block) > strlen($_buffer["ciphertext"])) { - $in = $self->_generateXor($_xor, '.$block_size.'); - '.$encrypt_block.' - $_buffer["ciphertext"].= $in; - } - $_key = $self->_stringShift($_buffer["ciphertext"], '.$block_size.'); - $_plaintext.= $_block ^ $_key; - } - } else { - for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { - $_block = substr($_text, $_i, '.$block_size.'); - $in = $self->_generateXor($_xor, '.$block_size.'); - '.$encrypt_block.' - $_key = $in; - $_plaintext.= $_block ^ $_key; - } - } - if ($self->continuousBuffer) { - $self->decryptIV = $_xor; - if ($_start = $_ciphertext_len % '.$block_size.') { - $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"]; - } - } - - return $_plaintext; - '; - break; - case CRYPT_MODE_CFB: - $encrypt = $init_encrypt . ' - $_ciphertext = ""; - $_buffer = &$self->enbuffer; - - if ($self->continuousBuffer) { - $_iv = &$self->encryptIV; - $_pos = &$_buffer["pos"]; - } else { - $_iv = $self->encryptIV; - $_pos = 0; - } - $_len = strlen($_text); - $_i = 0; - if ($_pos) { - $_orig_pos = $_pos; - $_max = '.$block_size.' - $_pos; - if ($_len >= $_max) { - $_i = $_max; - $_len-= $_max; - $_pos = 0; - } else { - $_i = $_len; - $_pos+= $_len; - $_len = 0; - } - $_ciphertext = substr($_iv, $_orig_pos) ^ $_text; - $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i); - } - while ($_len >= '.$block_size.') { - $in = $_iv; - '.$encrypt_block.'; - $_iv = $in ^ substr($_text, $_i, '.$block_size.'); - $_ciphertext.= $_iv; - $_len-= '.$block_size.'; - $_i+= '.$block_size.'; - } - if ($_len) { - $in = $_iv; - '.$encrypt_block.' - $_iv = $in; - $_block = $_iv ^ substr($_text, $_i); - $_iv = substr_replace($_iv, $_block, 0, $_len); - $_ciphertext.= $_block; - $_pos = $_len; - } - return $_ciphertext; - '; - - $decrypt = $init_encrypt . ' - $_plaintext = ""; - $_buffer = &$self->debuffer; - - if ($self->continuousBuffer) { - $_iv = &$self->decryptIV; - $_pos = &$_buffer["pos"]; - } else { - $_iv = $self->decryptIV; - $_pos = 0; - } - $_len = strlen($_text); - $_i = 0; - if ($_pos) { - $_orig_pos = $_pos; - $_max = '.$block_size.' - $_pos; - if ($_len >= $_max) { - $_i = $_max; - $_len-= $_max; - $_pos = 0; - } else { - $_i = $_len; - $_pos+= $_len; - $_len = 0; - } - $_plaintext = substr($_iv, $_orig_pos) ^ $_text; - $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i); - } - while ($_len >= '.$block_size.') { - $in = $_iv; - '.$encrypt_block.' - $_iv = $in; - $cb = substr($_text, $_i, '.$block_size.'); - $_plaintext.= $_iv ^ $cb; - $_iv = $cb; - $_len-= '.$block_size.'; - $_i+= '.$block_size.'; - } - if ($_len) { - $in = $_iv; - '.$encrypt_block.' - $_iv = $in; - $_plaintext.= $_iv ^ substr($_text, $_i); - $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len); - $_pos = $_len; - } - - return $_plaintext; - '; - break; - case CRYPT_MODE_OFB: - $encrypt = $init_encrypt . ' - $_ciphertext = ""; - $_plaintext_len = strlen($_text); - $_xor = $self->encryptIV; - $_buffer = &$self->enbuffer; - - if (strlen($_buffer["xor"])) { - for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { - $_block = substr($_text, $_i, '.$block_size.'); - if (strlen($_block) > strlen($_buffer["xor"])) { - $in = $_xor; - '.$encrypt_block.' - $_xor = $in; - $_buffer["xor"].= $_xor; - } - $_key = $self->_stringShift($_buffer["xor"], '.$block_size.'); - $_ciphertext.= $_block ^ $_key; - } - } else { - for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { - $in = $_xor; - '.$encrypt_block.' - $_xor = $in; - $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor; - } - $_key = $_xor; - } - if ($self->continuousBuffer) { - $self->encryptIV = $_xor; - if ($_start = $_plaintext_len % '.$block_size.') { - $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; - } - } - return $_ciphertext; - '; - - $decrypt = $init_encrypt . ' - $_plaintext = ""; - $_ciphertext_len = strlen($_text); - $_xor = $self->decryptIV; - $_buffer = &$self->debuffer; - - if (strlen($_buffer["xor"])) { - for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { - $_block = substr($_text, $_i, '.$block_size.'); - if (strlen($_block) > strlen($_buffer["xor"])) { - $in = $_xor; - '.$encrypt_block.' - $_xor = $in; - $_buffer["xor"].= $_xor; - } - $_key = $self->_stringShift($_buffer["xor"], '.$block_size.'); - $_plaintext.= $_block ^ $_key; - } - } else { - for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { - $in = $_xor; - '.$encrypt_block.' - $_xor = $in; - $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor; - } - $_key = $_xor; - } - if ($self->continuousBuffer) { - $self->decryptIV = $_xor; - if ($_start = $_ciphertext_len % '.$block_size.') { - $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; - } - } - return $_plaintext; - '; - break; - case CRYPT_MODE_STREAM: - $encrypt = $init_encrypt . ' - $_ciphertext = ""; - '.$encrypt_block.' - return $_ciphertext; - '; - $decrypt = $init_decrypt . ' - $_plaintext = ""; - '.$decrypt_block.' - return $_plaintext; - '; - break; - // case CRYPT_MODE_CBC: - default: - $encrypt = $init_encrypt . ' - $_ciphertext = ""; - $_text = $self->_pad($_text); - $_plaintext_len = strlen($_text); - - $in = $self->encryptIV; - - for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { - $in = substr($_text, $_i, '.$block_size.') ^ $in; - '.$encrypt_block.' - $_ciphertext.= $in; - } - - if ($self->continuousBuffer) { - $self->encryptIV = $in; - } - - return $_ciphertext; - '; - - $decrypt = $init_decrypt . ' - $_plaintext = ""; - $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); - $_ciphertext_len = strlen($_text); - - $_iv = $self->decryptIV; - - for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { - $in = $_block = substr($_text, $_i, '.$block_size.'); - '.$decrypt_block.' - $_plaintext.= $in ^ $_iv; - $_iv = $_block; - } - - if ($self->continuousBuffer) { - $self->decryptIV = $_iv; - } - - return $self->_unpad($_plaintext); - '; - break; - } - - // Create the $inline function and return its name as string. Ready to run! - return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }'); - } - - /** - * Holds the lambda_functions table (classwide) - * - * Each name of the lambda function, created from - * _setupInlineCrypt() && _createInlineCryptFunction() - * is stored, classwide (!), here for reusing. - * - * The string-based index of $function is a classwide - * uniqe value representing, at least, the $mode of - * operation (or more... depends of the optimizing level) - * for which $mode the lambda function was created. - * - * @access private - * @return &Array - */ - function &_getLambdaFunctions() - { - static $functions = array(); - return $functions; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Blowfish.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Blowfish.php deleted file mode 100644 index f39f17d7..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Blowfish.php +++ /dev/null @@ -1,644 +0,0 @@ - - * setKey('12345678901234567890123456789012'); - * - * $plaintext = str_repeat('a', 1024); - * - * echo $blowfish->decrypt($blowfish->encrypt($plaintext)); - * ?> - * - * - * 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. - * - * @category Crypt - * @package Crypt_Blowfish - * @author Jim Wigginton - * @author Hans-Juergen Petrich - * @copyright 2007 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Crypt_Base - * - * Base cipher class - */ -if (!class_exists('Crypt_Base')) { - include_once 'Base.php'; -} - -/**#@+ - * @access public - * @see Crypt_Blowfish::encrypt() - * @see Crypt_Blowfish::decrypt() - */ -/** - * Encrypt / decrypt using the Counter mode. - * - * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 - */ -define('CRYPT_BLOWFISH_MODE_CTR', CRYPT_MODE_CTR); -/** - * Encrypt / decrypt using the Electronic Code Book mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 - */ -define('CRYPT_BLOWFISH_MODE_ECB', CRYPT_MODE_ECB); -/** - * Encrypt / decrypt using the Code Book Chaining mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - */ -define('CRYPT_BLOWFISH_MODE_CBC', CRYPT_MODE_CBC); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 - */ -define('CRYPT_BLOWFISH_MODE_CFB', CRYPT_MODE_CFB); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 - */ -define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_Base::Crypt_Base() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_BLOWFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_BLOWFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - -/** - * Pure-PHP implementation of Blowfish. - * - * @package Crypt_Blowfish - * @author Jim Wigginton - * @author Hans-Juergen Petrich - * @access public - */ -class Crypt_Blowfish extends Crypt_Base -{ - /** - * Block Length of the cipher - * - * @see Crypt_Base::block_size - * @var Integer - * @access private - */ - var $block_size = 8; - - /** - * The default password key_size used by setPassword() - * - * @see Crypt_Base::password_key_size - * @see Crypt_Base::setPassword() - * @var Integer - * @access private - */ - var $password_key_size = 56; - - /** - * The namespace used by the cipher for its constants. - * - * @see Crypt_Base::const_namespace - * @var String - * @access private - */ - var $const_namespace = 'BLOWFISH'; - - /** - * The mcrypt specific name of the cipher - * - * @see Crypt_Base::cipher_name_mcrypt - * @var String - * @access private - */ - var $cipher_name_mcrypt = 'blowfish'; - - /** - * Optimizing value while CFB-encrypting - * - * @see Crypt_Base::cfb_init_len - * @var Integer - * @access private - */ - var $cfb_init_len = 500; - - /** - * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each - * - * S-Box 1 - * - * @access private - * @var array - */ - var $sbox0 = array ( - 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, - 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, - 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, - 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, - 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, - 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, - 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, - 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, - 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, - 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, - 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, - 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, - 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, - 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, - 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, - 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, - 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, - 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, - 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, - 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, - 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, - 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, - 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, - 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, - 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, - 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, - 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, - 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, - 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, - 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, - 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, - 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a - ); - - /** - * S-Box 1 - * - * @access private - * @var array - */ - var $sbox1 = array( - 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, - 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, - 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, - 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, - 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, - 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, - 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, - 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, - 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, - 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, - 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, - 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, - 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, - 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, - 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, - 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, - 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, - 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, - 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, - 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, - 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, - 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, - 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, - 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, - 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, - 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, - 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, - 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, - 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, - 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, - 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, - 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 - ); - - /** - * S-Box 2 - * - * @access private - * @var array - */ - var $sbox2 = array( - 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, - 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, - 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, - 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, - 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, - 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, - 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, - 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, - 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, - 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, - 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, - 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, - 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, - 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, - 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, - 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, - 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, - 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, - 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, - 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, - 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, - 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, - 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, - 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, - 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, - 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, - 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, - 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, - 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, - 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, - 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, - 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 - ); - - /** - * S-Box 3 - * - * @access private - * @var array - */ - var $sbox3 = array( - 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, - 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, - 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, - 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, - 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, - 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, - 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, - 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, - 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, - 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, - 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, - 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, - 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, - 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, - 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, - 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, - 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, - 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, - 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, - 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, - 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, - 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, - 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, - 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, - 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, - 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, - 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, - 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, - 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, - 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, - 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, - 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 - ); - - /** - * P-Array consists of 18 32-bit subkeys - * - * @var array $parray - * @access private - */ - var $parray = array( - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, - 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b - ); - - /** - * The BCTX-working Array - * - * Holds the expanded key [p] and the key-depended s-boxes [sb] - * - * @var array $bctx - * @access private - */ - var $bctx; - - /** - * Holds the last used key - * - * @var Array - * @access private - */ - var $kl; - - /** - * Sets the key. - * - * Keys can be of any length. Blowfish, itself, requires the use of a key between 32 and max. 448-bits long. - * If the key is less than 32-bits we NOT fill the key to 32bit but let the key as it is to be compatible - * with mcrypt because mcrypt act this way with blowfish key's < 32 bits. - * - * If the key is more than 448-bits, we trim the excess bits. - * - * If the key is not explicitly set, or empty, it'll be assumed a 128 bits key to be all null bytes. - * - * @access public - * @see Crypt_Base::setKey() - * @param String $key - */ - function setKey($key) - { - $keylength = strlen($key); - - if (!$keylength) { - $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - } elseif ($keylength > 56) { - $key = substr($key, 0, 56); - } - - parent::setKey($key); - } - - /** - * Setup the key (expansion) - * - * @see Crypt_Base::_setupKey() - * @access private - */ - function _setupKey() - { - if (isset($this->kl['key']) && $this->key === $this->kl['key']) { - // already expanded - return; - } - $this->kl = array('key' => $this->key); - - /* key-expanding p[] and S-Box building sb[] */ - $this->bctx = array( - 'p' => array(), - 'sb' => array( - $this->sbox0, - $this->sbox1, - $this->sbox2, - $this->sbox3 - ) - ); - - // unpack binary string in unsigned chars - $key = array_values(unpack('C*', $this->key)); - $keyl = count($key); - for ($j = 0, $i = 0; $i < 18; ++$i) { - // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ... - for ($data = 0, $k = 0; $k < 4; ++$k) { - $data = ($data << 8) | $key[$j]; - if (++$j >= $keyl) { - $j = 0; - } - } - $this->bctx['p'][] = $this->parray[$i] ^ $data; - } - - // encrypt the zero-string, replace P1 and P2 with the encrypted data, - // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys - $data = "\0\0\0\0\0\0\0\0"; - for ($i = 0; $i < 18; $i += 2) { - list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data))); - $this->bctx['p'][$i ] = $l; - $this->bctx['p'][$i + 1] = $r; - } - for ($i = 0; $i < 4; ++$i) { - for ($j = 0; $j < 256; $j += 2) { - list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data))); - $this->bctx['sb'][$i][$j ] = $l; - $this->bctx['sb'][$i][$j + 1] = $r; - } - } - } - - /** - * Encrypts a block - * - * @access private - * @param String $in - * @return String - */ - function _encryptBlock($in) - { - $p = $this->bctx["p"]; - // extract($this->bctx["sb"], EXTR_PREFIX_ALL, "sb"); // slower - $sb_0 = $this->bctx["sb"][0]; - $sb_1 = $this->bctx["sb"][1]; - $sb_2 = $this->bctx["sb"][2]; - $sb_3 = $this->bctx["sb"][3]; - - $in = unpack("N*", $in); - $l = $in[1]; - $r = $in[2]; - - for ($i = 0; $i < 16; $i+= 2) { - $l^= $p[$i]; - $r^= ($sb_0[$l >> 24 & 0xff] + - $sb_1[$l >> 16 & 0xff] ^ - $sb_2[$l >> 8 & 0xff]) + - $sb_3[$l & 0xff]; - - $r^= $p[$i + 1]; - $l^= ($sb_0[$r >> 24 & 0xff] + - $sb_1[$r >> 16 & 0xff] ^ - $sb_2[$r >> 8 & 0xff]) + - $sb_3[$r & 0xff]; - } - return pack("N*", $r ^ $p[17], $l ^ $p[16]); - } - - /** - * Decrypts a block - * - * @access private - * @param String $in - * @return String - */ - function _decryptBlock($in) - { - $p = $this->bctx["p"]; - $sb_0 = $this->bctx["sb"][0]; - $sb_1 = $this->bctx["sb"][1]; - $sb_2 = $this->bctx["sb"][2]; - $sb_3 = $this->bctx["sb"][3]; - - $in = unpack("N*", $in); - $l = $in[1]; - $r = $in[2]; - - for ($i = 17; $i > 2; $i-= 2) { - $l^= $p[$i]; - $r^= ($sb_0[$l >> 24 & 0xff] + - $sb_1[$l >> 16 & 0xff] ^ - $sb_2[$l >> 8 & 0xff]) + - $sb_3[$l & 0xff]; - - $r^= $p[$i - 1]; - $l^= ($sb_0[$r >> 24 & 0xff] + - $sb_1[$r >> 16 & 0xff] ^ - $sb_2[$r >> 8 & 0xff]) + - $sb_3[$r & 0xff]; - } - - return pack("N*", $r ^ $p[0], $l ^ $p[1]); - } - - /** - * Setup the performance-optimized function for de/encrypt() - * - * @see Crypt_Base::_setupInlineCrypt() - * @access private - */ - function _setupInlineCrypt() - { - $lambda_functions =& Crypt_Blowfish::_getLambdaFunctions(); - - // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function. - // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one. - $gen_hi_opt_code = (bool)( count($lambda_functions) < 10); - - switch (true) { - case $gen_hi_opt_code: - $code_hash = md5(str_pad("Crypt_Blowfish, {$this->mode}, ", 32, "\0") . $this->key); - break; - default: - $code_hash = "Crypt_Blowfish, {$this->mode}"; - } - - if (!isset($lambda_functions[$code_hash])) { - switch (true) { - case $gen_hi_opt_code: - $p = $this->bctx['p']; - $init_crypt = ' - static $sb_0, $sb_1, $sb_2, $sb_3; - if (!$sb_0) { - $sb_0 = $self->bctx["sb"][0]; - $sb_1 = $self->bctx["sb"][1]; - $sb_2 = $self->bctx["sb"][2]; - $sb_3 = $self->bctx["sb"][3]; - } - '; - break; - default: - $p = array(); - for ($i = 0; $i < 18; ++$i) { - $p[] = '$p_' . $i; - } - $init_crypt = ' - list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"]; - list(' . implode(',', $p) . ') = $self->bctx["p"]; - - '; - } - - // Generating encrypt code: - $encrypt_block = ' - $in = unpack("N*", $in); - $l = $in[1]; - $r = $in[2]; - '; - for ($i = 0; $i < 16; $i+= 2) { - $encrypt_block.= ' - $l^= ' . $p[$i] . '; - $r^= ($sb_0[$l >> 24 & 0xff] + - $sb_1[$l >> 16 & 0xff] ^ - $sb_2[$l >> 8 & 0xff]) + - $sb_3[$l & 0xff]; - - $r^= ' . $p[$i + 1] . '; - $l^= ($sb_0[$r >> 24 & 0xff] + - $sb_1[$r >> 16 & 0xff] ^ - $sb_2[$r >> 8 & 0xff]) + - $sb_3[$r & 0xff]; - '; - } - $encrypt_block.= ' - $in = pack("N*", - $r ^ ' . $p[17] . ', - $l ^ ' . $p[16] . ' - ); - '; - - // Generating decrypt code: - $decrypt_block = ' - $in = unpack("N*", $in); - $l = $in[1]; - $r = $in[2]; - '; - - for ($i = 17; $i > 2; $i-= 2) { - $decrypt_block.= ' - $l^= ' . $p[$i] . '; - $r^= ($sb_0[$l >> 24 & 0xff] + - $sb_1[$l >> 16 & 0xff] ^ - $sb_2[$l >> 8 & 0xff]) + - $sb_3[$l & 0xff]; - - $r^= ' . $p[$i - 1] . '; - $l^= ($sb_0[$r >> 24 & 0xff] + - $sb_1[$r >> 16 & 0xff] ^ - $sb_2[$r >> 8 & 0xff]) + - $sb_3[$r & 0xff]; - '; - } - - $decrypt_block.= ' - $in = pack("N*", - $r ^ ' . $p[0] . ', - $l ^ ' . $p[1] . ' - ); - '; - - $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( - array( - 'init_crypt' => $init_crypt, - 'init_encrypt' => '', - 'init_decrypt' => '', - 'encrypt_block' => $encrypt_block, - 'decrypt_block' => $decrypt_block - ) - ); - } - $this->inline_crypt = $lambda_functions[$code_hash]; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/DES.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/DES.php deleted file mode 100644 index f92f30b2..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/DES.php +++ /dev/null @@ -1,1506 +0,0 @@ - - * setKey('abcdefgh'); - * - * $size = 10 * 1024; - * $plaintext = ''; - * for ($i = 0; $i < $size; $i++) { - * $plaintext.= 'a'; - * } - * - * echo $des->decrypt($des->encrypt($plaintext)); - * ?> - * - * - * 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. - * - * @category Crypt - * @package Crypt_DES - * @author Jim Wigginton - * @copyright 2007 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Crypt_Base - * - * Base cipher class - */ -if (!class_exists('Crypt_Base')) { - include_once 'Base.php'; -} - -/**#@+ - * @access private - * @see Crypt_DES::_setupKey() - * @see Crypt_DES::_processBlock() - */ -/** - * Contains $keys[CRYPT_DES_ENCRYPT] - */ -define('CRYPT_DES_ENCRYPT', 0); -/** - * Contains $keys[CRYPT_DES_DECRYPT] - */ -define('CRYPT_DES_DECRYPT', 1); -/**#@-*/ - -/**#@+ - * @access public - * @see Crypt_DES::encrypt() - * @see Crypt_DES::decrypt() - */ -/** - * Encrypt / decrypt using the Counter mode. - * - * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 - */ -define('CRYPT_DES_MODE_CTR', CRYPT_MODE_CTR); -/** - * Encrypt / decrypt using the Electronic Code Book mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 - */ -define('CRYPT_DES_MODE_ECB', CRYPT_MODE_ECB); -/** - * Encrypt / decrypt using the Code Book Chaining mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - */ -define('CRYPT_DES_MODE_CBC', CRYPT_MODE_CBC); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 - */ -define('CRYPT_DES_MODE_CFB', CRYPT_MODE_CFB); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 - */ -define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_Base::Crypt_Base() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_DES_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_DES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - -/** - * Pure-PHP implementation of DES. - * - * @package Crypt_DES - * @author Jim Wigginton - * @access public - */ -class Crypt_DES extends Crypt_Base -{ - /** - * Block Length of the cipher - * - * @see Crypt_Base::block_size - * @var Integer - * @access private - */ - var $block_size = 8; - - /** - * The Key - * - * @see Crypt_Base::key - * @see setKey() - * @var String - * @access private - */ - var $key = "\0\0\0\0\0\0\0\0"; - - /** - * The default password key_size used by setPassword() - * - * @see Crypt_Base::password_key_size - * @see Crypt_Base::setPassword() - * @var Integer - * @access private - */ - var $password_key_size = 8; - - /** - * The namespace used by the cipher for its constants. - * - * @see Crypt_Base::const_namespace - * @var String - * @access private - */ - var $const_namespace = 'DES'; - - /** - * The mcrypt specific name of the cipher - * - * @see Crypt_Base::cipher_name_mcrypt - * @var String - * @access private - */ - var $cipher_name_mcrypt = 'des'; - - /** - * Optimizing value while CFB-encrypting - * - * @see Crypt_Base::cfb_init_len - * @var Integer - * @access private - */ - var $cfb_init_len = 500; - - /** - * Switch for DES/3DES encryption - * - * Used only if $engine == CRYPT_DES_MODE_INTERNAL - * - * @see Crypt_DES::_setupKey() - * @see Crypt_DES::_processBlock() - * @var Integer - * @access private - */ - var $des_rounds = 1; - - /** - * max possible size of $key - * - * @see Crypt_DES::setKey() - * @var String - * @access private - */ - var $key_size_max = 8; - - /** - * The Key Schedule - * - * @see Crypt_DES::_setupKey() - * @var Array - * @access private - */ - var $keys; - - /** - * Shuffle table. - * - * For each byte value index, the entry holds an 8-byte string - * with each byte containing all bits in the same state as the - * corresponding bit in the index value. - * - * @see Crypt_DES::_processBlock() - * @see Crypt_DES::_setupKey() - * @var Array - * @access private - */ - var $shuffle = array( - "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF", - "\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF", - "\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF", - "\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF", - "\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF", - "\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF", - "\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF", - "\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF", - "\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF", - "\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF", - "\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF", - "\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF", - "\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF", - "\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF", - "\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF", - "\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF", - "\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF", - "\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF", - "\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF", - "\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF", - "\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF", - "\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF", - "\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF", - "\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF", - "\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF", - "\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF", - "\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF", - "\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF", - "\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF", - "\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF", - "\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF", - "\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF", - "\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF", - "\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF", - "\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF", - "\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF", - "\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF", - "\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF", - "\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF", - "\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF", - "\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF", - "\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF", - "\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF", - "\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF", - "\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF", - "\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF", - "\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF", - "\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF", - "\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF", - "\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF", - "\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF", - "\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF", - "\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF", - "\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF", - "\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF", - "\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF", - "\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF", - "\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF", - "\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF", - "\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF", - "\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF", - "\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF", - "\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF", - "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF", - "\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF", - "\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF", - "\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF", - "\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF", - "\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF", - "\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF", - "\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF", - "\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF", - "\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF", - "\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF", - "\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF", - "\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF", - "\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF", - "\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF", - "\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF", - "\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF", - "\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF", - "\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF", - "\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF", - "\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF", - "\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF", - "\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF", - "\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF", - "\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF", - "\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF", - "\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF", - "\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF", - "\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF", - "\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF", - "\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF", - "\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF", - "\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF", - "\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF", - "\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF", - "\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF", - "\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF", - "\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF", - "\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF", - "\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF", - "\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF", - "\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF", - "\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF", - "\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF", - "\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF", - "\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF", - "\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF", - "\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF", - "\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF", - "\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF", - "\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF", - "\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF", - "\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF", - "\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF", - "\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF", - "\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF", - "\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF", - "\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF", - "\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF", - "\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF", - "\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF", - "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF", - "\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF", - "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF", - "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" - ); - - /** - * IP mapping helper table. - * - * Indexing this table with each source byte performs the initial bit permutation. - * - * @var Array - * @access private - */ - var $ipmap = array( - 0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31, - 0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33, - 0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71, - 0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73, - 0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35, - 0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37, - 0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75, - 0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77, - 0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1, - 0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3, - 0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1, - 0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3, - 0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5, - 0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7, - 0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5, - 0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7, - 0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39, - 0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B, - 0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79, - 0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B, - 0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D, - 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, - 0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D, - 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, - 0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9, - 0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB, - 0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9, - 0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB, - 0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD, - 0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF, - 0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD, - 0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF - ); - - /** - * Inverse IP mapping helper table. - * Indexing this table with a byte value reverses the bit order. - * - * @var Array - * @access private - */ - var $invipmap = array( - 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, - 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, - 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, - 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, - 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, - 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, - 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, - 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, - 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, - 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, - 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, - 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, - 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, - 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, - 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, - 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, - 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, - 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, - 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, - 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, - 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, - 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, - 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, - 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, - 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, - 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, - 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, - 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, - 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, - 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, - 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, - 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF - ); - - /** - * Pre-permuted S-box1 - * - * Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the - * P table: concatenation can then be replaced by exclusive ORs. - * - * @var Array - * @access private - */ - var $sbox1 = array( - 0x00808200, 0x00000000, 0x00008000, 0x00808202, - 0x00808002, 0x00008202, 0x00000002, 0x00008000, - 0x00000200, 0x00808200, 0x00808202, 0x00000200, - 0x00800202, 0x00808002, 0x00800000, 0x00000002, - 0x00000202, 0x00800200, 0x00800200, 0x00008200, - 0x00008200, 0x00808000, 0x00808000, 0x00800202, - 0x00008002, 0x00800002, 0x00800002, 0x00008002, - 0x00000000, 0x00000202, 0x00008202, 0x00800000, - 0x00008000, 0x00808202, 0x00000002, 0x00808000, - 0x00808200, 0x00800000, 0x00800000, 0x00000200, - 0x00808002, 0x00008000, 0x00008200, 0x00800002, - 0x00000200, 0x00000002, 0x00800202, 0x00008202, - 0x00808202, 0x00008002, 0x00808000, 0x00800202, - 0x00800002, 0x00000202, 0x00008202, 0x00808200, - 0x00000202, 0x00800200, 0x00800200, 0x00000000, - 0x00008002, 0x00008200, 0x00000000, 0x00808002 - ); - - /** - * Pre-permuted S-box2 - * - * @var Array - * @access private - */ - var $sbox2 = array( - 0x40084010, 0x40004000, 0x00004000, 0x00084010, - 0x00080000, 0x00000010, 0x40080010, 0x40004010, - 0x40000010, 0x40084010, 0x40084000, 0x40000000, - 0x40004000, 0x00080000, 0x00000010, 0x40080010, - 0x00084000, 0x00080010, 0x40004010, 0x00000000, - 0x40000000, 0x00004000, 0x00084010, 0x40080000, - 0x00080010, 0x40000010, 0x00000000, 0x00084000, - 0x00004010, 0x40084000, 0x40080000, 0x00004010, - 0x00000000, 0x00084010, 0x40080010, 0x00080000, - 0x40004010, 0x40080000, 0x40084000, 0x00004000, - 0x40080000, 0x40004000, 0x00000010, 0x40084010, - 0x00084010, 0x00000010, 0x00004000, 0x40000000, - 0x00004010, 0x40084000, 0x00080000, 0x40000010, - 0x00080010, 0x40004010, 0x40000010, 0x00080010, - 0x00084000, 0x00000000, 0x40004000, 0x00004010, - 0x40000000, 0x40080010, 0x40084010, 0x00084000 - ); - - /** - * Pre-permuted S-box3 - * - * @var Array - * @access private - */ - var $sbox3 = array( - 0x00000104, 0x04010100, 0x00000000, 0x04010004, - 0x04000100, 0x00000000, 0x00010104, 0x04000100, - 0x00010004, 0x04000004, 0x04000004, 0x00010000, - 0x04010104, 0x00010004, 0x04010000, 0x00000104, - 0x04000000, 0x00000004, 0x04010100, 0x00000100, - 0x00010100, 0x04010000, 0x04010004, 0x00010104, - 0x04000104, 0x00010100, 0x00010000, 0x04000104, - 0x00000004, 0x04010104, 0x00000100, 0x04000000, - 0x04010100, 0x04000000, 0x00010004, 0x00000104, - 0x00010000, 0x04010100, 0x04000100, 0x00000000, - 0x00000100, 0x00010004, 0x04010104, 0x04000100, - 0x04000004, 0x00000100, 0x00000000, 0x04010004, - 0x04000104, 0x00010000, 0x04000000, 0x04010104, - 0x00000004, 0x00010104, 0x00010100, 0x04000004, - 0x04010000, 0x04000104, 0x00000104, 0x04010000, - 0x00010104, 0x00000004, 0x04010004, 0x00010100 - ); - - /** - * Pre-permuted S-box4 - * - * @var Array - * @access private - */ - var $sbox4 = array( - 0x80401000, 0x80001040, 0x80001040, 0x00000040, - 0x00401040, 0x80400040, 0x80400000, 0x80001000, - 0x00000000, 0x00401000, 0x00401000, 0x80401040, - 0x80000040, 0x00000000, 0x00400040, 0x80400000, - 0x80000000, 0x00001000, 0x00400000, 0x80401000, - 0x00000040, 0x00400000, 0x80001000, 0x00001040, - 0x80400040, 0x80000000, 0x00001040, 0x00400040, - 0x00001000, 0x00401040, 0x80401040, 0x80000040, - 0x00400040, 0x80400000, 0x00401000, 0x80401040, - 0x80000040, 0x00000000, 0x00000000, 0x00401000, - 0x00001040, 0x00400040, 0x80400040, 0x80000000, - 0x80401000, 0x80001040, 0x80001040, 0x00000040, - 0x80401040, 0x80000040, 0x80000000, 0x00001000, - 0x80400000, 0x80001000, 0x00401040, 0x80400040, - 0x80001000, 0x00001040, 0x00400000, 0x80401000, - 0x00000040, 0x00400000, 0x00001000, 0x00401040 - ); - - /** - * Pre-permuted S-box5 - * - * @var Array - * @access private - */ - var $sbox5 = array( - 0x00000080, 0x01040080, 0x01040000, 0x21000080, - 0x00040000, 0x00000080, 0x20000000, 0x01040000, - 0x20040080, 0x00040000, 0x01000080, 0x20040080, - 0x21000080, 0x21040000, 0x00040080, 0x20000000, - 0x01000000, 0x20040000, 0x20040000, 0x00000000, - 0x20000080, 0x21040080, 0x21040080, 0x01000080, - 0x21040000, 0x20000080, 0x00000000, 0x21000000, - 0x01040080, 0x01000000, 0x21000000, 0x00040080, - 0x00040000, 0x21000080, 0x00000080, 0x01000000, - 0x20000000, 0x01040000, 0x21000080, 0x20040080, - 0x01000080, 0x20000000, 0x21040000, 0x01040080, - 0x20040080, 0x00000080, 0x01000000, 0x21040000, - 0x21040080, 0x00040080, 0x21000000, 0x21040080, - 0x01040000, 0x00000000, 0x20040000, 0x21000000, - 0x00040080, 0x01000080, 0x20000080, 0x00040000, - 0x00000000, 0x20040000, 0x01040080, 0x20000080 - ); - - /** - * Pre-permuted S-box6 - * - * @var Array - * @access private - */ - var $sbox6 = array( - 0x10000008, 0x10200000, 0x00002000, 0x10202008, - 0x10200000, 0x00000008, 0x10202008, 0x00200000, - 0x10002000, 0x00202008, 0x00200000, 0x10000008, - 0x00200008, 0x10002000, 0x10000000, 0x00002008, - 0x00000000, 0x00200008, 0x10002008, 0x00002000, - 0x00202000, 0x10002008, 0x00000008, 0x10200008, - 0x10200008, 0x00000000, 0x00202008, 0x10202000, - 0x00002008, 0x00202000, 0x10202000, 0x10000000, - 0x10002000, 0x00000008, 0x10200008, 0x00202000, - 0x10202008, 0x00200000, 0x00002008, 0x10000008, - 0x00200000, 0x10002000, 0x10000000, 0x00002008, - 0x10000008, 0x10202008, 0x00202000, 0x10200000, - 0x00202008, 0x10202000, 0x00000000, 0x10200008, - 0x00000008, 0x00002000, 0x10200000, 0x00202008, - 0x00002000, 0x00200008, 0x10002008, 0x00000000, - 0x10202000, 0x10000000, 0x00200008, 0x10002008 - ); - - /** - * Pre-permuted S-box7 - * - * @var Array - * @access private - */ - var $sbox7 = array( - 0x00100000, 0x02100001, 0x02000401, 0x00000000, - 0x00000400, 0x02000401, 0x00100401, 0x02100400, - 0x02100401, 0x00100000, 0x00000000, 0x02000001, - 0x00000001, 0x02000000, 0x02100001, 0x00000401, - 0x02000400, 0x00100401, 0x00100001, 0x02000400, - 0x02000001, 0x02100000, 0x02100400, 0x00100001, - 0x02100000, 0x00000400, 0x00000401, 0x02100401, - 0x00100400, 0x00000001, 0x02000000, 0x00100400, - 0x02000000, 0x00100400, 0x00100000, 0x02000401, - 0x02000401, 0x02100001, 0x02100001, 0x00000001, - 0x00100001, 0x02000000, 0x02000400, 0x00100000, - 0x02100400, 0x00000401, 0x00100401, 0x02100400, - 0x00000401, 0x02000001, 0x02100401, 0x02100000, - 0x00100400, 0x00000000, 0x00000001, 0x02100401, - 0x00000000, 0x00100401, 0x02100000, 0x00000400, - 0x02000001, 0x02000400, 0x00000400, 0x00100001 - ); - - /** - * Pre-permuted S-box8 - * - * @var Array - * @access private - */ - var $sbox8 = array( - 0x08000820, 0x00000800, 0x00020000, 0x08020820, - 0x08000000, 0x08000820, 0x00000020, 0x08000000, - 0x00020020, 0x08020000, 0x08020820, 0x00020800, - 0x08020800, 0x00020820, 0x00000800, 0x00000020, - 0x08020000, 0x08000020, 0x08000800, 0x00000820, - 0x00020800, 0x00020020, 0x08020020, 0x08020800, - 0x00000820, 0x00000000, 0x00000000, 0x08020020, - 0x08000020, 0x08000800, 0x00020820, 0x00020000, - 0x00020820, 0x00020000, 0x08020800, 0x00000800, - 0x00000020, 0x08020020, 0x00000800, 0x00020820, - 0x08000800, 0x00000020, 0x08000020, 0x08020000, - 0x08020020, 0x08000000, 0x00020000, 0x08000820, - 0x00000000, 0x08020820, 0x00020020, 0x08000020, - 0x08020000, 0x08000800, 0x08000820, 0x00000000, - 0x08020820, 0x00020800, 0x00020800, 0x00000820, - 0x00000820, 0x00020020, 0x08000000, 0x08020800 - ); - - /** - * Sets the key. - * - * Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we - * only use the first eight, if $key has more then eight characters in it, and pad $key with the - * null byte if it is less then eight characters long. - * - * DES also requires that every eighth bit be a parity bit, however, we'll ignore that. - * - * If the key is not explicitly set, it'll be assumed to be all zero's. - * - * @see Crypt_Base::setKey() - * @access public - * @param String $key - */ - function setKey($key) - { - // We check/cut here only up to max length of the key. - // Key padding to the proper length will be done in _setupKey() - if (strlen($key) > $this->key_size_max) { - $key = substr($key, 0, $this->key_size_max); - } - - // Sets the key - parent::setKey($key); - } - - /** - * Encrypts a block - * - * @see Crypt_Base::_encryptBlock() - * @see Crypt_Base::encrypt() - * @see Crypt_DES::encrypt() - * @access private - * @param String $in - * @return String - */ - function _encryptBlock($in) - { - return $this->_processBlock($in, CRYPT_DES_ENCRYPT); - } - - /** - * Decrypts a block - * - * @see Crypt_Base::_decryptBlock() - * @see Crypt_Base::decrypt() - * @see Crypt_DES::decrypt() - * @access private - * @param String $in - * @return String - */ - function _decryptBlock($in) - { - return $this->_processBlock($in, CRYPT_DES_DECRYPT); - } - - /** - * Encrypts or decrypts a 64-bit block - * - * $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See - * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general - * idea of what this function does. - * - * @see Crypt_DES::_encryptBlock() - * @see Crypt_DES::_decryptBlock() - * @access private - * @param String $block - * @param Integer $mode - * @return String - */ - function _processBlock($block, $mode) - { - static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip; - if (!$sbox1) { - $sbox1 = array_map("intval", $this->sbox1); - $sbox2 = array_map("intval", $this->sbox2); - $sbox3 = array_map("intval", $this->sbox3); - $sbox4 = array_map("intval", $this->sbox4); - $sbox5 = array_map("intval", $this->sbox5); - $sbox6 = array_map("intval", $this->sbox6); - $sbox7 = array_map("intval", $this->sbox7); - $sbox8 = array_map("intval", $this->sbox8); - /* Merge $shuffle with $[inv]ipmap */ - for ($i = 0; $i < 256; ++$i) { - $shuffleip[] = $this->shuffle[$this->ipmap[$i]]; - $shuffleinvip[] = $this->shuffle[$this->invipmap[$i]]; - } - } - - $keys = $this->keys[$mode]; - $ki = -1; - - // Do the initial IP permutation. - $t = unpack('Nl/Nr', $block); - list($l, $r) = array($t['l'], $t['r']); - $block = ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | - ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | - ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | - ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | - ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | - ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | - ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | - ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); - - // Extract L0 and R0. - $t = unpack('Nl/Nr', $block); - list($l, $r) = array($t['l'], $t['r']); - - for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) { - // Perform the 16 steps. - for ($i = 0; $i < 16; $i++) { - // start of "the Feistel (F) function" - see the following URL: - // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png - // Merge key schedule. - $b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki]; - $b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[++$ki]; - - // S-box indexing. - $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^ - $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^ - $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^ - $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $l; - // end of "the Feistel (F) function" - - $l = $r; - $r = $t; - } - - // Last step should not permute L & R. - $t = $l; - $l = $r; - $r = $t; - } - - // Perform the inverse IP permutation. - return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | - ($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | - ($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | - ($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | - ($shuffleinvip[($r >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | - ($shuffleinvip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | - ($shuffleinvip[ $r & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | - ($shuffleinvip[ $l & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); - } - - /** - * Creates the key schedule - * - * @see Crypt_Base::_setupKey() - * @access private - */ - function _setupKey() - { - if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) { - // already expanded - return; - } - $this->kl = array('key' => $this->key, 'des_rounds' => $this->des_rounds); - - static $shifts = array( // number of key bits shifted per round - 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 - ); - - static $pc1map = array( - 0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C, - 0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E, - 0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C, - 0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E, - 0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C, - 0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E, - 0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C, - 0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E, - 0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C, - 0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E, - 0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C, - 0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E, - 0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C, - 0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E, - 0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C, - 0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E, - 0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C, - 0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E, - 0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C, - 0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E, - 0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC, - 0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE, - 0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC, - 0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE, - 0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC, - 0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE, - 0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC, - 0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE, - 0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC, - 0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE, - 0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC, - 0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE - ); - - // Mapping tables for the PC-2 transformation. - static $pc2mapc1 = array( - 0x00000000, 0x00000400, 0x00200000, 0x00200400, - 0x00000001, 0x00000401, 0x00200001, 0x00200401, - 0x02000000, 0x02000400, 0x02200000, 0x02200400, - 0x02000001, 0x02000401, 0x02200001, 0x02200401 - ); - static $pc2mapc2 = array( - 0x00000000, 0x00000800, 0x08000000, 0x08000800, - 0x00010000, 0x00010800, 0x08010000, 0x08010800, - 0x00000000, 0x00000800, 0x08000000, 0x08000800, - 0x00010000, 0x00010800, 0x08010000, 0x08010800, - 0x00000100, 0x00000900, 0x08000100, 0x08000900, - 0x00010100, 0x00010900, 0x08010100, 0x08010900, - 0x00000100, 0x00000900, 0x08000100, 0x08000900, - 0x00010100, 0x00010900, 0x08010100, 0x08010900, - 0x00000010, 0x00000810, 0x08000010, 0x08000810, - 0x00010010, 0x00010810, 0x08010010, 0x08010810, - 0x00000010, 0x00000810, 0x08000010, 0x08000810, - 0x00010010, 0x00010810, 0x08010010, 0x08010810, - 0x00000110, 0x00000910, 0x08000110, 0x08000910, - 0x00010110, 0x00010910, 0x08010110, 0x08010910, - 0x00000110, 0x00000910, 0x08000110, 0x08000910, - 0x00010110, 0x00010910, 0x08010110, 0x08010910, - 0x00040000, 0x00040800, 0x08040000, 0x08040800, - 0x00050000, 0x00050800, 0x08050000, 0x08050800, - 0x00040000, 0x00040800, 0x08040000, 0x08040800, - 0x00050000, 0x00050800, 0x08050000, 0x08050800, - 0x00040100, 0x00040900, 0x08040100, 0x08040900, - 0x00050100, 0x00050900, 0x08050100, 0x08050900, - 0x00040100, 0x00040900, 0x08040100, 0x08040900, - 0x00050100, 0x00050900, 0x08050100, 0x08050900, - 0x00040010, 0x00040810, 0x08040010, 0x08040810, - 0x00050010, 0x00050810, 0x08050010, 0x08050810, - 0x00040010, 0x00040810, 0x08040010, 0x08040810, - 0x00050010, 0x00050810, 0x08050010, 0x08050810, - 0x00040110, 0x00040910, 0x08040110, 0x08040910, - 0x00050110, 0x00050910, 0x08050110, 0x08050910, - 0x00040110, 0x00040910, 0x08040110, 0x08040910, - 0x00050110, 0x00050910, 0x08050110, 0x08050910, - 0x01000000, 0x01000800, 0x09000000, 0x09000800, - 0x01010000, 0x01010800, 0x09010000, 0x09010800, - 0x01000000, 0x01000800, 0x09000000, 0x09000800, - 0x01010000, 0x01010800, 0x09010000, 0x09010800, - 0x01000100, 0x01000900, 0x09000100, 0x09000900, - 0x01010100, 0x01010900, 0x09010100, 0x09010900, - 0x01000100, 0x01000900, 0x09000100, 0x09000900, - 0x01010100, 0x01010900, 0x09010100, 0x09010900, - 0x01000010, 0x01000810, 0x09000010, 0x09000810, - 0x01010010, 0x01010810, 0x09010010, 0x09010810, - 0x01000010, 0x01000810, 0x09000010, 0x09000810, - 0x01010010, 0x01010810, 0x09010010, 0x09010810, - 0x01000110, 0x01000910, 0x09000110, 0x09000910, - 0x01010110, 0x01010910, 0x09010110, 0x09010910, - 0x01000110, 0x01000910, 0x09000110, 0x09000910, - 0x01010110, 0x01010910, 0x09010110, 0x09010910, - 0x01040000, 0x01040800, 0x09040000, 0x09040800, - 0x01050000, 0x01050800, 0x09050000, 0x09050800, - 0x01040000, 0x01040800, 0x09040000, 0x09040800, - 0x01050000, 0x01050800, 0x09050000, 0x09050800, - 0x01040100, 0x01040900, 0x09040100, 0x09040900, - 0x01050100, 0x01050900, 0x09050100, 0x09050900, - 0x01040100, 0x01040900, 0x09040100, 0x09040900, - 0x01050100, 0x01050900, 0x09050100, 0x09050900, - 0x01040010, 0x01040810, 0x09040010, 0x09040810, - 0x01050010, 0x01050810, 0x09050010, 0x09050810, - 0x01040010, 0x01040810, 0x09040010, 0x09040810, - 0x01050010, 0x01050810, 0x09050010, 0x09050810, - 0x01040110, 0x01040910, 0x09040110, 0x09040910, - 0x01050110, 0x01050910, 0x09050110, 0x09050910, - 0x01040110, 0x01040910, 0x09040110, 0x09040910, - 0x01050110, 0x01050910, 0x09050110, 0x09050910 - ); - static $pc2mapc3 = array( - 0x00000000, 0x00000004, 0x00001000, 0x00001004, - 0x00000000, 0x00000004, 0x00001000, 0x00001004, - 0x10000000, 0x10000004, 0x10001000, 0x10001004, - 0x10000000, 0x10000004, 0x10001000, 0x10001004, - 0x00000020, 0x00000024, 0x00001020, 0x00001024, - 0x00000020, 0x00000024, 0x00001020, 0x00001024, - 0x10000020, 0x10000024, 0x10001020, 0x10001024, - 0x10000020, 0x10000024, 0x10001020, 0x10001024, - 0x00080000, 0x00080004, 0x00081000, 0x00081004, - 0x00080000, 0x00080004, 0x00081000, 0x00081004, - 0x10080000, 0x10080004, 0x10081000, 0x10081004, - 0x10080000, 0x10080004, 0x10081000, 0x10081004, - 0x00080020, 0x00080024, 0x00081020, 0x00081024, - 0x00080020, 0x00080024, 0x00081020, 0x00081024, - 0x10080020, 0x10080024, 0x10081020, 0x10081024, - 0x10080020, 0x10080024, 0x10081020, 0x10081024, - 0x20000000, 0x20000004, 0x20001000, 0x20001004, - 0x20000000, 0x20000004, 0x20001000, 0x20001004, - 0x30000000, 0x30000004, 0x30001000, 0x30001004, - 0x30000000, 0x30000004, 0x30001000, 0x30001004, - 0x20000020, 0x20000024, 0x20001020, 0x20001024, - 0x20000020, 0x20000024, 0x20001020, 0x20001024, - 0x30000020, 0x30000024, 0x30001020, 0x30001024, - 0x30000020, 0x30000024, 0x30001020, 0x30001024, - 0x20080000, 0x20080004, 0x20081000, 0x20081004, - 0x20080000, 0x20080004, 0x20081000, 0x20081004, - 0x30080000, 0x30080004, 0x30081000, 0x30081004, - 0x30080000, 0x30080004, 0x30081000, 0x30081004, - 0x20080020, 0x20080024, 0x20081020, 0x20081024, - 0x20080020, 0x20080024, 0x20081020, 0x20081024, - 0x30080020, 0x30080024, 0x30081020, 0x30081024, - 0x30080020, 0x30080024, 0x30081020, 0x30081024, - 0x00000002, 0x00000006, 0x00001002, 0x00001006, - 0x00000002, 0x00000006, 0x00001002, 0x00001006, - 0x10000002, 0x10000006, 0x10001002, 0x10001006, - 0x10000002, 0x10000006, 0x10001002, 0x10001006, - 0x00000022, 0x00000026, 0x00001022, 0x00001026, - 0x00000022, 0x00000026, 0x00001022, 0x00001026, - 0x10000022, 0x10000026, 0x10001022, 0x10001026, - 0x10000022, 0x10000026, 0x10001022, 0x10001026, - 0x00080002, 0x00080006, 0x00081002, 0x00081006, - 0x00080002, 0x00080006, 0x00081002, 0x00081006, - 0x10080002, 0x10080006, 0x10081002, 0x10081006, - 0x10080002, 0x10080006, 0x10081002, 0x10081006, - 0x00080022, 0x00080026, 0x00081022, 0x00081026, - 0x00080022, 0x00080026, 0x00081022, 0x00081026, - 0x10080022, 0x10080026, 0x10081022, 0x10081026, - 0x10080022, 0x10080026, 0x10081022, 0x10081026, - 0x20000002, 0x20000006, 0x20001002, 0x20001006, - 0x20000002, 0x20000006, 0x20001002, 0x20001006, - 0x30000002, 0x30000006, 0x30001002, 0x30001006, - 0x30000002, 0x30000006, 0x30001002, 0x30001006, - 0x20000022, 0x20000026, 0x20001022, 0x20001026, - 0x20000022, 0x20000026, 0x20001022, 0x20001026, - 0x30000022, 0x30000026, 0x30001022, 0x30001026, - 0x30000022, 0x30000026, 0x30001022, 0x30001026, - 0x20080002, 0x20080006, 0x20081002, 0x20081006, - 0x20080002, 0x20080006, 0x20081002, 0x20081006, - 0x30080002, 0x30080006, 0x30081002, 0x30081006, - 0x30080002, 0x30080006, 0x30081002, 0x30081006, - 0x20080022, 0x20080026, 0x20081022, 0x20081026, - 0x20080022, 0x20080026, 0x20081022, 0x20081026, - 0x30080022, 0x30080026, 0x30081022, 0x30081026, - 0x30080022, 0x30080026, 0x30081022, 0x30081026 - ); - static $pc2mapc4 = array( - 0x00000000, 0x00100000, 0x00000008, 0x00100008, - 0x00000200, 0x00100200, 0x00000208, 0x00100208, - 0x00000000, 0x00100000, 0x00000008, 0x00100008, - 0x00000200, 0x00100200, 0x00000208, 0x00100208, - 0x04000000, 0x04100000, 0x04000008, 0x04100008, - 0x04000200, 0x04100200, 0x04000208, 0x04100208, - 0x04000000, 0x04100000, 0x04000008, 0x04100008, - 0x04000200, 0x04100200, 0x04000208, 0x04100208, - 0x00002000, 0x00102000, 0x00002008, 0x00102008, - 0x00002200, 0x00102200, 0x00002208, 0x00102208, - 0x00002000, 0x00102000, 0x00002008, 0x00102008, - 0x00002200, 0x00102200, 0x00002208, 0x00102208, - 0x04002000, 0x04102000, 0x04002008, 0x04102008, - 0x04002200, 0x04102200, 0x04002208, 0x04102208, - 0x04002000, 0x04102000, 0x04002008, 0x04102008, - 0x04002200, 0x04102200, 0x04002208, 0x04102208, - 0x00000000, 0x00100000, 0x00000008, 0x00100008, - 0x00000200, 0x00100200, 0x00000208, 0x00100208, - 0x00000000, 0x00100000, 0x00000008, 0x00100008, - 0x00000200, 0x00100200, 0x00000208, 0x00100208, - 0x04000000, 0x04100000, 0x04000008, 0x04100008, - 0x04000200, 0x04100200, 0x04000208, 0x04100208, - 0x04000000, 0x04100000, 0x04000008, 0x04100008, - 0x04000200, 0x04100200, 0x04000208, 0x04100208, - 0x00002000, 0x00102000, 0x00002008, 0x00102008, - 0x00002200, 0x00102200, 0x00002208, 0x00102208, - 0x00002000, 0x00102000, 0x00002008, 0x00102008, - 0x00002200, 0x00102200, 0x00002208, 0x00102208, - 0x04002000, 0x04102000, 0x04002008, 0x04102008, - 0x04002200, 0x04102200, 0x04002208, 0x04102208, - 0x04002000, 0x04102000, 0x04002008, 0x04102008, - 0x04002200, 0x04102200, 0x04002208, 0x04102208, - 0x00020000, 0x00120000, 0x00020008, 0x00120008, - 0x00020200, 0x00120200, 0x00020208, 0x00120208, - 0x00020000, 0x00120000, 0x00020008, 0x00120008, - 0x00020200, 0x00120200, 0x00020208, 0x00120208, - 0x04020000, 0x04120000, 0x04020008, 0x04120008, - 0x04020200, 0x04120200, 0x04020208, 0x04120208, - 0x04020000, 0x04120000, 0x04020008, 0x04120008, - 0x04020200, 0x04120200, 0x04020208, 0x04120208, - 0x00022000, 0x00122000, 0x00022008, 0x00122008, - 0x00022200, 0x00122200, 0x00022208, 0x00122208, - 0x00022000, 0x00122000, 0x00022008, 0x00122008, - 0x00022200, 0x00122200, 0x00022208, 0x00122208, - 0x04022000, 0x04122000, 0x04022008, 0x04122008, - 0x04022200, 0x04122200, 0x04022208, 0x04122208, - 0x04022000, 0x04122000, 0x04022008, 0x04122008, - 0x04022200, 0x04122200, 0x04022208, 0x04122208, - 0x00020000, 0x00120000, 0x00020008, 0x00120008, - 0x00020200, 0x00120200, 0x00020208, 0x00120208, - 0x00020000, 0x00120000, 0x00020008, 0x00120008, - 0x00020200, 0x00120200, 0x00020208, 0x00120208, - 0x04020000, 0x04120000, 0x04020008, 0x04120008, - 0x04020200, 0x04120200, 0x04020208, 0x04120208, - 0x04020000, 0x04120000, 0x04020008, 0x04120008, - 0x04020200, 0x04120200, 0x04020208, 0x04120208, - 0x00022000, 0x00122000, 0x00022008, 0x00122008, - 0x00022200, 0x00122200, 0x00022208, 0x00122208, - 0x00022000, 0x00122000, 0x00022008, 0x00122008, - 0x00022200, 0x00122200, 0x00022208, 0x00122208, - 0x04022000, 0x04122000, 0x04022008, 0x04122008, - 0x04022200, 0x04122200, 0x04022208, 0x04122208, - 0x04022000, 0x04122000, 0x04022008, 0x04122008, - 0x04022200, 0x04122200, 0x04022208, 0x04122208 - ); - static $pc2mapd1 = array( - 0x00000000, 0x00000001, 0x08000000, 0x08000001, - 0x00200000, 0x00200001, 0x08200000, 0x08200001, - 0x00000002, 0x00000003, 0x08000002, 0x08000003, - 0x00200002, 0x00200003, 0x08200002, 0x08200003 - ); - static $pc2mapd2 = array( - 0x00000000, 0x00100000, 0x00000800, 0x00100800, - 0x00000000, 0x00100000, 0x00000800, 0x00100800, - 0x04000000, 0x04100000, 0x04000800, 0x04100800, - 0x04000000, 0x04100000, 0x04000800, 0x04100800, - 0x00000004, 0x00100004, 0x00000804, 0x00100804, - 0x00000004, 0x00100004, 0x00000804, 0x00100804, - 0x04000004, 0x04100004, 0x04000804, 0x04100804, - 0x04000004, 0x04100004, 0x04000804, 0x04100804, - 0x00000000, 0x00100000, 0x00000800, 0x00100800, - 0x00000000, 0x00100000, 0x00000800, 0x00100800, - 0x04000000, 0x04100000, 0x04000800, 0x04100800, - 0x04000000, 0x04100000, 0x04000800, 0x04100800, - 0x00000004, 0x00100004, 0x00000804, 0x00100804, - 0x00000004, 0x00100004, 0x00000804, 0x00100804, - 0x04000004, 0x04100004, 0x04000804, 0x04100804, - 0x04000004, 0x04100004, 0x04000804, 0x04100804, - 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, - 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, - 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, - 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, - 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, - 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, - 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, - 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, - 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, - 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, - 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, - 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, - 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, - 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, - 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, - 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, - 0x00020000, 0x00120000, 0x00020800, 0x00120800, - 0x00020000, 0x00120000, 0x00020800, 0x00120800, - 0x04020000, 0x04120000, 0x04020800, 0x04120800, - 0x04020000, 0x04120000, 0x04020800, 0x04120800, - 0x00020004, 0x00120004, 0x00020804, 0x00120804, - 0x00020004, 0x00120004, 0x00020804, 0x00120804, - 0x04020004, 0x04120004, 0x04020804, 0x04120804, - 0x04020004, 0x04120004, 0x04020804, 0x04120804, - 0x00020000, 0x00120000, 0x00020800, 0x00120800, - 0x00020000, 0x00120000, 0x00020800, 0x00120800, - 0x04020000, 0x04120000, 0x04020800, 0x04120800, - 0x04020000, 0x04120000, 0x04020800, 0x04120800, - 0x00020004, 0x00120004, 0x00020804, 0x00120804, - 0x00020004, 0x00120004, 0x00020804, 0x00120804, - 0x04020004, 0x04120004, 0x04020804, 0x04120804, - 0x04020004, 0x04120004, 0x04020804, 0x04120804, - 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, - 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, - 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, - 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, - 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, - 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, - 0x04020204, 0x04120204, 0x04020A04, 0x04120A04, - 0x04020204, 0x04120204, 0x04020A04, 0x04120A04, - 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, - 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, - 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, - 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, - 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, - 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, - 0x04020204, 0x04120204, 0x04020A04, 0x04120A04, - 0x04020204, 0x04120204, 0x04020A04, 0x04120A04 - ); - static $pc2mapd3 = array( - 0x00000000, 0x00010000, 0x02000000, 0x02010000, - 0x00000020, 0x00010020, 0x02000020, 0x02010020, - 0x00040000, 0x00050000, 0x02040000, 0x02050000, - 0x00040020, 0x00050020, 0x02040020, 0x02050020, - 0x00002000, 0x00012000, 0x02002000, 0x02012000, - 0x00002020, 0x00012020, 0x02002020, 0x02012020, - 0x00042000, 0x00052000, 0x02042000, 0x02052000, - 0x00042020, 0x00052020, 0x02042020, 0x02052020, - 0x00000000, 0x00010000, 0x02000000, 0x02010000, - 0x00000020, 0x00010020, 0x02000020, 0x02010020, - 0x00040000, 0x00050000, 0x02040000, 0x02050000, - 0x00040020, 0x00050020, 0x02040020, 0x02050020, - 0x00002000, 0x00012000, 0x02002000, 0x02012000, - 0x00002020, 0x00012020, 0x02002020, 0x02012020, - 0x00042000, 0x00052000, 0x02042000, 0x02052000, - 0x00042020, 0x00052020, 0x02042020, 0x02052020, - 0x00000010, 0x00010010, 0x02000010, 0x02010010, - 0x00000030, 0x00010030, 0x02000030, 0x02010030, - 0x00040010, 0x00050010, 0x02040010, 0x02050010, - 0x00040030, 0x00050030, 0x02040030, 0x02050030, - 0x00002010, 0x00012010, 0x02002010, 0x02012010, - 0x00002030, 0x00012030, 0x02002030, 0x02012030, - 0x00042010, 0x00052010, 0x02042010, 0x02052010, - 0x00042030, 0x00052030, 0x02042030, 0x02052030, - 0x00000010, 0x00010010, 0x02000010, 0x02010010, - 0x00000030, 0x00010030, 0x02000030, 0x02010030, - 0x00040010, 0x00050010, 0x02040010, 0x02050010, - 0x00040030, 0x00050030, 0x02040030, 0x02050030, - 0x00002010, 0x00012010, 0x02002010, 0x02012010, - 0x00002030, 0x00012030, 0x02002030, 0x02012030, - 0x00042010, 0x00052010, 0x02042010, 0x02052010, - 0x00042030, 0x00052030, 0x02042030, 0x02052030, - 0x20000000, 0x20010000, 0x22000000, 0x22010000, - 0x20000020, 0x20010020, 0x22000020, 0x22010020, - 0x20040000, 0x20050000, 0x22040000, 0x22050000, - 0x20040020, 0x20050020, 0x22040020, 0x22050020, - 0x20002000, 0x20012000, 0x22002000, 0x22012000, - 0x20002020, 0x20012020, 0x22002020, 0x22012020, - 0x20042000, 0x20052000, 0x22042000, 0x22052000, - 0x20042020, 0x20052020, 0x22042020, 0x22052020, - 0x20000000, 0x20010000, 0x22000000, 0x22010000, - 0x20000020, 0x20010020, 0x22000020, 0x22010020, - 0x20040000, 0x20050000, 0x22040000, 0x22050000, - 0x20040020, 0x20050020, 0x22040020, 0x22050020, - 0x20002000, 0x20012000, 0x22002000, 0x22012000, - 0x20002020, 0x20012020, 0x22002020, 0x22012020, - 0x20042000, 0x20052000, 0x22042000, 0x22052000, - 0x20042020, 0x20052020, 0x22042020, 0x22052020, - 0x20000010, 0x20010010, 0x22000010, 0x22010010, - 0x20000030, 0x20010030, 0x22000030, 0x22010030, - 0x20040010, 0x20050010, 0x22040010, 0x22050010, - 0x20040030, 0x20050030, 0x22040030, 0x22050030, - 0x20002010, 0x20012010, 0x22002010, 0x22012010, - 0x20002030, 0x20012030, 0x22002030, 0x22012030, - 0x20042010, 0x20052010, 0x22042010, 0x22052010, - 0x20042030, 0x20052030, 0x22042030, 0x22052030, - 0x20000010, 0x20010010, 0x22000010, 0x22010010, - 0x20000030, 0x20010030, 0x22000030, 0x22010030, - 0x20040010, 0x20050010, 0x22040010, 0x22050010, - 0x20040030, 0x20050030, 0x22040030, 0x22050030, - 0x20002010, 0x20012010, 0x22002010, 0x22012010, - 0x20002030, 0x20012030, 0x22002030, 0x22012030, - 0x20042010, 0x20052010, 0x22042010, 0x22052010, - 0x20042030, 0x20052030, 0x22042030, 0x22052030 - ); - static $pc2mapd4 = array( - 0x00000000, 0x00000400, 0x01000000, 0x01000400, - 0x00000000, 0x00000400, 0x01000000, 0x01000400, - 0x00000100, 0x00000500, 0x01000100, 0x01000500, - 0x00000100, 0x00000500, 0x01000100, 0x01000500, - 0x10000000, 0x10000400, 0x11000000, 0x11000400, - 0x10000000, 0x10000400, 0x11000000, 0x11000400, - 0x10000100, 0x10000500, 0x11000100, 0x11000500, - 0x10000100, 0x10000500, 0x11000100, 0x11000500, - 0x00080000, 0x00080400, 0x01080000, 0x01080400, - 0x00080000, 0x00080400, 0x01080000, 0x01080400, - 0x00080100, 0x00080500, 0x01080100, 0x01080500, - 0x00080100, 0x00080500, 0x01080100, 0x01080500, - 0x10080000, 0x10080400, 0x11080000, 0x11080400, - 0x10080000, 0x10080400, 0x11080000, 0x11080400, - 0x10080100, 0x10080500, 0x11080100, 0x11080500, - 0x10080100, 0x10080500, 0x11080100, 0x11080500, - 0x00000008, 0x00000408, 0x01000008, 0x01000408, - 0x00000008, 0x00000408, 0x01000008, 0x01000408, - 0x00000108, 0x00000508, 0x01000108, 0x01000508, - 0x00000108, 0x00000508, 0x01000108, 0x01000508, - 0x10000008, 0x10000408, 0x11000008, 0x11000408, - 0x10000008, 0x10000408, 0x11000008, 0x11000408, - 0x10000108, 0x10000508, 0x11000108, 0x11000508, - 0x10000108, 0x10000508, 0x11000108, 0x11000508, - 0x00080008, 0x00080408, 0x01080008, 0x01080408, - 0x00080008, 0x00080408, 0x01080008, 0x01080408, - 0x00080108, 0x00080508, 0x01080108, 0x01080508, - 0x00080108, 0x00080508, 0x01080108, 0x01080508, - 0x10080008, 0x10080408, 0x11080008, 0x11080408, - 0x10080008, 0x10080408, 0x11080008, 0x11080408, - 0x10080108, 0x10080508, 0x11080108, 0x11080508, - 0x10080108, 0x10080508, 0x11080108, 0x11080508, - 0x00001000, 0x00001400, 0x01001000, 0x01001400, - 0x00001000, 0x00001400, 0x01001000, 0x01001400, - 0x00001100, 0x00001500, 0x01001100, 0x01001500, - 0x00001100, 0x00001500, 0x01001100, 0x01001500, - 0x10001000, 0x10001400, 0x11001000, 0x11001400, - 0x10001000, 0x10001400, 0x11001000, 0x11001400, - 0x10001100, 0x10001500, 0x11001100, 0x11001500, - 0x10001100, 0x10001500, 0x11001100, 0x11001500, - 0x00081000, 0x00081400, 0x01081000, 0x01081400, - 0x00081000, 0x00081400, 0x01081000, 0x01081400, - 0x00081100, 0x00081500, 0x01081100, 0x01081500, - 0x00081100, 0x00081500, 0x01081100, 0x01081500, - 0x10081000, 0x10081400, 0x11081000, 0x11081400, - 0x10081000, 0x10081400, 0x11081000, 0x11081400, - 0x10081100, 0x10081500, 0x11081100, 0x11081500, - 0x10081100, 0x10081500, 0x11081100, 0x11081500, - 0x00001008, 0x00001408, 0x01001008, 0x01001408, - 0x00001008, 0x00001408, 0x01001008, 0x01001408, - 0x00001108, 0x00001508, 0x01001108, 0x01001508, - 0x00001108, 0x00001508, 0x01001108, 0x01001508, - 0x10001008, 0x10001408, 0x11001008, 0x11001408, - 0x10001008, 0x10001408, 0x11001008, 0x11001408, - 0x10001108, 0x10001508, 0x11001108, 0x11001508, - 0x10001108, 0x10001508, 0x11001108, 0x11001508, - 0x00081008, 0x00081408, 0x01081008, 0x01081408, - 0x00081008, 0x00081408, 0x01081008, 0x01081408, - 0x00081108, 0x00081508, 0x01081108, 0x01081508, - 0x00081108, 0x00081508, 0x01081108, 0x01081508, - 0x10081008, 0x10081408, 0x11081008, 0x11081408, - 0x10081008, 0x10081408, 0x11081008, 0x11081408, - 0x10081108, 0x10081508, 0x11081108, 0x11081508, - 0x10081108, 0x10081508, 0x11081108, 0x11081508 - ); - - $keys = array(); - for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) { - // pad the key and remove extra characters as appropriate. - $key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0"); - - // Perform the PC/1 transformation and compute C and D. - $t = unpack('Nl/Nr', $key); - list($l, $r) = array($t['l'], $t['r']); - $key = ($this->shuffle[$pc1map[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") | - ($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") | - ($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") | - ($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") | - ($this->shuffle[$pc1map[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") | - ($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") | - ($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") | - ($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00"); - $key = unpack('Nc/Nd', $key); - $c = ( $key['c'] >> 4) & 0x0FFFFFFF; - $d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F); - - $keys[$des_round] = array( - CRYPT_DES_ENCRYPT => array(), - CRYPT_DES_DECRYPT => array_fill(0, 32, 0) - ); - for ($i = 0, $ki = 31; $i < 16; ++$i, $ki-= 2) { - $c <<= $shifts[$i]; - $c = ($c | ($c >> 28)) & 0x0FFFFFFF; - $d <<= $shifts[$i]; - $d = ($d | ($d >> 28)) & 0x0FFFFFFF; - - // Perform the PC-2 transformation. - $cp = $pc2mapc1[ $c >> 24 ] | $pc2mapc2[($c >> 16) & 0xFF] | - $pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[ $c & 0xFF]; - $dp = $pc2mapd1[ $d >> 24 ] | $pc2mapd2[($d >> 16) & 0xFF] | - $pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF]; - - // Reorder: odd bytes/even bytes. Push the result in key schedule. - $val1 = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) | - (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF); - $val2 = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) | - (($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF); - $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val1; - $keys[$des_round][CRYPT_DES_DECRYPT][$ki - 1] = $val1; - $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val2; - $keys[$des_round][CRYPT_DES_DECRYPT][$ki ] = $val2; - } - } - - switch ($this->des_rounds) { - case 3: // 3DES keys - $this->keys = array( - CRYPT_DES_ENCRYPT => array_merge( - $keys[0][CRYPT_DES_ENCRYPT], - $keys[1][CRYPT_DES_DECRYPT], - $keys[2][CRYPT_DES_ENCRYPT] - ), - CRYPT_DES_DECRYPT => array_merge( - $keys[2][CRYPT_DES_DECRYPT], - $keys[1][CRYPT_DES_ENCRYPT], - $keys[0][CRYPT_DES_DECRYPT] - ) - ); - break; - // case 1: // DES keys - default: - $this->keys = array( - CRYPT_DES_ENCRYPT => $keys[0][CRYPT_DES_ENCRYPT], - CRYPT_DES_DECRYPT => $keys[0][CRYPT_DES_DECRYPT] - ); - } - } - - /** - * Setup the performance-optimized function for de/encrypt() - * - * @see Crypt_Base::_setupInlineCrypt() - * @access private - */ - function _setupInlineCrypt() - { - $lambda_functions =& Crypt_DES::_getLambdaFunctions(); - - // Engine configuration for: - // - DES ($des_rounds == 1) or - // - 3DES ($des_rounds == 3) - $des_rounds = $this->des_rounds; - - // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function. - // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one - $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); - - // Generation of a uniqe hash for our generated code - switch (true) { - case $gen_hi_opt_code: - // For hi-optimized code, we create for each combination of - // $mode, $des_rounds and $this->key its own encrypt/decrypt function. - $code_hash = md5(str_pad("Crypt_DES, $des_rounds, {$this->mode}, ", 32, "\0") . $this->key); - break; - default: - // After max 10 hi-optimized functions, we create generic - // (still very fast.. but not ultra) functions for each $mode/$des_rounds - // Currently 2 * 5 generic functions will be then max. possible. - $code_hash = "Crypt_DES, $des_rounds, {$this->mode}"; - } - - // Is there a re-usable $lambda_functions in there? If not, we have to create it. - if (!isset($lambda_functions[$code_hash])) { - // Init code for both, encrypt and decrypt. - $init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip; - if (!$sbox1) { - $sbox1 = array_map("intval", $self->sbox1); - $sbox2 = array_map("intval", $self->sbox2); - $sbox3 = array_map("intval", $self->sbox3); - $sbox4 = array_map("intval", $self->sbox4); - $sbox5 = array_map("intval", $self->sbox5); - $sbox6 = array_map("intval", $self->sbox6); - $sbox7 = array_map("intval", $self->sbox7); - $sbox8 = array_map("intval", $self->sbox8);' - /* Merge $shuffle with $[inv]ipmap */ . ' - for ($i = 0; $i < 256; ++$i) { - $shuffleip[] = $self->shuffle[$self->ipmap[$i]]; - $shuffleinvip[] = $self->shuffle[$self->invipmap[$i]]; - } - } - '; - - switch (true) { - case $gen_hi_opt_code: - // In Hi-optimized code mode, we use our [3]DES key schedule as hardcoded integers. - // No futher initialisation of the $keys schedule is necessary. - // That is the extra performance boost. - $k = array( - CRYPT_DES_ENCRYPT => $this->keys[CRYPT_DES_ENCRYPT], - CRYPT_DES_DECRYPT => $this->keys[CRYPT_DES_DECRYPT] - ); - $init_encrypt = ''; - $init_decrypt = ''; - break; - default: - // In generic optimized code mode, we have to use, as the best compromise [currently], - // our key schedule as $ke/$kd arrays. (with hardcoded indexes...) - $k = array( - CRYPT_DES_ENCRYPT => array(), - CRYPT_DES_DECRYPT => array() - ); - for ($i = 0, $c = count($this->keys[CRYPT_DES_ENCRYPT]); $i < $c; ++$i) { - $k[CRYPT_DES_ENCRYPT][$i] = '$ke[' . $i . ']'; - $k[CRYPT_DES_DECRYPT][$i] = '$kd[' . $i . ']'; - } - $init_encrypt = '$ke = $self->keys[CRYPT_DES_ENCRYPT];'; - $init_decrypt = '$kd = $self->keys[CRYPT_DES_DECRYPT];'; - break; - } - - // Creating code for en- and decryption. - $crypt_block = array(); - foreach (array(CRYPT_DES_ENCRYPT, CRYPT_DES_DECRYPT) as $c) { - - /* Do the initial IP permutation. */ - $crypt_block[$c] = ' - $in = unpack("N*", $in); - $l = $in[1]; - $r = $in[2]; - $in = unpack("N*", - ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | - ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | - ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | - ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | - ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | - ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | - ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | - ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01") - ); - ' . /* Extract L0 and R0 */ ' - $l = $in[1]; - $r = $in[2]; - '; - - $l = '$l'; - $r = '$r'; - - // Perform DES or 3DES. - for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) { - // Perform the 16 steps. - for ($i = 0; $i < 16; ++$i) { - // start of "the Feistel (F) function" - see the following URL: - // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png - // Merge key schedule. - $crypt_block[$c].= ' - $b1 = ((' . $r . ' >> 3) & 0x1FFFFFFF) ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . '; - $b2 = ((' . $r . ' >> 31) & 0x00000001) ^ (' . $r . ' << 1) ^ ' . $k[$c][++$ki] . ';' . - /* S-box indexing. */ - $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^ - $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^ - $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^ - $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ ' . $l . '; - '; - // end of "the Feistel (F) function" - - // swap L & R - list($l, $r) = array($r, $l); - } - list($l, $r) = array($r, $l); - } - - // Perform the inverse IP permutation. - $crypt_block[$c].= '$in = - ($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | - ($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | - ($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | - ($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | - ($shuffleinvip[($l >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | - ($shuffleinvip[($r >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | - ($shuffleinvip[ $l & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | - ($shuffleinvip[ $r & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); - '; - } - - // Creates the inline-crypt function - $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( - array( - 'init_crypt' => $init_crypt, - 'init_encrypt' => $init_encrypt, - 'init_decrypt' => $init_decrypt, - 'encrypt_block' => $crypt_block[CRYPT_DES_ENCRYPT], - 'decrypt_block' => $crypt_block[CRYPT_DES_DECRYPT] - ) - ); - } - - // Set the inline-crypt function as callback in: $this->inline_crypt - $this->inline_crypt = $lambda_functions[$code_hash]; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Hash.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Hash.php deleted file mode 100644 index 4ab75b2d..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Hash.php +++ /dev/null @@ -1,841 +0,0 @@ - - * setKey('abcdefg'); - * - * echo base64_encode($hash->hash('abcdefg')); - * ?> - * - * - * 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. - * - * @category Crypt - * @package Crypt_Hash - * @author Jim Wigginton - * @copyright 2007 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/**#@+ - * @access private - * @see Crypt_Hash::Crypt_Hash() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_HASH_MODE_INTERNAL', 1); -/** - * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+. - */ -define('CRYPT_HASH_MODE_MHASH', 2); -/** - * Toggles the hash() implementation, which works on PHP 5.1.2+. - */ -define('CRYPT_HASH_MODE_HASH', 3); -/**#@-*/ - -/** - * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions. - * - * @package Crypt_Hash - * @author Jim Wigginton - * @access public - */ -class Crypt_Hash -{ - /** - * Hash Parameter - * - * @see Crypt_Hash::setHash() - * @var Integer - * @access private - */ - var $hashParam; - - /** - * Byte-length of compression blocks / key (Internal HMAC) - * - * @see Crypt_Hash::setAlgorithm() - * @var Integer - * @access private - */ - var $b; - - /** - * Byte-length of hash output (Internal HMAC) - * - * @see Crypt_Hash::setHash() - * @var Integer - * @access private - */ - var $l = false; - - /** - * Hash Algorithm - * - * @see Crypt_Hash::setHash() - * @var String - * @access private - */ - var $hash; - - /** - * Key - * - * @see Crypt_Hash::setKey() - * @var String - * @access private - */ - var $key = false; - - /** - * Outer XOR (Internal HMAC) - * - * @see Crypt_Hash::setKey() - * @var String - * @access private - */ - var $opad; - - /** - * Inner XOR (Internal HMAC) - * - * @see Crypt_Hash::setKey() - * @var String - * @access private - */ - var $ipad; - - /** - * Default Constructor. - * - * @param optional String $hash - * @return Crypt_Hash - * @access public - */ - function Crypt_Hash($hash = 'sha1') - { - if ( !defined('CRYPT_HASH_MODE') ) { - switch (true) { - case extension_loaded('hash'): - define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH); - break; - case extension_loaded('mhash'): - define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH); - break; - default: - define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL); - } - } - - $this->setHash($hash); - } - - /** - * Sets the key for HMACs - * - * Keys can be of any length. - * - * @access public - * @param optional String $key - */ - function setKey($key = false) - { - $this->key = $key; - } - - /** - * Gets the hash function. - * - * As set by the constructor or by the setHash() method. - * - * @access public - * @return String - */ - function getHash() - { - return $this->hashParam; - } - - /** - * Sets the hash function. - * - * @access public - * @param String $hash - */ - function setHash($hash) - { - $this->hashParam = $hash = strtolower($hash); - switch ($hash) { - case 'md5-96': - case 'sha1-96': - case 'sha256-96': - case 'sha512-96': - $hash = substr($hash, 0, -3); - $this->l = 12; // 96 / 8 = 12 - break; - case 'md2': - case 'md5': - $this->l = 16; - break; - case 'sha1': - $this->l = 20; - break; - case 'sha256': - $this->l = 32; - break; - case 'sha384': - $this->l = 48; - break; - case 'sha512': - $this->l = 64; - } - - switch ($hash) { - case 'md2': - $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ? - CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL; - break; - case 'sha384': - case 'sha512': - $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; - break; - default: - $mode = CRYPT_HASH_MODE; - } - - switch ( $mode ) { - case CRYPT_HASH_MODE_MHASH: - switch ($hash) { - case 'md5': - $this->hash = MHASH_MD5; - break; - case 'sha256': - $this->hash = MHASH_SHA256; - break; - case 'sha1': - default: - $this->hash = MHASH_SHA1; - } - return; - case CRYPT_HASH_MODE_HASH: - switch ($hash) { - case 'md5': - $this->hash = 'md5'; - return; - case 'md2': - case 'sha256': - case 'sha384': - case 'sha512': - $this->hash = $hash; - return; - case 'sha1': - default: - $this->hash = 'sha1'; - } - return; - } - - switch ($hash) { - case 'md2': - $this->b = 16; - $this->hash = array($this, '_md2'); - break; - case 'md5': - $this->b = 64; - $this->hash = array($this, '_md5'); - break; - case 'sha256': - $this->b = 64; - $this->hash = array($this, '_sha256'); - break; - case 'sha384': - case 'sha512': - $this->b = 128; - $this->hash = array($this, '_sha512'); - break; - case 'sha1': - default: - $this->b = 64; - $this->hash = array($this, '_sha1'); - } - - $this->ipad = str_repeat(chr(0x36), $this->b); - $this->opad = str_repeat(chr(0x5C), $this->b); - } - - /** - * Compute the HMAC. - * - * @access public - * @param String $text - * @return String - */ - function hash($text) - { - $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; - - if (!empty($this->key) || is_string($this->key)) { - switch ( $mode ) { - case CRYPT_HASH_MODE_MHASH: - $output = mhash($this->hash, $text, $this->key); - break; - case CRYPT_HASH_MODE_HASH: - $output = hash_hmac($this->hash, $text, $this->key, true); - break; - case CRYPT_HASH_MODE_INTERNAL: - /* "Applications that use keys longer than B bytes will first hash the key using H and then use the - resultant L byte string as the actual key to HMAC." - - -- http://tools.ietf.org/html/rfc2104#section-2 */ - $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key; - - $key = str_pad($key, $this->b, chr(0)); // step 1 - $temp = $this->ipad ^ $key; // step 2 - $temp .= $text; // step 3 - $temp = call_user_func($this->hash, $temp); // step 4 - $output = $this->opad ^ $key; // step 5 - $output.= $temp; // step 6 - $output = call_user_func($this->hash, $output); // step 7 - } - } else { - switch ( $mode ) { - case CRYPT_HASH_MODE_MHASH: - $output = mhash($this->hash, $text); - break; - case CRYPT_HASH_MODE_HASH: - $output = hash($this->hash, $text, true); - break; - case CRYPT_HASH_MODE_INTERNAL: - $output = call_user_func($this->hash, $text); - } - } - - return substr($output, 0, $this->l); - } - - /** - * Returns the hash length (in bytes) - * - * @access public - * @return Integer - */ - function getLength() - { - return $this->l; - } - - /** - * Wrapper for MD5 - * - * @access private - * @param String $m - */ - function _md5($m) - { - return pack('H*', md5($m)); - } - - /** - * Wrapper for SHA1 - * - * @access private - * @param String $m - */ - function _sha1($m) - { - return pack('H*', sha1($m)); - } - - /** - * Pure-PHP implementation of MD2 - * - * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}. - * - * @access private - * @param String $m - */ - function _md2($m) - { - static $s = array( - 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, - 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, - 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, - 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, - 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, - 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, - 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, - 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, - 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, - 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, - 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, - 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, - 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, - 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, - 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, - 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, - 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, - 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 - ); - - // Step 1. Append Padding Bytes - $pad = 16 - (strlen($m) & 0xF); - $m.= str_repeat(chr($pad), $pad); - - $length = strlen($m); - - // Step 2. Append Checksum - $c = str_repeat(chr(0), 16); - $l = chr(0); - for ($i = 0; $i < $length; $i+= 16) { - for ($j = 0; $j < 16; $j++) { - // RFC1319 incorrectly states that C[j] should be set to S[c xor L] - //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]); - // per , however, C[j] should be set to S[c xor L] xor C[j] - $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j])); - $l = $c[$j]; - } - } - $m.= $c; - - $length+= 16; - - // Step 3. Initialize MD Buffer - $x = str_repeat(chr(0), 48); - - // Step 4. Process Message in 16-Byte Blocks - for ($i = 0; $i < $length; $i+= 16) { - for ($j = 0; $j < 16; $j++) { - $x[$j + 16] = $m[$i + $j]; - $x[$j + 32] = $x[$j + 16] ^ $x[$j]; - } - $t = chr(0); - for ($j = 0; $j < 18; $j++) { - for ($k = 0; $k < 48; $k++) { - $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]); - //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]); - } - $t = chr(ord($t) + $j); - } - } - - // Step 5. Output - return substr($x, 0, 16); - } - - /** - * Pure-PHP implementation of SHA256 - * - * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}. - * - * @access private - * @param String $m - */ - function _sha256($m) - { - if (extension_loaded('suhosin')) { - return pack('H*', sha256($m)); - } - - // Initialize variables - $hash = array( - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 - ); - // Initialize table of round constants - // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311) - static $k = array( - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 - ); - - // Pre-processing - $length = strlen($m); - // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64 - $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F)); - $m[$length] = chr(0x80); - // we don't support hashing strings 512MB long - $m.= pack('N2', 0, $length << 3); - - // Process the message in successive 512-bit chunks - $chunks = str_split($m, 64); - foreach ($chunks as $chunk) { - $w = array(); - for ($i = 0; $i < 16; $i++) { - extract(unpack('Ntemp', $this->_string_shift($chunk, 4))); - $w[] = $temp; - } - - // Extend the sixteen 32-bit words into sixty-four 32-bit words - for ($i = 16; $i < 64; $i++) { - $s0 = $this->_rightRotate($w[$i - 15], 7) ^ - $this->_rightRotate($w[$i - 15], 18) ^ - $this->_rightShift( $w[$i - 15], 3); - $s1 = $this->_rightRotate($w[$i - 2], 17) ^ - $this->_rightRotate($w[$i - 2], 19) ^ - $this->_rightShift( $w[$i - 2], 10); - $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1); - - } - - // Initialize hash value for this chunk - list($a, $b, $c, $d, $e, $f, $g, $h) = $hash; - - // Main loop - for ($i = 0; $i < 64; $i++) { - $s0 = $this->_rightRotate($a, 2) ^ - $this->_rightRotate($a, 13) ^ - $this->_rightRotate($a, 22); - $maj = ($a & $b) ^ - ($a & $c) ^ - ($b & $c); - $t2 = $this->_add($s0, $maj); - - $s1 = $this->_rightRotate($e, 6) ^ - $this->_rightRotate($e, 11) ^ - $this->_rightRotate($e, 25); - $ch = ($e & $f) ^ - ($this->_not($e) & $g); - $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]); - - $h = $g; - $g = $f; - $f = $e; - $e = $this->_add($d, $t1); - $d = $c; - $c = $b; - $b = $a; - $a = $this->_add($t1, $t2); - } - - // Add this chunk's hash to result so far - $hash = array( - $this->_add($hash[0], $a), - $this->_add($hash[1], $b), - $this->_add($hash[2], $c), - $this->_add($hash[3], $d), - $this->_add($hash[4], $e), - $this->_add($hash[5], $f), - $this->_add($hash[6], $g), - $this->_add($hash[7], $h) - ); - } - - // Produce the final hash value (big-endian) - return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]); - } - - /** - * Pure-PHP implementation of SHA384 and SHA512 - * - * @access private - * @param String $m - */ - function _sha512($m) - { - if (!class_exists('Math_BigInteger')) { - include_once 'Math/BigInteger.php'; - } - - static $init384, $init512, $k; - - if (!isset($k)) { - // Initialize variables - $init384 = array( // initial values for SHA384 - 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939', - '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4' - ); - $init512 = array( // initial values for SHA512 - '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1', - '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179' - ); - - for ($i = 0; $i < 8; $i++) { - $init384[$i] = new Math_BigInteger($init384[$i], 16); - $init384[$i]->setPrecision(64); - $init512[$i] = new Math_BigInteger($init512[$i], 16); - $init512[$i]->setPrecision(64); - } - - // Initialize table of round constants - // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409) - $k = array( - '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc', - '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118', - 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2', - '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694', - 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65', - '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5', - '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4', - 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70', - '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df', - '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b', - 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30', - 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8', - '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8', - '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3', - '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec', - '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b', - 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178', - '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b', - '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c', - '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817' - ); - - for ($i = 0; $i < 80; $i++) { - $k[$i] = new Math_BigInteger($k[$i], 16); - } - } - - $hash = $this->l == 48 ? $init384 : $init512; - - // Pre-processing - $length = strlen($m); - // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128 - $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F)); - $m[$length] = chr(0x80); - // we don't support hashing strings 512MB long - $m.= pack('N4', 0, 0, 0, $length << 3); - - // Process the message in successive 1024-bit chunks - $chunks = str_split($m, 128); - foreach ($chunks as $chunk) { - $w = array(); - for ($i = 0; $i < 16; $i++) { - $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256); - $temp->setPrecision(64); - $w[] = $temp; - } - - // Extend the sixteen 32-bit words into eighty 32-bit words - for ($i = 16; $i < 80; $i++) { - $temp = array( - $w[$i - 15]->bitwise_rightRotate(1), - $w[$i - 15]->bitwise_rightRotate(8), - $w[$i - 15]->bitwise_rightShift(7) - ); - $s0 = $temp[0]->bitwise_xor($temp[1]); - $s0 = $s0->bitwise_xor($temp[2]); - $temp = array( - $w[$i - 2]->bitwise_rightRotate(19), - $w[$i - 2]->bitwise_rightRotate(61), - $w[$i - 2]->bitwise_rightShift(6) - ); - $s1 = $temp[0]->bitwise_xor($temp[1]); - $s1 = $s1->bitwise_xor($temp[2]); - $w[$i] = $w[$i - 16]->copy(); - $w[$i] = $w[$i]->add($s0); - $w[$i] = $w[$i]->add($w[$i - 7]); - $w[$i] = $w[$i]->add($s1); - } - - // Initialize hash value for this chunk - $a = $hash[0]->copy(); - $b = $hash[1]->copy(); - $c = $hash[2]->copy(); - $d = $hash[3]->copy(); - $e = $hash[4]->copy(); - $f = $hash[5]->copy(); - $g = $hash[6]->copy(); - $h = $hash[7]->copy(); - - // Main loop - for ($i = 0; $i < 80; $i++) { - $temp = array( - $a->bitwise_rightRotate(28), - $a->bitwise_rightRotate(34), - $a->bitwise_rightRotate(39) - ); - $s0 = $temp[0]->bitwise_xor($temp[1]); - $s0 = $s0->bitwise_xor($temp[2]); - $temp = array( - $a->bitwise_and($b), - $a->bitwise_and($c), - $b->bitwise_and($c) - ); - $maj = $temp[0]->bitwise_xor($temp[1]); - $maj = $maj->bitwise_xor($temp[2]); - $t2 = $s0->add($maj); - - $temp = array( - $e->bitwise_rightRotate(14), - $e->bitwise_rightRotate(18), - $e->bitwise_rightRotate(41) - ); - $s1 = $temp[0]->bitwise_xor($temp[1]); - $s1 = $s1->bitwise_xor($temp[2]); - $temp = array( - $e->bitwise_and($f), - $g->bitwise_and($e->bitwise_not()) - ); - $ch = $temp[0]->bitwise_xor($temp[1]); - $t1 = $h->add($s1); - $t1 = $t1->add($ch); - $t1 = $t1->add($k[$i]); - $t1 = $t1->add($w[$i]); - - $h = $g->copy(); - $g = $f->copy(); - $f = $e->copy(); - $e = $d->add($t1); - $d = $c->copy(); - $c = $b->copy(); - $b = $a->copy(); - $a = $t1->add($t2); - } - - // Add this chunk's hash to result so far - $hash = array( - $hash[0]->add($a), - $hash[1]->add($b), - $hash[2]->add($c), - $hash[3]->add($d), - $hash[4]->add($e), - $hash[5]->add($f), - $hash[6]->add($g), - $hash[7]->add($h) - ); - } - - // Produce the final hash value (big-endian) - // (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here) - $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() . - $hash[4]->toBytes() . $hash[5]->toBytes(); - if ($this->l != 48) { - $temp.= $hash[6]->toBytes() . $hash[7]->toBytes(); - } - - return $temp; - } - - /** - * Right Rotate - * - * @access private - * @param Integer $int - * @param Integer $amt - * @see _sha256() - * @return Integer - */ - function _rightRotate($int, $amt) - { - $invamt = 32 - $amt; - $mask = (1 << $invamt) - 1; - return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask); - } - - /** - * Right Shift - * - * @access private - * @param Integer $int - * @param Integer $amt - * @see _sha256() - * @return Integer - */ - function _rightShift($int, $amt) - { - $mask = (1 << (32 - $amt)) - 1; - return ($int >> $amt) & $mask; - } - - /** - * Not - * - * @access private - * @param Integer $int - * @see _sha256() - * @return Integer - */ - function _not($int) - { - return ~$int & 0xFFFFFFFF; - } - - /** - * Add - * - * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the - * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster. - * - * @param Integer $... - * @return Integer - * @see _sha256() - * @access private - */ - function _add() - { - static $mod; - if (!isset($mod)) { - $mod = pow(2, 32); - } - - $result = 0; - $arguments = func_get_args(); - foreach ($arguments as $argument) { - $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument; - } - - return fmod($result, $mod); - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RC2.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RC2.php deleted file mode 100644 index 96c9f18c..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RC2.php +++ /dev/null @@ -1,652 +0,0 @@ - - * setKey('abcdefgh'); - * - * $plaintext = str_repeat('a', 1024); - * - * echo $rc2->decrypt($rc2->encrypt($plaintext)); - * ?> - * - * - * 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. - * - * @category Crypt - * @package Crypt_RC2 - * @author Patrick Monnerat - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Crypt_Base - * - * Base cipher class - */ -if (!class_exists('Crypt_Base')) { - include_once 'Base.php'; -} - -/**#@+ - * @access public - * @see Crypt_RC2::encrypt() - * @see Crypt_RC2::decrypt() - */ -/** - * Encrypt / decrypt using the Counter mode. - * - * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 - */ -define('CRYPT_RC2_MODE_CTR', CRYPT_MODE_CTR); -/** - * Encrypt / decrypt using the Electronic Code Book mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 - */ -define('CRYPT_RC2_MODE_ECB', CRYPT_MODE_ECB); -/** - * Encrypt / decrypt using the Code Book Chaining mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - */ -define('CRYPT_RC2_MODE_CBC', CRYPT_MODE_CBC); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 - */ -define('CRYPT_RC2_MODE_CFB', CRYPT_MODE_CFB); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 - */ -define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_RC2::Crypt_RC2() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_RC2_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_RC2_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - -/** - * Pure-PHP implementation of RC2. - * - * @package Crypt_RC2 - * @access public - */ -class Crypt_RC2 extends Crypt_Base -{ - /** - * Block Length of the cipher - * - * @see Crypt_Base::block_size - * @var Integer - * @access private - */ - var $block_size = 8; - - /** - * The Key - * - * @see Crypt_Base::key - * @see setKey() - * @var String - * @access private - */ - var $key = "\0"; - - /** - * The default password key_size used by setPassword() - * - * @see Crypt_Base::password_key_size - * @see Crypt_Base::setPassword() - * @var Integer - * @access private - */ - var $password_key_size = 16; // = 128 bits - - /** - * The namespace used by the cipher for its constants. - * - * @see Crypt_Base::const_namespace - * @var String - * @access private - */ - var $const_namespace = 'RC2'; - - /** - * The mcrypt specific name of the cipher - * - * @see Crypt_Base::cipher_name_mcrypt - * @var String - * @access private - */ - var $cipher_name_mcrypt = 'rc2'; - - /** - * Optimizing value while CFB-encrypting - * - * @see Crypt_Base::cfb_init_len - * @var Integer - * @access private - */ - var $cfb_init_len = 500; - - /** - * The key length in bits. - * - * @see Crypt_RC2::setKeyLength() - * @see Crypt_RC2::setKey() - * @var Integer - * @access private - * @internal Should be in range [1..1024]. - * @internal Changing this value after setting the key has no effect. - */ - var $default_key_length = 1024; - - /** - * The Key Schedule - * - * @see Crypt_RC2::_setupKey() - * @var Array - * @access private - */ - var $keys; - - /** - * Key expansion randomization table. - * Twice the same 256-value sequence to save a modulus in key expansion. - * - * @see Crypt_RC2::setKey() - * @var Array - * @access private - */ - var $pitable = array( - 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, - 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D, - 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, - 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, - 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13, - 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, - 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, - 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82, - 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, - 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, - 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1, - 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, - 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, - 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03, - 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, - 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, - 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7, - 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, - 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, - 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC, - 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, - 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, - 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A, - 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, - 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, - 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9, - 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, - 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, - 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0, - 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, - 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, - 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD, - 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, - 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D, - 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, - 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, - 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13, - 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, - 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, - 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82, - 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, - 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, - 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1, - 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, - 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, - 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03, - 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, - 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, - 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7, - 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, - 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, - 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC, - 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, - 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, - 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A, - 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, - 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, - 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9, - 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, - 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, - 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0, - 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, - 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, - 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD - ); - - /** - * Inverse key expansion randomization table. - * - * @see Crypt_RC2::setKey() - * @var Array - * @access private - */ - var $invpitable = array( - 0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66, - 0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4, - 0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20, - 0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53, - 0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68, - 0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B, - 0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12, - 0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB, - 0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3, - 0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26, - 0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67, - 0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB, - 0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC, - 0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60, - 0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7, - 0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD, - 0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24, - 0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31, - 0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE, - 0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99, - 0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C, - 0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA, - 0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35, - 0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61, - 0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72, - 0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3, - 0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F, - 0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9, - 0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77, - 0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75, - 0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87, - 0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6 - ); - - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_RC2_MODE_ECB - * - * - CRYPT_RC2_MODE_CBC - * - * - CRYPT_RC2_MODE_CTR - * - * - CRYPT_RC2_MODE_CFB - * - * - CRYPT_RC2_MODE_OFB - * - * If not explicitly set, CRYPT_RC2_MODE_CBC will be used. - * - * @see Crypt_Base::Crypt_Base() - * @param optional Integer $mode - * @access public - */ - function Crypt_RC2($mode = CRYPT_RC2_MODE_CBC) - { - parent::Crypt_Base($mode); - $this->setKey(''); - } - - /** - * Sets the key length - * - * Valid key lengths are 1 to 1024. - * Calling this function after setting the key has no effect until the next - * Crypt_RC2::setKey() call. - * - * @access public - * @param Integer $length in bits - */ - function setKeyLength($length) - { - if ($length >= 1 && $length <= 1024) { - $this->default_key_length = $length; - } - } - - /** - * Sets the key. - * - * Keys can be of any length. RC2, itself, uses 1 to 1024 bit keys (eg. - * strlen($key) <= 128), however, we only use the first 128 bytes if $key - * has more then 128 bytes in it, and set $key to a single null byte if - * it is empty. - * - * If the key is not explicitly set, it'll be assumed to be a single - * null byte. - * - * @see Crypt_Base::setKey() - * @access public - * @param String $key - * @param Integer $t1 optional Effective key length in bits. - */ - function setKey($key, $t1 = 0) - { - if ($t1 <= 0) { - $t1 = $this->default_key_length; - } else if ($t1 > 1024) { - $t1 = 1024; - } - // Key byte count should be 1..128. - $key = strlen($key) ? substr($key, 0, 128) : "\x00"; - $t = strlen($key); - - // The mcrypt RC2 implementation only supports effective key length - // of 1024 bits. It is however possible to handle effective key - // lengths in range 1..1024 by expanding the key and applying - // inverse pitable mapping to the first byte before submitting it - // to mcrypt. - - // Key expansion. - $l = array_values(unpack('C*', $key)); - $t8 = ($t1 + 7) >> 3; - $tm = 0xFF >> (8 * $t8 - $t1); - - // Expand key. - $pitable = $this->pitable; - for ($i = $t; $i < 128; $i++) { - $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]]; - } - $i = 128 - $t8; - $l[$i] = $pitable[$l[$i] & $tm]; - while ($i--) { - $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]]; - } - - // Prepare the key for mcrypt. - $l[0] = $this->invpitable[$l[0]]; - array_unshift($l, 'C*'); - parent::setKey(call_user_func_array('pack', $l)); - } - - /** - * Encrypts a block - * - * @see Crypt_Base::_encryptBlock() - * @see Crypt_Base::encrypt() - * @access private - * @param String $in - * @return String - */ - function _encryptBlock($in) - { - list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in)); - $keys = $this->keys; - $limit = 20; - $actions = array($limit => 44, 44 => 64); - $j = 0; - - for (;;) { - // Mixing round. - $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1; - $r0 |= $r0 >> 16; - $r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2; - $r1 |= $r1 >> 16; - $r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3; - $r2 |= $r2 >> 16; - $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5; - $r3 |= $r3 >> 16; - - if ($j === $limit) { - if ($limit === 64) { - break; - } - - // Mashing round. - $r0 += $keys[$r3 & 0x3F]; - $r1 += $keys[$r0 & 0x3F]; - $r2 += $keys[$r1 & 0x3F]; - $r3 += $keys[$r2 & 0x3F]; - $limit = $actions[$limit]; - } - } - - return pack('vvvv', $r0, $r1, $r2, $r3); - } - - /** - * Decrypts a block - * - * @see Crypt_Base::_decryptBlock() - * @see Crypt_Base::decrypt() - * @access private - * @param String $in - * @return String - */ - function _decryptBlock($in) - { - list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in)); - $keys = $this->keys; - $limit = 44; - $actions = array($limit => 20, 20 => 0); - $j = 64; - - for (;;) { - // R-mixing round. - $r3 = ($r3 | ($r3 << 16)) >> 5; - $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF; - $r2 = ($r2 | ($r2 << 16)) >> 3; - $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF; - $r1 = ($r1 | ($r1 << 16)) >> 2; - $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF; - $r0 = ($r0 | ($r0 << 16)) >> 1; - $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF; - - if ($j === $limit) { - if ($limit === 0) { - break; - } - - // R-mashing round. - $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF; - $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF; - $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF; - $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF; - $limit = $actions[$limit]; - } - } - - return pack('vvvv', $r0, $r1, $r2, $r3); - } - - /** - * Creates the key schedule - * - * @see Crypt_Base::_setupKey() - * @access private - */ - function _setupKey() - { - // Key has already been expanded in Crypt_RC2::setKey(): - // Only the first value must be altered. - $l = unpack('Ca/Cb/v*', $this->key); - array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8)); - unset($l['a']); - unset($l['b']); - $this->keys = $l; - } - - /** - * Setup the performance-optimized function for de/encrypt() - * - * @see Crypt_Base::_setupInlineCrypt() - * @access private - */ - function _setupInlineCrypt() - { - $lambda_functions = &Crypt_RC2::_getLambdaFunctions(); - - // The first 10 generated $lambda_functions will use the $keys hardcoded as integers - // for the mixing rounds, for better inline crypt performance [~20% faster]. - // But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10. - $keys = $this->keys; - if (count($lambda_functions) >= 10) { - foreach ($this->keys as $k => $v) { - $keys[$k] = '$keys[' . $k . ']'; - } - } - - $code_hash = md5(str_pad("Crypt_RC2, {$this->mode}, ", 32, "\0") . implode(',', $keys)); - - // Is there a re-usable $lambda_functions in there? - // If not, we have to create it. - if (!isset($lambda_functions[$code_hash])) { - // Init code for both, encrypt and decrypt. - $init_crypt = '$keys = $self->keys;'; - - // $in is the current 8 bytes block which has to be en/decrypt - $encrypt_block = $decrypt_block = ' - $in = unpack("v4", $in); - $r0 = $in[1]; - $r1 = $in[2]; - $r2 = $in[3]; - $r3 = $in[4]; - '; - - // Create code for encryption. - $limit = 20; - $actions = array($limit => 44, 44 => 64); - $j = 0; - - for (;;) { - // Mixing round. - $encrypt_block .= ' - $r0 = (($r0 + ' . $keys[$j++] . ' + - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1; - $r0 |= $r0 >> 16; - $r1 = (($r1 + ' . $keys[$j++] . ' + - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2; - $r1 |= $r1 >> 16; - $r2 = (($r2 + ' . $keys[$j++] . ' + - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3; - $r2 |= $r2 >> 16; - $r3 = (($r3 + ' . $keys[$j++] . ' + - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5; - $r3 |= $r3 >> 16;'; - - if ($j === $limit) { - if ($limit === 64) { - break; - } - - // Mashing round. - $encrypt_block .= ' - $r0 += $keys[$r3 & 0x3F]; - $r1 += $keys[$r0 & 0x3F]; - $r2 += $keys[$r1 & 0x3F]; - $r3 += $keys[$r2 & 0x3F];'; - $limit = $actions[$limit]; - } - } - - $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);'; - - // Create code for decryption. - $limit = 44; - $actions = array($limit => 20, 20 => 0); - $j = 64; - - for (;;) { - // R-mixing round. - $decrypt_block .= ' - $r3 = ($r3 | ($r3 << 16)) >> 5; - $r3 = ($r3 - ' . $keys[--$j] . ' - - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF; - $r2 = ($r2 | ($r2 << 16)) >> 3; - $r2 = ($r2 - ' . $keys[--$j] . ' - - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF; - $r1 = ($r1 | ($r1 << 16)) >> 2; - $r1 = ($r1 - ' . $keys[--$j] . ' - - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF; - $r0 = ($r0 | ($r0 << 16)) >> 1; - $r0 = ($r0 - ' . $keys[--$j] . ' - - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;'; - - if ($j === $limit) { - if ($limit === 0) { - break; - } - - // R-mashing round. - $decrypt_block .= ' - $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF; - $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF; - $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF; - $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;'; - $limit = $actions[$limit]; - } - } - - $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);'; - - // Creates the inline-crypt function - $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( - array( - 'init_crypt' => $init_crypt, - 'encrypt_block' => $encrypt_block, - 'decrypt_block' => $decrypt_block - ) - ); - } - - // Set the inline-crypt function as callback in: $this->inline_crypt - $this->inline_crypt = $lambda_functions[$code_hash]; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RC4.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RC4.php deleted file mode 100644 index d5eda8c3..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RC4.php +++ /dev/null @@ -1,329 +0,0 @@ - - * setKey('abcdefgh'); - * - * $size = 10 * 1024; - * $plaintext = ''; - * for ($i = 0; $i < $size; $i++) { - * $plaintext.= 'a'; - * } - * - * echo $rc4->decrypt($rc4->encrypt($plaintext)); - * ?> - * - * - * 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. - * - * @category Crypt - * @package Crypt_RC4 - * @author Jim Wigginton - * @copyright 2007 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Crypt_Base - * - * Base cipher class - */ -if (!class_exists('Crypt_Base')) { - include_once 'Base.php'; -} - -/**#@+ - * @access private - * @see Crypt_RC4::Crypt_RC4() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_RC4_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_RC4::_crypt() - */ -define('CRYPT_RC4_ENCRYPT', 0); -define('CRYPT_RC4_DECRYPT', 1); -/**#@-*/ - -/** - * Pure-PHP implementation of RC4. - * - * @package Crypt_RC4 - * @author Jim Wigginton - * @access public - */ -class Crypt_RC4 extends Crypt_Base -{ - /** - * Block Length of the cipher - * - * RC4 is a stream cipher - * so we the block_size to 0 - * - * @see Crypt_Base::block_size - * @var Integer - * @access private - */ - var $block_size = 0; - - /** - * The default password key_size used by setPassword() - * - * @see Crypt_Base::password_key_size - * @see Crypt_Base::setPassword() - * @var Integer - * @access private - */ - var $password_key_size = 128; // = 1024 bits - - /** - * The namespace used by the cipher for its constants. - * - * @see Crypt_Base::const_namespace - * @var String - * @access private - */ - var $const_namespace = 'RC4'; - - /** - * The mcrypt specific name of the cipher - * - * @see Crypt_Base::cipher_name_mcrypt - * @var String - * @access private - */ - var $cipher_name_mcrypt = 'arcfour'; - - /** - * Holds whether performance-optimized $inline_crypt() can/should be used. - * - * @see Crypt_Base::inline_crypt - * @var mixed - * @access private - */ - var $use_inline_crypt = false; // currently not available - - /** - * The Key - * - * @see Crypt_RC4::setKey() - * @var String - * @access private - */ - var $key = "\0"; - - /** - * The Key Stream for decryption and encryption - * - * @see Crypt_RC4::setKey() - * @var Array - * @access private - */ - var $stream; - - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. - * - * @see Crypt_Base::Crypt_Base() - * @return Crypt_RC4 - * @access public - */ - function Crypt_RC4() - { - parent::Crypt_Base(CRYPT_MODE_STREAM); - } - - /** - * Dummy function. - * - * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1]. - * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before - * calling setKey(). - * - * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol, - * the IV's are relatively easy to predict, an attack described by - * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir} - * can be used to quickly guess at the rest of the key. The following links elaborate: - * - * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009} - * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack} - * - * @param String $iv - * @see Crypt_RC4::setKey() - * @access public - */ - function setIV($iv) - { - } - - /** - * Sets the key. - * - * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will - * be used. If no key is explicitly set, it'll be assumed to be a single null byte. - * - * @access public - * @see Crypt_Base::setKey() - * @param String $key - */ - function setKey($key) - { - parent::setKey(substr($key, 0, 256)); - } - - /** - * Encrypts a message. - * - * @see Crypt_Base::decrypt() - * @see Crypt_RC4::_crypt() - * @access public - * @param String $plaintext - * @return String $ciphertext - */ - function encrypt($plaintext) - { - if ($this->engine == CRYPT_MODE_MCRYPT) { - return parent::encrypt($plaintext); - } - return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT); - } - - /** - * Decrypts a message. - * - * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). - * At least if the continuous buffer is disabled. - * - * @see Crypt_Base::encrypt() - * @see Crypt_RC4::_crypt() - * @access public - * @param String $ciphertext - * @return String $plaintext - */ - function decrypt($ciphertext) - { - if ($this->engine == CRYPT_MODE_MCRYPT) { - return parent::decrypt($ciphertext); - } - return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT); - } - - - /** - * Setup the key (expansion) - * - * @see Crypt_Base::_setupKey() - * @access private - */ - function _setupKey() - { - $key = $this->key; - $keyLength = strlen($key); - $keyStream = range(0, 255); - $j = 0; - for ($i = 0; $i < 256; $i++) { - $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; - $temp = $keyStream[$i]; - $keyStream[$i] = $keyStream[$j]; - $keyStream[$j] = $temp; - } - - $this->stream = array(); - $this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array( - 0, // index $i - 0, // index $j - $keyStream - ); - } - - /** - * Encrypts or decrypts a message. - * - * @see Crypt_RC4::encrypt() - * @see Crypt_RC4::decrypt() - * @access private - * @param String $text - * @param Integer $mode - * @return String $text - */ - function _crypt($text, $mode) - { - if ($this->changed) { - $this->_setup(); - $this->changed = false; - } - - $stream = &$this->stream[$mode]; - if ($this->continuousBuffer) { - $i = &$stream[0]; - $j = &$stream[1]; - $keyStream = &$stream[2]; - } else { - $i = $stream[0]; - $j = $stream[1]; - $keyStream = $stream[2]; - } - - $len = strlen($text); - for ($k = 0; $k < $len; ++$k) { - $i = ($i + 1) & 255; - $ksi = $keyStream[$i]; - $j = ($j + $ksi) & 255; - $ksj = $keyStream[$j]; - - $keyStream[$i] = $ksj; - $keyStream[$j] = $ksi; - $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]); - } - - return $text; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RSA.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RSA.php deleted file mode 100644 index 53f94354..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RSA.php +++ /dev/null @@ -1,2997 +0,0 @@ - - * createKey()); - * - * $plaintext = 'terrafrost'; - * - * $rsa->loadKey($privatekey); - * $ciphertext = $rsa->encrypt($plaintext); - * - * $rsa->loadKey($publickey); - * echo $rsa->decrypt($ciphertext); - * ?> - * - * - * Here's an example of how to create signatures and verify signatures with this library: - * - * createKey()); - * - * $plaintext = 'terrafrost'; - * - * $rsa->loadKey($privatekey); - * $signature = $rsa->sign($plaintext); - * - * $rsa->loadKey($publickey); - * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified'; - * ?> - * - * - * 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. - * - * @category Crypt - * @package Crypt_RSA - * @author Jim Wigginton - * @copyright 2009 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Crypt_Random - */ -// the class_exists() will only be called if the crypt_random_string function hasn't been defined and -// will trigger a call to __autoload() if you're wanting to auto-load classes -// call function_exists() a second time to stop the include_once from being called outside -// of the auto loader -if (!function_exists('crypt_random_string')) { - include_once 'Random.php'; -} - -/** - * Include Crypt_Hash - */ -if (!class_exists('Crypt_Hash')) { - include_once 'Hash.php'; -} - -/**#@+ - * @access public - * @see Crypt_RSA::encrypt() - * @see Crypt_RSA::decrypt() - */ -/** - * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding} - * (OAEP) for encryption / decryption. - * - * Uses sha1 by default. - * - * @see Crypt_RSA::setHash() - * @see Crypt_RSA::setMGFHash() - */ -define('CRYPT_RSA_ENCRYPTION_OAEP', 1); -/** - * Use PKCS#1 padding. - * - * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards - * compatibility with protocols (like SSH-1) written before OAEP's introduction. - */ -define('CRYPT_RSA_ENCRYPTION_PKCS1', 2); -/**#@-*/ - -/**#@+ - * @access public - * @see Crypt_RSA::sign() - * @see Crypt_RSA::verify() - * @see Crypt_RSA::setHash() - */ -/** - * Use the Probabilistic Signature Scheme for signing - * - * Uses sha1 by default. - * - * @see Crypt_RSA::setSaltLength() - * @see Crypt_RSA::setMGFHash() - */ -define('CRYPT_RSA_SIGNATURE_PSS', 1); -/** - * Use the PKCS#1 scheme by default. - * - * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards - * compatibility with protocols (like SSH-2) written before PSS's introduction. - */ -define('CRYPT_RSA_SIGNATURE_PKCS1', 2); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_RSA::createKey() - */ -/** - * ASN1 Integer - */ -define('CRYPT_RSA_ASN1_INTEGER', 2); -/** - * ASN1 Bit String - */ -define('CRYPT_RSA_ASN1_BITSTRING', 3); -/** - * ASN1 Octet String - */ -define('CRYPT_RSA_ASN1_OCTETSTRING', 4); -/** - * ASN1 Object Identifier - */ -define('CRYPT_RSA_ASN1_OBJECT', 6); -/** - * ASN1 Sequence (with the constucted bit set) - */ -define('CRYPT_RSA_ASN1_SEQUENCE', 48); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_RSA::Crypt_RSA() - */ -/** - * To use the pure-PHP implementation - */ -define('CRYPT_RSA_MODE_INTERNAL', 1); -/** - * To use the OpenSSL library - * - * (if enabled; otherwise, the internal implementation will be used) - */ -define('CRYPT_RSA_MODE_OPENSSL', 2); -/**#@-*/ - -/** - * Default openSSL configuration file. - */ -define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf'); - -/**#@+ - * @access public - * @see Crypt_RSA::createKey() - * @see Crypt_RSA::setPrivateKeyFormat() - */ -/** - * PKCS#1 formatted private key - * - * Used by OpenSSH - */ -define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0); -/** - * PuTTY formatted private key - */ -define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1); -/** - * XML formatted private key - */ -define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2); -/** - * PKCS#8 formatted private key - */ -define('CRYPT_RSA_PRIVATE_FORMAT_PKCS8', 3); -/**#@-*/ - -/**#@+ - * @access public - * @see Crypt_RSA::createKey() - * @see Crypt_RSA::setPublicKeyFormat() - */ -/** - * Raw public key - * - * An array containing two Math_BigInteger objects. - * - * The exponent can be indexed with any of the following: - * - * 0, e, exponent, publicExponent - * - * The modulus can be indexed with any of the following: - * - * 1, n, modulo, modulus - */ -define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3); -/** - * PKCS#1 formatted public key (raw) - * - * Used by File/X509.php - * - * Has the following header: - * - * -----BEGIN RSA PUBLIC KEY----- - * - * Analogous to ssh-keygen's pem format (as specified by -m) - */ -define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4); -define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4); -/** - * XML formatted public key - */ -define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5); -/** - * OpenSSH formatted public key - * - * Place in $HOME/.ssh/authorized_keys - */ -define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6); -/** - * PKCS#1 formatted public key (encapsulated) - * - * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set) - * - * Has the following header: - * - * -----BEGIN PUBLIC KEY----- - * - * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8 - * is specific to private keys it's basically creating a DER-encoded wrapper - * for keys. This just extends that same concept to public keys (much like ssh-keygen) - */ -define('CRYPT_RSA_PUBLIC_FORMAT_PKCS8', 7); -/**#@-*/ - -/** - * Pure-PHP PKCS#1 compliant implementation of RSA. - * - * @package Crypt_RSA - * @author Jim Wigginton - * @access public - */ -class Crypt_RSA -{ - /** - * Precomputed Zero - * - * @var Array - * @access private - */ - var $zero; - - /** - * Precomputed One - * - * @var Array - * @access private - */ - var $one; - - /** - * Private Key Format - * - * @var Integer - * @access private - */ - var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1; - - /** - * Public Key Format - * - * @var Integer - * @access public - */ - var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS8; - - /** - * Modulus (ie. n) - * - * @var Math_BigInteger - * @access private - */ - var $modulus; - - /** - * Modulus length - * - * @var Math_BigInteger - * @access private - */ - var $k; - - /** - * Exponent (ie. e or d) - * - * @var Math_BigInteger - * @access private - */ - var $exponent; - - /** - * Primes for Chinese Remainder Theorem (ie. p and q) - * - * @var Array - * @access private - */ - var $primes; - - /** - * Exponents for Chinese Remainder Theorem (ie. dP and dQ) - * - * @var Array - * @access private - */ - var $exponents; - - /** - * Coefficients for Chinese Remainder Theorem (ie. qInv) - * - * @var Array - * @access private - */ - var $coefficients; - - /** - * Hash name - * - * @var String - * @access private - */ - var $hashName; - - /** - * Hash function - * - * @var Crypt_Hash - * @access private - */ - var $hash; - - /** - * Length of hash function output - * - * @var Integer - * @access private - */ - var $hLen; - - /** - * Length of salt - * - * @var Integer - * @access private - */ - var $sLen; - - /** - * Hash function for the Mask Generation Function - * - * @var Crypt_Hash - * @access private - */ - var $mgfHash; - - /** - * Length of MGF hash function output - * - * @var Integer - * @access private - */ - var $mgfHLen; - - /** - * Encryption mode - * - * @var Integer - * @access private - */ - var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP; - - /** - * Signature mode - * - * @var Integer - * @access private - */ - var $signatureMode = CRYPT_RSA_SIGNATURE_PSS; - - /** - * Public Exponent - * - * @var Mixed - * @access private - */ - var $publicExponent = false; - - /** - * Password - * - * @var String - * @access private - */ - var $password = false; - - /** - * Components - * - * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions - - * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't. - * - * @see Crypt_RSA::_start_element_handler() - * @var Array - * @access private - */ - var $components = array(); - - /** - * Current String - * - * For use with parsing XML formatted keys. - * - * @see Crypt_RSA::_character_handler() - * @see Crypt_RSA::_stop_element_handler() - * @var Mixed - * @access private - */ - var $current; - - /** - * OpenSSL configuration file name. - * - * Set to null to use system configuration file. - * @see Crypt_RSA::createKey() - * @var Mixed - * @Access public - */ - var $configFile; - - /** - * Public key comment field. - * - * @var String - * @access private - */ - var $comment = 'phpseclib-generated-key'; - - /** - * The constructor - * - * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason - * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires - * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late. - * - * @return Crypt_RSA - * @access public - */ - function Crypt_RSA() - { - if (!class_exists('Math_BigInteger')) { - include_once 'Math/BigInteger.php'; - } - - $this->configFile = CRYPT_RSA_OPENSSL_CONFIG; - - if ( !defined('CRYPT_RSA_MODE') ) { - switch (true) { - // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular, - // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger - // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either. - case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'): - define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); - break; - // openssl_pkey_get_details - which is used in the only place Crypt/RSA.php uses OpenSSL - was introduced in PHP 5.2.0 - case !function_exists('openssl_pkey_get_details'): - define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); - break; - case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile): - // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work - ob_start(); - @phpinfo(); - $content = ob_get_contents(); - ob_end_clean(); - - preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches); - - $versions = array(); - if (!empty($matches[1])) { - for ($i = 0; $i < count($matches[1]); $i++) { - $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); - - // Remove letter part in OpenSSL version - if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) { - $versions[$matches[1][$i]] = $fullVersion; - } else { - $versions[$matches[1][$i]] = $m[0]; - } - } - } - - // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+ - switch (true) { - case !isset($versions['Header']): - case !isset($versions['Library']): - case $versions['Header'] == $versions['Library']: - define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL); - break; - default: - define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); - define('MATH_BIGINTEGER_OPENSSL_DISABLE', true); - } - break; - default: - define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); - } - } - - $this->zero = new Math_BigInteger(); - $this->one = new Math_BigInteger(1); - - $this->hash = new Crypt_Hash('sha1'); - $this->hLen = $this->hash->getLength(); - $this->hashName = 'sha1'; - $this->mgfHash = new Crypt_Hash('sha1'); - $this->mgfHLen = $this->mgfHash->getLength(); - } - - /** - * Create public / private key pair - * - * Returns an array with the following three elements: - * - 'privatekey': The private key. - * - 'publickey': The public key. - * - 'partialkey': A partially computed key (if the execution time exceeded $timeout). - * Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing. - * - * @access public - * @param optional Integer $bits - * @param optional Integer $timeout - * @param optional Math_BigInteger $p - */ - function createKey($bits = 1024, $timeout = false, $partial = array()) - { - if (!defined('CRYPT_RSA_EXPONENT')) { - // http://en.wikipedia.org/wiki/65537_%28number%29 - define('CRYPT_RSA_EXPONENT', '65537'); - } - // per , this number ought not result in primes smaller - // than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME - // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if - // CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then - // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key - // generation when there's a chance neither gmp nor OpenSSL are installed) - if (!defined('CRYPT_RSA_SMALLEST_PRIME')) { - define('CRYPT_RSA_SMALLEST_PRIME', 4096); - } - - // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum - if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) { - $config = array(); - if (isset($this->configFile)) { - $config['config'] = $this->configFile; - } - $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config); - openssl_pkey_export($rsa, $privatekey, null, $config); - $publickey = openssl_pkey_get_details($rsa); - $publickey = $publickey['key']; - - $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1))); - $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1))); - - // clear the buffer of error strings stemming from a minimalistic openssl.cnf - while (openssl_error_string() !== false); - - return array( - 'privatekey' => $privatekey, - 'publickey' => $publickey, - 'partialkey' => false - ); - } - - static $e; - if (!isset($e)) { - $e = new Math_BigInteger(CRYPT_RSA_EXPONENT); - } - - extract($this->_generateMinMax($bits)); - $absoluteMin = $min; - $temp = $bits >> 1; // divide by two to see how many bits P and Q would be - if ($temp > CRYPT_RSA_SMALLEST_PRIME) { - $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME); - $temp = CRYPT_RSA_SMALLEST_PRIME; - } else { - $num_primes = 2; - } - extract($this->_generateMinMax($temp + $bits % $temp)); - $finalMax = $max; - extract($this->_generateMinMax($temp)); - - $generator = new Math_BigInteger(); - - $n = $this->one->copy(); - if (!empty($partial)) { - extract(unserialize($partial)); - } else { - $exponents = $coefficients = $primes = array(); - $lcm = array( - 'top' => $this->one->copy(), - 'bottom' => false - ); - } - - $start = time(); - $i0 = count($primes) + 1; - - do { - for ($i = $i0; $i <= $num_primes; $i++) { - if ($timeout !== false) { - $timeout-= time() - $start; - $start = time(); - if ($timeout <= 0) { - return array( - 'privatekey' => '', - 'publickey' => '', - 'partialkey' => serialize(array( - 'primes' => $primes, - 'coefficients' => $coefficients, - 'lcm' => $lcm, - 'exponents' => $exponents - )) - ); - } - } - - if ($i == $num_primes) { - list($min, $temp) = $absoluteMin->divide($n); - if (!$temp->equals($this->zero)) { - $min = $min->add($this->one); // ie. ceil() - } - $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout); - } else { - $primes[$i] = $generator->randomPrime($min, $max, $timeout); - } - - if ($primes[$i] === false) { // if we've reached the timeout - if (count($primes) > 1) { - $partialkey = ''; - } else { - array_pop($primes); - $partialkey = serialize(array( - 'primes' => $primes, - 'coefficients' => $coefficients, - 'lcm' => $lcm, - 'exponents' => $exponents - )); - } - - return array( - 'privatekey' => '', - 'publickey' => '', - 'partialkey' => $partialkey - ); - } - - // the first coefficient is calculated differently from the rest - // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1]) - if ($i > 2) { - $coefficients[$i] = $n->modInverse($primes[$i]); - } - - $n = $n->multiply($primes[$i]); - - $temp = $primes[$i]->subtract($this->one); - - // textbook RSA implementations use Euler's totient function instead of the least common multiple. - // see http://en.wikipedia.org/wiki/Euler%27s_totient_function - $lcm['top'] = $lcm['top']->multiply($temp); - $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp); - - $exponents[$i] = $e->modInverse($temp); - } - - list($temp) = $lcm['top']->divide($lcm['bottom']); - $gcd = $temp->gcd($e); - $i0 = 1; - } while (!$gcd->equals($this->one)); - - $d = $e->modInverse($temp); - - $coefficients[2] = $primes[2]->modInverse($primes[1]); - - // from : - // RSAPrivateKey ::= SEQUENCE { - // version Version, - // modulus INTEGER, -- n - // publicExponent INTEGER, -- e - // privateExponent INTEGER, -- d - // prime1 INTEGER, -- p - // prime2 INTEGER, -- q - // exponent1 INTEGER, -- d mod (p-1) - // exponent2 INTEGER, -- d mod (q-1) - // coefficient INTEGER, -- (inverse of q) mod p - // otherPrimeInfos OtherPrimeInfos OPTIONAL - // } - - return array( - 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients), - 'publickey' => $this->_convertPublicKey($n, $e), - 'partialkey' => false - ); - } - - /** - * Convert a private key to the appropriate format. - * - * @access private - * @see setPrivateKeyFormat() - * @param String $RSAPrivateKey - * @return String - */ - function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients) - { - $signed = $this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_XML; - $num_primes = count($primes); - $raw = array( - 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi - 'modulus' => $n->toBytes($signed), - 'publicExponent' => $e->toBytes($signed), - 'privateExponent' => $d->toBytes($signed), - 'prime1' => $primes[1]->toBytes($signed), - 'prime2' => $primes[2]->toBytes($signed), - 'exponent1' => $exponents[1]->toBytes($signed), - 'exponent2' => $exponents[2]->toBytes($signed), - 'coefficient' => $coefficients[2]->toBytes($signed) - ); - - // if the format in question does not support multi-prime rsa and multi-prime rsa was used, - // call _convertPublicKey() instead. - switch ($this->privateKeyFormat) { - case CRYPT_RSA_PRIVATE_FORMAT_XML: - if ($num_primes != 2) { - return false; - } - return "\r\n" . - ' ' . base64_encode($raw['modulus']) . "\r\n" . - ' ' . base64_encode($raw['publicExponent']) . "\r\n" . - '

' . base64_encode($raw['prime1']) . "

\r\n" . - ' ' . base64_encode($raw['prime2']) . "\r\n" . - ' ' . base64_encode($raw['exponent1']) . "\r\n" . - ' ' . base64_encode($raw['exponent2']) . "\r\n" . - ' ' . base64_encode($raw['coefficient']) . "\r\n" . - ' ' . base64_encode($raw['privateExponent']) . "\r\n" . - '
'; - break; - case CRYPT_RSA_PRIVATE_FORMAT_PUTTY: - if ($num_primes != 2) { - return false; - } - $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: "; - $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none'; - $key.= $encryption; - $key.= "\r\nComment: " . $this->comment . "\r\n"; - $public = pack('Na*Na*Na*', - strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus'] - ); - $source = pack('Na*Na*Na*Na*', - strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption, - strlen($this->comment), $this->comment, strlen($public), $public - ); - $public = base64_encode($public); - $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n"; - $key.= chunk_split($public, 64); - $private = pack('Na*Na*Na*Na*', - strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'], - strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient'] - ); - if (empty($this->password) && !is_string($this->password)) { - $source.= pack('Na*', strlen($private), $private); - $hashkey = 'putty-private-key-file-mac-key'; - } else { - $private.= crypt_random_string(16 - (strlen($private) & 15)); - $source.= pack('Na*', strlen($private), $private); - if (!class_exists('Crypt_AES')) { - include_once 'Crypt/AES.php'; - } - $sequence = 0; - $symkey = ''; - while (strlen($symkey) < 32) { - $temp = pack('Na*', $sequence++, $this->password); - $symkey.= pack('H*', sha1($temp)); - } - $symkey = substr($symkey, 0, 32); - $crypto = new Crypt_AES(); - - $crypto->setKey($symkey); - $crypto->disablePadding(); - $private = $crypto->encrypt($private); - $hashkey = 'putty-private-key-file-mac-key' . $this->password; - } - - $private = base64_encode($private); - $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n"; - $key.= chunk_split($private, 64); - if (!class_exists('Crypt_Hash')) { - include_once 'Crypt/Hash.php'; - } - $hash = new Crypt_Hash('sha1'); - $hash->setKey(pack('H*', sha1($hashkey))); - $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n"; - - return $key; - default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1 - $components = array(); - foreach ($raw as $name => $value) { - $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value); - } - - $RSAPrivateKey = implode('', $components); - - if ($num_primes > 2) { - $OtherPrimeInfos = ''; - for ($i = 3; $i <= $num_primes; $i++) { - // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo - // - // OtherPrimeInfo ::= SEQUENCE { - // prime INTEGER, -- ri - // exponent INTEGER, -- di - // coefficient INTEGER -- ti - // } - $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true)); - $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true)); - $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true)); - $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo); - } - $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos); - } - - $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); - - if ($this->privateKeyFormat == CRYPT_RSA_PRIVATE_FORMAT_PKCS8) { - $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA - $RSAPrivateKey = pack('Ca*a*Ca*a*', - CRYPT_RSA_ASN1_INTEGER, "\01\00", $rsaOID, 4, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey - ); - $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); - if (!empty($this->password) || is_string($this->password)) { - $salt = crypt_random_string(8); - $iterationCount = 2048; - - if (!class_exists('Crypt_DES')) { - include_once 'Crypt/DES.php'; - } - $crypto = new Crypt_DES(); - $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount); - $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey); - - $parameters = pack('Ca*a*Ca*N', - CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($salt)), $salt, - CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(4), $iterationCount - ); - $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03"; - - $encryptionAlgorithm = pack('Ca*a*Ca*a*', - CRYPT_RSA_ASN1_OBJECT, $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)), $pbeWithMD5AndDES_CBC, - CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($parameters)), $parameters - ); - - $RSAPrivateKey = pack('Ca*a*Ca*a*', - CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($encryptionAlgorithm)), $encryptionAlgorithm, - CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey - ); - - $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); - - $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" . - chunk_split(base64_encode($RSAPrivateKey), 64) . - '-----END ENCRYPTED PRIVATE KEY-----'; - } else { - $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" . - chunk_split(base64_encode($RSAPrivateKey), 64) . - '-----END PRIVATE KEY-----'; - } - return $RSAPrivateKey; - } - - if (!empty($this->password) || is_string($this->password)) { - $iv = crypt_random_string(8); - $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key - $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8); - if (!class_exists('Crypt_TripleDES')) { - include_once 'Crypt/TripleDES.php'; - } - $des = new Crypt_TripleDES(); - $des->setKey($symkey); - $des->setIV($iv); - $iv = strtoupper(bin2hex($iv)); - $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . - "Proc-Type: 4,ENCRYPTED\r\n" . - "DEK-Info: DES-EDE3-CBC,$iv\r\n" . - "\r\n" . - chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) . - '-----END RSA PRIVATE KEY-----'; - } else { - $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . - chunk_split(base64_encode($RSAPrivateKey), 64) . - '-----END RSA PRIVATE KEY-----'; - } - - return $RSAPrivateKey; - } - } - - /** - * Convert a public key to the appropriate format - * - * @access private - * @see setPublicKeyFormat() - * @param String $RSAPrivateKey - * @return String - */ - function _convertPublicKey($n, $e) - { - $signed = $this->publicKeyFormat != CRYPT_RSA_PUBLIC_FORMAT_XML; - - $modulus = $n->toBytes($signed); - $publicExponent = $e->toBytes($signed); - - switch ($this->publicKeyFormat) { - case CRYPT_RSA_PUBLIC_FORMAT_RAW: - return array('e' => $e->copy(), 'n' => $n->copy()); - case CRYPT_RSA_PUBLIC_FORMAT_XML: - return "\r\n" . - ' ' . base64_encode($modulus) . "\r\n" . - ' ' . base64_encode($publicExponent) . "\r\n" . - ''; - break; - case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: - // from : - // string "ssh-rsa" - // mpint e - // mpint n - $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus); - $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment; - - return $RSAPublicKey; - default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1 - // from : - // RSAPublicKey ::= SEQUENCE { - // modulus INTEGER, -- n - // publicExponent INTEGER -- e - // } - $components = array( - 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus), - 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent) - ); - - $RSAPublicKey = pack('Ca*a*a*', - CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), - $components['modulus'], $components['publicExponent'] - ); - - if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) { - $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" . - chunk_split(base64_encode($RSAPublicKey), 64) . - '-----END RSA PUBLIC KEY-----'; - } else { - // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption. - $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA - $RSAPublicKey = chr(0) . $RSAPublicKey; - $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey; - - $RSAPublicKey = pack('Ca*a*', - CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey - ); - - $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . - chunk_split(base64_encode($RSAPublicKey), 64) . - '-----END PUBLIC KEY-----'; - } - - return $RSAPublicKey; - } - } - - /** - * Break a public or private key down into its constituant components - * - * @access private - * @see _convertPublicKey() - * @see _convertPrivateKey() - * @param String $key - * @param Integer $type - * @return Array - */ - function _parseKey($key, $type) - { - if ($type != CRYPT_RSA_PUBLIC_FORMAT_RAW && !is_string($key)) { - return false; - } - - switch ($type) { - case CRYPT_RSA_PUBLIC_FORMAT_RAW: - if (!is_array($key)) { - return false; - } - $components = array(); - switch (true) { - case isset($key['e']): - $components['publicExponent'] = $key['e']->copy(); - break; - case isset($key['exponent']): - $components['publicExponent'] = $key['exponent']->copy(); - break; - case isset($key['publicExponent']): - $components['publicExponent'] = $key['publicExponent']->copy(); - break; - case isset($key[0]): - $components['publicExponent'] = $key[0]->copy(); - } - switch (true) { - case isset($key['n']): - $components['modulus'] = $key['n']->copy(); - break; - case isset($key['modulo']): - $components['modulus'] = $key['modulo']->copy(); - break; - case isset($key['modulus']): - $components['modulus'] = $key['modulus']->copy(); - break; - case isset($key[1]): - $components['modulus'] = $key[1]->copy(); - } - return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false; - case CRYPT_RSA_PRIVATE_FORMAT_PKCS1: - case CRYPT_RSA_PRIVATE_FORMAT_PKCS8: - case CRYPT_RSA_PUBLIC_FORMAT_PKCS1: - /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is - "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to - protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding - two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here: - - http://tools.ietf.org/html/rfc1421#section-4.6.1.1 - http://tools.ietf.org/html/rfc1421#section-4.6.1.3 - - DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell. - DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation - function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's - own implementation. ie. the implementation *is* the standard and any bugs that may exist in that - implementation are part of the standard, as well. - - * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */ - if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) { - $iv = pack('H*', trim($matches[2])); - $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key - $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8))); - // remove the Proc-Type / DEK-Info sections as they're no longer needed - $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key); - $ciphertext = $this->_extractBER($key); - if ($ciphertext === false) { - $ciphertext = $key; - } - switch ($matches[1]) { - case 'AES-256-CBC': - if (!class_exists('Crypt_AES')) { - include_once 'Crypt/AES.php'; - } - $crypto = new Crypt_AES(); - break; - case 'AES-128-CBC': - if (!class_exists('Crypt_AES')) { - include_once 'Crypt/AES.php'; - } - $symkey = substr($symkey, 0, 16); - $crypto = new Crypt_AES(); - break; - case 'DES-EDE3-CFB': - if (!class_exists('Crypt_TripleDES')) { - include_once 'Crypt/TripleDES.php'; - } - $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB); - break; - case 'DES-EDE3-CBC': - if (!class_exists('Crypt_TripleDES')) { - include_once 'Crypt/TripleDES.php'; - } - $symkey = substr($symkey, 0, 24); - $crypto = new Crypt_TripleDES(); - break; - case 'DES-CBC': - if (!class_exists('Crypt_DES')) { - include_once 'Crypt/DES.php'; - } - $crypto = new Crypt_DES(); - break; - default: - return false; - } - $crypto->setKey($symkey); - $crypto->setIV($iv); - $decoded = $crypto->decrypt($ciphertext); - } else { - $decoded = $this->_extractBER($key); - } - - if ($decoded !== false) { - $key = $decoded; - } - - $components = array(); - - if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { - return false; - } - if ($this->_decodeLength($key) != strlen($key)) { - return false; - } - - $tag = ord($this->_string_shift($key)); - /* intended for keys for which OpenSSL's asn1parse returns the following: - - 0:d=0 hl=4 l= 631 cons: SEQUENCE - 4:d=1 hl=2 l= 1 prim: INTEGER :00 - 7:d=1 hl=2 l= 13 cons: SEQUENCE - 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption - 20:d=2 hl=2 l= 0 prim: NULL - 22:d=1 hl=4 l= 609 prim: OCTET STRING - - ie. PKCS8 keys*/ - - if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") { - $this->_string_shift($key, 3); - $tag = CRYPT_RSA_ASN1_SEQUENCE; - } - - if ($tag == CRYPT_RSA_ASN1_SEQUENCE) { - $temp = $this->_string_shift($key, $this->_decodeLength($key)); - if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_OBJECT) { - return false; - } - $length = $this->_decodeLength($temp); - switch ($this->_string_shift($temp, $length)) { - case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption - break; - case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC - /* - PBEParameter ::= SEQUENCE { - salt OCTET STRING (SIZE(8)), - iterationCount INTEGER } - */ - if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_SEQUENCE) { - return false; - } - if ($this->_decodeLength($temp) != strlen($temp)) { - return false; - } - $this->_string_shift($temp); // assume it's an octet string - $salt = $this->_string_shift($temp, $this->_decodeLength($temp)); - if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_INTEGER) { - return false; - } - $this->_decodeLength($temp); - list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT)); - $this->_string_shift($key); // assume it's an octet string - $length = $this->_decodeLength($key); - if (strlen($key) != $length) { - return false; - } - - if (!class_exists('Crypt_DES')) { - include_once 'Crypt/DES.php'; - } - $crypto = new Crypt_DES(); - $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount); - $key = $crypto->decrypt($key); - if ($key === false) { - return false; - } - return $this->_parseKey($key, CRYPT_RSA_PRIVATE_FORMAT_PKCS1); - default: - return false; - } - /* intended for keys for which OpenSSL's asn1parse returns the following: - - 0:d=0 hl=4 l= 290 cons: SEQUENCE - 4:d=1 hl=2 l= 13 cons: SEQUENCE - 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption - 17:d=2 hl=2 l= 0 prim: NULL - 19:d=1 hl=4 l= 271 prim: BIT STRING */ - $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag - $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length - // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of - // unused bits in the final subsequent octet. The number shall be in the range zero to seven." - // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2) - if ($tag == CRYPT_RSA_ASN1_BITSTRING) { - $this->_string_shift($key); - } - if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { - return false; - } - if ($this->_decodeLength($key) != strlen($key)) { - return false; - } - $tag = ord($this->_string_shift($key)); - } - if ($tag != CRYPT_RSA_ASN1_INTEGER) { - return false; - } - - $length = $this->_decodeLength($key); - $temp = $this->_string_shift($key, $length); - if (strlen($temp) != 1 || ord($temp) > 2) { - $components['modulus'] = new Math_BigInteger($temp, 256); - $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER - $length = $this->_decodeLength($key); - $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256); - - return $components; - } - if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) { - return false; - } - $length = $this->_decodeLength($key); - $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256)); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256)); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256)); - - if (!empty($key)) { - if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { - return false; - } - $this->_decodeLength($key); - while (!empty($key)) { - if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { - return false; - } - $this->_decodeLength($key); - $key = substr($key, 1); - $length = $this->_decodeLength($key); - $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256); - } - } - - return $components; - case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: - $parts = explode(' ', $key, 3); - - $key = isset($parts[1]) ? base64_decode($parts[1]) : false; - if ($key === false) { - return false; - } - - $comment = isset($parts[2]) ? $parts[2] : false; - - $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa"; - - if (strlen($key) <= 4) { - return false; - } - extract(unpack('Nlength', $this->_string_shift($key, 4))); - $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256); - if (strlen($key) <= 4) { - return false; - } - extract(unpack('Nlength', $this->_string_shift($key, 4))); - $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256); - - if ($cleanup && strlen($key)) { - if (strlen($key) <= 4) { - return false; - } - extract(unpack('Nlength', $this->_string_shift($key, 4))); - $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256); - return strlen($key) ? false : array( - 'modulus' => $realModulus, - 'publicExponent' => $modulus, - 'comment' => $comment - ); - } else { - return strlen($key) ? false : array( - 'modulus' => $modulus, - 'publicExponent' => $publicExponent, - 'comment' => $comment - ); - } - // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue - // http://en.wikipedia.org/wiki/XML_Signature - case CRYPT_RSA_PRIVATE_FORMAT_XML: - case CRYPT_RSA_PUBLIC_FORMAT_XML: - $this->components = array(); - - $xml = xml_parser_create('UTF-8'); - xml_set_object($xml, $this); - xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler'); - xml_set_character_data_handler($xml, '_data_handler'); - // add to account for "dangling" tags like ... that are sometimes added - if (!xml_parse($xml, '' . $key . '')) { - return false; - } - - return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false; - // from PuTTY's SSHPUBK.C - case CRYPT_RSA_PRIVATE_FORMAT_PUTTY: - $components = array(); - $key = preg_split('#\r\n|\r|\n#', $key); - $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0])); - if ($type != 'ssh-rsa') { - return false; - } - $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1])); - $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2])); - - $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3])); - $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength)))); - $public = substr($public, 11); - extract(unpack('Nlength', $this->_string_shift($public, 4))); - $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256); - extract(unpack('Nlength', $this->_string_shift($public, 4))); - $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256); - - $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4])); - $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength)))); - - switch ($encryption) { - case 'aes256-cbc': - if (!class_exists('Crypt_AES')) { - include_once 'Crypt/AES.php'; - } - $symkey = ''; - $sequence = 0; - while (strlen($symkey) < 32) { - $temp = pack('Na*', $sequence++, $this->password); - $symkey.= pack('H*', sha1($temp)); - } - $symkey = substr($symkey, 0, 32); - $crypto = new Crypt_AES(); - } - - if ($encryption != 'none') { - $crypto->setKey($symkey); - $crypto->disablePadding(); - $private = $crypto->decrypt($private); - if ($private === false) { - return false; - } - } - - extract(unpack('Nlength', $this->_string_shift($private, 4))); - if (strlen($private) < $length) { - return false; - } - $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256); - extract(unpack('Nlength', $this->_string_shift($private, 4))); - if (strlen($private) < $length) { - return false; - } - $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256)); - extract(unpack('Nlength', $this->_string_shift($private, 4))); - if (strlen($private) < $length) { - return false; - } - $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256); - - $temp = $components['primes'][1]->subtract($this->one); - $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp)); - $temp = $components['primes'][2]->subtract($this->one); - $components['exponents'][] = $components['publicExponent']->modInverse($temp); - - extract(unpack('Nlength', $this->_string_shift($private, 4))); - if (strlen($private) < $length) { - return false; - } - $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256)); - - return $components; - } - } - - /** - * Returns the key size - * - * More specifically, this returns the size of the modulo in bits. - * - * @access public - * @return Integer - */ - function getSize() - { - return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits()); - } - - /** - * Start Element Handler - * - * Called by xml_set_element_handler() - * - * @access private - * @param Resource $parser - * @param String $name - * @param Array $attribs - */ - function _start_element_handler($parser, $name, $attribs) - { - //$name = strtoupper($name); - switch ($name) { - case 'MODULUS': - $this->current = &$this->components['modulus']; - break; - case 'EXPONENT': - $this->current = &$this->components['publicExponent']; - break; - case 'P': - $this->current = &$this->components['primes'][1]; - break; - case 'Q': - $this->current = &$this->components['primes'][2]; - break; - case 'DP': - $this->current = &$this->components['exponents'][1]; - break; - case 'DQ': - $this->current = &$this->components['exponents'][2]; - break; - case 'INVERSEQ': - $this->current = &$this->components['coefficients'][2]; - break; - case 'D': - $this->current = &$this->components['privateExponent']; - } - $this->current = ''; - } - - /** - * Stop Element Handler - * - * Called by xml_set_element_handler() - * - * @access private - * @param Resource $parser - * @param String $name - */ - function _stop_element_handler($parser, $name) - { - if (isset($this->current)) { - $this->current = new Math_BigInteger(base64_decode($this->current), 256); - unset($this->current); - } - } - - /** - * Data Handler - * - * Called by xml_set_character_data_handler() - * - * @access private - * @param Resource $parser - * @param String $data - */ - function _data_handler($parser, $data) - { - if (!isset($this->current) || is_object($this->current)) { - return; - } - $this->current.= trim($data); - } - - /** - * Loads a public or private key - * - * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed) - * - * @access public - * @param String $key - * @param Integer $type optional - */ - function loadKey($key, $type = false) - { - if (is_object($key) && strtolower(get_class($key)) == 'crypt_rsa') { - $this->privateKeyFormat = $key->privateKeyFormat; - $this->publicKeyFormat = $key->publicKeyFormat; - $this->k = $key->k; - $this->hLen = $key->hLen; - $this->sLen = $key->sLen; - $this->mgfHLen = $key->mgfHLen; - $this->encryptionMode = $key->encryptionMode; - $this->signatureMode = $key->signatureMode; - $this->password = $key->password; - $this->configFile = $key->configFile; - $this->comment = $key->comment; - - if (is_object($key->hash)) { - $this->hash = new Crypt_Hash($key->hash->getHash()); - } - if (is_object($key->mgfHash)) { - $this->mgfHash = new Crypt_Hash($key->mgfHash->getHash()); - } - - if (is_object($key->modulus)) { - $this->modulus = $key->modulus->copy(); - } - if (is_object($key->exponent)) { - $this->exponent = $key->exponent->copy(); - } - if (is_object($key->publicExponent)) { - $this->publicExponent = $key->publicExponent->copy(); - } - - $this->primes = array(); - $this->exponents = array(); - $this->coefficients = array(); - - foreach ($this->primes as $prime) { - $this->primes[] = $prime->copy(); - } - foreach ($this->exponents as $exponent) { - $this->exponents[] = $exponent->copy(); - } - foreach ($this->coefficients as $coefficient) { - $this->coefficients[] = $coefficient->copy(); - } - - return true; - } - - if ($type === false) { - $types = array( - CRYPT_RSA_PUBLIC_FORMAT_RAW, - CRYPT_RSA_PRIVATE_FORMAT_PKCS1, - CRYPT_RSA_PRIVATE_FORMAT_XML, - CRYPT_RSA_PRIVATE_FORMAT_PUTTY, - CRYPT_RSA_PUBLIC_FORMAT_OPENSSH - ); - foreach ($types as $type) { - $components = $this->_parseKey($key, $type); - if ($components !== false) { - break; - } - } - - } else { - $components = $this->_parseKey($key, $type); - } - - if ($components === false) { - return false; - } - - if (isset($components['comment']) && $components['comment'] !== false) { - $this->comment = $components['comment']; - } - $this->modulus = $components['modulus']; - $this->k = strlen($this->modulus->toBytes()); - $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent']; - if (isset($components['primes'])) { - $this->primes = $components['primes']; - $this->exponents = $components['exponents']; - $this->coefficients = $components['coefficients']; - $this->publicExponent = $components['publicExponent']; - } else { - $this->primes = array(); - $this->exponents = array(); - $this->coefficients = array(); - $this->publicExponent = false; - } - - switch ($type) { - case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: - case CRYPT_RSA_PUBLIC_FORMAT_RAW: - $this->setPublicKey(); - break; - case CRYPT_RSA_PRIVATE_FORMAT_PKCS1: - switch (true) { - case strpos($key, '-BEGIN PUBLIC KEY-') !== false: - case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false: - $this->setPublicKey(); - } - } - - return true; - } - - /** - * Sets the password - * - * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false. - * Or rather, pass in $password such that empty($password) && !is_string($password) is true. - * - * @see createKey() - * @see loadKey() - * @access public - * @param String $password - */ - function setPassword($password = false) - { - $this->password = $password; - } - - /** - * Defines the public key - * - * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when - * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a - * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys - * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public - * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used - * is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being - * public. - * - * Do note that when a new key is loaded the index will be cleared. - * - * Returns true on success, false on failure - * - * @see getPublicKey() - * @access public - * @param String $key optional - * @param Integer $type optional - * @return Boolean - */ - function setPublicKey($key = false, $type = false) - { - // if a public key has already been loaded return false - if (!empty($this->publicExponent)) { - return false; - } - - if ($key === false && !empty($this->modulus)) { - $this->publicExponent = $this->exponent; - return true; - } - - if ($type === false) { - $types = array( - CRYPT_RSA_PUBLIC_FORMAT_RAW, - CRYPT_RSA_PUBLIC_FORMAT_PKCS1, - CRYPT_RSA_PUBLIC_FORMAT_XML, - CRYPT_RSA_PUBLIC_FORMAT_OPENSSH - ); - foreach ($types as $type) { - $components = $this->_parseKey($key, $type); - if ($components !== false) { - break; - } - } - } else { - $components = $this->_parseKey($key, $type); - } - - if ($components === false) { - return false; - } - - if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { - $this->modulus = $components['modulus']; - $this->exponent = $this->publicExponent = $components['publicExponent']; - return true; - } - - $this->publicExponent = $components['publicExponent']; - - return true; - } - - /** - * Defines the private key - * - * If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force - * phpseclib to treat the key as a private key. This function will do that. - * - * Do note that when a new key is loaded the index will be cleared. - * - * Returns true on success, false on failure - * - * @see getPublicKey() - * @access public - * @param String $key optional - * @param Integer $type optional - * @return Boolean - */ - function setPrivateKey($key = false, $type = false) - { - if ($key === false && !empty($this->publicExponent)) { - unset($this->publicExponent); - return true; - } - - $rsa = new Crypt_RSA(); - if (!$rsa->loadKey($key, $type)) { - return false; - } - unset($rsa->publicExponent); - - // don't overwrite the old key if the new key is invalid - $this->loadKey($rsa); - return true; - } - - /** - * Returns the public key - * - * The public key is only returned under two circumstances - if the private key had the public key embedded within it - * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this - * function won't return it since this library, for the most part, doesn't distinguish between public and private keys. - * - * @see getPublicKey() - * @access public - * @param String $key - * @param Integer $type optional - */ - function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS8) - { - if (empty($this->modulus) || empty($this->publicExponent)) { - return false; - } - - $oldFormat = $this->publicKeyFormat; - $this->publicKeyFormat = $type; - $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent); - $this->publicKeyFormat = $oldFormat; - return $temp; - } - - /** - * Returns the private key - * - * The private key is only returned if the currently loaded key contains the constituent prime numbers. - * - * @see getPublicKey() - * @access public - * @param String $key - * @param Integer $type optional - */ - function getPrivateKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) - { - if (empty($this->primes)) { - return false; - } - - $oldFormat = $this->privateKeyFormat; - $this->privateKeyFormat = $type; - $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients); - $this->privateKeyFormat = $oldFormat; - return $temp; - } - - /** - * Returns a minimalistic private key - * - * Returns the private key without the prime number constituants. Structurally identical to a public key that - * hasn't been set as the public key - * - * @see getPrivateKey() - * @access private - * @param String $key - * @param Integer $type optional - */ - function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS8) - { - if (empty($this->modulus) || empty($this->exponent)) { - return false; - } - - $oldFormat = $this->publicKeyFormat; - $this->publicKeyFormat = $mode; - $temp = $this->_convertPublicKey($this->modulus, $this->exponent); - $this->publicKeyFormat = $oldFormat; - return $temp; - } - - /** - * __toString() magic method - * - * @access public - */ - function __toString() - { - $key = $this->getPrivateKey($this->privateKeyFormat); - if ($key !== false) { - return $key; - } - $key = $this->_getPrivatePublicKey($this->publicKeyFormat); - return $key !== false ? $key : ''; - } - - /** - * __clone() magic method - * - * @access public - */ - function __clone() - { - $key = new Crypt_RSA(); - $key->loadKey($this); - return $key; - } - - /** - * Generates the smallest and largest numbers requiring $bits bits - * - * @access private - * @param Integer $bits - * @return Array - */ - function _generateMinMax($bits) - { - $bytes = $bits >> 3; - $min = str_repeat(chr(0), $bytes); - $max = str_repeat(chr(0xFF), $bytes); - $msb = $bits & 7; - if ($msb) { - $min = chr(1 << ($msb - 1)) . $min; - $max = chr((1 << $msb) - 1) . $max; - } else { - $min[0] = chr(0x80); - } - - return array( - 'min' => new Math_BigInteger($min, 256), - 'max' => new Math_BigInteger($max, 256) - ); - } - - /** - * DER-decode the length - * - * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See - * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. - * - * @access private - * @param String $string - * @return Integer - */ - function _decodeLength(&$string) - { - $length = ord($this->_string_shift($string)); - if ( $length & 0x80 ) { // definite length, long form - $length&= 0x7F; - $temp = $this->_string_shift($string, $length); - list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)); - } - return $length; - } - - /** - * DER-encode the length - * - * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See - * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. - * - * @access private - * @param Integer $length - * @return String - */ - function _encodeLength($length) - { - if ($length <= 0x7F) { - return chr($length); - } - - $temp = ltrim(pack('N', $length), chr(0)); - return pack('Ca*', 0x80 | strlen($temp), $temp); - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; - } - - /** - * Determines the private key format - * - * @see createKey() - * @access public - * @param Integer $format - */ - function setPrivateKeyFormat($format) - { - $this->privateKeyFormat = $format; - } - - /** - * Determines the public key format - * - * @see createKey() - * @access public - * @param Integer $format - */ - function setPublicKeyFormat($format) - { - $this->publicKeyFormat = $format; - } - - /** - * Determines which hashing function should be used - * - * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and - * decryption. If $hash isn't supported, sha1 is used. - * - * @access public - * @param String $hash - */ - function setHash($hash) - { - // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. - switch ($hash) { - case 'md2': - case 'md5': - case 'sha1': - case 'sha256': - case 'sha384': - case 'sha512': - $this->hash = new Crypt_Hash($hash); - $this->hashName = $hash; - break; - default: - $this->hash = new Crypt_Hash('sha1'); - $this->hashName = 'sha1'; - } - $this->hLen = $this->hash->getLength(); - } - - /** - * Determines which hashing function should be used for the mask generation function - * - * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's - * best if Hash and MGFHash are set to the same thing this is not a requirement. - * - * @access public - * @param String $hash - */ - function setMGFHash($hash) - { - // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. - switch ($hash) { - case 'md2': - case 'md5': - case 'sha1': - case 'sha256': - case 'sha384': - case 'sha512': - $this->mgfHash = new Crypt_Hash($hash); - break; - default: - $this->mgfHash = new Crypt_Hash('sha1'); - } - $this->mgfHLen = $this->mgfHash->getLength(); - } - - /** - * Determines the salt length - * - * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}: - * - * Typical salt lengths in octets are hLen (the length of the output - * of the hash function Hash) and 0. - * - * @access public - * @param Integer $format - */ - function setSaltLength($sLen) - { - $this->sLen = $sLen; - } - - /** - * Integer-to-Octet-String primitive - * - * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}. - * - * @access private - * @param Math_BigInteger $x - * @param Integer $xLen - * @return String - */ - function _i2osp($x, $xLen) - { - $x = $x->toBytes(); - if (strlen($x) > $xLen) { - user_error('Integer too large'); - return false; - } - return str_pad($x, $xLen, chr(0), STR_PAD_LEFT); - } - - /** - * Octet-String-to-Integer primitive - * - * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}. - * - * @access private - * @param String $x - * @return Math_BigInteger - */ - function _os2ip($x) - { - return new Math_BigInteger($x, 256); - } - - /** - * Exponentiate with or without Chinese Remainder Theorem - * - * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}. - * - * @access private - * @param Math_BigInteger $x - * @return Math_BigInteger - */ - function _exponentiate($x) - { - if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) { - return $x->modPow($this->exponent, $this->modulus); - } - - $num_primes = count($this->primes); - - if (defined('CRYPT_RSA_DISABLE_BLINDING')) { - $m_i = array( - 1 => $x->modPow($this->exponents[1], $this->primes[1]), - 2 => $x->modPow($this->exponents[2], $this->primes[2]) - ); - $h = $m_i[1]->subtract($m_i[2]); - $h = $h->multiply($this->coefficients[2]); - list(, $h) = $h->divide($this->primes[1]); - $m = $m_i[2]->add($h->multiply($this->primes[2])); - - $r = $this->primes[1]; - for ($i = 3; $i <= $num_primes; $i++) { - $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]); - - $r = $r->multiply($this->primes[$i - 1]); - - $h = $m_i->subtract($m); - $h = $h->multiply($this->coefficients[$i]); - list(, $h) = $h->divide($this->primes[$i]); - - $m = $m->add($r->multiply($h)); - } - } else { - $smallest = $this->primes[1]; - for ($i = 2; $i <= $num_primes; $i++) { - if ($smallest->compare($this->primes[$i]) > 0) { - $smallest = $this->primes[$i]; - } - } - - $one = new Math_BigInteger(1); - - $r = $one->random($one, $smallest->subtract($one)); - - $m_i = array( - 1 => $this->_blind($x, $r, 1), - 2 => $this->_blind($x, $r, 2) - ); - $h = $m_i[1]->subtract($m_i[2]); - $h = $h->multiply($this->coefficients[2]); - list(, $h) = $h->divide($this->primes[1]); - $m = $m_i[2]->add($h->multiply($this->primes[2])); - - $r = $this->primes[1]; - for ($i = 3; $i <= $num_primes; $i++) { - $m_i = $this->_blind($x, $r, $i); - - $r = $r->multiply($this->primes[$i - 1]); - - $h = $m_i->subtract($m); - $h = $h->multiply($this->coefficients[$i]); - list(, $h) = $h->divide($this->primes[$i]); - - $m = $m->add($r->multiply($h)); - } - } - - return $m; - } - - /** - * Performs RSA Blinding - * - * Protects against timing attacks by employing RSA Blinding. - * Returns $x->modPow($this->exponents[$i], $this->primes[$i]) - * - * @access private - * @param Math_BigInteger $x - * @param Math_BigInteger $r - * @param Integer $i - * @return Math_BigInteger - */ - function _blind($x, $r, $i) - { - $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i])); - $x = $x->modPow($this->exponents[$i], $this->primes[$i]); - - $r = $r->modInverse($this->primes[$i]); - $x = $x->multiply($r); - list(, $x) = $x->divide($this->primes[$i]); - - return $x; - } - - /** - * Performs blinded RSA equality testing - * - * Protects against a particular type of timing attack described. - * - * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)} - * - * Thanks for the heads up singpolyma! - * - * @access private - * @param String $x - * @param String $y - * @return Boolean - */ - function _equals($x, $y) - { - if (strlen($x) != strlen($y)) { - return false; - } - - $result = 0; - for ($i = 0; $i < strlen($x); $i++) { - $result |= ord($x[$i]) ^ ord($y[$i]); - } - - return $result == 0; - } - - /** - * RSAEP - * - * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}. - * - * @access private - * @param Math_BigInteger $m - * @return Math_BigInteger - */ - function _rsaep($m) - { - if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { - user_error('Message representative out of range'); - return false; - } - return $this->_exponentiate($m); - } - - /** - * RSADP - * - * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}. - * - * @access private - * @param Math_BigInteger $c - * @return Math_BigInteger - */ - function _rsadp($c) - { - if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) { - user_error('Ciphertext representative out of range'); - return false; - } - return $this->_exponentiate($c); - } - - /** - * RSASP1 - * - * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}. - * - * @access private - * @param Math_BigInteger $m - * @return Math_BigInteger - */ - function _rsasp1($m) - { - if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { - user_error('Message representative out of range'); - return false; - } - return $this->_exponentiate($m); - } - - /** - * RSAVP1 - * - * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}. - * - * @access private - * @param Math_BigInteger $s - * @return Math_BigInteger - */ - function _rsavp1($s) - { - if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) { - user_error('Signature representative out of range'); - return false; - } - return $this->_exponentiate($s); - } - - /** - * MGF1 - * - * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}. - * - * @access private - * @param String $mgfSeed - * @param Integer $mgfLen - * @return String - */ - function _mgf1($mgfSeed, $maskLen) - { - // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output. - - $t = ''; - $count = ceil($maskLen / $this->mgfHLen); - for ($i = 0; $i < $count; $i++) { - $c = pack('N', $i); - $t.= $this->mgfHash->hash($mgfSeed . $c); - } - - return substr($t, 0, $maskLen); - } - - /** - * RSAES-OAEP-ENCRYPT - * - * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and - * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}. - * - * @access private - * @param String $m - * @param String $l - * @return String - */ - function _rsaes_oaep_encrypt($m, $l = '') - { - $mLen = strlen($m); - - // Length checking - - // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error - // be output. - - if ($mLen > $this->k - 2 * $this->hLen - 2) { - user_error('Message too long'); - return false; - } - - // EME-OAEP encoding - - $lHash = $this->hash->hash($l); - $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2); - $db = $lHash . $ps . chr(1) . $m; - $seed = crypt_random_string($this->hLen); - $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); - $maskedDB = $db ^ $dbMask; - $seedMask = $this->_mgf1($maskedDB, $this->hLen); - $maskedSeed = $seed ^ $seedMask; - $em = chr(0) . $maskedSeed . $maskedDB; - - // RSA encryption - - $m = $this->_os2ip($em); - $c = $this->_rsaep($m); - $c = $this->_i2osp($c, $this->k); - - // Output the ciphertext C - - return $c; - } - - /** - * RSAES-OAEP-DECRYPT - * - * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error - * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2: - * - * Note. Care must be taken to ensure that an opponent cannot - * distinguish the different error conditions in Step 3.g, whether by - * error message or timing, or, more generally, learn partial - * information about the encoded message EM. Otherwise an opponent may - * be able to obtain useful information about the decryption of the - * ciphertext C, leading to a chosen-ciphertext attack such as the one - * observed by Manger [36]. - * - * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}: - * - * Both the encryption and the decryption operations of RSAES-OAEP take - * the value of a label L as input. In this version of PKCS #1, L is - * the empty string; other uses of the label are outside the scope of - * this document. - * - * @access private - * @param String $c - * @param String $l - * @return String - */ - function _rsaes_oaep_decrypt($c, $l = '') - { - // Length checking - - // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error - // be output. - - if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) { - user_error('Decryption error'); - return false; - } - - // RSA decryption - - $c = $this->_os2ip($c); - $m = $this->_rsadp($c); - if ($m === false) { - user_error('Decryption error'); - return false; - } - $em = $this->_i2osp($m, $this->k); - - // EME-OAEP decoding - - $lHash = $this->hash->hash($l); - $y = ord($em[0]); - $maskedSeed = substr($em, 1, $this->hLen); - $maskedDB = substr($em, $this->hLen + 1); - $seedMask = $this->_mgf1($maskedDB, $this->hLen); - $seed = $maskedSeed ^ $seedMask; - $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); - $db = $maskedDB ^ $dbMask; - $lHash2 = substr($db, 0, $this->hLen); - $m = substr($db, $this->hLen); - if ($lHash != $lHash2) { - user_error('Decryption error'); - return false; - } - $m = ltrim($m, chr(0)); - if (ord($m[0]) != 1) { - user_error('Decryption error'); - return false; - } - - // Output the message M - - return substr($m, 1); - } - - /** - * RSAES-PKCS1-V1_5-ENCRYPT - * - * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}. - * - * @access private - * @param String $m - * @return String - */ - function _rsaes_pkcs1_v1_5_encrypt($m) - { - $mLen = strlen($m); - - // Length checking - - if ($mLen > $this->k - 11) { - user_error('Message too long'); - return false; - } - - // EME-PKCS1-v1_5 encoding - - $psLen = $this->k - $mLen - 3; - $ps = ''; - while (strlen($ps) != $psLen) { - $temp = crypt_random_string($psLen - strlen($ps)); - $temp = str_replace("\x00", '', $temp); - $ps.= $temp; - } - $type = 2; - // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done - if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) { - $type = 1; - // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF" - $ps = str_repeat("\xFF", $psLen); - } - $em = chr(0) . chr($type) . $ps . chr(0) . $m; - - // RSA encryption - $m = $this->_os2ip($em); - $c = $this->_rsaep($m); - $c = $this->_i2osp($c, $this->k); - - // Output the ciphertext C - - return $c; - } - - /** - * RSAES-PKCS1-V1_5-DECRYPT - * - * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}. - * - * For compatibility purposes, this function departs slightly from the description given in RFC3447. - * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the - * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the - * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed - * to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the - * second byte is 2 or less. If it is, we'll accept the decrypted string as valid. - * - * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt - * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but - * not private key encrypted ciphertext's. - * - * @access private - * @param String $c - * @return String - */ - function _rsaes_pkcs1_v1_5_decrypt($c) - { - // Length checking - - if (strlen($c) != $this->k) { // or if k < 11 - user_error('Decryption error'); - return false; - } - - // RSA decryption - - $c = $this->_os2ip($c); - $m = $this->_rsadp($c); - - if ($m === false) { - user_error('Decryption error'); - return false; - } - $em = $this->_i2osp($m, $this->k); - - // EME-PKCS1-v1_5 decoding - - if (ord($em[0]) != 0 || ord($em[1]) > 2) { - user_error('Decryption error'); - return false; - } - - $ps = substr($em, 2, strpos($em, chr(0), 2) - 2); - $m = substr($em, strlen($ps) + 3); - - if (strlen($ps) < 8) { - user_error('Decryption error'); - return false; - } - - // Output M - - return $m; - } - - /** - * EMSA-PSS-ENCODE - * - * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}. - * - * @access private - * @param String $m - * @param Integer $emBits - */ - function _emsa_pss_encode($m, $emBits) - { - // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error - // be output. - - $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8) - $sLen = $this->sLen == false ? $this->hLen : $this->sLen; - - $mHash = $this->hash->hash($m); - if ($emLen < $this->hLen + $sLen + 2) { - user_error('Encoding error'); - return false; - } - - $salt = crypt_random_string($sLen); - $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; - $h = $this->hash->hash($m2); - $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2); - $db = $ps . chr(1) . $salt; - $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); - $maskedDB = $db ^ $dbMask; - $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0]; - $em = $maskedDB . $h . chr(0xBC); - - return $em; - } - - /** - * EMSA-PSS-VERIFY - * - * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}. - * - * @access private - * @param String $m - * @param String $em - * @param Integer $emBits - * @return String - */ - function _emsa_pss_verify($m, $em, $emBits) - { - // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error - // be output. - - $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8); - $sLen = $this->sLen == false ? $this->hLen : $this->sLen; - - $mHash = $this->hash->hash($m); - if ($emLen < $this->hLen + $sLen + 2) { - return false; - } - - if ($em[strlen($em) - 1] != chr(0xBC)) { - return false; - } - - $maskedDB = substr($em, 0, -$this->hLen - 1); - $h = substr($em, -$this->hLen - 1, $this->hLen); - $temp = chr(0xFF << ($emBits & 7)); - if ((~$maskedDB[0] & $temp) != $temp) { - return false; - } - $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); - $db = $maskedDB ^ $dbMask; - $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0]; - $temp = $emLen - $this->hLen - $sLen - 2; - if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) { - return false; - } - $salt = substr($db, $temp + 1); // should be $sLen long - $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; - $h2 = $this->hash->hash($m2); - return $this->_equals($h, $h2); - } - - /** - * RSASSA-PSS-SIGN - * - * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}. - * - * @access private - * @param String $m - * @return String - */ - function _rsassa_pss_sign($m) - { - // EMSA-PSS encoding - - $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1); - - // RSA signature - - $m = $this->_os2ip($em); - $s = $this->_rsasp1($m); - $s = $this->_i2osp($s, $this->k); - - // Output the signature S - - return $s; - } - - /** - * RSASSA-PSS-VERIFY - * - * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}. - * - * @access private - * @param String $m - * @param String $s - * @return String - */ - function _rsassa_pss_verify($m, $s) - { - // Length checking - - if (strlen($s) != $this->k) { - user_error('Invalid signature'); - return false; - } - - // RSA verification - - $modBits = 8 * $this->k; - - $s2 = $this->_os2ip($s); - $m2 = $this->_rsavp1($s2); - if ($m2 === false) { - user_error('Invalid signature'); - return false; - } - $em = $this->_i2osp($m2, $modBits >> 3); - if ($em === false) { - user_error('Invalid signature'); - return false; - } - - // EMSA-PSS verification - - return $this->_emsa_pss_verify($m, $em, $modBits - 1); - } - - /** - * EMSA-PKCS1-V1_5-ENCODE - * - * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}. - * - * @access private - * @param String $m - * @param Integer $emLen - * @return String - */ - function _emsa_pkcs1_v1_5_encode($m, $emLen) - { - $h = $this->hash->hash($m); - if ($h === false) { - return false; - } - - // see http://tools.ietf.org/html/rfc3447#page-43 - switch ($this->hashName) { - case 'md2': - $t = pack('H*', '3020300c06082a864886f70d020205000410'); - break; - case 'md5': - $t = pack('H*', '3020300c06082a864886f70d020505000410'); - break; - case 'sha1': - $t = pack('H*', '3021300906052b0e03021a05000414'); - break; - case 'sha256': - $t = pack('H*', '3031300d060960864801650304020105000420'); - break; - case 'sha384': - $t = pack('H*', '3041300d060960864801650304020205000430'); - break; - case 'sha512': - $t = pack('H*', '3051300d060960864801650304020305000440'); - } - $t.= $h; - $tLen = strlen($t); - - if ($emLen < $tLen + 11) { - user_error('Intended encoded message length too short'); - return false; - } - - $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3); - - $em = "\0\1$ps\0$t"; - - return $em; - } - - /** - * RSASSA-PKCS1-V1_5-SIGN - * - * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}. - * - * @access private - * @param String $m - * @return String - */ - function _rsassa_pkcs1_v1_5_sign($m) - { - // EMSA-PKCS1-v1_5 encoding - - $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); - if ($em === false) { - user_error('RSA modulus too short'); - return false; - } - - // RSA signature - - $m = $this->_os2ip($em); - $s = $this->_rsasp1($m); - $s = $this->_i2osp($s, $this->k); - - // Output the signature S - - return $s; - } - - /** - * RSASSA-PKCS1-V1_5-VERIFY - * - * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}. - * - * @access private - * @param String $m - * @return String - */ - function _rsassa_pkcs1_v1_5_verify($m, $s) - { - // Length checking - - if (strlen($s) != $this->k) { - user_error('Invalid signature'); - return false; - } - - // RSA verification - - $s = $this->_os2ip($s); - $m2 = $this->_rsavp1($s); - if ($m2 === false) { - user_error('Invalid signature'); - return false; - } - $em = $this->_i2osp($m2, $this->k); - if ($em === false) { - user_error('Invalid signature'); - return false; - } - - // EMSA-PKCS1-v1_5 encoding - - $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); - if ($em2 === false) { - user_error('RSA modulus too short'); - return false; - } - - // Compare - return $this->_equals($em, $em2); - } - - /** - * Set Encryption Mode - * - * Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1. - * - * @access public - * @param Integer $mode - */ - function setEncryptionMode($mode) - { - $this->encryptionMode = $mode; - } - - /** - * Set Signature Mode - * - * Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1 - * - * @access public - * @param Integer $mode - */ - function setSignatureMode($mode) - { - $this->signatureMode = $mode; - } - - /** - * Set public key comment. - * - * @access public - * @param String $comment - */ - function setComment($comment) - { - $this->comment = $comment; - } - - /** - * Get public key comment. - * - * @access public - * @return String - */ - function getComment() - { - return $this->comment; - } - - /** - * Encryption - * - * Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be. - * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will - * be concatenated together. - * - * @see decrypt() - * @access public - * @param String $plaintext - * @return String - */ - function encrypt($plaintext) - { - switch ($this->encryptionMode) { - case CRYPT_RSA_ENCRYPTION_PKCS1: - $length = $this->k - 11; - if ($length <= 0) { - return false; - } - - $plaintext = str_split($plaintext, $length); - $ciphertext = ''; - foreach ($plaintext as $m) { - $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m); - } - return $ciphertext; - //case CRYPT_RSA_ENCRYPTION_OAEP: - default: - $length = $this->k - 2 * $this->hLen - 2; - if ($length <= 0) { - return false; - } - - $plaintext = str_split($plaintext, $length); - $ciphertext = ''; - foreach ($plaintext as $m) { - $ciphertext.= $this->_rsaes_oaep_encrypt($m); - } - return $ciphertext; - } - } - - /** - * Decryption - * - * @see encrypt() - * @access public - * @param String $plaintext - * @return String - */ - function decrypt($ciphertext) - { - if ($this->k <= 0) { - return false; - } - - $ciphertext = str_split($ciphertext, $this->k); - $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT); - - $plaintext = ''; - - switch ($this->encryptionMode) { - case CRYPT_RSA_ENCRYPTION_PKCS1: - $decrypt = '_rsaes_pkcs1_v1_5_decrypt'; - break; - //case CRYPT_RSA_ENCRYPTION_OAEP: - default: - $decrypt = '_rsaes_oaep_decrypt'; - } - - foreach ($ciphertext as $c) { - $temp = $this->$decrypt($c); - if ($temp === false) { - return false; - } - $plaintext.= $temp; - } - - return $plaintext; - } - - /** - * Create a signature - * - * @see verify() - * @access public - * @param String $message - * @return String - */ - function sign($message) - { - if (empty($this->modulus) || empty($this->exponent)) { - return false; - } - - switch ($this->signatureMode) { - case CRYPT_RSA_SIGNATURE_PKCS1: - return $this->_rsassa_pkcs1_v1_5_sign($message); - //case CRYPT_RSA_SIGNATURE_PSS: - default: - return $this->_rsassa_pss_sign($message); - } - } - - /** - * Verifies a signature - * - * @see sign() - * @access public - * @param String $message - * @param String $signature - * @return Boolean - */ - function verify($message, $signature) - { - if (empty($this->modulus) || empty($this->exponent)) { - return false; - } - - switch ($this->signatureMode) { - case CRYPT_RSA_SIGNATURE_PKCS1: - return $this->_rsassa_pkcs1_v1_5_verify($message, $signature); - //case CRYPT_RSA_SIGNATURE_PSS: - default: - return $this->_rsassa_pss_verify($message, $signature); - } - } - - /** - * Extract raw BER from Base64 encoding - * - * @access private - * @param String $str - * @return String - */ - function _extractBER($str) - { - /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them - * above and beyond the ceritificate. - * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line: - * - * Bag Attributes - * localKeyID: 01 00 00 00 - * subject=/O=organization/OU=org unit/CN=common name - * issuer=/O=organization/CN=common name - */ - $temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $str, 1); - // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff - $temp = preg_replace('#-+[^-]+-+#', '', $temp); - // remove new lines - $temp = str_replace(array("\r", "\n", ' '), '', $temp); - $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; - return $temp != false ? $temp : $str; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Random.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Random.php deleted file mode 100644 index 918b97bf..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Random.php +++ /dev/null @@ -1,300 +0,0 @@ - - * - * - * - * 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. - * - * @category Crypt - * @package Crypt_Random - * @author Jim Wigginton - * @copyright 2007 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -// laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently, -// have phpseclib as a requirement as well. if you're developing such a program you may encounter -// a "Cannot redeclare crypt_random_string()" error. -if (!function_exists('crypt_random_string')) { - /** - * "Is Windows" test - * - * @access private - */ - define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); - - /** - * Generate a random string. - * - * Although microoptimizations are generally discouraged as they impair readability this function is ripe with - * microoptimizations because this function has the potential of being called a huge number of times. - * eg. for RSA key generation. - * - * @param Integer $length - * @return String - * @access public - */ - function crypt_random_string($length) - { - if (CRYPT_RANDOM_IS_WINDOWS) { - // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call. - // ie. class_alias is a function that was introduced in PHP 5.3 - if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) { - return mcrypt_create_iv($length); - } - // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was, - // to quote , "possible blocking behavior". as of 5.3.4 - // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both - // call php_win32_get_random_bytes(): - // - // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008 - // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392 - // - // php_win32_get_random_bytes() is defined thusly: - // - // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80 - // - // we're calling it, all the same, in the off chance that the mcrypt extension is not available - if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) { - return openssl_random_pseudo_bytes($length); - } - } else { - // method 1. the fastest - if (function_exists('openssl_random_pseudo_bytes')) { - return openssl_random_pseudo_bytes($length); - } - // method 2 - static $fp = true; - if ($fp === true) { - // warning's will be output unles the error suppression operator is used. errors such as - // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc. - $fp = @fopen('/dev/urandom', 'rb'); - } - if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource() - return fread($fp, $length); - } - // method 3. pretty much does the same thing as method 2 per the following url: - // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391 - // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're - // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir - // restrictions or some such - if (function_exists('mcrypt_create_iv')) { - return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); - } - } - // at this point we have no choice but to use a pure-PHP CSPRNG - - // cascade entropy across multiple PHP instances by fixing the session and collecting all - // environmental variables, including the previous session data and the current session - // data. - // - // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively) - // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but - // PHP isn't low level to be able to use those as sources and on a web server there's not likely - // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use - // however, a ton of people visiting the website. obviously you don't want to base your seeding - // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled - // by the user and (2) this isn't just looking at the data sent by the current user - it's based - // on the data sent by all users. one user requests the page and a hash of their info is saved. - // another user visits the page and the serialization of their data is utilized along with the - // server envirnment stuff and a hash of the previous http request data (which itself utilizes - // a hash of the session data before that). certainly an attacker should be assumed to have - // full control over his own http requests. he, however, is not going to have control over - // everyone's http requests. - static $crypto = false, $v; - if ($crypto === false) { - // save old session data - $old_session_id = session_id(); - $old_use_cookies = ini_get('session.use_cookies'); - $old_session_cache_limiter = session_cache_limiter(); - $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false; - if ($old_session_id != '') { - session_write_close(); - } - - session_id(1); - ini_set('session.use_cookies', 0); - session_cache_limiter(''); - session_start(); - - $v = $seed = $_SESSION['seed'] = pack('H*', sha1( - serialize($_SERVER) . - serialize($_POST) . - serialize($_GET) . - serialize($_COOKIE) . - serialize($GLOBALS) . - serialize($_SESSION) . - serialize($_OLD_SESSION) - )); - if (!isset($_SESSION['count'])) { - $_SESSION['count'] = 0; - } - $_SESSION['count']++; - - session_write_close(); - - // restore old session data - if ($old_session_id != '') { - session_id($old_session_id); - session_start(); - ini_set('session.use_cookies', $old_use_cookies); - session_cache_limiter($old_session_cache_limiter); - } else { - if ($_OLD_SESSION !== false) { - $_SESSION = $_OLD_SESSION; - unset($_OLD_SESSION); - } else { - unset($_SESSION); - } - } - - // in SSH2 a shared secret and an exchange hash are generated through the key exchange process. - // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C. - // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the - // original hash and the current hash. we'll be emulating that. for more info see the following URL: - // - // http://tools.ietf.org/html/rfc4253#section-7.2 - // - // see the is_string($crypto) part for an example of how to expand the keys - $key = pack('H*', sha1($seed . 'A')); - $iv = pack('H*', sha1($seed . 'C')); - - // ciphers are used as per the nist.gov link below. also, see this link: - // - // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives - switch (true) { - case phpseclib_resolve_include_path('Crypt/AES.php'): - if (!class_exists('Crypt_AES')) { - include_once 'AES.php'; - } - $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); - break; - case phpseclib_resolve_include_path('Crypt/Twofish.php'): - if (!class_exists('Crypt_Twofish')) { - include_once 'Twofish.php'; - } - $crypto = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); - break; - case phpseclib_resolve_include_path('Crypt/Blowfish.php'): - if (!class_exists('Crypt_Blowfish')) { - include_once 'Blowfish.php'; - } - $crypto = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); - break; - case phpseclib_resolve_include_path('Crypt/TripleDES.php'): - if (!class_exists('Crypt_TripleDES')) { - include_once 'TripleDES.php'; - } - $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); - break; - case phpseclib_resolve_include_path('Crypt/DES.php'): - if (!class_exists('Crypt_DES')) { - include_once 'DES.php'; - } - $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); - break; - case phpseclib_resolve_include_path('Crypt/RC4.php'): - if (!class_exists('Crypt_RC4')) { - include_once 'RC4.php'; - } - $crypto = new Crypt_RC4(); - break; - default: - user_error('crypt_random_string requires at least one symmetric cipher be loaded'); - return false; - } - - $crypto->setKey($key); - $crypto->setIV($iv); - $crypto->enableContinuousBuffer(); - } - - //return $crypto->encrypt(str_repeat("\0", $length)); - - // the following is based off of ANSI X9.31: - // - // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf - // - // OpenSSL uses that same standard for it's random numbers: - // - // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c - // (do a search for "ANS X9.31 A.2.4") - $result = ''; - while (strlen($result) < $length) { - $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21 - $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20 - $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20 - $result.= $r; - } - return substr($result, 0, $length); - } -} - -if (!function_exists('phpseclib_resolve_include_path')) { - /** - * Resolve filename against the include path. - * - * Wrapper around stream_resolve_include_path() (which was introduced in - * PHP 5.3.2) with fallback implementation for earlier PHP versions. - * - * @param string $filename - * @return mixed Filename (string) on success, false otherwise. - * @access public - */ - function phpseclib_resolve_include_path($filename) - { - if (function_exists('stream_resolve_include_path')) { - return stream_resolve_include_path($filename); - } - - // handle non-relative paths - if (file_exists($filename)) { - return realpath($filename); - } - - $paths = PATH_SEPARATOR == ':' ? - preg_split('#(? - * setKey('abcdefghijklmnop'); - * - * $size = 10 * 1024; - * $plaintext = ''; - * for ($i = 0; $i < $size; $i++) { - * $plaintext.= 'a'; - * } - * - * echo $rijndael->decrypt($rijndael->encrypt($plaintext)); - * ?> - * - * - * 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. - * - * @category Crypt - * @package Crypt_Rijndael - * @author Jim Wigginton - * @copyright 2008 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Crypt_Base - * - * Base cipher class - */ -if (!class_exists('Crypt_Base')) { - include_once 'Base.php'; -} - -/**#@+ - * @access public - * @see Crypt_Rijndael::encrypt() - * @see Crypt_Rijndael::decrypt() - */ -/** - * Encrypt / decrypt using the Counter mode. - * - * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 - */ -define('CRYPT_RIJNDAEL_MODE_CTR', CRYPT_MODE_CTR); -/** - * Encrypt / decrypt using the Electronic Code Book mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 - */ -define('CRYPT_RIJNDAEL_MODE_ECB', CRYPT_MODE_ECB); -/** - * Encrypt / decrypt using the Code Book Chaining mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - */ -define('CRYPT_RIJNDAEL_MODE_CBC', CRYPT_MODE_CBC); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 - */ -define('CRYPT_RIJNDAEL_MODE_CFB', CRYPT_MODE_CFB); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 - */ -define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_Base::Crypt_Base() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_RIJNDAEL_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - -/** - * Pure-PHP implementation of Rijndael. - * - * @package Crypt_Rijndael - * @author Jim Wigginton - * @access public - */ -class Crypt_Rijndael extends Crypt_Base -{ - /** - * The default password key_size used by setPassword() - * - * @see Crypt_Base::password_key_size - * @see Crypt_Base::setPassword() - * @var Integer - * @access private - */ - var $password_key_size = 16; - - /** - * The namespace used by the cipher for its constants. - * - * @see Crypt_Base::const_namespace - * @var String - * @access private - */ - var $const_namespace = 'RIJNDAEL'; - - /** - * The mcrypt specific name of the cipher - * - * Mcrypt is useable for 128/192/256-bit $block_size/$key_size. For 160/224 not. - * Crypt_Rijndael determines automatically whether mcrypt is useable - * or not for the current $block_size/$key_size. - * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly. - * - * @see Crypt_Base::cipher_name_mcrypt - * @see Crypt_Base::engine - * @see _setupEngine() - * @var String - * @access private - */ - var $cipher_name_mcrypt = 'rijndael-128'; - - /** - * The default salt used by setPassword() - * - * @see Crypt_Base::password_default_salt - * @see Crypt_Base::setPassword() - * @var String - * @access private - */ - var $password_default_salt = 'phpseclib'; - - /** - * Has the key length explicitly been set or should it be derived from the key, itself? - * - * @see setKeyLength() - * @var Boolean - * @access private - */ - var $explicit_key_length = false; - - /** - * The Key Schedule - * - * @see _setup() - * @var Array - * @access private - */ - var $w; - - /** - * The Inverse Key Schedule - * - * @see _setup() - * @var Array - * @access private - */ - var $dw; - - /** - * The Block Length divided by 32 - * - * @see setBlockLength() - * @var Integer - * @access private - * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size - * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could - * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu - * of that, we'll just precompute it once. - * - */ - var $Nb = 4; - - /** - * The Key Length - * - * @see setKeyLength() - * @var Integer - * @access private - * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk - * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could - * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu - * of that, we'll just precompute it once. - */ - var $key_size = 16; - - /** - * The Key Length divided by 32 - * - * @see setKeyLength() - * @var Integer - * @access private - * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4 - */ - var $Nk = 4; - - /** - * The Number of Rounds - * - * @var Integer - * @access private - * @internal The max value is 14, the min value is 10. - */ - var $Nr; - - /** - * Shift offsets - * - * @var Array - * @access private - */ - var $c; - - /** - * Holds the last used key- and block_size information - * - * @var Array - * @access private - */ - var $kl; - - /** - * Precomputed mixColumns table - * - * According to (section 5.2.1), - * precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so - * those are the names we'll use. - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $t0 = array( - 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, - 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, - 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, - 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B, - 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, - 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, - 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5, - 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, - 0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, - 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497, - 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, - 0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, - 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594, - 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, - 0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, - 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D, - 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, - 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, - 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883, - 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, - 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, - 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B, - 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, - 0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, - 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651, - 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, - 0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, - 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9, - 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, - 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, - 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8, - 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A - ); - - /** - * Precomputed mixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $t1 = array( - 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, - 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676, - 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, - 0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, - 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC, - 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, - 0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, - 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575, - 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, - 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, - 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B, - 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, - 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, - 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8, - 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, - 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, - 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717, - 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, - 0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, - 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB, - 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, - 0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, - 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9, - 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, - 0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, - 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A, - 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, - 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, - 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494, - 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, - 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, - 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616 - ); - - /** - * Precomputed mixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $t2 = array( - 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, - 0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, - 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0, - 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, - 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, - 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15, - 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, - 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, - 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0, - 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, - 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, - 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF, - 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, - 0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, - 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5, - 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, - 0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, - 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673, - 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, - 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, - 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C, - 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, - 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, - 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008, - 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, - 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, - 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E, - 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, - 0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, - 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF, - 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, - 0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16 - ); - - /** - * Precomputed mixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $t3 = array( - 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, - 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, - 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, - 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, - 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, - 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, - 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, - 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, - 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, - 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, - 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, - 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, - 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, - 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, - 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, - 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, - 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, - 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, - 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, - 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, - 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, - 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, - 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, - 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, - 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, - 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, - 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, - 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, - 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, - 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, - 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, - 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C - ); - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $dt0 = array( - 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1, 0xACFA58AB, 0x4BE30393, - 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25, 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, - 0xDEB15A49, 0x25BA1B67, 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6, - 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3, 0x49E06929, 0x8EC9C844, - 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD, 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, - 0x63DF4A18, 0xE51A3182, 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94, - 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2, 0xE31F8F57, 0x6655AB2A, - 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, - 0x8ACF1C2B, 0xA779B492, 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A, - 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA, 0x5E719F06, 0xBD6E1051, - 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, - 0x1998FB24, 0xD6BDE997, 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB, - 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48, 0x1E1170AC, 0x6C5A724E, - 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927, 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, - 0x0C0A67B1, 0x9357E70F, 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16, - 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD, 0x2DB6A8B9, 0x141EA9C8, - 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD, 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, - 0x8B432976, 0xCB23C6DC, 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120, - 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3, 0x0D8652EC, 0x77C1E3D0, - 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422, 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, - 0x87494EC7, 0xD938D1C1, 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4, - 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8, 0x2E39F75E, 0x82C3AFF5, - 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, - 0xCD267809, 0x6E5918F4, 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6, - 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331, 0xC6A59430, 0x35A266C0, - 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, - 0x764DD68D, 0x43EFB04D, 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F, - 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252, 0xE9105633, 0x6DD64713, - 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89, 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, - 0x9CD2DF59, 0x55F2733F, 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86, - 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C, 0x283C498B, 0xFF0D9541, - 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190, 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742 - ); - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $dt1 = array( - 0x5051F4A7, 0x537E4165, 0xC31A17A4, 0x963A275E, 0xCB3BAB6B, 0xF11F9D45, 0xABACFA58, 0x934BE303, - 0x552030FA, 0xF6AD766D, 0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB, 0x80263544, 0x8FB562A3, - 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0, 0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9, - 0xE7038F5F, 0x9515929C, 0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421, 0x2949E069, 0x448EC9C8, - 0x6A75C289, 0x78F48E79, 0x6B99583E, 0xDD27B971, 0xB6BEE14F, 0x17F088AD, 0x66C920AC, 0xB47DCE3A, - 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F, 0xE0B16477, 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B, - 0x58704868, 0x198F45FD, 0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02, 0x57E31F8F, 0x2A6655AB, - 0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, 0xF2302887, 0xB223BFA5, 0xBA02036A, 0x5CED1682, - 0x2B8ACF1C, 0x92A779B4, 0xF0F307F2, 0xA14E69E2, 0xCD65DAF4, 0xD50605BE, 0x1FD13462, 0x8AC4A6FE, - 0x9D342E53, 0xA0A2F355, 0x32058AE1, 0x75A4F6EB, 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10, - 0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, 0xB591548D, 0x0571C45D, 0x6F0406D4, 0xFF605015, - 0x241998FB, 0x97D6BDE9, 0xCC894043, 0x7767D99E, 0xBDB0E842, 0x8807898B, 0x38E7195B, 0xDB79C8EE, - 0x47A17C0A, 0xE97C420F, 0xC9F8841E, 0x00000000, 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72, - 0xFBFD0EFF, 0x560F8538, 0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6, 0xD19B5B54, 0x3A24362E, - 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, 0x9E1B9B91, 0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A, - 0x0AE293BA, 0xE5C0A02A, 0x433C22E0, 0x1D121B17, 0x0B0E090D, 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9, - 0x8557F119, 0x4CAF7507, 0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5, 0xC544663B, 0x345BFB7E, - 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1, 0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611, - 0x7D854A24, 0xF8D2BB3D, 0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230, 0xEC0D8652, 0xD077C1E3, - 0x6C2BB316, 0x99A970B9, 0xFA119448, 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F, 0xD8567D2C, 0xEF223390, - 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B, 0xCFA6F581, 0x28A57ADE, 0x26DAB78E, 0xA43FADBF, - 0xE42C3A9D, 0x0D507892, 0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, 0xF582C3AF, - 0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, 0x3BC8AC99, 0xA710187D, 0x6EE89C63, 0x7BDB3BBB, - 0x09CD2678, 0xF46E5918, 0x01EC9AB7, 0xA8834F9A, 0x65E6956E, 0x7EAAFFE6, 0x0821BCCF, 0xE6EF15E8, - 0xD9BAE79B, 0xCE4A6F36, 0xD4EA9F09, 0xD629B07C, 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266, - 0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, 0x4AF10498, 0xF741ECDA, 0x0E7FCD50, 0x2F1791F6, - 0x8D764DD6, 0x4D43EFB0, 0x54CCAA4D, 0xDFE49604, 0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, 0x7F466551, - 0x049D5EEA, 0x5D018C35, 0x73FA8774, 0x2EFB0B41, 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647, - 0x8C9AD761, 0x7A37A10C, 0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9, 0xEDE11CE5, 0x3C7A47B1, - 0x599CD2DF, 0x3F55F273, 0x791814CE, 0xBF73C737, 0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB, - 0x81CAAFF3, 0x3EB968C4, 0x2C382434, 0x5FC2A340, 0x72161DC3, 0x0CBCE225, 0x8B283C49, 0x41FF0D95, - 0x7139A801, 0xDE080CB3, 0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6, 0x74486C5C, 0x42D0B857 - ); - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $dt2 = array( - 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27, 0x6BCB3BAB, 0x45F11F9D, 0x58ABACFA, 0x03934BE3, - 0xFA552030, 0x6DF6AD76, 0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, 0xA38FB562, - 0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, 0x7502C32F, 0xF012814C, 0x97A38D46, 0xF9C66BD3, - 0x5FE7038F, 0x9C951592, 0x7AEBBF6D, 0x59DA9552, 0x832DD4BE, 0x21D35874, 0x692949E0, 0xC8448EC9, - 0x896A75C2, 0x7978F48E, 0x3E6B9958, 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE, - 0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, 0x77E0B164, 0xAE84BB6B, 0xA01CFE81, 0x2B94F908, - 0x68587048, 0xFD198F45, 0x6C8794DE, 0xF8B7527B, 0xD323AB73, 0x02E2724B, 0x8F57E31F, 0xAB2A6655, - 0x2807B2EB, 0xC2032FB5, 0x7B9A86C5, 0x08A5D337, 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16, - 0x1C2B8ACF, 0xB492A779, 0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605, 0x621FD134, 0xFE8AC4A6, - 0x539D342E, 0x55A0A2F3, 0xE132058A, 0xEB75A4F6, 0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E, - 0x8AF93E21, 0x063D96DD, 0x05AEDD3E, 0xBD464DE6, 0x8DB59154, 0x5D0571C4, 0xD46F0406, 0x15FF6050, - 0xFB241998, 0xE997D6BD, 0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789, 0x5B38E719, 0xEEDB79C8, - 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000, 0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A, - 0xFFFBFD0E, 0x38560F85, 0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C, 0x54D19B5B, 0x2E3A2436, - 0x67B10C0A, 0xE70F9357, 0x96D2B4EE, 0x919E1B9B, 0xC54F80C0, 0x20A261DC, 0x4B695A77, 0x1A161C12, - 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B, 0x0D0B0E09, 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E, - 0x198557F1, 0x074CAF75, 0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72, 0x3BC54466, 0x7E345BFB, - 0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, 0xDCCAD731, 0x85104263, 0x22401397, 0x112084C6, - 0x247D854A, 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729, 0x2F4B1D9E, 0x30F3DCB2, 0x52EC0D86, 0xE3D077C1, - 0x166C2BB3, 0xB999A970, 0x48FA1194, 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233, - 0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, 0xDE28A57A, 0x8E26DAB7, 0xBFA43FAD, - 0x9DE42C3A, 0x920D5078, 0xCC9B6A5F, 0x4662547E, 0x13C2F68D, 0xB8E890D8, 0xF75E2E39, 0xAFF582C3, - 0x80BE9F5D, 0x937C69D0, 0x2DA96FD5, 0x12B3CF25, 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B, - 0x7809CD26, 0x18F46E59, 0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF, 0xCF0821BC, 0xE8E6EF15, - 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, 0x7CD629B0, 0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2, - 0xBC37744E, 0xCAA6FC82, 0xD0B0E090, 0xD81533A7, 0x984AF104, 0xDAF741EC, 0x500E7FCD, 0xF62F1791, - 0xD68D764D, 0xB04D43EF, 0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A, 0x1FB8C12C, 0x517F4665, - 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B, 0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6, - 0x618C9AD7, 0x0C7A37A1, 0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761, 0xE5EDE11C, 0xB13C7A47, - 0xDF599CD2, 0x733F55F2, 0xCE791814, 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD, 0x6F14DF3D, 0xDB867844, - 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3, 0xC372161D, 0x250CBCE2, 0x498B283C, 0x9541FF0D, - 0x017139A8, 0xB3DE080C, 0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532, 0x5C74486C, 0x5742D0B8 - ); - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $dt3 = array( - 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, - 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, - 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, - 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, - 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, - 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, - 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, - 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, - 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, - 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, - 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, - 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, - 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, - 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, - 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, - 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, - 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, - 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, - 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, - 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, - 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, - 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, - 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, - 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, - 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, - 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, - 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, - 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, - 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, - 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, - 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, - 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 - ); - - /** - * The SubByte S-Box - * - * @see Crypt_Rijndael::_encryptBlock() - * @var Array - * @access private - */ - var $sbox = array( - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 - ); - - /** - * The inverse SubByte S-Box - * - * @see Crypt_Rijndael::_decryptBlock() - * @var Array - * @access private - */ - var $isbox = array( - 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, - 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, - 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, - 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, - 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, - 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, - 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, - 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, - 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, - 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, - 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, - 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, - 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, - 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, - 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D - ); - - /** - * Sets the key. - * - * Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and - * whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length - * up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the - * excess bits. - * - * If the key is not explicitly set, it'll be assumed to be all null bytes. - * - * Note: 160/224-bit keys must explicitly set by setKeyLength(), otherwise they will be round/pad up to 192/256 bits. - * - * @see Crypt_Base:setKey() - * @see setKeyLength() - * @access public - * @param String $key - */ - function setKey($key) - { - parent::setKey($key); - - if (!$this->explicit_key_length) { - $length = strlen($key); - switch (true) { - case $length <= 16: - $this->key_size = 16; - break; - case $length <= 20: - $this->key_size = 20; - break; - case $length <= 24: - $this->key_size = 24; - break; - case $length <= 28: - $this->key_size = 28; - break; - default: - $this->key_size = 32; - } - $this->_setupEngine(); - } - } - - /** - * Sets the key length - * - * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to - * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. - * - * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined - * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to - * 192/256 bits as, for example, mcrypt will do. - * - * That said, if you want be compatible with other Rijndael and AES implementations, - * you should not setKeyLength(160) or setKeyLength(224). - * - * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use - * the mcrypt php extension, even if available. - * This results then in slower encryption. - * - * @access public - * @param Integer $length - */ - function setKeyLength($length) - { - switch (true) { - case $length == 160: - $this->key_size = 20; - break; - case $length == 224: - $this->key_size = 28; - break; - case $length <= 128: - $this->key_size = 16; - break; - case $length <= 192: - $this->key_size = 24; - break; - default: - $this->key_size = 32; - } - - $this->explicit_key_length = true; - $this->changed = true; - $this->_setupEngine(); - } - - /** - * Sets the block length - * - * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to - * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. - * - * @access public - * @param Integer $length - */ - function setBlockLength($length) - { - $length >>= 5; - if ($length > 8) { - $length = 8; - } else if ($length < 4) { - $length = 4; - } - $this->Nb = $length; - $this->block_size = $length << 2; - $this->changed = true; - $this->_setupEngine(); - } - - /** - * Setup the fastest possible $engine - * - * Determines if the mcrypt (MODE_MCRYPT) $engine available - * and usable for the current $block_size and $key_size. - * - * If not, the slower MODE_INTERNAL $engine will be set. - * - * @see setKey() - * @see setKeyLength() - * @see setBlockLength() - * @access private - */ - function _setupEngine() - { - if (constant('CRYPT_' . $this->const_namespace . '_MODE') == CRYPT_MODE_INTERNAL) { - // No mcrypt support at all for rijndael - return; - } - - // The required mcrypt module name for the current $block_size of rijndael - $cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3); - - // Determining the availibility/usability of $cipher_name_mcrypt - switch (true) { - case $this->key_size % 8: // mcrypt is not usable for 160/224-bit keys, only for 128/192/256-bit keys - case !in_array($cipher_name_mcrypt, mcrypt_list_algorithms()): // $cipher_name_mcrypt is not available for the current $block_size - $engine = CRYPT_MODE_INTERNAL; - break; - default: - $engine = CRYPT_MODE_MCRYPT; - } - - if ($this->engine == $engine && $this->cipher_name_mcrypt == $cipher_name_mcrypt) { - // allready set, so we not unnecessary close $this->enmcrypt/demcrypt/ecb - return; - } - - // Set the $engine - $this->engine = $engine; - $this->cipher_name_mcrypt = $cipher_name_mcrypt; - - if ($this->enmcrypt) { - // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed, - // (re)open them with the module named in $this->cipher_name_mcrypt - mcrypt_module_close($this->enmcrypt); - mcrypt_module_close($this->demcrypt); - $this->enmcrypt = null; - $this->demcrypt = null; - - if ($this->ecb) { - mcrypt_module_close($this->ecb); - $this->ecb = null; - } - } - } - - /** - * Setup the CRYPT_MODE_MCRYPT $engine - * - * @see Crypt_Base::_setupMcrypt() - * @access private - */ - function _setupMcrypt() - { - $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0"); - parent::_setupMcrypt(); - } - - /** - * Encrypts a block - * - * @access private - * @param String $in - * @return String - */ - function _encryptBlock($in) - { - static $t0, $t1, $t2, $t3, $sbox; - if (!$t0) { - for ($i = 0; $i < 256; ++$i) { - $t0[] = (int)$this->t0[$i]; - $t1[] = (int)$this->t1[$i]; - $t2[] = (int)$this->t2[$i]; - $t3[] = (int)$this->t3[$i]; - $sbox[] = (int)$this->sbox[$i]; - } - } - - $state = array(); - $words = unpack('N*', $in); - - $c = $this->c; - $w = $this->w; - $Nb = $this->Nb; - $Nr = $this->Nr; - - // addRoundKey - $i = -1; - foreach ($words as $word) { - $state[] = $word ^ $w[0][++$i]; - } - - // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - - // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding - // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf. - // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization. - // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1], - // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well. - - // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf - $temp = array(); - for ($round = 1; $round < $Nr; ++$round) { - $i = 0; // $c[0] == 0 - $j = $c[1]; - $k = $c[2]; - $l = $c[3]; - - while ($i < $Nb) { - $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^ - $t1[$state[$j] >> 16 & 0x000000FF] ^ - $t2[$state[$k] >> 8 & 0x000000FF] ^ - $t3[$state[$l] & 0x000000FF] ^ - $w[$round][$i]; - ++$i; - $j = ($j + 1) % $Nb; - $k = ($k + 1) % $Nb; - $l = ($l + 1) % $Nb; - } - $state = $temp; - } - - // subWord - for ($i = 0; $i < $Nb; ++$i) { - $state[$i] = $sbox[$state[$i] & 0x000000FF] | - ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) | - ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) | - ($sbox[$state[$i] >> 24 & 0x000000FF] << 24); - } - - // shiftRows + addRoundKey - $i = 0; // $c[0] == 0 - $j = $c[1]; - $k = $c[2]; - $l = $c[3]; - while ($i < $Nb) { - $temp[$i] = ($state[$i] & 0xFF000000) ^ - ($state[$j] & 0x00FF0000) ^ - ($state[$k] & 0x0000FF00) ^ - ($state[$l] & 0x000000FF) ^ - $w[$Nr][$i]; - ++$i; - $j = ($j + 1) % $Nb; - $k = ($k + 1) % $Nb; - $l = ($l + 1) % $Nb; - } - - switch ($Nb) { - case 8: - return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); - case 7: - return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]); - case 6: - return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]); - case 5: - return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]); - default: - return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); - } - } - - /** - * Decrypts a block - * - * @access private - * @param String $in - * @return String - */ - function _decryptBlock($in) - { - static $dt0, $dt1, $dt2, $dt3, $isbox; - if (!$dt0) { - for ($i = 0; $i < 256; ++$i) { - $dt0[] = (int)$this->dt0[$i]; - $dt1[] = (int)$this->dt1[$i]; - $dt2[] = (int)$this->dt2[$i]; - $dt3[] = (int)$this->dt3[$i]; - $isbox[] = (int)$this->isbox[$i]; - } - } - - $state = array(); - $words = unpack('N*', $in); - - $c = $this->c; - $dw = $this->dw; - $Nb = $this->Nb; - $Nr = $this->Nr; - - // addRoundKey - $i = -1; - foreach ($words as $word) { - $state[] = $word ^ $dw[$Nr][++$i]; - } - - $temp = array(); - for ($round = $Nr - 1; $round > 0; --$round) { - $i = 0; // $c[0] == 0 - $j = $Nb - $c[1]; - $k = $Nb - $c[2]; - $l = $Nb - $c[3]; - - while ($i < $Nb) { - $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^ - $dt1[$state[$j] >> 16 & 0x000000FF] ^ - $dt2[$state[$k] >> 8 & 0x000000FF] ^ - $dt3[$state[$l] & 0x000000FF] ^ - $dw[$round][$i]; - ++$i; - $j = ($j + 1) % $Nb; - $k = ($k + 1) % $Nb; - $l = ($l + 1) % $Nb; - } - $state = $temp; - } - - // invShiftRows + invSubWord + addRoundKey - $i = 0; // $c[0] == 0 - $j = $Nb - $c[1]; - $k = $Nb - $c[2]; - $l = $Nb - $c[3]; - - while ($i < $Nb) { - $word = ($state[$i] & 0xFF000000) | - ($state[$j] & 0x00FF0000) | - ($state[$k] & 0x0000FF00) | - ($state[$l] & 0x000000FF); - - $temp[$i] = $dw[0][$i] ^ ($isbox[$word & 0x000000FF] | - ($isbox[$word >> 8 & 0x000000FF] << 8) | - ($isbox[$word >> 16 & 0x000000FF] << 16) | - ($isbox[$word >> 24 & 0x000000FF] << 24)); - ++$i; - $j = ($j + 1) % $Nb; - $k = ($k + 1) % $Nb; - $l = ($l + 1) % $Nb; - } - - switch ($Nb) { - case 8: - return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); - case 7: - return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]); - case 6: - return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]); - case 5: - return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]); - default: - return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); - } - } - - /** - * Setup the key (expansion) - * - * @see Crypt_Base::_setupKey() - * @access private - */ - function _setupKey() - { - // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field. - // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse - static $rcon = array(0, - 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, - 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, - 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000, - 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000, - 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000, - 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 - ); - - $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0"); - - if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_size === $this->kl['key_size'] && $this->block_size === $this->kl['block_size']) { - // already expanded - return; - } - $this->kl = array('key' => $this->key, 'key_size' => $this->key_size, 'block_size' => $this->block_size); - - $this->Nk = $this->key_size >> 2; - // see Rijndael-ammended.pdf#page=44 - $this->Nr = max($this->Nk, $this->Nb) + 6; - - // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44, - // "Table 8: Shift offsets in Shiftrow for the alternative block lengths" - // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14, - // "Table 2: Shift offsets for different block lengths" - switch ($this->Nb) { - case 4: - case 5: - case 6: - $this->c = array(0, 1, 2, 3); - break; - case 7: - $this->c = array(0, 1, 2, 4); - break; - case 8: - $this->c = array(0, 1, 3, 4); - } - - $w = array_values(unpack('N*words', $this->key)); - - $length = $this->Nb * ($this->Nr + 1); - for ($i = $this->Nk; $i < $length; $i++) { - $temp = $w[$i - 1]; - if ($i % $this->Nk == 0) { - // according to , "the size of an integer is platform-dependent". - // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine, - // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and' - // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is. - $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord - $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk]; - } else if ($this->Nk > 6 && $i % $this->Nk == 4) { - $temp = $this->_subWord($temp); - } - $w[$i] = $w[$i - $this->Nk] ^ $temp; - } - - // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns - // and generate the inverse key schedule. more specifically, - // according to (section 5.3.3), - // "The key expansion for the Inverse Cipher is defined as follows: - // 1. Apply the Key Expansion. - // 2. Apply InvMixColumn to all Round Keys except the first and the last one." - // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher" - $temp = $this->w = $this->dw = array(); - for ($i = $row = $col = 0; $i < $length; $i++, $col++) { - if ($col == $this->Nb) { - if ($row == 0) { - $this->dw[0] = $this->w[0]; - } else { - // subWord + invMixColumn + invSubWord = invMixColumn - $j = 0; - while ($j < $this->Nb) { - $dw = $this->_subWord($this->w[$row][$j]); - $temp[$j] = $this->dt0[$dw >> 24 & 0x000000FF] ^ - $this->dt1[$dw >> 16 & 0x000000FF] ^ - $this->dt2[$dw >> 8 & 0x000000FF] ^ - $this->dt3[$dw & 0x000000FF]; - $j++; - } - $this->dw[$row] = $temp; - } - - $col = 0; - $row++; - } - $this->w[$row][$col] = $w[$i]; - } - - $this->dw[$row] = $this->w[$row]; - - // In case of $this->use_inline_crypt === true we have to use 1-dim key arrays (both ascending) - if ($this->use_inline_crypt) { - $this->dw = array_reverse($this->dw); - $w = array_pop($this->w); - $dw = array_pop($this->dw); - foreach ($this->w as $r => $wr) { - foreach ($wr as $c => $wc) { - $w[] = $wc; - $dw[] = $this->dw[$r][$c]; - } - } - $this->w = $w; - $this->dw = $dw; - } - } - - /** - * Performs S-Box substitutions - * - * @access private - * @param Integer $word - */ - function _subWord($word) - { - $sbox = $this->sbox; - - return $sbox[$word & 0x000000FF] | - ($sbox[$word >> 8 & 0x000000FF] << 8) | - ($sbox[$word >> 16 & 0x000000FF] << 16) | - ($sbox[$word >> 24 & 0x000000FF] << 24); - } - - /** - * Setup the performance-optimized function for de/encrypt() - * - * @see Crypt_Base::_setupInlineCrypt() - * @access private - */ - function _setupInlineCrypt() - { - // Note: _setupInlineCrypt() will be called only if $this->changed === true - // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt(). - // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible. - - $lambda_functions =& Crypt_Rijndael::_getLambdaFunctions(); - - // The first 10 generated $lambda_functions will use the key-words hardcoded for better performance. - // For memory reason we limit those ultra-optimized functions. - // After that, we use pure (extracted) integer vars for the key-words which is faster than accessing them via array. - if (count($lambda_functions) < 10) { - $w = $this->w; - $dw = $this->dw; - $init_encrypt = ''; - $init_decrypt = ''; - } else { - for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) { - $w[] = '$w[' . $i . ']'; - $dw[] = '$dw[' . $i . ']'; - } - $init_encrypt = '$w = $self->w;'; - $init_decrypt = '$dw = $self->dw;'; - } - - $code_hash = md5(str_pad("Crypt_Rijndael, {$this->mode}, {$this->block_size}, ", 32, "\0") . implode(',', $w)); - - if (!isset($lambda_functions[$code_hash])) { - $Nr = $this->Nr; - $Nb = $this->Nb; - $c = $this->c; - - // Generating encrypt code: - $init_encrypt.= ' - static $t0, $t1, $t2, $t3, $sbox; - if (!$t0) { - for ($i = 0; $i < 256; ++$i) { - $t0[$i] = (int)$self->t0[$i]; - $t1[$i] = (int)$self->t1[$i]; - $t2[$i] = (int)$self->t2[$i]; - $t3[$i] = (int)$self->t3[$i]; - $sbox[$i] = (int)$self->sbox[$i]; - } - } - '; - - $s = 'e'; - $e = 's'; - $wc = $Nb - 1; - - // Preround: addRoundKey - $encrypt_block = '$in = unpack("N*", $in);'."\n"; - for ($i = 0; $i < $Nb; ++$i) { - $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n"; - } - - // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey - for ($round = 1; $round < $Nr; ++$round) { - list($s, $e) = array($e, $s); - for ($i = 0; $i < $Nb; ++$i) { - $encrypt_block.= - '$'.$e.$i.' = - $t0[($'.$s.$i .' >> 24) & 0xff] ^ - $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^ - $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^ - $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^ - '.$w[++$wc].";\n"; - } - } - - // Finalround: subWord + shiftRows + addRoundKey - for ($i = 0; $i < $Nb; ++$i) { - $encrypt_block.= - '$'.$e.$i.' = - $sbox[ $'.$e.$i.' & 0xff] | - ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) | - ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) | - ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; - } - $encrypt_block .= '$in = pack("N*"'."\n"; - for ($i = 0; $i < $Nb; ++$i) { - $encrypt_block.= ', - ($'.$e.$i .' & 0xFF000000) ^ - ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000) ^ - ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00) ^ - ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF) ^ - '.$w[$i]."\n"; - } - $encrypt_block .= ');'; - - // Generating decrypt code: - $init_decrypt.= ' - static $dt0, $dt1, $dt2, $dt3, $isbox; - if (!$dt0) { - for ($i = 0; $i < 256; ++$i) { - $dt0[$i] = (int)$self->dt0[$i]; - $dt1[$i] = (int)$self->dt1[$i]; - $dt2[$i] = (int)$self->dt2[$i]; - $dt3[$i] = (int)$self->dt3[$i]; - $isbox[$i] = (int)$self->isbox[$i]; - } - } - '; - - $s = 'e'; - $e = 's'; - $wc = $Nb - 1; - - // Preround: addRoundKey - $decrypt_block = '$in = unpack("N*", $in);'."\n"; - for ($i = 0; $i < $Nb; ++$i) { - $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n"; - } - - // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey - for ($round = 1; $round < $Nr; ++$round) { - list($s, $e) = array($e, $s); - for ($i = 0; $i < $Nb; ++$i) { - $decrypt_block.= - '$'.$e.$i.' = - $dt0[($'.$s.$i .' >> 24) & 0xff] ^ - $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^ - $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^ - $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^ - '.$dw[++$wc].";\n"; - } - } - - // Finalround: subWord + shiftRows + addRoundKey - for ($i = 0; $i < $Nb; ++$i) { - $decrypt_block.= - '$'.$e.$i.' = - $isbox[ $'.$e.$i.' & 0xff] | - ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) | - ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) | - ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; - } - $decrypt_block .= '$in = pack("N*"'."\n"; - for ($i = 0; $i < $Nb; ++$i) { - $decrypt_block.= ', - ($'.$e.$i. ' & 0xFF000000) ^ - ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000) ^ - ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00) ^ - ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF) ^ - '.$dw[$i]."\n"; - } - $decrypt_block .= ');'; - - $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( - array( - 'init_crypt' => '', - 'init_encrypt' => $init_encrypt, - 'init_decrypt' => $init_decrypt, - 'encrypt_block' => $encrypt_block, - 'decrypt_block' => $decrypt_block - ) - ); - } - $this->inline_crypt = $lambda_functions[$code_hash]; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/TripleDES.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/TripleDES.php deleted file mode 100644 index 06ea09b1..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/TripleDES.php +++ /dev/null @@ -1,428 +0,0 @@ - - * setKey('abcdefghijklmnopqrstuvwx'); - * - * $size = 10 * 1024; - * $plaintext = ''; - * for ($i = 0; $i < $size; $i++) { - * $plaintext.= 'a'; - * } - * - * echo $des->decrypt($des->encrypt($plaintext)); - * ?> - * - * - * 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. - * - * @category Crypt - * @package Crypt_TripleDES - * @author Jim Wigginton - * @copyright 2007 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Crypt_DES - */ -if (!class_exists('Crypt_DES')) { - include_once 'DES.php'; -} - -/** - * Encrypt / decrypt using inner chaining - * - * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3). - */ -define('CRYPT_DES_MODE_3CBC', -2); - -/** - * Encrypt / decrypt using outer chaining - * - * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC. - */ -define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC); - -/** - * Pure-PHP implementation of Triple DES. - * - * @package Crypt_TripleDES - * @author Jim Wigginton - * @access public - */ -class Crypt_TripleDES extends Crypt_DES -{ - /** - * The default password key_size used by setPassword() - * - * @see Crypt_DES::password_key_size - * @see Crypt_Base::password_key_size - * @see Crypt_Base::setPassword() - * @var Integer - * @access private - */ - var $password_key_size = 24; - - /** - * The default salt used by setPassword() - * - * @see Crypt_Base::password_default_salt - * @see Crypt_Base::setPassword() - * @var String - * @access private - */ - var $password_default_salt = 'phpseclib'; - - /** - * The namespace used by the cipher for its constants. - * - * @see Crypt_DES::const_namespace - * @see Crypt_Base::const_namespace - * @var String - * @access private - */ - var $const_namespace = 'DES'; - - /** - * The mcrypt specific name of the cipher - * - * @see Crypt_DES::cipher_name_mcrypt - * @see Crypt_Base::cipher_name_mcrypt - * @var String - * @access private - */ - var $cipher_name_mcrypt = 'tripledes'; - - /** - * Optimizing value while CFB-encrypting - * - * @see Crypt_Base::cfb_init_len - * @var Integer - * @access private - */ - var $cfb_init_len = 750; - - /** - * max possible size of $key - * - * @see Crypt_TripleDES::setKey() - * @see Crypt_DES::setKey() - * @var String - * @access private - */ - var $key_size_max = 24; - - /** - * Internal flag whether using CRYPT_DES_MODE_3CBC or not - * - * @var Boolean - * @access private - */ - var $mode_3cbc; - - /** - * The Crypt_DES objects - * - * Used only if $mode_3cbc === true - * - * @var Array - * @access private - */ - var $des; - - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. - * - * $mode could be: - * - * - CRYPT_DES_MODE_ECB - * - * - CRYPT_DES_MODE_CBC - * - * - CRYPT_DES_MODE_CTR - * - * - CRYPT_DES_MODE_CFB - * - * - CRYPT_DES_MODE_OFB - * - * - CRYPT_DES_MODE_3CBC - * - * If not explicitly set, CRYPT_DES_MODE_CBC will be used. - * - * @see Crypt_DES::Crypt_DES() - * @see Crypt_Base::Crypt_Base() - * @param optional Integer $mode - * @access public - */ - function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC) - { - switch ($mode) { - // In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC - // and additional flag us internally as 3CBC - case CRYPT_DES_MODE_3CBC: - parent::Crypt_Base(CRYPT_DES_MODE_CBC); - $this->mode_3cbc = true; - - // This three $des'es will do the 3CBC work (if $key > 64bits) - $this->des = array( - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC), - ); - - // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects - $this->des[0]->disablePadding(); - $this->des[1]->disablePadding(); - $this->des[2]->disablePadding(); - break; - // If not 3CBC, we init as usual - default: - parent::Crypt_Base($mode); - } - } - - /** - * Sets the initialization vector. (optional) - * - * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explicitly set, it'll be assumed - * to be all zero's. - * - * @see Crypt_Base::setIV() - * @access public - * @param String $iv - */ - function setIV($iv) - { - parent::setIV($iv); - if ($this->mode_3cbc) { - $this->des[0]->setIV($iv); - $this->des[1]->setIV($iv); - $this->des[2]->setIV($iv); - } - } - - /** - * Sets the key. - * - * Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or - * 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate. - * - * DES also requires that every eighth bit be a parity bit, however, we'll ignore that. - * - * If the key is not explicitly set, it'll be assumed to be all null bytes. - * - * @access public - * @see Crypt_DES::setKey() - * @see Crypt_Base::setKey() - * @param String $key - */ - function setKey($key) - { - $length = strlen($key); - if ($length > 8) { - $key = str_pad(substr($key, 0, 24), 24, chr(0)); - // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this: - // http://php.net/function.mcrypt-encrypt#47973 - //$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24); - } else { - $key = str_pad($key, 8, chr(0)); - } - parent::setKey($key); - - // And in case of CRYPT_DES_MODE_3CBC: - // if key <= 64bits we not need the 3 $des to work, - // because we will then act as regular DES-CBC with just a <= 64bit key. - // So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des. - if ($this->mode_3cbc && $length > 8) { - $this->des[0]->setKey(substr($key, 0, 8)); - $this->des[1]->setKey(substr($key, 8, 8)); - $this->des[2]->setKey(substr($key, 16, 8)); - } - } - - /** - * Encrypts a message. - * - * @see Crypt_Base::encrypt() - * @access public - * @param String $plaintext - * @return String $cipertext - */ - function encrypt($plaintext) - { - // parent::en/decrypt() is able to do all the work for all modes and keylengths, - // except for: CRYPT_DES_MODE_3CBC (inner chaining CBC) with a key > 64bits - - // if the key is smaller then 8, do what we'd normally do - if ($this->mode_3cbc && strlen($this->key) > 8) { - return $this->des[2]->encrypt( - $this->des[1]->decrypt( - $this->des[0]->encrypt( - $this->_pad($plaintext) - ) - ) - ); - } - - return parent::encrypt($plaintext); - } - - /** - * Decrypts a message. - * - * @see Crypt_Base::decrypt() - * @access public - * @param String $ciphertext - * @return String $plaintext - */ - function decrypt($ciphertext) - { - if ($this->mode_3cbc && strlen($this->key) > 8) { - return $this->_unpad( - $this->des[0]->decrypt( - $this->des[1]->encrypt( - $this->des[2]->decrypt( - str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0") - ) - ) - ) - ); - } - - return parent::decrypt($ciphertext); - } - - /** - * Treat consecutive "packets" as if they are a continuous buffer. - * - * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets - * will yield different outputs: - * - * - * echo $des->encrypt(substr($plaintext, 0, 8)); - * echo $des->encrypt(substr($plaintext, 8, 8)); - * - * - * echo $des->encrypt($plaintext); - * - * - * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates - * another, as demonstrated with the following: - * - * - * $des->encrypt(substr($plaintext, 0, 8)); - * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different - * outputs. The reason is due to the fact that the initialization vector's change after every encryption / - * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. - * - * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each - * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that - * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), - * however, they are also less intuitive and more likely to cause you problems. - * - * @see Crypt_Base::enableContinuousBuffer() - * @see Crypt_TripleDES::disableContinuousBuffer() - * @access public - */ - function enableContinuousBuffer() - { - parent::enableContinuousBuffer(); - if ($this->mode_3cbc) { - $this->des[0]->enableContinuousBuffer(); - $this->des[1]->enableContinuousBuffer(); - $this->des[2]->enableContinuousBuffer(); - } - } - - /** - * Treat consecutive packets as if they are a discontinuous buffer. - * - * The default behavior. - * - * @see Crypt_Base::disableContinuousBuffer() - * @see Crypt_TripleDES::enableContinuousBuffer() - * @access public - */ - function disableContinuousBuffer() - { - parent::disableContinuousBuffer(); - if ($this->mode_3cbc) { - $this->des[0]->disableContinuousBuffer(); - $this->des[1]->disableContinuousBuffer(); - $this->des[2]->disableContinuousBuffer(); - } - } - - /** - * Creates the key schedule - * - * @see Crypt_DES::_setupKey() - * @see Crypt_Base::_setupKey() - * @access private - */ - function _setupKey() - { - switch (true) { - // if $key <= 64bits we configure our internal pure-php cipher engine - // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same. - case strlen($this->key) <= 8: - $this->des_rounds = 1; - break; - - // otherwise, if $key > 64bits, we configure our engine to work as 3DES. - default: - $this->des_rounds = 3; - - // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately. - if ($this->mode_3cbc) { - $this->des[0]->_setupKey(); - $this->des[1]->_setupKey(); - $this->des[2]->_setupKey(); - - // because $des[0-2] will, now, do all the work we can return here - // not need unnecessary stress parent::_setupKey() with our, now unused, $key. - return; - } - } - // setup our key - parent::_setupKey(); - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Twofish.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Twofish.php deleted file mode 100644 index 8dd7933a..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Twofish.php +++ /dev/null @@ -1,895 +0,0 @@ - - * setKey('12345678901234567890123456789012'); - * - * $plaintext = str_repeat('a', 1024); - * - * echo $twofish->decrypt($twofish->encrypt($plaintext)); - * ?> - * - * - * 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. - * - * @category Crypt - * @package Crypt_Twofish - * @author Jim Wigginton - * @author Hans-Juergen Petrich - * @copyright 2007 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Crypt_Base - * - * Base cipher class - */ -if (!class_exists('Crypt_Base')) { - include_once 'Base.php'; -} - -/**#@+ - * @access public - * @see Crypt_Twofish::encrypt() - * @see Crypt_Twofish::decrypt() - */ -/** - * Encrypt / decrypt using the Counter mode. - * - * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 - */ -define('CRYPT_TWOFISH_MODE_CTR', CRYPT_MODE_CTR); -/** - * Encrypt / decrypt using the Electronic Code Book mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 - */ -define('CRYPT_TWOFISH_MODE_ECB', CRYPT_MODE_ECB); -/** - * Encrypt / decrypt using the Code Book Chaining mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - */ -define('CRYPT_TWOFISH_MODE_CBC', CRYPT_MODE_CBC); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 - */ -define('CRYPT_TWOFISH_MODE_CFB', CRYPT_MODE_CFB); -/** - * Encrypt / decrypt using the Cipher Feedback mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 - */ -define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_Base::Crypt_Base() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_TWOFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_TWOFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - -/** - * Pure-PHP implementation of Twofish. - * - * @package Crypt_Twofish - * @author Jim Wigginton - * @author Hans-Juergen Petrich - * @access public - */ -class Crypt_Twofish extends Crypt_Base -{ - /** - * The namespace used by the cipher for its constants. - * - * @see Crypt_Base::const_namespace - * @var String - * @access private - */ - var $const_namespace = 'TWOFISH'; - - /** - * The mcrypt specific name of the cipher - * - * @see Crypt_Base::cipher_name_mcrypt - * @var String - * @access private - */ - var $cipher_name_mcrypt = 'twofish'; - - /** - * Optimizing value while CFB-encrypting - * - * @see Crypt_Base::cfb_init_len - * @var Integer - * @access private - */ - var $cfb_init_len = 800; - - /** - * Q-Table - * - * @var Array - * @access private - */ - var $q0 = array ( - 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, - 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, - 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, - 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, - 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, - 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, - 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, - 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, - 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, - 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, - 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, - 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, - 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, - 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, - 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, - 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, - 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, - 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, - 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, - 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, - 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, - 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, - 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, - 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, - 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, - 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, - 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, - 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, - 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, - 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, - 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, - 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0 - ); - - /** - * Q-Table - * - * @var Array - * @access private - */ - var $q1 = array ( - 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, - 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, - 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, - 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, - 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, - 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, - 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, - 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, - 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, - 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, - 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, - 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, - 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, - 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, - 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, - 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, - 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, - 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, - 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, - 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, - 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, - 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, - 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, - 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, - 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, - 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, - 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, - 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, - 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, - 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, - 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, - 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91 - ); - - /** - * M-Table - * - * @var Array - * @access private - */ - var $m0 = array ( - 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8, - 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, - 0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1, - 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F, - 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, - 0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5, - 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3, - 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, - 0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796, - 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C, - 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, - 0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8, - 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC, - 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, - 0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9, - 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17, - 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, - 0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E, - 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149, - 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, - 0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01, - 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48, - 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, - 0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64, - 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5, - 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, - 0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E, - 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC, - 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, - 0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9, - 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2, - 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91 - ); - - /** - * M-Table - * - * @var Array - * @access private - */ - var $m1 = array ( - 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4, - 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, - 0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141, - 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E, - 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, - 0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757, - 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D, - 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, - 0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656, - 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B, - 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, - 0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3, - 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D, - 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, - 0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282, - 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7, - 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, - 0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC, - 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E, - 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, - 0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272, - 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F, - 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, - 0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5, - 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7, - 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, - 0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3, - 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323, - 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, - 0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF, - 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000, - 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8 - ); - - /** - * M-Table - * - * @var Array - * @access private - */ - var $m2 = array ( - 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA, - 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, - 0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783, - 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE, - 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, - 0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA, - 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065, - 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, - 0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07, - 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF, - 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, - 0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96, - 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF, - 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, - 0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD, - 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC, - 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, - 0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85, - 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101, - 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, - 0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B, - 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A, - 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, - 0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D, - 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6, - 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, - 0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D, - 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB, - 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, - 0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9, - 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746, - 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF - ); - - /** - * M-Table - * - * @var Array - * @access private - */ - var $m3 = array ( - 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF, - 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, - 0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77, - 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A, - 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, - 0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216, - 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63, - 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, - 0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7, - 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197, - 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, - 0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C, - 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20, - 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, - 0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE, - 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730, - 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, - 0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4, - 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F, - 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, - 0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB, - 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D, - 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, - 0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8, - 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6, - 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, - 0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA, - 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439, - 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, - 0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D, - 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000, - 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8 - ); - - /** - * The Key Schedule Array - * - * @var Array - * @access private - */ - var $K = array(); - - /** - * The Key depended S-Table 0 - * - * @var Array - * @access private - */ - var $S0 = array(); - - /** - * The Key depended S-Table 1 - * - * @var Array - * @access private - */ - var $S1 = array(); - - /** - * The Key depended S-Table 2 - * - * @var Array - * @access private - */ - var $S2 = array(); - - /** - * The Key depended S-Table 3 - * - * @var Array - * @access private - */ - var $S3 = array(); - - /** - * Holds the last used key - * - * @var Array - * @access private - */ - var $kl; - - /** - * Sets the key. - * - * Keys can be of any length. Twofish, itself, requires the use of a key that's 128, 192 or 256-bits long. - * If the key is less than 256-bits we round the length up to the closest valid key length, - * padding $key with null bytes. If the key is more than 256-bits, we trim the excess bits. - * - * If the key is not explicitly set, it'll be assumed a 128 bits key to be all null bytes. - * - * @access public - * @see Crypt_Base::setKey() - * @param String $key - */ - function setKey($key) - { - $keylength = strlen($key); - switch (true) { - case $keylength <= 16: - $key = str_pad($key, 16, "\0"); - break; - case $keylength <= 24: - $key = str_pad($key, 24, "\0"); - break; - case $keylength < 32: - $key = str_pad($key, 32, "\0"); - break; - case $keylength > 32: - $key = substr($key, 0, 32); - } - parent::setKey($key); - } - - /** - * Setup the key (expansion) - * - * @see Crypt_Base::_setupKey() - * @access private - */ - function _setupKey() - { - if (isset($this->kl['key']) && $this->key === $this->kl['key']) { - // already expanded - return; - } - $this->kl = array('key' => $this->key); - - /* Key expanding and generating the key-depended s-boxes */ - $le_longs = unpack('V*', $this->key); - $key = unpack('C*', $this->key); - $m0 = $this->m0; - $m1 = $this->m1; - $m2 = $this->m2; - $m3 = $this->m3; - $q0 = $this->q0; - $q1 = $this->q1; - - $K = $S0 = $S1 = $S2 = $S3 = array(); - - switch (strlen($this->key)) { - case 16: - list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[1], $le_longs[2]); - list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[3], $le_longs[4]); - for ($i = 0, $j = 1; $i < 40; $i+= 2,$j+= 2) { - $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^ - $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^ - $m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^ - $m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]]; - $B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^ - $m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^ - $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^ - $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]]; - $B = ($B << 8) | ($B >> 24 & 0xff); - $K[] = $A+= $B; - $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff); - } - for ($i = 0; $i < 256; ++$i) { - $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0]; - $S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1]; - $S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2]; - $S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3]; - } - break; - case 24: - list ($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[1], $le_longs[2]); - list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[3], $le_longs[4]); - list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[5], $le_longs[6]); - for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) { - $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^ - $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^ - $m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^ - $m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]]; - $B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^ - $m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^ - $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^ - $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]]; - $B = ($B << 8) | ($B >> 24 & 0xff); - $K[] = $A+= $B; - $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff); - } - for ($i = 0; $i < 256; ++$i) { - $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0]; - $S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1]; - $S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2]; - $S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3]; - } - break; - default: // 32 - list ($sf, $se, $sd, $sc) = $this->_mdsrem($le_longs[1], $le_longs[2]); - list ($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[3], $le_longs[4]); - list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[5], $le_longs[6]); - list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[7], $le_longs[8]); - for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) { - $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^ - $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^ - $m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^ - $m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]]; - $B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^ - $m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^ - $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^ - $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]]; - $B = ($B << 8) | ($B >> 24 & 0xff); - $K[] = $A+= $B; - $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff); - } - for ($i = 0; $i < 256; ++$i) { - $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0]; - $S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1]; - $S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2]; - $S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3]; - } - } - - $this->K = $K; - $this->S0 = $S0; - $this->S1 = $S1; - $this->S2 = $S2; - $this->S3 = $S3; - } - - /** - * _mdsrem function using by the twofish cipher algorithm - * - * @access private - * @param String $A - * @param String $B - * @return Array - */ - function _mdsrem($A, $B) - { - // No gain by unrolling this loop. - for ($i = 0; $i < 8; ++$i) { - // Get most significant coefficient. - $t = 0xff & ($B >> 24); - - // Shift the others up. - $B = ($B << 8) | (0xff & ($A >> 24)); - $A<<= 8; - - $u = $t << 1; - - // Subtract the modular polynomial on overflow. - if ($t & 0x80) { - $u^= 0x14d; - } - - // Remove t * (a * x^2 + 1). - $B ^= $t ^ ($u << 16); - - // Form u = a*t + t/a = t*(a + 1/a). - $u^= 0x7fffffff & ($t >> 1); - - // Add the modular polynomial on underflow. - if ($t & 0x01) $u^= 0xa6 ; - - // Remove t * (a + 1/a) * (x^3 + x). - $B^= ($u << 24) | ($u << 8); - } - - return array( - 0xff & $B >> 24, - 0xff & $B >> 16, - 0xff & $B >> 8, - 0xff & $B); - } - - /** - * Encrypts a block - * - * @access private - * @param String $in - * @return String - */ - function _encryptBlock($in) - { - $S0 = $this->S0; - $S1 = $this->S1; - $S2 = $this->S2; - $S3 = $this->S3; - $K = $this->K; - - $in = unpack("V4", $in); - $R0 = $K[0] ^ $in[1]; - $R1 = $K[1] ^ $in[2]; - $R2 = $K[2] ^ $in[3]; - $R3 = $K[3] ^ $in[4]; - - $ki = 7; - while ($ki < 39) { - $t0 = $S0[ $R0 & 0xff] ^ - $S1[($R0 >> 8) & 0xff] ^ - $S2[($R0 >> 16) & 0xff] ^ - $S3[($R0 >> 24) & 0xff]; - $t1 = $S0[($R1 >> 24) & 0xff] ^ - $S1[ $R1 & 0xff] ^ - $S2[($R1 >> 8) & 0xff] ^ - $S3[($R1 >> 16) & 0xff]; - $R2^= $t0 + $t1 + $K[++$ki]; - $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31); - $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]); - - $t0 = $S0[ $R2 & 0xff] ^ - $S1[($R2 >> 8) & 0xff] ^ - $S2[($R2 >> 16) & 0xff] ^ - $S3[($R2 >> 24) & 0xff]; - $t1 = $S0[($R3 >> 24) & 0xff] ^ - $S1[ $R3 & 0xff] ^ - $S2[($R3 >> 8) & 0xff] ^ - $S3[($R3 >> 16) & 0xff]; - $R0^= ($t0 + $t1 + $K[++$ki]); - $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31); - $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]); - } - - // @codingStandardsIgnoreStart - return pack("V4", $K[4] ^ $R2, - $K[5] ^ $R3, - $K[6] ^ $R0, - $K[7] ^ $R1); - // @codingStandardsIgnoreEnd - } - - /** - * Decrypts a block - * - * @access private - * @param String $in - * @return String - */ - function _decryptBlock($in) - { - $S0 = $this->S0; - $S1 = $this->S1; - $S2 = $this->S2; - $S3 = $this->S3; - $K = $this->K; - - $in = unpack("V4", $in); - $R0 = $K[4] ^ $in[1]; - $R1 = $K[5] ^ $in[2]; - $R2 = $K[6] ^ $in[3]; - $R3 = $K[7] ^ $in[4]; - - $ki = 40; - while ($ki > 8) { - $t0 = $S0[$R0 & 0xff] ^ - $S1[$R0 >> 8 & 0xff] ^ - $S2[$R0 >> 16 & 0xff] ^ - $S3[$R0 >> 24 & 0xff]; - $t1 = $S0[$R1 >> 24 & 0xff] ^ - $S1[$R1 & 0xff] ^ - $S2[$R1 >> 8 & 0xff] ^ - $S3[$R1 >> 16 & 0xff]; - $R3^= $t0 + ($t1 << 1) + $K[--$ki]; - $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31; - $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K[--$ki]); - - $t0 = $S0[$R2 & 0xff] ^ - $S1[$R2 >> 8 & 0xff] ^ - $S2[$R2 >> 16 & 0xff] ^ - $S3[$R2 >> 24 & 0xff]; - $t1 = $S0[$R3 >> 24 & 0xff] ^ - $S1[$R3 & 0xff] ^ - $S2[$R3 >> 8 & 0xff] ^ - $S3[$R3 >> 16 & 0xff]; - $R1^= $t0 + ($t1 << 1) + $K[--$ki]; - $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31; - $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]); - } - - // @codingStandardsIgnoreStart - return pack("V4", $K[0] ^ $R2, - $K[1] ^ $R3, - $K[2] ^ $R0, - $K[3] ^ $R1); - // @codingStandardsIgnoreEnd - } - - /** - * Setup the performance-optimized function for de/encrypt() - * - * @see Crypt_Base::_setupInlineCrypt() - * @access private - */ - function _setupInlineCrypt() - { - $lambda_functions =& Crypt_Twofish::_getLambdaFunctions(); - - // Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one. - $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); - - switch (true) { - case $gen_hi_opt_code: - $code_hash = md5(str_pad("Crypt_Twofish, {$this->mode}, ", 32, "\0") . $this->key); - break; - default: - $code_hash = "Crypt_Twofish, {$this->mode}"; - } - - if (!isset($lambda_functions[$code_hash])) { - switch (true) { - case $gen_hi_opt_code: - $K = $this->K; - - $init_crypt = ' - static $S0, $S1, $S2, $S3; - if (!$S0) { - for ($i = 0; $i < 256; ++$i) { - $S0[] = (int)$self->S0[$i]; - $S1[] = (int)$self->S1[$i]; - $S2[] = (int)$self->S2[$i]; - $S3[] = (int)$self->S3[$i]; - } - } - '; - break; - default: - $K = array(); - for ($i = 0; $i < 40; ++$i) { - $K[] = '$K_' . $i; - } - - $init_crypt = ' - $S0 = $self->S0; - $S1 = $self->S1; - $S2 = $self->S2; - $S3 = $self->S3; - list(' . implode(',', $K) . ') = $self->K; - '; - } - - // Generating encrypt code: - $encrypt_block = ' - $in = unpack("V4", $in); - $R0 = '.$K[0].' ^ $in[1]; - $R1 = '.$K[1].' ^ $in[2]; - $R2 = '.$K[2].' ^ $in[3]; - $R3 = '.$K[3].' ^ $in[4]; - '; - for ($ki = 7, $i = 0; $i < 8; ++$i) { - $encrypt_block.= ' - $t0 = $S0[ $R0 & 0xff] ^ - $S1[($R0 >> 8) & 0xff] ^ - $S2[($R0 >> 16) & 0xff] ^ - $S3[($R0 >> 24) & 0xff]; - $t1 = $S0[($R1 >> 24) & 0xff] ^ - $S1[ $R1 & 0xff] ^ - $S2[($R1 >> 8) & 0xff] ^ - $S3[($R1 >> 16) & 0xff]; - $R2^= ($t0 + $t1 + '.$K[++$ki].'); - $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31); - $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].'); - - $t0 = $S0[ $R2 & 0xff] ^ - $S1[($R2 >> 8) & 0xff] ^ - $S2[($R2 >> 16) & 0xff] ^ - $S3[($R2 >> 24) & 0xff]; - $t1 = $S0[($R3 >> 24) & 0xff] ^ - $S1[ $R3 & 0xff] ^ - $S2[($R3 >> 8) & 0xff] ^ - $S3[($R3 >> 16) & 0xff]; - $R0^= ($t0 + $t1 + '.$K[++$ki].'); - $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31); - $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].'); - '; - } - $encrypt_block.= ' - $in = pack("V4", '.$K[4].' ^ $R2, - '.$K[5].' ^ $R3, - '.$K[6].' ^ $R0, - '.$K[7].' ^ $R1); - '; - - // Generating decrypt code: - $decrypt_block = ' - $in = unpack("V4", $in); - $R0 = '.$K[4].' ^ $in[1]; - $R1 = '.$K[5].' ^ $in[2]; - $R2 = '.$K[6].' ^ $in[3]; - $R3 = '.$K[7].' ^ $in[4]; - '; - for ($ki = 40, $i = 0; $i < 8; ++$i) { - $decrypt_block.= ' - $t0 = $S0[$R0 & 0xff] ^ - $S1[$R0 >> 8 & 0xff] ^ - $S2[$R0 >> 16 & 0xff] ^ - $S3[$R0 >> 24 & 0xff]; - $t1 = $S0[$R1 >> 24 & 0xff] ^ - $S1[$R1 & 0xff] ^ - $S2[$R1 >> 8 & 0xff] ^ - $S3[$R1 >> 16 & 0xff]; - $R3^= $t0 + ($t1 << 1) + '.$K[--$ki].'; - $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31; - $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + '.$K[--$ki].'); - - $t0 = $S0[$R2 & 0xff] ^ - $S1[$R2 >> 8 & 0xff] ^ - $S2[$R2 >> 16 & 0xff] ^ - $S3[$R2 >> 24 & 0xff]; - $t1 = $S0[$R3 >> 24 & 0xff] ^ - $S1[$R3 & 0xff] ^ - $S2[$R3 >> 8 & 0xff] ^ - $S3[$R3 >> 16 & 0xff]; - $R1^= $t0 + ($t1 << 1) + '.$K[--$ki].'; - $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31; - $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + '.$K[--$ki].'); - '; - } - $decrypt_block.= ' - $in = pack("V4", '.$K[0].' ^ $R2, - '.$K[1].' ^ $R3, - '.$K[2].' ^ $R0, - '.$K[3].' ^ $R1); - '; - - $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( - array( - 'init_crypt' => $init_crypt, - 'init_encrypt' => '', - 'init_decrypt' => '', - 'encrypt_block' => $encrypt_block, - 'decrypt_block' => $decrypt_block - ) - ); - } - $this->inline_crypt = $lambda_functions[$code_hash]; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/ANSI.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/ANSI.php deleted file mode 100644 index 3ff1b7d4..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/ANSI.php +++ /dev/null @@ -1,559 +0,0 @@ - - * @copyright 2012 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Pure-PHP ANSI Decoder - * - * @package File_ANSI - * @author Jim Wigginton - * @access public - */ -class File_ANSI -{ - /** - * Max Width - * - * @var Integer - * @access private - */ - var $max_x; - - /** - * Max Height - * - * @var Integer - * @access private - */ - var $max_y; - - /** - * Max History - * - * @var Integer - * @access private - */ - var $max_history; - - /** - * History - * - * @var Array - * @access private - */ - var $history; - - /** - * History Attributes - * - * @var Array - * @access private - */ - var $history_attrs; - - /** - * Current Column - * - * @var Integer - * @access private - */ - var $x; - - /** - * Current Row - * - * @var Integer - * @access private - */ - var $y; - - /** - * Old Column - * - * @var Integer - * @access private - */ - var $old_x; - - /** - * Old Row - * - * @var Integer - * @access private - */ - var $old_y; - - /** - * An empty attribute row - * - * @var Array - * @access private - */ - var $attr_row; - - /** - * The current screen text - * - * @var Array - * @access private - */ - var $screen; - - /** - * The current screen attributes - * - * @var Array - * @access private - */ - var $attrs; - - /** - * The current foreground color - * - * @var String - * @access private - */ - var $foreground; - - /** - * The current background color - * - * @var String - * @access private - */ - var $background; - - /** - * Bold flag - * - * @var Boolean - * @access private - */ - var $bold; - - /** - * Underline flag - * - * @var Boolean - * @access private - */ - var $underline; - - /** - * Blink flag - * - * @var Boolean - * @access private - */ - var $blink; - - /** - * Reverse flag - * - * @var Boolean - * @access private - */ - var $reverse; - - /** - * Color flag - * - * @var Boolean - * @access private - */ - var $color; - - /** - * Current ANSI code - * - * @var String - * @access private - */ - var $ansi; - - /** - * Default Constructor. - * - * @return File_ANSI - * @access public - */ - function File_ANSI() - { - $this->setHistory(200); - $this->setDimensions(80, 24); - } - - /** - * Set terminal width and height - * - * Resets the screen as well - * - * @param Integer $x - * @param Integer $y - * @access public - */ - function setDimensions($x, $y) - { - $this->max_x = $x - 1; - $this->max_y = $y - 1; - $this->x = $this->y = 0; - $this->history = $this->history_attrs = array(); - $this->attr_row = array_fill(0, $this->max_x + 1, ''); - $this->screen = array_fill(0, $this->max_y + 1, ''); - $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row); - $this->foreground = 'white'; - $this->background = 'black'; - $this->bold = false; - $this->underline = false; - $this->blink = false; - $this->reverse = false; - $this->color = false; - - $this->ansi = ''; - } - - /** - * Set the number of lines that should be logged past the terminal height - * - * @param Integer $x - * @param Integer $y - * @access public - */ - function setHistory($history) - { - $this->max_history = $history; - } - - /** - * Load a string - * - * @param String $source - * @access public - */ - function loadString($source) - { - $this->setDimensions($this->max_x + 1, $this->max_y + 1); - $this->appendString($source); - } - - /** - * Appdend a string - * - * @param String $source - * @access public - */ - function appendString($source) - { - for ($i = 0; $i < strlen($source); $i++) { - if (strlen($this->ansi)) { - $this->ansi.= $source[$i]; - $chr = ord($source[$i]); - // http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements - // single character CSI's not currently supported - switch (true) { - case $this->ansi == "\x1B=": - $this->ansi = ''; - continue 2; - case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['): - case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126: - break; - default: - continue 2; - } - // http://ascii-table.com/ansi-escape-sequences-vt-100.php - switch ($this->ansi) { - case "\x1B[H": // Move cursor to upper left corner - $this->old_x = $this->x; - $this->old_y = $this->y; - $this->x = $this->y = 0; - break; - case "\x1B[J": // Clear screen from cursor down - $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y)); - $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, '')); - - $this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y)); - $this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row)); - - if (count($this->history) == $this->max_history) { - array_shift($this->history); - array_shift($this->history_attrs); - } - case "\x1B[K": // Clear screen from cursor right - $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x); - - array_splice($this->attrs[$this->y], $this->x + 1); - break; - case "\x1B[2K": // Clear entire line - $this->screen[$this->y] = str_repeat(' ', $this->x); - $this->attrs[$this->y] = $this->attr_row; - break; - case "\x1B[?1h": // set cursor key to application - case "\x1B[?25h": // show the cursor - break; - case "\x1BE": // Move to next line - $this->_newLine(); - $this->x = 0; - break; - default: - switch (true) { - case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h - $this->old_x = $this->x; - $this->old_y = $this->y; - $this->x = $match[2] - 1; - $this->y = $match[1] - 1; - break; - case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines - $this->old_x = $this->x; - $x = $match[1] - 1; - break; - case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window - break; - case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes - $mods = explode(';', $match[1]); - foreach ($mods as $mod) { - switch ($mod) { - case 0: // Turn off character attributes - $this->attrs[$this->y][$this->x] = ''; - - if ($this->bold) $this->attrs[$this->y][$this->x].= ''; - if ($this->underline) $this->attrs[$this->y][$this->x].= ''; - if ($this->blink) $this->attrs[$this->y][$this->x].= ''; - if ($this->color) $this->attrs[$this->y][$this->x].= ''; - - if ($this->reverse) { - $temp = $this->background; - $this->background = $this->foreground; - $this->foreground = $temp; - } - - $this->bold = $this->underline = $this->blink = $this->color = $this->reverse = false; - break; - case 1: // Turn bold mode on - if (!$this->bold) { - $this->attrs[$this->y][$this->x] = ''; - $this->bold = true; - } - break; - case 4: // Turn underline mode on - if (!$this->underline) { - $this->attrs[$this->y][$this->x] = ''; - $this->underline = true; - } - break; - case 5: // Turn blinking mode on - if (!$this->blink) { - $this->attrs[$this->y][$this->x] = ''; - $this->blink = true; - } - break; - case 7: // Turn reverse video on - $this->reverse = !$this->reverse; - $temp = $this->background; - $this->background = $this->foreground; - $this->foreground = $temp; - $this->attrs[$this->y][$this->x] = ''; - if ($this->color) { - $this->attrs[$this->y][$this->x] = '' . $this->attrs[$this->y][$this->x]; - } - $this->color = true; - break; - default: // set colors - //$front = $this->reverse ? &$this->background : &$this->foreground; - $front = &$this->{ $this->reverse ? 'background' : 'foreground' }; - //$back = $this->reverse ? &$this->foreground : &$this->background; - $back = &$this->{ $this->reverse ? 'foreground' : 'background' }; - switch ($mod) { - case 30: $front = 'black'; break; - case 31: $front = 'red'; break; - case 32: $front = 'green'; break; - case 33: $front = 'yellow'; break; - case 34: $front = 'blue'; break; - case 35: $front = 'magenta'; break; - case 36: $front = 'cyan'; break; - case 37: $front = 'white'; break; - - case 40: $back = 'black'; break; - case 41: $back = 'red'; break; - case 42: $back = 'green'; break; - case 43: $back = 'yellow'; break; - case 44: $back = 'blue'; break; - case 45: $back = 'magenta'; break; - case 46: $back = 'cyan'; break; - case 47: $back = 'white'; break; - - default: - user_error('Unsupported attribute: ' . $mod); - $this->ansi = ''; - break 2; - } - - unset($temp); - $this->attrs[$this->y][$this->x] = ''; - if ($this->color) { - $this->attrs[$this->y][$this->x] = '' . $this->attrs[$this->y][$this->x]; - } - $this->color = true; - } - } - break; - default: - user_error("{$this->ansi} unsupported\r\n"); - } - } - $this->ansi = ''; - continue; - } - - switch ($source[$i]) { - case "\r": - $this->x = 0; - break; - case "\n": - $this->_newLine(); - break; - case "\x0F": // shift - break; - case "\x1B": // start ANSI escape code - $this->ansi.= "\x1B"; - break; - default: - $this->screen[$this->y] = substr_replace( - $this->screen[$this->y], - $source[$i], - $this->x, - 1 - ); - - if ($this->x > $this->max_x) { - $this->x = 0; - $this->y++; - } else { - $this->x++; - } - } - } - } - - /** - * Add a new line - * - * Also update the $this->screen and $this->history buffers - * - * @access private - */ - function _newLine() - { - //if ($this->y < $this->max_y) { - // $this->y++; - //} - - while ($this->y >= $this->max_y) { - $this->history = array_merge($this->history, array(array_shift($this->screen))); - $this->screen[] = ''; - - $this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs))); - $this->attrs[] = $this->attr_row; - - if (count($this->history) >= $this->max_history) { - array_shift($this->history); - array_shift($this->history_attrs); - } - - $this->y--; - } - $this->y++; - } - - /** - * Returns the current screen without preformating - * - * @access private - * @return String - */ - function _getScreen() - { - $output = ''; - for ($i = 0; $i <= $this->max_y; $i++) { - for ($j = 0; $j <= $this->max_x + 1; $j++) { - if (isset($this->attrs[$i][$j])) { - $output.= $this->attrs[$i][$j]; - } - if (isset($this->screen[$i][$j])) { - $output.= htmlspecialchars($this->screen[$i][$j]); - } - } - $output.= "\r\n"; - } - return rtrim($output); - } - - /** - * Returns the current screen - * - * @access public - * @return String - */ - function getScreen() - { - return '
' . $this->_getScreen() . '
'; - } - - /** - * Returns the current screen and the x previous lines - * - * @access public - * @return String - */ - function getHistory() - { - $scrollback = ''; - for ($i = 0; $i < count($this->history); $i++) { - for ($j = 0; $j <= $this->max_x + 1; $j++) { - if (isset($this->history_attrs[$i][$j])) { - $scrollback.= $this->history_attrs[$i][$j]; - } - if (isset($this->history[$i][$j])) { - $scrollback.= htmlspecialchars($this->history[$i][$j]); - } - } - $scrollback.= "\r\n"; - } - $scrollback.= $this->_getScreen(); - - return '
' . $scrollback . '
'; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/ASN1.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/ASN1.php deleted file mode 100644 index 1d66793a..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/ASN1.php +++ /dev/null @@ -1,1358 +0,0 @@ - - * @copyright 2012 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/**#@+ - * Tag Classes - * - * @access private - * @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12 - */ -define('FILE_ASN1_CLASS_UNIVERSAL', 0); -define('FILE_ASN1_CLASS_APPLICATION', 1); -define('FILE_ASN1_CLASS_CONTEXT_SPECIFIC', 2); -define('FILE_ASN1_CLASS_PRIVATE', 3); -/**#@-*/ - -/**#@+ - * Tag Classes - * - * @access private - * @link http://www.obj-sys.com/asn1tutorial/node124.html - */ -define('FILE_ASN1_TYPE_BOOLEAN', 1); -define('FILE_ASN1_TYPE_INTEGER', 2); -define('FILE_ASN1_TYPE_BIT_STRING', 3); -define('FILE_ASN1_TYPE_OCTET_STRING', 4); -define('FILE_ASN1_TYPE_NULL', 5); -define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER', 6); -//define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR', 7); -//define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL -define('FILE_ASN1_TYPE_REAL', 9); -define('FILE_ASN1_TYPE_ENUMERATED', 10); -//define('FILE_ASN1_TYPE_EMBEDDED', 11); -define('FILE_ASN1_TYPE_UTF8_STRING', 12); -//define('FILE_ASN1_TYPE_RELATIVE_OID', 13); -define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF -define('FILE_ASN1_TYPE_SET', 17); // SET OF -/**#@-*/ -/**#@+ - * More Tag Classes - * - * @access private - * @link http://www.obj-sys.com/asn1tutorial/node10.html - */ -define('FILE_ASN1_TYPE_NUMERIC_STRING', 18); -define('FILE_ASN1_TYPE_PRINTABLE_STRING', 19); -define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String -define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21); -define('FILE_ASN1_TYPE_IA5_STRING', 22); -define('FILE_ASN1_TYPE_UTC_TIME', 23); -define('FILE_ASN1_TYPE_GENERALIZED_TIME', 24); -define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25); -define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String -define('FILE_ASN1_TYPE_GENERAL_STRING', 27); -define('FILE_ASN1_TYPE_UNIVERSAL_STRING', 28); -//define('FILE_ASN1_TYPE_CHARACTER_STRING', 29); -define('FILE_ASN1_TYPE_BMP_STRING', 30); -/**#@-*/ - -/**#@+ - * Tag Aliases - * - * These tags are kinda place holders for other tags. - * - * @access private - */ -define('FILE_ASN1_TYPE_CHOICE', -1); -define('FILE_ASN1_TYPE_ANY', -2); -/**#@-*/ - -/** - * ASN.1 Element - * - * Bypass normal encoding rules in File_ASN1::encodeDER() - * - * @package File_ASN1 - * @author Jim Wigginton - * @access public - */ -class File_ASN1_Element -{ - /** - * Raw element value - * - * @var String - * @access private - */ - var $element; - - /** - * Constructor - * - * @param String $encoded - * @return File_ASN1_Element - * @access public - */ - function File_ASN1_Element($encoded) - { - $this->element = $encoded; - } -} - -/** - * Pure-PHP ASN.1 Parser - * - * @package File_ASN1 - * @author Jim Wigginton - * @access public - */ -class File_ASN1 -{ - /** - * ASN.1 object identifier - * - * @var Array - * @access private - * @link http://en.wikipedia.org/wiki/Object_identifier - */ - var $oids = array(); - - /** - * Default date format - * - * @var String - * @access private - * @link http://php.net/class.datetime - */ - var $format = 'D, d M Y H:i:s O'; - - /** - * Default date format - * - * @var Array - * @access private - * @see File_ASN1::setTimeFormat() - * @see File_ASN1::asn1map() - * @link http://php.net/class.datetime - */ - var $encoded; - - /** - * Filters - * - * If the mapping type is FILE_ASN1_TYPE_ANY what do we actually encode it as? - * - * @var Array - * @access private - * @see File_ASN1::_encode_der() - */ - var $filters; - - /** - * Type mapping table for the ANY type. - * - * Structured or unknown types are mapped to a FILE_ASN1_Element. - * Unambiguous types get the direct mapping (int/real/bool). - * Others are mapped as a choice, with an extra indexing level. - * - * @var Array - * @access public - */ - var $ANYmap = array( - FILE_ASN1_TYPE_BOOLEAN => true, - FILE_ASN1_TYPE_INTEGER => true, - FILE_ASN1_TYPE_BIT_STRING => 'bitString', - FILE_ASN1_TYPE_OCTET_STRING => 'octetString', - FILE_ASN1_TYPE_NULL => 'null', - FILE_ASN1_TYPE_OBJECT_IDENTIFIER => 'objectIdentifier', - FILE_ASN1_TYPE_REAL => true, - FILE_ASN1_TYPE_ENUMERATED => 'enumerated', - FILE_ASN1_TYPE_UTF8_STRING => 'utf8String', - FILE_ASN1_TYPE_NUMERIC_STRING => 'numericString', - FILE_ASN1_TYPE_PRINTABLE_STRING => 'printableString', - FILE_ASN1_TYPE_TELETEX_STRING => 'teletexString', - FILE_ASN1_TYPE_VIDEOTEX_STRING => 'videotexString', - FILE_ASN1_TYPE_IA5_STRING => 'ia5String', - FILE_ASN1_TYPE_UTC_TIME => 'utcTime', - FILE_ASN1_TYPE_GENERALIZED_TIME => 'generalTime', - FILE_ASN1_TYPE_GRAPHIC_STRING => 'graphicString', - FILE_ASN1_TYPE_VISIBLE_STRING => 'visibleString', - FILE_ASN1_TYPE_GENERAL_STRING => 'generalString', - FILE_ASN1_TYPE_UNIVERSAL_STRING => 'universalString', - //FILE_ASN1_TYPE_CHARACTER_STRING => 'characterString', - FILE_ASN1_TYPE_BMP_STRING => 'bmpString' - ); - - /** - * String type to character size mapping table. - * - * Non-convertable types are absent from this table. - * size == 0 indicates variable length encoding. - * - * @var Array - * @access public - */ - var $stringTypeSize = array( - FILE_ASN1_TYPE_UTF8_STRING => 0, - FILE_ASN1_TYPE_BMP_STRING => 2, - FILE_ASN1_TYPE_UNIVERSAL_STRING => 4, - FILE_ASN1_TYPE_PRINTABLE_STRING => 1, - FILE_ASN1_TYPE_TELETEX_STRING => 1, - FILE_ASN1_TYPE_IA5_STRING => 1, - FILE_ASN1_TYPE_VISIBLE_STRING => 1, - ); - - /** - * Default Constructor. - * - * @access public - */ - function File_ASN1() - { - static $static_init = null; - if (!$static_init) { - $static_init = true; - if (!class_exists('Math_BigInteger')) { - include_once 'Math/BigInteger.php'; - } - } - } - - /** - * Parse BER-encoding - * - * Serves a similar purpose to openssl's asn1parse - * - * @param String $encoded - * @return Array - * @access public - */ - function decodeBER($encoded) - { - if (is_object($encoded) && strtolower(get_class($encoded)) == 'file_asn1_element') { - $encoded = $encoded->element; - } - - $this->encoded = $encoded; - // encapsulate in an array for BC with the old decodeBER - return array($this->_decode_ber($encoded)); - } - - /** - * Parse BER-encoding (Helper function) - * - * Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode. - * $encoded is passed by reference for the recursive calls done for FILE_ASN1_TYPE_BIT_STRING and - * FILE_ASN1_TYPE_OCTET_STRING. In those cases, the indefinite length is used. - * - * @param String $encoded - * @param Integer $start - * @return Array - * @access private - */ - function _decode_ber($encoded, $start = 0) - { - $current = array('start' => $start); - - $type = ord($this->_string_shift($encoded)); - $start++; - - $constructed = ($type >> 5) & 1; - - $tag = $type & 0x1F; - if ($tag == 0x1F) { - $tag = 0; - // process septets (since the eighth bit is ignored, it's not an octet) - do { - $loop = ord($encoded[0]) >> 7; - $tag <<= 7; - $tag |= ord($this->_string_shift($encoded)) & 0x7F; - $start++; - } while ( $loop ); - } - - // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13 - $length = ord($this->_string_shift($encoded)); - $start++; - if ( $length == 0x80 ) { // indefinite length - // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all - // immediately available." -- paragraph 8.1.3.2.c - $length = strlen($encoded); - } elseif ( $length & 0x80 ) { // definite length, long form - // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only - // support it up to four. - $length&= 0x7F; - $temp = $this->_string_shift($encoded, $length); - // tags of indefinte length don't really have a header length; this length includes the tag - $current+= array('headerlength' => $length + 2); - $start+= $length; - extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4))); - } else { - $current+= array('headerlength' => 2); - } - - $content = $this->_string_shift($encoded, $length); - - // at this point $length can be overwritten. it's only accurate for definite length things as is - - /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1 - built-in types. It defines an application-independent data type that must be distinguishable from all other - data types. The other three classes are user defined. The APPLICATION class distinguishes data types that - have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within - a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the - alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this - data type; the term CONTEXT-SPECIFIC does not appear. - - -- http://www.obj-sys.com/asn1tutorial/node12.html */ - $class = ($type >> 6) & 3; - switch ($class) { - case FILE_ASN1_CLASS_APPLICATION: - case FILE_ASN1_CLASS_PRIVATE: - case FILE_ASN1_CLASS_CONTEXT_SPECIFIC: - if (!$constructed) { - return array( - 'type' => $class, - 'constant' => $tag, - 'content' => $content, - 'length' => $length + $start - $current['start'] - ); - } - - $newcontent = array(); - if (strlen($content)) { - $newcontent = $this->_decode_ber($content, $start); - $length = $newcontent['length']; - if (substr($content, $length, 2) == "\0\0") { - $length+= 2; - } - $start+= $length; - $newcontent = array($newcontent); - } - - return array( - 'type' => $class, - 'constant' => $tag, - // the array encapsulation is for BC with the old format - 'content' => $newcontent, - // the only time when $content['headerlength'] isn't defined is when the length is indefinite. - // the absence of $content['headerlength'] is how we know if something is indefinite or not. - // technically, it could be defined to be 2 and then another indicator could be used but whatever. - 'length' => $start - $current['start'] - ) + $current; - } - - $current+= array('type' => $tag); - - // decode UNIVERSAL tags - switch ($tag) { - case FILE_ASN1_TYPE_BOOLEAN: - // "The contents octets shall consist of a single octet." -- paragraph 8.2.1 - //if (strlen($content) != 1) { - // return false; - //} - $current['content'] = (bool) ord($content[0]); - break; - case FILE_ASN1_TYPE_INTEGER: - case FILE_ASN1_TYPE_ENUMERATED: - $current['content'] = new Math_BigInteger($content, -256); - break; - case FILE_ASN1_TYPE_REAL: // not currently supported - return false; - case FILE_ASN1_TYPE_BIT_STRING: - // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit, - // the number of unused bits in the final subsequent octet. The number shall be in the range zero to - // seven. - if (!$constructed) { - $current['content'] = $content; - } else { - $temp = $this->_decode_ber($content, $start); - $length-= strlen($content); - $last = count($temp) - 1; - for ($i = 0; $i < $last; $i++) { - // all subtags should be bit strings - //if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) { - // return false; - //} - $current['content'].= substr($temp[$i]['content'], 1); - } - // all subtags should be bit strings - //if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) { - // return false; - //} - $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1); - } - break; - case FILE_ASN1_TYPE_OCTET_STRING: - if (!$constructed) { - $current['content'] = $content; - } else { - $current['content'] = ''; - $length = 0; - while (substr($content, 0, 2) != "\0\0") { - $temp = $this->_decode_ber($content, $length + $start); - $this->_string_shift($content, $temp['length']); - // all subtags should be octet strings - //if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) { - // return false; - //} - $current['content'].= $temp['content']; - $length+= $temp['length']; - } - if (substr($content, 0, 2) == "\0\0") { - $length+= 2; // +2 for the EOC - } - } - break; - case FILE_ASN1_TYPE_NULL: - // "The contents octets shall not contain any octets." -- paragraph 8.8.2 - //if (strlen($content)) { - // return false; - //} - break; - case FILE_ASN1_TYPE_SEQUENCE: - case FILE_ASN1_TYPE_SET: - $offset = 0; - $current['content'] = array(); - while (strlen($content)) { - // if indefinite length construction was used and we have an end-of-content string next - // see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2 - if (!isset($current['headerlength']) && substr($content, 0, 2) == "\0\0") { - $length = $offset + 2; // +2 for the EOC - break 2; - } - $temp = $this->_decode_ber($content, $start + $offset); - $this->_string_shift($content, $temp['length']); - $current['content'][] = $temp; - $offset+= $temp['length']; - } - break; - case FILE_ASN1_TYPE_OBJECT_IDENTIFIER: - $temp = ord($this->_string_shift($content)); - $current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40); - $valuen = 0; - // process septets - while (strlen($content)) { - $temp = ord($this->_string_shift($content)); - $valuen <<= 7; - $valuen |= $temp & 0x7F; - if (~$temp & 0x80) { - $current['content'].= ".$valuen"; - $valuen = 0; - } - } - // the eighth bit of the last byte should not be 1 - //if ($temp >> 7) { - // return false; - //} - break; - /* Each character string type shall be encoded as if it had been declared: - [UNIVERSAL x] IMPLICIT OCTET STRING - - -- X.690-0207.pdf#page=23 (paragraph 8.21.3) - - Per that, we're not going to do any validation. If there are any illegal characters in the string, - we don't really care */ - case FILE_ASN1_TYPE_NUMERIC_STRING: - // 0,1,2,3,4,5,6,7,8,9, and space - case FILE_ASN1_TYPE_PRINTABLE_STRING: - // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma, - // hyphen, full stop, solidus, colon, equal sign, question mark - case FILE_ASN1_TYPE_TELETEX_STRING: - // The Teletex character set in CCITT's T61, space, and delete - // see http://en.wikipedia.org/wiki/Teletex#Character_sets - case FILE_ASN1_TYPE_VIDEOTEX_STRING: - // The Videotex character set in CCITT's T.100 and T.101, space, and delete - case FILE_ASN1_TYPE_VISIBLE_STRING: - // Printing character sets of international ASCII, and space - case FILE_ASN1_TYPE_IA5_STRING: - // International Alphabet 5 (International ASCII) - case FILE_ASN1_TYPE_GRAPHIC_STRING: - // All registered G sets, and space - case FILE_ASN1_TYPE_GENERAL_STRING: - // All registered C and G sets, space and delete - case FILE_ASN1_TYPE_UTF8_STRING: - // ???? - case FILE_ASN1_TYPE_BMP_STRING: - $current['content'] = $content; - break; - case FILE_ASN1_TYPE_UTC_TIME: - case FILE_ASN1_TYPE_GENERALIZED_TIME: - $current['content'] = $this->_decodeTime($content, $tag); - default: - } - - $start+= $length; - - // ie. length is the length of the full TLV encoding - it's not just the length of the value - return $current + array('length' => $start - $current['start']); - } - - /** - * ASN.1 Map - * - * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format. - * - * "Special" mappings may be applied on a per tag-name basis via $special. - * - * @param Array $decoded - * @param Array $mapping - * @param Array $special - * @return Array - * @access public - */ - function asn1map($decoded, $mapping, $special = array()) - { - if (isset($mapping['explicit']) && is_array($decoded['content'])) { - $decoded = $decoded['content'][0]; - } - - switch (true) { - case $mapping['type'] == FILE_ASN1_TYPE_ANY: - $intype = $decoded['type']; - if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || ($this->encoded[$decoded['start']] & 0x20)) { - return new File_ASN1_Element(substr($this->encoded, $decoded['start'], $decoded['length'])); - } - $inmap = $this->ANYmap[$intype]; - if (is_string($inmap)) { - return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special)); - } - break; - case $mapping['type'] == FILE_ASN1_TYPE_CHOICE: - foreach ($mapping['children'] as $key => $option) { - switch (true) { - case isset($option['constant']) && $option['constant'] == $decoded['constant']: - case !isset($option['constant']) && $option['type'] == $decoded['type']: - $value = $this->asn1map($decoded, $option, $special); - break; - case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE: - $v = $this->asn1map($decoded, $option, $special); - if (isset($v)) { - $value = $v; - } - } - if (isset($value)) { - if (isset($special[$key])) { - $value = call_user_func($special[$key], $value); - } - return array($key => $value); - } - } - return null; - case isset($mapping['implicit']): - case isset($mapping['explicit']): - case $decoded['type'] == $mapping['type']: - break; - default: - // if $decoded['type'] and $mapping['type'] are both strings, but different types of strings, - // let it through - switch (true) { - case $decoded['type'] < 18: // FILE_ASN1_TYPE_NUMERIC_STRING == 18 - case $decoded['type'] > 30: // FILE_ASN1_TYPE_BMP_STRING == 30 - case $mapping['type'] < 18: - case $mapping['type'] > 30: - return null; - } - } - - if (isset($mapping['implicit'])) { - $decoded['type'] = $mapping['type']; - } - - switch ($decoded['type']) { - case FILE_ASN1_TYPE_SEQUENCE: - $map = array(); - - // ignore the min and max - if (isset($mapping['min']) && isset($mapping['max'])) { - $child = $mapping['children']; - foreach ($decoded['content'] as $content) { - if (($map[] = $this->asn1map($content, $child, $special)) === null) { - return null; - } - } - - return $map; - } - - $n = count($decoded['content']); - $i = 0; - - foreach ($mapping['children'] as $key => $child) { - $maymatch = $i < $n; // Match only existing input. - if ($maymatch) { - $temp = $decoded['content'][$i]; - - if ($child['type'] != FILE_ASN1_TYPE_CHOICE) { - // Get the mapping and input class & constant. - $childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL; - $constant = null; - if (isset($temp['constant'])) { - $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC; - } - if (isset($child['class'])) { - $childClass = $child['class']; - $constant = $child['cast']; - } elseif (isset($child['constant'])) { - $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC; - $constant = $child['constant']; - } - - if (isset($constant) && isset($temp['constant'])) { - // Can only match if constants and class match. - $maymatch = $constant == $temp['constant'] && $childClass == $tempClass; - } else { - // Can only match if no constant expected and type matches or is generic. - $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false; - } - } - } - - if ($maymatch) { - // Attempt submapping. - $candidate = $this->asn1map($temp, $child, $special); - $maymatch = $candidate !== null; - } - - if ($maymatch) { - // Got the match: use it. - if (isset($special[$key])) { - $candidate = call_user_func($special[$key], $candidate); - } - $map[$key] = $candidate; - $i++; - } elseif (isset($child['default'])) { - $map[$key] = $child['default']; // Use default. - } elseif (!isset($child['optional'])) { - return null; // Syntax error. - } - } - - // Fail mapping if all input items have not been consumed. - return $i < $n? null: $map; - - // the main diff between sets and sequences is the encapsulation of the foreach in another for loop - case FILE_ASN1_TYPE_SET: - $map = array(); - - // ignore the min and max - if (isset($mapping['min']) && isset($mapping['max'])) { - $child = $mapping['children']; - foreach ($decoded['content'] as $content) { - if (($map[] = $this->asn1map($content, $child, $special)) === null) { - return null; - } - } - - return $map; - } - - for ($i = 0; $i < count($decoded['content']); $i++) { - $temp = $decoded['content'][$i]; - $tempClass = FILE_ASN1_CLASS_UNIVERSAL; - if (isset($temp['constant'])) { - $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC; - } - - foreach ($mapping['children'] as $key => $child) { - if (isset($map[$key])) { - continue; - } - $maymatch = true; - if ($child['type'] != FILE_ASN1_TYPE_CHOICE) { - $childClass = FILE_ASN1_CLASS_UNIVERSAL; - $constant = null; - if (isset($child['class'])) { - $childClass = $child['class']; - $constant = $child['cast']; - } elseif (isset($child['constant'])) { - $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC; - $constant = $child['constant']; - } - - if (isset($constant) && isset($temp['constant'])) { - // Can only match if constants and class match. - $maymatch = $constant == $temp['constant'] && $childClass == $tempClass; - } else { - // Can only match if no constant expected and type matches or is generic. - $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false; - } - } - - if ($maymatch) { - // Attempt submapping. - $candidate = $this->asn1map($temp, $child, $special); - $maymatch = $candidate !== null; - } - - if (!$maymatch) { - break; - } - - // Got the match: use it. - if (isset($special[$key])) { - $candidate = call_user_func($special[$key], $candidate); - } - $map[$key] = $candidate; - break; - } - } - - foreach ($mapping['children'] as $key => $child) { - if (!isset($map[$key])) { - if (isset($child['default'])) { - $map[$key] = $child['default']; - } elseif (!isset($child['optional'])) { - return null; - } - } - } - return $map; - case FILE_ASN1_TYPE_OBJECT_IDENTIFIER: - return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content']; - case FILE_ASN1_TYPE_UTC_TIME: - case FILE_ASN1_TYPE_GENERALIZED_TIME: - if (isset($mapping['implicit'])) { - $decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']); - } - return @date($this->format, $decoded['content']); - case FILE_ASN1_TYPE_BIT_STRING: - if (isset($mapping['mapping'])) { - $offset = ord($decoded['content'][0]); - $size = (strlen($decoded['content']) - 1) * 8 - $offset; - /* - From X.680-0207.pdf#page=46 (21.7): - - "When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove) - arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should - therefore ensure that different semantics are not associated with such values which differ only in the number of trailing - 0 bits." - */ - $bits = count($mapping['mapping']) == $size ? array() : array_fill(0, count($mapping['mapping']) - $size, false); - for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) { - $current = ord($decoded['content'][$i]); - for ($j = $offset; $j < 8; $j++) { - $bits[] = (bool) ($current & (1 << $j)); - } - $offset = 0; - } - $values = array(); - $map = array_reverse($mapping['mapping']); - foreach ($map as $i => $value) { - if ($bits[$i]) { - $values[] = $value; - } - } - return $values; - } - case FILE_ASN1_TYPE_OCTET_STRING: - return base64_encode($decoded['content']); - case FILE_ASN1_TYPE_NULL: - return ''; - case FILE_ASN1_TYPE_BOOLEAN: - return $decoded['content']; - case FILE_ASN1_TYPE_NUMERIC_STRING: - case FILE_ASN1_TYPE_PRINTABLE_STRING: - case FILE_ASN1_TYPE_TELETEX_STRING: - case FILE_ASN1_TYPE_VIDEOTEX_STRING: - case FILE_ASN1_TYPE_IA5_STRING: - case FILE_ASN1_TYPE_GRAPHIC_STRING: - case FILE_ASN1_TYPE_VISIBLE_STRING: - case FILE_ASN1_TYPE_GENERAL_STRING: - case FILE_ASN1_TYPE_UNIVERSAL_STRING: - case FILE_ASN1_TYPE_UTF8_STRING: - case FILE_ASN1_TYPE_BMP_STRING: - return $decoded['content']; - case FILE_ASN1_TYPE_INTEGER: - case FILE_ASN1_TYPE_ENUMERATED: - $temp = $decoded['content']; - if (isset($mapping['implicit'])) { - $temp = new Math_BigInteger($decoded['content'], -256); - } - if (isset($mapping['mapping'])) { - $temp = (int) $temp->toString(); - return isset($mapping['mapping'][$temp]) ? - $mapping['mapping'][$temp] : - false; - } - return $temp; - } - } - - /** - * ASN.1 Encode - * - * DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function - * an ASN.1 compiler. - * - * "Special" mappings can be applied via $special. - * - * @param String $source - * @param String $mapping - * @param Integer $idx - * @return String - * @access public - */ - function encodeDER($source, $mapping, $special = array()) - { - $this->location = array(); - return $this->_encode_der($source, $mapping, null, $special); - } - - /** - * ASN.1 Encode (Helper function) - * - * @param String $source - * @param String $mapping - * @param Integer $idx - * @return String - * @access private - */ - function _encode_der($source, $mapping, $idx = null, $special = array()) - { - if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') { - return $source->element; - } - - // do not encode (implicitly optional) fields with value set to default - if (isset($mapping['default']) && $source === $mapping['default']) { - return ''; - } - - if (isset($idx)) { - if (isset($special[$idx])) { - $source = call_user_func($special[$idx], $source); - } - $this->location[] = $idx; - } - - $tag = $mapping['type']; - - switch ($tag) { - case FILE_ASN1_TYPE_SET: // Children order is not important, thus process in sequence. - case FILE_ASN1_TYPE_SEQUENCE: - $tag|= 0x20; // set the constructed bit - $value = ''; - - // ignore the min and max - if (isset($mapping['min']) && isset($mapping['max'])) { - $child = $mapping['children']; - - foreach ($source as $content) { - $temp = $this->_encode_der($content, $child, null, $special); - if ($temp === false) { - return false; - } - $value.= $temp; - } - break; - } - - foreach ($mapping['children'] as $key => $child) { - if (!isset($source[$key])) { - if (!isset($child['optional'])) { - return false; - } - continue; - } - - $temp = $this->_encode_der($source[$key], $child, $key, $special); - if ($temp === false) { - return false; - } - - // An empty child encoding means it has been optimized out. - // Else we should have at least one tag byte. - if ($temp === '') { - continue; - } - - // if isset($child['constant']) is true then isset($child['optional']) should be true as well - if (isset($child['constant'])) { - /* - From X.680-0207.pdf#page=58 (30.6): - - "The tagging construction specifies explicit tagging if any of the following holds: - ... - c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or - AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or - an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)." - */ - if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) { - $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']); - $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp; - } else { - $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']); - $temp = $subtag . substr($temp, 1); - } - } - $value.= $temp; - } - break; - case FILE_ASN1_TYPE_CHOICE: - $temp = false; - - foreach ($mapping['children'] as $key => $child) { - if (!isset($source[$key])) { - continue; - } - - $temp = $this->_encode_der($source[$key], $child, $key, $special); - if ($temp === false) { - return false; - } - - // An empty child encoding means it has been optimized out. - // Else we should have at least one tag byte. - if ($temp === '') { - continue; - } - - $tag = ord($temp[0]); - - // if isset($child['constant']) is true then isset($child['optional']) should be true as well - if (isset($child['constant'])) { - if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) { - $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']); - $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp; - } else { - $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']); - $temp = $subtag . substr($temp, 1); - } - } - } - - if (isset($idx)) { - array_pop($this->location); - } - - if ($temp && isset($mapping['cast'])) { - $temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']); - } - - return $temp; - case FILE_ASN1_TYPE_INTEGER: - case FILE_ASN1_TYPE_ENUMERATED: - if (!isset($mapping['mapping'])) { - if (is_numeric($source)) { - $source = new Math_BigInteger($source); - } - $value = $source->toBytes(true); - } else { - $value = array_search($source, $mapping['mapping']); - if ($value === false) { - return false; - } - $value = new Math_BigInteger($value); - $value = $value->toBytes(true); - } - if (!strlen($value)) { - $value = chr(0); - } - break; - case FILE_ASN1_TYPE_UTC_TIME: - case FILE_ASN1_TYPE_GENERALIZED_TIME: - $format = $mapping['type'] == FILE_ASN1_TYPE_UTC_TIME ? 'y' : 'Y'; - $format.= 'mdHis'; - $value = @gmdate($format, strtotime($source)) . 'Z'; - break; - case FILE_ASN1_TYPE_BIT_STRING: - if (isset($mapping['mapping'])) { - $bits = array_fill(0, count($mapping['mapping']), 0); - $size = 0; - for ($i = 0; $i < count($mapping['mapping']); $i++) { - if (in_array($mapping['mapping'][$i], $source)) { - $bits[$i] = 1; - $size = $i; - } - } - - if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) { - $size = $mapping['min'] - 1; - } - - $offset = 8 - (($size + 1) & 7); - $offset = $offset !== 8 ? $offset : 0; - - $value = chr($offset); - - for ($i = $size + 1; $i < count($mapping['mapping']); $i++) { - unset($bits[$i]); - } - - $bits = implode('', array_pad($bits, $size + $offset + 1, 0)); - $bytes = explode(' ', rtrim(chunk_split($bits, 8, ' '))); - foreach ($bytes as $byte) { - $value.= chr(bindec($byte)); - } - - break; - } - case FILE_ASN1_TYPE_OCTET_STRING: - /* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit, - the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven. - - -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */ - $value = base64_decode($source); - break; - case FILE_ASN1_TYPE_OBJECT_IDENTIFIER: - $oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids); - if ($oid === false) { - user_error('Invalid OID'); - return false; - } - $value = ''; - $parts = explode('.', $oid); - $value = chr(40 * $parts[0] + $parts[1]); - for ($i = 2; $i < count($parts); $i++) { - $temp = ''; - if (!$parts[$i]) { - $temp = "\0"; - } else { - while ($parts[$i]) { - $temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp; - $parts[$i] >>= 7; - } - $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F); - } - $value.= $temp; - } - break; - case FILE_ASN1_TYPE_ANY: - $loc = $this->location; - if (isset($idx)) { - array_pop($this->location); - } - - switch (true) { - case !isset($source): - return $this->_encode_der(null, array('type' => FILE_ASN1_TYPE_NULL) + $mapping, null, $special); - case is_int($source): - case is_object($source) && strtolower(get_class($source)) == 'math_biginteger': - return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping, null, $special); - case is_float($source): - return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping, null, $special); - case is_bool($source): - return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping, null, $special); - case is_array($source) && count($source) == 1: - $typename = implode('', array_keys($source)); - $outtype = array_search($typename, $this->ANYmap, true); - if ($outtype !== false) { - return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special); - } - } - - $filters = $this->filters; - foreach ($loc as $part) { - if (!isset($filters[$part])) { - $filters = false; - break; - } - $filters = $filters[$part]; - } - if ($filters === false) { - user_error('No filters defined for ' . implode('/', $loc)); - return false; - } - return $this->_encode_der($source, $filters + $mapping, null, $special); - case FILE_ASN1_TYPE_NULL: - $value = ''; - break; - case FILE_ASN1_TYPE_NUMERIC_STRING: - case FILE_ASN1_TYPE_TELETEX_STRING: - case FILE_ASN1_TYPE_PRINTABLE_STRING: - case FILE_ASN1_TYPE_UNIVERSAL_STRING: - case FILE_ASN1_TYPE_UTF8_STRING: - case FILE_ASN1_TYPE_BMP_STRING: - case FILE_ASN1_TYPE_IA5_STRING: - case FILE_ASN1_TYPE_VISIBLE_STRING: - case FILE_ASN1_TYPE_VIDEOTEX_STRING: - case FILE_ASN1_TYPE_GRAPHIC_STRING: - case FILE_ASN1_TYPE_GENERAL_STRING: - $value = $source; - break; - case FILE_ASN1_TYPE_BOOLEAN: - $value = $source ? "\xFF" : "\x00"; - break; - default: - user_error('Mapping provides no type definition for ' . implode('/', $this->location)); - return false; - } - - if (isset($idx)) { - array_pop($this->location); - } - - if (isset($mapping['cast'])) { - if (isset($mapping['explicit']) || $mapping['type'] == FILE_ASN1_TYPE_CHOICE) { - $value = chr($tag) . $this->_encodeLength(strlen($value)) . $value; - $tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast']; - } else { - $tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast']; - } - } - - return chr($tag) . $this->_encodeLength(strlen($value)) . $value; - } - - /** - * DER-encode the length - * - * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See - * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. - * - * @access private - * @param Integer $length - * @return String - */ - function _encodeLength($length) - { - if ($length <= 0x7F) { - return chr($length); - } - - $temp = ltrim(pack('N', $length), chr(0)); - return pack('Ca*', 0x80 | strlen($temp), $temp); - } - - /** - * BER-decode the time - * - * Called by _decode_ber() and in the case of implicit tags asn1map(). - * - * @access private - * @param String $content - * @param Integer $tag - * @return String - */ - function _decodeTime($content, $tag) - { - /* UTCTime: - http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 - http://www.obj-sys.com/asn1tutorial/node15.html - - GeneralizedTime: - http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2 - http://www.obj-sys.com/asn1tutorial/node14.html */ - - $pattern = $tag == FILE_ASN1_TYPE_UTC_TIME ? - '#(..)(..)(..)(..)(..)(..)(.*)#' : - '#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#'; - - preg_match($pattern, $content, $matches); - - list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches; - - if ($tag == FILE_ASN1_TYPE_UTC_TIME) { - $year = $year >= 50 ? "19$year" : "20$year"; - } - - if ($timezone == 'Z') { - $mktime = 'gmmktime'; - $timezone = 0; - } elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) { - $mktime = 'gmmktime'; - $timezone = 60 * $matches[3] + 3600 * $matches[2]; - if ($matches[1] == '-') { - $timezone = -$timezone; - } - } else { - $mktime = 'mktime'; - $timezone = 0; - } - - return @$mktime($hour, $minute, $second, $month, $day, $year) + $timezone; - } - - /** - * Set the time format - * - * Sets the time / date format for asn1map(). - * - * @access public - * @param String $format - */ - function setTimeFormat($format) - { - $this->format = $format; - } - - /** - * Load OIDs - * - * Load the relevant OIDs for a particular ASN.1 semantic mapping. - * - * @access public - * @param Array $oids - */ - function loadOIDs($oids) - { - $this->oids = $oids; - } - - /** - * Load filters - * - * See File_X509, etc, for an example. - * - * @access public - * @param Array $filters - */ - function loadFilters($filters) - { - $this->filters = $filters; - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; - } - - /** - * String type conversion - * - * This is a lazy conversion, dealing only with character size. - * No real conversion table is used. - * - * @param String $in - * @param optional Integer $from - * @param optional Integer $to - * @return String - * @access public - */ - function convert($in, $from = FILE_ASN1_TYPE_UTF8_STRING, $to = FILE_ASN1_TYPE_UTF8_STRING) - { - if (!isset($this->stringTypeSize[$from]) || !isset($this->stringTypeSize[$to])) { - return false; - } - $insize = $this->stringTypeSize[$from]; - $outsize = $this->stringTypeSize[$to]; - $inlength = strlen($in); - $out = ''; - - for ($i = 0; $i < $inlength;) { - if ($inlength - $i < $insize) { - return false; - } - - // Get an input character as a 32-bit value. - $c = ord($in[$i++]); - switch (true) { - case $insize == 4: - $c = ($c << 8) | ord($in[$i++]); - $c = ($c << 8) | ord($in[$i++]); - case $insize == 2: - $c = ($c << 8) | ord($in[$i++]); - case $insize == 1: - break; - case ($c & 0x80) == 0x00: - break; - case ($c & 0x40) == 0x00: - return false; - default: - $bit = 6; - do { - if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) { - return false; - } - $c = ($c << 6) | (ord($in[$i++]) & 0x3F); - $bit += 5; - $mask = 1 << $bit; - } while ($c & $bit); - $c &= $mask - 1; - break; - } - - // Convert and append the character to output string. - $v = ''; - switch (true) { - case $outsize == 4: - $v .= chr($c & 0xFF); - $c >>= 8; - $v .= chr($c & 0xFF); - $c >>= 8; - case $outsize == 2: - $v .= chr($c & 0xFF); - $c >>= 8; - case $outsize == 1: - $v .= chr($c & 0xFF); - $c >>= 8; - if ($c) { - return false; - } - break; - case ($c & 0x80000000) != 0: - return false; - case $c >= 0x04000000: - $v .= chr(0x80 | ($c & 0x3F)); - $c = ($c >> 6) | 0x04000000; - case $c >= 0x00200000: - $v .= chr(0x80 | ($c & 0x3F)); - $c = ($c >> 6) | 0x00200000; - case $c >= 0x00010000: - $v .= chr(0x80 | ($c & 0x3F)); - $c = ($c >> 6) | 0x00010000; - case $c >= 0x00000800: - $v .= chr(0x80 | ($c & 0x3F)); - $c = ($c >> 6) | 0x00000800; - case $c >= 0x00000080: - $v .= chr(0x80 | ($c & 0x3F)); - $c = ($c >> 6) | 0x000000C0; - default: - $v .= chr($c); - break; - } - $out .= strrev($v); - } - return $out; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/X509.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/X509.php deleted file mode 100644 index 36a6287b..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/X509.php +++ /dev/null @@ -1,4583 +0,0 @@ - - * @copyright 2012 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include File_ASN1 - */ -if (!class_exists('File_ASN1')) { - include_once 'ASN1.php'; -} - -/** - * Flag to only accept signatures signed by certificate authorities - * - * Not really used anymore but retained all the same to suppress E_NOTICEs from old installs - * - * @access public - */ -define('FILE_X509_VALIDATE_SIGNATURE_BY_CA', 1); - -/**#@+ - * @access public - * @see File_X509::getDN() - */ -/** - * Return internal array representation - */ -define('FILE_X509_DN_ARRAY', 0); -/** - * Return string - */ -define('FILE_X509_DN_STRING', 1); -/** - * Return ASN.1 name string - */ -define('FILE_X509_DN_ASN1', 2); -/** - * Return OpenSSL compatible array - */ -define('FILE_X509_DN_OPENSSL', 3); -/** - * Return canonical ASN.1 RDNs string - */ -define('FILE_X509_DN_CANON', 4); -/** - * Return name hash for file indexing - */ -define('FILE_X509_DN_HASH', 5); -/**#@-*/ - -/**#@+ - * @access public - * @see File_X509::saveX509() - * @see File_X509::saveCSR() - * @see File_X509::saveCRL() - */ -/** - * Save as PEM - * - * ie. a base64-encoded PEM with a header and a footer - */ -define('FILE_X509_FORMAT_PEM', 0); -/** - * Save as DER - */ -define('FILE_X509_FORMAT_DER', 1); -/** - * Save as a SPKAC - * - * Only works on CSRs. Not currently supported. - */ -define('FILE_X509_FORMAT_SPKAC', 2); -/**#@-*/ - -/** - * Attribute value disposition. - * If disposition is >= 0, this is the index of the target value. - */ -define('FILE_X509_ATTR_ALL', -1); // All attribute values (array). -define('FILE_X509_ATTR_APPEND', -2); // Add a value. -define('FILE_X509_ATTR_REPLACE', -3); // Clear first, then add a value. - -/** - * Pure-PHP X.509 Parser - * - * @package File_X509 - * @author Jim Wigginton - * @access public - */ -class File_X509 -{ - /** - * ASN.1 syntax for X.509 certificates - * - * @var Array - * @access private - */ - var $Certificate; - - /**#@+ - * ASN.1 syntax for various extensions - * - * @access private - */ - var $DirectoryString; - var $PKCS9String; - var $AttributeValue; - var $Extensions; - var $KeyUsage; - var $ExtKeyUsageSyntax; - var $BasicConstraints; - var $KeyIdentifier; - var $CRLDistributionPoints; - var $AuthorityKeyIdentifier; - var $CertificatePolicies; - var $AuthorityInfoAccessSyntax; - var $SubjectAltName; - var $PrivateKeyUsagePeriod; - var $IssuerAltName; - var $PolicyMappings; - var $NameConstraints; - - var $CPSuri; - var $UserNotice; - - var $netscape_cert_type; - var $netscape_comment; - var $netscape_ca_policy_url; - - var $Name; - var $RelativeDistinguishedName; - var $CRLNumber; - var $CRLReason; - var $IssuingDistributionPoint; - var $InvalidityDate; - var $CertificateIssuer; - var $HoldInstructionCode; - var $SignedPublicKeyAndChallenge; - /**#@-*/ - - /** - * ASN.1 syntax for Certificate Signing Requests (RFC2986) - * - * @var Array - * @access private - */ - var $CertificationRequest; - - /** - * ASN.1 syntax for Certificate Revocation Lists (RFC5280) - * - * @var Array - * @access private - */ - var $CertificateList; - - /** - * Distinguished Name - * - * @var Array - * @access private - */ - var $dn; - - /** - * Public key - * - * @var String - * @access private - */ - var $publicKey; - - /** - * Private key - * - * @var String - * @access private - */ - var $privateKey; - - /** - * Object identifiers for X.509 certificates - * - * @var Array - * @access private - * @link http://en.wikipedia.org/wiki/Object_identifier - */ - var $oids; - - /** - * The certificate authorities - * - * @var Array - * @access private - */ - var $CAs; - - /** - * The currently loaded certificate - * - * @var Array - * @access private - */ - var $currentCert; - - /** - * The signature subject - * - * There's no guarantee File_X509 is going to reencode an X.509 cert in the same way it was originally - * encoded so we take save the portion of the original cert that the signature would have made for. - * - * @var String - * @access private - */ - var $signatureSubject; - - /** - * Certificate Start Date - * - * @var String - * @access private - */ - var $startDate; - - /** - * Certificate End Date - * - * @var String - * @access private - */ - var $endDate; - - /** - * Serial Number - * - * @var String - * @access private - */ - var $serialNumber; - - /** - * Key Identifier - * - * See {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.1 RFC5280#section-4.2.1.1} and - * {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.2 RFC5280#section-4.2.1.2}. - * - * @var String - * @access private - */ - var $currentKeyIdentifier; - - /** - * CA Flag - * - * @var Boolean - * @access private - */ - var $caFlag = false; - - /** - * SPKAC Challenge - * - * @var String - * @access private - */ - var $challenge; - - /** - * Default Constructor. - * - * @return File_X509 - * @access public - */ - function File_X509() - { - if (!class_exists('Math_BigInteger')) { - include_once 'Math/BigInteger.php'; - } - - // Explicitly Tagged Module, 1988 Syntax - // http://tools.ietf.org/html/rfc5280#appendix-A.1 - - $this->DirectoryString = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'teletexString' => array('type' => FILE_ASN1_TYPE_TELETEX_STRING), - 'printableString' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING), - 'universalString' => array('type' => FILE_ASN1_TYPE_UNIVERSAL_STRING), - 'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING), - 'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING) - ) - ); - - $this->PKCS9String = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING), - 'directoryString' => $this->DirectoryString - ) - ); - - $this->AttributeValue = array('type' => FILE_ASN1_TYPE_ANY); - - $AttributeType = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER); - - $AttributeTypeAndValue = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'type' => $AttributeType, - 'value'=> $this->AttributeValue - ) - ); - - /* - In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare, - but they can be useful at times when either there is no unique attribute in the entry or you - want to ensure that the entry's DN contains some useful identifying information. - - - https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName - */ - $this->RelativeDistinguishedName = array( - 'type' => FILE_ASN1_TYPE_SET, - 'min' => 1, - 'max' => -1, - 'children' => $AttributeTypeAndValue - ); - - // http://tools.ietf.org/html/rfc5280#section-4.1.2.4 - $RDNSequence = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - // RDNSequence does not define a min or a max, which means it doesn't have one - 'min' => 0, - 'max' => -1, - 'children' => $this->RelativeDistinguishedName - ); - - $this->Name = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'rdnSequence' => $RDNSequence - ) - ); - - // http://tools.ietf.org/html/rfc5280#section-4.1.1.2 - $AlgorithmIdentifier = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'algorithm' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER), - 'parameters' => array( - 'type' => FILE_ASN1_TYPE_ANY, - 'optional' => true - ) - ) - ); - - /* - A certificate using system MUST reject the certificate if it encounters - a critical extension it does not recognize; however, a non-critical - extension may be ignored if it is not recognized. - - http://tools.ietf.org/html/rfc5280#section-4.2 - */ - $Extension = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'extnId' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER), - 'critical' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'optional' => true, - 'default' => false - ), - 'extnValue' => array('type' => FILE_ASN1_TYPE_OCTET_STRING) - ) - ); - - $this->Extensions = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - // technically, it's MAX, but we'll assume anything < 0 is MAX - 'max' => -1, - // if 'children' isn't an array then 'min' and 'max' must be defined - 'children' => $Extension - ); - - $SubjectPublicKeyInfo = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'algorithm' => $AlgorithmIdentifier, - 'subjectPublicKey' => array('type' => FILE_ASN1_TYPE_BIT_STRING) - ) - ); - - $UniqueIdentifier = array('type' => FILE_ASN1_TYPE_BIT_STRING); - - $Time = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'utcTime' => array('type' => FILE_ASN1_TYPE_UTC_TIME), - 'generalTime' => array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME) - ) - ); - - // http://tools.ietf.org/html/rfc5280#section-4.1.2.5 - $Validity = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'notBefore' => $Time, - 'notAfter' => $Time - ) - ); - - $CertificateSerialNumber = array('type' => FILE_ASN1_TYPE_INTEGER); - - $Version = array( - 'type' => FILE_ASN1_TYPE_INTEGER, - 'mapping' => array('v1', 'v2', 'v3') - ); - - // assert($TBSCertificate['children']['signature'] == $Certificate['children']['signatureAlgorithm']) - $TBSCertificate = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - // technically, default implies optional, but we'll define it as being optional, none-the-less, just to - // reenforce that fact - 'version' => array( - 'constant' => 0, - 'optional' => true, - 'explicit' => true, - 'default' => 'v1' - ) + $Version, - 'serialNumber' => $CertificateSerialNumber, - 'signature' => $AlgorithmIdentifier, - 'issuer' => $this->Name, - 'validity' => $Validity, - 'subject' => $this->Name, - 'subjectPublicKeyInfo' => $SubjectPublicKeyInfo, - // implicit means that the T in the TLV structure is to be rewritten, regardless of the type - 'issuerUniqueID' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $UniqueIdentifier, - 'subjectUniqueID' => array( - 'constant' => 2, - 'optional' => true, - 'implicit' => true - ) + $UniqueIdentifier, - // doesn't use the EXPLICIT keyword but if - // it's not IMPLICIT, it's EXPLICIT - 'extensions' => array( - 'constant' => 3, - 'optional' => true, - 'explicit' => true - ) + $this->Extensions - ) - ); - - $this->Certificate = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'tbsCertificate' => $TBSCertificate, - 'signatureAlgorithm' => $AlgorithmIdentifier, - 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING) - ) - ); - - $this->KeyUsage = array( - 'type' => FILE_ASN1_TYPE_BIT_STRING, - 'mapping' => array( - 'digitalSignature', - 'nonRepudiation', - 'keyEncipherment', - 'dataEncipherment', - 'keyAgreement', - 'keyCertSign', - 'cRLSign', - 'encipherOnly', - 'decipherOnly' - ) - ); - - $this->BasicConstraints = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'cA' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'optional' => true, - 'default' => false - ), - 'pathLenConstraint' => array( - 'type' => FILE_ASN1_TYPE_INTEGER, - 'optional' => true - ) - ) - ); - - $this->KeyIdentifier = array('type' => FILE_ASN1_TYPE_OCTET_STRING); - - $OrganizationalUnitNames = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => 4, // ub-organizational-units - 'children' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING) - ); - - $PersonalName = array( - 'type' => FILE_ASN1_TYPE_SET, - 'children' => array( - 'surname' => array( - 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING, - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ), - 'given-name' => array( - 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING, - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ), - 'initials' => array( - 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING, - 'constant' => 2, - 'optional' => true, - 'implicit' => true - ), - 'generation-qualifier' => array( - 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING, - 'constant' => 3, - 'optional' => true, - 'implicit' => true - ) - ) - ); - - $NumericUserIdentifier = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING); - - $OrganizationName = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING); - - $PrivateDomainName = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING), - 'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING) - ) - ); - - $TerminalIdentifier = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING); - - $NetworkAddress = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING); - - $AdministrationDomainName = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - // if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or - // (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC - 'class' => FILE_ASN1_CLASS_APPLICATION, - 'cast' => 2, - 'children' => array( - 'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING), - 'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING) - ) - ); - - $CountryName = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - // if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or - // (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC - 'class' => FILE_ASN1_CLASS_APPLICATION, - 'cast' => 1, - 'children' => array( - 'x121-dcc-code' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING), - 'iso-3166-alpha2-code' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING) - ) - ); - - $AnotherName = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'type-id' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER), - 'value' => array( - 'type' => FILE_ASN1_TYPE_ANY, - 'constant' => 0, - 'optional' => true, - 'explicit' => true - ) - ) - ); - - $ExtensionAttribute = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'extension-attribute-type' => array( - 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING, - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ), - 'extension-attribute-value' => array( - 'type' => FILE_ASN1_TYPE_ANY, - 'constant' => 1, - 'optional' => true, - 'explicit' => true - ) - ) - ); - - $ExtensionAttributes = array( - 'type' => FILE_ASN1_TYPE_SET, - 'min' => 1, - 'max' => 256, // ub-extension-attributes - 'children' => $ExtensionAttribute - ); - - $BuiltInDomainDefinedAttribute = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'type' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING), - 'value' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING) - ) - ); - - $BuiltInDomainDefinedAttributes = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => 4, // ub-domain-defined-attributes - 'children' => $BuiltInDomainDefinedAttribute - ); - - $BuiltInStandardAttributes = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'country-name' => array('optional' => true) + $CountryName, - 'administration-domain-name' => array('optional' => true) + $AdministrationDomainName, - 'network-address' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $NetworkAddress, - 'terminal-identifier' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $TerminalIdentifier, - 'private-domain-name' => array( - 'constant' => 2, - 'optional' => true, - 'explicit' => true - ) + $PrivateDomainName, - 'organization-name' => array( - 'constant' => 3, - 'optional' => true, - 'implicit' => true - ) + $OrganizationName, - 'numeric-user-identifier' => array( - 'constant' => 4, - 'optional' => true, - 'implicit' => true - ) + $NumericUserIdentifier, - 'personal-name' => array( - 'constant' => 5, - 'optional' => true, - 'implicit' => true - ) + $PersonalName, - 'organizational-unit-names' => array( - 'constant' => 6, - 'optional' => true, - 'implicit' => true - ) + $OrganizationalUnitNames - ) - ); - - $ORAddress = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'built-in-standard-attributes' => $BuiltInStandardAttributes, - 'built-in-domain-defined-attributes' => array('optional' => true) + $BuiltInDomainDefinedAttributes, - 'extension-attributes' => array('optional' => true) + $ExtensionAttributes - ) - ); - - $EDIPartyName = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'nameAssigner' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $this->DirectoryString, - // partyName is technically required but File_ASN1 doesn't currently support non-optional constants and - // setting it to optional gets the job done in any event. - 'partyName' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $this->DirectoryString - ) - ); - - $GeneralName = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'otherName' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $AnotherName, - 'rfc822Name' => array( - 'type' => FILE_ASN1_TYPE_IA5_STRING, - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ), - 'dNSName' => array( - 'type' => FILE_ASN1_TYPE_IA5_STRING, - 'constant' => 2, - 'optional' => true, - 'implicit' => true - ), - 'x400Address' => array( - 'constant' => 3, - 'optional' => true, - 'implicit' => true - ) + $ORAddress, - 'directoryName' => array( - 'constant' => 4, - 'optional' => true, - 'explicit' => true - ) + $this->Name, - 'ediPartyName' => array( - 'constant' => 5, - 'optional' => true, - 'implicit' => true - ) + $EDIPartyName, - 'uniformResourceIdentifier' => array( - 'type' => FILE_ASN1_TYPE_IA5_STRING, - 'constant' => 6, - 'optional' => true, - 'implicit' => true - ), - 'iPAddress' => array( - 'type' => FILE_ASN1_TYPE_OCTET_STRING, - 'constant' => 7, - 'optional' => true, - 'implicit' => true - ), - 'registeredID' => array( - 'type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER, - 'constant' => 8, - 'optional' => true, - 'implicit' => true - ) - ) - ); - - $GeneralNames = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $GeneralName - ); - - $this->IssuerAltName = $GeneralNames; - - $ReasonFlags = array( - 'type' => FILE_ASN1_TYPE_BIT_STRING, - 'mapping' => array( - 'unused', - 'keyCompromise', - 'cACompromise', - 'affiliationChanged', - 'superseded', - 'cessationOfOperation', - 'certificateHold', - 'privilegeWithdrawn', - 'aACompromise' - ) - ); - - $DistributionPointName = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'fullName' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $GeneralNames, - 'nameRelativeToCRLIssuer' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $this->RelativeDistinguishedName - ) - ); - - $DistributionPoint = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'distributionPoint' => array( - 'constant' => 0, - 'optional' => true, - 'explicit' => true - ) + $DistributionPointName, - 'reasons' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $ReasonFlags, - 'cRLIssuer' => array( - 'constant' => 2, - 'optional' => true, - 'implicit' => true - ) + $GeneralNames - ) - ); - - $this->CRLDistributionPoints = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $DistributionPoint - ); - - $this->AuthorityKeyIdentifier = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'keyIdentifier' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $this->KeyIdentifier, - 'authorityCertIssuer' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $GeneralNames, - 'authorityCertSerialNumber' => array( - 'constant' => 2, - 'optional' => true, - 'implicit' => true - ) + $CertificateSerialNumber - ) - ); - - $PolicyQualifierId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER); - - $PolicyQualifierInfo = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'policyQualifierId' => $PolicyQualifierId, - 'qualifier' => array('type' => FILE_ASN1_TYPE_ANY) - ) - ); - - $CertPolicyId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER); - - $PolicyInformation = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'policyIdentifier' => $CertPolicyId, - 'policyQualifiers' => array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 0, - 'max' => -1, - 'optional' => true, - 'children' => $PolicyQualifierInfo - ) - ) - ); - - $this->CertificatePolicies = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $PolicyInformation - ); - - $this->PolicyMappings = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'issuerDomainPolicy' => $CertPolicyId, - 'subjectDomainPolicy' => $CertPolicyId - ) - ) - ); - - $KeyPurposeId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER); - - $this->ExtKeyUsageSyntax = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $KeyPurposeId - ); - - $AccessDescription = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'accessMethod' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER), - 'accessLocation' => $GeneralName - ) - ); - - $this->AuthorityInfoAccessSyntax = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $AccessDescription - ); - - $this->SubjectAltName = $GeneralNames; - - $this->PrivateKeyUsagePeriod = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'notBefore' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true, - 'type' => FILE_ASN1_TYPE_GENERALIZED_TIME), - 'notAfter' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true, - 'type' => FILE_ASN1_TYPE_GENERALIZED_TIME) - ) - ); - - $BaseDistance = array('type' => FILE_ASN1_TYPE_INTEGER); - - $GeneralSubtree = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'base' => $GeneralName, - 'minimum' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true, - 'default' => new Math_BigInteger(0) - ) + $BaseDistance, - 'maximum' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true, - ) + $BaseDistance - ) - ); - - $GeneralSubtrees = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $GeneralSubtree - ); - - $this->NameConstraints = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'permittedSubtrees' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $GeneralSubtrees, - 'excludedSubtrees' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $GeneralSubtrees - ) - ); - - $this->CPSuri = array('type' => FILE_ASN1_TYPE_IA5_STRING); - - $DisplayText = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING), - 'visibleString' => array('type' => FILE_ASN1_TYPE_VISIBLE_STRING), - 'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING), - 'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING) - ) - ); - - $NoticeReference = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'organization' => $DisplayText, - 'noticeNumbers' => array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => 200, - 'children' => array('type' => FILE_ASN1_TYPE_INTEGER) - ) - ) - ); - - $this->UserNotice = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'noticeRef' => array( - 'optional' => true, - 'implicit' => true - ) + $NoticeReference, - 'explicitText' => array( - 'optional' => true, - 'implicit' => true - ) + $DisplayText - ) - ); - - // mapping is from - $this->netscape_cert_type = array( - 'type' => FILE_ASN1_TYPE_BIT_STRING, - 'mapping' => array( - 'SSLClient', - 'SSLServer', - 'Email', - 'ObjectSigning', - 'Reserved', - 'SSLCA', - 'EmailCA', - 'ObjectSigningCA' - ) - ); - - $this->netscape_comment = array('type' => FILE_ASN1_TYPE_IA5_STRING); - $this->netscape_ca_policy_url = array('type' => FILE_ASN1_TYPE_IA5_STRING); - - // attribute is used in RFC2986 but we're using the RFC5280 definition - - $Attribute = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'type' => $AttributeType, - 'value'=> array( - 'type' => FILE_ASN1_TYPE_SET, - 'min' => 1, - 'max' => -1, - 'children' => $this->AttributeValue - ) - ) - ); - - // adapted from - - $Attributes = array( - 'type' => FILE_ASN1_TYPE_SET, - 'min' => 1, - 'max' => -1, - 'children' => $Attribute - ); - - $CertificationRequestInfo = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'version' => array( - 'type' => FILE_ASN1_TYPE_INTEGER, - 'mapping' => array('v1') - ), - 'subject' => $this->Name, - 'subjectPKInfo' => $SubjectPublicKeyInfo, - 'attributes' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $Attributes, - ) - ); - - $this->CertificationRequest = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'certificationRequestInfo' => $CertificationRequestInfo, - 'signatureAlgorithm' => $AlgorithmIdentifier, - 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING) - ) - ); - - $RevokedCertificate = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'userCertificate' => $CertificateSerialNumber, - 'revocationDate' => $Time, - 'crlEntryExtensions' => array( - 'optional' => true - ) + $this->Extensions - ) - ); - - $TBSCertList = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'version' => array( - 'optional' => true, - 'default' => 'v1' - ) + $Version, - 'signature' => $AlgorithmIdentifier, - 'issuer' => $this->Name, - 'thisUpdate' => $Time, - 'nextUpdate' => array( - 'optional' => true - ) + $Time, - 'revokedCertificates' => array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'optional' => true, - 'min' => 0, - 'max' => -1, - 'children' => $RevokedCertificate - ), - 'crlExtensions' => array( - 'constant' => 0, - 'optional' => true, - 'explicit' => true - ) + $this->Extensions - ) - ); - - $this->CertificateList = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'tbsCertList' => $TBSCertList, - 'signatureAlgorithm' => $AlgorithmIdentifier, - 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING) - ) - ); - - $this->CRLNumber = array('type' => FILE_ASN1_TYPE_INTEGER); - - $this->CRLReason = array('type' => FILE_ASN1_TYPE_ENUMERATED, - 'mapping' => array( - 'unspecified', - 'keyCompromise', - 'cACompromise', - 'affiliationChanged', - 'superseded', - 'cessationOfOperation', - 'certificateHold', - // Value 7 is not used. - 8 => 'removeFromCRL', - 'privilegeWithdrawn', - 'aACompromise' - ) - ); - - $this->IssuingDistributionPoint = array('type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'distributionPoint' => array( - 'constant' => 0, - 'optional' => true, - 'explicit' => true - ) + $DistributionPointName, - 'onlyContainsUserCerts' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'constant' => 1, - 'optional' => true, - 'default' => false, - 'implicit' => true - ), - 'onlyContainsCACerts' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'constant' => 2, - 'optional' => true, - 'default' => false, - 'implicit' => true - ), - 'onlySomeReasons' => array( - 'constant' => 3, - 'optional' => true, - 'implicit' => true - ) + $ReasonFlags, - 'indirectCRL' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'constant' => 4, - 'optional' => true, - 'default' => false, - 'implicit' => true - ), - 'onlyContainsAttributeCerts' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'constant' => 5, - 'optional' => true, - 'default' => false, - 'implicit' => true - ) - ) - ); - - $this->InvalidityDate = array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME); - - $this->CertificateIssuer = $GeneralNames; - - $this->HoldInstructionCode = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER); - - $PublicKeyAndChallenge = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'spki' => $SubjectPublicKeyInfo, - 'challenge' => array('type' => FILE_ASN1_TYPE_IA5_STRING) - ) - ); - - $this->SignedPublicKeyAndChallenge = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'publicKeyAndChallenge' => $PublicKeyAndChallenge, - 'signatureAlgorithm' => $AlgorithmIdentifier, - 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING) - ) - ); - - // OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2 - $this->oids = array( - '1.3.6.1.5.5.7' => 'id-pkix', - '1.3.6.1.5.5.7.1' => 'id-pe', - '1.3.6.1.5.5.7.2' => 'id-qt', - '1.3.6.1.5.5.7.3' => 'id-kp', - '1.3.6.1.5.5.7.48' => 'id-ad', - '1.3.6.1.5.5.7.2.1' => 'id-qt-cps', - '1.3.6.1.5.5.7.2.2' => 'id-qt-unotice', - '1.3.6.1.5.5.7.48.1' =>'id-ad-ocsp', - '1.3.6.1.5.5.7.48.2' => 'id-ad-caIssuers', - '1.3.6.1.5.5.7.48.3' => 'id-ad-timeStamping', - '1.3.6.1.5.5.7.48.5' => 'id-ad-caRepository', - '2.5.4' => 'id-at', - '2.5.4.41' => 'id-at-name', - '2.5.4.4' => 'id-at-surname', - '2.5.4.42' => 'id-at-givenName', - '2.5.4.43' => 'id-at-initials', - '2.5.4.44' => 'id-at-generationQualifier', - '2.5.4.3' => 'id-at-commonName', - '2.5.4.7' => 'id-at-localityName', - '2.5.4.8' => 'id-at-stateOrProvinceName', - '2.5.4.10' => 'id-at-organizationName', - '2.5.4.11' => 'id-at-organizationalUnitName', - '2.5.4.12' => 'id-at-title', - '2.5.4.13' => 'id-at-description', - '2.5.4.46' => 'id-at-dnQualifier', - '2.5.4.6' => 'id-at-countryName', - '2.5.4.5' => 'id-at-serialNumber', - '2.5.4.65' => 'id-at-pseudonym', - '2.5.4.17' => 'id-at-postalCode', - '2.5.4.9' => 'id-at-streetAddress', - '2.5.4.45' => 'id-at-uniqueIdentifier', - '2.5.4.72' => 'id-at-role', - - '0.9.2342.19200300.100.1.25' => 'id-domainComponent', - '1.2.840.113549.1.9' => 'pkcs-9', - '1.2.840.113549.1.9.1' => 'pkcs-9-at-emailAddress', - '2.5.29' => 'id-ce', - '2.5.29.35' => 'id-ce-authorityKeyIdentifier', - '2.5.29.14' => 'id-ce-subjectKeyIdentifier', - '2.5.29.15' => 'id-ce-keyUsage', - '2.5.29.16' => 'id-ce-privateKeyUsagePeriod', - '2.5.29.32' => 'id-ce-certificatePolicies', - '2.5.29.32.0' => 'anyPolicy', - - '2.5.29.33' => 'id-ce-policyMappings', - '2.5.29.17' => 'id-ce-subjectAltName', - '2.5.29.18' => 'id-ce-issuerAltName', - '2.5.29.9' => 'id-ce-subjectDirectoryAttributes', - '2.5.29.19' => 'id-ce-basicConstraints', - '2.5.29.30' => 'id-ce-nameConstraints', - '2.5.29.36' => 'id-ce-policyConstraints', - '2.5.29.31' => 'id-ce-cRLDistributionPoints', - '2.5.29.37' => 'id-ce-extKeyUsage', - '2.5.29.37.0' => 'anyExtendedKeyUsage', - '1.3.6.1.5.5.7.3.1' => 'id-kp-serverAuth', - '1.3.6.1.5.5.7.3.2' => 'id-kp-clientAuth', - '1.3.6.1.5.5.7.3.3' => 'id-kp-codeSigning', - '1.3.6.1.5.5.7.3.4' => 'id-kp-emailProtection', - '1.3.6.1.5.5.7.3.8' => 'id-kp-timeStamping', - '1.3.6.1.5.5.7.3.9' => 'id-kp-OCSPSigning', - '2.5.29.54' => 'id-ce-inhibitAnyPolicy', - '2.5.29.46' => 'id-ce-freshestCRL', - '1.3.6.1.5.5.7.1.1' => 'id-pe-authorityInfoAccess', - '1.3.6.1.5.5.7.1.11' => 'id-pe-subjectInfoAccess', - '2.5.29.20' => 'id-ce-cRLNumber', - '2.5.29.28' => 'id-ce-issuingDistributionPoint', - '2.5.29.27' => 'id-ce-deltaCRLIndicator', - '2.5.29.21' => 'id-ce-cRLReasons', - '2.5.29.29' => 'id-ce-certificateIssuer', - '2.5.29.23' => 'id-ce-holdInstructionCode', - '1.2.840.10040.2' => 'holdInstruction', - '1.2.840.10040.2.1' => 'id-holdinstruction-none', - '1.2.840.10040.2.2' => 'id-holdinstruction-callissuer', - '1.2.840.10040.2.3' => 'id-holdinstruction-reject', - '2.5.29.24' => 'id-ce-invalidityDate', - - '1.2.840.113549.2.2' => 'md2', - '1.2.840.113549.2.5' => 'md5', - '1.3.14.3.2.26' => 'id-sha1', - '1.2.840.10040.4.1' => 'id-dsa', - '1.2.840.10040.4.3' => 'id-dsa-with-sha1', - '1.2.840.113549.1.1' => 'pkcs-1', - '1.2.840.113549.1.1.1' => 'rsaEncryption', - '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption', - '1.2.840.113549.1.1.4' => 'md5WithRSAEncryption', - '1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption', - '1.2.840.10046.2.1' => 'dhpublicnumber', - '2.16.840.1.101.2.1.1.22' => 'id-keyExchangeAlgorithm', - '1.2.840.10045' => 'ansi-X9-62', - '1.2.840.10045.4' => 'id-ecSigType', - '1.2.840.10045.4.1' => 'ecdsa-with-SHA1', - '1.2.840.10045.1' => 'id-fieldType', - '1.2.840.10045.1.1' => 'prime-field', - '1.2.840.10045.1.2' => 'characteristic-two-field', - '1.2.840.10045.1.2.3' => 'id-characteristic-two-basis', - '1.2.840.10045.1.2.3.1' => 'gnBasis', - '1.2.840.10045.1.2.3.2' => 'tpBasis', - '1.2.840.10045.1.2.3.3' => 'ppBasis', - '1.2.840.10045.2' => 'id-publicKeyType', - '1.2.840.10045.2.1' => 'id-ecPublicKey', - '1.2.840.10045.3' => 'ellipticCurve', - '1.2.840.10045.3.0' => 'c-TwoCurve', - '1.2.840.10045.3.0.1' => 'c2pnb163v1', - '1.2.840.10045.3.0.2' => 'c2pnb163v2', - '1.2.840.10045.3.0.3' => 'c2pnb163v3', - '1.2.840.10045.3.0.4' => 'c2pnb176w1', - '1.2.840.10045.3.0.5' => 'c2pnb191v1', - '1.2.840.10045.3.0.6' => 'c2pnb191v2', - '1.2.840.10045.3.0.7' => 'c2pnb191v3', - '1.2.840.10045.3.0.8' => 'c2pnb191v4', - '1.2.840.10045.3.0.9' => 'c2pnb191v5', - '1.2.840.10045.3.0.10' => 'c2pnb208w1', - '1.2.840.10045.3.0.11' => 'c2pnb239v1', - '1.2.840.10045.3.0.12' => 'c2pnb239v2', - '1.2.840.10045.3.0.13' => 'c2pnb239v3', - '1.2.840.10045.3.0.14' => 'c2pnb239v4', - '1.2.840.10045.3.0.15' => 'c2pnb239v5', - '1.2.840.10045.3.0.16' => 'c2pnb272w1', - '1.2.840.10045.3.0.17' => 'c2pnb304w1', - '1.2.840.10045.3.0.18' => 'c2pnb359v1', - '1.2.840.10045.3.0.19' => 'c2pnb368w1', - '1.2.840.10045.3.0.20' => 'c2pnb431r1', - '1.2.840.10045.3.1' => 'primeCurve', - '1.2.840.10045.3.1.1' => 'prime192v1', - '1.2.840.10045.3.1.2' => 'prime192v2', - '1.2.840.10045.3.1.3' => 'prime192v3', - '1.2.840.10045.3.1.4' => 'prime239v1', - '1.2.840.10045.3.1.5' => 'prime239v2', - '1.2.840.10045.3.1.6' => 'prime239v3', - '1.2.840.10045.3.1.7' => 'prime256v1', - '1.2.840.113549.1.1.7' => 'id-RSAES-OAEP', - '1.2.840.113549.1.1.9' => 'id-pSpecified', - '1.2.840.113549.1.1.10' => 'id-RSASSA-PSS', - '1.2.840.113549.1.1.8' => 'id-mgf1', - '1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption', - '1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption', - '1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption', - '1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption', - '2.16.840.1.101.3.4.2.4' => 'id-sha224', - '2.16.840.1.101.3.4.2.1' => 'id-sha256', - '2.16.840.1.101.3.4.2.2' => 'id-sha384', - '2.16.840.1.101.3.4.2.3' => 'id-sha512', - '1.2.643.2.2.4' => 'id-GostR3411-94-with-GostR3410-94', - '1.2.643.2.2.3' => 'id-GostR3411-94-with-GostR3410-2001', - '1.2.643.2.2.20' => 'id-GostR3410-2001', - '1.2.643.2.2.19' => 'id-GostR3410-94', - // Netscape Object Identifiers from "Netscape Certificate Extensions" - '2.16.840.1.113730' => 'netscape', - '2.16.840.1.113730.1' => 'netscape-cert-extension', - '2.16.840.1.113730.1.1' => 'netscape-cert-type', - '2.16.840.1.113730.1.13' => 'netscape-comment', - '2.16.840.1.113730.1.8' => 'netscape-ca-policy-url', - // the following are X.509 extensions not supported by phpseclib - '1.3.6.1.5.5.7.1.12' => 'id-pe-logotype', - '1.2.840.113533.7.65.0' => 'entrustVersInfo', - '2.16.840.1.113733.1.6.9' => 'verisignPrivate', - // for Certificate Signing Requests - // see http://tools.ietf.org/html/rfc2985 - '1.2.840.113549.1.9.2' => 'pkcs-9-at-unstructuredName', // PKCS #9 unstructured name - '1.2.840.113549.1.9.7' => 'pkcs-9-at-challengePassword', // Challenge password for certificate revocations - '1.2.840.113549.1.9.14' => 'pkcs-9-at-extensionRequest' // Certificate extension request - ); - } - - /** - * Load X.509 certificate - * - * Returns an associative array describing the X.509 cert or a false if the cert failed to load - * - * @param String $cert - * @access public - * @return Mixed - */ - function loadX509($cert) - { - if (is_array($cert) && isset($cert['tbsCertificate'])) { - unset($this->currentCert); - unset($this->currentKeyIdentifier); - $this->dn = $cert['tbsCertificate']['subject']; - if (!isset($this->dn)) { - return false; - } - $this->currentCert = $cert; - - $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier'); - $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null; - - unset($this->signatureSubject); - - return $cert; - } - - $asn1 = new File_ASN1(); - - $cert = $this->_extractBER($cert); - - if ($cert === false) { - $this->currentCert = false; - return false; - } - - $asn1->loadOIDs($this->oids); - $decoded = $asn1->decodeBER($cert); - - if (!empty($decoded)) { - $x509 = $asn1->asn1map($decoded[0], $this->Certificate); - } - if (!isset($x509) || $x509 === false) { - $this->currentCert = false; - return false; - } - - $this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); - - $this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1); - - $key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']; - $key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key); - - $this->currentCert = $x509; - $this->dn = $x509['tbsCertificate']['subject']; - - $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier'); - $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null; - - return $x509; - } - - /** - * Save X.509 certificate - * - * @param Array $cert - * @param Integer $format optional - * @access public - * @return String - */ - function saveX509($cert, $format = FILE_X509_FORMAT_PEM) - { - if (!is_array($cert) || !isset($cert['tbsCertificate'])) { - return false; - } - - switch (true) { - // "case !$a: case !$b: break; default: whatever();" is the same thing as "if ($a && $b) whatever()" - case !($algorithm = $this->_subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')): - case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']): - break; - default: - switch ($algorithm) { - case 'rsaEncryption': - $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] - = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']))); - } - } - - $asn1 = new File_ASN1(); - $asn1->loadOIDs($this->oids); - - $filters = array(); - $type_utf8_string = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string; - $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $type_utf8_string; - $filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $type_utf8_string; - $filters['tbsCertificate']['subject']['rdnSequence']['value'] = $type_utf8_string; - $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $type_utf8_string; - $filters['signatureAlgorithm']['parameters'] = $type_utf8_string; - $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $type_utf8_string; - //$filters['policyQualifiers']['qualifier'] = $type_utf8_string; - $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $type_utf8_string; - $filters['directoryName']['rdnSequence']['value'] = $type_utf8_string; - - /* in the case of policyQualifiers/qualifier, the type has to be FILE_ASN1_TYPE_IA5_STRING. - FILE_ASN1_TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random - characters. - */ - $filters['policyQualifiers']['qualifier'] - = array('type' => FILE_ASN1_TYPE_IA5_STRING); - - $asn1->loadFilters($filters); - - $this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1); - - $cert = $asn1->encodeDER($cert, $this->Certificate); - - switch ($format) { - case FILE_X509_FORMAT_DER: - return $cert; - // case FILE_X509_FORMAT_PEM: - default: - return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert), 64) . '-----END CERTIFICATE-----'; - } - } - - /** - * Map extension values from octet string to extension-specific internal - * format. - * - * @param Array ref $root - * @param String $path - * @param Object $asn1 - * @access private - */ - function _mapInExtensions(&$root, $path, $asn1) - { - $extensions = &$this->_subArray($root, $path); - - if (is_array($extensions)) { - for ($i = 0; $i < count($extensions); $i++) { - $id = $extensions[$i]['extnId']; - $value = &$extensions[$i]['extnValue']; - $value = base64_decode($value); - $decoded = $asn1->decodeBER($value); - /* [extnValue] contains the DER encoding of an ASN.1 value - corresponding to the extension type identified by extnID */ - $map = $this->_getMapping($id); - if (!is_bool($map)) { - $mapped = $asn1->asn1map($decoded[0], $map, array('iPAddress' => array($this, '_decodeIP'))); - $value = $mapped === false ? $decoded[0] : $mapped; - - if ($id == 'id-ce-certificatePolicies') { - for ($j = 0; $j < count($value); $j++) { - if (!isset($value[$j]['policyQualifiers'])) { - continue; - } - for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) { - $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId']; - $map = $this->_getMapping($subid); - $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier']; - if ($map !== false) { - $decoded = $asn1->decodeBER($subvalue); - $mapped = $asn1->asn1map($decoded[0], $map); - $subvalue = $mapped === false ? $decoded[0] : $mapped; - } - } - } - } - } elseif ($map) { - $value = base64_encode($value); - } - } - } - } - - /** - * Map extension values from extension-specific internal format to - * octet string. - * - * @param Array ref $root - * @param String $path - * @param Object $asn1 - * @access private - */ - function _mapOutExtensions(&$root, $path, $asn1) - { - $extensions = &$this->_subArray($root, $path); - - if (is_array($extensions)) { - $size = count($extensions); - for ($i = 0; $i < $size; $i++) { - $id = $extensions[$i]['extnId']; - $value = &$extensions[$i]['extnValue']; - - switch ($id) { - case 'id-ce-certificatePolicies': - for ($j = 0; $j < count($value); $j++) { - if (!isset($value[$j]['policyQualifiers'])) { - continue; - } - for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) { - $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId']; - $map = $this->_getMapping($subid); - $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier']; - if ($map !== false) { - // by default File_ASN1 will try to render qualifier as a FILE_ASN1_TYPE_IA5_STRING since it's - // actual type is FILE_ASN1_TYPE_ANY - $subvalue = new File_ASN1_Element($asn1->encodeDER($subvalue, $map)); - } - } - } - break; - case 'id-ce-authorityKeyIdentifier': // use 00 as the serial number instead of an empty string - if (isset($value['authorityCertSerialNumber'])) { - if ($value['authorityCertSerialNumber']->toBytes() == '') { - $temp = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0"; - $value['authorityCertSerialNumber'] = new File_ASN1_Element($temp); - } - } - } - - /* [extnValue] contains the DER encoding of an ASN.1 value - corresponding to the extension type identified by extnID */ - $map = $this->_getMapping($id); - if (is_bool($map)) { - if (!$map) { - user_error($id . ' is not a currently supported extension'); - unset($extensions[$i]); - } - } else { - $temp = $asn1->encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP'))); - $value = base64_encode($temp); - } - } - } - } - - /** - * Map attribute values from ANY type to attribute-specific internal - * format. - * - * @param Array ref $root - * @param String $path - * @param Object $asn1 - * @access private - */ - function _mapInAttributes(&$root, $path, $asn1) - { - $attributes = &$this->_subArray($root, $path); - - if (is_array($attributes)) { - for ($i = 0; $i < count($attributes); $i++) { - $id = $attributes[$i]['type']; - /* $value contains the DER encoding of an ASN.1 value - corresponding to the attribute type identified by type */ - $map = $this->_getMapping($id); - if (is_array($attributes[$i]['value'])) { - $values = &$attributes[$i]['value']; - for ($j = 0; $j < count($values); $j++) { - $value = $asn1->encodeDER($values[$j], $this->AttributeValue); - $decoded = $asn1->decodeBER($value); - if (!is_bool($map)) { - $mapped = $asn1->asn1map($decoded[0], $map); - if ($mapped !== false) { - $values[$j] = $mapped; - } - if ($id == 'pkcs-9-at-extensionRequest') { - $this->_mapInExtensions($values, $j, $asn1); - } - } elseif ($map) { - $values[$j] = base64_encode($value); - } - } - } - } - } - } - - /** - * Map attribute values from attribute-specific internal format to - * ANY type. - * - * @param Array ref $root - * @param String $path - * @param Object $asn1 - * @access private - */ - function _mapOutAttributes(&$root, $path, $asn1) - { - $attributes = &$this->_subArray($root, $path); - - if (is_array($attributes)) { - $size = count($attributes); - for ($i = 0; $i < $size; $i++) { - /* [value] contains the DER encoding of an ASN.1 value - corresponding to the attribute type identified by type */ - $id = $attributes[$i]['type']; - $map = $this->_getMapping($id); - if ($map === false) { - user_error($id . ' is not a currently supported attribute', E_USER_NOTICE); - unset($attributes[$i]); - } elseif (is_array($attributes[$i]['value'])) { - $values = &$attributes[$i]['value']; - for ($j = 0; $j < count($values); $j++) { - switch ($id) { - case 'pkcs-9-at-extensionRequest': - $this->_mapOutExtensions($values, $j, $asn1); - break; - } - - if (!is_bool($map)) { - $temp = $asn1->encodeDER($values[$j], $map); - $decoded = $asn1->decodeBER($temp); - $values[$j] = $asn1->asn1map($decoded[0], $this->AttributeValue); - } - } - } - } - } - } - - /** - * Associate an extension ID to an extension mapping - * - * @param String $extnId - * @access private - * @return Mixed - */ - function _getMapping($extnId) - { - if (!is_string($extnId)) { // eg. if it's a File_ASN1_Element object - return true; - } - - switch ($extnId) { - case 'id-ce-keyUsage': - return $this->KeyUsage; - case 'id-ce-basicConstraints': - return $this->BasicConstraints; - case 'id-ce-subjectKeyIdentifier': - return $this->KeyIdentifier; - case 'id-ce-cRLDistributionPoints': - return $this->CRLDistributionPoints; - case 'id-ce-authorityKeyIdentifier': - return $this->AuthorityKeyIdentifier; - case 'id-ce-certificatePolicies': - return $this->CertificatePolicies; - case 'id-ce-extKeyUsage': - return $this->ExtKeyUsageSyntax; - case 'id-pe-authorityInfoAccess': - return $this->AuthorityInfoAccessSyntax; - case 'id-ce-subjectAltName': - return $this->SubjectAltName; - case 'id-ce-privateKeyUsagePeriod': - return $this->PrivateKeyUsagePeriod; - case 'id-ce-issuerAltName': - return $this->IssuerAltName; - case 'id-ce-policyMappings': - return $this->PolicyMappings; - case 'id-ce-nameConstraints': - return $this->NameConstraints; - - case 'netscape-cert-type': - return $this->netscape_cert_type; - case 'netscape-comment': - return $this->netscape_comment; - case 'netscape-ca-policy-url': - return $this->netscape_ca_policy_url; - - // since id-qt-cps isn't a constructed type it will have already been decoded as a string by the time it gets - // back around to asn1map() and we don't want it decoded again. - //case 'id-qt-cps': - // return $this->CPSuri; - case 'id-qt-unotice': - return $this->UserNotice; - - // the following OIDs are unsupported but we don't want them to give notices when calling saveX509(). - case 'id-pe-logotype': // http://www.ietf.org/rfc/rfc3709.txt - case 'entrustVersInfo': - // http://support.microsoft.com/kb/287547 - case '1.3.6.1.4.1.311.20.2': // szOID_ENROLL_CERTTYPE_EXTENSION - case '1.3.6.1.4.1.311.21.1': // szOID_CERTSRV_CA_VERSION - // "SET Secure Electronic Transaction Specification" - // http://www.maithean.com/docs/set_bk3.pdf - case '2.23.42.7.0': // id-set-hashedRootKey - return true; - - // CSR attributes - case 'pkcs-9-at-unstructuredName': - return $this->PKCS9String; - case 'pkcs-9-at-challengePassword': - return $this->DirectoryString; - case 'pkcs-9-at-extensionRequest': - return $this->Extensions; - - // CRL extensions. - case 'id-ce-cRLNumber': - return $this->CRLNumber; - case 'id-ce-deltaCRLIndicator': - return $this->CRLNumber; - case 'id-ce-issuingDistributionPoint': - return $this->IssuingDistributionPoint; - case 'id-ce-freshestCRL': - return $this->CRLDistributionPoints; - case 'id-ce-cRLReasons': - return $this->CRLReason; - case 'id-ce-invalidityDate': - return $this->InvalidityDate; - case 'id-ce-certificateIssuer': - return $this->CertificateIssuer; - case 'id-ce-holdInstructionCode': - return $this->HoldInstructionCode; - } - - return false; - } - - /** - * Load an X.509 certificate as a certificate authority - * - * @param String $cert - * @access public - * @return Boolean - */ - function loadCA($cert) - { - $olddn = $this->dn; - $oldcert = $this->currentCert; - $oldsigsubj = $this->signatureSubject; - $oldkeyid = $this->currentKeyIdentifier; - - $cert = $this->loadX509($cert); - if (!$cert) { - $this->dn = $olddn; - $this->currentCert = $oldcert; - $this->signatureSubject = $oldsigsubj; - $this->currentKeyIdentifier = $oldkeyid; - - return false; - } - - /* From RFC5280 "PKIX Certificate and CRL Profile": - - If the keyUsage extension is present, then the subject public key - MUST NOT be used to verify signatures on certificates or CRLs unless - the corresponding keyCertSign or cRLSign bit is set. */ - //$keyUsage = $this->getExtension('id-ce-keyUsage'); - //if ($keyUsage && !in_array('keyCertSign', $keyUsage)) { - // return false; - //} - - /* From RFC5280 "PKIX Certificate and CRL Profile": - - The cA boolean indicates whether the certified public key may be used - to verify certificate signatures. If the cA boolean is not asserted, - then the keyCertSign bit in the key usage extension MUST NOT be - asserted. If the basic constraints extension is not present in a - version 3 certificate, or the extension is present but the cA boolean - is not asserted, then the certified public key MUST NOT be used to - verify certificate signatures. */ - //$basicConstraints = $this->getExtension('id-ce-basicConstraints'); - //if (!$basicConstraints || !$basicConstraints['cA']) { - // return false; - //} - - $this->CAs[] = $cert; - - $this->dn = $olddn; - $this->currentCert = $oldcert; - $this->signatureSubject = $oldsigsubj; - - return true; - } - - /** - * Validate an X.509 certificate against a URL - * - * From RFC2818 "HTTP over TLS": - * - * Matching is performed using the matching rules specified by - * [RFC2459]. If more than one identity of a given type is present in - * the certificate (e.g., more than one dNSName name, a match in any one - * of the set is considered acceptable.) Names may contain the wildcard - * character * which is considered to match any single domain name - * component or component fragment. E.g., *.a.com matches foo.a.com but - * not bar.foo.a.com. f*.com matches foo.com but not bar.com. - * - * @param String $url - * @access public - * @return Boolean - */ - function validateURL($url) - { - if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) { - return false; - } - - $components = parse_url($url); - if (!isset($components['host'])) { - return false; - } - - if ($names = $this->getExtension('id-ce-subjectAltName')) { - foreach ($names as $key => $value) { - $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value); - switch ($key) { - case 'dNSName': - /* From RFC2818 "HTTP over TLS": - - If a subjectAltName extension of type dNSName is present, that MUST - be used as the identity. Otherwise, the (most specific) Common Name - field in the Subject field of the certificate MUST be used. Although - the use of the Common Name is existing practice, it is deprecated and - Certification Authorities are encouraged to use the dNSName instead. */ - if (preg_match('#^' . $value . '$#', $components['host'])) { - return true; - } - break; - case 'iPAddress': - /* From RFC2818 "HTTP over TLS": - - In some cases, the URI is specified as an IP address rather than a - hostname. In this case, the iPAddress subjectAltName must be present - in the certificate and must exactly match the IP in the URI. */ - if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) { - return true; - } - } - } - return false; - } - - if ($value = $this->getDNProp('id-at-commonName')) { - $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value[0]); - return preg_match('#^' . $value . '$#', $components['host']); - } - - return false; - } - - /** - * Validate a date - * - * If $date isn't defined it is assumed to be the current date. - * - * @param Integer $date optional - * @access public - */ - function validateDate($date = null) - { - if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) { - return false; - } - - if (!isset($date)) { - $date = time(); - } - - $notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore']; - $notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime']; - - $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter']; - $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime']; - - switch (true) { - case $date < @strtotime($notBefore): - case $date > @strtotime($notAfter): - return false; - } - - return true; - } - - /** - * Validate a signature - * - * Works on X.509 certs, CSR's and CRL's. - * Returns true if the signature is verified, false if it is not correct or null on error - * - * By default returns false for self-signed certs. Call validateSignature(false) to make this support - * self-signed. - * - * The behavior of this function is inspired by {@link http://php.net/openssl-verify openssl_verify}. - * - * @param Boolean $caonly optional - * @access public - * @return Mixed - */ - function validateSignature($caonly = true) - { - if (!is_array($this->currentCert) || !isset($this->signatureSubject)) { - return null; - } - - /* TODO: - "emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")." - -- http://tools.ietf.org/html/rfc5280#section-4.1.2.6 - - implement pathLenConstraint in the id-ce-basicConstraints extension */ - - switch (true) { - case isset($this->currentCert['tbsCertificate']): - // self-signed cert - if ($this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']) { - $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier'); - $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier'); - switch (true) { - case !is_array($authorityKey): - case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: - $signingCert = $this->currentCert; // working cert - } - } - - if (!empty($this->CAs)) { - for ($i = 0; $i < count($this->CAs); $i++) { - // even if the cert is a self-signed one we still want to see if it's a CA; - // if not, we'll conditionally return an error - $ca = $this->CAs[$i]; - if ($this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) { - $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier'); - $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca); - switch (true) { - case !is_array($authorityKey): - case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: - $signingCert = $ca; // working cert - break 2; - } - } - } - if (count($this->CAs) == $i && $caonly) { - return false; - } - } elseif (!isset($signingCert) || $caonly) { - return false; - } - return $this->_validateSignature( - $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], - $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], - $this->currentCert['signatureAlgorithm']['algorithm'], - substr(base64_decode($this->currentCert['signature']), 1), - $this->signatureSubject - ); - case isset($this->currentCert['certificationRequestInfo']): - return $this->_validateSignature( - $this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'], - $this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], - $this->currentCert['signatureAlgorithm']['algorithm'], - substr(base64_decode($this->currentCert['signature']), 1), - $this->signatureSubject - ); - case isset($this->currentCert['publicKeyAndChallenge']): - return $this->_validateSignature( - $this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'], - $this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'], - $this->currentCert['signatureAlgorithm']['algorithm'], - substr(base64_decode($this->currentCert['signature']), 1), - $this->signatureSubject - ); - case isset($this->currentCert['tbsCertList']): - if (!empty($this->CAs)) { - for ($i = 0; $i < count($this->CAs); $i++) { - $ca = $this->CAs[$i]; - if ($this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']) { - $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier'); - $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca); - switch (true) { - case !is_array($authorityKey): - case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: - $signingCert = $ca; // working cert - break 2; - } - } - } - } - if (!isset($signingCert)) { - return false; - } - return $this->_validateSignature( - $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], - $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], - $this->currentCert['signatureAlgorithm']['algorithm'], - substr(base64_decode($this->currentCert['signature']), 1), - $this->signatureSubject - ); - default: - return false; - } - } - - /** - * Validates a signature - * - * Returns true if the signature is verified, false if it is not correct or null on error - * - * @param String $publicKeyAlgorithm - * @param String $publicKey - * @param String $signatureAlgorithm - * @param String $signature - * @param String $signatureSubject - * @access private - * @return Integer - */ - function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject) - { - switch ($publicKeyAlgorithm) { - case 'rsaEncryption': - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $rsa = new Crypt_RSA(); - $rsa->loadKey($publicKey); - - switch ($signatureAlgorithm) { - case 'md2WithRSAEncryption': - case 'md5WithRSAEncryption': - case 'sha1WithRSAEncryption': - case 'sha224WithRSAEncryption': - case 'sha256WithRSAEncryption': - case 'sha384WithRSAEncryption': - case 'sha512WithRSAEncryption': - $rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm)); - $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); - if (!@$rsa->verify($signatureSubject, $signature)) { - return false; - } - break; - default: - return null; - } - break; - default: - return null; - } - - return true; - } - - /** - * Reformat public keys - * - * Reformats a public key to a format supported by phpseclib (if applicable) - * - * @param String $algorithm - * @param String $key - * @access private - * @return String - */ - function _reformatKey($algorithm, $key) - { - switch ($algorithm) { - case 'rsaEncryption': - return - "-----BEGIN RSA PUBLIC KEY-----\r\n" . - // subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits - // in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox - // uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do. - chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) . - '-----END RSA PUBLIC KEY-----'; - default: - return $key; - } - } - - /** - * Decodes an IP address - * - * Takes in a base64 encoded "blob" and returns a human readable IP address - * - * @param String $ip - * @access private - * @return String - */ - function _decodeIP($ip) - { - $ip = base64_decode($ip); - list(, $ip) = unpack('N', $ip); - return long2ip($ip); - } - - /** - * Encodes an IP address - * - * Takes a human readable IP address into a base64-encoded "blob" - * - * @param String $ip - * @access private - * @return String - */ - function _encodeIP($ip) - { - return base64_encode(pack('N', ip2long($ip))); - } - - /** - * "Normalizes" a Distinguished Name property - * - * @param String $propName - * @access private - * @return Mixed - */ - function _translateDNProp($propName) - { - switch (strtolower($propName)) { - case 'id-at-countryname': - case 'countryname': - case 'c': - return 'id-at-countryName'; - case 'id-at-organizationname': - case 'organizationname': - case 'o': - return 'id-at-organizationName'; - case 'id-at-dnqualifier': - case 'dnqualifier': - return 'id-at-dnQualifier'; - case 'id-at-commonname': - case 'commonname': - case 'cn': - return 'id-at-commonName'; - case 'id-at-stateorprovincename': - case 'stateorprovincename': - case 'state': - case 'province': - case 'provincename': - case 'st': - return 'id-at-stateOrProvinceName'; - case 'id-at-localityname': - case 'localityname': - case 'l': - return 'id-at-localityName'; - case 'id-emailaddress': - case 'emailaddress': - return 'pkcs-9-at-emailAddress'; - case 'id-at-serialnumber': - case 'serialnumber': - return 'id-at-serialNumber'; - case 'id-at-postalcode': - case 'postalcode': - return 'id-at-postalCode'; - case 'id-at-streetaddress': - case 'streetaddress': - return 'id-at-streetAddress'; - case 'id-at-name': - case 'name': - return 'id-at-name'; - case 'id-at-givenname': - case 'givenname': - return 'id-at-givenName'; - case 'id-at-surname': - case 'surname': - case 'sn': - return 'id-at-surname'; - case 'id-at-initials': - case 'initials': - return 'id-at-initials'; - case 'id-at-generationqualifier': - case 'generationqualifier': - return 'id-at-generationQualifier'; - case 'id-at-organizationalunitname': - case 'organizationalunitname': - case 'ou': - return 'id-at-organizationalUnitName'; - case 'id-at-pseudonym': - case 'pseudonym': - return 'id-at-pseudonym'; - case 'id-at-title': - case 'title': - return 'id-at-title'; - case 'id-at-description': - case 'description': - return 'id-at-description'; - case 'id-at-role': - case 'role': - return 'id-at-role'; - case 'id-at-uniqueidentifier': - case 'uniqueidentifier': - case 'x500uniqueidentifier': - return 'id-at-uniqueIdentifier'; - default: - return false; - } - } - - /** - * Set a Distinguished Name property - * - * @param String $propName - * @param Mixed $propValue - * @param String $type optional - * @access public - * @return Boolean - */ - function setDNProp($propName, $propValue, $type = 'utf8String') - { - if (empty($this->dn)) { - $this->dn = array('rdnSequence' => array()); - } - - if (($propName = $this->_translateDNProp($propName)) === false) { - return false; - } - - foreach ((array) $propValue as $v) { - if (!is_array($v) && isset($type)) { - $v = array($type => $v); - } - $this->dn['rdnSequence'][] = array( - array( - 'type' => $propName, - 'value'=> $v - ) - ); - } - - return true; - } - - /** - * Remove Distinguished Name properties - * - * @param String $propName - * @access public - */ - function removeDNProp($propName) - { - if (empty($this->dn)) { - return; - } - - if (($propName = $this->_translateDNProp($propName)) === false) { - return; - } - - $dn = &$this->dn['rdnSequence']; - $size = count($dn); - for ($i = 0; $i < $size; $i++) { - if ($dn[$i][0]['type'] == $propName) { - unset($dn[$i]); - } - } - - $dn = array_values($dn); - } - - /** - * Get Distinguished Name properties - * - * @param String $propName - * @param Array $dn optional - * @param Boolean $withType optional - * @return Mixed - * @access public - */ - function getDNProp($propName, $dn = null, $withType = false) - { - if (!isset($dn)) { - $dn = $this->dn; - } - - if (empty($dn)) { - return false; - } - - if (($propName = $this->_translateDNProp($propName)) === false) { - return false; - } - - $dn = $dn['rdnSequence']; - $result = array(); - $asn1 = new File_ASN1(); - for ($i = 0; $i < count($dn); $i++) { - if ($dn[$i][0]['type'] == $propName) { - $v = $dn[$i][0]['value']; - if (!$withType && is_array($v)) { - foreach ($v as $type => $s) { - $type = array_search($type, $asn1->ANYmap, true); - if ($type !== false && isset($asn1->stringTypeSize[$type])) { - $s = $asn1->convert($s, $type); - if ($s !== false) { - $v = $s; - break; - } - } - } - if (is_array($v)) { - $v = array_pop($v); // Always strip data type. - } - } - $result[] = $v; - } - } - - return $result; - } - - /** - * Set a Distinguished Name - * - * @param Mixed $dn - * @param Boolean $merge optional - * @param String $type optional - * @access public - * @return Boolean - */ - function setDN($dn, $merge = false, $type = 'utf8String') - { - if (!$merge) { - $this->dn = null; - } - - if (is_array($dn)) { - if (isset($dn['rdnSequence'])) { - $this->dn = $dn; // No merge here. - return true; - } - - // handles stuff generated by openssl_x509_parse() - foreach ($dn as $prop => $value) { - if (!$this->setDNProp($prop, $value, $type)) { - return false; - } - } - return true; - } - - // handles everything else - $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE); - for ($i = 1; $i < count($results); $i+=2) { - $prop = trim($results[$i], ', =/'); - $value = $results[$i + 1]; - if (!$this->setDNProp($prop, $value, $type)) { - return false; - } - } - - return true; - } - - /** - * Get the Distinguished Name for a certificates subject - * - * @param Mixed $format optional - * @param Array $dn optional - * @access public - * @return Boolean - */ - function getDN($format = FILE_X509_DN_ARRAY, $dn = null) - { - if (!isset($dn)) { - $dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn; - } - - switch ((int) $format) { - case FILE_X509_DN_ARRAY: - return $dn; - case FILE_X509_DN_ASN1: - $asn1 = new File_ASN1(); - $asn1->loadOIDs($this->oids); - $filters = array(); - $filters['rdnSequence']['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $asn1->loadFilters($filters); - return $asn1->encodeDER($dn, $this->Name); - case FILE_X509_DN_OPENSSL: - $dn = $this->getDN(FILE_X509_DN_STRING, $dn); - if ($dn === false) { - return false; - } - $attrs = preg_split('#((?:^|, *|/)[a-z][a-z0-9]*=)#i', $dn, -1, PREG_SPLIT_DELIM_CAPTURE); - $dn = array(); - for ($i = 1; $i < count($attrs); $i += 2) { - $prop = trim($attrs[$i], ', =/'); - $value = $attrs[$i + 1]; - if (!isset($dn[$prop])) { - $dn[$prop] = $value; - } else { - $dn[$prop] = array_merge((array) $dn[$prop], array($value)); - } - } - return $dn; - case FILE_X509_DN_CANON: - // No SEQUENCE around RDNs and all string values normalized as - // trimmed lowercase UTF-8 with all spacing as one blank. - $asn1 = new File_ASN1(); - $asn1->loadOIDs($this->oids); - $filters = array(); - $filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $asn1->loadFilters($filters); - $result = ''; - foreach ($dn['rdnSequence'] as $rdn) { - foreach ($rdn as $i=>$attr) { - $attr = &$rdn[$i]; - if (is_array($attr['value'])) { - foreach ($attr['value'] as $type => $v) { - $type = array_search($type, $asn1->ANYmap, true); - if ($type !== false && isset($asn1->stringTypeSize[$type])) { - $v = $asn1->convert($v, $type); - if ($v !== false) { - $v = preg_replace('/\s+/', ' ', $v); - $attr['value'] = strtolower(trim($v)); - break; - } - } - } - } - } - $result .= $asn1->encodeDER($rdn, $this->RelativeDistinguishedName); - } - return $result; - case FILE_X509_DN_HASH: - $dn = $this->getDN(FILE_X509_DN_CANON, $dn); - if (!class_exists('Crypt_Hash')) { - include_once 'Crypt/Hash.php'; - } - $hash = new Crypt_Hash('sha1'); - $hash = $hash->hash($dn); - extract(unpack('Vhash', $hash)); - return strtolower(bin2hex(pack('N', $hash))); - } - - // Default is to return a string. - $start = true; - $output = ''; - $asn1 = new File_ASN1(); - foreach ($dn['rdnSequence'] as $field) { - $prop = $field[0]['type']; - $value = $field[0]['value']; - - $delim = ', '; - switch ($prop) { - case 'id-at-countryName': - $desc = 'C='; - break; - case 'id-at-stateOrProvinceName': - $desc = 'ST='; - break; - case 'id-at-organizationName': - $desc = 'O='; - break; - case 'id-at-organizationalUnitName': - $desc = 'OU='; - break; - case 'id-at-commonName': - $desc = 'CN='; - break; - case 'id-at-localityName': - $desc = 'L='; - break; - case 'id-at-surname': - $desc = 'SN='; - break; - case 'id-at-uniqueIdentifier': - $delim = '/'; - $desc = 'x500UniqueIdentifier='; - break; - default: - $delim = '/'; - $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop) . '='; - } - - if (!$start) { - $output.= $delim; - } - if (is_array($value)) { - foreach ($value as $type => $v) { - $type = array_search($type, $asn1->ANYmap, true); - if ($type !== false && isset($asn1->stringTypeSize[$type])) { - $v = $asn1->convert($v, $type); - if ($v !== false) { - $value = $v; - break; - } - } - } - if (is_array($value)) { - $value = array_pop($value); // Always strip data type. - } - } - $output.= $desc . $value; - $start = false; - } - - return $output; - } - - /** - * Get the Distinguished Name for a certificate/crl issuer - * - * @param Integer $format optional - * @access public - * @return Mixed - */ - function getIssuerDN($format = FILE_X509_DN_ARRAY) - { - switch (true) { - case !isset($this->currentCert) || !is_array($this->currentCert): - break; - case isset($this->currentCert['tbsCertificate']): - return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']); - case isset($this->currentCert['tbsCertList']): - return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']); - } - - return false; - } - - /** - * Get the Distinguished Name for a certificate/csr subject - * Alias of getDN() - * - * @param Integer $format optional - * @access public - * @return Mixed - */ - function getSubjectDN($format = FILE_X509_DN_ARRAY) - { - switch (true) { - case !empty($this->dn): - return $this->getDN($format); - case !isset($this->currentCert) || !is_array($this->currentCert): - break; - case isset($this->currentCert['tbsCertificate']): - return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']); - case isset($this->currentCert['certificationRequestInfo']): - return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']); - } - - return false; - } - - /** - * Get an individual Distinguished Name property for a certificate/crl issuer - * - * @param String $propName - * @param Boolean $withType optional - * @access public - * @return Mixed - */ - function getIssuerDNProp($propName, $withType = false) - { - switch (true) { - case !isset($this->currentCert) || !is_array($this->currentCert): - break; - case isset($this->currentCert['tbsCertificate']): - return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType); - case isset($this->currentCert['tbsCertList']): - return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType); - } - - return false; - } - - /** - * Get an individual Distinguished Name property for a certificate/csr subject - * - * @param String $propName - * @param Boolean $withType optional - * @access public - * @return Mixed - */ - function getSubjectDNProp($propName, $withType = false) - { - switch (true) { - case !empty($this->dn): - return $this->getDNProp($propName, null, $withType); - case !isset($this->currentCert) || !is_array($this->currentCert): - break; - case isset($this->currentCert['tbsCertificate']): - return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType); - case isset($this->currentCert['certificationRequestInfo']): - return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType); - } - - return false; - } - - /** - * Get the certificate chain for the current cert - * - * @access public - * @return Mixed - */ - function getChain() - { - $chain = array($this->currentCert); - - if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) { - return false; - } - if (empty($this->CAs)) { - return $chain; - } - while (true) { - $currentCert = $chain[count($chain) - 1]; - for ($i = 0; $i < count($this->CAs); $i++) { - $ca = $this->CAs[$i]; - if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) { - $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert); - $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca); - switch (true) { - case !is_array($authorityKey): - case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: - if ($currentCert === $ca) { - break 3; - } - $chain[] = $ca; - break 2; - } - } - } - if ($i == count($this->CAs)) { - break; - } - } - foreach ($chain as $key=>$value) { - $chain[$key] = new File_X509(); - $chain[$key]->loadX509($value); - } - return $chain; - } - - /** - * Set public key - * - * Key needs to be a Crypt_RSA object - * - * @param Object $key - * @access public - * @return Boolean - */ - function setPublicKey($key) - { - $key->setPublicKey(); - $this->publicKey = $key; - } - - /** - * Set private key - * - * Key needs to be a Crypt_RSA object - * - * @param Object $key - * @access public - */ - function setPrivateKey($key) - { - $this->privateKey = $key; - } - - /** - * Set challenge - * - * Used for SPKAC CSR's - * - * @param String $challenge - * @access public - */ - function setChallenge($challenge) - { - $this->challenge = $challenge; - } - - /** - * Gets the public key - * - * Returns a Crypt_RSA object or a false. - * - * @access public - * @return Mixed - */ - function getPublicKey() - { - if (isset($this->publicKey)) { - return $this->publicKey; - } - - if (isset($this->currentCert) && is_array($this->currentCert)) { - foreach (array('tbsCertificate/subjectPublicKeyInfo', 'certificationRequestInfo/subjectPKInfo') as $path) { - $keyinfo = $this->_subArray($this->currentCert, $path); - if (!empty($keyinfo)) { - break; - } - } - } - if (empty($keyinfo)) { - return false; - } - - $key = $keyinfo['subjectPublicKey']; - - switch ($keyinfo['algorithm']['algorithm']) { - case 'rsaEncryption': - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $publicKey = new Crypt_RSA(); - $publicKey->loadKey($key); - $publicKey->setPublicKey(); - break; - default: - return false; - } - - return $publicKey; - } - - /** - * Load a Certificate Signing Request - * - * @param String $csr - * @access public - * @return Mixed - */ - function loadCSR($csr) - { - if (is_array($csr) && isset($csr['certificationRequestInfo'])) { - unset($this->currentCert); - unset($this->currentKeyIdentifier); - unset($this->signatureSubject); - $this->dn = $csr['certificationRequestInfo']['subject']; - if (!isset($this->dn)) { - return false; - } - - $this->currentCert = $csr; - return $csr; - } - - // see http://tools.ietf.org/html/rfc2986 - - $asn1 = new File_ASN1(); - - $csr = $this->_extractBER($csr); - $orig = $csr; - - if ($csr === false) { - $this->currentCert = false; - return false; - } - - $asn1->loadOIDs($this->oids); - $decoded = $asn1->decodeBER($csr); - - if (empty($decoded)) { - $this->currentCert = false; - return false; - } - - $csr = $asn1->asn1map($decoded[0], $this->CertificationRequest); - if (!isset($csr) || $csr === false) { - $this->currentCert = false; - return false; - } - - $this->dn = $csr['certificationRequestInfo']['subject']; - $this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1); - - $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); - - $algorithm = &$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm']; - $key = &$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']; - $key = $this->_reformatKey($algorithm, $key); - - switch ($algorithm) { - case 'rsaEncryption': - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $this->publicKey = new Crypt_RSA(); - $this->publicKey->loadKey($key); - $this->publicKey->setPublicKey(); - break; - default: - $this->publicKey = null; - } - - $this->currentKeyIdentifier = null; - $this->currentCert = $csr; - - return $csr; - } - - /** - * Save CSR request - * - * @param Array $csr - * @param Integer $format optional - * @access public - * @return String - */ - function saveCSR($csr, $format = FILE_X509_FORMAT_PEM) - { - if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) { - return false; - } - - switch (true) { - case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')): - case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']); - break; - default: - switch ($algorithm) { - case 'rsaEncryption': - $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'] - = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']))); - } - } - - $asn1 = new File_ASN1(); - - $asn1->loadOIDs($this->oids); - - $filters = array(); - $filters['certificationRequestInfo']['subject']['rdnSequence']['value'] - = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - - $asn1->loadFilters($filters); - - $this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1); - $csr = $asn1->encodeDER($csr, $this->CertificationRequest); - - switch ($format) { - case FILE_X509_FORMAT_DER: - return $csr; - // case FILE_X509_FORMAT_PEM: - default: - return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----'; - } - } - - /** - * Load a SPKAC CSR - * - * SPKAC's are produced by the HTML5 keygen element: - * - * https://developer.mozilla.org/en-US/docs/HTML/Element/keygen - * - * @param String $csr - * @access public - * @return Mixed - */ - function loadSPKAC($spkac) - { - if (is_array($spkac) && isset($spkac['publicKeyAndChallenge'])) { - unset($this->currentCert); - unset($this->currentKeyIdentifier); - unset($this->signatureSubject); - $this->currentCert = $spkac; - return $spkac; - } - - // see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge - - $asn1 = new File_ASN1(); - - // OpenSSL produces SPKAC's that are preceeded by the string SPKAC= - $temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac); - $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; - if ($temp != false) { - $spkac = $temp; - } - $orig = $spkac; - - if ($spkac === false) { - $this->currentCert = false; - return false; - } - - $asn1->loadOIDs($this->oids); - $decoded = $asn1->decodeBER($spkac); - - if (empty($decoded)) { - $this->currentCert = false; - return false; - } - - $spkac = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge); - - if (!isset($spkac) || $spkac === false) { - $this->currentCert = false; - return false; - } - - $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); - - $algorithm = &$spkac['publicKeyAndChallenge']['spki']['algorithm']['algorithm']; - $key = &$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']; - $key = $this->_reformatKey($algorithm, $key); - - switch ($algorithm) { - case 'rsaEncryption': - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $this->publicKey = new Crypt_RSA(); - $this->publicKey->loadKey($key); - $this->publicKey->setPublicKey(); - break; - default: - $this->publicKey = null; - } - - $this->currentKeyIdentifier = null; - $this->currentCert = $spkac; - - return $spkac; - } - - /** - * Save a SPKAC CSR request - * - * @param Array $csr - * @param Integer $format optional - * @access public - * @return String - */ - function saveSPKAC($spkac, $format = FILE_X509_FORMAT_PEM) - { - if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) { - return false; - } - - $algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm'); - switch (true) { - case !$algorithm: - case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']); - break; - default: - switch ($algorithm) { - case 'rsaEncryption': - $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'] - = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']))); - } - } - - $asn1 = new File_ASN1(); - - $asn1->loadOIDs($this->oids); - $spkac = $asn1->encodeDER($spkac, $this->SignedPublicKeyAndChallenge); - - switch ($format) { - case FILE_X509_FORMAT_DER: - return $spkac; - // case FILE_X509_FORMAT_PEM: - default: - // OpenSSL's implementation of SPKAC requires the SPKAC be preceeded by SPKAC= and since there are pretty much - // no other SPKAC decoders phpseclib will use that same format - return 'SPKAC=' . base64_encode($spkac); - } - } - - /** - * Load a Certificate Revocation List - * - * @param String $crl - * @access public - * @return Mixed - */ - function loadCRL($crl) - { - if (is_array($crl) && isset($crl['tbsCertList'])) { - $this->currentCert = $crl; - unset($this->signatureSubject); - return $crl; - } - - $asn1 = new File_ASN1(); - - $crl = $this->_extractBER($crl); - $orig = $crl; - - if ($crl === false) { - $this->currentCert = false; - return false; - } - - $asn1->loadOIDs($this->oids); - $decoded = $asn1->decodeBER($crl); - - if (empty($decoded)) { - $this->currentCert = false; - return false; - } - - $crl = $asn1->asn1map($decoded[0], $this->CertificateList); - if (!isset($crl) || $crl === false) { - $this->currentCert = false; - return false; - } - - $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); - - $this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1); - $rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates'); - if (is_array($rclist)) { - foreach ($rclist as $i => $extension) { - $this->_mapInExtensions($rclist, "$i/crlEntryExtensions", $asn1); - } - } - - $this->currentKeyIdentifier = null; - $this->currentCert = $crl; - - return $crl; - } - - /** - * Save Certificate Revocation List. - * - * @param Array $crl - * @param Integer $format optional - * @access public - * @return String - */ - function saveCRL($crl, $format = FILE_X509_FORMAT_PEM) - { - if (!is_array($crl) || !isset($crl['tbsCertList'])) { - return false; - } - - $asn1 = new File_ASN1(); - - $asn1->loadOIDs($this->oids); - - $filters = array(); - $filters['tbsCertList']['issuer']['rdnSequence']['value'] - = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $filters['tbsCertList']['signature']['parameters'] - = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $filters['signatureAlgorithm']['parameters'] - = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - - if (empty($crl['tbsCertList']['signature']['parameters'])) { - $filters['tbsCertList']['signature']['parameters'] - = array('type' => FILE_ASN1_TYPE_NULL); - } - - if (empty($crl['signatureAlgorithm']['parameters'])) { - $filters['signatureAlgorithm']['parameters'] - = array('type' => FILE_ASN1_TYPE_NULL); - } - - $asn1->loadFilters($filters); - - $this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1); - $rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates'); - if (is_array($rclist)) { - foreach ($rclist as $i => $extension) { - $this->_mapOutExtensions($rclist, "$i/crlEntryExtensions", $asn1); - } - } - - $crl = $asn1->encodeDER($crl, $this->CertificateList); - - switch ($format) { - case FILE_X509_FORMAT_DER: - return $crl; - // case FILE_X509_FORMAT_PEM: - default: - return "-----BEGIN X509 CRL-----\r\n" . chunk_split(base64_encode($crl), 64) . '-----END X509 CRL-----'; - } - } - - /** - * Helper function to build a time field according to RFC 3280 section - * - 4.1.2.5 Validity - * - 5.1.2.4 This Update - * - 5.1.2.5 Next Update - * - 5.1.2.6 Revoked Certificates - * by choosing utcTime iff year of date given is before 2050 and generalTime else. - * - * @param String $date in format date('D, d M Y H:i:s O') - * @access private - * @return Array - */ - function _timeField($date) - { - $year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this - if ($year < 2050) { - return array('utcTime' => $date); - } else { - return array('generalTime' => $date); - } - } - - /** - * Sign an X.509 certificate - * - * $issuer's private key needs to be loaded. - * $subject can be either an existing X.509 cert (if you want to resign it), - * a CSR or something with the DN and public key explicitly set. - * - * @param File_X509 $issuer - * @param File_X509 $subject - * @param String $signatureAlgorithm optional - * @access public - * @return Mixed - */ - function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption') - { - if (!is_object($issuer->privateKey) || empty($issuer->dn)) { - return false; - } - - if (isset($subject->publicKey) && !($subjectPublicKey = $subject->_formatSubjectPublicKey())) { - return false; - } - - $currentCert = isset($this->currentCert) ? $this->currentCert : null; - $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null; - - if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) { - $this->currentCert = $subject->currentCert; - $this->currentCert['tbsCertificate']['signature']['algorithm'] = $signatureAlgorithm; - $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; - - if (!empty($this->startDate)) { - $this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate); - } - if (!empty($this->endDate)) { - $this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate); - } - if (!empty($this->serialNumber)) { - $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber; - } - if (!empty($subject->dn)) { - $this->currentCert['tbsCertificate']['subject'] = $subject->dn; - } - if (!empty($subject->publicKey)) { - $this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey; - } - $this->removeExtension('id-ce-authorityKeyIdentifier'); - if (isset($subject->domains)) { - $this->removeExtension('id-ce-subjectAltName'); - } - } else if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) { - return false; - } else { - if (!isset($subject->publicKey)) { - return false; - } - - $startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O'); - $endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year')); - $serialNumber = !empty($this->serialNumber) ? $this->serialNumber : new Math_BigInteger(); - - $this->currentCert = array( - 'tbsCertificate' => - array( - 'version' => 'v3', - 'serialNumber' => $serialNumber, // $this->setserialNumber() - 'signature' => array('algorithm' => $signatureAlgorithm), - 'issuer' => false, // this is going to be overwritten later - 'validity' => array( - 'notBefore' => $this->_timeField($startDate), // $this->setStartDate() - 'notAfter' => $this->_timeField($endDate) // $this->setEndDate() - ), - 'subject' => $subject->dn, - 'subjectPublicKeyInfo' => $subjectPublicKey - ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later - ); - - // Copy extensions from CSR. - $csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0); - - if (!empty($csrexts)) { - $this->currentCert['tbsCertificate']['extensions'] = $csrexts; - } - } - - $this->currentCert['tbsCertificate']['issuer'] = $issuer->dn; - - if (isset($issuer->currentKeyIdentifier)) { - $this->setExtension('id-ce-authorityKeyIdentifier', array( - //'authorityCertIssuer' => array( - // array( - // 'directoryName' => $issuer->dn - // ) - //), - 'keyIdentifier' => $issuer->currentKeyIdentifier - ) - ); - //$extensions = &$this->currentCert['tbsCertificate']['extensions']; - //if (isset($issuer->serialNumber)) { - // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber; - //} - //unset($extensions); - } - - if (isset($subject->currentKeyIdentifier)) { - $this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier); - } - - $altName = array(); - - if (isset($subject->domains) && count($subject->domains) > 1) { - $altName = array_map(array('File_X509', '_dnsName'), $subject->domains); - } - - if (isset($subject->ipAddresses) && count($subject->ipAddresses)) { - // should an IP address appear as the CN if no domain name is specified? idk - //$ips = count($subject->domains) ? $subject->ipAddresses : array_slice($subject->ipAddresses, 1); - $ipAddresses = array(); - foreach ($subject->ipAddresses as $ipAddress) { - $encoded = $subject->_ipAddress($ipAddress); - if ($encoded !== false) { - $ipAddresses[] = $encoded; - } - } - if (count($ipAddresses)) { - $altName = array_merge($altName, $ipAddresses); - } - } - - if (!empty($altName)) { - $this->setExtension('id-ce-subjectAltName', $altName); - } - - if ($this->caFlag) { - $keyUsage = $this->getExtension('id-ce-keyUsage'); - if (!$keyUsage) { - $keyUsage = array(); - } - - $this->setExtension('id-ce-keyUsage', - array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign')))) - ); - - $basicConstraints = $this->getExtension('id-ce-basicConstraints'); - if (!$basicConstraints) { - $basicConstraints = array(); - } - - $this->setExtension('id-ce-basicConstraints', - array_unique(array_merge(array('cA' => true), $basicConstraints)), true); - - if (!isset($subject->currentKeyIdentifier)) { - $this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false); - } - } - - // resync $this->signatureSubject - // save $tbsCertificate in case there are any File_ASN1_Element objects in it - $tbsCertificate = $this->currentCert['tbsCertificate']; - $this->loadX509($this->saveX509($this->currentCert)); - - $result = $this->_sign($issuer->privateKey, $signatureAlgorithm); - $result['tbsCertificate'] = $tbsCertificate; - - $this->currentCert = $currentCert; - $this->signatureSubject = $signatureSubject; - - return $result; - } - - /** - * Sign a CSR - * - * @access public - * @return Mixed - */ - function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption') - { - if (!is_object($this->privateKey) || empty($this->dn)) { - return false; - } - - $origPublicKey = $this->publicKey; - $class = get_class($this->privateKey); - $this->publicKey = new $class(); - $this->publicKey->loadKey($this->privateKey->getPublicKey()); - $this->publicKey->setPublicKey(); - if (!($publicKey = $this->_formatSubjectPublicKey())) { - return false; - } - $this->publicKey = $origPublicKey; - - $currentCert = isset($this->currentCert) ? $this->currentCert : null; - $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null; - - if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) { - $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; - if (!empty($this->dn)) { - $this->currentCert['certificationRequestInfo']['subject'] = $this->dn; - } - $this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey; - } else { - $this->currentCert = array( - 'certificationRequestInfo' => - array( - 'version' => 'v1', - 'subject' => $this->dn, - 'subjectPKInfo' => $publicKey - ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later - ); - } - - // resync $this->signatureSubject - // save $certificationRequestInfo in case there are any File_ASN1_Element objects in it - $certificationRequestInfo = $this->currentCert['certificationRequestInfo']; - $this->loadCSR($this->saveCSR($this->currentCert)); - - $result = $this->_sign($this->privateKey, $signatureAlgorithm); - $result['certificationRequestInfo'] = $certificationRequestInfo; - - $this->currentCert = $currentCert; - $this->signatureSubject = $signatureSubject; - - return $result; - } - - /** - * Sign a SPKAC - * - * @access public - * @return Mixed - */ - function signSPKAC($signatureAlgorithm = 'sha1WithRSAEncryption') - { - if (!is_object($this->privateKey)) { - return false; - } - - $origPublicKey = $this->publicKey; - $class = get_class($this->privateKey); - $this->publicKey = new $class(); - $this->publicKey->loadKey($this->privateKey->getPublicKey()); - $this->publicKey->setPublicKey(); - $publicKey = $this->_formatSubjectPublicKey(); - if (!$publicKey) { - return false; - } - $this->publicKey = $origPublicKey; - - $currentCert = isset($this->currentCert) ? $this->currentCert : null; - $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null; - - // re-signing a SPKAC seems silly but since everything else supports re-signing why not? - if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) { - $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; - $this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey; - if (!empty($this->challenge)) { - // the bitwise AND ensures that the output is a valid IA5String - $this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge)); - } - } else { - $this->currentCert = array( - 'publicKeyAndChallenge' => - array( - 'spki' => $publicKey, - // quoting , - // "A challenge string that is submitted along with the public key. Defaults to an empty string if not specified." - // both Firefox and OpenSSL ("openssl spkac -key private.key") behave this way - // we could alternatively do this instead if we ignored the specs: - // crypt_random_string(8) & str_repeat("\x7F", 8) - 'challenge' => !empty($this->challenge) ? $this->challenge : '' - ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later - ); - } - - // resync $this->signatureSubject - // save $publicKeyAndChallenge in case there are any File_ASN1_Element objects in it - $publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge']; - $this->loadSPKAC($this->saveSPKAC($this->currentCert)); - - $result = $this->_sign($this->privateKey, $signatureAlgorithm); - $result['publicKeyAndChallenge'] = $publicKeyAndChallenge; - - $this->currentCert = $currentCert; - $this->signatureSubject = $signatureSubject; - - return $result; - } - - /** - * Sign a CRL - * - * $issuer's private key needs to be loaded. - * - * @param File_X509 $issuer - * @param File_X509 $crl - * @param String $signatureAlgorithm optional - * @access public - * @return Mixed - */ - function signCRL($issuer, $crl, $signatureAlgorithm = 'sha1WithRSAEncryption') - { - if (!is_object($issuer->privateKey) || empty($issuer->dn)) { - return false; - } - - $currentCert = isset($this->currentCert) ? $this->currentCert : null; - $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null; - $thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O'); - - if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) { - $this->currentCert = $crl->currentCert; - $this->currentCert['tbsCertList']['signature']['algorithm'] = $signatureAlgorithm; - $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; - } else { - $this->currentCert = array( - 'tbsCertList' => - array( - 'version' => 'v2', - 'signature' => array('algorithm' => $signatureAlgorithm), - 'issuer' => false, // this is going to be overwritten later - 'thisUpdate' => $this->_timeField($thisUpdate) // $this->setStartDate() - ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later - ); - } - - $tbsCertList = &$this->currentCert['tbsCertList']; - $tbsCertList['issuer'] = $issuer->dn; - $tbsCertList['thisUpdate'] = $this->_timeField($thisUpdate); - - if (!empty($this->endDate)) { - $tbsCertList['nextUpdate'] = $this->_timeField($this->endDate); // $this->setEndDate() - } else { - unset($tbsCertList['nextUpdate']); - } - - if (!empty($this->serialNumber)) { - $crlNumber = $this->serialNumber; - } else { - $crlNumber = $this->getExtension('id-ce-cRLNumber'); - $crlNumber = $crlNumber !== false ? $crlNumber->add(new Math_BigInteger(1)) : null; - } - - $this->removeExtension('id-ce-authorityKeyIdentifier'); - $this->removeExtension('id-ce-issuerAltName'); - - // Be sure version >= v2 if some extension found. - $version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0; - if (!$version) { - if (!empty($tbsCertList['crlExtensions'])) { - $version = 1; // v2. - } elseif (!empty($tbsCertList['revokedCertificates'])) { - foreach ($tbsCertList['revokedCertificates'] as $cert) { - if (!empty($cert['crlEntryExtensions'])) { - $version = 1; // v2. - } - } - } - - if ($version) { - $tbsCertList['version'] = $version; - } - } - - // Store additional extensions. - if (!empty($tbsCertList['version'])) { // At least v2. - if (!empty($crlNumber)) { - $this->setExtension('id-ce-cRLNumber', $crlNumber); - } - - if (isset($issuer->currentKeyIdentifier)) { - $this->setExtension('id-ce-authorityKeyIdentifier', array( - //'authorityCertIssuer' => array( - // array( - // 'directoryName' => $issuer->dn - // ) - //), - 'keyIdentifier' => $issuer->currentKeyIdentifier - ) - ); - //$extensions = &$tbsCertList['crlExtensions']; - //if (isset($issuer->serialNumber)) { - // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber; - //} - //unset($extensions); - } - - $issuerAltName = $this->getExtension('id-ce-subjectAltName', $issuer->currentCert); - - if ($issuerAltName !== false) { - $this->setExtension('id-ce-issuerAltName', $issuerAltName); - } - } - - if (empty($tbsCertList['revokedCertificates'])) { - unset($tbsCertList['revokedCertificates']); - } - - unset($tbsCertList); - - // resync $this->signatureSubject - // save $tbsCertList in case there are any File_ASN1_Element objects in it - $tbsCertList = $this->currentCert['tbsCertList']; - $this->loadCRL($this->saveCRL($this->currentCert)); - - $result = $this->_sign($issuer->privateKey, $signatureAlgorithm); - $result['tbsCertList'] = $tbsCertList; - - $this->currentCert = $currentCert; - $this->signatureSubject = $signatureSubject; - - return $result; - } - - /** - * X.509 certificate signing helper function. - * - * @param Object $key - * @param File_X509 $subject - * @param String $signatureAlgorithm - * @access public - * @return Mixed - */ - function _sign($key, $signatureAlgorithm) - { - switch (strtolower(get_class($key))) { - case 'crypt_rsa': - switch ($signatureAlgorithm) { - case 'md2WithRSAEncryption': - case 'md5WithRSAEncryption': - case 'sha1WithRSAEncryption': - case 'sha224WithRSAEncryption': - case 'sha256WithRSAEncryption': - case 'sha384WithRSAEncryption': - case 'sha512WithRSAEncryption': - $key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm)); - $key->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); - - $this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject)); - return $this->currentCert; - } - default: - return false; - } - } - - /** - * Set certificate start date - * - * @param String $date - * @access public - */ - function setStartDate($date) - { - $this->startDate = @date('D, d M Y H:i:s O', @strtotime($date)); - } - - /** - * Set certificate end date - * - * @param String $date - * @access public - */ - function setEndDate($date) - { - /* - To indicate that a certificate has no well-defined expiration date, - the notAfter SHOULD be assigned the GeneralizedTime value of - 99991231235959Z. - - -- http://tools.ietf.org/html/rfc5280#section-4.1.2.5 - */ - if (strtolower($date) == 'lifetime') { - $temp = '99991231235959Z'; - $asn1 = new File_ASN1(); - $temp = chr(FILE_ASN1_TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp; - $this->endDate = new File_ASN1_Element($temp); - } else { - $this->endDate = @date('D, d M Y H:i:s O', @strtotime($date)); - } - } - - /** - * Set Serial Number - * - * @param String $serial - * @param $base optional - * @access public - */ - function setSerialNumber($serial, $base = -256) - { - $this->serialNumber = new Math_BigInteger($serial, $base); - } - - /** - * Turns the certificate into a certificate authority - * - * @access public - */ - function makeCA() - { - $this->caFlag = true; - } - - /** - * Get a reference to a subarray - * - * @param array $root - * @param String $path absolute path with / as component separator - * @param Boolean $create optional - * @access private - * @return array item ref or false - */ - function &_subArray(&$root, $path, $create = false) - { - $false = false; - - if (!is_array($root)) { - return $false; - } - - foreach (explode('/', $path) as $i) { - if (!is_array($root)) { - return $false; - } - - if (!isset($root[$i])) { - if (!$create) { - return $false; - } - - $root[$i] = array(); - } - - $root = &$root[$i]; - } - - return $root; - } - - /** - * Get a reference to an extension subarray - * - * @param array $root - * @param String $path optional absolute path with / as component separator - * @param Boolean $create optional - * @access private - * @return array ref or false - */ - function &_extensions(&$root, $path = null, $create = false) - { - if (!isset($root)) { - $root = $this->currentCert; - } - - switch (true) { - case !empty($path): - case !is_array($root): - break; - case isset($root['tbsCertificate']): - $path = 'tbsCertificate/extensions'; - break; - case isset($root['tbsCertList']): - $path = 'tbsCertList/crlExtensions'; - break; - case isset($root['certificationRequestInfo']): - $pth = 'certificationRequestInfo/attributes'; - $attributes = &$this->_subArray($root, $pth, $create); - - if (is_array($attributes)) { - foreach ($attributes as $key => $value) { - if ($value['type'] == 'pkcs-9-at-extensionRequest') { - $path = "$pth/$key/value/0"; - break 2; - } - } - if ($create) { - $key = count($attributes); - $attributes[] = array('type' => 'pkcs-9-at-extensionRequest', 'value' => array()); - $path = "$pth/$key/value/0"; - } - } - break; - } - - $extensions = &$this->_subArray($root, $path, $create); - - if (!is_array($extensions)) { - $false = false; - return $false; - } - - return $extensions; - } - - /** - * Remove an Extension - * - * @param String $id - * @param String $path optional - * @access private - * @return Boolean - */ - function _removeExtension($id, $path = null) - { - $extensions = &$this->_extensions($this->currentCert, $path); - - if (!is_array($extensions)) { - return false; - } - - $result = false; - foreach ($extensions as $key => $value) { - if ($value['extnId'] == $id) { - unset($extensions[$key]); - $result = true; - } - } - - $extensions = array_values($extensions); - return $result; - } - - /** - * Get an Extension - * - * Returns the extension if it exists and false if not - * - * @param String $id - * @param Array $cert optional - * @param String $path optional - * @access private - * @return Mixed - */ - function _getExtension($id, $cert = null, $path = null) - { - $extensions = $this->_extensions($cert, $path); - - if (!is_array($extensions)) { - return false; - } - - foreach ($extensions as $key => $value) { - if ($value['extnId'] == $id) { - return $value['extnValue']; - } - } - - return false; - } - - /** - * Returns a list of all extensions in use - * - * @param array $cert optional - * @param String $path optional - * @access private - * @return Array - */ - function _getExtensions($cert = null, $path = null) - { - $exts = $this->_extensions($cert, $path); - $extensions = array(); - - if (is_array($exts)) { - foreach ($exts as $extension) { - $extensions[] = $extension['extnId']; - } - } - - return $extensions; - } - - /** - * Set an Extension - * - * @param String $id - * @param Mixed $value - * @param Boolean $critical optional - * @param Boolean $replace optional - * @param String $path optional - * @access private - * @return Boolean - */ - function _setExtension($id, $value, $critical = false, $replace = true, $path = null) - { - $extensions = &$this->_extensions($this->currentCert, $path, true); - - if (!is_array($extensions)) { - return false; - } - - $newext = array('extnId' => $id, 'critical' => $critical, 'extnValue' => $value); - - foreach ($extensions as $key => $value) { - if ($value['extnId'] == $id) { - if (!$replace) { - return false; - } - - $extensions[$key] = $newext; - return true; - } - } - - $extensions[] = $newext; - return true; - } - - /** - * Remove a certificate, CSR or CRL Extension - * - * @param String $id - * @access public - * @return Boolean - */ - function removeExtension($id) - { - return $this->_removeExtension($id); - } - - /** - * Get a certificate, CSR or CRL Extension - * - * Returns the extension if it exists and false if not - * - * @param String $id - * @param Array $cert optional - * @access public - * @return Mixed - */ - function getExtension($id, $cert = null) - { - return $this->_getExtension($id, $cert); - } - - /** - * Returns a list of all extensions in use in certificate, CSR or CRL - * - * @param array $cert optional - * @access public - * @return Array - */ - function getExtensions($cert = null) - { - return $this->_getExtensions($cert); - } - - /** - * Set a certificate, CSR or CRL Extension - * - * @param String $id - * @param Mixed $value - * @param Boolean $critical optional - * @param Boolean $replace optional - * @access public - * @return Boolean - */ - function setExtension($id, $value, $critical = false, $replace = true) - { - return $this->_setExtension($id, $value, $critical, $replace); - } - - /** - * Remove a CSR attribute. - * - * @param String $id - * @param Integer $disposition optional - * @access public - * @return Boolean - */ - function removeAttribute($id, $disposition = FILE_X509_ATTR_ALL) - { - $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes'); - - if (!is_array($attributes)) { - return false; - } - - $result = false; - foreach ($attributes as $key => $attribute) { - if ($attribute['type'] == $id) { - $n = count($attribute['value']); - switch (true) { - case $disposition == FILE_X509_ATTR_APPEND: - case $disposition == FILE_X509_ATTR_REPLACE: - return false; - case $disposition >= $n: - $disposition -= $n; - break; - case $disposition == FILE_X509_ATTR_ALL: - case $n == 1: - unset($attributes[$key]); - $result = true; - break; - default: - unset($attributes[$key]['value'][$disposition]); - $attributes[$key]['value'] = array_values($attributes[$key]['value']); - $result = true; - break; - } - if ($result && $disposition != FILE_X509_ATTR_ALL) { - break; - } - } - } - - $attributes = array_values($attributes); - return $result; - } - - /** - * Get a CSR attribute - * - * Returns the attribute if it exists and false if not - * - * @param String $id - * @param Integer $disposition optional - * @param Array $csr optional - * @access public - * @return Mixed - */ - function getAttribute($id, $disposition = FILE_X509_ATTR_ALL, $csr = null) - { - if (empty($csr)) { - $csr = $this->currentCert; - } - - $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes'); - - if (!is_array($attributes)) { - return false; - } - - foreach ($attributes as $key => $attribute) { - if ($attribute['type'] == $id) { - $n = count($attribute['value']); - switch (true) { - case $disposition == FILE_X509_ATTR_APPEND: - case $disposition == FILE_X509_ATTR_REPLACE: - return false; - case $disposition == FILE_X509_ATTR_ALL: - return $attribute['value']; - case $disposition >= $n: - $disposition -= $n; - break; - default: - return $attribute['value'][$disposition]; - } - } - } - - return false; - } - - /** - * Returns a list of all CSR attributes in use - * - * @param array $csr optional - * @access public - * @return Array - */ - function getAttributes($csr = null) - { - if (empty($csr)) { - $csr = $this->currentCert; - } - - $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes'); - $attrs = array(); - - if (is_array($attributes)) { - foreach ($attributes as $attribute) { - $attrs[] = $attribute['type']; - } - } - - return $attrs; - } - - /** - * Set a CSR attribute - * - * @param String $id - * @param Mixed $value - * @param Boolean $disposition optional - * @access public - * @return Boolean - */ - function setAttribute($id, $value, $disposition = FILE_X509_ATTR_ALL) - { - $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes', true); - - if (!is_array($attributes)) { - return false; - } - - switch ($disposition) { - case FILE_X509_ATTR_REPLACE: - $disposition = FILE_X509_ATTR_APPEND; - case FILE_X509_ATTR_ALL: - $this->removeAttribute($id); - break; - } - - foreach ($attributes as $key => $attribute) { - if ($attribute['type'] == $id) { - $n = count($attribute['value']); - switch (true) { - case $disposition == FILE_X509_ATTR_APPEND: - $last = $key; - break; - case $disposition >= $n; - $disposition -= $n; - break; - default: - $attributes[$key]['value'][$disposition] = $value; - return true; - } - } - } - - switch (true) { - case $disposition >= 0: - return false; - case isset($last): - $attributes[$last]['value'][] = $value; - break; - default: - $attributes[] = array('type' => $id, 'value' => $disposition == FILE_X509_ATTR_ALL ? $value: array($value)); - break; - } - - return true; - } - - /** - * Sets the subject key identifier - * - * This is used by the id-ce-authorityKeyIdentifier and the id-ce-subjectKeyIdentifier extensions. - * - * @param String $value - * @access public - */ - function setKeyIdentifier($value) - { - if (empty($value)) { - unset($this->currentKeyIdentifier); - } else { - $this->currentKeyIdentifier = base64_encode($value); - } - } - - /** - * Compute a public key identifier. - * - * Although key identifiers may be set to any unique value, this function - * computes key identifiers from public key according to the two - * recommended methods (4.2.1.2 RFC 3280). - * Highly polymorphic: try to accept all possible forms of key: - * - Key object - * - File_X509 object with public or private key defined - * - Certificate or CSR array - * - File_ASN1_Element object - * - PEM or DER string - * - * @param Mixed $key optional - * @param Integer $method optional - * @access public - * @return String binary key identifier - */ - function computeKeyIdentifier($key = null, $method = 1) - { - if (is_null($key)) { - $key = $this; - } - - switch (true) { - case is_string($key): - break; - case is_array($key) && isset($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']): - return $this->computeKeyIdentifier($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $method); - case is_array($key) && isset($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']): - return $this->computeKeyIdentifier($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $method); - case !is_object($key): - return false; - case strtolower(get_class($key)) == 'file_asn1_element': - // Assume the element is a bitstring-packed key. - $asn1 = new File_ASN1(); - $decoded = $asn1->decodeBER($key->element); - if (empty($decoded)) { - return false; - } - $raw = $asn1->asn1map($decoded[0], array('type' => FILE_ASN1_TYPE_BIT_STRING)); - if (empty($raw)) { - return false; - } - $raw = base64_decode($raw); - // If the key is private, compute identifier from its corresponding public key. - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $key = new Crypt_RSA(); - if (!$key->loadKey($raw)) { - return false; // Not an unencrypted RSA key. - } - if ($key->getPrivateKey() !== false) { // If private. - return $this->computeKeyIdentifier($key, $method); - } - $key = $raw; // Is a public key. - break; - case strtolower(get_class($key)) == 'file_x509': - if (isset($key->publicKey)) { - return $this->computeKeyIdentifier($key->publicKey, $method); - } - if (isset($key->privateKey)) { - return $this->computeKeyIdentifier($key->privateKey, $method); - } - if (isset($key->currentCert['tbsCertificate']) || isset($key->currentCert['certificationRequestInfo'])) { - return $this->computeKeyIdentifier($key->currentCert, $method); - } - return false; - default: // Should be a key object (i.e.: Crypt_RSA). - $key = $key->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1); - break; - } - - // If in PEM format, convert to binary. - $key = $this->_extractBER($key); - - // Now we have the key string: compute its sha-1 sum. - if (!class_exists('Crypt_Hash')) { - include_once 'Crypt/Hash.php'; - } - $hash = new Crypt_Hash('sha1'); - $hash = $hash->hash($key); - - if ($method == 2) { - $hash = substr($hash, -8); - $hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40); - } - - return $hash; - } - - /** - * Format a public key as appropriate - * - * @access private - * @return Array - */ - function _formatSubjectPublicKey() - { - if (!isset($this->publicKey) || !is_object($this->publicKey)) { - return false; - } - - switch (strtolower(get_class($this->publicKey))) { - case 'crypt_rsa': - // the following two return statements do the same thing. i dunno.. i just prefer the later for some reason. - // the former is a good example of how to do fuzzing on the public key - //return new File_ASN1_Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey()))); - return array( - 'algorithm' => array('algorithm' => 'rsaEncryption'), - 'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1) - ); - default: - return false; - } - } - - /** - * Set the domain name's which the cert is to be valid for - * - * @access public - * @return Array - */ - function setDomain() - { - $this->domains = func_get_args(); - $this->removeDNProp('id-at-commonName'); - $this->setDNProp('id-at-commonName', $this->domains[0]); - } - - /** - * Set the IP Addresses's which the cert is to be valid for - * - * @access public - * @param String $ipAddress optional - */ - function setIPAddress() - { - $this->ipAddresses = func_get_args(); - /* - if (!isset($this->domains)) { - $this->removeDNProp('id-at-commonName'); - $this->setDNProp('id-at-commonName', $this->ipAddresses[0]); - } - */ - } - - /** - * Helper function to build domain array - * - * @access private - * @param String $domain - * @return Array - */ - function _dnsName($domain) - { - return array('dNSName' => $domain); - } - - /** - * Helper function to build IP Address array - * - * (IPv6 is not currently supported) - * - * @access private - * @param String $address - * @return Array - */ - function _iPAddress($address) - { - return array('iPAddress' => $address); - } - - /** - * Get the index of a revoked certificate. - * - * @param array $rclist - * @param String $serial - * @param Boolean $create optional - * @access private - * @return Integer or false - */ - function _revokedCertificate(&$rclist, $serial, $create = false) - { - $serial = new Math_BigInteger($serial); - - foreach ($rclist as $i => $rc) { - if (!($serial->compare($rc['userCertificate']))) { - return $i; - } - } - - if (!$create) { - return false; - } - - $i = count($rclist); - $rclist[] = array('userCertificate' => $serial, - 'revocationDate' => $this->_timeField(@date('D, d M Y H:i:s O'))); - return $i; - } - - /** - * Revoke a certificate. - * - * @param String $serial - * @param String $date optional - * @access public - * @return Boolean - */ - function revoke($serial, $date = null) - { - if (isset($this->currentCert['tbsCertList'])) { - if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) { - if ($this->_revokedCertificate($rclist, $serial) === false) { // If not yet revoked - if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) { - - if (!empty($date)) { - $rclist[$i]['revocationDate'] = $this->_timeField($date); - } - - return true; - } - } - } - } - - return false; - } - - /** - * Unrevoke a certificate. - * - * @param String $serial - * @access public - * @return Boolean - */ - function unrevoke($serial) - { - if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) { - if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) { - unset($rclist[$i]); - $rclist = array_values($rclist); - return true; - } - } - - return false; - } - - /** - * Get a revoked certificate. - * - * @param String $serial - * @access public - * @return Mixed - */ - function getRevoked($serial) - { - if (is_array($rclist = $this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) { - if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) { - return $rclist[$i]; - } - } - - return false; - } - - /** - * List revoked certificates - * - * @param array $crl optional - * @access public - * @return array - */ - function listRevoked($crl = null) - { - if (!isset($crl)) { - $crl = $this->currentCert; - } - - if (!isset($crl['tbsCertList'])) { - return false; - } - - $result = array(); - - if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) { - foreach ($rclist as $rc) { - $result[] = $rc['userCertificate']->toString(); - } - } - - return $result; - } - - /** - * Remove a Revoked Certificate Extension - * - * @param String $serial - * @param String $id - * @access public - * @return Boolean - */ - function removeRevokedCertificateExtension($serial, $id) - { - if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) { - if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) { - return $this->_removeExtension($id, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); - } - } - - return false; - } - - /** - * Get a Revoked Certificate Extension - * - * Returns the extension if it exists and false if not - * - * @param String $serial - * @param String $id - * @param Array $crl optional - * @access public - * @return Mixed - */ - function getRevokedCertificateExtension($serial, $id, $crl = null) - { - if (!isset($crl)) { - $crl = $this->currentCert; - } - - if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) { - if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) { - return $this->_getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); - } - } - - return false; - } - - /** - * Returns a list of all extensions in use for a given revoked certificate - * - * @param String $serial - * @param array $crl optional - * @access public - * @return Array - */ - function getRevokedCertificateExtensions($serial, $crl = null) - { - if (!isset($crl)) { - $crl = $this->currentCert; - } - - if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) { - if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) { - return $this->_getExtensions($crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); - } - } - - return false; - } - - /** - * Set a Revoked Certificate Extension - * - * @param String $serial - * @param String $id - * @param Mixed $value - * @param Boolean $critical optional - * @param Boolean $replace optional - * @access public - * @return Boolean - */ - function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true) - { - if (isset($this->currentCert['tbsCertList'])) { - if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) { - if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) { - return $this->_setExtension($id, $value, $critical, $replace, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); - } - } - } - - return false; - } - - /** - * Extract raw BER from Base64 encoding - * - * @access private - * @param String $str - * @return String - */ - function _extractBER($str) - { - /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them - * above and beyond the ceritificate. - * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line: - * - * Bag Attributes - * localKeyID: 01 00 00 00 - * subject=/O=organization/OU=org unit/CN=common name - * issuer=/O=organization/CN=common name - */ - $temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $str, 1); - // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff - $temp = preg_replace('#-+[^-]+-+#', '', $temp); - // remove new lines - $temp = str_replace(array("\r", "\n", ' '), '', $temp); - $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; - return $temp != false ? $temp : $str; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Math/BigInteger.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Math/BigInteger.php deleted file mode 100644 index 8e54f741..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Math/BigInteger.php +++ /dev/null @@ -1,3758 +0,0 @@ -> and << cannot be used, nor can the modulo operator %, - * which only supports integers. Although this fact will slow this library down, the fact that such a high - * base is being used should more than compensate. - * - * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie. - * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1) - * - * Useful resources are as follows: - * - * - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)} - * - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)} - * - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip - * - * Here's an example of how to use this library: - * - * add($b); - * - * echo $c->toString(); // outputs 5 - * ?> - * - * - * 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. - * - * @category Math - * @package Math_BigInteger - * @author Jim Wigginton - * @copyright 2006 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://pear.php.net/package/Math_BigInteger - */ - -/**#@+ - * Reduction constants - * - * @access private - * @see Math_BigInteger::_reduce() - */ -/** - * @see Math_BigInteger::_montgomery() - * @see Math_BigInteger::_prepMontgomery() - */ -define('MATH_BIGINTEGER_MONTGOMERY', 0); -/** - * @see Math_BigInteger::_barrett() - */ -define('MATH_BIGINTEGER_BARRETT', 1); -/** - * @see Math_BigInteger::_mod2() - */ -define('MATH_BIGINTEGER_POWEROF2', 2); -/** - * @see Math_BigInteger::_remainder() - */ -define('MATH_BIGINTEGER_CLASSIC', 3); -/** - * @see Math_BigInteger::__clone() - */ -define('MATH_BIGINTEGER_NONE', 4); -/**#@-*/ - -/**#@+ - * Array constants - * - * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and - * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them. - * - * @access private - */ -/** - * $result[MATH_BIGINTEGER_VALUE] contains the value. - */ -define('MATH_BIGINTEGER_VALUE', 0); -/** - * $result[MATH_BIGINTEGER_SIGN] contains the sign. - */ -define('MATH_BIGINTEGER_SIGN', 1); -/**#@-*/ - -/**#@+ - * @access private - * @see Math_BigInteger::_montgomery() - * @see Math_BigInteger::_barrett() - */ -/** - * Cache constants - * - * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid. - */ -define('MATH_BIGINTEGER_VARIABLE', 0); -/** - * $cache[MATH_BIGINTEGER_DATA] contains the cached data. - */ -define('MATH_BIGINTEGER_DATA', 1); -/**#@-*/ - -/**#@+ - * Mode constants. - * - * @access private - * @see Math_BigInteger::Math_BigInteger() - */ -/** - * To use the pure-PHP implementation - */ -define('MATH_BIGINTEGER_MODE_INTERNAL', 1); -/** - * To use the BCMath library - * - * (if enabled; otherwise, the internal implementation will be used) - */ -define('MATH_BIGINTEGER_MODE_BCMATH', 2); -/** - * To use the GMP library - * - * (if present; otherwise, either the BCMath or the internal implementation will be used) - */ -define('MATH_BIGINTEGER_MODE_GMP', 3); -/**#@-*/ - -/** - * Karatsuba Cutoff - * - * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication? - * - * @access private - */ -define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25); - -/** - * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256 - * numbers. - * - * @package Math_BigInteger - * @author Jim Wigginton - * @access public - */ -class Math_BigInteger -{ - /** - * Holds the BigInteger's value. - * - * @var Array - * @access private - */ - var $value; - - /** - * Holds the BigInteger's magnitude. - * - * @var Boolean - * @access private - */ - var $is_negative = false; - - /** - * Random number generator function - * - * @see setRandomGenerator() - * @access private - */ - var $generator = 'mt_rand'; - - /** - * Precision - * - * @see setPrecision() - * @access private - */ - var $precision = -1; - - /** - * Precision Bitmask - * - * @see setPrecision() - * @access private - */ - var $bitmask = false; - - /** - * Mode independent value used for serialization. - * - * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for - * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value, - * however, $this->hex is only calculated when $this->__sleep() is called. - * - * @see __sleep() - * @see __wakeup() - * @var String - * @access private - */ - var $hex; - - /** - * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers. - * - * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using - * two's compliment. The sole exception to this is -10, which is treated the same as 10 is. - * - * Here's an example: - * - * toString(); // outputs 50 - * ?> - * - * - * @param optional $x base-10 number or base-$base number if $base set. - * @param optional integer $base - * @return Math_BigInteger - * @access public - */ - function Math_BigInteger($x = 0, $base = 10) - { - if ( !defined('MATH_BIGINTEGER_MODE') ) { - switch (true) { - case extension_loaded('gmp'): - define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP); - break; - case extension_loaded('bcmath'): - define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH); - break; - default: - define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL); - } - } - - if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { - // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work - ob_start(); - @phpinfo(); - $content = ob_get_contents(); - ob_end_clean(); - - preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches); - - $versions = array(); - if (!empty($matches[1])) { - for ($i = 0; $i < count($matches[1]); $i++) { - $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); - - // Remove letter part in OpenSSL version - if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) { - $versions[$matches[1][$i]] = $fullVersion; - } else { - $versions[$matches[1][$i]] = $m[0]; - } - } - } - - // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+ - switch (true) { - case !isset($versions['Header']): - case !isset($versions['Library']): - case $versions['Header'] == $versions['Library']: - define('MATH_BIGINTEGER_OPENSSL_ENABLED', true); - break; - default: - define('MATH_BIGINTEGER_OPENSSL_DISABLE', true); - } - } - - if (!defined('PHP_INT_SIZE')) { - define('PHP_INT_SIZE', 4); - } - - if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) { - switch (PHP_INT_SIZE) { - case 8: // use 64-bit integers if int size is 8 bytes - define('MATH_BIGINTEGER_BASE', 31); - define('MATH_BIGINTEGER_BASE_FULL', 0x80000000); - define('MATH_BIGINTEGER_MAX_DIGIT', 0x7FFFFFFF); - define('MATH_BIGINTEGER_MSB', 0x40000000); - // 10**9 is the closest we can get to 2**31 without passing it - define('MATH_BIGINTEGER_MAX10', 1000000000); - define('MATH_BIGINTEGER_MAX10_LEN', 9); - // the largest digit that may be used in addition / subtraction - define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62)); - break; - //case 4: // use 64-bit floats if int size is 4 bytes - default: - define('MATH_BIGINTEGER_BASE', 26); - define('MATH_BIGINTEGER_BASE_FULL', 0x4000000); - define('MATH_BIGINTEGER_MAX_DIGIT', 0x3FFFFFF); - define('MATH_BIGINTEGER_MSB', 0x2000000); - // 10**7 is the closest to 2**26 without passing it - define('MATH_BIGINTEGER_MAX10', 10000000); - define('MATH_BIGINTEGER_MAX10_LEN', 7); - // the largest digit that may be used in addition / subtraction - // we do pow(2, 52) instead of using 4503599627370496 directly because some - // PHP installations will truncate 4503599627370496. - define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52)); - } - } - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - switch (true) { - case is_resource($x) && get_resource_type($x) == 'GMP integer': - // PHP 5.6 switched GMP from using resources to objects - case is_object($x) && get_class($x) == 'GMP': - $this->value = $x; - return; - } - $this->value = gmp_init(0); - break; - case MATH_BIGINTEGER_MODE_BCMATH: - $this->value = '0'; - break; - default: - $this->value = array(); - } - - // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48 - // '0' is the only value like this per http://php.net/empty - if (empty($x) && (abs($base) != 256 || $x !== '0')) { - return; - } - - switch ($base) { - case -256: - if (ord($x[0]) & 0x80) { - $x = ~$x; - $this->is_negative = true; - } - case 256: - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $sign = $this->is_negative ? '-' : ''; - $this->value = gmp_init($sign . '0x' . bin2hex($x)); - break; - case MATH_BIGINTEGER_MODE_BCMATH: - // round $len to the nearest 4 (thanks, DavidMJ!) - $len = (strlen($x) + 3) & 0xFFFFFFFC; - - $x = str_pad($x, $len, chr(0), STR_PAD_LEFT); - - for ($i = 0; $i < $len; $i+= 4) { - $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32 - $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0); - } - - if ($this->is_negative) { - $this->value = '-' . $this->value; - } - - break; - // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb) - default: - while (strlen($x)) { - $this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE)); - } - } - - if ($this->is_negative) { - if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { - $this->is_negative = false; - } - $temp = $this->add(new Math_BigInteger('-1')); - $this->value = $temp->value; - } - break; - case 16: - case -16: - if ($base > 0 && $x[0] == '-') { - $this->is_negative = true; - $x = substr($x, 1); - } - - $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x); - - $is_negative = false; - if ($base < 0 && hexdec($x[0]) >= 8) { - $this->is_negative = $is_negative = true; - $x = bin2hex(~pack('H*', $x)); - } - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = $this->is_negative ? '-0x' . $x : '0x' . $x; - $this->value = gmp_init($temp); - $this->is_negative = false; - break; - case MATH_BIGINTEGER_MODE_BCMATH: - $x = ( strlen($x) & 1 ) ? '0' . $x : $x; - $temp = new Math_BigInteger(pack('H*', $x), 256); - $this->value = $this->is_negative ? '-' . $temp->value : $temp->value; - $this->is_negative = false; - break; - default: - $x = ( strlen($x) & 1 ) ? '0' . $x : $x; - $temp = new Math_BigInteger(pack('H*', $x), 256); - $this->value = $temp->value; - } - - if ($is_negative) { - $temp = $this->add(new Math_BigInteger('-1')); - $this->value = $temp->value; - } - break; - case 10: - case -10: - // (?value = gmp_init($x); - break; - case MATH_BIGINTEGER_MODE_BCMATH: - // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different - // results then doing it on '-1' does (modInverse does $x[0]) - $this->value = $x === '-' ? '0' : (string) $x; - break; - default: - $temp = new Math_BigInteger(); - - $multiplier = new Math_BigInteger(); - $multiplier->value = array(MATH_BIGINTEGER_MAX10); - - if ($x[0] == '-') { - $this->is_negative = true; - $x = substr($x, 1); - } - - $x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT); - while (strlen($x)) { - $temp = $temp->multiply($multiplier); - $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256)); - $x = substr($x, MATH_BIGINTEGER_MAX10_LEN); - } - - $this->value = $temp->value; - } - break; - case 2: // base-2 support originally implemented by Lluis Pamies - thanks! - case -2: - if ($base > 0 && $x[0] == '-') { - $this->is_negative = true; - $x = substr($x, 1); - } - - $x = preg_replace('#^([01]*).*#', '$1', $x); - $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT); - - $str = '0x'; - while (strlen($x)) { - $part = substr($x, 0, 4); - $str.= dechex(bindec($part)); - $x = substr($x, 4); - } - - if ($this->is_negative) { - $str = '-' . $str; - } - - $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16 - $this->value = $temp->value; - $this->is_negative = $temp->is_negative; - - break; - default: - // base not supported, so we'll let $this == 0 - } - } - - /** - * Converts a BigInteger to a byte string (eg. base-256). - * - * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're - * saved as two's compliment. - * - * Here's an example: - * - * toBytes(); // outputs chr(65) - * ?> - * - * - * @param Boolean $twos_compliment - * @return String - * @access public - * @internal Converts a base-2**26 number to base-2**8 - */ - function toBytes($twos_compliment = false) - { - if ($twos_compliment) { - $comparison = $this->compare(new Math_BigInteger()); - if ($comparison == 0) { - return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; - } - - $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy(); - $bytes = $temp->toBytes(); - - if (empty($bytes)) { // eg. if the number we're trying to convert is -1 - $bytes = chr(0); - } - - if (ord($bytes[0]) & 0x80) { - $bytes = chr(0) . $bytes; - } - - return $comparison < 0 ? ~$bytes : $bytes; - } - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - if (gmp_cmp($this->value, gmp_init(0)) == 0) { - return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; - } - - $temp = gmp_strval(gmp_abs($this->value), 16); - $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp; - $temp = pack('H*', $temp); - - return $this->precision > 0 ? - substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) : - ltrim($temp, chr(0)); - case MATH_BIGINTEGER_MODE_BCMATH: - if ($this->value === '0') { - return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; - } - - $value = ''; - $current = $this->value; - - if ($current[0] == '-') { - $current = substr($current, 1); - } - - while (bccomp($current, '0', 0) > 0) { - $temp = bcmod($current, '16777216'); - $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value; - $current = bcdiv($current, '16777216', 0); - } - - return $this->precision > 0 ? - substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) : - ltrim($value, chr(0)); - } - - if (!count($this->value)) { - return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; - } - $result = $this->_int2bytes($this->value[count($this->value) - 1]); - - $temp = $this->copy(); - - for ($i = count($temp->value) - 2; $i >= 0; --$i) { - $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE); - $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT); - } - - return $this->precision > 0 ? - str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) : - $result; - } - - /** - * Converts a BigInteger to a hex string (eg. base-16)). - * - * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're - * saved as two's compliment. - * - * Here's an example: - * - * toHex(); // outputs '41' - * ?> - * - * - * @param Boolean $twos_compliment - * @return String - * @access public - * @internal Converts a base-2**26 number to base-2**8 - */ - function toHex($twos_compliment = false) - { - return bin2hex($this->toBytes($twos_compliment)); - } - - /** - * Converts a BigInteger to a bit string (eg. base-2). - * - * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're - * saved as two's compliment. - * - * Here's an example: - * - * toBits(); // outputs '1000001' - * ?> - * - * - * @param Boolean $twos_compliment - * @return String - * @access public - * @internal Converts a base-2**26 number to base-2**2 - */ - function toBits($twos_compliment = false) - { - $hex = $this->toHex($twos_compliment); - $bits = ''; - for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) { - $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits; - } - if ($start) { // hexdec('') == 0 - $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits; - } - $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0'); - - if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) { - return '0' . $result; - } - - return $result; - } - - /** - * Converts a BigInteger to a base-10 number. - * - * Here's an example: - * - * toString(); // outputs 50 - * ?> - * - * - * @return String - * @access public - * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10) - */ - function toString() - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - return gmp_strval($this->value); - case MATH_BIGINTEGER_MODE_BCMATH: - if ($this->value === '0') { - return '0'; - } - - return ltrim($this->value, '0'); - } - - if (!count($this->value)) { - return '0'; - } - - $temp = $this->copy(); - $temp->is_negative = false; - - $divisor = new Math_BigInteger(); - $divisor->value = array(MATH_BIGINTEGER_MAX10); - $result = ''; - while (count($temp->value)) { - list($temp, $mod) = $temp->divide($divisor); - $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result; - } - $result = ltrim($result, '0'); - if (empty($result)) { - $result = '0'; - } - - if ($this->is_negative) { - $result = '-' . $result; - } - - return $result; - } - - /** - * Copy an object - * - * PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee - * that all objects are passed by value, when appropriate. More information can be found here: - * - * {@link http://php.net/language.oop5.basic#51624} - * - * @access public - * @see __clone() - * @return Math_BigInteger - */ - function copy() - { - $temp = new Math_BigInteger(); - $temp->value = $this->value; - $temp->is_negative = $this->is_negative; - $temp->generator = $this->generator; - $temp->precision = $this->precision; - $temp->bitmask = $this->bitmask; - return $temp; - } - - /** - * __toString() magic method - * - * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call - * toString(). - * - * @access public - * @internal Implemented per a suggestion by Techie-Michael - thanks! - */ - function __toString() - { - return $this->toString(); - } - - /** - * __clone() magic method - * - * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone() - * directly in PHP5. You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5 - * only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5, - * call Math_BigInteger::copy(), instead. - * - * @access public - * @see copy() - * @return Math_BigInteger - */ - function __clone() - { - return $this->copy(); - } - - /** - * __sleep() magic method - * - * Will be called, automatically, when serialize() is called on a Math_BigInteger object. - * - * @see __wakeup() - * @access public - */ - function __sleep() - { - $this->hex = $this->toHex(true); - $vars = array('hex'); - if ($this->generator != 'mt_rand') { - $vars[] = 'generator'; - } - if ($this->precision > 0) { - $vars[] = 'precision'; - } - return $vars; - - } - - /** - * __wakeup() magic method - * - * Will be called, automatically, when unserialize() is called on a Math_BigInteger object. - * - * @see __sleep() - * @access public - */ - function __wakeup() - { - $temp = new Math_BigInteger($this->hex, -16); - $this->value = $temp->value; - $this->is_negative = $temp->is_negative; - $this->setRandomGenerator($this->generator); - if ($this->precision > 0) { - // recalculate $this->bitmask - $this->setPrecision($this->precision); - } - } - - /** - * Adds two BigIntegers. - * - * Here's an example: - * - * add($b); - * - * echo $c->toString(); // outputs 30 - * ?> - * - * - * @param Math_BigInteger $y - * @return Math_BigInteger - * @access public - * @internal Performs base-2**52 addition - */ - function add($y) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_add($this->value, $y->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $temp = new Math_BigInteger(); - $temp->value = bcadd($this->value, $y->value, 0); - - return $this->_normalize($temp); - } - - $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative); - - $result = new Math_BigInteger(); - $result->value = $temp[MATH_BIGINTEGER_VALUE]; - $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; - - return $this->_normalize($result); - } - - /** - * Performs addition. - * - * @param Array $x_value - * @param Boolean $x_negative - * @param Array $y_value - * @param Boolean $y_negative - * @return Array - * @access private - */ - function _add($x_value, $x_negative, $y_value, $y_negative) - { - $x_size = count($x_value); - $y_size = count($y_value); - - if ($x_size == 0) { - return array( - MATH_BIGINTEGER_VALUE => $y_value, - MATH_BIGINTEGER_SIGN => $y_negative - ); - } else if ($y_size == 0) { - return array( - MATH_BIGINTEGER_VALUE => $x_value, - MATH_BIGINTEGER_SIGN => $x_negative - ); - } - - // subtract, if appropriate - if ( $x_negative != $y_negative ) { - if ( $x_value == $y_value ) { - return array( - MATH_BIGINTEGER_VALUE => array(), - MATH_BIGINTEGER_SIGN => false - ); - } - - $temp = $this->_subtract($x_value, false, $y_value, false); - $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ? - $x_negative : $y_negative; - - return $temp; - } - - if ($x_size < $y_size) { - $size = $x_size; - $value = $y_value; - } else { - $size = $y_size; - $value = $x_value; - } - - $value[count($value)] = 0; // just in case the carry adds an extra digit - - $carry = 0; - for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) { - $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry; - $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 - $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum; - - $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31); - - $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000) - $value[$j] = $temp; - } - - if ($j == $size) { // ie. if $y_size is odd - $sum = $x_value[$i] + $y_value[$i] + $carry; - $carry = $sum >= MATH_BIGINTEGER_BASE_FULL; - $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum; - ++$i; // ie. let $i = $j since we've just done $value[$i] - } - - if ($carry) { - for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) { - $value[$i] = 0; - } - ++$value[$i]; - } - - return array( - MATH_BIGINTEGER_VALUE => $this->_trim($value), - MATH_BIGINTEGER_SIGN => $x_negative - ); - } - - /** - * Subtracts two BigIntegers. - * - * Here's an example: - * - * subtract($b); - * - * echo $c->toString(); // outputs -10 - * ?> - * - * - * @param Math_BigInteger $y - * @return Math_BigInteger - * @access public - * @internal Performs base-2**52 subtraction - */ - function subtract($y) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_sub($this->value, $y->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $temp = new Math_BigInteger(); - $temp->value = bcsub($this->value, $y->value, 0); - - return $this->_normalize($temp); - } - - $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative); - - $result = new Math_BigInteger(); - $result->value = $temp[MATH_BIGINTEGER_VALUE]; - $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; - - return $this->_normalize($result); - } - - /** - * Performs subtraction. - * - * @param Array $x_value - * @param Boolean $x_negative - * @param Array $y_value - * @param Boolean $y_negative - * @return Array - * @access private - */ - function _subtract($x_value, $x_negative, $y_value, $y_negative) - { - $x_size = count($x_value); - $y_size = count($y_value); - - if ($x_size == 0) { - return array( - MATH_BIGINTEGER_VALUE => $y_value, - MATH_BIGINTEGER_SIGN => !$y_negative - ); - } else if ($y_size == 0) { - return array( - MATH_BIGINTEGER_VALUE => $x_value, - MATH_BIGINTEGER_SIGN => $x_negative - ); - } - - // add, if appropriate (ie. -$x - +$y or +$x - -$y) - if ( $x_negative != $y_negative ) { - $temp = $this->_add($x_value, false, $y_value, false); - $temp[MATH_BIGINTEGER_SIGN] = $x_negative; - - return $temp; - } - - $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative); - - if ( !$diff ) { - return array( - MATH_BIGINTEGER_VALUE => array(), - MATH_BIGINTEGER_SIGN => false - ); - } - - // switch $x and $y around, if appropriate. - if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) { - $temp = $x_value; - $x_value = $y_value; - $y_value = $temp; - - $x_negative = !$x_negative; - - $x_size = count($x_value); - $y_size = count($y_value); - } - - // at this point, $x_value should be at least as big as - if not bigger than - $y_value - - $carry = 0; - for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) { - $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry; - $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 - $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum; - - $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31); - - $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); - $x_value[$j] = $temp; - } - - if ($j == $y_size) { // ie. if $y_size is odd - $sum = $x_value[$i] - $y_value[$i] - $carry; - $carry = $sum < 0; - $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum; - ++$i; - } - - if ($carry) { - for (; !$x_value[$i]; ++$i) { - $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT; - } - --$x_value[$i]; - } - - return array( - MATH_BIGINTEGER_VALUE => $this->_trim($x_value), - MATH_BIGINTEGER_SIGN => $x_negative - ); - } - - /** - * Multiplies two BigIntegers - * - * Here's an example: - * - * multiply($b); - * - * echo $c->toString(); // outputs 200 - * ?> - * - * - * @param Math_BigInteger $x - * @return Math_BigInteger - * @access public - */ - function multiply($x) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_mul($this->value, $x->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $temp = new Math_BigInteger(); - $temp->value = bcmul($this->value, $x->value, 0); - - return $this->_normalize($temp); - } - - $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative); - - $product = new Math_BigInteger(); - $product->value = $temp[MATH_BIGINTEGER_VALUE]; - $product->is_negative = $temp[MATH_BIGINTEGER_SIGN]; - - return $this->_normalize($product); - } - - /** - * Performs multiplication. - * - * @param Array $x_value - * @param Boolean $x_negative - * @param Array $y_value - * @param Boolean $y_negative - * @return Array - * @access private - */ - function _multiply($x_value, $x_negative, $y_value, $y_negative) - { - //if ( $x_value == $y_value ) { - // return array( - // MATH_BIGINTEGER_VALUE => $this->_square($x_value), - // MATH_BIGINTEGER_SIGN => $x_sign != $y_value - // ); - //} - - $x_length = count($x_value); - $y_length = count($y_value); - - if ( !$x_length || !$y_length ) { // a 0 is being multiplied - return array( - MATH_BIGINTEGER_VALUE => array(), - MATH_BIGINTEGER_SIGN => false - ); - } - - return array( - MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? - $this->_trim($this->_regularMultiply($x_value, $y_value)) : - $this->_trim($this->_karatsuba($x_value, $y_value)), - MATH_BIGINTEGER_SIGN => $x_negative != $y_negative - ); - } - - /** - * Performs long multiplication on two BigIntegers - * - * Modeled after 'multiply' in MutableBigInteger.java. - * - * @param Array $x_value - * @param Array $y_value - * @return Array - * @access private - */ - function _regularMultiply($x_value, $y_value) - { - $x_length = count($x_value); - $y_length = count($y_value); - - if ( !$x_length || !$y_length ) { // a 0 is being multiplied - return array(); - } - - if ( $x_length < $y_length ) { - $temp = $x_value; - $x_value = $y_value; - $y_value = $temp; - - $x_length = count($x_value); - $y_length = count($y_value); - } - - $product_value = $this->_array_repeat(0, $x_length + $y_length); - - // the following for loop could be removed if the for loop following it - // (the one with nested for loops) initially set $i to 0, but - // doing so would also make the result in one set of unnecessary adds, - // since on the outermost loops first pass, $product->value[$k] is going - // to always be 0 - - $carry = 0; - - for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0 - $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 - $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); - $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); - } - - $product_value[$j] = $carry; - - // the above for loop is what the previous comment was talking about. the - // following for loop is the "one with nested for loops" - for ($i = 1; $i < $y_length; ++$i) { - $carry = 0; - - for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { - $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; - $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); - $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); - } - - $product_value[$k] = $carry; - } - - return $product_value; - } - - /** - * Performs Karatsuba multiplication on two BigIntegers - * - * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}. - * - * @param Array $x_value - * @param Array $y_value - * @return Array - * @access private - */ - function _karatsuba($x_value, $y_value) - { - $m = min(count($x_value) >> 1, count($y_value) >> 1); - - if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { - return $this->_regularMultiply($x_value, $y_value); - } - - $x1 = array_slice($x_value, $m); - $x0 = array_slice($x_value, 0, $m); - $y1 = array_slice($y_value, $m); - $y0 = array_slice($y_value, 0, $m); - - $z2 = $this->_karatsuba($x1, $y1); - $z0 = $this->_karatsuba($x0, $y0); - - $z1 = $this->_add($x1, false, $x0, false); - $temp = $this->_add($y1, false, $y0, false); - $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]); - $temp = $this->_add($z2, false, $z0, false); - $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); - - $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2); - $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]); - - $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); - $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false); - - return $xy[MATH_BIGINTEGER_VALUE]; - } - - /** - * Performs squaring - * - * @param Array $x - * @return Array - * @access private - */ - function _square($x = false) - { - return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? - $this->_trim($this->_baseSquare($x)) : - $this->_trim($this->_karatsubaSquare($x)); - } - - /** - * Performs traditional squaring on two BigIntegers - * - * Squaring can be done faster than multiplying a number by itself can be. See - * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} / - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information. - * - * @param Array $value - * @return Array - * @access private - */ - function _baseSquare($value) - { - if ( empty($value) ) { - return array(); - } - $square_value = $this->_array_repeat(0, 2 * count($value)); - - for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) { - $i2 = $i << 1; - - $temp = $square_value[$i2] + $value[$i] * $value[$i]; - $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); - $square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); - - // note how we start from $i+1 instead of 0 as we do in multiplication. - for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) { - $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; - $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); - $square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); - } - - // the following line can yield values larger 2**15. at this point, PHP should switch - // over to floats. - $square_value[$i + $max_index + 1] = $carry; - } - - return $square_value; - } - - /** - * Performs Karatsuba "squaring" on two BigIntegers - * - * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}. - * - * @param Array $value - * @return Array - * @access private - */ - function _karatsubaSquare($value) - { - $m = count($value) >> 1; - - if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { - return $this->_baseSquare($value); - } - - $x1 = array_slice($value, $m); - $x0 = array_slice($value, 0, $m); - - $z2 = $this->_karatsubaSquare($x1); - $z0 = $this->_karatsubaSquare($x0); - - $z1 = $this->_add($x1, false, $x0, false); - $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]); - $temp = $this->_add($z2, false, $z0, false); - $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); - - $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2); - $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]); - - $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); - $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false); - - return $xx[MATH_BIGINTEGER_VALUE]; - } - - /** - * Divides two BigIntegers. - * - * Returns an array whose first element contains the quotient and whose second element contains the - * "common residue". If the remainder would be positive, the "common residue" and the remainder are the - * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder - * and the divisor (basically, the "common residue" is the first positive modulo). - * - * Here's an example: - * - * divide($b); - * - * echo $quotient->toString(); // outputs 0 - * echo "\r\n"; - * echo $remainder->toString(); // outputs 10 - * ?> - * - * - * @param Math_BigInteger $y - * @return Array - * @access public - * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}. - */ - function divide($y) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $quotient = new Math_BigInteger(); - $remainder = new Math_BigInteger(); - - list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value); - - if (gmp_sign($remainder->value) < 0) { - $remainder->value = gmp_add($remainder->value, gmp_abs($y->value)); - } - - return array($this->_normalize($quotient), $this->_normalize($remainder)); - case MATH_BIGINTEGER_MODE_BCMATH: - $quotient = new Math_BigInteger(); - $remainder = new Math_BigInteger(); - - $quotient->value = bcdiv($this->value, $y->value, 0); - $remainder->value = bcmod($this->value, $y->value); - - if ($remainder->value[0] == '-') { - $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0); - } - - return array($this->_normalize($quotient), $this->_normalize($remainder)); - } - - if (count($y->value) == 1) { - list($q, $r) = $this->_divide_digit($this->value, $y->value[0]); - $quotient = new Math_BigInteger(); - $remainder = new Math_BigInteger(); - $quotient->value = $q; - $remainder->value = array($r); - $quotient->is_negative = $this->is_negative != $y->is_negative; - return array($this->_normalize($quotient), $this->_normalize($remainder)); - } - - static $zero; - if ( !isset($zero) ) { - $zero = new Math_BigInteger(); - } - - $x = $this->copy(); - $y = $y->copy(); - - $x_sign = $x->is_negative; - $y_sign = $y->is_negative; - - $x->is_negative = $y->is_negative = false; - - $diff = $x->compare($y); - - if ( !$diff ) { - $temp = new Math_BigInteger(); - $temp->value = array(1); - $temp->is_negative = $x_sign != $y_sign; - return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger())); - } - - if ( $diff < 0 ) { - // if $x is negative, "add" $y. - if ( $x_sign ) { - $x = $y->subtract($x); - } - return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x)); - } - - // normalize $x and $y as described in HAC 14.23 / 14.24 - $msb = $y->value[count($y->value) - 1]; - for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) { - $msb <<= 1; - } - $x->_lshift($shift); - $y->_lshift($shift); - $y_value = &$y->value; - - $x_max = count($x->value) - 1; - $y_max = count($y->value) - 1; - - $quotient = new Math_BigInteger(); - $quotient_value = &$quotient->value; - $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1); - - static $temp, $lhs, $rhs; - if (!isset($temp)) { - $temp = new Math_BigInteger(); - $lhs = new Math_BigInteger(); - $rhs = new Math_BigInteger(); - } - $temp_value = &$temp->value; - $rhs_value = &$rhs->value; - - // $temp = $y << ($x_max - $y_max-1) in base 2**26 - $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value); - - while ( $x->compare($temp) >= 0 ) { - // calculate the "common residue" - ++$quotient_value[$x_max - $y_max]; - $x = $x->subtract($temp); - $x_max = count($x->value) - 1; - } - - for ($i = $x_max; $i >= $y_max + 1; --$i) { - $x_value = &$x->value; - $x_window = array( - isset($x_value[$i]) ? $x_value[$i] : 0, - isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0, - isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0 - ); - $y_window = array( - $y_value[$y_max], - ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0 - ); - - $q_index = $i - $y_max - 1; - if ($x_window[0] == $y_window[0]) { - $quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT; - } else { - $quotient_value[$q_index] = $this->_safe_divide( - $x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1], - $y_window[0] - ); - } - - $temp_value = array($y_window[1], $y_window[0]); - - $lhs->value = array($quotient_value[$q_index]); - $lhs = $lhs->multiply($temp); - - $rhs_value = array($x_window[2], $x_window[1], $x_window[0]); - - while ( $lhs->compare($rhs) > 0 ) { - --$quotient_value[$q_index]; - - $lhs->value = array($quotient_value[$q_index]); - $lhs = $lhs->multiply($temp); - } - - $adjust = $this->_array_repeat(0, $q_index); - $temp_value = array($quotient_value[$q_index]); - $temp = $temp->multiply($y); - $temp_value = &$temp->value; - $temp_value = array_merge($adjust, $temp_value); - - $x = $x->subtract($temp); - - if ($x->compare($zero) < 0) { - $temp_value = array_merge($adjust, $y_value); - $x = $x->add($temp); - - --$quotient_value[$q_index]; - } - - $x_max = count($x_value) - 1; - } - - // unnormalize the remainder - $x->_rshift($shift); - - $quotient->is_negative = $x_sign != $y_sign; - - // calculate the "common residue", if appropriate - if ( $x_sign ) { - $y->_rshift($shift); - $x = $y->subtract($x); - } - - return array($this->_normalize($quotient), $this->_normalize($x)); - } - - /** - * Divides a BigInteger by a regular integer - * - * abc / x = a00 / x + b0 / x + c / x - * - * @param Array $dividend - * @param Array $divisor - * @return Array - * @access private - */ - function _divide_digit($dividend, $divisor) - { - $carry = 0; - $result = array(); - - for ($i = count($dividend) - 1; $i >= 0; --$i) { - $temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i]; - $result[$i] = $this->_safe_divide($temp, $divisor); - $carry = (int) ($temp - $divisor * $result[$i]); - } - - return array($result, $carry); - } - - /** - * Performs modular exponentiation. - * - * Here's an example: - * - * modPow($b, $c); - * - * echo $c->toString(); // outputs 10 - * ?> - * - * - * @param Math_BigInteger $e - * @param Math_BigInteger $n - * @return Math_BigInteger - * @access public - * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and - * and although the approach involving repeated squaring does vastly better, it, too, is impractical - * for our purposes. The reason being that division - by far the most complicated and time-consuming - * of the basic operations (eg. +,-,*,/) - occurs multiple times within it. - * - * Modular reductions resolve this issue. Although an individual modular reduction takes more time - * then an individual division, when performed in succession (with the same modulo), they're a lot faster. - * - * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction, - * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the - * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because - * the product of two odd numbers is odd), but what about when RSA isn't used? - * - * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a - * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the - * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however, - * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and - * the other, a power of two - and recombine them, later. This is the method that this modPow function uses. - * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates. - */ - function modPow($e, $n) - { - $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs(); - - if ($e->compare(new Math_BigInteger()) < 0) { - $e = $e->abs(); - - $temp = $this->modInverse($n); - if ($temp === false) { - return false; - } - - return $this->_normalize($temp->modPow($e, $n)); - } - - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) { - $temp = new Math_BigInteger(); - $temp->value = gmp_powm($this->value, $e->value, $n->value); - - return $this->_normalize($temp); - } - - if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) { - list(, $temp) = $this->divide($n); - return $temp->modPow($e, $n); - } - - if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { - $components = array( - 'modulus' => $n->toBytes(true), - 'publicExponent' => $e->toBytes(true) - ); - - $components = array( - 'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']), - 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent']) - ); - - $RSAPublicKey = pack('Ca*a*a*', - 48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])), - $components['modulus'], $components['publicExponent'] - ); - - $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA - $RSAPublicKey = chr(0) . $RSAPublicKey; - $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey; - - $encapsulated = pack('Ca*a*', - 48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey - ); - - $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . - chunk_split(base64_encode($encapsulated)) . - '-----END PUBLIC KEY-----'; - - $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT); - - if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) { - return new Math_BigInteger($result, 256); - } - } - - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { - $temp = new Math_BigInteger(); - $temp->value = bcpowmod($this->value, $e->value, $n->value, 0); - - return $this->_normalize($temp); - } - - if ( empty($e->value) ) { - $temp = new Math_BigInteger(); - $temp->value = array(1); - return $this->_normalize($temp); - } - - if ( $e->value == array(1) ) { - list(, $temp) = $this->divide($n); - return $this->_normalize($temp); - } - - if ( $e->value == array(2) ) { - $temp = new Math_BigInteger(); - $temp->value = $this->_square($this->value); - list(, $temp) = $temp->divide($n); - return $this->_normalize($temp); - } - - return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT)); - - // the following code, although not callable, can be run independently of the above code - // although the above code performed better in my benchmarks the following could might - // perform better under different circumstances. in lieu of deleting it it's just been - // made uncallable - - // is the modulo odd? - if ( $n->value[0] & 1 ) { - return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY)); - } - // if it's not, it's even - - // find the lowest set bit (eg. the max pow of 2 that divides $n) - for ($i = 0; $i < count($n->value); ++$i) { - if ( $n->value[$i] ) { - $temp = decbin($n->value[$i]); - $j = strlen($temp) - strrpos($temp, '1') - 1; - $j+= 26 * $i; - break; - } - } - // at this point, 2^$j * $n/(2^$j) == $n - - $mod1 = $n->copy(); - $mod1->_rshift($j); - $mod2 = new Math_BigInteger(); - $mod2->value = array(1); - $mod2->_lshift($j); - - $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger(); - $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2); - - $y1 = $mod2->modInverse($mod1); - $y2 = $mod1->modInverse($mod2); - - $result = $part1->multiply($mod2); - $result = $result->multiply($y1); - - $temp = $part2->multiply($mod1); - $temp = $temp->multiply($y2); - - $result = $result->add($temp); - list(, $result) = $result->divide($n); - - return $this->_normalize($result); - } - - /** - * Performs modular exponentiation. - * - * Alias for Math_BigInteger::modPow() - * - * @param Math_BigInteger $e - * @param Math_BigInteger $n - * @return Math_BigInteger - * @access public - */ - function powMod($e, $n) - { - return $this->modPow($e, $n); - } - - /** - * Sliding Window k-ary Modular Exponentiation - * - * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} / - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims, - * however, this function performs a modular reduction after every multiplication and squaring operation. - * As such, this function has the same preconditions that the reductions being used do. - * - * @param Math_BigInteger $e - * @param Math_BigInteger $n - * @param Integer $mode - * @return Math_BigInteger - * @access private - */ - function _slidingWindow($e, $n, $mode) - { - static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function - //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1 - - $e_value = $e->value; - $e_length = count($e_value) - 1; - $e_bits = decbin($e_value[$e_length]); - for ($i = $e_length - 1; $i >= 0; --$i) { - $e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT); - } - - $e_length = strlen($e_bits); - - // calculate the appropriate window size. - // $window_size == 3 if $window_ranges is between 25 and 81, for example. - for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i); - - $n_value = $n->value; - - // precompute $this^0 through $this^$window_size - $powers = array(); - $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode); - $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode); - - // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end - // in a 1. ie. it's supposed to be odd. - $temp = 1 << ($window_size - 1); - for ($i = 1; $i < $temp; ++$i) { - $i2 = $i << 1; - $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode); - } - - $result = array(1); - $result = $this->_prepareReduce($result, $n_value, $mode); - - for ($i = 0; $i < $e_length; ) { - if ( !$e_bits[$i] ) { - $result = $this->_squareReduce($result, $n_value, $mode); - ++$i; - } else { - for ($j = $window_size - 1; $j > 0; --$j) { - if ( !empty($e_bits[$i + $j]) ) { - break; - } - } - - for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1) - $result = $this->_squareReduce($result, $n_value, $mode); - } - - $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode); - - $i+=$j + 1; - } - } - - $temp = new Math_BigInteger(); - $temp->value = $this->_reduce($result, $n_value, $mode); - - return $temp; - } - - /** - * Modular reduction - * - * For most $modes this will return the remainder. - * - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @param Integer $mode - * @return Array - */ - function _reduce($x, $n, $mode) - { - switch ($mode) { - case MATH_BIGINTEGER_MONTGOMERY: - return $this->_montgomery($x, $n); - case MATH_BIGINTEGER_BARRETT: - return $this->_barrett($x, $n); - case MATH_BIGINTEGER_POWEROF2: - $lhs = new Math_BigInteger(); - $lhs->value = $x; - $rhs = new Math_BigInteger(); - $rhs->value = $n; - return $x->_mod2($n); - case MATH_BIGINTEGER_CLASSIC: - $lhs = new Math_BigInteger(); - $lhs->value = $x; - $rhs = new Math_BigInteger(); - $rhs->value = $n; - list(, $temp) = $lhs->divide($rhs); - return $temp->value; - case MATH_BIGINTEGER_NONE: - return $x; - default: - // an invalid $mode was provided - } - } - - /** - * Modular reduction preperation - * - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @param Integer $mode - * @return Array - */ - function _prepareReduce($x, $n, $mode) - { - if ($mode == MATH_BIGINTEGER_MONTGOMERY) { - return $this->_prepMontgomery($x, $n); - } - return $this->_reduce($x, $n, $mode); - } - - /** - * Modular multiply - * - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $y - * @param Array $n - * @param Integer $mode - * @return Array - */ - function _multiplyReduce($x, $y, $n, $mode) - { - if ($mode == MATH_BIGINTEGER_MONTGOMERY) { - return $this->_montgomeryMultiply($x, $y, $n); - } - $temp = $this->_multiply($x, false, $y, false); - return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode); - } - - /** - * Modular square - * - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @param Integer $mode - * @return Array - */ - function _squareReduce($x, $n, $mode) - { - if ($mode == MATH_BIGINTEGER_MONTGOMERY) { - return $this->_montgomeryMultiply($x, $x, $n); - } - return $this->_reduce($this->_square($x), $n, $mode); - } - - /** - * Modulos for Powers of Two - * - * Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1), - * we'll just use this function as a wrapper for doing that. - * - * @see _slidingWindow() - * @access private - * @param Math_BigInteger - * @return Math_BigInteger - */ - function _mod2($n) - { - $temp = new Math_BigInteger(); - $temp->value = array(1); - return $this->bitwise_and($n->subtract($temp)); - } - - /** - * Barrett Modular Reduction - * - * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} / - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly, - * so as not to require negative numbers (initially, this script didn't support negative numbers). - * - * Employs "folding", as described at - * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from - * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x." - * - * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that - * usable on account of (1) its not using reasonable radix points as discussed in - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable - * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that - * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line - * comments for details. - * - * @see _slidingWindow() - * @access private - * @param Array $n - * @param Array $m - * @return Array - */ - function _barrett($n, $m) - { - static $cache = array( - MATH_BIGINTEGER_VARIABLE => array(), - MATH_BIGINTEGER_DATA => array() - ); - - $m_length = count($m); - - // if ($this->_compare($n, $this->_square($m)) >= 0) { - if (count($n) > 2 * $m_length) { - $lhs = new Math_BigInteger(); - $rhs = new Math_BigInteger(); - $lhs->value = $n; - $rhs->value = $m; - list(, $temp) = $lhs->divide($rhs); - return $temp->value; - } - - // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced - if ($m_length < 5) { - return $this->_regularBarrett($n, $m); - } - - // n = 2 * m.length - - if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { - $key = count($cache[MATH_BIGINTEGER_VARIABLE]); - $cache[MATH_BIGINTEGER_VARIABLE][] = $m; - - $lhs = new Math_BigInteger(); - $lhs_value = &$lhs->value; - $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1)); - $lhs_value[] = 1; - $rhs = new Math_BigInteger(); - $rhs->value = $m; - - list($u, $m1) = $lhs->divide($rhs); - $u = $u->value; - $m1 = $m1->value; - - $cache[MATH_BIGINTEGER_DATA][] = array( - 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1) - 'm1'=> $m1 // m.length - ); - } else { - extract($cache[MATH_BIGINTEGER_DATA][$key]); - } - - $cutoff = $m_length + ($m_length >> 1); - $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1) - $msd = array_slice($n, $cutoff); // m.length >> 1 - $lsd = $this->_trim($lsd); - $temp = $this->_multiply($msd, false, $m1, false); - $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1 - - if ($m_length & 1) { - return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m); - } - - // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2 - $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1); - // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2 - // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1 - $temp = $this->_multiply($temp, false, $u, false); - // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1 - // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) - $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1); - // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1 - // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1) - $temp = $this->_multiply($temp, false, $m, false); - - // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit - // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop - // following this comment would loop a lot (hence our calling _regularBarrett() in that situation). - - $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); - - while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) { - $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false); - } - - return $result[MATH_BIGINTEGER_VALUE]; - } - - /** - * (Regular) Barrett Modular Reduction - * - * For numbers with more than four digits Math_BigInteger::_barrett() is faster. The difference between that and this - * is that this function does not fold the denominator into a smaller form. - * - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @return Array - */ - function _regularBarrett($x, $n) - { - static $cache = array( - MATH_BIGINTEGER_VARIABLE => array(), - MATH_BIGINTEGER_DATA => array() - ); - - $n_length = count($n); - - if (count($x) > 2 * $n_length) { - $lhs = new Math_BigInteger(); - $rhs = new Math_BigInteger(); - $lhs->value = $x; - $rhs->value = $n; - list(, $temp) = $lhs->divide($rhs); - return $temp->value; - } - - if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { - $key = count($cache[MATH_BIGINTEGER_VARIABLE]); - $cache[MATH_BIGINTEGER_VARIABLE][] = $n; - $lhs = new Math_BigInteger(); - $lhs_value = &$lhs->value; - $lhs_value = $this->_array_repeat(0, 2 * $n_length); - $lhs_value[] = 1; - $rhs = new Math_BigInteger(); - $rhs->value = $n; - list($temp, ) = $lhs->divide($rhs); // m.length - $cache[MATH_BIGINTEGER_DATA][] = $temp->value; - } - - // 2 * m.length - (m.length - 1) = m.length + 1 - $temp = array_slice($x, $n_length - 1); - // (m.length + 1) + m.length = 2 * m.length + 1 - $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false); - // (2 * m.length + 1) - (m.length - 1) = m.length + 2 - $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1); - - // m.length + 1 - $result = array_slice($x, 0, $n_length + 1); - // m.length + 1 - $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1); - // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1) - - if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) { - $corrector_value = $this->_array_repeat(0, $n_length + 1); - $corrector_value[count($corrector_value)] = 1; - $result = $this->_add($result, false, $corrector_value, false); - $result = $result[MATH_BIGINTEGER_VALUE]; - } - - // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits - $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]); - while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) { - $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false); - } - - return $result[MATH_BIGINTEGER_VALUE]; - } - - /** - * Performs long multiplication up to $stop digits - * - * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved. - * - * @see _regularBarrett() - * @param Array $x_value - * @param Boolean $x_negative - * @param Array $y_value - * @param Boolean $y_negative - * @param Integer $stop - * @return Array - * @access private - */ - function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop) - { - $x_length = count($x_value); - $y_length = count($y_value); - - if ( !$x_length || !$y_length ) { // a 0 is being multiplied - return array( - MATH_BIGINTEGER_VALUE => array(), - MATH_BIGINTEGER_SIGN => false - ); - } - - if ( $x_length < $y_length ) { - $temp = $x_value; - $x_value = $y_value; - $y_value = $temp; - - $x_length = count($x_value); - $y_length = count($y_value); - } - - $product_value = $this->_array_repeat(0, $x_length + $y_length); - - // the following for loop could be removed if the for loop following it - // (the one with nested for loops) initially set $i to 0, but - // doing so would also make the result in one set of unnecessary adds, - // since on the outermost loops first pass, $product->value[$k] is going - // to always be 0 - - $carry = 0; - - for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i - $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 - $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); - $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); - } - - if ($j < $stop) { - $product_value[$j] = $carry; - } - - // the above for loop is what the previous comment was talking about. the - // following for loop is the "one with nested for loops" - - for ($i = 1; $i < $y_length; ++$i) { - $carry = 0; - - for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { - $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; - $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); - $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); - } - - if ($k < $stop) { - $product_value[$k] = $carry; - } - } - - return array( - MATH_BIGINTEGER_VALUE => $this->_trim($product_value), - MATH_BIGINTEGER_SIGN => $x_negative != $y_negative - ); - } - - /** - * Montgomery Modular Reduction - * - * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n. - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be - * improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function - * to work correctly. - * - * @see _prepMontgomery() - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @return Array - */ - function _montgomery($x, $n) - { - static $cache = array( - MATH_BIGINTEGER_VARIABLE => array(), - MATH_BIGINTEGER_DATA => array() - ); - - if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { - $key = count($cache[MATH_BIGINTEGER_VARIABLE]); - $cache[MATH_BIGINTEGER_VARIABLE][] = $x; - $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n); - } - - $k = count($n); - - $result = array(MATH_BIGINTEGER_VALUE => $x); - - for ($i = 0; $i < $k; ++$i) { - $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key]; - $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31)); - $temp = $this->_regularMultiply(array($temp), $n); - $temp = array_merge($this->_array_repeat(0, $i), $temp); - $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false); - } - - $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k); - - if ($this->_compare($result, false, $n, false) >= 0) { - $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false); - } - - return $result[MATH_BIGINTEGER_VALUE]; - } - - /** - * Montgomery Multiply - * - * Interleaves the montgomery reduction and long multiplication algorithms together as described in - * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36} - * - * @see _prepMontgomery() - * @see _montgomery() - * @access private - * @param Array $x - * @param Array $y - * @param Array $m - * @return Array - */ - function _montgomeryMultiply($x, $y, $m) - { - $temp = $this->_multiply($x, false, $y, false); - return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m); - - // the following code, although not callable, can be run independently of the above code - // although the above code performed better in my benchmarks the following could might - // perform better under different circumstances. in lieu of deleting it it's just been - // made uncallable - - static $cache = array( - MATH_BIGINTEGER_VARIABLE => array(), - MATH_BIGINTEGER_DATA => array() - ); - - if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { - $key = count($cache[MATH_BIGINTEGER_VARIABLE]); - $cache[MATH_BIGINTEGER_VARIABLE][] = $m; - $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m); - } - - $n = max(count($x), count($y), count($m)); - $x = array_pad($x, $n, 0); - $y = array_pad($y, $n, 0); - $m = array_pad($m, $n, 0); - $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1)); - for ($i = 0; $i < $n; ++$i) { - $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0]; - $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31)); - $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key]; - $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31)); - $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false); - $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); - $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1); - } - if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) { - $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false); - } - return $a[MATH_BIGINTEGER_VALUE]; - } - - /** - * Prepare a number for use in Montgomery Modular Reductions - * - * @see _montgomery() - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @return Array - */ - function _prepMontgomery($x, $n) - { - $lhs = new Math_BigInteger(); - $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x); - $rhs = new Math_BigInteger(); - $rhs->value = $n; - - list(, $temp) = $lhs->divide($rhs); - return $temp->value; - } - - /** - * Modular Inverse of a number mod 2**26 (eg. 67108864) - * - * Based off of the bnpInvDigit function implemented and justified in the following URL: - * - * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js} - * - * The following URL provides more info: - * - * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85} - * - * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For - * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields - * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't - * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that - * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the - * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to - * 40 bits, which only 64-bit floating points will support. - * - * Thanks to Pedro Gimeno Fortea for input! - * - * @see _montgomery() - * @access private - * @param Array $x - * @return Integer - */ - function _modInverse67108864($x) // 2**26 == 67,108,864 - { - $x = -$x[0]; - $result = $x & 0x3; // x**-1 mod 2**2 - $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4 - $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8 - $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16 - $result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26 - return $result & MATH_BIGINTEGER_MAX_DIGIT; - } - - /** - * Calculates modular inverses. - * - * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. - * - * Here's an example: - * - * modInverse($b); - * echo $c->toString(); // outputs 4 - * - * echo "\r\n"; - * - * $d = $a->multiply($c); - * list(, $d) = $d->divide($b); - * echo $d; // outputs 1 (as per the definition of modular inverse) - * ?> - * - * - * @param Math_BigInteger $n - * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise. - * @access public - * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information. - */ - function modInverse($n) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_invert($this->value, $n->value); - - return ( $temp->value === false ) ? false : $this->_normalize($temp); - } - - static $zero, $one; - if (!isset($zero)) { - $zero = new Math_BigInteger(); - $one = new Math_BigInteger(1); - } - - // $x mod -$n == $x mod $n. - $n = $n->abs(); - - if ($this->compare($zero) < 0) { - $temp = $this->abs(); - $temp = $temp->modInverse($n); - return $this->_normalize($n->subtract($temp)); - } - - extract($this->extendedGCD($n)); - - if (!$gcd->equals($one)) { - return false; - } - - $x = $x->compare($zero) < 0 ? $x->add($n) : $x; - - return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x); - } - - /** - * Calculates the greatest common divisor and Bezout's identity. - * - * Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that - * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which - * combination is returned is dependant upon which mode is in use. See - * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information. - * - * Here's an example: - * - * extendedGCD($b)); - * - * echo $gcd->toString() . "\r\n"; // outputs 21 - * echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21 - * ?> - * - * - * @param Math_BigInteger $n - * @return Math_BigInteger - * @access public - * @internal Calculates the GCD using the binary xGCD algorithim described in - * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes, - * the more traditional algorithim requires "relatively costly multiple-precision divisions". - */ - function extendedGCD($n) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - extract(gmp_gcdext($this->value, $n->value)); - - return array( - 'gcd' => $this->_normalize(new Math_BigInteger($g)), - 'x' => $this->_normalize(new Math_BigInteger($s)), - 'y' => $this->_normalize(new Math_BigInteger($t)) - ); - case MATH_BIGINTEGER_MODE_BCMATH: - // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works - // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is, - // the basic extended euclidean algorithim is what we're using. - - $u = $this->value; - $v = $n->value; - - $a = '1'; - $b = '0'; - $c = '0'; - $d = '1'; - - while (bccomp($v, '0', 0) != 0) { - $q = bcdiv($u, $v, 0); - - $temp = $u; - $u = $v; - $v = bcsub($temp, bcmul($v, $q, 0), 0); - - $temp = $a; - $a = $c; - $c = bcsub($temp, bcmul($a, $q, 0), 0); - - $temp = $b; - $b = $d; - $d = bcsub($temp, bcmul($b, $q, 0), 0); - } - - return array( - 'gcd' => $this->_normalize(new Math_BigInteger($u)), - 'x' => $this->_normalize(new Math_BigInteger($a)), - 'y' => $this->_normalize(new Math_BigInteger($b)) - ); - } - - $y = $n->copy(); - $x = $this->copy(); - $g = new Math_BigInteger(); - $g->value = array(1); - - while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) { - $x->_rshift(1); - $y->_rshift(1); - $g->_lshift(1); - } - - $u = $x->copy(); - $v = $y->copy(); - - $a = new Math_BigInteger(); - $b = new Math_BigInteger(); - $c = new Math_BigInteger(); - $d = new Math_BigInteger(); - - $a->value = $d->value = $g->value = array(1); - $b->value = $c->value = array(); - - while ( !empty($u->value) ) { - while ( !($u->value[0] & 1) ) { - $u->_rshift(1); - if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) { - $a = $a->add($y); - $b = $b->subtract($x); - } - $a->_rshift(1); - $b->_rshift(1); - } - - while ( !($v->value[0] & 1) ) { - $v->_rshift(1); - if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) { - $c = $c->add($y); - $d = $d->subtract($x); - } - $c->_rshift(1); - $d->_rshift(1); - } - - if ($u->compare($v) >= 0) { - $u = $u->subtract($v); - $a = $a->subtract($c); - $b = $b->subtract($d); - } else { - $v = $v->subtract($u); - $c = $c->subtract($a); - $d = $d->subtract($b); - } - } - - return array( - 'gcd' => $this->_normalize($g->multiply($v)), - 'x' => $this->_normalize($c), - 'y' => $this->_normalize($d) - ); - } - - /** - * Calculates the greatest common divisor - * - * Say you have 693 and 609. The GCD is 21. - * - * Here's an example: - * - * extendedGCD($b); - * - * echo $gcd->toString() . "\r\n"; // outputs 21 - * ?> - * - * - * @param Math_BigInteger $n - * @return Math_BigInteger - * @access public - */ - function gcd($n) - { - extract($this->extendedGCD($n)); - return $gcd; - } - - /** - * Absolute value. - * - * @return Math_BigInteger - * @access public - */ - function abs() - { - $temp = new Math_BigInteger(); - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp->value = gmp_abs($this->value); - break; - case MATH_BIGINTEGER_MODE_BCMATH: - $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value; - break; - default: - $temp->value = $this->value; - } - - return $temp; - } - - /** - * Compares two numbers. - * - * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is - * demonstrated thusly: - * - * $x > $y: $x->compare($y) > 0 - * $x < $y: $x->compare($y) < 0 - * $x == $y: $x->compare($y) == 0 - * - * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). - * - * @param Math_BigInteger $y - * @return Integer < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. - * @access public - * @see equals() - * @internal Could return $this->subtract($x), but that's not as fast as what we do do. - */ - function compare($y) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - return gmp_cmp($this->value, $y->value); - case MATH_BIGINTEGER_MODE_BCMATH: - return bccomp($this->value, $y->value, 0); - } - - return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative); - } - - /** - * Compares two numbers. - * - * @param Array $x_value - * @param Boolean $x_negative - * @param Array $y_value - * @param Boolean $y_negative - * @return Integer - * @see compare() - * @access private - */ - function _compare($x_value, $x_negative, $y_value, $y_negative) - { - if ( $x_negative != $y_negative ) { - return ( !$x_negative && $y_negative ) ? 1 : -1; - } - - $result = $x_negative ? -1 : 1; - - if ( count($x_value) != count($y_value) ) { - return ( count($x_value) > count($y_value) ) ? $result : -$result; - } - $size = max(count($x_value), count($y_value)); - - $x_value = array_pad($x_value, $size, 0); - $y_value = array_pad($y_value, $size, 0); - - for ($i = count($x_value) - 1; $i >= 0; --$i) { - if ($x_value[$i] != $y_value[$i]) { - return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result; - } - } - - return 0; - } - - /** - * Tests the equality of two numbers. - * - * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare() - * - * @param Math_BigInteger $x - * @return Boolean - * @access public - * @see compare() - */ - function equals($x) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - return gmp_cmp($this->value, $x->value) == 0; - default: - return $this->value === $x->value && $this->is_negative == $x->is_negative; - } - } - - /** - * Set Precision - * - * Some bitwise operations give different results depending on the precision being used. Examples include left - * shift, not, and rotates. - * - * @param Integer $bits - * @access public - */ - function setPrecision($bits) - { - $this->precision = $bits; - if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) { - $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256); - } else { - $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0)); - } - - $temp = $this->_normalize($this); - $this->value = $temp->value; - } - - /** - * Logical And - * - * @param Math_BigInteger $x - * @access public - * @internal Implemented per a request by Lluis Pamies i Juarez - * @return Math_BigInteger - */ - function bitwise_and($x) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_and($this->value, $x->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $left = $this->toBytes(); - $right = $x->toBytes(); - - $length = max(strlen($left), strlen($right)); - - $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); - $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); - - return $this->_normalize(new Math_BigInteger($left & $right, 256)); - } - - $result = $this->copy(); - - $length = min(count($x->value), count($this->value)); - - $result->value = array_slice($result->value, 0, $length); - - for ($i = 0; $i < $length; ++$i) { - $result->value[$i]&= $x->value[$i]; - } - - return $this->_normalize($result); - } - - /** - * Logical Or - * - * @param Math_BigInteger $x - * @access public - * @internal Implemented per a request by Lluis Pamies i Juarez - * @return Math_BigInteger - */ - function bitwise_or($x) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_or($this->value, $x->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $left = $this->toBytes(); - $right = $x->toBytes(); - - $length = max(strlen($left), strlen($right)); - - $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); - $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); - - return $this->_normalize(new Math_BigInteger($left | $right, 256)); - } - - $length = max(count($this->value), count($x->value)); - $result = $this->copy(); - $result->value = array_pad($result->value, $length, 0); - $x->value = array_pad($x->value, $length, 0); - - for ($i = 0; $i < $length; ++$i) { - $result->value[$i]|= $x->value[$i]; - } - - return $this->_normalize($result); - } - - /** - * Logical Exclusive-Or - * - * @param Math_BigInteger $x - * @access public - * @internal Implemented per a request by Lluis Pamies i Juarez - * @return Math_BigInteger - */ - function bitwise_xor($x) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_xor($this->value, $x->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $left = $this->toBytes(); - $right = $x->toBytes(); - - $length = max(strlen($left), strlen($right)); - - $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); - $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); - - return $this->_normalize(new Math_BigInteger($left ^ $right, 256)); - } - - $length = max(count($this->value), count($x->value)); - $result = $this->copy(); - $result->value = array_pad($result->value, $length, 0); - $x->value = array_pad($x->value, $length, 0); - - for ($i = 0; $i < $length; ++$i) { - $result->value[$i]^= $x->value[$i]; - } - - return $this->_normalize($result); - } - - /** - * Logical Not - * - * @access public - * @internal Implemented per a request by Lluis Pamies i Juarez - * @return Math_BigInteger - */ - function bitwise_not() - { - // calculuate "not" without regard to $this->precision - // (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0) - $temp = $this->toBytes(); - $pre_msb = decbin(ord($temp[0])); - $temp = ~$temp; - $msb = decbin(ord($temp[0])); - if (strlen($msb) == 8) { - $msb = substr($msb, strpos($msb, '0')); - } - $temp[0] = chr(bindec($msb)); - - // see if we need to add extra leading 1's - $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8; - $new_bits = $this->precision - $current_bits; - if ($new_bits <= 0) { - return $this->_normalize(new Math_BigInteger($temp, 256)); - } - - // generate as many leading 1's as we need to. - $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3); - $this->_base256_lshift($leading_ones, $current_bits); - - $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT); - - return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256)); - } - - /** - * Logical Right Shift - * - * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift. - * - * @param Integer $shift - * @return Math_BigInteger - * @access public - * @internal The only version that yields any speed increases is the internal version. - */ - function bitwise_rightShift($shift) - { - $temp = new Math_BigInteger(); - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - static $two; - - if (!isset($two)) { - $two = gmp_init('2'); - } - - $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift)); - - break; - case MATH_BIGINTEGER_MODE_BCMATH: - $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0); - - break; - default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten - // and I don't want to do that... - $temp->value = $this->value; - $temp->_rshift($shift); - } - - return $this->_normalize($temp); - } - - /** - * Logical Left Shift - * - * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift. - * - * @param Integer $shift - * @return Math_BigInteger - * @access public - * @internal The only version that yields any speed increases is the internal version. - */ - function bitwise_leftShift($shift) - { - $temp = new Math_BigInteger(); - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - static $two; - - if (!isset($two)) { - $two = gmp_init('2'); - } - - $temp->value = gmp_mul($this->value, gmp_pow($two, $shift)); - - break; - case MATH_BIGINTEGER_MODE_BCMATH: - $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0); - - break; - default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten - // and I don't want to do that... - $temp->value = $this->value; - $temp->_lshift($shift); - } - - return $this->_normalize($temp); - } - - /** - * Logical Left Rotate - * - * Instead of the top x bits being dropped they're appended to the shifted bit string. - * - * @param Integer $shift - * @return Math_BigInteger - * @access public - */ - function bitwise_leftRotate($shift) - { - $bits = $this->toBytes(); - - if ($this->precision > 0) { - $precision = $this->precision; - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { - $mask = $this->bitmask->subtract(new Math_BigInteger(1)); - $mask = $mask->toBytes(); - } else { - $mask = $this->bitmask->toBytes(); - } - } else { - $temp = ord($bits[0]); - for ($i = 0; $temp >> $i; ++$i); - $precision = 8 * strlen($bits) - 8 + $i; - $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3); - } - - if ($shift < 0) { - $shift+= $precision; - } - $shift%= $precision; - - if (!$shift) { - return $this->copy(); - } - - $left = $this->bitwise_leftShift($shift); - $left = $left->bitwise_and(new Math_BigInteger($mask, 256)); - $right = $this->bitwise_rightShift($precision - $shift); - $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right); - return $this->_normalize($result); - } - - /** - * Logical Right Rotate - * - * Instead of the bottom x bits being dropped they're prepended to the shifted bit string. - * - * @param Integer $shift - * @return Math_BigInteger - * @access public - */ - function bitwise_rightRotate($shift) - { - return $this->bitwise_leftRotate(-$shift); - } - - /** - * Set random number generator function - * - * This function is deprecated. - * - * @param String $generator - * @access public - */ - function setRandomGenerator($generator) - { - } - - /** - * Generates a random BigInteger - * - * Byte length is equal to $length. Uses crypt_random if it's loaded and mt_rand if it's not. - * - * @param Integer $length - * @return Math_BigInteger - * @access private - */ - function _random_number_helper($size) - { - if (function_exists('crypt_random_string')) { - $random = crypt_random_string($size); - } else { - $random = ''; - - if ($size & 1) { - $random.= chr(mt_rand(0, 255)); - } - - $blocks = $size >> 1; - for ($i = 0; $i < $blocks; ++$i) { - // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems - $random.= pack('n', mt_rand(0, 0xFFFF)); - } - } - - return new Math_BigInteger($random, 256); - } - - /** - * Generate a random number - * - * Returns a random number between $min and $max where $min and $max - * can be defined using one of the two methods: - * - * $min->random($max) - * $max->random($min) - * - * @param Math_BigInteger $arg1 - * @param optional Math_BigInteger $arg2 - * @return Math_BigInteger - * @access public - * @internal The API for creating random numbers used to be $a->random($min, $max), where $a was a Math_BigInteger object. - * That method is still supported for BC purposes. - */ - function random($arg1, $arg2 = false) - { - if ($arg1 === false) { - return false; - } - - if ($arg2 === false) { - $max = $arg1; - $min = $this; - } else { - $min = $arg1; - $max = $arg2; - } - - $compare = $max->compare($min); - - if (!$compare) { - return $this->_normalize($min); - } else if ($compare < 0) { - // if $min is bigger then $max, swap $min and $max - $temp = $max; - $max = $min; - $min = $temp; - } - - static $one; - if (!isset($one)) { - $one = new Math_BigInteger(1); - } - - $max = $max->subtract($min->subtract($one)); - $size = strlen(ltrim($max->toBytes(), chr(0))); - - /* - doing $random % $max doesn't work because some numbers will be more likely to occur than others. - eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145 - would produce 5 whereas the only value of random that could produce 139 would be 139. ie. - not all numbers would be equally likely. some would be more likely than others. - - creating a whole new random number until you find one that is within the range doesn't work - because, for sufficiently small ranges, the likelihood that you'd get a number within that range - would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability - would be pretty high that $random would be greater than $max. - - phpseclib works around this using the technique described here: - - http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string - */ - $random_max = new Math_BigInteger(chr(1) . str_repeat("\0", $size), 256); - $random = $this->_random_number_helper($size); - - list($max_multiple) = $random_max->divide($max); - $max_multiple = $max_multiple->multiply($max); - - while ($random->compare($max_multiple) >= 0) { - $random = $random->subtract($max_multiple); - $random_max = $random_max->subtract($max_multiple); - $random = $random->bitwise_leftShift(8); - $random = $random->add($this->_random_number_helper(1)); - $random_max = $random_max->bitwise_leftShift(8); - list($max_multiple) = $random_max->divide($max); - $max_multiple = $max_multiple->multiply($max); - } - list(, $random) = $random->divide($max); - - return $this->_normalize($random->add($min)); - } - - /** - * Generate a random prime number. - * - * If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed, - * give up and return false. - * - * @param Math_BigInteger $arg1 - * @param optional Math_BigInteger $arg2 - * @param optional Integer $timeout - * @return Mixed - * @access public - * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}. - */ - function randomPrime($arg1, $arg2 = false, $timeout = false) - { - if ($arg1 === false) { - return false; - } - - if ($arg2 === false) { - $max = $arg1; - $min = $this; - } else { - $min = $arg1; - $max = $arg2; - } - - $compare = $max->compare($min); - - if (!$compare) { - return $min->isPrime() ? $min : false; - } else if ($compare < 0) { - // if $min is bigger then $max, swap $min and $max - $temp = $max; - $max = $min; - $min = $temp; - } - - static $one, $two; - if (!isset($one)) { - $one = new Math_BigInteger(1); - $two = new Math_BigInteger(2); - } - - $start = time(); - - $x = $this->random($min, $max); - - // gmp_nextprime() requires PHP 5 >= 5.2.0 per . - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) { - $p = new Math_BigInteger(); - $p->value = gmp_nextprime($x->value); - - if ($p->compare($max) <= 0) { - return $p; - } - - if (!$min->equals($x)) { - $x = $x->subtract($one); - } - - return $x->randomPrime($min, $x); - } - - if ($x->equals($two)) { - return $x; - } - - $x->_make_odd(); - if ($x->compare($max) > 0) { - // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range - if ($min->equals($max)) { - return false; - } - $x = $min->copy(); - $x->_make_odd(); - } - - $initial_x = $x->copy(); - - while (true) { - if ($timeout !== false && time() - $start > $timeout) { - return false; - } - - if ($x->isPrime()) { - return $x; - } - - $x = $x->add($two); - - if ($x->compare($max) > 0) { - $x = $min->copy(); - if ($x->equals($two)) { - return $x; - } - $x->_make_odd(); - } - - if ($x->equals($initial_x)) { - return false; - } - } - } - - /** - * Make the current number odd - * - * If the current number is odd it'll be unchanged. If it's even, one will be added to it. - * - * @see randomPrime() - * @access private - */ - function _make_odd() - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - gmp_setbit($this->value, 0); - break; - case MATH_BIGINTEGER_MODE_BCMATH: - if ($this->value[strlen($this->value) - 1] % 2 == 0) { - $this->value = bcadd($this->value, '1'); - } - break; - default: - $this->value[0] |= 1; - } - } - - /** - * Checks a numer to see if it's prime - * - * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the - * $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed across multiple pageloads - * on a website instead of just one. - * - * @param optional Math_BigInteger $t - * @return Boolean - * @access public - * @internal Uses the - * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See - * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}. - */ - function isPrime($t = false) - { - $length = strlen($this->toBytes()); - - if (!$t) { - // see HAC 4.49 "Note (controlling the error probability)" - // @codingStandardsIgnoreStart - if ($length >= 163) { $t = 2; } // floor(1300 / 8) - else if ($length >= 106) { $t = 3; } // floor( 850 / 8) - else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8) - else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8) - else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8) - else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8) - else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8) - else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8) - else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8) - else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8) - else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8) - else { $t = 27; } - // @codingStandardsIgnoreEnd - } - - // ie. gmp_testbit($this, 0) - // ie. isEven() or !isOdd() - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - return gmp_prob_prime($this->value, $t) != 0; - case MATH_BIGINTEGER_MODE_BCMATH: - if ($this->value === '2') { - return true; - } - if ($this->value[strlen($this->value) - 1] % 2 == 0) { - return false; - } - break; - default: - if ($this->value == array(2)) { - return true; - } - if (~$this->value[0] & 1) { - return false; - } - } - - static $primes, $zero, $one, $two; - - if (!isset($primes)) { - $primes = array( - 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, - 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, - 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, - 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, - 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, - 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, - 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, - 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, - 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, - 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, - 953, 967, 971, 977, 983, 991, 997 - ); - - if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) { - for ($i = 0; $i < count($primes); ++$i) { - $primes[$i] = new Math_BigInteger($primes[$i]); - } - } - - $zero = new Math_BigInteger(); - $one = new Math_BigInteger(1); - $two = new Math_BigInteger(2); - } - - if ($this->equals($one)) { - return false; - } - - // see HAC 4.4.1 "Random search for probable primes" - if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) { - foreach ($primes as $prime) { - list(, $r) = $this->divide($prime); - if ($r->equals($zero)) { - return $this->equals($prime); - } - } - } else { - $value = $this->value; - foreach ($primes as $prime) { - list(, $r) = $this->_divide_digit($value, $prime); - if (!$r) { - return count($value) == 1 && $value[0] == $prime; - } - } - } - - $n = $this->copy(); - $n_1 = $n->subtract($one); - $n_2 = $n->subtract($two); - - $r = $n_1->copy(); - $r_value = $r->value; - // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s)); - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { - $s = 0; - // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier - while ($r->value[strlen($r->value) - 1] % 2 == 0) { - $r->value = bcdiv($r->value, '2', 0); - ++$s; - } - } else { - for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) { - $temp = ~$r_value[$i] & 0xFFFFFF; - for ($j = 1; ($temp >> $j) & 1; ++$j); - if ($j != 25) { - break; - } - } - $s = 26 * $i + $j - 1; - $r->_rshift($s); - } - - for ($i = 0; $i < $t; ++$i) { - $a = $this->random($two, $n_2); - $y = $a->modPow($r, $n); - - if (!$y->equals($one) && !$y->equals($n_1)) { - for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) { - $y = $y->modPow($two, $n); - if ($y->equals($one)) { - return false; - } - } - - if (!$y->equals($n_1)) { - return false; - } - } - } - return true; - } - - /** - * Logical Left Shift - * - * Shifts BigInteger's by $shift bits. - * - * @param Integer $shift - * @access private - */ - function _lshift($shift) - { - if ( $shift == 0 ) { - return; - } - - $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE); - $shift %= MATH_BIGINTEGER_BASE; - $shift = 1 << $shift; - - $carry = 0; - - for ($i = 0; $i < count($this->value); ++$i) { - $temp = $this->value[$i] * $shift + $carry; - $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); - $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL); - } - - if ( $carry ) { - $this->value[count($this->value)] = $carry; - } - - while ($num_digits--) { - array_unshift($this->value, 0); - } - } - - /** - * Logical Right Shift - * - * Shifts BigInteger's by $shift bits. - * - * @param Integer $shift - * @access private - */ - function _rshift($shift) - { - if ($shift == 0) { - return; - } - - $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE); - $shift %= MATH_BIGINTEGER_BASE; - $carry_shift = MATH_BIGINTEGER_BASE - $shift; - $carry_mask = (1 << $shift) - 1; - - if ( $num_digits ) { - $this->value = array_slice($this->value, $num_digits); - } - - $carry = 0; - - for ($i = count($this->value) - 1; $i >= 0; --$i) { - $temp = $this->value[$i] >> $shift | $carry; - $carry = ($this->value[$i] & $carry_mask) << $carry_shift; - $this->value[$i] = $temp; - } - - $this->value = $this->_trim($this->value); - } - - /** - * Normalize - * - * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision - * - * @param Math_BigInteger - * @return Math_BigInteger - * @see _trim() - * @access private - */ - function _normalize($result) - { - $result->precision = $this->precision; - $result->bitmask = $this->bitmask; - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - if (!empty($result->bitmask->value)) { - $result->value = gmp_and($result->value, $result->bitmask->value); - } - - return $result; - case MATH_BIGINTEGER_MODE_BCMATH: - if (!empty($result->bitmask->value)) { - $result->value = bcmod($result->value, $result->bitmask->value); - } - - return $result; - } - - $value = &$result->value; - - if ( !count($value) ) { - return $result; - } - - $value = $this->_trim($value); - - if (!empty($result->bitmask->value)) { - $length = min(count($value), count($this->bitmask->value)); - $value = array_slice($value, 0, $length); - - for ($i = 0; $i < $length; ++$i) { - $value[$i] = $value[$i] & $this->bitmask->value[$i]; - } - } - - return $result; - } - - /** - * Trim - * - * Removes leading zeros - * - * @param Array $value - * @return Math_BigInteger - * @access private - */ - function _trim($value) - { - for ($i = count($value) - 1; $i >= 0; --$i) { - if ( $value[$i] ) { - break; - } - unset($value[$i]); - } - - return $value; - } - - /** - * Array Repeat - * - * @param $input Array - * @param $multiplier mixed - * @return Array - * @access private - */ - function _array_repeat($input, $multiplier) - { - return ($multiplier) ? array_fill(0, $multiplier, $input) : array(); - } - - /** - * Logical Left Shift - * - * Shifts binary strings $shift bits, essentially multiplying by 2**$shift. - * - * @param $x String - * @param $shift Integer - * @return String - * @access private - */ - function _base256_lshift(&$x, $shift) - { - if ($shift == 0) { - return; - } - - $num_bytes = $shift >> 3; // eg. floor($shift/8) - $shift &= 7; // eg. $shift % 8 - - $carry = 0; - for ($i = strlen($x) - 1; $i >= 0; --$i) { - $temp = ord($x[$i]) << $shift | $carry; - $x[$i] = chr($temp); - $carry = $temp >> 8; - } - $carry = ($carry != 0) ? chr($carry) : ''; - $x = $carry . $x . str_repeat(chr(0), $num_bytes); - } - - /** - * Logical Right Shift - * - * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder. - * - * @param $x String - * @param $shift Integer - * @return String - * @access private - */ - function _base256_rshift(&$x, $shift) - { - if ($shift == 0) { - $x = ltrim($x, chr(0)); - return ''; - } - - $num_bytes = $shift >> 3; // eg. floor($shift/8) - $shift &= 7; // eg. $shift % 8 - - $remainder = ''; - if ($num_bytes) { - $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes; - $remainder = substr($x, $start); - $x = substr($x, 0, -$num_bytes); - } - - $carry = 0; - $carry_shift = 8 - $shift; - for ($i = 0; $i < strlen($x); ++$i) { - $temp = (ord($x[$i]) >> $shift) | $carry; - $carry = (ord($x[$i]) << $carry_shift) & 0xFF; - $x[$i] = chr($temp); - } - $x = ltrim($x, chr(0)); - - $remainder = chr($carry >> $carry_shift) . $remainder; - - return ltrim($remainder, chr(0)); - } - - // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long - // at 32-bits, while java's longs are 64-bits. - - /** - * Converts 32-bit integers to bytes. - * - * @param Integer $x - * @return String - * @access private - */ - function _int2bytes($x) - { - return ltrim(pack('N', $x), chr(0)); - } - - /** - * Converts bytes to 32-bit integers - * - * @param String $x - * @return Integer - * @access private - */ - function _bytes2int($x) - { - $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT)); - return $temp['int']; - } - - /** - * DER-encode an integer - * - * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL - * - * @see modPow() - * @access private - * @param Integer $length - * @return String - */ - function _encodeASN1Length($length) - { - if ($length <= 0x7F) { - return chr($length); - } - - $temp = ltrim(pack('N', $length), chr(0)); - return pack('Ca*', 0x80 | strlen($temp), $temp); - } - - /** - * Single digit division - * - * Even if int64 is being used the division operator will return a float64 value - * if the dividend is not evenly divisible by the divisor. Since a float64 doesn't - * have the precision of int64 this is a problem so, when int64 is being used, - * we'll guarantee that the dividend is divisible by first subtracting the remainder. - * - * @access private - * @param Integer $x - * @param Integer $y - * @return Integer - */ - function _safe_divide($x, $y) - { - if (MATH_BIGINTEGER_BASE === 26) { - return (int) ($x / $y); - } - - // MATH_BIGINTEGER_BASE === 31 - return ($x - ($x % $y)) / $y; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SCP.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SCP.php deleted file mode 100644 index b5cd2f55..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SCP.php +++ /dev/null @@ -1,360 +0,0 @@ - - * login('username', 'password')) { - * exit('bad login'); - * } - - * $scp = new Net_SCP($ssh); - * $scp->put('abcd', str_repeat('x', 1024*1024)); - * ?> - * - * - * 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. - * - * @category Net - * @package Net_SCP - * @author Jim Wigginton - * @copyright 2010 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/**#@+ - * @access public - * @see Net_SCP::put() - */ -/** - * Reads data from a local file. - */ -define('NET_SCP_LOCAL_FILE', 1); -/** - * Reads data from a string. - */ -define('NET_SCP_STRING', 2); -/**#@-*/ - -/**#@+ - * @access private - * @see Net_SCP::_send() - * @see Net_SCP::_receive() - */ -/** - * SSH1 is being used. - */ -define('NET_SCP_SSH1', 1); -/** - * SSH2 is being used. - */ -define('NET_SCP_SSH2', 2); -/**#@-*/ - -/** - * Pure-PHP implementations of SCP. - * - * @package Net_SCP - * @author Jim Wigginton - * @access public - */ -class Net_SCP -{ - /** - * SSH Object - * - * @var Object - * @access private - */ - var $ssh; - - /** - * Packet Size - * - * @var Integer - * @access private - */ - var $packet_size; - - /** - * Mode - * - * @var Integer - * @access private - */ - var $mode; - - /** - * Default Constructor. - * - * Connects to an SSH server - * - * @param String $host - * @param optional Integer $port - * @param optional Integer $timeout - * @return Net_SCP - * @access public - */ - function Net_SCP($ssh) - { - if (!is_object($ssh)) { - return; - } - - switch (strtolower(get_class($ssh))) { - case 'net_ssh2': - $this->mode = NET_SCP_SSH2; - break; - case 'net_ssh1': - $this->packet_size = 50000; - $this->mode = NET_SCP_SSH1; - break; - default: - return; - } - - $this->ssh = $ssh; - } - - /** - * Uploads a file to the SCP server. - * - * By default, Net_SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file. - * So, for example, if you set $data to 'filename.ext' and then do Net_SCP::get(), you will get a file, twelve bytes - * long, containing 'filename.ext' as its contents. - * - * Setting $mode to NET_SCP_LOCAL_FILE will change the above behavior. With NET_SCP_LOCAL_FILE, $remote_file will - * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how - * large $remote_file will be, as well. - * - * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take - * care of that, yourself. - * - * @param String $remote_file - * @param String $data - * @param optional Integer $mode - * @param optional Callable $callback - * @return Boolean - * @access public - */ - function put($remote_file, $data, $mode = NET_SCP_STRING, $callback = null) - { - if (!isset($this->ssh)) { - return false; - } - - if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to - return false; - } - - $temp = $this->_receive(); - if ($temp !== chr(0)) { - return false; - } - - if ($this->mode == NET_SCP_SSH2) { - $this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC] - 4; - } - - $remote_file = basename($remote_file); - - if ($mode == NET_SCP_STRING) { - $size = strlen($data); - } else { - if (!is_file($data)) { - user_error("$data is not a valid file", E_USER_NOTICE); - return false; - } - - $fp = @fopen($data, 'rb'); - if (!$fp) { - return false; - } - $size = filesize($data); - } - - $this->_send('C0644 ' . $size . ' ' . $remote_file . "\n"); - - $temp = $this->_receive(); - if ($temp !== chr(0)) { - return false; - } - - $sent = 0; - while ($sent < $size) { - $temp = $mode & NET_SCP_STRING ? substr($data, $sent, $this->packet_size) : fread($fp, $this->packet_size); - $this->_send($temp); - $sent+= strlen($temp); - - if (is_callable($callback)) { - call_user_func($callback, $sent); - } - } - $this->_close(); - - if ($mode != NET_SCP_STRING) { - fclose($fp); - } - - return true; - } - - /** - * Downloads a file from the SCP server. - * - * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if - * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the - * operation - * - * @param String $remote_file - * @param optional String $local_file - * @return Mixed - * @access public - */ - function get($remote_file, $local_file = false) - { - if (!isset($this->ssh)) { - return false; - } - - if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from - return false; - } - - $this->_send("\0"); - - if (!preg_match('#(?[^ ]+) (?\d+) (?.+)#', rtrim($this->_receive()), $info)) { - return false; - } - - $this->_send("\0"); - - $size = 0; - - if ($local_file !== false) { - $fp = @fopen($local_file, 'wb'); - if (!$fp) { - return false; - } - } - - $content = ''; - while ($size < $info['size']) { - $data = $this->_receive(); - // SCP usually seems to split stuff out into 16k chunks - $size+= strlen($data); - - if ($local_file === false) { - $content.= $data; - } else { - fputs($fp, $data); - } - } - - $this->_close(); - - if ($local_file !== false) { - fclose($fp); - return true; - } - - return $content; - } - - /** - * Sends a packet to an SSH server - * - * @param String $data - * @access private - */ - function _send($data) - { - switch ($this->mode) { - case NET_SCP_SSH2: - $this->ssh->_send_channel_packet(NET_SSH2_CHANNEL_EXEC, $data); - break; - case NET_SCP_SSH1: - $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data); - $this->ssh->_send_binary_packet($data); - } - } - - /** - * Receives a packet from an SSH server - * - * @return String - * @access private - */ - function _receive() - { - switch ($this->mode) { - case NET_SCP_SSH2: - return $this->ssh->_get_channel_packet(NET_SSH2_CHANNEL_EXEC, true); - case NET_SCP_SSH1: - if (!$this->ssh->bitmap) { - return false; - } - while (true) { - $response = $this->ssh->_get_binary_packet(); - switch ($response[NET_SSH1_RESPONSE_TYPE]) { - case NET_SSH1_SMSG_STDOUT_DATA: - extract(unpack('Nlength', $response[NET_SSH1_RESPONSE_DATA])); - return $this->ssh->_string_shift($response[NET_SSH1_RESPONSE_DATA], $length); - case NET_SSH1_SMSG_STDERR_DATA: - break; - case NET_SSH1_SMSG_EXITSTATUS: - $this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION)); - fclose($this->ssh->fsock); - $this->ssh->bitmap = 0; - return false; - default: - user_error('Unknown packet received', E_USER_NOTICE); - return false; - } - } - } - } - - /** - * Closes the connection to an SSH server - * - * @access private - */ - function _close() - { - switch ($this->mode) { - case NET_SCP_SSH2: - $this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC, true); - break; - case NET_SCP_SSH1: - $this->ssh->disconnect(); - } - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SFTP.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SFTP.php deleted file mode 100644 index 5f7d3666..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SFTP.php +++ /dev/null @@ -1,2778 +0,0 @@ - - * login('username', 'password')) { - * exit('Login Failed'); - * } - * - * echo $sftp->pwd() . "\r\n"; - * $sftp->put('filename.ext', 'hello, world!'); - * print_r($sftp->nlist()); - * ?> - * - * - * 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. - * - * @category Net - * @package Net_SFTP - * @author Jim Wigginton - * @copyright 2009 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Net_SSH2 - */ -if (!class_exists('Net_SSH2')) { - include_once 'SSH2.php'; -} - -/**#@+ - * @access public - * @see Net_SFTP::getLog() - */ -/** - * Returns the message numbers - */ -define('NET_SFTP_LOG_SIMPLE', NET_SSH2_LOG_SIMPLE); -/** - * Returns the message content - */ -define('NET_SFTP_LOG_COMPLEX', NET_SSH2_LOG_COMPLEX); -/** - * Outputs the message content in real-time. - */ -define('NET_SFTP_LOG_REALTIME', 3); -/**#@-*/ - -/** - * SFTP channel constant - * - * Net_SSH2::exec() uses 0 and Net_SSH2::read() / Net_SSH2::write() use 1. - * - * @see Net_SSH2::_send_channel_packet() - * @see Net_SSH2::_get_channel_packet() - * @access private - */ -define('NET_SFTP_CHANNEL', 0x100); - -/**#@+ - * @access public - * @see Net_SFTP::put() - */ -/** - * Reads data from a local file. - */ -define('NET_SFTP_LOCAL_FILE', 1); -/** - * Reads data from a string. - */ -// this value isn't really used anymore but i'm keeping it reserved for historical reasons -define('NET_SFTP_STRING', 2); -/** - * Resumes an upload - */ -define('NET_SFTP_RESUME', 4); -/** - * Append a local file to an already existing remote file - */ -define('NET_SFTP_RESUME_START', 8); -/**#@-*/ - -/** - * Pure-PHP implementations of SFTP. - * - * @package Net_SFTP - * @author Jim Wigginton - * @access public - */ -class Net_SFTP extends Net_SSH2 -{ - /** - * Packet Types - * - * @see Net_SFTP::Net_SFTP() - * @var Array - * @access private - */ - var $packet_types = array(); - - /** - * Status Codes - * - * @see Net_SFTP::Net_SFTP() - * @var Array - * @access private - */ - var $status_codes = array(); - - /** - * The Request ID - * - * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support - * concurrent actions, so it's somewhat academic, here. - * - * @var Integer - * @see Net_SFTP::_send_sftp_packet() - * @access private - */ - var $request_id = false; - - /** - * The Packet Type - * - * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support - * concurrent actions, so it's somewhat academic, here. - * - * @var Integer - * @see Net_SFTP::_get_sftp_packet() - * @access private - */ - var $packet_type = -1; - - /** - * Packet Buffer - * - * @var String - * @see Net_SFTP::_get_sftp_packet() - * @access private - */ - var $packet_buffer = ''; - - /** - * Extensions supported by the server - * - * @var Array - * @see Net_SFTP::_initChannel() - * @access private - */ - var $extensions = array(); - - /** - * Server SFTP version - * - * @var Integer - * @see Net_SFTP::_initChannel() - * @access private - */ - var $version; - - /** - * Current working directory - * - * @var String - * @see Net_SFTP::_realpath() - * @see Net_SFTP::chdir() - * @access private - */ - var $pwd = false; - - /** - * Packet Type Log - * - * @see Net_SFTP::getLog() - * @var Array - * @access private - */ - var $packet_type_log = array(); - - /** - * Packet Log - * - * @see Net_SFTP::getLog() - * @var Array - * @access private - */ - var $packet_log = array(); - - /** - * Error information - * - * @see Net_SFTP::getSFTPErrors() - * @see Net_SFTP::getLastSFTPError() - * @var String - * @access private - */ - var $sftp_errors = array(); - - /** - * Stat Cache - * - * Rather than always having to open a directory and close it immediately there after to see if a file is a directory - * we'll cache the results. - * - * @see Net_SFTP::_update_stat_cache() - * @see Net_SFTP::_remove_from_stat_cache() - * @see Net_SFTP::_query_stat_cache() - * @var Array - * @access private - */ - var $stat_cache = array(); - - /** - * Max SFTP Packet Size - * - * @see Net_SFTP::Net_SFTP() - * @see Net_SFTP::get() - * @var Array - * @access private - */ - var $max_sftp_packet; - - /** - * Stat Cache Flag - * - * @see Net_SFTP::disableStatCache() - * @see Net_SFTP::enableStatCache() - * @var Boolean - * @access private - */ - var $use_stat_cache = true; - - /** - * Sort Options - * - * @see Net_SFTP::_comparator() - * @see Net_SFTP::setListOrder() - * @var Array - * @access private - */ - var $sortOptions = array(); - - /** - * Default Constructor. - * - * Connects to an SFTP server - * - * @param String $host - * @param optional Integer $port - * @param optional Integer $timeout - * @return Net_SFTP - * @access public - */ - function Net_SFTP($host, $port = 22, $timeout = 10) - { - parent::Net_SSH2($host, $port, $timeout); - - $this->max_sftp_packet = 1 << 15; - - $this->packet_types = array( - 1 => 'NET_SFTP_INIT', - 2 => 'NET_SFTP_VERSION', - /* the format of SSH_FXP_OPEN changed between SFTPv4 and SFTPv5+: - SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.1 - pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 */ - 3 => 'NET_SFTP_OPEN', - 4 => 'NET_SFTP_CLOSE', - 5 => 'NET_SFTP_READ', - 6 => 'NET_SFTP_WRITE', - 7 => 'NET_SFTP_LSTAT', - 9 => 'NET_SFTP_SETSTAT', - 11 => 'NET_SFTP_OPENDIR', - 12 => 'NET_SFTP_READDIR', - 13 => 'NET_SFTP_REMOVE', - 14 => 'NET_SFTP_MKDIR', - 15 => 'NET_SFTP_RMDIR', - 16 => 'NET_SFTP_REALPATH', - 17 => 'NET_SFTP_STAT', - /* the format of SSH_FXP_RENAME changed between SFTPv4 and SFTPv5+: - SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 - pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */ - 18 => 'NET_SFTP_RENAME', - 19 => 'NET_SFTP_READLINK', - 20 => 'NET_SFTP_SYMLINK', - - 101=> 'NET_SFTP_STATUS', - 102=> 'NET_SFTP_HANDLE', - /* the format of SSH_FXP_NAME changed between SFTPv3 and SFTPv4+: - SFTPv4+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4 - pre-SFTPv4 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 */ - 103=> 'NET_SFTP_DATA', - 104=> 'NET_SFTP_NAME', - 105=> 'NET_SFTP_ATTRS', - - 200=> 'NET_SFTP_EXTENDED' - ); - $this->status_codes = array( - 0 => 'NET_SFTP_STATUS_OK', - 1 => 'NET_SFTP_STATUS_EOF', - 2 => 'NET_SFTP_STATUS_NO_SUCH_FILE', - 3 => 'NET_SFTP_STATUS_PERMISSION_DENIED', - 4 => 'NET_SFTP_STATUS_FAILURE', - 5 => 'NET_SFTP_STATUS_BAD_MESSAGE', - 6 => 'NET_SFTP_STATUS_NO_CONNECTION', - 7 => 'NET_SFTP_STATUS_CONNECTION_LOST', - 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED', - 9 => 'NET_SFTP_STATUS_INVALID_HANDLE', - 10 => 'NET_SFTP_STATUS_NO_SUCH_PATH', - 11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS', - 12 => 'NET_SFTP_STATUS_WRITE_PROTECT', - 13 => 'NET_SFTP_STATUS_NO_MEDIA', - 14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM', - 15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED', - 16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL', - 17 => 'NET_SFTP_STATUS_LOCK_CONFLICT', - 18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY', - 19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY', - 20 => 'NET_SFTP_STATUS_INVALID_FILENAME', - 21 => 'NET_SFTP_STATUS_LINK_LOOP', - 22 => 'NET_SFTP_STATUS_CANNOT_DELETE', - 23 => 'NET_SFTP_STATUS_INVALID_PARAMETER', - 24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY', - 25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT', - 26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED', - 27 => 'NET_SFTP_STATUS_DELETE_PENDING', - 28 => 'NET_SFTP_STATUS_FILE_CORRUPT', - 29 => 'NET_SFTP_STATUS_OWNER_INVALID', - 30 => 'NET_SFTP_STATUS_GROUP_INVALID', - 31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK' - ); - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1 - // the order, in this case, matters quite a lot - see Net_SFTP::_parseAttributes() to understand why - $this->attributes = array( - 0x00000001 => 'NET_SFTP_ATTR_SIZE', - 0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+ - 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS', - 0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME', - // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers - // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in - // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000. - // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored. - -1 << 31 => 'NET_SFTP_ATTR_EXTENDED' - ); - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 - // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name - // the array for that $this->open5_flags and similarily alter the constant names. - $this->open_flags = array( - 0x00000001 => 'NET_SFTP_OPEN_READ', - 0x00000002 => 'NET_SFTP_OPEN_WRITE', - 0x00000004 => 'NET_SFTP_OPEN_APPEND', - 0x00000008 => 'NET_SFTP_OPEN_CREATE', - 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE', - 0x00000020 => 'NET_SFTP_OPEN_EXCL' - ); - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 - // see Net_SFTP::_parseLongname() for an explanation - $this->file_types = array( - 1 => 'NET_SFTP_TYPE_REGULAR', - 2 => 'NET_SFTP_TYPE_DIRECTORY', - 3 => 'NET_SFTP_TYPE_SYMLINK', - 4 => 'NET_SFTP_TYPE_SPECIAL', - 5 => 'NET_SFTP_TYPE_UNKNOWN', - // the followin types were first defined for use in SFTPv5+ - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2 - 6 => 'NET_SFTP_TYPE_SOCKET', - 7 => 'NET_SFTP_TYPE_CHAR_DEVICE', - 8 => 'NET_SFTP_TYPE_BLOCK_DEVICE', - 9 => 'NET_SFTP_TYPE_FIFO' - ); - $this->_define_array( - $this->packet_types, - $this->status_codes, - $this->attributes, - $this->open_flags, - $this->file_types - ); - - if (!defined('NET_SFTP_QUEUE_SIZE')) { - define('NET_SFTP_QUEUE_SIZE', 50); - } - } - - /** - * Login - * - * @param String $username - * @param optional String $password - * @return Boolean - * @access public - */ - function login($username) - { - $args = func_get_args(); - if (!call_user_func_array(array(&$this, '_login'), $args)) { - return false; - } - - $this->window_size_server_to_client[NET_SFTP_CHANNEL] = $this->window_size; - - $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SFTP_CHANNEL, $this->window_size, 0x4000); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN; - - $response = $this->_get_channel_packet(NET_SFTP_CHANNEL); - if ($response === false) { - return false; - } - - $packet = pack('CNNa*CNa*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('subsystem'), 'subsystem', 1, strlen('sftp'), 'sftp'); - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST; - - $response = $this->_get_channel_packet(NET_SFTP_CHANNEL); - if ($response === false) { - // from PuTTY's psftp.exe - $command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" . - "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" . - "exec sftp-server"; - // we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does - // is redundant - $packet = pack('CNNa*CNa*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('exec'), 'exec', 1, strlen($command), $command); - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST; - - $response = $this->_get_channel_packet(NET_SFTP_CHANNEL); - if ($response === false) { - return false; - } - } - - $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA; - - if (!$this->_send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_VERSION) { - user_error('Expected SSH_FXP_VERSION'); - return false; - } - - extract(unpack('Nversion', $this->_string_shift($response, 4))); - $this->version = $version; - while (!empty($response)) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $key = $this->_string_shift($response, $length); - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $value = $this->_string_shift($response, $length); - $this->extensions[$key] = $value; - } - - /* - SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com', - however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's - not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for - one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that - 'newline@vandyke.com' would. - */ - /* - if (isset($this->extensions['newline@vandyke.com'])) { - $this->extensions['newline'] = $this->extensions['newline@vandyke.com']; - unset($this->extensions['newline@vandyke.com']); - } - */ - - $this->request_id = 1; - - /* - A Note on SFTPv4/5/6 support: - states the following: - - "If the client wishes to interoperate with servers that support noncontiguous version - numbers it SHOULD send '3'" - - Given that the server only sends its version number after the client has already done so, the above - seems to be suggesting that v3 should be the default version. This makes sense given that v3 is the - most popular. - - states the following; - - "If the server did not send the "versions" extension, or the version-from-list was not included, the - server MAY send a status response describing the failure, but MUST then close the channel without - processing any further requests." - - So what do you do if you have a client whose initial SSH_FXP_INIT packet says it implements v3 and - a server whose initial SSH_FXP_VERSION reply says it implements v4 and only v4? If it only implements - v4, the "versions" extension is likely not going to have been sent so version re-negotiation as discussed - in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what Net_SFTP would do is close the - channel and reopen it with a new and updated SSH_FXP_INIT packet. - */ - switch ($this->version) { - case 2: - case 3: - break; - default: - return false; - } - - $this->pwd = $this->_realpath('.'); - - $this->_update_stat_cache($this->pwd, array()); - - return true; - } - - /** - * Disable the stat cache - * - * @access public - */ - function disableStatCache() - { - $this->use_stat_cache = false; - } - - /** - * Enable the stat cache - * - * @access public - */ - function enableStatCache() - { - $this->use_stat_cache = true; - } - - /** - * Clear the stat cache - * - * @access public - */ - function clearStatCache() - { - $this->stat_cache = array(); - } - - /** - * Returns the current directory name - * - * @return Mixed - * @access public - */ - function pwd() - { - return $this->pwd; - } - - /** - * Logs errors - * - * @param String $response - * @param optional Integer $status - * @access public - */ - function _logError($response, $status = -1) - { - if ($status == -1) { - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - } - - $error = $this->status_codes[$status]; - - if ($this->version > 2) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length); - } else { - $this->sftp_errors[] = $error; - } - } - - /** - * Canonicalize the Server-Side Path Name - * - * SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns - * the absolute (canonicalized) path. - * - * @see Net_SFTP::chdir() - * @param String $path - * @return Mixed - * @access private - */ - function _realpath($path) - { - if ($this->pwd === false) { - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9 - if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_NAME: - // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following - // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks - // at is the first part and that part is defined the same in SFTP versions 3 through 6. - $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway - extract(unpack('Nlength', $this->_string_shift($response, 4))); - return $this->_string_shift($response, $length); - case NET_SFTP_STATUS: - $this->_logError($response); - return false; - default: - user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS'); - return false; - } - } - - if ($path[0] != '/') { - $path = $this->pwd . '/' . $path; - } - - $path = explode('/', $path); - $new = array(); - foreach ($path as $dir) { - if (!strlen($dir)) { - continue; - } - switch ($dir) { - case '..': - array_pop($new); - case '.': - break; - default: - $new[] = $dir; - } - } - - return '/' . implode('/', $new); - } - - /** - * Changes the current directory - * - * @param String $dir - * @return Boolean - * @access public - */ - function chdir($dir) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - // assume current dir if $dir is empty - if ($dir === '') { - $dir = './'; - // suffix a slash if needed - } elseif ($dir[strlen($dir) - 1] != '/') { - $dir.= '/'; - } - - $dir = $this->_realpath($dir); - - // confirm that $dir is, in fact, a valid directory - if ($this->use_stat_cache && is_array($this->_query_stat_cache($dir))) { - $this->pwd = $dir; - return true; - } - - // we could do a stat on the alleged $dir to see if it's a directory but that doesn't tell us - // the currently logged in user has the appropriate permissions or not. maybe you could see if - // the file's uid / gid match the currently logged in user's uid / gid but how there's no easy - // way to get those with SFTP - - if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) { - return false; - } - - // see Net_SFTP::nlist() for a more thorough explanation of the following - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_HANDLE: - $handle = substr($response, 4); - break; - case NET_SFTP_STATUS: - $this->_logError($response); - return false; - default: - user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS'); - return false; - } - - if (!$this->_close_handle($handle)) { - return false; - } - - $this->_update_stat_cache($dir, array()); - - $this->pwd = $dir; - return true; - } - - /** - * Returns a list of files in the given directory - * - * @param optional String $dir - * @param optional Boolean $recursive - * @return Mixed - * @access public - */ - function nlist($dir = '.', $recursive = false) - { - return $this->_nlist_helper($dir, $recursive, ''); - } - - /** - * Helper method for nlist - * - * @param String $dir - * @param Boolean $recursive - * @param String $relativeDir - * @return Mixed - * @access private - */ - function _nlist_helper($dir, $recursive, $relativeDir) - { - $files = $this->_list($dir, false); - - if (!$recursive) { - return $files; - } - - $result = array(); - foreach ($files as $value) { - if ($value == '.' || $value == '..') { - if ($relativeDir == '') { - $result[] = $value; - } - continue; - } - if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) { - $temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/'); - $result = array_merge($result, $temp); - } else { - $result[] = $relativeDir . $value; - } - } - - return $result; - } - - /** - * Returns a detailed list of files in the given directory - * - * @param optional String $dir - * @param optional Boolean $recursive - * @return Mixed - * @access public - */ - function rawlist($dir = '.', $recursive = false) - { - $files = $this->_list($dir, true); - if (!$recursive || $files === false) { - return $files; - } - - static $depth = 0; - - foreach ($files as $key=>$value) { - if ($depth != 0 && $key == '..') { - unset($files[$key]); - continue; - } - if ($key != '.' && $key != '..' && is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)))) { - $depth++; - $files[$key] = $this->rawlist($dir . '/' . $key, true); - $depth--; - } else { - $files[$key] = (object) $value; - } - } - - return $files; - } - - /** - * Reads a list, be it detailed or not, of files in the given directory - * - * @param String $dir - * @param optional Boolean $raw - * @return Mixed - * @access private - */ - function _list($dir, $raw = true) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $dir = $this->_realpath($dir . '/'); - if ($dir === false) { - return false; - } - - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2 - if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_HANDLE: - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.2 - // since 'handle' is the last field in the SSH_FXP_HANDLE packet, we'll just remove the first four bytes that - // represent the length of the string and leave it at that - $handle = substr($response, 4); - break; - case NET_SFTP_STATUS: - // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED - $this->_logError($response); - return false; - default: - user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS'); - return false; - } - - $this->_update_stat_cache($dir, array()); - - $contents = array(); - while (true) { - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2 - // why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many - // SSH_MSG_CHANNEL_DATA messages is not known to me. - if (!$this->_send_sftp_packet(NET_SFTP_READDIR, pack('Na*', strlen($handle), $handle))) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_NAME: - extract(unpack('Ncount', $this->_string_shift($response, 4))); - for ($i = 0; $i < $count; $i++) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $shortname = $this->_string_shift($response, $length); - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $longname = $this->_string_shift($response, $length); - $attributes = $this->_parseAttributes($response); - if (!isset($attributes['type'])) { - $fileType = $this->_parseLongname($longname); - if ($fileType) { - $attributes['type'] = $fileType; - } - } - $contents[$shortname] = $attributes + array('filename' => $shortname); - - if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) { - $this->_update_stat_cache($dir . '/' . $shortname, array()); - } else { - if ($shortname == '..') { - $temp = $this->_realpath($dir . '/..') . '/.'; - } else { - $temp = $dir . '/' . $shortname; - } - $this->_update_stat_cache($temp, (object) $attributes); - } - // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the - // final SSH_FXP_STATUS packet should tell us that, already. - } - break; - case NET_SFTP_STATUS: - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_EOF) { - $this->_logError($response, $status); - return false; - } - break 2; - default: - user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS'); - return false; - } - } - - if (!$this->_close_handle($handle)) { - return false; - } - - if (count($this->sortOptions)) { - uasort($contents, array(&$this, '_comparator')); - } - - return $raw ? $contents : array_keys($contents); - } - - /** - * Compares two rawlist entries using parameters set by setListOrder() - * - * Intended for use with uasort() - * - * @param Array $a - * @param Array $b - * @return Integer - * @access private - */ - function _comparator($a, $b) - { - switch (true) { - case $a['filename'] === '.' || $b['filename'] === '.': - if ($a['filename'] === $b['filename']) { - return 0; - } - return $a['filename'] === '.' ? -1 : 1; - case $a['filename'] === '..' || $b['filename'] === '..': - if ($a['filename'] === $b['filename']) { - return 0; - } - return $a['filename'] === '..' ? -1 : 1; - case isset($a['type']) && $a['type'] === NET_SFTP_TYPE_DIRECTORY: - if (!isset($b['type'])) { - return 1; - } - if ($b['type'] !== $a['type']) { - return -1; - } - break; - case isset($b['type']) && $b['type'] === NET_SFTP_TYPE_DIRECTORY: - return 1; - } - foreach ($this->sortOptions as $sort => $order) { - if (!isset($a[$sort]) || !isset($b[$sort])) { - if (isset($a[$sort])) { - return -1; - } - if (isset($b[$sort])) { - return 1; - } - return 0; - } - switch ($sort) { - case 'filename': - $result = strcasecmp($a['filename'], $b['filename']); - if ($result) { - return $order === SORT_DESC ? -$result : $result; - } - break; - case 'permissions': - case 'mode': - $a[$sort]&= 07777; - $b[$sort]&= 07777; - default: - if ($a[$sort] === $b[$sort]) { - break; - } - return $order === SORT_ASC ? $a[$sort] - $b[$sort] : $b[$sort] - $a[$sort]; - } - } - } - - /** - * Defines how nlist() and rawlist() will be sorted - if at all. - * - * If sorting is enabled directories and files will be sorted independently with - * directories appearing before files in the resultant array that is returned. - * - * Any parameter returned by stat is a valid sort parameter for this function. - * Filename comparisons are case insensitive. - * - * Examples: - * - * $sftp->setListOrder('filename', SORT_ASC); - * $sftp->setListOrder('size', SORT_DESC, 'filename', SORT_ASC); - * $sftp->setListOrder(true); - * Separates directories from files but doesn't do any sorting beyond that - * $sftp->setListOrder(); - * Don't do any sort of sorting - * - * @access public - */ - function setListOrder() - { - $this->sortOptions = array(); - $args = func_get_args(); - if (empty($args)) { - return; - } - $len = count($args) & 0x7FFFFFFE; - for ($i = 0; $i < $len; $i+=2) { - $this->sortOptions[$args[$i]] = $args[$i + 1]; - } - if (!count($this->sortOptions)) { - $this->sortOptions = array('bogus' => true); - } - } - - /** - * Returns the file size, in bytes, or false, on failure - * - * Files larger than 4GB will show up as being exactly 4GB. - * - * @param String $filename - * @return Mixed - * @access public - */ - function size($filename) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $result = $this->stat($filename); - if ($result === false) { - return false; - } - return isset($result['size']) ? $result['size'] : -1; - } - - /** - * Save files / directories to cache - * - * @param String $path - * @param Mixed $value - * @access private - */ - function _update_stat_cache($path, $value) - { - // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/')) - $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); - - $temp = &$this->stat_cache; - $max = count($dirs) - 1; - foreach ($dirs as $i=>$dir) { - if (!isset($temp[$dir])) { - $temp[$dir] = array(); - } - if ($i === $max) { - $temp[$dir] = $value; - break; - } - $temp = &$temp[$dir]; - } - } - - /** - * Remove files / directories from cache - * - * @param String $path - * @return Boolean - * @access private - */ - function _remove_from_stat_cache($path) - { - $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); - - $temp = &$this->stat_cache; - $max = count($dirs) - 1; - foreach ($dirs as $i=>$dir) { - if ($i === $max) { - unset($temp[$dir]); - return true; - } - if (!isset($temp[$dir])) { - return false; - } - $temp = &$temp[$dir]; - } - } - - /** - * Checks cache for path - * - * Mainly used by file_exists - * - * @param String $dir - * @return Mixed - * @access private - */ - function _query_stat_cache($path) - { - $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); - - $temp = &$this->stat_cache; - foreach ($dirs as $dir) { - if (!isset($temp[$dir])) { - return null; - } - $temp = &$temp[$dir]; - } - return $temp; - } - - /** - * Returns general information about a file. - * - * Returns an array on success and false otherwise. - * - * @param String $filename - * @return Mixed - * @access public - */ - function stat($filename) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $filename = $this->_realpath($filename); - if ($filename === false) { - return false; - } - - if ($this->use_stat_cache) { - $result = $this->_query_stat_cache($filename); - if (is_array($result) && isset($result['.'])) { - return (array) $result['.']; - } - if (is_object($result)) { - return (array) $result; - } - } - - $stat = $this->_stat($filename, NET_SFTP_STAT); - if ($stat === false) { - $this->_remove_from_stat_cache($filename); - return false; - } - if (isset($stat['type'])) { - if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) { - $filename.= '/.'; - } - $this->_update_stat_cache($filename, (object) $stat); - return $stat; - } - - $pwd = $this->pwd; - $stat['type'] = $this->chdir($filename) ? - NET_SFTP_TYPE_DIRECTORY : - NET_SFTP_TYPE_REGULAR; - $this->pwd = $pwd; - - if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) { - $filename.= '/.'; - } - $this->_update_stat_cache($filename, (object) $stat); - - return $stat; - } - - /** - * Returns general information about a file or symbolic link. - * - * Returns an array on success and false otherwise. - * - * @param String $filename - * @return Mixed - * @access public - */ - function lstat($filename) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $filename = $this->_realpath($filename); - if ($filename === false) { - return false; - } - - if ($this->use_stat_cache) { - $result = $this->_query_stat_cache($filename); - if (is_array($result) && isset($result['.'])) { - return (array) $result['.']; - } - if (is_object($result)) { - return (array) $result; - } - } - - $lstat = $this->_stat($filename, NET_SFTP_LSTAT); - if ($lstat === false) { - $this->_remove_from_stat_cache($filename); - return false; - } - if (isset($lstat['type'])) { - if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) { - $filename.= '/.'; - } - $this->_update_stat_cache($filename, (object) $lstat); - return $lstat; - } - - $stat = $this->_stat($filename, NET_SFTP_STAT); - - if ($lstat != $stat) { - $lstat = array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK)); - $this->_update_stat_cache($filename, (object) $lstat); - return $stat; - } - - $pwd = $this->pwd; - $lstat['type'] = $this->chdir($filename) ? - NET_SFTP_TYPE_DIRECTORY : - NET_SFTP_TYPE_REGULAR; - $this->pwd = $pwd; - - if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) { - $filename.= '/.'; - } - $this->_update_stat_cache($filename, (object) $lstat); - - return $lstat; - } - - /** - * Returns general information about a file or symbolic link - * - * Determines information without calling Net_SFTP::_realpath(). - * The second parameter can be either NET_SFTP_STAT or NET_SFTP_LSTAT. - * - * @param String $filename - * @param Integer $type - * @return Mixed - * @access private - */ - function _stat($filename, $type) - { - // SFTPv4+ adds an additional 32-bit integer field - flags - to the following: - $packet = pack('Na*', strlen($filename), $filename); - if (!$this->_send_sftp_packet($type, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_ATTRS: - return $this->_parseAttributes($response); - case NET_SFTP_STATUS: - $this->_logError($response); - return false; - } - - user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS'); - return false; - } - - /** - * Truncates a file to a given length - * - * @param String $filename - * @param Integer $new_size - * @return Boolean - * @access public - */ - function truncate($filename, $new_size) - { - $attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 4294967296, $new_size); // 4294967296 == 0x100000000 == 1<<32 - - return $this->_setstat($filename, $attr, false); - } - - /** - * Sets access and modification time of file. - * - * If the file does not exist, it will be created. - * - * @param String $filename - * @param optional Integer $time - * @param optional Integer $atime - * @return Boolean - * @access public - */ - function touch($filename, $time = null, $atime = null) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $filename = $this->_realpath($filename); - if ($filename === false) { - return false; - } - - if (!isset($time)) { - $time = time(); - } - if (!isset($atime)) { - $atime = $time; - } - - $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL; - $attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime); - $packet = pack('Na*Na*', strlen($filename), $filename, $flags, $attr); - if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_HANDLE: - return $this->_close_handle(substr($response, 4)); - case NET_SFTP_STATUS: - $this->_logError($response); - break; - default: - user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS'); - return false; - } - - return $this->_setstat($filename, $attr, false); - } - - /** - * Changes file or directory owner - * - * Returns true on success or false on error. - * - * @param String $filename - * @param Integer $uid - * @param optional Boolean $recursive - * @return Boolean - * @access public - */ - function chown($filename, $uid, $recursive = false) - { - // quoting from , - // "if the owner or group is specified as -1, then that ID is not changed" - $attr = pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1); - - return $this->_setstat($filename, $attr, $recursive); - } - - /** - * Changes file or directory group - * - * Returns true on success or false on error. - * - * @param String $filename - * @param Integer $gid - * @param optional Boolean $recursive - * @return Boolean - * @access public - */ - function chgrp($filename, $gid, $recursive = false) - { - $attr = pack('N3', NET_SFTP_ATTR_UIDGID, -1, $gid); - - return $this->_setstat($filename, $attr, $recursive); - } - - /** - * Set permissions on a file. - * - * Returns the new file permissions on success or false on error. - * If $recursive is true than this just returns true or false. - * - * @param Integer $mode - * @param String $filename - * @param optional Boolean $recursive - * @return Mixed - * @access public - */ - function chmod($mode, $filename, $recursive = false) - { - if (is_string($mode) && is_int($filename)) { - $temp = $mode; - $mode = $filename; - $filename = $temp; - } - - $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777); - if (!$this->_setstat($filename, $attr, $recursive)) { - return false; - } - if ($recursive) { - return true; - } - - // rather than return what the permissions *should* be, we'll return what they actually are. this will also - // tell us if the file actually exists. - // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following: - $packet = pack('Na*', strlen($filename), $filename); - if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_ATTRS: - $attrs = $this->_parseAttributes($response); - return $attrs['permissions']; - case NET_SFTP_STATUS: - $this->_logError($response); - return false; - } - - user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS'); - return false; - } - - /** - * Sets information about a file - * - * @param String $filename - * @param String $attr - * @param Boolean $recursive - * @return Boolean - * @access private - */ - function _setstat($filename, $attr, $recursive) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $filename = $this->_realpath($filename); - if ($filename === false) { - return false; - } - - $this->_remove_from_stat_cache($filename); - - if ($recursive) { - $i = 0; - $result = $this->_setstat_recursive($filename, $attr, $i); - $this->_read_put_responses($i); - return $result; - } - - // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to - // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT. - if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) { - return false; - } - - /* - "Because some systems must use separate system calls to set various attributes, it is possible that a failure - response will be returned, but yet some of the attributes may be have been successfully modified. If possible, - servers SHOULD avoid this situation; however, clients MUST be aware that this is possible." - - -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6 - */ - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); - return false; - } - - return true; - } - - /** - * Recursively sets information on directories on the SFTP server - * - * Minimizes directory lookups and SSH_FXP_STATUS requests for speed. - * - * @param String $path - * @param String $attr - * @param Integer $i - * @return Boolean - * @access private - */ - function _setstat_recursive($path, $attr, &$i) - { - if (!$this->_read_put_responses($i)) { - return false; - } - $i = 0; - $entries = $this->_list($path, true); - - if ($entries === false) { - return $this->_setstat($path, $attr, false); - } - - // normally $entries would have at least . and .. but it might not if the directories - // permissions didn't allow reading - if (empty($entries)) { - return false; - } - - unset($entries['.'], $entries['..']); - foreach ($entries as $filename=>$props) { - if (!isset($props['type'])) { - return false; - } - - $temp = $path . '/' . $filename; - if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) { - if (!$this->_setstat_recursive($temp, $attr, $i)) { - return false; - } - } else { - if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($temp), $temp, $attr))) { - return false; - } - - $i++; - - if ($i >= NET_SFTP_QUEUE_SIZE) { - if (!$this->_read_put_responses($i)) { - return false; - } - $i = 0; - } - } - } - - if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($path), $path, $attr))) { - return false; - } - - $i++; - - if ($i >= NET_SFTP_QUEUE_SIZE) { - if (!$this->_read_put_responses($i)) { - return false; - } - $i = 0; - } - - return true; - } - - /** - * Return the target of a symbolic link - * - * @param String $link - * @return Mixed - * @access public - */ - function readlink($link) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $link = $this->_realpath($link); - - if (!$this->_send_sftp_packet(NET_SFTP_READLINK, pack('Na*', strlen($link), $link))) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_NAME: - break; - case NET_SFTP_STATUS: - $this->_logError($response); - return false; - default: - user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Ncount', $this->_string_shift($response, 4))); - // the file isn't a symlink - if (!$count) { - return false; - } - - extract(unpack('Nlength', $this->_string_shift($response, 4))); - return $this->_string_shift($response, $length); - } - - /** - * Create a symlink - * - * symlink() creates a symbolic link to the existing target with the specified name link. - * - * @param String $target - * @param String $link - * @return Boolean - * @access public - */ - function symlink($target, $link) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $target = $this->_realpath($target); - $link = $this->_realpath($link); - - $packet = pack('Na*Na*', strlen($target), $target, strlen($link), $link); - if (!$this->_send_sftp_packet(NET_SFTP_SYMLINK, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); - return false; - } - - return true; - } - - /** - * Creates a directory. - * - * @param String $dir - * @return Boolean - * @access public - */ - function mkdir($dir, $mode = -1, $recursive = false) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $dir = $this->_realpath($dir); - // by not providing any permissions, hopefully the server will use the logged in users umask - their - // default permissions. - $attr = $mode == -1 ? "\0\0\0\0" : pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777); - - if ($recursive) { - $dirs = explode('/', preg_replace('#/(?=/)|/$#', '', $dir)); - if (empty($dirs[0])) { - array_shift($dirs); - $dirs[0] = '/' . $dirs[0]; - } - for ($i = 0; $i < count($dirs); $i++) { - $temp = array_slice($dirs, 0, $i + 1); - $temp = implode('/', $temp); - $result = $this->_mkdir_helper($temp, $attr); - } - return $result; - } - - return $this->_mkdir_helper($dir, $attr); - } - - /** - * Helper function for directory creation - * - * @param String $dir - * @return Boolean - * @access private - */ - function _mkdir_helper($dir, $attr) - { - if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*a*', strlen($dir), $dir, $attr))) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); - return false; - } - - return true; - } - - /** - * Removes a directory. - * - * @param String $dir - * @return Boolean - * @access public - */ - function rmdir($dir) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $dir = $this->_realpath($dir); - if ($dir === false) { - return false; - } - - if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($dir), $dir))) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED? - $this->_logError($response, $status); - return false; - } - - $this->_remove_from_stat_cache($dir); - // the following will do a soft delete, which would be useful if you deleted a file - // and then tried to do a stat on the deleted file. the above, in contrast, does - // a hard delete - //$this->_update_stat_cache($dir, false); - - return true; - } - - /** - * Uploads a file to the SFTP server. - * - * By default, Net_SFTP::put() does not read from the local filesystem. $data is dumped directly into $remote_file. - * So, for example, if you set $data to 'filename.ext' and then do Net_SFTP::get(), you will get a file, twelve bytes - * long, containing 'filename.ext' as its contents. - * - * Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will - * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how - * large $remote_file will be, as well. - * - * If $data is a resource then it'll be used as a resource instead. - * - * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take - * care of that, yourself. - * - * $mode can take an additional two parameters - NET_SFTP_RESUME and NET_SFTP_RESUME_START. These are bitwise AND'd with - * $mode. So if you want to resume upload of a 300mb file on the local file system you'd set $mode to the following: - * - * NET_SFTP_LOCAL_FILE | NET_SFTP_RESUME - * - * If you wanted to simply append the full contents of a local file to the full contents of a remote file you'd replace - * NET_SFTP_RESUME with NET_SFTP_RESUME_START. - * - * If $mode & (NET_SFTP_RESUME | NET_SFTP_RESUME_START) then NET_SFTP_RESUME_START will be assumed. - * - * $start and $local_start give you more fine grained control over this process and take precident over NET_SFTP_RESUME - * when they're non-negative. ie. $start could let you write at the end of a file (like NET_SFTP_RESUME) or in the middle - * of one. $local_start could let you start your reading from the end of a file (like NET_SFTP_RESUME_START) or in the - * middle of one. - * - * Setting $local_start to > 0 or $mode | NET_SFTP_RESUME_START doesn't do anything unless $mode | NET_SFTP_LOCAL_FILE. - * - * @param String $remote_file - * @param String|resource $data - * @param optional Integer $mode - * @param optional Integer $start - * @param optional Integer $local_start - * @return Boolean - * @access public - * @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode(). - */ - function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_start = -1) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $remote_file = $this->_realpath($remote_file); - if ($remote_file === false) { - return false; - } - - $this->_remove_from_stat_cache($remote_file); - - $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE; - // according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file." - // in practice, it doesn't seem to do that. - //$flags|= ($mode & NET_SFTP_RESUME) ? NET_SFTP_OPEN_APPEND : NET_SFTP_OPEN_TRUNCATE; - - if ($start >= 0) { - $offset = $start; - } elseif ($mode & NET_SFTP_RESUME) { - // if NET_SFTP_OPEN_APPEND worked as it should _size() wouldn't need to be called - $size = $this->size($remote_file); - $offset = $size !== false ? $size : 0; - } else { - $offset = 0; - $flags|= NET_SFTP_OPEN_TRUNCATE; - } - - $packet = pack('Na*N2', strlen($remote_file), $remote_file, $flags, 0); - if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_HANDLE: - $handle = substr($response, 4); - break; - case NET_SFTP_STATUS: - $this->_logError($response); - return false; - default: - user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS'); - return false; - } - - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3 - switch (true) { - case is_resource($data): - $mode = $mode & ~NET_SFTP_LOCAL_FILE; - $fp = $data; - break; - case $mode & NET_SFTP_LOCAL_FILE: - if (!is_file($data)) { - user_error("$data is not a valid file"); - return false; - } - $fp = @fopen($data, 'rb'); - if (!$fp) { - return false; - } - } - - if (isset($fp)) { - $stat = fstat($fp); - $size = $stat['size']; - - if ($local_start >= 0) { - fseek($fp, $local_start); - } elseif ($mode & NET_SFTP_RESUME_START) { - // do nothing - } else { - fseek($fp, $offset); - } - } else { - $size = strlen($data); - } - - $sent = 0; - $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; - - $sftp_packet_size = 4096; // PuTTY uses 4096 - // make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header" - $sftp_packet_size-= strlen($handle) + 25; - $i = 0; - while ($sent < $size) { - $temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); - $subtemp = $offset + $sent; - $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp); - if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) { - if ($mode & NET_SFTP_LOCAL_FILE) { - fclose($fp); - } - return false; - } - $sent+= strlen($temp); - - $i++; - - if ($i == NET_SFTP_QUEUE_SIZE) { - if (!$this->_read_put_responses($i)) { - $i = 0; - break; - } - $i = 0; - } - } - - if (!$this->_read_put_responses($i)) { - if ($mode & NET_SFTP_LOCAL_FILE) { - fclose($fp); - } - $this->_close_handle($handle); - return false; - } - - if ($mode & NET_SFTP_LOCAL_FILE) { - fclose($fp); - } - - return $this->_close_handle($handle); - } - - /** - * Reads multiple successive SSH_FXP_WRITE responses - * - * Sending an SSH_FXP_WRITE packet and immediately reading its response isn't as efficient as blindly sending out $i - * SSH_FXP_WRITEs, in succession, and then reading $i responses. - * - * @param Integer $i - * @return Boolean - * @access private - */ - function _read_put_responses($i) - { - while ($i--) { - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); - break; - } - } - - return $i < 0; - } - - /** - * Close handle - * - * @param String $handle - * @return Boolean - * @access private - */ - function _close_handle($handle) - { - if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { - return false; - } - - // "The client MUST release all resources associated with the handle regardless of the status." - // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3 - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); - return false; - } - - return true; - } - - /** - * Downloads a file from the SFTP server. - * - * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if - * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the - * operation. - * - * $offset and $length can be used to download files in chunks. - * - * @param String $remote_file - * @param optional String $local_file - * @param optional Integer $offset - * @param optional Integer $length - * @return Mixed - * @access public - */ - function get($remote_file, $local_file = false, $offset = 0, $length = -1) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $remote_file = $this->_realpath($remote_file); - if ($remote_file === false) { - return false; - } - - $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0); - if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_HANDLE: - $handle = substr($response, 4); - break; - case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED - $this->_logError($response); - return false; - default: - user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS'); - return false; - } - - if (is_resource($local_file)) { - $fp = $local_file; - $stat = fstat($fp); - $res_offset = $stat['size']; - } else { - $res_offset = 0; - if ($local_file !== false) { - $fp = fopen($local_file, 'wb'); - if (!$fp) { - return false; - } - } else { - $content = ''; - } - } - - $fclose_check = $local_file !== false && !is_resource($local_file); - - $start = $offset; - $size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length; - while (true) { - $packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size); - if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) { - if ($fclose_check) { - fclose($fp); - } - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_DATA: - $temp = substr($response, 4); - $offset+= strlen($temp); - if ($local_file === false) { - $content.= $temp; - } else { - fputs($fp, $temp); - } - break; - case NET_SFTP_STATUS: - // could, in theory, return false if !strlen($content) but we'll hold off for the time being - $this->_logError($response); - break 2; - default: - user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS'); - if ($fclose_check) { - fclose($fp); - } - return false; - } - - if ($length > 0 && $length <= $offset - $start) { - break; - } - } - - if ($length > 0 && $length <= $offset - $start) { - if ($local_file === false) { - $content = substr($content, 0, $length); - } else { - ftruncate($fp, $length + $res_offset); - } - } - - if ($fclose_check) { - fclose($fp); - } - - if (!$this->_close_handle($handle)) { - return false; - } - - // if $content isn't set that means a file was written to - return isset($content) ? $content : true; - } - - /** - * Deletes a file on the SFTP server. - * - * @param String $path - * @param Boolean $recursive - * @return Boolean - * @access public - */ - function delete($path, $recursive = true) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $path = $this->_realpath($path); - if ($path === false) { - return false; - } - - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 - if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path))) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); - if (!$recursive) { - return false; - } - $i = 0; - $result = $this->_delete_recursive($path, $i); - $this->_read_put_responses($i); - return $result; - } - - $this->_remove_from_stat_cache($path); - - return true; - } - - /** - * Recursively deletes directories on the SFTP server - * - * Minimizes directory lookups and SSH_FXP_STATUS requests for speed. - * - * @param String $path - * @param Integer $i - * @return Boolean - * @access private - */ - function _delete_recursive($path, &$i) - { - if (!$this->_read_put_responses($i)) { - return false; - } - $i = 0; - $entries = $this->_list($path, true); - - // normally $entries would have at least . and .. but it might not if the directories - // permissions didn't allow reading - if (empty($entries)) { - return false; - } - - unset($entries['.'], $entries['..']); - foreach ($entries as $filename=>$props) { - if (!isset($props['type'])) { - return false; - } - - $temp = $path . '/' . $filename; - if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) { - if (!$this->_delete_recursive($temp, $i)) { - return false; - } - } else { - if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($temp), $temp))) { - return false; - } - - $i++; - - if ($i >= NET_SFTP_QUEUE_SIZE) { - if (!$this->_read_put_responses($i)) { - return false; - } - $i = 0; - } - } - $this->_remove_from_stat_cache($path); - } - - if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) { - return false; - } - - $i++; - - if ($i >= NET_SFTP_QUEUE_SIZE) { - if (!$this->_read_put_responses($i)) { - return false; - } - $i = 0; - } - - return true; - } - - /** - * Checks whether a file or directory exists - * - * @param String $path - * @return Boolean - * @access public - */ - function file_exists($path) - { - if ($this->use_stat_cache) { - $path = $this->_realpath($path); - - $result = $this->_query_stat_cache($path); - - if (isset($result)) { - // return true if $result is an array or if it's an stdClass object - return $result !== false; - } - } - - return $this->stat($path) !== false; - } - - /** - * Tells whether the filename is a directory - * - * @param String $path - * @return Boolean - * @access public - */ - function is_dir($path) - { - $result = $this->_get_stat_cache_prop($path, 'type'); - if ($result === false) { - return false; - } - return $result === NET_SFTP_TYPE_DIRECTORY; - } - - /** - * Tells whether the filename is a regular file - * - * @param String $path - * @return Boolean - * @access public - */ - function is_file($path) - { - $result = $this->_get_stat_cache_prop($path, 'type'); - if ($result === false) { - return false; - } - return $result === NET_SFTP_TYPE_REGULAR; - } - - /** - * Tells whether the filename is a symbolic link - * - * @param String $path - * @return Boolean - * @access public - */ - function is_link($path) - { - $result = $this->_get_stat_cache_prop($path, 'type'); - if ($result === false) { - return false; - } - return $result === NET_SFTP_TYPE_SYMLINK; - } - - /** - * Gets last access time of file - * - * @param String $path - * @return Mixed - * @access public - */ - function fileatime($path) - { - return $this->_get_stat_cache_prop($path, 'atime'); - } - - /** - * Gets file modification time - * - * @param String $path - * @return Mixed - * @access public - */ - function filemtime($path) - { - return $this->_get_stat_cache_prop($path, 'mtime'); - } - - /** - * Gets file permissions - * - * @param String $path - * @return Mixed - * @access public - */ - function fileperms($path) - { - return $this->_get_stat_cache_prop($path, 'permissions'); - } - - /** - * Gets file owner - * - * @param String $path - * @return Mixed - * @access public - */ - function fileowner($path) - { - return $this->_get_stat_cache_prop($path, 'uid'); - } - - /** - * Gets file group - * - * @param String $path - * @return Mixed - * @access public - */ - function filegroup($path) - { - return $this->_get_stat_cache_prop($path, 'gid'); - } - - /** - * Gets file size - * - * @param String $path - * @return Mixed - * @access public - */ - function filesize($path) - { - return $this->_get_stat_cache_prop($path, 'size'); - } - - /** - * Gets file type - * - * @param String $path - * @return Mixed - * @access public - */ - function filetype($path) - { - $type = $this->_get_stat_cache_prop($path, 'type'); - if ($type === false) { - return false; - } - - switch ($type) { - case NET_SFTP_TYPE_BLOCK_DEVICE: return 'block'; - case NET_SFTP_TYPE_CHAR_DEVICE: return 'char'; - case NET_SFTP_TYPE_DIRECTORY: return 'dir'; - case NET_SFTP_TYPE_FIFO: return 'fifo'; - case NET_SFTP_TYPE_REGULAR: return 'file'; - case NET_SFTP_TYPE_SYMLINK: return 'link'; - default: return false; - } - } - - /** - * Return a stat properity - * - * Uses cache if appropriate. - * - * @param String $path - * @param String $prop - * @return Mixed - * @access private - */ - function _get_stat_cache_prop($path, $prop) - { - if ($this->use_stat_cache) { - $path = $this->_realpath($path); - - $result = $this->_query_stat_cache($path); - - if (is_object($result) && isset($result->$prop)) { - return $result->$prop; - } - } - - $result = $this->stat($path); - - if ($result === false || !isset($result[$prop])) { - return false; - } - - return $result[$prop]; - } - - /** - * Renames a file or a directory on the SFTP server - * - * @param String $oldname - * @param String $newname - * @return Boolean - * @access public - */ - function rename($oldname, $newname) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $oldname = $this->_realpath($oldname); - $newname = $this->_realpath($newname); - if ($oldname === false || $newname === false) { - return false; - } - - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 - $packet = pack('Na*Na*', strlen($oldname), $oldname, strlen($newname), $newname); - if (!$this->_send_sftp_packet(NET_SFTP_RENAME, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS'); - return false; - } - - // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - $this->_logError($response, $status); - return false; - } - - // don't move the stat cache entry over since this operation could very well change the - // atime and mtime attributes - //$this->_update_stat_cache($newname, $this->_query_stat_cache($oldname)); - $this->_remove_from_stat_cache($oldname); - $this->_remove_from_stat_cache($newname); - - return true; - } - - /** - * Parse Attributes - * - * See '7. File Attributes' of draft-ietf-secsh-filexfer-13 for more info. - * - * @param String $response - * @return Array - * @access private - */ - function _parseAttributes(&$response) - { - $attr = array(); - extract(unpack('Nflags', $this->_string_shift($response, 4))); - // SFTPv4+ have a type field (a byte) that follows the above flag field - foreach ($this->attributes as $key => $value) { - switch ($flags & $key) { - case NET_SFTP_ATTR_SIZE: // 0x00000001 - // The size attribute is defined as an unsigned 64-bit integer. - // The following will use floats on 32-bit platforms, if necessary. - // As can be seen in the BigInteger class, floats are generally - // IEEE 754 binary64 "double precision" on such platforms and - // as such can represent integers of at least 2^50 without loss - // of precision. Interpreted in filesize, 2^50 bytes = 1024 TiB. - $attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8))); - break; - case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only) - $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8)); - break; - case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004 - $attr+= unpack('Npermissions', $this->_string_shift($response, 4)); - // mode == permissions; permissions was the original array key and is retained for bc purposes. - // mode was added because that's the more industry standard terminology - $attr+= array('mode' => $attr['permissions']); - $fileType = $this->_parseMode($attr['permissions']); - if ($fileType !== false) { - $attr+= array('type' => $fileType); - } - break; - case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008 - $attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8)); - break; - case NET_SFTP_ATTR_EXTENDED: // 0x80000000 - extract(unpack('Ncount', $this->_string_shift($response, 4))); - for ($i = 0; $i < $count; $i++) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $key = $this->_string_shift($response, $length); - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $attr[$key] = $this->_string_shift($response, $length); - } - } - } - return $attr; - } - - /** - * Attempt to identify the file type - * - * Quoting the SFTP RFC, "Implementations MUST NOT send bits that are not defined" but they seem to anyway - * - * @param Integer $mode - * @return Integer - * @access private - */ - function _parseMode($mode) - { - // values come from http://lxr.free-electrons.com/source/include/uapi/linux/stat.h#L12 - // see, also, http://linux.die.net/man/2/stat - switch ($mode & 0170000) {// ie. 1111 0000 0000 0000 - case 0000000: // no file type specified - figure out the file type using alternative means - return false; - case 0040000: - return NET_SFTP_TYPE_DIRECTORY; - case 0100000: - return NET_SFTP_TYPE_REGULAR; - case 0120000: - return NET_SFTP_TYPE_SYMLINK; - // new types introduced in SFTPv5+ - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2 - case 0010000: // named pipe (fifo) - return NET_SFTP_TYPE_FIFO; - case 0020000: // character special - return NET_SFTP_TYPE_CHAR_DEVICE; - case 0060000: // block special - return NET_SFTP_TYPE_BLOCK_DEVICE; - case 0140000: // socket - return NET_SFTP_TYPE_SOCKET; - case 0160000: // whiteout - // "SPECIAL should be used for files that are of - // a known type which cannot be expressed in the protocol" - return NET_SFTP_TYPE_SPECIAL; - default: - return NET_SFTP_TYPE_UNKNOWN; - } - } - - /** - * Parse Longname - * - * SFTPv3 doesn't provide any easy way of identifying a file type. You could try to open - * a file as a directory and see if an error is returned or you could try to parse the - * SFTPv3-specific longname field of the SSH_FXP_NAME packet. That's what this function does. - * The result is returned using the - * {@link http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 SFTPv4 type constants}. - * - * If the longname is in an unrecognized format bool(false) is returned. - * - * @param String $longname - * @return Mixed - * @access private - */ - function _parseLongname($longname) - { - // http://en.wikipedia.org/wiki/Unix_file_types - // http://en.wikipedia.org/wiki/Filesystem_permissions#Notation_of_traditional_Unix_permissions - if (preg_match('#^[^/]([r-][w-][xstST-]){3}#', $longname)) { - switch ($longname[0]) { - case '-': - return NET_SFTP_TYPE_REGULAR; - case 'd': - return NET_SFTP_TYPE_DIRECTORY; - case 'l': - return NET_SFTP_TYPE_SYMLINK; - default: - return NET_SFTP_TYPE_SPECIAL; - } - } - - return false; - } - - /** - * Sends SFTP Packets - * - * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info. - * - * @param Integer $type - * @param String $data - * @see Net_SFTP::_get_sftp_packet() - * @see Net_SSH2::_send_channel_packet() - * @return Boolean - * @access private - */ - function _send_sftp_packet($type, $data) - { - $packet = $this->request_id !== false ? - pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) : - pack('NCa*', strlen($data) + 1, $type, $data); - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $result = $this->_send_channel_packet(NET_SFTP_CHANNEL, $packet); - $stop = strtok(microtime(), ' ') + strtok(''); - - if (defined('NET_SFTP_LOGGING')) { - $packet_type = '-> ' . $this->packet_types[$type] . - ' (' . round($stop - $start, 4) . 's)'; - if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) { - echo "
\r\n" . $this->_format_log(array($data), array($packet_type)) . "\r\n
\r\n"; - flush(); - ob_flush(); - } else { - $this->packet_type_log[] = $packet_type; - if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) { - $this->packet_log[] = $data; - } - } - } - - return $result; - } - - /** - * Receives SFTP Packets - * - * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info. - * - * Incidentally, the number of SSH_MSG_CHANNEL_DATA messages has no bearing on the number of SFTP packets present. - * There can be one SSH_MSG_CHANNEL_DATA messages containing two SFTP packets or there can be two SSH_MSG_CHANNEL_DATA - * messages containing one SFTP packet. - * - * @see Net_SFTP::_send_sftp_packet() - * @return String - * @access private - */ - function _get_sftp_packet() - { - $this->curTimeout = false; - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - - // SFTP packet length - while (strlen($this->packet_buffer) < 4) { - $temp = $this->_get_channel_packet(NET_SFTP_CHANNEL); - if (is_bool($temp)) { - $this->packet_type = false; - $this->packet_buffer = ''; - return false; - } - $this->packet_buffer.= $temp; - } - extract(unpack('Nlength', $this->_string_shift($this->packet_buffer, 4))); - $tempLength = $length; - $tempLength-= strlen($this->packet_buffer); - - // SFTP packet type and data payload - while ($tempLength > 0) { - $temp = $this->_get_channel_packet(NET_SFTP_CHANNEL); - if (is_bool($temp)) { - $this->packet_type = false; - $this->packet_buffer = ''; - return false; - } - $this->packet_buffer.= $temp; - $tempLength-= strlen($temp); - } - - $stop = strtok(microtime(), ' ') + strtok(''); - - $this->packet_type = ord($this->_string_shift($this->packet_buffer)); - - if ($this->request_id !== false) { - $this->_string_shift($this->packet_buffer, 4); // remove the request id - $length-= 5; // account for the request id and the packet type - } else { - $length-= 1; // account for the packet type - } - - $packet = $this->_string_shift($this->packet_buffer, $length); - - if (defined('NET_SFTP_LOGGING')) { - $packet_type = '<- ' . $this->packet_types[$this->packet_type] . - ' (' . round($stop - $start, 4) . 's)'; - if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) { - echo "
\r\n" . $this->_format_log(array($packet), array($packet_type)) . "\r\n
\r\n"; - flush(); - ob_flush(); - } else { - $this->packet_type_log[] = $packet_type; - if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) { - $this->packet_log[] = $packet; - } - } - } - - return $packet; - } - - /** - * Returns a log of the packets that have been sent and received. - * - * Returns a string if NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX, an array if NET_SFTP_LOGGING == NET_SFTP_LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING') - * - * @access public - * @return String or Array - */ - function getSFTPLog() - { - if (!defined('NET_SFTP_LOGGING')) { - return false; - } - - switch (NET_SFTP_LOGGING) { - case NET_SFTP_LOG_COMPLEX: - return $this->_format_log($this->packet_log, $this->packet_type_log); - break; - //case NET_SFTP_LOG_SIMPLE: - default: - return $this->packet_type_log; - } - } - - /** - * Returns all errors - * - * @return String - * @access public - */ - function getSFTPErrors() - { - return $this->sftp_errors; - } - - /** - * Returns the last error - * - * @return String - * @access public - */ - function getLastSFTPError() - { - return count($this->sftp_errors) ? $this->sftp_errors[count($this->sftp_errors) - 1] : ''; - } - - /** - * Get supported SFTP versions - * - * @return Array - * @access public - */ - function getSupportedVersions() - { - $temp = array('version' => $this->version); - if (isset($this->extensions['versions'])) { - $temp['extensions'] = $this->extensions['versions']; - } - return $temp; - } - - /** - * Disconnect - * - * @param Integer $reason - * @return Boolean - * @access private - */ - function _disconnect($reason) - { - $this->pwd = false; - parent::_disconnect($reason); - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SFTP/Stream.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SFTP/Stream.php deleted file mode 100644 index eda1cdba..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SFTP/Stream.php +++ /dev/null @@ -1,801 +0,0 @@ - - * @copyright 2013 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * SFTP Stream Wrapper - * - * @package Net_SFTP_Stream - * @author Jim Wigginton - * @access public - */ -class Net_SFTP_Stream -{ - /** - * SFTP instances - * - * Rather than re-create the connection we re-use instances if possible - * - * @var Array - */ - static $instances; - - /** - * SFTP instance - * - * @var Object - * @access private - */ - var $sftp; - - /** - * Path - * - * @var String - * @access private - */ - var $path; - - /** - * Mode - * - * @var String - * @access private - */ - var $mode; - - /** - * Position - * - * @var Integer - * @access private - */ - var $pos; - - /** - * Size - * - * @var Integer - * @access private - */ - var $size; - - /** - * Directory entries - * - * @var Array - * @access private - */ - var $entries; - - /** - * EOF flag - * - * @var Boolean - * @access private - */ - var $eof; - - /** - * Context resource - * - * Technically this needs to be publically accessible so PHP can set it directly - * - * @var Resource - * @access public - */ - var $context; - - /** - * Notification callback function - * - * @var Callable - * @access public - */ - var $notification; - - /** - * Registers this class as a URL wrapper. - * - * @param optional String $protocol The wrapper name to be registered. - * @return Boolean True on success, false otherwise. - * @access public - */ - static function register($protocol = 'sftp') - { - if (in_array($protocol, stream_get_wrappers(), true)) { - return false; - } - $class = function_exists('get_called_class') ? get_called_class() : __CLASS__; - return stream_wrapper_register($protocol, $class); - } - - /** - * The Constructor - * - * @access public - */ - function Net_SFTP_Stream() - { - if (defined('NET_SFTP_STREAM_LOGGING')) { - echo "__construct()\r\n"; - } - - if (!class_exists('Net_SFTP')) { - include_once 'Net/SFTP.php'; - } - } - - /** - * Path Parser - * - * Extract a path from a URI and actually connect to an SSH server if appropriate - * - * If "notification" is set as a context parameter the message code for successful login is - * NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE. - * - * @param String $path - * @return String - * @access private - */ - function _parse_path($path) - { - extract(parse_url($path) + array('port' => 22)); - - if (!isset($host)) { - return false; - } - - if (isset($this->context)) { - $context = stream_context_get_params($this->context); - if (isset($context['notification'])) { - $this->notification = $context['notification']; - } - } - - if ($host[0] == '$') { - $host = substr($host, 1); - global $$host; - if (!is_object($$host) || get_class($$host) != 'Net_SFTP') { - return false; - } - $this->sftp = $$host; - } else { - if (isset($this->context)) { - $context = stream_context_get_options($this->context); - } - if (isset($context[$scheme]['session'])) { - $sftp = $context[$scheme]['session']; - } - if (isset($context[$scheme]['sftp'])) { - $sftp = $context[$scheme]['sftp']; - } - if (isset($sftp) && is_object($sftp) && get_class($sftp) == 'Net_SFTP') { - $this->sftp = $sftp; - return $path; - } - if (isset($context[$scheme]['username'])) { - $user = $context[$scheme]['username']; - } - if (isset($context[$scheme]['password'])) { - $pass = $context[$scheme]['password']; - } - if (isset($context[$scheme]['privkey']) && is_object($context[$scheme]['privkey']) && get_Class($context[$scheme]['privkey']) == 'Crypt_RSA') { - $pass = $context[$scheme]['privkey']; - } - - if (!isset($user) || !isset($pass)) { - return false; - } - - // casting $pass to a string is necessary in the event that it's a Crypt_RSA object - if (isset(self::$instances[$host][$port][$user][(string) $pass])) { - $this->sftp = self::$instances[$host][$port][$user][(string) $pass]; - } else { - $this->sftp = new Net_SFTP($host, $port); - $this->sftp->disableStatCache(); - if (isset($this->notification) && is_callable($this->notification)) { - /* if !is_callable($this->notification) we could do this: - - user_error('fopen(): failed to call user notifier', E_USER_WARNING); - - the ftp wrapper gives errors like that when the notifier isn't callable. - i've opted not to do that, however, since the ftp wrapper gives the line - on which the fopen occurred as the line number - not the line that the - user_error is on. - */ - call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0); - call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0); - if (!$this->sftp->login($user, $pass)) { - call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0); - return false; - } - call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0); - } else { - if (!$this->sftp->login($user, $pass)) { - return false; - } - } - self::$instances[$host][$port][$user][(string) $pass] = $this->sftp; - } - } - - return $path; - } - - /** - * Opens file or URL - * - * @param String $path - * @param String $mode - * @param Integer $options - * @param String $opened_path - * @return Boolean - * @access public - */ - function _stream_open($path, $mode, $options, &$opened_path) - { - $path = $this->_parse_path($path); - - if ($path === false) { - return false; - } - $this->path = $path; - - $this->size = $this->sftp->size($path); - $this->mode = preg_replace('#[bt]$#', '', $mode); - $this->eof = false; - - if ($this->size === false) { - if ($this->mode[0] == 'r') { - return false; - } - } else { - switch ($this->mode[0]) { - case 'x': - return false; - case 'w': - case 'c': - $this->sftp->truncate($path, 0); - } - } - - $this->pos = $this->mode[0] != 'a' ? 0 : $this->size; - - return true; - } - - /** - * Read from stream - * - * @param Integer $count - * @return Mixed - * @access public - */ - function _stream_read($count) - { - switch ($this->mode) { - case 'w': - case 'a': - case 'x': - case 'c': - return false; - } - - // commented out because some files - eg. /dev/urandom - will say their size is 0 when in fact it's kinda infinite - //if ($this->pos >= $this->size) { - // $this->eof = true; - // return false; - //} - - $result = $this->sftp->get($this->path, false, $this->pos, $count); - if (isset($this->notification) && is_callable($this->notification)) { - if ($result === false) { - call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0); - return 0; - } - // seems that PHP calls stream_read in 8k chunks - call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $this->size); - } - - if (empty($result)) { // ie. false or empty string - $this->eof = true; - return false; - } - $this->pos+= strlen($result); - - return $result; - } - - /** - * Write to stream - * - * @param String $data - * @return Mixed - * @access public - */ - function _stream_write($data) - { - switch ($this->mode) { - case 'r': - return false; - } - - $result = $this->sftp->put($this->path, $data, NET_SFTP_STRING, $this->pos); - if (isset($this->notification) && is_callable($this->notification)) { - if (!$result) { - call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0); - return 0; - } - // seems that PHP splits up strings into 8k blocks before calling stream_write - call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data)); - } - - if ($result === false) { - return false; - } - $this->pos+= strlen($data); - if ($this->pos > $this->size) { - $this->size = $this->pos; - } - $this->eof = false; - return strlen($data); - } - - /** - * Retrieve the current position of a stream - * - * @return Integer - * @access public - */ - function _stream_tell() - { - return $this->pos; - } - - /** - * Tests for end-of-file on a file pointer - * - * In my testing there are four classes functions that normally effect the pointer: - * fseek, fputs / fwrite, fgets / fread and ftruncate. - * - * Only fgets / fread, however, results in feof() returning true. do fputs($fp, 'aaa') on a blank file and feof() - * will return false. do fread($fp, 1) and feof() will then return true. do fseek($fp, 10) on ablank file and feof() - * will return false. do fread($fp, 1) and feof() will then return true. - * - * @return Boolean - * @access public - */ - function _stream_eof() - { - return $this->eof; - } - - /** - * Seeks to specific location in a stream - * - * @param Integer $offset - * @param Integer $whence - * @return Boolean - * @access public - */ - function _stream_seek($offset, $whence) - { - switch ($whence) { - case SEEK_SET: - if ($offset >= $this->size || $offset < 0) { - return false; - } - break; - case SEEK_CUR: - $offset+= $this->pos; - break; - case SEEK_END: - $offset+= $this->size; - } - - $this->pos = $offset; - $this->eof = false; - return true; - } - - /** - * Change stream options - * - * @param String $path - * @param Integer $option - * @param Mixed $var - * @return Boolean - * @access public - */ - function _stream_metadata($path, $option, $var) - { - $path = $this->_parse_path($path); - if ($path === false) { - return false; - } - - // stream_metadata was introduced in PHP 5.4.0 but as of 5.4.11 the constants haven't been defined - // see http://www.php.net/streamwrapper.stream-metadata and https://bugs.php.net/64246 - // and https://github.com/php/php-src/blob/master/main/php_streams.h#L592 - switch ($option) { - case 1: // PHP_STREAM_META_TOUCH - return $this->sftp->touch($path, $var[0], $var[1]); - case 2: // PHP_STREAM_OWNER_NAME - case 3: // PHP_STREAM_GROUP_NAME - return false; - case 4: // PHP_STREAM_META_OWNER - return $this->sftp->chown($path, $var); - case 5: // PHP_STREAM_META_GROUP - return $this->sftp->chgrp($path, $var); - case 6: // PHP_STREAM_META_ACCESS - return $this->sftp->chmod($path, $var) !== false; - } - } - - /** - * Retrieve the underlaying resource - * - * @param Integer $cast_as - * @return Resource - * @access public - */ - function _stream_cast($cast_as) - { - return $this->sftp->fsock; - } - - /** - * Advisory file locking - * - * @param Integer $operation - * @return Boolean - * @access public - */ - function _stream_lock($operation) - { - return false; - } - - /** - * Renames a file or directory - * - * Attempts to rename oldname to newname, moving it between directories if necessary. - * If newname exists, it will be overwritten. This is a departure from what Net_SFTP - * does. - * - * @param String $path_from - * @param String $path_to - * @return Boolean - * @access public - */ - function _rename($path_from, $path_to) - { - $path1 = parse_url($path_from); - $path2 = parse_url($path_to); - unset($path1['path'], $path2['path']); - if ($path1 != $path2) { - return false; - } - - $path_from = $this->_parse_path($path_from); - $path_to = parse_url($path_to); - if ($path_from == false) { - return false; - } - - $path_to = $path_to['path']; // the $component part of parse_url() was added in PHP 5.1.2 - // "It is an error if there already exists a file with the name specified by newpath." - // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5 - if (!$this->sftp->rename($path_from, $path_to)) { - if ($this->sftp->stat($path_to)) { - return $this->sftp->delete($path_to, true) && $this->sftp->rename($path_from, $path_to); - } - return false; - } - - return true; - } - - /** - * Open directory handle - * - * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and - * removed in 5.4 I'm just going to ignore it. - * - * Also, nlist() is the best that this function is realistically going to be able to do. When an SFTP client - * sends a SSH_FXP_READDIR packet you don't generally get info on just one file but on multiple files. Quoting - * the SFTP specs: - * - * The SSH_FXP_NAME response has the following format: - * - * uint32 id - * uint32 count - * repeats count times: - * string filename - * string longname - * ATTRS attrs - * - * @param String $path - * @param Integer $options - * @return Boolean - * @access public - */ - function _dir_opendir($path, $options) - { - $path = $this->_parse_path($path); - if ($path === false) { - return false; - } - $this->pos = 0; - $this->entries = $this->sftp->nlist($path); - return $this->entries !== false; - } - - /** - * Read entry from directory handle - * - * @return Mixed - * @access public - */ - function _dir_readdir() - { - if (isset($this->entries[$this->pos])) { - return $this->entries[$this->pos++]; - } - return false; - } - - /** - * Rewind directory handle - * - * @return Boolean - * @access public - */ - function _dir_rewinddir() - { - $this->pos = 0; - return true; - } - - /** - * Close directory handle - * - * @return Boolean - * @access public - */ - function _dir_closedir() - { - return true; - } - - /** - * Create a directory - * - * Only valid $options is STREAM_MKDIR_RECURSIVE - * - * @param String $path - * @param Integer $mode - * @param Integer $options - * @return Boolean - * @access public - */ - function _mkdir($path, $mode, $options) - { - $path = $this->_parse_path($path); - if ($path === false) { - return false; - } - - return $this->sftp->mkdir($path, $mode, $options & STREAM_MKDIR_RECURSIVE); - } - - /** - * Removes a directory - * - * Only valid $options is STREAM_MKDIR_RECURSIVE per , however, - * does not have a $recursive parameter as mkdir() does so I don't know how - * STREAM_MKDIR_RECURSIVE is supposed to be set. Also, when I try it out with rmdir() I get 8 as - * $options. What does 8 correspond to? - * - * @param String $path - * @param Integer $mode - * @param Integer $options - * @return Boolean - * @access public - */ - function _rmdir($path, $options) - { - $path = $this->_parse_path($path); - if ($path === false) { - return false; - } - - return $this->sftp->rmdir($path); - } - - /** - * Flushes the output - * - * See . Always returns true because Net_SFTP doesn't cache stuff before writing - * - * @return Boolean - * @access public - */ - function _stream_flush() - { - return true; - } - - /** - * Retrieve information about a file resource - * - * @return Mixed - * @access public - */ - function _stream_stat() - { - $results = $this->sftp->stat($this->path); - if ($results === false) { - return false; - } - return $results; - } - - /** - * Delete a file - * - * @param String $path - * @return Boolean - * @access public - */ - function _unlink($path) - { - $path = $this->_parse_path($path); - if ($path === false) { - return false; - } - - return $this->sftp->delete($path, false); - } - - /** - * Retrieve information about a file - * - * Ignores the STREAM_URL_STAT_QUIET flag because the entirety of Net_SFTP_Stream is quiet by default - * might be worthwhile to reconstruct bits 12-16 (ie. the file type) if mode doesn't have them but we'll - * cross that bridge when and if it's reached - * - * @param String $path - * @param Integer $flags - * @return Mixed - * @access public - */ - function _url_stat($path, $flags) - { - $path = $this->_parse_path($path); - if ($path === false) { - return false; - } - - $results = $flags & STREAM_URL_STAT_LINK ? $this->sftp->lstat($path) : $this->sftp->stat($path); - if ($results === false) { - return false; - } - - return $results; - } - - /** - * Truncate stream - * - * @param Integer $new_size - * @return Boolean - * @access public - */ - function _stream_truncate($new_size) - { - if (!$this->sftp->truncate($this->path, $new_size)) { - return false; - } - - $this->eof = false; - $this->size = $new_size; - - return true; - } - - /** - * Change stream options - * - * STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush isn't. - * The other two aren't supported because of limitations in Net_SFTP. - * - * @param Integer $option - * @param Integer $arg1 - * @param Integer $arg2 - * @return Boolean - * @access public - */ - function _stream_set_option($option, $arg1, $arg2) - { - return false; - } - - /** - * Close an resource - * - * @access public - */ - function _stream_close() - { - } - - /** - * __call Magic Method - * - * When you're utilizing an SFTP stream you're not calling the methods in this class directly - PHP is calling them for you. - * Which kinda begs the question... what methods is PHP calling and what parameters is it passing to them? This function - * lets you figure that out. - * - * If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not - * NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method. - * - * @param String - * @param Array - * @return Mixed - * @access public - */ - function __call($name, $arguments) - { - if (defined('NET_SFTP_STREAM_LOGGING')) { - echo $name . '('; - $last = count($arguments) - 1; - foreach ($arguments as $i => $argument) { - var_export($argument); - if ($i != $last) { - echo ','; - } - } - echo ")\r\n"; - } - $name = '_' . $name; - if (!method_exists($this, $name)) { - return false; - } - return call_user_func_array(array($this, $name), $arguments); - } -} - -Net_SFTP_Stream::register(); diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SSH1.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SSH1.php deleted file mode 100644 index f1fae02b..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SSH1.php +++ /dev/null @@ -1,1651 +0,0 @@ - - * login('username', 'password')) { - * exit('Login Failed'); - * } - * - * echo $ssh->exec('ls -la'); - * ?> - * - * - * Here's another short example: - * - * login('username', 'password')) { - * exit('Login Failed'); - * } - * - * echo $ssh->read('username@username:~$'); - * $ssh->write("ls -la\n"); - * echo $ssh->read('username@username:~$'); - * ?> - * - * - * More information on the SSHv1 specification can be found by reading - * {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}. - * - * 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. - * - * @category Net - * @package Net_SSH1 - * @author Jim Wigginton - * @copyright 2007 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/**#@+ - * Encryption Methods - * - * @see Net_SSH1::getSupportedCiphers() - * @access public - */ -/** - * No encryption - * - * Not supported. - */ -define('NET_SSH1_CIPHER_NONE', 0); -/** - * IDEA in CFB mode - * - * Not supported. - */ -define('NET_SSH1_CIPHER_IDEA', 1); -/** - * DES in CBC mode - */ -define('NET_SSH1_CIPHER_DES', 2); -/** - * Triple-DES in CBC mode - * - * All implementations are required to support this - */ -define('NET_SSH1_CIPHER_3DES', 3); -/** - * TRI's Simple Stream encryption CBC - * - * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, does define it (see cipher.h), - * although it doesn't use it (see cipher.c) - */ -define('NET_SSH1_CIPHER_BROKEN_TSS', 4); -/** - * RC4 - * - * Not supported. - * - * @internal According to the SSH1 specs: - * - * "The first 16 bytes of the session key are used as the key for - * the server to client direction. The remaining 16 bytes are used - * as the key for the client to server direction. This gives - * independent 128-bit keys for each direction." - * - * This library currently only supports encryption when the same key is being used for both directions. This is - * because there's only one $crypto object. Two could be added ($encrypt and $decrypt, perhaps). - */ -define('NET_SSH1_CIPHER_RC4', 5); -/** - * Blowfish - * - * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, defines it (see cipher.h) and - * uses it (see cipher.c) - */ -define('NET_SSH1_CIPHER_BLOWFISH', 6); -/**#@-*/ - -/**#@+ - * Authentication Methods - * - * @see Net_SSH1::getSupportedAuthentications() - * @access public - */ -/** - * .rhosts or /etc/hosts.equiv - */ -define('NET_SSH1_AUTH_RHOSTS', 1); -/** - * pure RSA authentication - */ -define('NET_SSH1_AUTH_RSA', 2); -/** - * password authentication - * - * This is the only method that is supported by this library. - */ -define('NET_SSH1_AUTH_PASSWORD', 3); -/** - * .rhosts with RSA host authentication - */ -define('NET_SSH1_AUTH_RHOSTS_RSA', 4); -/**#@-*/ - -/**#@+ - * Terminal Modes - * - * @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html - * @access private - */ -define('NET_SSH1_TTY_OP_END', 0); -/**#@-*/ - -/** - * The Response Type - * - * @see Net_SSH1::_get_binary_packet() - * @access private - */ -define('NET_SSH1_RESPONSE_TYPE', 1); - -/** - * The Response Data - * - * @see Net_SSH1::_get_binary_packet() - * @access private - */ -define('NET_SSH1_RESPONSE_DATA', 2); - -/**#@+ - * Execution Bitmap Masks - * - * @see Net_SSH1::bitmap - * @access private - */ -define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001); -define('NET_SSH1_MASK_CONNECTED', 0x00000002); -define('NET_SSH1_MASK_LOGIN', 0x00000004); -define('NET_SSH1_MASK_SHELL', 0x00000008); -/**#@-*/ - -/**#@+ - * @access public - * @see Net_SSH1::getLog() - */ -/** - * Returns the message numbers - */ -define('NET_SSH1_LOG_SIMPLE', 1); -/** - * Returns the message content - */ -define('NET_SSH1_LOG_COMPLEX', 2); -/** - * Outputs the content real-time - */ -define('NET_SSH1_LOG_REALTIME', 3); -/** - * Dumps the content real-time to a file - */ -define('NET_SSH1_LOG_REALTIME_FILE', 4); -/**#@-*/ - -/**#@+ - * @access public - * @see Net_SSH1::read() - */ -/** - * Returns when a string matching $expect exactly is found - */ -define('NET_SSH1_READ_SIMPLE', 1); -/** - * Returns when a string matching the regular expression $expect is found - */ -define('NET_SSH1_READ_REGEX', 2); -/**#@-*/ - -/** - * Pure-PHP implementation of SSHv1. - * - * @package Net_SSH1 - * @author Jim Wigginton - * @access public - */ -class Net_SSH1 -{ - /** - * The SSH identifier - * - * @var String - * @access private - */ - var $identifier = 'SSH-1.5-phpseclib'; - - /** - * The Socket Object - * - * @var Object - * @access private - */ - var $fsock; - - /** - * The cryptography object - * - * @var Object - * @access private - */ - var $crypto = false; - - /** - * Execution Bitmap - * - * The bits that are set represent functions that have been called already. This is used to determine - * if a requisite function has been successfully executed. If not, an error should be thrown. - * - * @var Integer - * @access private - */ - var $bitmap = 0; - - /** - * The Server Key Public Exponent - * - * Logged for debug purposes - * - * @see Net_SSH1::getServerKeyPublicExponent() - * @var String - * @access private - */ - var $server_key_public_exponent; - - /** - * The Server Key Public Modulus - * - * Logged for debug purposes - * - * @see Net_SSH1::getServerKeyPublicModulus() - * @var String - * @access private - */ - var $server_key_public_modulus; - - /** - * The Host Key Public Exponent - * - * Logged for debug purposes - * - * @see Net_SSH1::getHostKeyPublicExponent() - * @var String - * @access private - */ - var $host_key_public_exponent; - - /** - * The Host Key Public Modulus - * - * Logged for debug purposes - * - * @see Net_SSH1::getHostKeyPublicModulus() - * @var String - * @access private - */ - var $host_key_public_modulus; - - /** - * Supported Ciphers - * - * Logged for debug purposes - * - * @see Net_SSH1::getSupportedCiphers() - * @var Array - * @access private - */ - var $supported_ciphers = array( - NET_SSH1_CIPHER_NONE => 'No encryption', - NET_SSH1_CIPHER_IDEA => 'IDEA in CFB mode', - NET_SSH1_CIPHER_DES => 'DES in CBC mode', - NET_SSH1_CIPHER_3DES => 'Triple-DES in CBC mode', - NET_SSH1_CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC', - NET_SSH1_CIPHER_RC4 => 'RC4', - NET_SSH1_CIPHER_BLOWFISH => 'Blowfish' - ); - - /** - * Supported Authentications - * - * Logged for debug purposes - * - * @see Net_SSH1::getSupportedAuthentications() - * @var Array - * @access private - */ - var $supported_authentications = array( - NET_SSH1_AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv', - NET_SSH1_AUTH_RSA => 'pure RSA authentication', - NET_SSH1_AUTH_PASSWORD => 'password authentication', - NET_SSH1_AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication' - ); - - /** - * Server Identification - * - * @see Net_SSH1::getServerIdentification() - * @var String - * @access private - */ - var $server_identification = ''; - - /** - * Protocol Flags - * - * @see Net_SSH1::Net_SSH1() - * @var Array - * @access private - */ - var $protocol_flags = array(); - - /** - * Protocol Flag Log - * - * @see Net_SSH1::getLog() - * @var Array - * @access private - */ - var $protocol_flag_log = array(); - - /** - * Message Log - * - * @see Net_SSH1::getLog() - * @var Array - * @access private - */ - var $message_log = array(); - - /** - * Real-time log file pointer - * - * @see Net_SSH1::_append_log() - * @var Resource - * @access private - */ - var $realtime_log_file; - - /** - * Real-time log file size - * - * @see Net_SSH1::_append_log() - * @var Integer - * @access private - */ - var $realtime_log_size; - - /** - * Real-time log file wrap boolean - * - * @see Net_SSH1::_append_log() - * @var Boolean - * @access private - */ - var $realtime_log_wrap; - - /** - * Interactive Buffer - * - * @see Net_SSH1::read() - * @var Array - * @access private - */ - var $interactiveBuffer = ''; - - /** - * Timeout - * - * @see Net_SSH1::setTimeout() - * @access private - */ - var $timeout; - - /** - * Current Timeout - * - * @see Net_SSH1::_get_channel_packet() - * @access private - */ - var $curTimeout; - - /** - * Log Boundary - * - * @see Net_SSH1::_format_log - * @access private - */ - var $log_boundary = ':'; - - /** - * Log Long Width - * - * @see Net_SSH1::_format_log - * @access private - */ - var $log_long_width = 65; - - /** - * Log Short Width - * - * @see Net_SSH1::_format_log - * @access private - */ - var $log_short_width = 16; - - /** - * Hostname - * - * @see Net_SSH1::Net_SSH1() - * @see Net_SSH1::_connect() - * @var String - * @access private - */ - var $host; - - /** - * Port Number - * - * @see Net_SSH1::Net_SSH1() - * @see Net_SSH1::_connect() - * @var Integer - * @access private - */ - var $port; - - /** - * Timeout for initial connection - * - * Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like - * exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor, - * however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be - * 10 seconds. It is used by fsockopen() in that function. - * - * @see Net_SSH1::Net_SSH1() - * @see Net_SSH1::_connect() - * @var Integer - * @access private - */ - var $connectionTimeout; - - /** - * Default cipher - * - * @see Net_SSH1::Net_SSH1() - * @see Net_SSH1::_connect() - * @var Integer - * @access private - */ - var $cipher; - - /** - * Default Constructor. - * - * Connects to an SSHv1 server - * - * @param String $host - * @param optional Integer $port - * @param optional Integer $timeout - * @param optional Integer $cipher - * @return Net_SSH1 - * @access public - */ - function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES) - { - if (!class_exists('Math_BigInteger')) { - include_once 'Math/BigInteger.php'; - } - - // Include Crypt_Random - // the class_exists() will only be called if the crypt_random_string function hasn't been defined and - // will trigger a call to __autoload() if you're wanting to auto-load classes - // call function_exists() a second time to stop the include_once from being called outside - // of the auto loader - if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) { - include_once 'Crypt/Random.php'; - } - - $this->protocol_flags = array( - 1 => 'NET_SSH1_MSG_DISCONNECT', - 2 => 'NET_SSH1_SMSG_PUBLIC_KEY', - 3 => 'NET_SSH1_CMSG_SESSION_KEY', - 4 => 'NET_SSH1_CMSG_USER', - 9 => 'NET_SSH1_CMSG_AUTH_PASSWORD', - 10 => 'NET_SSH1_CMSG_REQUEST_PTY', - 12 => 'NET_SSH1_CMSG_EXEC_SHELL', - 13 => 'NET_SSH1_CMSG_EXEC_CMD', - 14 => 'NET_SSH1_SMSG_SUCCESS', - 15 => 'NET_SSH1_SMSG_FAILURE', - 16 => 'NET_SSH1_CMSG_STDIN_DATA', - 17 => 'NET_SSH1_SMSG_STDOUT_DATA', - 18 => 'NET_SSH1_SMSG_STDERR_DATA', - 19 => 'NET_SSH1_CMSG_EOF', - 20 => 'NET_SSH1_SMSG_EXITSTATUS', - 33 => 'NET_SSH1_CMSG_EXIT_CONFIRMATION' - ); - - $this->_define_array($this->protocol_flags); - - $this->host = $host; - $this->port = $port; - $this->connectionTimeout = $timeout; - $this->cipher = $cipher; - } - - /** - * Connect to an SSHv1 server - * - * @return Boolean - * @access private - */ - function _connect() - { - $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout); - if (!$this->fsock) { - user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr")); - return false; - } - - $this->server_identification = $init_line = fgets($this->fsock, 255); - - if (defined('NET_SSH1_LOGGING')) { - $this->_append_log('<-', $this->server_identification); - $this->_append_log('->', $this->identifier . "\r\n"); - } - - if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) { - user_error('Can only connect to SSH servers'); - return false; - } - if ($parts[1][0] != 1) { - user_error("Cannot connect to SSH $parts[1] servers"); - return false; - } - - fputs($this->fsock, $this->identifier."\r\n"); - - $response = $this->_get_binary_packet(); - if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) { - user_error('Expected SSH_SMSG_PUBLIC_KEY'); - return false; - } - - $anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8); - - $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4); - - $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); - $server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); - $this->server_key_public_exponent = $server_key_public_exponent; - - $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); - $server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); - $this->server_key_public_modulus = $server_key_public_modulus; - - $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4); - - $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); - $host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); - $this->host_key_public_exponent = $host_key_public_exponent; - - $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); - $host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); - $this->host_key_public_modulus = $host_key_public_modulus; - - $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4); - - // get a list of the supported ciphers - extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4))); - foreach ($this->supported_ciphers as $mask=>$name) { - if (($supported_ciphers_mask & (1 << $mask)) == 0) { - unset($this->supported_ciphers[$mask]); - } - } - - // get a list of the supported authentications - extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4))); - foreach ($this->supported_authentications as $mask=>$name) { - if (($supported_authentications_mask & (1 << $mask)) == 0) { - unset($this->supported_authentications[$mask]); - } - } - - $session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie)); - - $session_key = crypt_random_string(32); - $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0)); - - if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) { - $double_encrypted_session_key = $this->_rsa_crypt( - $double_encrypted_session_key, - array( - $server_key_public_exponent, - $server_key_public_modulus - ) - ); - $double_encrypted_session_key = $this->_rsa_crypt( - $double_encrypted_session_key, - array( - $host_key_public_exponent, - $host_key_public_modulus - ) - ); - } else { - $double_encrypted_session_key = $this->_rsa_crypt( - $double_encrypted_session_key, - array( - $host_key_public_exponent, - $host_key_public_modulus - ) - ); - $double_encrypted_session_key = $this->_rsa_crypt( - $double_encrypted_session_key, - array( - $server_key_public_exponent, - $server_key_public_modulus - ) - ); - } - - $cipher = isset($this->supported_ciphers[$this->cipher]) ? $this->cipher : NET_SSH1_CIPHER_3DES; - $data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_SESSION_KEY'); - return false; - } - - switch ($cipher) { - //case NET_SSH1_CIPHER_NONE: - // $this->crypto = new Crypt_Null(); - // break; - case NET_SSH1_CIPHER_DES: - if (!class_exists('Crypt_DES')) { - include_once 'Crypt/DES.php'; - } - $this->crypto = new Crypt_DES(); - $this->crypto->disablePadding(); - $this->crypto->enableContinuousBuffer(); - $this->crypto->setKey(substr($session_key, 0, 8)); - break; - case NET_SSH1_CIPHER_3DES: - if (!class_exists('Crypt_TripleDES')) { - include_once 'Crypt/TripleDES.php'; - } - $this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC); - $this->crypto->disablePadding(); - $this->crypto->enableContinuousBuffer(); - $this->crypto->setKey(substr($session_key, 0, 24)); - break; - //case NET_SSH1_CIPHER_RC4: - // if (!class_exists('Crypt_RC4')) { - // include_once 'Crypt/RC4.php'; - // } - // $this->crypto = new Crypt_RC4(); - // $this->crypto->enableContinuousBuffer(); - // $this->crypto->setKey(substr($session_key, 0, 16)); - // break; - } - - $response = $this->_get_binary_packet(); - - if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) { - user_error('Expected SSH_SMSG_SUCCESS'); - return false; - } - - $this->bitmap = NET_SSH1_MASK_CONNECTED; - - return true; - } - - /** - * Login - * - * @param String $username - * @param optional String $password - * @return Boolean - * @access public - */ - function login($username, $password = '') - { - if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) { - $this->bitmap |= NET_SSH1_MASK_CONSTRUCTOR; - if (!$this->_connect()) { - return false; - } - } - - if (!($this->bitmap & NET_SSH1_MASK_CONNECTED)) { - return false; - } - - $data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_USER'); - return false; - } - - $response = $this->_get_binary_packet(); - - if ($response === true) { - return false; - } - if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) { - $this->bitmap |= NET_SSH1_MASK_LOGIN; - return true; - } else if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) { - user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE'); - return false; - } - - $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_AUTH_PASSWORD'); - return false; - } - - // remove the username and password from the last logged packet - if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) { - $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen('password'), 'password'); - $this->message_log[count($this->message_log) - 1] = $data; - } - - $response = $this->_get_binary_packet(); - - if ($response === true) { - return false; - } - if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) { - $this->bitmap |= NET_SSH1_MASK_LOGIN; - return true; - } else if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) { - return false; - } else { - user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE'); - return false; - } - } - - /** - * Set Timeout - * - * $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely. setTimeout() makes it so it'll timeout. - * Setting $timeout to false or 0 will mean there is no timeout. - * - * @param Mixed $timeout - */ - function setTimeout($timeout) - { - $this->timeout = $this->curTimeout = $timeout; - } - - /** - * Executes a command on a non-interactive shell, returns the output, and quits. - * - * An SSH1 server will close the connection after a command has been executed on a non-interactive shell. SSH2 - * servers don't, however, this isn't an SSH2 client. The way this works, on the server, is by initiating a - * shell with the -s option, as discussed in the following links: - * - * {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html} - * {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html} - * - * To execute further commands, a new Net_SSH1 object will need to be created. - * - * Returns false on failure and the output, otherwise. - * - * @see Net_SSH1::interactiveRead() - * @see Net_SSH1::interactiveWrite() - * @param String $cmd - * @return mixed - * @access public - */ - function exec($cmd, $block = true) - { - if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) { - user_error('Operation disallowed prior to login()'); - return false; - } - - $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_EXEC_CMD'); - return false; - } - - if (!$block) { - return true; - } - - $output = ''; - $response = $this->_get_binary_packet(); - - if ($response !== false) { - do { - $output.= substr($response[NET_SSH1_RESPONSE_DATA], 4); - $response = $this->_get_binary_packet(); - } while (is_array($response) && $response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS); - } - - $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION); - - // i don't think it's really all that important if this packet gets sent or not. - $this->_send_binary_packet($data); - - fclose($this->fsock); - - // reset the execution bitmap - a new Net_SSH1 object needs to be created. - $this->bitmap = 0; - - return $output; - } - - /** - * Creates an interactive shell - * - * @see Net_SSH1::interactiveRead() - * @see Net_SSH1::interactiveWrite() - * @return Boolean - * @access private - */ - function _initShell() - { - // connect using the sample parameters in protocol-1.5.txt. - // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text - // terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell. - $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_REQUEST_PTY'); - return false; - } - - $response = $this->_get_binary_packet(); - - if ($response === true) { - return false; - } - if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) { - user_error('Expected SSH_SMSG_SUCCESS'); - return false; - } - - $data = pack('C', NET_SSH1_CMSG_EXEC_SHELL); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_EXEC_SHELL'); - return false; - } - - $this->bitmap |= NET_SSH1_MASK_SHELL; - - //stream_set_blocking($this->fsock, 0); - - return true; - } - - /** - * Inputs a command into an interactive shell. - * - * @see Net_SSH1::interactiveWrite() - * @param String $cmd - * @return Boolean - * @access public - */ - function write($cmd) - { - return $this->interactiveWrite($cmd); - } - - /** - * Returns the output of an interactive shell when there's a match for $expect - * - * $expect can take the form of a string literal or, if $mode == NET_SSH1_READ_REGEX, - * a regular expression. - * - * @see Net_SSH1::write() - * @param String $expect - * @param Integer $mode - * @return Boolean - * @access public - */ - function read($expect, $mode = NET_SSH1_READ_SIMPLE) - { - if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) { - user_error('Operation disallowed prior to login()'); - return false; - } - - if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) { - user_error('Unable to initiate an interactive shell session'); - return false; - } - - $match = $expect; - while (true) { - if ($mode == NET_SSH1_READ_REGEX) { - preg_match($expect, $this->interactiveBuffer, $matches); - $match = isset($matches[0]) ? $matches[0] : ''; - } - $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false; - if ($pos !== false) { - return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match)); - } - $response = $this->_get_binary_packet(); - - if ($response === true) { - return $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer)); - } - $this->interactiveBuffer.= substr($response[NET_SSH1_RESPONSE_DATA], 4); - } - } - - /** - * Inputs a command into an interactive shell. - * - * @see Net_SSH1::interactiveRead() - * @param String $cmd - * @return Boolean - * @access public - */ - function interactiveWrite($cmd) - { - if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) { - user_error('Operation disallowed prior to login()'); - return false; - } - - if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) { - user_error('Unable to initiate an interactive shell session'); - return false; - } - - $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_STDIN'); - return false; - } - - return true; - } - - /** - * Returns the output of an interactive shell when no more output is available. - * - * Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see stuff like - * "^[[00m", you're seeing ANSI escape codes. According to - * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT - * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user, - * there's not going to be much recourse. - * - * @see Net_SSH1::interactiveRead() - * @return String - * @access public - */ - function interactiveRead() - { - if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) { - user_error('Operation disallowed prior to login()'); - return false; - } - - if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) { - user_error('Unable to initiate an interactive shell session'); - return false; - } - - $read = array($this->fsock); - $write = $except = null; - if (stream_select($read, $write, $except, 0)) { - $response = $this->_get_binary_packet(); - return substr($response[NET_SSH1_RESPONSE_DATA], 4); - } else { - return ''; - } - } - - /** - * Disconnect - * - * @access public - */ - function disconnect() - { - $this->_disconnect(); - } - - /** - * Destructor. - * - * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call - * disconnect(). - * - * @access public - */ - function __destruct() - { - $this->_disconnect(); - } - - /** - * Disconnect - * - * @param String $msg - * @access private - */ - function _disconnect($msg = 'Client Quit') - { - if ($this->bitmap) { - $data = pack('C', NET_SSH1_CMSG_EOF); - $this->_send_binary_packet($data); - /* - $response = $this->_get_binary_packet(); - if ($response === true) { - $response = array(NET_SSH1_RESPONSE_TYPE => -1); - } - switch ($response[NET_SSH1_RESPONSE_TYPE]) { - case NET_SSH1_SMSG_EXITSTATUS: - $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION); - break; - default: - $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg); - } - */ - $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg); - - $this->_send_binary_packet($data); - fclose($this->fsock); - $this->bitmap = 0; - } - } - - /** - * Gets Binary Packets - * - * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info. - * - * Also, this function could be improved upon by adding detection for the following exploit: - * http://www.securiteam.com/securitynews/5LP042K3FY.html - * - * @see Net_SSH1::_send_binary_packet() - * @return Array - * @access private - */ - function _get_binary_packet() - { - if (feof($this->fsock)) { - //user_error('connection closed prematurely'); - return false; - } - - if ($this->curTimeout) { - $read = array($this->fsock); - $write = $except = null; - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $sec = floor($this->curTimeout); - $usec = 1000000 * ($this->curTimeout - $sec); - // on windows this returns a "Warning: Invalid CRT parameters detected" error - if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { - //$this->_disconnect('Timeout'); - return true; - } - $elapsed = strtok(microtime(), ' ') + strtok('') - $start; - $this->curTimeout-= $elapsed; - } - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $temp = unpack('Nlength', fread($this->fsock, 4)); - - $padding_length = 8 - ($temp['length'] & 7); - $length = $temp['length'] + $padding_length; - $raw = ''; - - while ($length > 0) { - $temp = fread($this->fsock, $length); - $raw.= $temp; - $length-= strlen($temp); - } - $stop = strtok(microtime(), ' ') + strtok(''); - - if (strlen($raw) && $this->crypto !== false) { - $raw = $this->crypto->decrypt($raw); - } - - $padding = substr($raw, 0, $padding_length); - $type = $raw[$padding_length]; - $data = substr($raw, $padding_length + 1, -4); - - $temp = unpack('Ncrc', substr($raw, -4)); - - //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) { - // user_error('Bad CRC in packet from server'); - // return false; - //} - - $type = ord($type); - - if (defined('NET_SSH1_LOGGING')) { - $temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN'; - $temp = '<- ' . $temp . - ' (' . round($stop - $start, 4) . 's)'; - $this->_append_log($temp, $data); - } - - return array( - NET_SSH1_RESPONSE_TYPE => $type, - NET_SSH1_RESPONSE_DATA => $data - ); - } - - /** - * Sends Binary Packets - * - * Returns true on success, false on failure. - * - * @see Net_SSH1::_get_binary_packet() - * @param String $data - * @return Boolean - * @access private - */ - function _send_binary_packet($data) - { - if (feof($this->fsock)) { - //user_error('connection closed prematurely'); - return false; - } - - $length = strlen($data) + 4; - - $padding = crypt_random_string(8 - ($length & 7)); - - $orig = $data; - $data = $padding . $data; - $data.= pack('N', $this->_crc($data)); - - if ($this->crypto !== false) { - $data = $this->crypto->encrypt($data); - } - - $packet = pack('Na*', $length, $data); - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $result = strlen($packet) == fputs($this->fsock, $packet); - $stop = strtok(microtime(), ' ') + strtok(''); - - if (defined('NET_SSH1_LOGGING')) { - $temp = isset($this->protocol_flags[ord($orig[0])]) ? $this->protocol_flags[ord($orig[0])] : 'UNKNOWN'; - $temp = '-> ' . $temp . - ' (' . round($stop - $start, 4) . 's)'; - $this->_append_log($temp, $orig); - } - - return $result; - } - - /** - * Cyclic Redundancy Check (CRC) - * - * PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so - * we've reimplemented it. A more detailed discussion of the differences can be found after - * $crc_lookup_table's initialization. - * - * @see Net_SSH1::_get_binary_packet() - * @see Net_SSH1::_send_binary_packet() - * @param String $data - * @return Integer - * @access private - */ - function _crc($data) - { - static $crc_lookup_table = array( - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, - 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, - 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, - 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, - 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, - 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, - 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, - 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, - 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, - 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, - 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, - 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, - 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, - 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, - 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, - 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - ); - - // For this function to yield the same output as PHP's crc32 function, $crc would have to be - // set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is. - $crc = 0x00000000; - $length = strlen($data); - - for ($i=0;$i<$length;$i++) { - // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all - // be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example, - // yields 0xFF800000 - not 0x00800000. The following link elaborates: - // http://www.php.net/manual/en/language.operators.bitwise.php#57281 - $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])]; - } - - // In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with - // 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would. - return $crc; - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; - } - - /** - * RSA Encrypt - * - * Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e - * should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that - * calls this call modexp, instead, but I think this makes things clearer, maybe... - * - * @see Net_SSH1::Net_SSH1() - * @param Math_BigInteger $m - * @param Array $key - * @return Math_BigInteger - * @access private - */ - function _rsa_crypt($m, $key) - { - /* - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - - $rsa = new Crypt_RSA(); - $rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW); - $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); - return $rsa->encrypt($m); - */ - - // To quote from protocol-1.5.txt: - // The most significant byte (which is only partial as the value must be - // less than the public modulus, which is never a power of two) is zero. - // - // The next byte contains the value 2 (which stands for public-key - // encrypted data in the PKCS standard [PKCS#1]). Then, there are non- - // zero random bytes to fill any unused space, a zero byte, and the data - // to be encrypted in the least significant bytes, the last byte of the - // data in the least significant byte. - - // Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation", - // under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL: - // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf - $modulus = $key[1]->toBytes(); - $length = strlen($modulus) - strlen($m) - 3; - $random = ''; - while (strlen($random) != $length) { - $block = crypt_random_string($length - strlen($random)); - $block = str_replace("\x00", '', $block); - $random.= $block; - } - $temp = chr(0) . chr(2) . $random . chr(0) . $m; - - $m = new Math_BigInteger($temp, 256); - $m = $m->modPow($key[0], $key[1]); - - return $m->toBytes(); - } - - /** - * Define Array - * - * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of - * named constants from it, using the value as the name of the constant and the index as the value of the constant. - * If any of the constants that would be defined already exists, none of the constants will be defined. - * - * @param Array $array - * @access private - */ - function _define_array() - { - $args = func_get_args(); - foreach ($args as $arg) { - foreach ($arg as $key=>$value) { - if (!defined($value)) { - define($value, $key); - } else { - break 2; - } - } - } - } - - /** - * Returns a log of the packets that have been sent and received. - * - * Returns a string if NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX, an array if NET_SSH1_LOGGING == NET_SSH1_LOG_SIMPLE and false if !defined('NET_SSH1_LOGGING') - * - * @access public - * @return String or Array - */ - function getLog() - { - if (!defined('NET_SSH1_LOGGING')) { - return false; - } - - switch (NET_SSH1_LOGGING) { - case NET_SSH1_LOG_SIMPLE: - return $this->message_number_log; - break; - case NET_SSH1_LOG_COMPLEX: - return $this->_format_log($this->message_log, $this->protocol_flags_log); - break; - default: - return false; - } - } - - /** - * Formats a log for printing - * - * @param Array $message_log - * @param Array $message_number_log - * @access private - * @return String - */ - function _format_log($message_log, $message_number_log) - { - $output = ''; - for ($i = 0; $i < count($message_log); $i++) { - $output.= $message_number_log[$i] . "\r\n"; - $current_log = $message_log[$i]; - $j = 0; - do { - if (strlen($current_log)) { - $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 '; - } - $fragment = $this->_string_shift($current_log, $this->log_short_width); - $hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary)); - // replace non ASCII printable characters with dots - // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters - // also replace < with a . since < messes up the output on web browsers - $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment); - $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n"; - $j++; - } while (strlen($current_log)); - $output.= "\r\n"; - } - - return $output; - } - - /** - * Helper function for _format_log - * - * For use with preg_replace_callback() - * - * @param Array $matches - * @access private - * @return String - */ - function _format_log_helper($matches) - { - return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT); - } - - /** - * Return the server key public exponent - * - * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead, - * the raw bytes. This behavior is similar to PHP's md5() function. - * - * @param optional Boolean $raw_output - * @return String - * @access public - */ - function getServerKeyPublicExponent($raw_output = false) - { - return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString(); - } - - /** - * Return the server key public modulus - * - * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead, - * the raw bytes. This behavior is similar to PHP's md5() function. - * - * @param optional Boolean $raw_output - * @return String - * @access public - */ - function getServerKeyPublicModulus($raw_output = false) - { - return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString(); - } - - /** - * Return the host key public exponent - * - * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead, - * the raw bytes. This behavior is similar to PHP's md5() function. - * - * @param optional Boolean $raw_output - * @return String - * @access public - */ - function getHostKeyPublicExponent($raw_output = false) - { - return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString(); - } - - /** - * Return the host key public modulus - * - * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead, - * the raw bytes. This behavior is similar to PHP's md5() function. - * - * @param optional Boolean $raw_output - * @return String - * @access public - */ - function getHostKeyPublicModulus($raw_output = false) - { - return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString(); - } - - /** - * Return a list of ciphers supported by SSH1 server. - * - * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output - * is set to true, returns, instead, an array of constants. ie. instead of array('Triple-DES in CBC mode'), you'll - * get array(NET_SSH1_CIPHER_3DES). - * - * @param optional Boolean $raw_output - * @return Array - * @access public - */ - function getSupportedCiphers($raw_output = false) - { - return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers); - } - - /** - * Return a list of authentications supported by SSH1 server. - * - * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output - * is set to true, returns, instead, an array of constants. ie. instead of array('password authentication'), you'll - * get array(NET_SSH1_AUTH_PASSWORD). - * - * @param optional Boolean $raw_output - * @return Array - * @access public - */ - function getSupportedAuthentications($raw_output = false) - { - return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications); - } - - /** - * Return the server identification. - * - * @return String - * @access public - */ - function getServerIdentification() - { - return rtrim($this->server_identification); - } - - /** - * Logs data packets - * - * Makes sure that only the last 1MB worth of packets will be logged - * - * @param String $data - * @access private - */ - function _append_log($protocol_flags, $message) - { - switch (NET_SSH1_LOGGING) { - // useful for benchmarks - case NET_SSH1_LOG_SIMPLE: - $this->protocol_flags_log[] = $protocol_flags; - break; - // the most useful log for SSH1 - case NET_SSH1_LOG_COMPLEX: - $this->protocol_flags_log[] = $protocol_flags; - $this->_string_shift($message); - $this->log_size+= strlen($message); - $this->message_log[] = $message; - while ($this->log_size > NET_SSH1_LOG_MAX_SIZE) { - $this->log_size-= strlen(array_shift($this->message_log)); - array_shift($this->protocol_flags_log); - } - break; - // dump the output out realtime; packets may be interspersed with non packets, - // passwords won't be filtered out and select other packets may not be correctly - // identified - case NET_SSH1_LOG_REALTIME: - echo "
\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n
\r\n"; - @flush(); - @ob_flush(); - break; - // basically the same thing as NET_SSH1_LOG_REALTIME with the caveat that NET_SSH1_LOG_REALTIME_FILE - // needs to be defined and that the resultant log file will be capped out at NET_SSH1_LOG_MAX_SIZE. - // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily - // at the beginning of the file - case NET_SSH1_LOG_REALTIME_FILE: - if (!isset($this->realtime_log_file)) { - // PHP doesn't seem to like using constants in fopen() - $filename = NET_SSH1_LOG_REALTIME_FILE; - $fp = fopen($filename, 'w'); - $this->realtime_log_file = $fp; - } - if (!is_resource($this->realtime_log_file)) { - break; - } - $entry = $this->_format_log(array($message), array($protocol_flags)); - if ($this->realtime_log_wrap) { - $temp = "<<< START >>>\r\n"; - $entry.= $temp; - fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp)); - } - $this->realtime_log_size+= strlen($entry); - if ($this->realtime_log_size > NET_SSH1_LOG_MAX_SIZE) { - fseek($this->realtime_log_file, 0); - $this->realtime_log_size = strlen($entry); - $this->realtime_log_wrap = true; - } - fputs($this->realtime_log_file, $entry); - } - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SSH2.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SSH2.php deleted file mode 100644 index d6134562..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SSH2.php +++ /dev/null @@ -1,3878 +0,0 @@ - - * login('username', 'password')) { - * exit('Login Failed'); - * } - * - * echo $ssh->exec('pwd'); - * echo $ssh->exec('ls -la'); - * ?> - * - * - * - * setPassword('whatever'); - * $key->loadKey(file_get_contents('privatekey')); - * - * $ssh = new Net_SSH2('www.domain.tld'); - * if (!$ssh->login('username', $key)) { - * exit('Login Failed'); - * } - * - * echo $ssh->read('username@username:~$'); - * $ssh->write("ls -la\n"); - * echo $ssh->read('username@username:~$'); - * ?> - * - * - * 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. - * - * @category Net - * @package Net_SSH2 - * @author Jim Wigginton - * @copyright 2007 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/**#@+ - * Execution Bitmap Masks - * - * @see Net_SSH2::bitmap - * @access private - */ -define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001); -define('NET_SSH2_MASK_CONNECTED', 0x00000002); -define('NET_SSH2_MASK_LOGIN_REQ', 0x00000004); -define('NET_SSH2_MASK_LOGIN', 0x00000008); -define('NET_SSH2_MASK_SHELL', 0x00000010); -define('NET_SSH2_MASK_WINDOW_ADJUST', 0x00000020); -/**#@-*/ - -/**#@+ - * Channel constants - * - * RFC4254 refers not to client and server channels but rather to sender and recipient channels. we don't refer - * to them in that way because RFC4254 toggles the meaning. the client sends a SSH_MSG_CHANNEL_OPEN message with - * a sender channel and the server sends a SSH_MSG_CHANNEL_OPEN_CONFIRMATION in response, with a sender and a - * recepient channel. at first glance, you might conclude that SSH_MSG_CHANNEL_OPEN_CONFIRMATION's sender channel - * would be the same thing as SSH_MSG_CHANNEL_OPEN's sender channel, but it's not, per this snipet: - * The 'recipient channel' is the channel number given in the original - * open request, and 'sender channel' is the channel number allocated by - * the other side. - * - * @see Net_SSH2::_send_channel_packet() - * @see Net_SSH2::_get_channel_packet() - * @access private - */ -define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100 -define('NET_SSH2_CHANNEL_SHELL', 1); -define('NET_SSH2_CHANNEL_SUBSYSTEM', 2); -/**#@-*/ - -/**#@+ - * @access public - * @see Net_SSH2::getLog() - */ -/** - * Returns the message numbers - */ -define('NET_SSH2_LOG_SIMPLE', 1); -/** - * Returns the message content - */ -define('NET_SSH2_LOG_COMPLEX', 2); -/** - * Outputs the content real-time - */ -define('NET_SSH2_LOG_REALTIME', 3); -/** - * Dumps the content real-time to a file - */ -define('NET_SSH2_LOG_REALTIME_FILE', 4); -/**#@-*/ - -/**#@+ - * @access public - * @see Net_SSH2::read() - */ -/** - * Returns when a string matching $expect exactly is found - */ -define('NET_SSH2_READ_SIMPLE', 1); -/** - * Returns when a string matching the regular expression $expect is found - */ -define('NET_SSH2_READ_REGEX', 2); -/** - * Make sure that the log never gets larger than this - */ -define('NET_SSH2_LOG_MAX_SIZE', 1024 * 1024); -/**#@-*/ - -/** - * Pure-PHP implementation of SSHv2. - * - * @package Net_SSH2 - * @author Jim Wigginton - * @access public - */ -class Net_SSH2 -{ - /** - * The SSH identifier - * - * @var String - * @access private - */ - var $identifier; - - /** - * The Socket Object - * - * @var Object - * @access private - */ - var $fsock; - - /** - * Execution Bitmap - * - * The bits that are set represent functions that have been called already. This is used to determine - * if a requisite function has been successfully executed. If not, an error should be thrown. - * - * @var Integer - * @access private - */ - var $bitmap = 0; - - /** - * Error information - * - * @see Net_SSH2::getErrors() - * @see Net_SSH2::getLastError() - * @var String - * @access private - */ - var $errors = array(); - - /** - * Server Identifier - * - * @see Net_SSH2::getServerIdentification() - * @var mixed false or Array - * @access private - */ - var $server_identifier = false; - - /** - * Key Exchange Algorithms - * - * @see Net_SSH2::getKexAlgorithims() - * @var mixed false or Array - * @access private - */ - var $kex_algorithms = false; - - /** - * Server Host Key Algorithms - * - * @see Net_SSH2::getServerHostKeyAlgorithms() - * @var mixed false or Array - * @access private - */ - var $server_host_key_algorithms = false; - - /** - * Encryption Algorithms: Client to Server - * - * @see Net_SSH2::getEncryptionAlgorithmsClient2Server() - * @var mixed false or Array - * @access private - */ - var $encryption_algorithms_client_to_server = false; - - /** - * Encryption Algorithms: Server to Client - * - * @see Net_SSH2::getEncryptionAlgorithmsServer2Client() - * @var mixed false or Array - * @access private - */ - var $encryption_algorithms_server_to_client = false; - - /** - * MAC Algorithms: Client to Server - * - * @see Net_SSH2::getMACAlgorithmsClient2Server() - * @var mixed false or Array - * @access private - */ - var $mac_algorithms_client_to_server = false; - - /** - * MAC Algorithms: Server to Client - * - * @see Net_SSH2::getMACAlgorithmsServer2Client() - * @var mixed false or Array - * @access private - */ - var $mac_algorithms_server_to_client = false; - - /** - * Compression Algorithms: Client to Server - * - * @see Net_SSH2::getCompressionAlgorithmsClient2Server() - * @var mixed false or Array - * @access private - */ - var $compression_algorithms_client_to_server = false; - - /** - * Compression Algorithms: Server to Client - * - * @see Net_SSH2::getCompressionAlgorithmsServer2Client() - * @var mixed false or Array - * @access private - */ - var $compression_algorithms_server_to_client = false; - - /** - * Languages: Server to Client - * - * @see Net_SSH2::getLanguagesServer2Client() - * @var mixed false or Array - * @access private - */ - var $languages_server_to_client = false; - - /** - * Languages: Client to Server - * - * @see Net_SSH2::getLanguagesClient2Server() - * @var mixed false or Array - * @access private - */ - var $languages_client_to_server = false; - - /** - * Block Size for Server to Client Encryption - * - * "Note that the length of the concatenation of 'packet_length', - * 'padding_length', 'payload', and 'random padding' MUST be a multiple - * of the cipher block size or 8, whichever is larger. This constraint - * MUST be enforced, even when using stream ciphers." - * - * -- http://tools.ietf.org/html/rfc4253#section-6 - * - * @see Net_SSH2::Net_SSH2() - * @see Net_SSH2::_send_binary_packet() - * @var Integer - * @access private - */ - var $encrypt_block_size = 8; - - /** - * Block Size for Client to Server Encryption - * - * @see Net_SSH2::Net_SSH2() - * @see Net_SSH2::_get_binary_packet() - * @var Integer - * @access private - */ - var $decrypt_block_size = 8; - - /** - * Server to Client Encryption Object - * - * @see Net_SSH2::_get_binary_packet() - * @var Object - * @access private - */ - var $decrypt = false; - - /** - * Client to Server Encryption Object - * - * @see Net_SSH2::_send_binary_packet() - * @var Object - * @access private - */ - var $encrypt = false; - - /** - * Client to Server HMAC Object - * - * @see Net_SSH2::_send_binary_packet() - * @var Object - * @access private - */ - var $hmac_create = false; - - /** - * Server to Client HMAC Object - * - * @see Net_SSH2::_get_binary_packet() - * @var Object - * @access private - */ - var $hmac_check = false; - - /** - * Size of server to client HMAC - * - * We need to know how big the HMAC will be for the server to client direction so that we know how many bytes to read. - * For the client to server side, the HMAC object will make the HMAC as long as it needs to be. All we need to do is - * append it. - * - * @see Net_SSH2::_get_binary_packet() - * @var Integer - * @access private - */ - var $hmac_size = false; - - /** - * Server Public Host Key - * - * @see Net_SSH2::getServerPublicHostKey() - * @var String - * @access private - */ - var $server_public_host_key; - - /** - * Session identifer - * - * "The exchange hash H from the first key exchange is additionally - * used as the session identifier, which is a unique identifier for - * this connection." - * - * -- http://tools.ietf.org/html/rfc4253#section-7.2 - * - * @see Net_SSH2::_key_exchange() - * @var String - * @access private - */ - var $session_id = false; - - /** - * Exchange hash - * - * The current exchange hash - * - * @see Net_SSH2::_key_exchange() - * @var String - * @access private - */ - var $exchange_hash = false; - - /** - * Message Numbers - * - * @see Net_SSH2::Net_SSH2() - * @var Array - * @access private - */ - var $message_numbers = array(); - - /** - * Disconnection Message 'reason codes' defined in RFC4253 - * - * @see Net_SSH2::Net_SSH2() - * @var Array - * @access private - */ - var $disconnect_reasons = array(); - - /** - * SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254 - * - * @see Net_SSH2::Net_SSH2() - * @var Array - * @access private - */ - var $channel_open_failure_reasons = array(); - - /** - * Terminal Modes - * - * @link http://tools.ietf.org/html/rfc4254#section-8 - * @see Net_SSH2::Net_SSH2() - * @var Array - * @access private - */ - var $terminal_modes = array(); - - /** - * SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes - * - * @link http://tools.ietf.org/html/rfc4254#section-5.2 - * @see Net_SSH2::Net_SSH2() - * @var Array - * @access private - */ - var $channel_extended_data_type_codes = array(); - - /** - * Send Sequence Number - * - * See 'Section 6.4. Data Integrity' of rfc4253 for more info. - * - * @see Net_SSH2::_send_binary_packet() - * @var Integer - * @access private - */ - var $send_seq_no = 0; - - /** - * Get Sequence Number - * - * See 'Section 6.4. Data Integrity' of rfc4253 for more info. - * - * @see Net_SSH2::_get_binary_packet() - * @var Integer - * @access private - */ - var $get_seq_no = 0; - - /** - * Server Channels - * - * Maps client channels to server channels - * - * @see Net_SSH2::_get_channel_packet() - * @see Net_SSH2::exec() - * @var Array - * @access private - */ - var $server_channels = array(); - - /** - * Channel Buffers - * - * If a client requests a packet from one channel but receives two packets from another those packets should - * be placed in a buffer - * - * @see Net_SSH2::_get_channel_packet() - * @see Net_SSH2::exec() - * @var Array - * @access private - */ - var $channel_buffers = array(); - - /** - * Channel Status - * - * Contains the type of the last sent message - * - * @see Net_SSH2::_get_channel_packet() - * @var Array - * @access private - */ - var $channel_status = array(); - - /** - * Packet Size - * - * Maximum packet size indexed by channel - * - * @see Net_SSH2::_send_channel_packet() - * @var Array - * @access private - */ - var $packet_size_client_to_server = array(); - - /** - * Message Number Log - * - * @see Net_SSH2::getLog() - * @var Array - * @access private - */ - var $message_number_log = array(); - - /** - * Message Log - * - * @see Net_SSH2::getLog() - * @var Array - * @access private - */ - var $message_log = array(); - - /** - * The Window Size - * - * Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 2GB) - * - * @var Integer - * @see Net_SSH2::_send_channel_packet() - * @see Net_SSH2::exec() - * @access private - */ - var $window_size = 0x7FFFFFFF; - - /** - * Window size, server to client - * - * Window size indexed by channel - * - * @see Net_SSH2::_send_channel_packet() - * @var Array - * @access private - */ - var $window_size_server_to_client = array(); - - /** - * Window size, client to server - * - * Window size indexed by channel - * - * @see Net_SSH2::_get_channel_packet() - * @var Array - * @access private - */ - var $window_size_client_to_server = array(); - - /** - * Server signature - * - * Verified against $this->session_id - * - * @see Net_SSH2::getServerPublicHostKey() - * @var String - * @access private - */ - var $signature = ''; - - /** - * Server signature format - * - * ssh-rsa or ssh-dss. - * - * @see Net_SSH2::getServerPublicHostKey() - * @var String - * @access private - */ - var $signature_format = ''; - - /** - * Interactive Buffer - * - * @see Net_SSH2::read() - * @var Array - * @access private - */ - var $interactiveBuffer = ''; - - /** - * Current log size - * - * Should never exceed NET_SSH2_LOG_MAX_SIZE - * - * @see Net_SSH2::_send_binary_packet() - * @see Net_SSH2::_get_binary_packet() - * @var Integer - * @access private - */ - var $log_size; - - /** - * Timeout - * - * @see Net_SSH2::setTimeout() - * @access private - */ - var $timeout; - - /** - * Current Timeout - * - * @see Net_SSH2::_get_channel_packet() - * @access private - */ - var $curTimeout; - - /** - * Real-time log file pointer - * - * @see Net_SSH2::_append_log() - * @var Resource - * @access private - */ - var $realtime_log_file; - - /** - * Real-time log file size - * - * @see Net_SSH2::_append_log() - * @var Integer - * @access private - */ - var $realtime_log_size; - - /** - * Has the signature been validated? - * - * @see Net_SSH2::getServerPublicHostKey() - * @var Boolean - * @access private - */ - var $signature_validated = false; - - /** - * Real-time log file wrap boolean - * - * @see Net_SSH2::_append_log() - * @access private - */ - var $realtime_log_wrap; - - /** - * Flag to suppress stderr from output - * - * @see Net_SSH2::enableQuietMode() - * @access private - */ - var $quiet_mode = false; - - /** - * Time of first network activity - * - * @var Integer - * @access private - */ - var $last_packet; - - /** - * Exit status returned from ssh if any - * - * @var Integer - * @access private - */ - var $exit_status; - - /** - * Flag to request a PTY when using exec() - * - * @var Boolean - * @see Net_SSH2::enablePTY() - * @access private - */ - var $request_pty = false; - - /** - * Flag set while exec() is running when using enablePTY() - * - * @var Boolean - * @access private - */ - var $in_request_pty_exec = false; - - /** - * Flag set after startSubsystem() is called - * - * @var Boolean - * @access private - */ - var $in_subsystem; - - /** - * Contents of stdError - * - * @var String - * @access private - */ - var $stdErrorLog; - - /** - * The Last Interactive Response - * - * @see Net_SSH2::_keyboard_interactive_process() - * @var String - * @access private - */ - var $last_interactive_response = ''; - - /** - * Keyboard Interactive Request / Responses - * - * @see Net_SSH2::_keyboard_interactive_process() - * @var Array - * @access private - */ - var $keyboard_requests_responses = array(); - - /** - * Banner Message - * - * Quoting from the RFC, "in some jurisdictions, sending a warning message before - * authentication may be relevant for getting legal protection." - * - * @see Net_SSH2::_filter() - * @see Net_SSH2::getBannerMessage() - * @var String - * @access private - */ - var $banner_message = ''; - - /** - * Did read() timeout or return normally? - * - * @see Net_SSH2::isTimeout() - * @var Boolean - * @access private - */ - var $is_timeout = false; - - /** - * Log Boundary - * - * @see Net_SSH2::_format_log() - * @var String - * @access private - */ - var $log_boundary = ':'; - - /** - * Log Long Width - * - * @see Net_SSH2::_format_log() - * @var Integer - * @access private - */ - var $log_long_width = 65; - - /** - * Log Short Width - * - * @see Net_SSH2::_format_log() - * @var Integer - * @access private - */ - var $log_short_width = 16; - - /** - * Hostname - * - * @see Net_SSH2::Net_SSH2() - * @see Net_SSH2::_connect() - * @var String - * @access private - */ - var $host; - - /** - * Port Number - * - * @see Net_SSH2::Net_SSH2() - * @see Net_SSH2::_connect() - * @var Integer - * @access private - */ - var $port; - - /** - * Timeout for initial connection - * - * Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like - * exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor, - * however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be - * 10 seconds. It is used by fsockopen() and the initial stream_select in that function. - * - * @see Net_SSH2::Net_SSH2() - * @see Net_SSH2::_connect() - * @var Integer - * @access private - */ - var $connectionTimeout; - - /** - * Number of columns for terminal window size - * - * @see Net_SSH2::getWindowColumns() - * @see Net_SSH2::setWindowColumns() - * @see Net_SSH2::setWindowSize() - * @var Integer - * @access private - */ - var $windowColumns = 80; - - /** - * Number of columns for terminal window size - * - * @see Net_SSH2::getWindowRows() - * @see Net_SSH2::setWindowRows() - * @see Net_SSH2::setWindowSize() - * @var Integer - * @access private - */ - var $windowRows = 24; - - /** - * Default Constructor. - * - * @param String $host - * @param optional Integer $port - * @param optional Integer $timeout - * @see Net_SSH2::login() - * @return Net_SSH2 - * @access public - */ - function Net_SSH2($host, $port = 22, $timeout = 10) - { - // Include Math_BigInteger - // Used to do Diffie-Hellman key exchange and DSA/RSA signature verification. - if (!class_exists('Math_BigInteger')) { - include_once 'Math/BigInteger.php'; - } - - if (!function_exists('crypt_random_string')) { - include_once 'Crypt/Random.php'; - } - - if (!class_exists('Crypt_Hash')) { - include_once 'Crypt/Hash.php'; - } - - $this->message_numbers = array( - 1 => 'NET_SSH2_MSG_DISCONNECT', - 2 => 'NET_SSH2_MSG_IGNORE', - 3 => 'NET_SSH2_MSG_UNIMPLEMENTED', - 4 => 'NET_SSH2_MSG_DEBUG', - 5 => 'NET_SSH2_MSG_SERVICE_REQUEST', - 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT', - 20 => 'NET_SSH2_MSG_KEXINIT', - 21 => 'NET_SSH2_MSG_NEWKEYS', - 30 => 'NET_SSH2_MSG_KEXDH_INIT', - 31 => 'NET_SSH2_MSG_KEXDH_REPLY', - 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST', - 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE', - 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS', - 53 => 'NET_SSH2_MSG_USERAUTH_BANNER', - - 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST', - 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS', - 82 => 'NET_SSH2_MSG_REQUEST_FAILURE', - 90 => 'NET_SSH2_MSG_CHANNEL_OPEN', - 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION', - 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE', - 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST', - 94 => 'NET_SSH2_MSG_CHANNEL_DATA', - 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA', - 96 => 'NET_SSH2_MSG_CHANNEL_EOF', - 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE', - 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST', - 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS', - 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE' - ); - $this->disconnect_reasons = array( - 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT', - 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR', - 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED', - 4 => 'NET_SSH2_DISCONNECT_RESERVED', - 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR', - 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR', - 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE', - 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED', - 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE', - 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST', - 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION', - 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS', - 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER', - 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE', - 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME' - ); - $this->channel_open_failure_reasons = array( - 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED' - ); - $this->terminal_modes = array( - 0 => 'NET_SSH2_TTY_OP_END' - ); - $this->channel_extended_data_type_codes = array( - 1 => 'NET_SSH2_EXTENDED_DATA_STDERR' - ); - - $this->_define_array( - $this->message_numbers, - $this->disconnect_reasons, - $this->channel_open_failure_reasons, - $this->terminal_modes, - $this->channel_extended_data_type_codes, - array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'), - array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'), - array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', - 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE') - ); - - $this->host = $host; - $this->port = $port; - $this->connectionTimeout = $timeout; - } - - /** - * Connect to an SSHv2 server - * - * @return Boolean - * @access private - */ - function _connect() - { - if ($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) { - return false; - } - - $this->bitmap |= NET_SSH2_MASK_CONSTRUCTOR; - - $timeout = $this->connectionTimeout; - $host = $this->host . ':' . $this->port; - - $this->last_packet = strtok(microtime(), ' ') + strtok(''); // == microtime(true) in PHP5 - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $timeout); - if (!$this->fsock) { - user_error(rtrim("Cannot connect to $host. Error $errno. $errstr")); - return false; - } - $elapsed = strtok(microtime(), ' ') + strtok('') - $start; - - $timeout-= $elapsed; - - if ($timeout <= 0) { - user_error("Cannot connect to $host. Timeout error"); - return false; - } - - $read = array($this->fsock); - $write = $except = null; - - $sec = floor($timeout); - $usec = 1000000 * ($timeout - $sec); - - // on windows this returns a "Warning: Invalid CRT parameters detected" error - // the !count() is done as a workaround for - if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { - user_error("Cannot connect to $host. Banner timeout"); - return false; - } - - /* According to the SSH2 specs, - - "The server MAY send other lines of data before sending the version - string. Each line SHOULD be terminated by a Carriage Return and Line - Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded - in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients - MUST be able to process such lines." */ - $temp = ''; - $extra = ''; - while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) { - if (substr($temp, -2) == "\r\n") { - $extra.= $temp; - $temp = ''; - } - $temp.= fgets($this->fsock, 255); - } - - if (feof($this->fsock)) { - user_error('Connection closed by server'); - return false; - } - - $this->identifier = $this->_generate_identifier(); - - if (defined('NET_SSH2_LOGGING')) { - $this->_append_log('<-', $extra . $temp); - $this->_append_log('->', $this->identifier . "\r\n"); - } - - $this->server_identifier = trim($temp, "\r\n"); - if (strlen($extra)) { - $this->errors[] = utf8_decode($extra); - } - - if ($matches[1] != '1.99' && $matches[1] != '2.0') { - user_error("Cannot connect to SSH $matches[1] servers"); - return false; - } - - fputs($this->fsock, $this->identifier . "\r\n"); - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - - if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) { - user_error('Expected SSH_MSG_KEXINIT'); - return false; - } - - if (!$this->_key_exchange($response)) { - return false; - } - - $this->bitmap|= NET_SSH2_MASK_CONNECTED; - - return true; - } - - /** - * Generates the SSH identifier - * - * You should overwrite this method in your own class if you want to use another identifier - * - * @access protected - * @return String - */ - function _generate_identifier() - { - $identifier = 'SSH-2.0-phpseclib_0.3'; - - $ext = array(); - if (extension_loaded('mcrypt')) { - $ext[] = 'mcrypt'; - } - - if (extension_loaded('gmp')) { - $ext[] = 'gmp'; - } elseif (extension_loaded('bcmath')) { - $ext[] = 'bcmath'; - } - - if (!empty($ext)) { - $identifier .= ' (' . implode(', ', $ext) . ')'; - } - - return $identifier; - } - - /** - * Key Exchange - * - * @param String $kexinit_payload_server - * @access private - */ - function _key_exchange($kexinit_payload_server) - { - static $kex_algorithms = array( - 'diffie-hellman-group1-sha1', // REQUIRED - 'diffie-hellman-group14-sha1' // REQUIRED - ); - - static $server_host_key_algorithms = array( - 'ssh-rsa', // RECOMMENDED sign Raw RSA Key - 'ssh-dss' // REQUIRED sign Raw DSS Key - ); - - static $encryption_algorithms = false; - if ($encryption_algorithms === false) { - $encryption_algorithms = array( - // from : - 'arcfour256', - 'arcfour128', - - //'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key - - // CTR modes from : - 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key - 'aes192-ctr', // RECOMMENDED AES with 192-bit key - 'aes256-ctr', // RECOMMENDED AES with 256-bit key - - 'twofish128-ctr', // OPTIONAL Twofish in SDCTR mode, with 128-bit key - 'twofish192-ctr', // OPTIONAL Twofish with 192-bit key - 'twofish256-ctr', // OPTIONAL Twofish with 256-bit key - - 'aes128-cbc', // RECOMMENDED AES with a 128-bit key - 'aes192-cbc', // OPTIONAL AES with a 192-bit key - 'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key - - 'twofish128-cbc', // OPTIONAL Twofish with a 128-bit key - 'twofish192-cbc', // OPTIONAL Twofish with a 192-bit key - 'twofish256-cbc', - 'twofish-cbc', // OPTIONAL alias for "twofish256-cbc" - // (this is being retained for historical reasons) - - 'blowfish-ctr', // OPTIONAL Blowfish in SDCTR mode - - 'blowfish-cbc', // OPTIONAL Blowfish in CBC mode - - '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode - - '3des-cbc', // REQUIRED three-key 3DES in CBC mode - //'none' // OPTIONAL no encryption; NOT RECOMMENDED - ); - - if (phpseclib_resolve_include_path('Crypt/RC4.php') === false) { - $encryption_algorithms = array_diff( - $encryption_algorithms, - array('arcfour256', 'arcfour128', 'arcfour') - ); - } - if (phpseclib_resolve_include_path('Crypt/Rijndael.php') === false) { - $encryption_algorithms = array_diff( - $encryption_algorithms, - array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc') - ); - } - if (phpseclib_resolve_include_path('Crypt/Twofish.php') === false) { - $encryption_algorithms = array_diff( - $encryption_algorithms, - array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc') - ); - } - if (phpseclib_resolve_include_path('Crypt/Blowfish.php') === false) { - $encryption_algorithms = array_diff( - $encryption_algorithms, - array('blowfish-ctr', 'blowfish-cbc') - ); - } - if (phpseclib_resolve_include_path('Crypt/TripleDES.php') === false) { - $encryption_algorithms = array_diff( - $encryption_algorithms, - array('3des-ctr', '3des-cbc') - ); - } - $encryption_algorithms = array_values($encryption_algorithms); - } - - $mac_algorithms = array( - // from : - 'hmac-sha2-256',// RECOMMENDED HMAC-SHA256 (digest length = key length = 32) - - 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20) - 'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20) - 'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16) - 'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16) - //'none' // OPTIONAL no MAC; NOT RECOMMENDED - ); - - static $compression_algorithms = array( - 'none' // REQUIRED no compression - //'zlib' // OPTIONAL ZLIB (LZ77) compression - ); - - // some SSH servers have buggy implementations of some of the above algorithms - switch ($this->server_identifier) { - case 'SSH-2.0-SSHD': - $mac_algorithms = array_values(array_diff( - $mac_algorithms, - array('hmac-sha1-96', 'hmac-md5-96') - )); - } - - static $str_kex_algorithms, $str_server_host_key_algorithms, - $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client, - $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server; - - if (empty($str_kex_algorithms)) { - $str_kex_algorithms = implode(',', $kex_algorithms); - $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms); - $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms); - $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms); - $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms); - } - - $client_cookie = crypt_random_string(16); - - $response = $kexinit_payload_server; - $this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT) - $server_cookie = $this->_string_shift($response, 16); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); - - extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1))); - $first_kex_packet_follows = $first_kex_packet_follows != 0; - - // the sending of SSH2_MSG_KEXINIT could go in one of two places. this is the second place. - $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', - NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms, - strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server), - $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client, - strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client), - $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server, - strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '', - 0, 0 - ); - - if (!$this->_send_binary_packet($kexinit_payload_client)) { - return false; - } - // here ends the second place. - - // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange - for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++); - if ($i == count($encryption_algorithms)) { - user_error('No compatible server to client encryption algorithms found'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the - // diffie-hellman key exchange as fast as possible - $decrypt = $encryption_algorithms[$i]; - switch ($decrypt) { - case '3des-cbc': - case '3des-ctr': - $decryptKeyLength = 24; // eg. 192 / 8 - break; - case 'aes256-cbc': - case 'aes256-ctr': - case 'twofish-cbc': - case 'twofish256-cbc': - case 'twofish256-ctr': - $decryptKeyLength = 32; // eg. 256 / 8 - break; - case 'aes192-cbc': - case 'aes192-ctr': - case 'twofish192-cbc': - case 'twofish192-ctr': - $decryptKeyLength = 24; // eg. 192 / 8 - break; - case 'aes128-cbc': - case 'aes128-ctr': - case 'twofish128-cbc': - case 'twofish128-ctr': - case 'blowfish-cbc': - case 'blowfish-ctr': - $decryptKeyLength = 16; // eg. 128 / 8 - break; - case 'arcfour': - case 'arcfour128': - $decryptKeyLength = 16; // eg. 128 / 8 - break; - case 'arcfour256': - $decryptKeyLength = 32; // eg. 128 / 8 - break; - case 'none'; - $decryptKeyLength = 0; - } - - for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++); - if ($i == count($encryption_algorithms)) { - user_error('No compatible client to server encryption algorithms found'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $encrypt = $encryption_algorithms[$i]; - switch ($encrypt) { - case '3des-cbc': - case '3des-ctr': - $encryptKeyLength = 24; - break; - case 'aes256-cbc': - case 'aes256-ctr': - case 'twofish-cbc': - case 'twofish256-cbc': - case 'twofish256-ctr': - $encryptKeyLength = 32; - break; - case 'aes192-cbc': - case 'aes192-ctr': - case 'twofish192-cbc': - case 'twofish192-ctr': - $encryptKeyLength = 24; - break; - case 'aes128-cbc': - case 'aes128-ctr': - case 'twofish128-cbc': - case 'twofish128-ctr': - case 'blowfish-cbc': - case 'blowfish-ctr': - $encryptKeyLength = 16; - break; - case 'arcfour': - case 'arcfour128': - $encryptKeyLength = 16; - break; - case 'arcfour256': - $encryptKeyLength = 32; - break; - case 'none'; - $encryptKeyLength = 0; - } - - $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength; - - // through diffie-hellman key exchange a symmetric key is obtained - for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++); - if ($i == count($kex_algorithms)) { - user_error('No compatible key exchange algorithms found'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - switch ($kex_algorithms[$i]) { - // see http://tools.ietf.org/html/rfc2409#section-6.2 and - // http://tools.ietf.org/html/rfc2412, appendex E - case 'diffie-hellman-group1-sha1': - $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . - '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . - '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . - 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'; - break; - // see http://tools.ietf.org/html/rfc3526#section-3 - case 'diffie-hellman-group14-sha1': - $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . - '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . - '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . - 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . - '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . - '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . - 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . - '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'; - break; - } - - // For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1 - // the generator field element is 2 (decimal) and the hash function is sha1. - $g = new Math_BigInteger(2); - $prime = new Math_BigInteger($prime, 16); - $kexHash = new Crypt_Hash('sha1'); - //$q = $p->bitwise_rightShift(1); - - /* To increase the speed of the key exchange, both client and server may - reduce the size of their private exponents. It should be at least - twice as long as the key material that is generated from the shared - secret. For more details, see the paper by van Oorschot and Wiener - [VAN-OORSCHOT]. - - -- http://tools.ietf.org/html/rfc4419#section-6.2 */ - $one = new Math_BigInteger(1); - $keyLength = min($keyLength, $kexHash->getLength()); - $max = $one->bitwise_leftShift(16 * $keyLength); // 2 * 8 * $keyLength - $max = $max->subtract($one); - - $x = $one->random($one, $max); - $e = $g->modPow($x, $prime); - - $eBytes = $e->toBytes(true); - $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes); - - if (!$this->_send_binary_packet($data)) { - user_error('Connection closed by server'); - return false; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - if ($type != NET_SSH2_MSG_KEXDH_REPLY) { - user_error('Expected SSH_MSG_KEXDH_REPLY'); - return false; - } - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']); - - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $fBytes = $this->_string_shift($response, $temp['length']); - $f = new Math_BigInteger($fBytes, -256); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->signature = $this->_string_shift($response, $temp['length']); - - $temp = unpack('Nlength', $this->_string_shift($this->signature, 4)); - $this->signature_format = $this->_string_shift($this->signature, $temp['length']); - - $key = $f->modPow($x, $prime); - $keyBytes = $key->toBytes(true); - - $this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*', - strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier, - strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server), - $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes), - $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes - ); - - $this->exchange_hash = $kexHash->hash($this->exchange_hash); - - if ($this->session_id === false) { - $this->session_id = $this->exchange_hash; - } - - for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++); - if ($i == count($server_host_key_algorithms)) { - user_error('No compatible server host key algorithms found'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) { - user_error('Server Host Key Algorithm Mismatch'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $packet = pack('C', - NET_SSH2_MSG_NEWKEYS - ); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $response = $this->_get_binary_packet(); - - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - if ($type != NET_SSH2_MSG_NEWKEYS) { - user_error('Expected SSH_MSG_NEWKEYS'); - return false; - } - - switch ($encrypt) { - case '3des-cbc': - if (!class_exists('Crypt_TripleDES')) { - include_once 'Crypt/TripleDES.php'; - } - $this->encrypt = new Crypt_TripleDES(); - // $this->encrypt_block_size = 64 / 8 == the default - break; - case '3des-ctr': - if (!class_exists('Crypt_TripleDES')) { - include_once 'Crypt/TripleDES.php'; - } - $this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); - // $this->encrypt_block_size = 64 / 8 == the default - break; - case 'aes256-cbc': - case 'aes192-cbc': - case 'aes128-cbc': - if (!class_exists('Crypt_Rijndael')) { - include_once 'Crypt/Rijndael.php'; - } - $this->encrypt = new Crypt_Rijndael(); - $this->encrypt_block_size = 16; // eg. 128 / 8 - break; - case 'aes256-ctr': - case 'aes192-ctr': - case 'aes128-ctr': - if (!class_exists('Crypt_Rijndael')) { - include_once 'Crypt/Rijndael.php'; - } - $this->encrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR); - $this->encrypt_block_size = 16; // eg. 128 / 8 - break; - case 'blowfish-cbc': - if (!class_exists('Crypt_Blowfish')) { - include_once 'Crypt/Blowfish.php'; - } - $this->encrypt = new Crypt_Blowfish(); - $this->encrypt_block_size = 8; - break; - case 'blowfish-ctr': - if (!class_exists('Crypt_Blowfish')) { - include_once 'Crypt/Blowfish.php'; - } - $this->encrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); - $this->encrypt_block_size = 8; - break; - case 'twofish128-cbc': - case 'twofish192-cbc': - case 'twofish256-cbc': - case 'twofish-cbc': - if (!class_exists('Crypt_Twofish')) { - include_once 'Crypt/Twofish.php'; - } - $this->encrypt = new Crypt_Twofish(); - $this->encrypt_block_size = 16; - break; - case 'twofish128-ctr': - case 'twofish192-ctr': - case 'twofish256-ctr': - if (!class_exists('Crypt_Twofish')) { - include_once 'Crypt/Twofish.php'; - } - $this->encrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); - $this->encrypt_block_size = 16; - break; - case 'arcfour': - case 'arcfour128': - case 'arcfour256': - if (!class_exists('Crypt_RC4')) { - include_once 'Crypt/RC4.php'; - } - $this->encrypt = new Crypt_RC4(); - break; - case 'none'; - //$this->encrypt = new Crypt_Null(); - } - - switch ($decrypt) { - case '3des-cbc': - if (!class_exists('Crypt_TripleDES')) { - include_once 'Crypt/TripleDES.php'; - } - $this->decrypt = new Crypt_TripleDES(); - break; - case '3des-ctr': - if (!class_exists('Crypt_TripleDES')) { - include_once 'Crypt/TripleDES.php'; - } - $this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); - break; - case 'aes256-cbc': - case 'aes192-cbc': - case 'aes128-cbc': - if (!class_exists('Crypt_Rijndael')) { - include_once 'Crypt/Rijndael.php'; - } - $this->decrypt = new Crypt_Rijndael(); - $this->decrypt_block_size = 16; - break; - case 'aes256-ctr': - case 'aes192-ctr': - case 'aes128-ctr': - if (!class_exists('Crypt_Rijndael')) { - include_once 'Crypt/Rijndael.php'; - } - $this->decrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR); - $this->decrypt_block_size = 16; - break; - case 'blowfish-cbc': - if (!class_exists('Crypt_Blowfish')) { - include_once 'Crypt/Blowfish.php'; - } - $this->decrypt = new Crypt_Blowfish(); - $this->decrypt_block_size = 8; - break; - case 'blowfish-ctr': - if (!class_exists('Crypt_Blowfish')) { - include_once 'Crypt/Blowfish.php'; - } - $this->decrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); - $this->decrypt_block_size = 8; - break; - case 'twofish128-cbc': - case 'twofish192-cbc': - case 'twofish256-cbc': - case 'twofish-cbc': - if (!class_exists('Crypt_Twofish')) { - include_once 'Crypt/Twofish.php'; - } - $this->decrypt = new Crypt_Twofish(); - $this->decrypt_block_size = 16; - break; - case 'twofish128-ctr': - case 'twofish192-ctr': - case 'twofish256-ctr': - if (!class_exists('Crypt_Twofish')) { - include_once 'Crypt/Twofish.php'; - } - $this->decrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); - $this->decrypt_block_size = 16; - break; - case 'arcfour': - case 'arcfour128': - case 'arcfour256': - if (!class_exists('Crypt_RC4')) { - include_once 'Crypt/RC4.php'; - } - $this->decrypt = new Crypt_RC4(); - break; - case 'none'; - //$this->decrypt = new Crypt_Null(); - } - - $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes); - - if ($this->encrypt) { - $this->encrypt->enableContinuousBuffer(); - $this->encrypt->disablePadding(); - - $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id); - while ($this->encrypt_block_size > strlen($iv)) { - $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv); - } - $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size)); - - $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id); - while ($encryptKeyLength > strlen($key)) { - $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); - } - $this->encrypt->setKey(substr($key, 0, $encryptKeyLength)); - } - - if ($this->decrypt) { - $this->decrypt->enableContinuousBuffer(); - $this->decrypt->disablePadding(); - - $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id); - while ($this->decrypt_block_size > strlen($iv)) { - $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv); - } - $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size)); - - $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id); - while ($decryptKeyLength > strlen($key)) { - $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); - } - $this->decrypt->setKey(substr($key, 0, $decryptKeyLength)); - } - - /* The "arcfour128" algorithm is the RC4 cipher, as described in - [SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream - generated by the cipher MUST be discarded, and the first byte of the - first encrypted packet MUST be encrypted using the 1537th byte of - keystream. - - -- http://tools.ietf.org/html/rfc4345#section-4 */ - if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') { - $this->encrypt->encrypt(str_repeat("\0", 1536)); - } - if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') { - $this->decrypt->decrypt(str_repeat("\0", 1536)); - } - - for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++); - if ($i == count($mac_algorithms)) { - user_error('No compatible client to server message authentication algorithms found'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none' - switch ($mac_algorithms[$i]) { - case 'hmac-sha2-256': - $this->hmac_create = new Crypt_Hash('sha256'); - $createKeyLength = 32; - break; - case 'hmac-sha1': - $this->hmac_create = new Crypt_Hash('sha1'); - $createKeyLength = 20; - break; - case 'hmac-sha1-96': - $this->hmac_create = new Crypt_Hash('sha1-96'); - $createKeyLength = 20; - break; - case 'hmac-md5': - $this->hmac_create = new Crypt_Hash('md5'); - $createKeyLength = 16; - break; - case 'hmac-md5-96': - $this->hmac_create = new Crypt_Hash('md5-96'); - $createKeyLength = 16; - } - - for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++); - if ($i == count($mac_algorithms)) { - user_error('No compatible server to client message authentication algorithms found'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $checkKeyLength = 0; - $this->hmac_size = 0; - switch ($mac_algorithms[$i]) { - case 'hmac-sha2-256': - $this->hmac_check = new Crypt_Hash('sha256'); - $checkKeyLength = 32; - $this->hmac_size = 32; - break; - case 'hmac-sha1': - $this->hmac_check = new Crypt_Hash('sha1'); - $checkKeyLength = 20; - $this->hmac_size = 20; - break; - case 'hmac-sha1-96': - $this->hmac_check = new Crypt_Hash('sha1-96'); - $checkKeyLength = 20; - $this->hmac_size = 12; - break; - case 'hmac-md5': - $this->hmac_check = new Crypt_Hash('md5'); - $checkKeyLength = 16; - $this->hmac_size = 16; - break; - case 'hmac-md5-96': - $this->hmac_check = new Crypt_Hash('md5-96'); - $checkKeyLength = 16; - $this->hmac_size = 12; - } - - $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id); - while ($createKeyLength > strlen($key)) { - $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); - } - $this->hmac_create->setKey(substr($key, 0, $createKeyLength)); - - $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id); - while ($checkKeyLength > strlen($key)) { - $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); - } - $this->hmac_check->setKey(substr($key, 0, $checkKeyLength)); - - for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++); - if ($i == count($compression_algorithms)) { - user_error('No compatible server to client compression algorithms found'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - $this->decompress = $compression_algorithms[$i] == 'zlib'; - - for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++); - if ($i == count($compression_algorithms)) { - user_error('No compatible client to server compression algorithms found'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - $this->compress = $compression_algorithms[$i] == 'zlib'; - - return true; - } - - /** - * Login - * - * The $password parameter can be a plaintext password, a Crypt_RSA object or an array - * - * @param String $username - * @param Mixed $password - * @param Mixed $... - * @return Boolean - * @see _login - * @access public - */ - function login($username) - { - $args = func_get_args(); - return call_user_func_array(array(&$this, '_login'), $args); - } - - /** - * Login Helper - * - * @param String $username - * @param Mixed $password - * @param Mixed $... - * @return Boolean - * @see _login_helper - * @access private - */ - function _login($username) - { - if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { - if (!$this->_connect()) { - return false; - } - } - - $args = array_slice(func_get_args(), 1); - if (empty($args)) { - return $this->_login_helper($username); - } - - foreach ($args as $arg) { - if ($this->_login_helper($username, $arg)) { - return true; - } - } - return false; - } - - /** - * Login Helper - * - * @param String $username - * @param optional String $password - * @return Boolean - * @access private - * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis} - * by sending dummy SSH_MSG_IGNORE messages. - */ - function _login_helper($username, $password = null) - { - if (!($this->bitmap & NET_SSH2_MASK_CONNECTED)) { - return false; - } - - if (!($this->bitmap & NET_SSH2_MASK_LOGIN_REQ)) { - $packet = pack('CNa*', - NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth'), 'ssh-userauth' - ); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) { - user_error('Expected SSH_MSG_SERVICE_ACCEPT'); - return false; - } - $this->bitmap |= NET_SSH2_MASK_LOGIN_REQ; - } - - if (strlen($this->last_interactive_response)) { - return !is_string($password) && !is_array($password) ? false : $this->_keyboard_interactive_process($password); - } - - // although PHP5's get_class() preserves the case, PHP4's does not - if (is_object($password)) { - switch (strtolower(get_class($password))) { - case 'crypt_rsa': - return $this->_privatekey_login($username, $password); - case 'system_ssh_agent': - return $this->_ssh_agent_login($username, $password); - } - } - - if (is_array($password)) { - if ($this->_keyboard_interactive_login($username, $password)) { - $this->bitmap |= NET_SSH2_MASK_LOGIN; - return true; - } - return false; - } - - if (!isset($password)) { - $packet = pack('CNa*Na*Na*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', - strlen('none'), 'none' - ); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - switch ($type) { - case NET_SSH2_MSG_USERAUTH_SUCCESS: - $this->bitmap |= NET_SSH2_MASK_LOGIN; - return true; - //case NET_SSH2_MSG_USERAUTH_FAILURE: - default: - return false; - } - } - - $packet = pack('CNa*Na*Na*CNa*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', - strlen('password'), 'password', 0, strlen($password), $password - ); - - // remove the username and password from the logged packet - if (!defined('NET_SSH2_LOGGING')) { - $logged = null; - } else { - $logged = pack('CNa*Na*Na*CNa*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username'), 'username', strlen('ssh-connection'), 'ssh-connection', - strlen('password'), 'password', 0, strlen('password'), 'password' - ); - } - - if (!$this->_send_binary_packet($packet, $logged)) { - return false; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - switch ($type) { - case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed - if (defined('NET_SSH2_LOGGING')) { - $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'; - } - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length)); - return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); - case NET_SSH2_MSG_USERAUTH_FAILURE: - // can we use keyboard-interactive authentication? if not then either the login is bad or the server employees - // multi-factor authentication - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $auth_methods = explode(',', $this->_string_shift($response, $length)); - extract(unpack('Cpartial_success', $this->_string_shift($response, 1))); - $partial_success = $partial_success != 0; - - if (!$partial_success && in_array('keyboard-interactive', $auth_methods)) { - if ($this->_keyboard_interactive_login($username, $password)) { - $this->bitmap |= NET_SSH2_MASK_LOGIN; - return true; - } - return false; - } - return false; - case NET_SSH2_MSG_USERAUTH_SUCCESS: - $this->bitmap |= NET_SSH2_MASK_LOGIN; - return true; - } - - return false; - } - - /** - * Login via keyboard-interactive authentication - * - * See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details. This is not a full-featured keyboard-interactive authenticator. - * - * @param String $username - * @param String $password - * @return Boolean - * @access private - */ - function _keyboard_interactive_login($username, $password) - { - $packet = pack('CNa*Na*Na*Na*Na*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', - strlen('keyboard-interactive'), 'keyboard-interactive', 0, '', 0, '' - ); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - return $this->_keyboard_interactive_process($password); - } - - /** - * Handle the keyboard-interactive requests / responses. - * - * @param String $responses... - * @return Boolean - * @access private - */ - function _keyboard_interactive_process() - { - $responses = func_get_args(); - - if (strlen($this->last_interactive_response)) { - $response = $this->last_interactive_response; - } else { - $orig = $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - switch ($type) { - case NET_SSH2_MSG_USERAUTH_INFO_REQUEST: - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->_string_shift($response, $length); // name; may be empty - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->_string_shift($response, $length); // instruction; may be empty - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->_string_shift($response, $length); // language tag; may be empty - extract(unpack('Nnum_prompts', $this->_string_shift($response, 4))); - - for ($i = 0; $i < count($responses); $i++) { - if (is_array($responses[$i])) { - foreach ($responses[$i] as $key => $value) { - $this->keyboard_requests_responses[$key] = $value; - } - unset($responses[$i]); - } - } - $responses = array_values($responses); - - if (isset($this->keyboard_requests_responses)) { - for ($i = 0; $i < $num_prompts; $i++) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - // prompt - ie. "Password: "; must not be empty - $prompt = $this->_string_shift($response, $length); - //$echo = $this->_string_shift($response) != chr(0); - foreach ($this->keyboard_requests_responses as $key => $value) { - if (substr($prompt, 0, strlen($key)) == $key) { - $responses[] = $value; - break; - } - } - } - } - - // see http://tools.ietf.org/html/rfc4256#section-3.2 - if (strlen($this->last_interactive_response)) { - $this->last_interactive_response = ''; - } else if (defined('NET_SSH2_LOGGING')) { - $this->message_number_log[count($this->message_number_log) - 1] = str_replace( - 'UNKNOWN', - 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', - $this->message_number_log[count($this->message_number_log) - 1] - ); - } - - if (!count($responses) && $num_prompts) { - $this->last_interactive_response = $orig; - return false; - } - - /* - After obtaining the requested information from the user, the client - MUST respond with an SSH_MSG_USERAUTH_INFO_RESPONSE message. - */ - // see http://tools.ietf.org/html/rfc4256#section-3.4 - $packet = $logged = pack('CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses)); - for ($i = 0; $i < count($responses); $i++) { - $packet.= pack('Na*', strlen($responses[$i]), $responses[$i]); - $logged.= pack('Na*', strlen('dummy-answer'), 'dummy-answer'); - } - - if (!$this->_send_binary_packet($packet, $logged)) { - return false; - } - - if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { - $this->message_number_log[count($this->message_number_log) - 1] = str_replace( - 'UNKNOWN', - 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE', - $this->message_number_log[count($this->message_number_log) - 1] - ); - } - - /* - After receiving the response, the server MUST send either an - SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another - SSH_MSG_USERAUTH_INFO_REQUEST message. - */ - // maybe phpseclib should force close the connection after x request / responses? unless something like that is done - // there could be an infinite loop of request / responses. - return $this->_keyboard_interactive_process(); - case NET_SSH2_MSG_USERAUTH_SUCCESS: - return true; - case NET_SSH2_MSG_USERAUTH_FAILURE: - return false; - } - - return false; - } - - /** - * Login with an ssh-agent provided key - * - * @param String $username - * @param System_SSH_Agent $agent - * @return Boolean - * @access private - */ - function _ssh_agent_login($username, $agent) - { - $keys = $agent->requestIdentities(); - foreach ($keys as $key) { - if ($this->_privatekey_login($username, $key)) { - return true; - } - } - - return false; - } - - /** - * Login with an RSA private key - * - * @param String $username - * @param Crypt_RSA $password - * @return Boolean - * @access private - * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis} - * by sending dummy SSH_MSG_IGNORE messages. - */ - function _privatekey_login($username, $privatekey) - { - // see http://tools.ietf.org/html/rfc4253#page-15 - $publickey = $privatekey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW); - if ($publickey === false) { - return false; - } - - $publickey = array( - 'e' => $publickey['e']->toBytes(true), - 'n' => $publickey['n']->toBytes(true) - ); - $publickey = pack('Na*Na*Na*', - strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey['e']), $publickey['e'], strlen($publickey['n']), $publickey['n'] - ); - - $part1 = pack('CNa*Na*Na*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', - strlen('publickey'), 'publickey' - ); - $part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey); - - $packet = $part1 . chr(0) . $part2; - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - switch ($type) { - case NET_SSH2_MSG_USERAUTH_FAILURE: - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length); - return false; - case NET_SSH2_MSG_USERAUTH_PK_OK: - // we'll just take it on faith that the public key blob and the public key algorithm name are as - // they should be - if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { - $this->message_number_log[count($this->message_number_log) - 1] = str_replace( - 'UNKNOWN', - 'NET_SSH2_MSG_USERAUTH_PK_OK', - $this->message_number_log[count($this->message_number_log) - 1] - ); - } - } - - $packet = $part1 . chr(1) . $part2; - $privatekey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); - $signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet)); - $signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature); - $packet.= pack('Na*', strlen($signature), $signature); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - switch ($type) { - case NET_SSH2_MSG_USERAUTH_FAILURE: - // either the login is bad or the server employs multi-factor authentication - return false; - case NET_SSH2_MSG_USERAUTH_SUCCESS: - $this->bitmap |= NET_SSH2_MASK_LOGIN; - return true; - } - - return false; - } - - /** - * Set Timeout - * - * $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely. setTimeout() makes it so it'll timeout. - * Setting $timeout to false or 0 will mean there is no timeout. - * - * @param Mixed $timeout - * @access public - */ - function setTimeout($timeout) - { - $this->timeout = $this->curTimeout = $timeout; - } - - /** - * Get the output from stdError - * - * @access public - */ - function getStdError() - { - return $this->stdErrorLog; - } - - /** - * Execute Command - * - * If $callback is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually. - * In all likelihood, this is not a feature you want to be taking advantage of. - * - * @param String $command - * @param optional Callback $callback - * @return String - * @access public - */ - function exec($command, $callback = null) - { - $this->curTimeout = $this->timeout; - $this->is_timeout = false; - $this->stdErrorLog = ''; - - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - // RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to - // be adjusted". 0x7FFFFFFF is, at 2GB, the max size. technically, it should probably be decremented, but, - // honestly, if you're transfering more than 2GB, you probably shouldn't be using phpseclib, anyway. - // see http://tools.ietf.org/html/rfc4254#section-5.2 for more info - $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC] = $this->window_size; - // 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy - // uses 0x4000, that's what will be used here, as well. - $packet_size = 0x4000; - - $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_EXEC, $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC], $packet_size); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN; - - $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); - if ($response === false) { - return false; - } - - if ($this->request_pty === true) { - $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); - $packet = pack('CNNa*CNa*N5a*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100', - $this->windowColumns, $this->windowRows, 0, 0, strlen($terminal_modes), $terminal_modes); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - - list(, $type) = unpack('C', $this->_string_shift($response, 1)); - - switch ($type) { - case NET_SSH2_MSG_CHANNEL_SUCCESS: - break; - case NET_SSH2_MSG_CHANNEL_FAILURE: - default: - user_error('Unable to request pseudo-terminal'); - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - $this->in_request_pty_exec = true; - } - - // sending a pty-req SSH_MSG_CHANNEL_REQUEST message is unnecessary and, in fact, in most cases, slows things - // down. the one place where it might be desirable is if you're doing something like Net_SSH2::exec('ping localhost &'). - // with a pty-req SSH_MSG_CHANNEL_REQUEST, exec() will return immediately and the ping process will then - // then immediately terminate. without such a request exec() will loop indefinitely. the ping process won't end but - // neither will your script. - - // although, in theory, the size of SSH_MSG_CHANNEL_REQUEST could exceed the maximum packet size established by - // SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the - // "maximum size of an individual data packet". ie. SSH_MSG_CHANNEL_DATA. RFC4254#section-5.2 corroborates. - $packet = pack('CNNa*CNa*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('exec'), 'exec', 1, strlen($command), $command); - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST; - - $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); - if ($response === false) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA; - - if ($callback === false || $this->in_request_pty_exec) { - return true; - } - - $output = ''; - while (true) { - $temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); - switch (true) { - case $temp === true: - return is_callable($callback) ? true : $output; - case $temp === false: - return false; - default: - if (is_callable($callback)) { - if (call_user_func($callback, $temp) === true) { - $this->_close_channel(NET_SSH2_CHANNEL_EXEC); - return true; - } - } else { - $output.= $temp; - } - } - } - } - - /** - * Creates an interactive shell - * - * @see Net_SSH2::read() - * @see Net_SSH2::write() - * @return Boolean - * @access private - */ - function _initShell() - { - if ($this->in_request_pty_exec === true) { - return true; - } - - $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL] = $this->window_size; - $packet_size = 0x4000; - - $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SHELL, $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL], $packet_size); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN; - - $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); - if ($response === false) { - return false; - } - - $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); - $packet = pack('CNNa*CNa*N5a*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100', - $this->windowColumns, $this->windowRows, 0, 0, strlen($terminal_modes), $terminal_modes); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - - list(, $type) = unpack('C', $this->_string_shift($response, 1)); - - switch ($type) { - case NET_SSH2_MSG_CHANNEL_SUCCESS: - // if a pty can't be opened maybe commands can still be executed - case NET_SSH2_MSG_CHANNEL_FAILURE: - break; - default: - user_error('Unable to request pseudo-terminal'); - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - - $packet = pack('CNNa*C', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('shell'), 'shell', 1); - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST; - - $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); - if ($response === false) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA; - - $this->bitmap |= NET_SSH2_MASK_SHELL; - - return true; - } - - /** - * Return the channel to be used with read() / write() - * - * @see Net_SSH2::read() - * @see Net_SSH2::write() - * @return Integer - * @access public - */ - function _get_interactive_channel() - { - switch (true) { - case $this->in_subsystem: - return NET_SSH2_CHANNEL_SUBSYSTEM; - case $this->in_request_pty_exec: - return NET_SSH2_CHANNEL_EXEC; - default: - return NET_SSH2_CHANNEL_SHELL; - } - } - - /** - * Returns the output of an interactive shell - * - * Returns when there's a match for $expect, which can take the form of a string literal or, - * if $mode == NET_SSH2_READ_REGEX, a regular expression. - * - * @see Net_SSH2::write() - * @param String $expect - * @param Integer $mode - * @return String - * @access public - */ - function read($expect = '', $mode = NET_SSH2_READ_SIMPLE) - { - $this->curTimeout = $this->timeout; - $this->is_timeout = false; - - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - user_error('Operation disallowed prior to login()'); - return false; - } - - if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) { - user_error('Unable to initiate an interactive shell session'); - return false; - } - - $channel = $this->_get_interactive_channel(); - - $match = $expect; - while (true) { - if ($mode == NET_SSH2_READ_REGEX) { - preg_match($expect, $this->interactiveBuffer, $matches); - $match = isset($matches[0]) ? $matches[0] : ''; - } - $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false; - if ($pos !== false) { - return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match)); - } - $response = $this->_get_channel_packet($channel); - if (is_bool($response)) { - $this->in_request_pty_exec = false; - return $response ? $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer)) : false; - } - - $this->interactiveBuffer.= $response; - } - } - - /** - * Inputs a command into an interactive shell. - * - * @see Net_SSH2::read() - * @param String $cmd - * @return Boolean - * @access public - */ - function write($cmd) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - user_error('Operation disallowed prior to login()'); - return false; - } - - if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) { - user_error('Unable to initiate an interactive shell session'); - return false; - } - - return $this->_send_channel_packet($this->_get_interactive_channel(), $cmd); - } - - /** - * Start a subsystem. - * - * Right now only one subsystem at a time is supported. To support multiple subsystem's stopSubsystem() could accept - * a string that contained the name of the subsystem, but at that point, only one subsystem of each type could be opened. - * To support multiple subsystem's of the same name maybe it'd be best if startSubsystem() generated a new channel id and - * returns that and then that that was passed into stopSubsystem() but that'll be saved for a future date and implemented - * if there's sufficient demand for such a feature. - * - * @see Net_SSH2::stopSubsystem() - * @param String $subsystem - * @return Boolean - * @access public - */ - function startSubsystem($subsystem) - { - $this->window_size_server_to_client[NET_SSH2_CHANNEL_SUBSYSTEM] = $this->window_size; - - $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SUBSYSTEM, $this->window_size, 0x4000); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_OPEN; - - $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SUBSYSTEM); - if ($response === false) { - return false; - } - - $packet = pack('CNNa*CNa*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SUBSYSTEM], strlen('subsystem'), 'subsystem', 1, strlen($subsystem), $subsystem); - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST; - - $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SUBSYSTEM); - - if ($response === false) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_DATA; - - $this->bitmap |= NET_SSH2_MASK_SHELL; - $this->in_subsystem = true; - - return true; - } - - /** - * Stops a subsystem. - * - * @see Net_SSH2::startSubsystem() - * @return Boolean - * @access public - */ - function stopSubsystem() - { - $this->in_subsystem = false; - $this->_close_channel(NET_SSH2_CHANNEL_SUBSYSTEM); - return true; - } - - /** - * Closes a channel - * - * If read() timed out you might want to just close the channel and have it auto-restart on the next read() call - * - * @access public - */ - function reset() - { - $this->_close_channel($this->_get_interactive_channel()); - } - - /** - * Is timeout? - * - * Did exec() or read() return because they timed out or because they encountered the end? - * - * @access public - */ - function isTimeout() - { - return $this->is_timeout; - } - - /** - * Disconnect - * - * @access public - */ - function disconnect() - { - $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) { - fclose($this->realtime_log_file); - } - } - - /** - * Destructor. - * - * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call - * disconnect(). - * - * @access public - */ - function __destruct() - { - $this->disconnect(); - } - - /** - * Is the connection still active? - * - * @return boolean - * @access public - */ - function isConnected() - { - return (bool) ($this->bitmap & NET_SSH2_MASK_CONNECTED); - } - - /** - * Gets Binary Packets - * - * See '6. Binary Packet Protocol' of rfc4253 for more info. - * - * @see Net_SSH2::_send_binary_packet() - * @return String - * @access private - */ - function _get_binary_packet() - { - if (!is_resource($this->fsock) || feof($this->fsock)) { - user_error('Connection closed prematurely'); - $this->bitmap = 0; - return false; - } - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $raw = fread($this->fsock, $this->decrypt_block_size); - - if (!strlen($raw)) { - return ''; - } - - if ($this->decrypt !== false) { - $raw = $this->decrypt->decrypt($raw); - } - if ($raw === false) { - user_error('Unable to decrypt content'); - return false; - } - - extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5))); - - $remaining_length = $packet_length + 4 - $this->decrypt_block_size; - - // quoting , - // "implementations SHOULD check that the packet length is reasonable" - // PuTTY uses 0x9000 as the actual max packet size and so to shall we - if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) { - user_error('Invalid size'); - return false; - } - - $buffer = ''; - while ($remaining_length > 0) { - $temp = fread($this->fsock, $remaining_length); - if ($temp === false || feof($this->fsock)) { - user_error('Error reading from socket'); - $this->bitmap = 0; - return false; - } - $buffer.= $temp; - $remaining_length-= strlen($temp); - } - $stop = strtok(microtime(), ' ') + strtok(''); - if (strlen($buffer)) { - $raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer; - } - - $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1); - $padding = $this->_string_shift($raw, $padding_length); // should leave $raw empty - - if ($this->hmac_check !== false) { - $hmac = fread($this->fsock, $this->hmac_size); - if ($hmac === false || strlen($hmac) != $this->hmac_size) { - user_error('Error reading socket'); - $this->bitmap = 0; - return false; - } elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) { - user_error('Invalid HMAC'); - return false; - } - } - - //if ($this->decompress) { - // $payload = gzinflate(substr($payload, 2)); - //} - - $this->get_seq_no++; - - if (defined('NET_SSH2_LOGGING')) { - $current = strtok(microtime(), ' ') + strtok(''); - $message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')'; - $message_number = '<- ' . $message_number . - ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)'; - $this->_append_log($message_number, $payload); - $this->last_packet = $current; - } - - return $this->_filter($payload); - } - - /** - * Filter Binary Packets - * - * Because some binary packets need to be ignored... - * - * @see Net_SSH2::_get_binary_packet() - * @return String - * @access private - */ - function _filter($payload) - { - switch (ord($payload[0])) { - case NET_SSH2_MSG_DISCONNECT: - $this->_string_shift($payload, 1); - extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8))); - $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length)); - $this->bitmap = 0; - return false; - case NET_SSH2_MSG_IGNORE: - $payload = $this->_get_binary_packet(); - break; - case NET_SSH2_MSG_DEBUG: - $this->_string_shift($payload, 2); - extract(unpack('Nlength', $this->_string_shift($payload, 4))); - $this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length)); - $payload = $this->_get_binary_packet(); - break; - case NET_SSH2_MSG_UNIMPLEMENTED: - return false; - case NET_SSH2_MSG_KEXINIT: - if ($this->session_id !== false) { - if (!$this->_key_exchange($payload)) { - $this->bitmap = 0; - return false; - } - $payload = $this->_get_binary_packet(); - } - } - - // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in - if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { - $this->_string_shift($payload, 1); - extract(unpack('Nlength', $this->_string_shift($payload, 4))); - $this->banner_message = utf8_decode($this->_string_shift($payload, $length)); - $payload = $this->_get_binary_packet(); - } - - // only called when we've already logged in - if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) { - switch (ord($payload[0])) { - case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4 - $this->_string_shift($payload, 1); - extract(unpack('Nlength', $this->_string_shift($payload))); - $this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . utf8_decode($this->_string_shift($payload, $length)); - - if (!$this->_send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE))) { - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - - $payload = $this->_get_binary_packet(); - break; - case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1 - $this->_string_shift($payload, 1); - extract(unpack('Nlength', $this->_string_shift($payload, 4))); - $this->errors[] = 'SSH_MSG_CHANNEL_OPEN: ' . utf8_decode($this->_string_shift($payload, $length)); - - $this->_string_shift($payload, 4); // skip over client channel - extract(unpack('Nserver_channel', $this->_string_shift($payload, 4))); - - $packet = pack('CN3a*Na*', - NET_SSH2_MSG_REQUEST_FAILURE, $server_channel, NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, 0, '', 0, ''); - - if (!$this->_send_binary_packet($packet)) { - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - - $payload = $this->_get_binary_packet(); - break; - case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST: - $this->_string_shift($payload, 1); - extract(unpack('Nchannel', $this->_string_shift($payload, 4))); - extract(unpack('Nwindow_size', $this->_string_shift($payload, 4))); - $this->window_size_client_to_server[$channel]+= $window_size; - - $payload = ($this->bitmap & NET_SSH2_MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet(); - } - } - - return $payload; - } - - /** - * Enable Quiet Mode - * - * Suppress stderr from output - * - * @access public - */ - function enableQuietMode() - { - $this->quiet_mode = true; - } - - /** - * Disable Quiet Mode - * - * Show stderr in output - * - * @access public - */ - function disableQuietMode() - { - $this->quiet_mode = false; - } - - /** - * Returns whether Quiet Mode is enabled or not - * - * @see Net_SSH2::enableQuietMode() - * @see Net_SSH2::disableQuietMode() - * - * @access public - * @return boolean - */ - function isQuietModeEnabled() - { - return $this->quiet_mode; - } - - /** - * Enable request-pty when using exec() - * - * @access public - */ - function enablePTY() - { - $this->request_pty = true; - } - - /** - * Disable request-pty when using exec() - * - * @access public - */ - function disablePTY() - { - $this->request_pty = false; - } - - /** - * Returns whether request-pty is enabled or not - * - * @see Net_SSH2::enablePTY() - * @see Net_SSH2::disablePTY() - * - * @access public - * @return boolean - */ - function isPTYEnabled() - { - return $this->request_pty; - } - - /** - * Gets channel data - * - * Returns the data as a string if it's available and false if not. - * - * @param $client_channel - * @return Mixed - * @access private - */ - function _get_channel_packet($client_channel, $skip_extended = false) - { - if (!empty($this->channel_buffers[$client_channel])) { - return array_shift($this->channel_buffers[$client_channel]); - } - - while (true) { - if ($this->curTimeout) { - if ($this->curTimeout < 0) { - $this->is_timeout = true; - return true; - } - - $read = array($this->fsock); - $write = $except = null; - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $sec = floor($this->curTimeout); - $usec = 1000000 * ($this->curTimeout - $sec); - // on windows this returns a "Warning: Invalid CRT parameters detected" error - if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { - $this->is_timeout = true; - return true; - } - $elapsed = strtok(microtime(), ' ') + strtok('') - $start; - $this->curTimeout-= $elapsed; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server'); - return false; - } - if ($client_channel == -1 && $response === true) { - return true; - } - if (!strlen($response)) { - return ''; - } - - extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5))); - - $this->window_size_server_to_client[$channel]-= strlen($response); - - // resize the window, if appropriate - if ($this->window_size_server_to_client[$channel] < 0) { - $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_size); - if (!$this->_send_binary_packet($packet)) { - return false; - } - $this->window_size_server_to_client[$channel]+= $this->window_size; - } - - switch ($this->channel_status[$channel]) { - case NET_SSH2_MSG_CHANNEL_OPEN: - switch ($type) { - case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: - extract(unpack('Nserver_channel', $this->_string_shift($response, 4))); - $this->server_channels[$channel] = $server_channel; - extract(unpack('Nwindow_size', $this->_string_shift($response, 4))); - $this->window_size_client_to_server[$channel] = $window_size; - $temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4)); - $this->packet_size_client_to_server[$channel] = $temp['packet_size_client_to_server']; - return $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended); - //case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE: - default: - user_error('Unable to open channel'); - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - break; - case NET_SSH2_MSG_CHANNEL_REQUEST: - switch ($type) { - case NET_SSH2_MSG_CHANNEL_SUCCESS: - return true; - case NET_SSH2_MSG_CHANNEL_FAILURE: - return false; - default: - user_error('Unable to fulfill channel request'); - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - case NET_SSH2_MSG_CHANNEL_CLOSE: - return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->_get_channel_packet($client_channel, $skip_extended); - } - - // ie. $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA - - switch ($type) { - case NET_SSH2_MSG_CHANNEL_DATA: - /* - if ($channel == NET_SSH2_CHANNEL_EXEC) { - // SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server - // this actually seems to make things twice as fast. more to the point, the message right after - // SSH_MSG_CHANNEL_DATA (usually SSH_MSG_IGNORE) won't block for as long as it would have otherwise. - // in OpenSSH it slows things down but only by a couple thousandths of a second. - $this->_send_channel_packet($channel, chr(0)); - } - */ - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $data = $this->_string_shift($response, $length); - if ($client_channel == $channel) { - return $data; - } - if (!isset($this->channel_buffers[$channel])) { - $this->channel_buffers[$channel] = array(); - } - $this->channel_buffers[$channel][] = $data; - break; - case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: - /* - if ($client_channel == NET_SSH2_CHANNEL_EXEC) { - $this->_send_channel_packet($client_channel, chr(0)); - } - */ - // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR - extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8))); - $data = $this->_string_shift($response, $length); - $this->stdErrorLog.= $data; - if ($skip_extended || $this->quiet_mode) { - break; - } - if ($client_channel == $channel) { - return $data; - } - if (!isset($this->channel_buffers[$channel])) { - $this->channel_buffers[$channel] = array(); - } - $this->channel_buffers[$channel][] = $data; - break; - case NET_SSH2_MSG_CHANNEL_REQUEST: - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $value = $this->_string_shift($response, $length); - switch ($value) { - case 'exit-signal': - $this->_string_shift($response, 1); - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length); - $this->_string_shift($response, 1); - extract(unpack('Nlength', $this->_string_shift($response, 4))); - if ($length) { - $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length); - } - - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); - - $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF; - - break; - case 'exit-status': - extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5))); - $this->exit_status = $exit_status; - - // "The client MAY ignore these messages." - // -- http://tools.ietf.org/html/rfc4254#section-6.10 - - break; - default: - // "Some systems may not implement signals, in which case they SHOULD ignore this message." - // -- http://tools.ietf.org/html/rfc4254#section-6.9 - break; - } - break; - case NET_SSH2_MSG_CHANNEL_CLOSE: - $this->curTimeout = 0; - - if ($this->bitmap & NET_SSH2_MASK_SHELL) { - $this->bitmap&= ~NET_SSH2_MASK_SHELL; - } - if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) { - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); - } - - $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE; - return true; - case NET_SSH2_MSG_CHANNEL_EOF: - break; - default: - user_error('Error reading channel data'); - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - } - } - - /** - * Sends Binary Packets - * - * See '6. Binary Packet Protocol' of rfc4253 for more info. - * - * @param String $data - * @param optional String $logged - * @see Net_SSH2::_get_binary_packet() - * @return Boolean - * @access private - */ - function _send_binary_packet($data, $logged = null) - { - if (!is_resource($this->fsock) || feof($this->fsock)) { - user_error('Connection closed prematurely'); - $this->bitmap = 0; - return false; - } - - //if ($this->compress) { - // // the -4 removes the checksum: - // // http://php.net/function.gzcompress#57710 - // $data = substr(gzcompress($data), 0, -4); - //} - - // 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9 - $packet_length = strlen($data) + 9; - // round up to the nearest $this->encrypt_block_size - $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size; - // subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length - $padding_length = $packet_length - strlen($data) - 5; - $padding = crypt_random_string($padding_length); - - // we subtract 4 from packet_length because the packet_length field isn't supposed to include itself - $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding); - - $hmac = $this->hmac_create !== false ? $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet)) : ''; - $this->send_seq_no++; - - if ($this->encrypt !== false) { - $packet = $this->encrypt->encrypt($packet); - } - - $packet.= $hmac; - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $result = strlen($packet) == fputs($this->fsock, $packet); - $stop = strtok(microtime(), ' ') + strtok(''); - - if (defined('NET_SSH2_LOGGING')) { - $current = strtok(microtime(), ' ') + strtok(''); - $message_number = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')'; - $message_number = '-> ' . $message_number . - ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)'; - $this->_append_log($message_number, isset($logged) ? $logged : $data); - $this->last_packet = $current; - } - - return $result; - } - - /** - * Logs data packets - * - * Makes sure that only the last 1MB worth of packets will be logged - * - * @param String $data - * @access private - */ - function _append_log($message_number, $message) - { - // remove the byte identifying the message type from all but the first two messages (ie. the identification strings) - if (strlen($message_number) > 2) { - $this->_string_shift($message); - } - - switch (NET_SSH2_LOGGING) { - // useful for benchmarks - case NET_SSH2_LOG_SIMPLE: - $this->message_number_log[] = $message_number; - break; - // the most useful log for SSH2 - case NET_SSH2_LOG_COMPLEX: - $this->message_number_log[] = $message_number; - $this->log_size+= strlen($message); - $this->message_log[] = $message; - while ($this->log_size > NET_SSH2_LOG_MAX_SIZE) { - $this->log_size-= strlen(array_shift($this->message_log)); - array_shift($this->message_number_log); - } - break; - // dump the output out realtime; packets may be interspersed with non packets, - // passwords won't be filtered out and select other packets may not be correctly - // identified - case NET_SSH2_LOG_REALTIME: - switch (PHP_SAPI) { - case 'cli': - $start = $stop = "\r\n"; - break; - default: - $start = '
';
-                        $stop = '
'; - } - echo $start . $this->_format_log(array($message), array($message_number)) . $stop; - @flush(); - @ob_flush(); - break; - // basically the same thing as NET_SSH2_LOG_REALTIME with the caveat that NET_SSH2_LOG_REALTIME_FILE - // needs to be defined and that the resultant log file will be capped out at NET_SSH2_LOG_MAX_SIZE. - // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily - // at the beginning of the file - case NET_SSH2_LOG_REALTIME_FILE: - if (!isset($this->realtime_log_file)) { - // PHP doesn't seem to like using constants in fopen() - $filename = NET_SSH2_LOG_REALTIME_FILENAME; - $fp = fopen($filename, 'w'); - $this->realtime_log_file = $fp; - } - if (!is_resource($this->realtime_log_file)) { - break; - } - $entry = $this->_format_log(array($message), array($message_number)); - if ($this->realtime_log_wrap) { - $temp = "<<< START >>>\r\n"; - $entry.= $temp; - fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp)); - } - $this->realtime_log_size+= strlen($entry); - if ($this->realtime_log_size > NET_SSH2_LOG_MAX_SIZE) { - fseek($this->realtime_log_file, 0); - $this->realtime_log_size = strlen($entry); - $this->realtime_log_wrap = true; - } - fputs($this->realtime_log_file, $entry); - } - } - - /** - * Sends channel data - * - * Spans multiple SSH_MSG_CHANNEL_DATAs if appropriate - * - * @param Integer $client_channel - * @param String $data - * @return Boolean - * @access private - */ - function _send_channel_packet($client_channel, $data) - { - while (strlen($data)) { - if (!$this->window_size_client_to_server[$client_channel]) { - $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; - // using an invalid channel will let the buffers be built up for the valid channels - $this->_get_channel_packet(-1); - $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; - } - - /* The maximum amount of data allowed is determined by the maximum - packet size for the channel, and the current window size, whichever - is smaller. - -- http://tools.ietf.org/html/rfc4254#section-5.2 */ - $max_size = min( - $this->packet_size_client_to_server[$client_channel], - $this->window_size_client_to_server[$client_channel] - ); - - $temp = $this->_string_shift($data, $max_size); - $packet = pack('CN2a*', - NET_SSH2_MSG_CHANNEL_DATA, - $this->server_channels[$client_channel], - strlen($temp), - $temp - ); - $this->window_size_client_to_server[$client_channel]-= strlen($temp); - if (!$this->_send_binary_packet($packet)) { - return false; - } - } - - return true; - } - - /** - * Closes and flushes a channel - * - * Net_SSH2 doesn't properly close most channels. For exec() channels are normally closed by the server - * and for SFTP channels are presumably closed when the client disconnects. This functions is intended - * for SCP more than anything. - * - * @param Integer $client_channel - * @param Boolean $want_reply - * @return Boolean - * @access private - */ - function _close_channel($client_channel, $want_reply = false) - { - // see http://tools.ietf.org/html/rfc4254#section-5.3 - - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); - - if (!$want_reply) { - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); - } - - $this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE; - - $this->curTimeout = 0; - - while (!is_bool($this->_get_channel_packet($client_channel))); - - if ($want_reply) { - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); - } - - if ($this->bitmap & NET_SSH2_MASK_SHELL) { - $this->bitmap&= ~NET_SSH2_MASK_SHELL; - } - } - - /** - * Disconnect - * - * @param Integer $reason - * @return Boolean - * @access private - */ - function _disconnect($reason) - { - if ($this->bitmap & NET_SSH2_MASK_CONNECTED) { - $data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, ''); - $this->_send_binary_packet($data); - $this->bitmap = 0; - fclose($this->fsock); - return false; - } - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; - } - - /** - * Define Array - * - * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of - * named constants from it, using the value as the name of the constant and the index as the value of the constant. - * If any of the constants that would be defined already exists, none of the constants will be defined. - * - * @param Array $array - * @access private - */ - function _define_array() - { - $args = func_get_args(); - foreach ($args as $arg) { - foreach ($arg as $key=>$value) { - if (!defined($value)) { - define($value, $key); - } else { - break 2; - } - } - } - } - - /** - * Returns a log of the packets that have been sent and received. - * - * Returns a string if NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX, an array if NET_SSH2_LOGGING == NET_SSH2_LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING') - * - * @access public - * @return String or Array - */ - function getLog() - { - if (!defined('NET_SSH2_LOGGING')) { - return false; - } - - switch (NET_SSH2_LOGGING) { - case NET_SSH2_LOG_SIMPLE: - return $this->message_number_log; - break; - case NET_SSH2_LOG_COMPLEX: - return $this->_format_log($this->message_log, $this->message_number_log); - break; - default: - return false; - } - } - - /** - * Formats a log for printing - * - * @param Array $message_log - * @param Array $message_number_log - * @access private - * @return String - */ - function _format_log($message_log, $message_number_log) - { - $output = ''; - for ($i = 0; $i < count($message_log); $i++) { - $output.= $message_number_log[$i] . "\r\n"; - $current_log = $message_log[$i]; - $j = 0; - do { - if (strlen($current_log)) { - $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 '; - } - $fragment = $this->_string_shift($current_log, $this->log_short_width); - $hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary)); - // replace non ASCII printable characters with dots - // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters - // also replace < with a . since < messes up the output on web browsers - $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment); - $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n"; - $j++; - } while (strlen($current_log)); - $output.= "\r\n"; - } - - return $output; - } - - /** - * Helper function for _format_log - * - * For use with preg_replace_callback() - * - * @param Array $matches - * @access private - * @return String - */ - function _format_log_helper($matches) - { - return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT); - } - - /** - * Returns all errors - * - * @return String - * @access public - */ - function getErrors() - { - return $this->errors; - } - - /** - * Returns the last error - * - * @return String - * @access public - */ - function getLastError() - { - return $this->errors[count($this->errors) - 1]; - } - - /** - * Return the server identification. - * - * @return String - * @access public - */ - function getServerIdentification() - { - $this->_connect(); - - return $this->server_identifier; - } - - /** - * Return a list of the key exchange algorithms the server supports. - * - * @return Array - * @access public - */ - function getKexAlgorithms() - { - $this->_connect(); - - return $this->kex_algorithms; - } - - /** - * Return a list of the host key (public key) algorithms the server supports. - * - * @return Array - * @access public - */ - function getServerHostKeyAlgorithms() - { - $this->_connect(); - - return $this->server_host_key_algorithms; - } - - /** - * Return a list of the (symmetric key) encryption algorithms the server supports, when receiving stuff from the client. - * - * @return Array - * @access public - */ - function getEncryptionAlgorithmsClient2Server() - { - $this->_connect(); - - return $this->encryption_algorithms_client_to_server; - } - - /** - * Return a list of the (symmetric key) encryption algorithms the server supports, when sending stuff to the client. - * - * @return Array - * @access public - */ - function getEncryptionAlgorithmsServer2Client() - { - $this->_connect(); - - return $this->encryption_algorithms_server_to_client; - } - - /** - * Return a list of the MAC algorithms the server supports, when receiving stuff from the client. - * - * @return Array - * @access public - */ - function getMACAlgorithmsClient2Server() - { - $this->_connect(); - - return $this->mac_algorithms_client_to_server; - } - - /** - * Return a list of the MAC algorithms the server supports, when sending stuff to the client. - * - * @return Array - * @access public - */ - function getMACAlgorithmsServer2Client() - { - $this->_connect(); - - return $this->mac_algorithms_server_to_client; - } - - /** - * Return a list of the compression algorithms the server supports, when receiving stuff from the client. - * - * @return Array - * @access public - */ - function getCompressionAlgorithmsClient2Server() - { - $this->_connect(); - - return $this->compression_algorithms_client_to_server; - } - - /** - * Return a list of the compression algorithms the server supports, when sending stuff to the client. - * - * @return Array - * @access public - */ - function getCompressionAlgorithmsServer2Client() - { - $this->_connect(); - - return $this->compression_algorithms_server_to_client; - } - - /** - * Return a list of the languages the server supports, when sending stuff to the client. - * - * @return Array - * @access public - */ - function getLanguagesServer2Client() - { - $this->_connect(); - - return $this->languages_server_to_client; - } - - /** - * Return a list of the languages the server supports, when receiving stuff from the client. - * - * @return Array - * @access public - */ - function getLanguagesClient2Server() - { - $this->_connect(); - - return $this->languages_client_to_server; - } - - /** - * Returns the banner message. - * - * Quoting from the RFC, "in some jurisdictions, sending a warning message before - * authentication may be relevant for getting legal protection." - * - * @return String - * @access public - */ - function getBannerMessage() - { - return $this->banner_message; - } - - /** - * Returns the server public host key. - * - * Caching this the first time you connect to a server and checking the result on subsequent connections - * is recommended. Returns false if the server signature is not signed correctly with the public host key. - * - * @return Mixed - * @access public - */ - function getServerPublicHostKey() - { - if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { - if (!$this->_connect()) { - return false; - } - } - - $signature = $this->signature; - $server_public_host_key = $this->server_public_host_key; - - extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4))); - $this->_string_shift($server_public_host_key, $length); - - if ($this->signature_validated) { - return $this->bitmap ? - $this->signature_format . ' ' . base64_encode($this->server_public_host_key) : - false; - } - - $this->signature_validated = true; - - switch ($this->signature_format) { - case 'ssh-dss': - $zero = new Math_BigInteger(); - - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - - /* The value for 'dss_signature_blob' is encoded as a string containing - r, followed by s (which are 160-bit integers, without lengths or - padding, unsigned, and in network byte order). */ - $temp = unpack('Nlength', $this->_string_shift($signature, 4)); - if ($temp['length'] != 40) { - user_error('Invalid signature'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $r = new Math_BigInteger($this->_string_shift($signature, 20), 256); - $s = new Math_BigInteger($this->_string_shift($signature, 20), 256); - - switch (true) { - case $r->equals($zero): - case $r->compare($q) >= 0: - case $s->equals($zero): - case $s->compare($q) >= 0: - user_error('Invalid signature'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $w = $s->modInverse($q); - - $u1 = $w->multiply(new Math_BigInteger(sha1($this->exchange_hash), 16)); - list(, $u1) = $u1->divide($q); - - $u2 = $w->multiply($r); - list(, $u2) = $u2->divide($q); - - $g = $g->modPow($u1, $p); - $y = $y->modPow($u2, $p); - - $v = $g->multiply($y); - list(, $v) = $v->divide($p); - list(, $v) = $v->divide($q); - - if (!$v->equals($r)) { - user_error('Bad server signature'); - return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); - } - - break; - case 'ssh-rsa': - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $rawN = $this->_string_shift($server_public_host_key, $temp['length']); - $n = new Math_BigInteger($rawN, -256); - $nLength = strlen(ltrim($rawN, "\0")); - - /* - $temp = unpack('Nlength', $this->_string_shift($signature, 4)); - $signature = $this->_string_shift($signature, $temp['length']); - - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - - $rsa = new Crypt_RSA(); - $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); - $rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW); - if (!$rsa->verify($this->exchange_hash, $signature)) { - user_error('Bad server signature'); - return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); - } - */ - - $temp = unpack('Nlength', $this->_string_shift($signature, 4)); - $s = new Math_BigInteger($this->_string_shift($signature, $temp['length']), 256); - - // validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the - // following URL: - // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf - - // also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source. - - if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) { - user_error('Invalid signature'); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $s = $s->modPow($e, $n); - $s = $s->toBytes(); - - $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash)); - $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h; - - if ($s != $h) { - user_error('Bad server signature'); - return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); - } - break; - default: - user_error('Unsupported signature format'); - return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); - } - - return $this->signature_format . ' ' . base64_encode($this->server_public_host_key); - } - - /** - * Returns the exit status of an SSH command or false. - * - * @return Integer or false - * @access public - */ - function getExitStatus() - { - if (is_null($this->exit_status)) { - return false; - } - return $this->exit_status; - } - - /** - * Returns the number of columns for the terminal window size. - * - * @return Integer - * @access public - */ - function getWindowColumns() - { - return $this->windowColumns; - } - - /** - * Returns the number of rows for the terminal window size. - * - * @return Integer - * @access public - */ - function getWindowRows() - { - return $this->windowRows; - } - - /** - * Sets the number of columns for the terminal window size. - * - * @param Integer $value - * @access public - */ - function setWindowColumns($value) - { - $this->windowColumns = $value; - } - - /** - * Sets the number of rows for the terminal window size. - * - * @param Integer $value - * @access public - */ - function setWindowRows($value) - { - $this->windowRows = $value; - } - - /** - * Sets the number of columns and rows for the terminal window size. - * - * @param Integer $columns - * @param Integer $rows - * @access public - */ - function setWindowSize($columns = 80, $rows = 24) - { - $this->windowColumns = $columns; - $this->windowRows = $rows; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/System/SSH/Agent.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/System/SSH/Agent.php deleted file mode 100644 index 4c0ef733..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/System/SSH/Agent.php +++ /dev/null @@ -1,313 +0,0 @@ - - * login('username', $agent)) { - * exit('Login Failed'); - * } - * - * echo $ssh->exec('pwd'); - * echo $ssh->exec('ls -la'); - * ?> - * - * - * 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. - * - * @category System - * @package System_SSH_Agent - * @author Jim Wigginton - * @copyright 2014 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - * @internal See http://api.libssh.org/rfc/PROTOCOL.agent - */ - -/**#@+ - * Message numbers - * - * @access private - */ -// to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1) -define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11); -// this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2). -define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12); -define('SYSTEM_SSH_AGENT_FAILURE', 5); -// the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3) -define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13); -// the SSH1 response is SSH_AGENT_RSA_RESPONSE (4) -define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14); -/**#@-*/ - -/** - * Pure-PHP ssh-agent client identity object - * - * Instantiation should only be performed by System_SSH_Agent class. - * This could be thought of as implementing an interface that Crypt_RSA - * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something. - * The methods in this interface would be getPublicKey, setSignatureMode - * and sign since those are the methods phpseclib looks for to perform - * public key authentication. - * - * @package System_SSH_Agent - * @author Jim Wigginton - * @access internal - */ -class System_SSH_Agent_Identity -{ - /** - * Key Object - * - * @var Crypt_RSA - * @access private - * @see System_SSH_Agent_Identity::getPublicKey() - */ - var $key; - - /** - * Key Blob - * - * @var String - * @access private - * @see System_SSH_Agent_Identity::sign() - */ - var $key_blob; - - /** - * Socket Resource - * - * @var Resource - * @access private - * @see System_SSH_Agent_Identity::sign() - */ - var $fsock; - - /** - * Default Constructor. - * - * @param Resource $fsock - * @return System_SSH_Agent_Identity - * @access private - */ - function System_SSH_Agent_Identity($fsock) - { - $this->fsock = $fsock; - } - - /** - * Set Public Key - * - * Called by System_SSH_Agent::requestIdentities() - * - * @param Crypt_RSA $key - * @access private - */ - function setPublicKey($key) - { - $this->key = $key; - $this->key->setPublicKey(); - } - - /** - * Set Public Key - * - * Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key - * but this saves a small amount of computation. - * - * @param String $key_blob - * @access private - */ - function setPublicKeyBlob($key_blob) - { - $this->key_blob = $key_blob; - } - - /** - * Get Public Key - * - * Wrapper for $this->key->getPublicKey() - * - * @param Integer $format optional - * @return Mixed - * @access public - */ - function getPublicKey($format = null) - { - return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format); - } - - /** - * Set Signature Mode - * - * Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie. - * ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1 - * - * @param Integer $mode - * @access public - */ - function setSignatureMode($mode) - { - } - - /** - * Create a signature - * - * See "2.6.2 Protocol 2 private key signature request" - * - * @param String $message - * @return String - * @access public - */ - function sign($message) - { - // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE - $packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0); - $packet = pack('Na*', strlen($packet), $packet); - if (strlen($packet) != fputs($this->fsock, $packet)) { - user_error('Connection closed during signing'); - } - - $length = current(unpack('N', fread($this->fsock, 4))); - $type = ord(fread($this->fsock, 1)); - if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) { - user_error('Unable to retreive signature'); - } - - $signature_blob = fread($this->fsock, $length - 1); - // the only other signature format defined - ssh-dss - is the same length as ssh-rsa - // the + 12 is for the other various SSH added length fields - return substr($signature_blob, strlen('ssh-rsa') + 12); - } -} - -/** - * Pure-PHP ssh-agent client identity factory - * - * requestIdentities() method pumps out System_SSH_Agent_Identity objects - * - * @package System_SSH_Agent - * @author Jim Wigginton - * @access internal - */ -class System_SSH_Agent -{ - /** - * Socket Resource - * - * @var Resource - * @access private - */ - var $fsock; - - /** - * Default Constructor - * - * @return System_SSH_Agent - * @access public - */ - function System_SSH_Agent() - { - switch (true) { - case isset($_SERVER['SSH_AUTH_SOCK']): - $address = $_SERVER['SSH_AUTH_SOCK']; - break; - case isset($_ENV['SSH_AUTH_SOCK']): - $address = $_ENV['SSH_AUTH_SOCK']; - break; - default: - user_error('SSH_AUTH_SOCK not found'); - return false; - } - - $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr); - if (!$this->fsock) { - user_error("Unable to connect to ssh-agent (Error $errno: $errstr)"); - } - } - - /** - * Request Identities - * - * See "2.5.2 Requesting a list of protocol 2 keys" - * Returns an array containing zero or more System_SSH_Agent_Identity objects - * - * @return Array - * @access public - */ - function requestIdentities() - { - if (!$this->fsock) { - return array(); - } - - $packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES); - if (strlen($packet) != fputs($this->fsock, $packet)) { - user_error('Connection closed while requesting identities'); - } - - $length = current(unpack('N', fread($this->fsock, 4))); - $type = ord(fread($this->fsock, 1)); - if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) { - user_error('Unable to request identities'); - } - - $identities = array(); - $keyCount = current(unpack('N', fread($this->fsock, 4))); - for ($i = 0; $i < $keyCount; $i++) { - $length = current(unpack('N', fread($this->fsock, 4))); - $key_blob = fread($this->fsock, $length); - $length = current(unpack('N', fread($this->fsock, 4))); - $key_comment = fread($this->fsock, $length); - $length = current(unpack('N', substr($key_blob, 0, 4))); - $key_type = substr($key_blob, 4, $length); - switch ($key_type) { - case 'ssh-rsa': - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $key = new Crypt_RSA(); - $key->loadKey('ssh-rsa ' . base64_encode($key_blob) . ' ' . $key_comment); - break; - case 'ssh-dss': - // not currently supported - break; - } - // resources are passed by reference by default - if (isset($key)) { - $identity = new System_SSH_Agent_Identity($this->fsock); - $identity->setPublicKey($key); - $identity->setPublicKeyBlob($key_blob); - $identities[] = $identity; - unset($key); - } - } - - return $identities; - } -} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/System/SSH_Agent.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/System/SSH_Agent.php deleted file mode 100644 index ea434b9c..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/System/SSH_Agent.php +++ /dev/null @@ -1,39 +0,0 @@ - - * @copyright 2014 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - * @internal See http://api.libssh.org/rfc/PROTOCOL.agent - */ - -require_once 'SSH/Agent.php'; diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/openssl.cnf b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/openssl.cnf deleted file mode 100644 index 2b8b52f9..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/openssl.cnf +++ /dev/null @@ -1,6 +0,0 @@ -# minimalist openssl.cnf file for use with phpseclib - -HOME = . -RANDFILE = $ENV::HOME/.rnd - -[ v3_ca ] diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ko_KR.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ko_KR.yml deleted file mode 100644 index 8ea7948d..00000000 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ko_KR.yml +++ /dev/null @@ -1,685 +0,0 @@ -ko_KR: - LOGIN: - LABEL_EMAIL: "이메일 주소" - LABEL_LOGIN: "아이디" - LABEL_PASSWORD: "비밀번호" - LABEL_SIGN_ME: "아이디 기억" - LABEL_DONT_ASK_VERIFICATION_CODE: "2주 동안 코드를 물어보지 않기" - BUTTON_SIGN_IN: "로그인" - TITLE_SIGN_IN_GOOGLE: "구글 계정으로 로그인" - TITLE_SIGN_IN_FACEBOOK: "페이스북 계정으로 로그인" - TITLE_SIGN_IN_TWITTER: "트위터 계정으로 로그인" - LABEL_FORGOT_PASSWORD: "비밀번호 분실" - LABEL_REGISTRATION: "회원가입" - TOP_TOOLBAR: - BUTTON_ADD_ACCOUNT: "계정 추가" - BUTTON_SETTINGS: "설정" - BUTTON_HELP: "도움말" - BUTTON_LOGOUT: "로그아웃" - MOBILE: - BUTTON_MOBILE_VERSION: "모바일 버전" - BUTTON_DESKTOP_VERSION: "데스크탑 버전" - SEARCH: - MAIN_INPUT_PLACEHOLDER: "검색" - TITLE_ADV: "고급 검색" - LABEL_ADV_FROM: "보낸 이" - LABEL_ADV_TO: "받는 이" - LABEL_ADV_SUBJECT: "제목" - LABEL_ADV_TEXT: "본문" - LABEL_ADV_HAS_ATTACHMENT: "첨부파일이 있는 메시지" - LABEL_ADV_HAS_ATTACHMENTS: "첨부파일이 있는 메시지" - LABEL_ADV_FLAGGED: "즐겨찾기" - LABEL_ADV_UNSEEN: "Unseen" - LABEL_ADV_DATE: "수신일" - LABEL_ADV_DATE_ALL: "모두" - LABEL_ADV_DATE_3_DAYS: "3일 이내" - LABEL_ADV_DATE_7_DAYS: "1주일 이내" - LABEL_ADV_DATE_MONTH: "1개월 이내" - LABEL_ADV_DATE_3_MONTHS: "3개월 이내" - LABEL_ADV_DATE_6_MONTHS: "6개월 이내" - LABEL_ADV_DATE_YEAR: "1년 이내" - BUTTON_ADV_SEARCH: "찾기" - PREVIEW_POPUP: - FULLSCREEN: "전체화면" - ZOOM: "확대/축소" - CLOSE: "닫기 (Esc)" - LOADING: "로딩 중..." - GALLERY_PREV: "이전 (왼쪽 방향키)" - GALLERY_NEXT: "다음 (오른쪽 방향키)" - GALLERY_COUNTER: "%total% 중 %curr%" - IMAGE_ERROR: "이미지를 불러오지 못했습니다." - AJAX_ERROR: "내용을 불러오지 못했습니다." - FOLDER_LIST: - BUTTON_COMPOSE: "메일 쓰기" - BUTTON_CONTACTS: "연락처" - BUTTON_NEW_MESSAGE: "새로운 메일" - INBOX_NAME: "받은 편지함" - SENT_NAME: "보낸 편지함" - DRAFTS_NAME: "임시 보관함" - SPAM_NAME: "스팸함" - TRASH_NAME: "휴지통" - ARCHIVE_NAME: "어카이브" - QUOTA: - TITLE: "사용량" - MESSAGE_LIST: - BUTTON_RELOAD: "메일 목록 새로고침" - BUTTON_MOVE_TO: "이동" - BUTTON_DELETE: "삭제" - BUTTON_ARCHIVE: "어카이브" - BUTTON_SPAM: "스팸" - BUTTON_NOT_SPAM: "스팸이 아님" - BUTTON_EMPTY_FOLDER: "폴더 비우기" - BUTTON_MULTY_FORWARD: "전달" - BUTTON_DELETE_WITHOUT_MOVE: "완전히 삭제" - BUTTON_MORE: "더 보기" - MENU_SET_SEEN: "읽음으로 표시" - MENU_SET_ALL_SEEN: "모두 읽음으로 표시" - MENU_UNSET_SEEN: "읽지않음으로 표시" - MENU_SET_FLAG: "즐겨찾기로 표시" - MENU_UNSET_FLAG: "즐겨찾기 해제" - MENU_SELECT_ALL: "모두" - MENU_SELECT_NONE: "없음" - MENU_SELECT_INVERT: "반전" - MENU_SELECT_UNSEEN: "읽지 않음" - MENU_SELECT_SEEN: "읽음" - MENU_SELECT_FLAGGED: "즐겨찾기" - MENU_SELECT_UNFLAGGED: "일반" - EMPTY_LIST: "메일함이 비어있습니다." - EMPTY_SEARCH_LIST: "검색 조건에 맞는 결과가 없습니다.." - SEARCH_RESULT_FOR: "\"%SEARCH%\"에 대한 검색결과" - BACK_TO_MESSAGE_LIST: "메일 목록으로 돌아가기" - LIST_LOADING: "로딩 중" - EMPTY_SUBJECT_TEXT: "(제목 없음)" - PUT_MESSAGE_HERE: "목록에서 표시할 메시지를 여기로 끌어 넣으세요." - TODAY_AT: "오늘 %TIME%" - YESTERDAY_AT: "어제 %TIME%" - SEARCH_PLACEHOLDER: "검색" - NEW_MESSAGE_NOTIFICATION: "새 메시지가 %COUNT% 건 있습니다." - QUOTA_SIZE: "총 %LIMIT%%PROC%%를 사용중입니다." - MESSAGE: - BUTTON_EDIT: "수정" - BUTTON_BACK: "뒤로" - BUTTON_CLOSE: "닫기" - BUTTON_DELETE: "삭제" - BUTTON_UNSUBSCRIBE: "이 메일링 리스트를 수신거부" - BUTTON_ARCHIVE: "어카이브" - BUTTON_SPAM: "스팸" - BUTTON_NOT_SPAM: "스팸이 아님" - BUTTON_MOVE_TO: "이동" - BUTTON_MORE: "더보기" - BUTTON_REPLY: "답장" - BUTTON_REPLY_ALL: "모두 답장" - BUTTON_FORWARD: "전달" - BUTTON_FORWARD_AS_ATTACHMENT: "첨부파일로 전달" - BUTTON_EDIT_AS_NEW: "새로 편집하기" - BUTTON_SHOW_IMAGES: "외부이미지 표시" - BUTTON_NOTIFY_READ_RECEIPT: "수신자가 메일을 확인하면 알람을 표시합니다." - BUTTON_IN_NEW_WINDOW: "분할화면에서 보기" - BUTTON_THREAD_LIST: "Thread list" - BUTTON_THREAD_PREV: "Previous" - BUTTON_THREAD_NEXT: "다음" - BUTTON_THREAD_MORE: "더보기" - MENU_HEADERS: "메시지 헤더 보기" - MENU_VIEW_ORIGINAL: "원본 보기" - MENU_DOWNLOAD_ORIGINAL: ".eml 파일로 다운로드" - MENU_FILTER_SIMILAR: "이러한 메시지를 필터링합니다" - MENU_PRINT: "인쇄" - EMPTY_SUBJECT_TEXT: "(제목없음)" - LABEL_SUBJECT: "제목" - LABEL_DATE: "날짜" - LABEL_FROM: "보낸이" - LABEL_FROM_SHORT: "보낸이" - LABEL_TO: "받는이" - LABEL_TO_SHORT: "받는이" - LABEL_CC: "참조" - LABEL_BCC: "숨은 참조" - LABEL_REPLY_TO: "답장" - PRINT_LABEL_FROM: "보낸 이" - PRINT_LABEL_TO: "받는 이" - PRINT_LABEL_CC: "참조" - PRINT_LABEL_BCC: "숨은 참조" - PRINT_LABEL_REPLY_TO: "답장하기" - PRINT_LABEL_DATE: "날짜" - PRINT_LABEL_SUBJECT: "제목" - PRINT_LABEL_ATTACHMENTS: "첨부파일" - MESSAGE_LOADING: "여는 중..." - MESSAGE_VIEW_DESC: "목록에서 선택한 메시지가 여기에 표시됩니다." - PGP_PASSWORD_INPUT_PLACEHOLDER: "비밀번호" - PGP_SIGNED_MESSAGE_DESC: "암호화로 서명된 메세지입니다. (클릭하여 확인하십시오)" - PGP_ENCRYPTED_MESSAGE_DESC: "암호화로 서명된 메세지입니다. (클릭하여 복호화 합니다)" - LINK_DOWNLOAD_AS_ZIP: "압축파일로 다운로드" - LINK_SAVE_TO_OWNCLOUD: "ownCloud에 저장하기" - LINK_SAVE_TO_DROPBOX: "Dropbox에 저장하기" - SUGGESTIONS: - SEARCHING_DESC: "검색중..." - CONTACTS: - LEGEND_CONTACTS: "연락처" - SEARCH_INPUT_PLACEHOLDER: "검색" - BUTTON_ADD_CONTACT: "연락처 추가" - BUTTON_CREATE_CONTACT: "연락처 추가" - BUTTON_UPDATE_CONTACT: "연락처 갱신" - BUTTON_IMPORT: "파일 첨부 (확장자 csv, vcf, vCard)" - BUTTON_EXPORT_VCARD: "내보내기 (확장자 vcf, vCard)" - BUTTON_EXPORT_CSV: "내보내기 (확장자 csv)" - ERROR_IMPORT_FILE: "지원하지 않는 형식의 포맷입니다." - LIST_LOADING: "여는중" - EMPTY_LIST: "연락처가 없습니다." - EMPTY_SEARCH: "연락처를 찾을 수 없습니다." - CLEAR_SEARCH: "검색 초기화" - CONTACT_VIEW_DESC: "선택한 연락처가 이 곳에 표시됩니다" - LABEL_DISPLAY_NAME: "이름 표시" - LABEL_EMAIL: "이메일" - LABEL_PHONE: "연락처" - LABEL_WEB: "홈페이지" - LABEL_BIRTHDAY: "생일" - LINK_ADD_EMAIL: "새 주소록 등록" - LINK_ADD_PHONE: "새 연락처 등록" - LINK_BIRTHDAY: "생일" - PLACEHOLDER_ENTER_DISPLAY_NAME: "표시할 이름을 입력해주세요." - PLACEHOLDER_ENTER_LAST_NAME: "성" - PLACEHOLDER_ENTER_FIRST_NAME: "이름" - PLACEHOLDER_ENTER_NICK_NAME: "별칭" - LABEL_READ_ONLY: "읽기 전용" - LABEL_SHARE: "공유하기" - ADD_MENU_LABEL: "추가" - ADD_MENU_NICKNAME: "별칭" - ADD_MENU_NOTES: "메모" - ADD_MENU_EMAIL: "이메일" - ADD_MENU_PHONE: "연락처" - ADD_MENU_URL: "웹 주소" - ADD_MENU_ADDRESS: "주소" - ADD_MENU_BIRTHDAY: "생일" - ADD_MENU_TAGS: "태그" - BUTTON_SHARE_NONE: "비어 있음" - BUTTON_SYNC: "동기화 (서비스 CardDAV)" - COMPOSE: - TITLE_FROM: "보낸 이" - TITLE_TO: "받는 이" - TITLE_CC: "참조" - TITLE_BCC: "숨은 참조" - TITLE_REPLY_TO: "답장하기" - TITLE_SUBJECT: "제목" - LINK_SHOW_INPUTS: "모든 입력창 보기" - BUTTON_SEND: "보내기" - BUTTON_SAVE: "저장" - BUTTON_DELETE: "삭제" - BUTTON_CANCEL: "취소" - BUTTON_MINIMIZE: "최소화" - SAVED_TIME: "%TIME% 에 저장됨" - SAVED_ERROR_ON_SEND: "메시지는 전송되었지만, 보낸 보관함에 저장되지 않았습니다." - DISCARD_UNSAVED_DATA: "저장되지 않은 데이터를 삭제하시겠습니까 ?" - ATTACH_FILES: "첨부파일" - ATTACH_DROP_FILES_DESC: "파일을 드래그해 넣으세요" - ATTACH_ITEM_CANCEL: "취소" - DROPBOX: "드롭박스" - GOOGLE_DRIVE: "구글 드라이브" - REPLY_MESSAGE_TITLE: "%DATETIME%, %EMAIL% wrote" - FORWARD_MESSAGE_TOP_TITLE: "-------- 전달된 메시지 -------" - FORWARD_MESSAGE_TOP_FROM: "보낸 이" - FORWARD_MESSAGE_TOP_TO: "받는 이" - FORWARD_MESSAGE_TOP_CC: "참조" - FORWARD_MESSAGE_TOP_SENT: "보냄" - FORWARD_MESSAGE_TOP_SUBJECT: "제목" - EMPTY_TO_ERROR_DESC: "수신인을 한 명 이상 선택하세요" - NO_ATTACHMENTS_HERE_DESC: "첨부된 파일이 없습니다." - ATTACHMENTS_ERROR_DESC: "경고 ! 모든 첨부파일이 업로드 되지 않습니다." - ATTACHMENTS_UPLOAD_ERROR_DESC: "첨부파일이 아직 업로드되지 않았습니다." - BUTTON_REQUEST_READ_RECEIPT: "수신확인 메일 요청" - BUTTON_MARK_AS_IMPORTANT: "중요메일 표시" - BUTTON_OPEN_PGP: "OpenPGP (글씨만)" - BUTTON_REQUEST_DSN: "영수증 요청" - POPUPS_WELCOME_PAGE: - BUTTON_CLOSE: "닫기" - POPUPS_ASK: - BUTTON_YES: "네" - BUTTON_NO: "아니요" - DESC_WANT_CLOSE_THIS_WINDOW: "정말 이 페이지를 닫으시겠습니까 ?" - DESC_WANT_DELETE_MESSAGES: "정말 이 메세지들을 삭제하시겠습니까 ?" - POPUPS_LANGUAGES: - TITLE_LANGUAGES: "사용할 언어를 선택하세요" - POPUPS_ADD_ACCOUNT: - TITLE_ADD_ACCOUNT: "새 사용자 추가?" - BUTTON_ADD_ACCOUNT: "추가" - TITLE_UPDATE_ACCOUNT: "사용자 적용" - BUTTON_UPDATE_ACCOUNT: "적용" - POPUPS_IDENTITY: - TITLE_ADD_IDENTITY: "새 서명 추가?" - TITLE_UPDATE_IDENTITY: "서명을 수정하시겠습니까?" - BUTTON_ADD_IDENTITY: "추가" - BUTTON_UPDATE_IDENTITY: "수정" - LABEL_EMAIL: "이메일" - LABEL_NAME: "이름" - LABEL_REPLY_TO: "답장" - LABEL_SIGNATURE: "서명" - LABEL_CC: "Cc" - LABEL_BCC: "숨은 참조" - LABEL_SIGNATURE_INSERT_BEFORE: "답장에 이 서명을 사용합니다." - POPUPS_CREATE_FOLDER: - TITLE_CREATE_FOLDER: "새 폴더 생성?" - LABEL_NAME: "폴더명" - LABEL_PARENT: "상위 폴더" - BUTTON_CREATE: "생성" - BUTTON_CANCEL: "취소" - BUTTON_CLOSE: "닫기" - TITLE_CREATING_PROCESS: "폴더 생성 중" - POPUPS_CLEAR_FOLDER: - TITLE_CLEAR_FOLDER: "이 폴더의 모든 메시지를 완전 삭제하시겠습니까?" - BUTTON_CLEAR: "초기화" - BUTTON_CANCEL: "취소" - BUTTON_CLOSE: "닫기" - DANGER_DESC_WARNING: "경고!" - DANGER_DESC_HTML_1: "이 동작은 %FOLDER% 폴더의 메시지를 모두 삭제할 것입니다." - DANGER_DESC_HTML_2: "작업이 시작되면 중지하거나 취소할 수 없습니다." - TITLE_CLEARING_PROCESS: "폴더 비우는 중..." - POPUPS_IMPORT_OPEN_PGP_KEY: - TITLE_IMPORT_OPEN_PGP_KEY: "OpenPGP키를 입력합니다." - BUTTON_IMPORT_OPEN_PGP_KEY: "입력" - POPUPS_VIEW_OPEN_PGP_KEY: - TITLE_VIEW_OPEN_PGP_KEY: "OpenPGP키 보기" - BUTTON_SELECT: "선택" - BUTTON_CLOSE: "닫기" - POPUPS_GENERATE_OPEN_PGP_KEYS: - TITLE_GENERATE_OPEN_PGP_KEYS: "OpenPGP키 생성" - LABEL_EMAIL: "이메일" - LABEL_NAME: "이름" - LABEL_PASSWORD: "비밀번호" - LABEL_KEY_BIT_LENGTH: "키 길이" - BUTTON_GENERATE_OPEN_PGP_KEYS: "생성" - POPUPS_COMPOSE_OPEN_PGP: - TITLE_COMPOSE_OPEN_PGP: "OpenPGP 로그인/암호화" - LABEL_SIGN: "로그인" - LABEL_ENCRYPT: "암호화" - LABEL_PASSWORD: "비밀번호" - BUTTON_SIGN: "로그인" - BUTTON_ENCRYPT: "암호화" - BUTTON_SIGN_AND_ENCRYPT: "서명과 암호화" - POPUPS_MESSAGE_OPEN_PGP: - TITLE_MESSAGE_OPEN_PGP: "OpenPGP 복호화" - LABEL_KEY: "비공개 키" - LABEL_PASSWORD: "비밀번호" - BUTTON_DECRYPT: "복호화" - POPUPS_TWO_FACTOR_TEST: - TITLE_TEST_CODE: "2단계 인증" - LABEL_CODE: "번호" - BUTTON_TEST: "테스트" - POPUPS_FILTER: - TITLE_CREATE_FILTER: "필터를 생성 하시겠습니까 ?" - TITLE_EDIT_FILTER: "필터를 적용 하시겠습니까 ?" - FILTER_NAME: "Name" - LEGEND_CONDITIONS: "Conditions" - LEGEND_ACTIONS: "Actions" - BUTTON_DONE: "Done" - BUTTON_ADD_CONDITION: "Add a Condition" - SELECT_ACTION_NONE: "None" - SELECT_ACTION_MOVE_TO: "Move to" - SELECT_ACTION_FORWARD_TO: "Forward to" - SELECT_ACTION_REJECT: "Reject" - SELECT_ACTION_VACATION_MESSAGE: "Vacation message" - SELECT_ACTION_DISCARD: "Discard" - SELECT_FIELD_FROM: "From" - SELECT_FIELD_RECIPIENTS: "Recipients (To or CC)" - SELECT_FIELD_SUBJECT: "Subject" - SELECT_FIELD_HEADER: "Header" - SELECT_FIELD_SIZE: "Size" - SELECT_TYPE_CONTAINS: "Contains" - SELECT_TYPE_NOT_CONTAINS: "Not Contains" - SELECT_TYPE_MATCHES: "Matches (* and ? supported)" - SELECT_TYPE_NOT_MATCHES: "Not Matches (* and ? supported)" - SELECT_TYPE_REGEXP: "Regexp" - SELECT_TYPE_NOT_REGEXP: "Not Regexp" - SELECT_TYPE_EQUAL_TO: "Equal To" - SELECT_TYPE_NOT_EQUAL_TO: "Not Equal To" - SELECT_TYPE_OVER: "Over" - SELECT_TYPE_UNDER: "Under" - SELECT_MATCH_ANY: "Matching any of the following rules" - SELECT_MATCH_ALL: "Matching all of the following rules" - MARK_AS_READ_LABEL: "Mark as read" - REPLY_INTERVAL_LABEL: "Reply interval (days)" - KEEP_LABEL: "Keep" - STOP_LABEL: "Don't stop processing rules" - EMAIL_LABEL: "Email" - VACATION_SUBJECT_LABEL: "Subject (optional)" - VACATION_MESSAGE_LABEL: "Message" - VACATION_RECIPIENTS_LABEL: "Recipients (comma separated)" - REJECT_MESSAGE_LABEL: "Reject message" - ALL_INCOMING_MESSAGES_DESC: "All incoming messages" - POPUPS_SYSTEM_FOLDERS: - TITLE_SYSTEM_FOLDERS: "메일함을 지정해주세요" - SELECT_CHOOSE_ONE: "선택해주세요" - SELECT_UNUSE_NAME: "사용하지 않음" - LABEL_SENT: "보낸 편지함" - LABEL_DRAFTS: "임시 보관함" - LABEL_SPAM: "스팸함" - LABEL_TRASH: "휴지통" - LABEL_ARCHIVE: "Archive" - BUTTON_CANCEL: "취소" - BUTTON_CLOSE: "닫기" - NOTIFICATION_SENT: |- - 보낸 편지함 폴더가 지정되지 않았습니다. 보낸 메시지를 보관하지 않고 삭제하려면 "사용하지 않음" 옵션을 선택해주세요. - NOTIFICATION_DRAFTS: "임시 보관함 폴더가 지정되지 않았습니다." - NOTIFICATION_SPAM: |- - 스팸함 폴더가 지정되지 않았습니다. 스팸처리한 메시지를 보관하지 않고 바로 삭제하려면 "사용하지 않음" 옵션을 선택해주세요. - NOTIFICATION_TRASH: |- - 휴지통 폴더가 지정되지 않았습니다. 삭제한 메시지를 휴지통에 보관하지 않고 바로 삭제하려면 "사용하지 않음" 옵션을 선택해주세요. - NOTIFICATION_ARCHIVE: "You haven't selected \"Archive\" system folder achived messages are placed to.\n" - POPUPS_TWO_FACTOR_CFG: - LEGEND_TWO_FACTOR_AUTH: "2-Step Verification" - LABEL_ENABLE_TWO_FACTOR: "Enable 2-Step verification" - LABEL_TWO_FACTOR_USER: "User" - LABEL_TWO_FACTOR_STATUS: "Status" - LABEL_TWO_FACTOR_SECRET: "Secret" - LABEL_TWO_FACTOR_BACKUP_CODES: "Backup codes" - BUTTON_CREATE: "Create New Secret" - BUTTON_ACTIVATE: "Activate" - BUTTON_CLEAR: "Clear" - BUTTON_LOGOUT: "Logout" - BUTTON_DONE: "Done" - BUTTON_TEST: "Test" - LINK_TEST: "test" - BUTTON_SHOW_SECRET: "Show Secret" - BUTTON_HIDE_SECRET: "Hide Secret" - TWO_FACTOR_REQUIRE_DESC: "Your account requires 2-Step verification configuration." - TWO_FACTOR_SECRET_CONFIGURED_DESC: "Configured" - TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Not configured" - TWO_FACTOR_SECRET_DESC: >- - Import this info into your Google Authenticator client (or other TOTP client) - using the provided QR code below or by entering the code manually. - TWO_FACTOR_BACKUP_CODES_DESC: >- - If you can't receive codes via Google Authenticator, you can use backup codes - to sign in. After you’ve used a backup code to sign in, it will become inactive. - TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "You can't change this setting before test." - TITLES: - LOADING: "로딩 중" - LOGIN: "로그인" - MAILBOX: "메일함" - SETTINGS: "설정" - COMPOSE: "편지쓰기" - UPLOAD: - ERROR_FILE_IS_TOO_BIG: "파일이 너무 큽니다." - ERROR_FILE_PARTIALLY_UPLOADED: "알 수 없는 오류로 인해 파일이 부분적으로만 업로드 되었습니다." - ERROR_NO_FILE_UPLOADED: "파일이 업로드되지 않았습니다." - ERROR_MISSING_TEMP_FOLDER: "업로드한 임시 파일을 찾을 수 없습니다." - ERROR_ON_SAVING_FILE: "알 수 없는 오류가 발생했습니다." - ERROR_FILE_TYPE: "정상적인 파일 형식이 아닙니다." - ERROR_UNKNOWN: "알 수 없는 오류가 발생했습니다." - EDITOR: - TEXT_SWITCHER_PLAINT_TEXT: "HTML <-> TEXT" - TEXT_SWITCHER_RICH_FORMATTING: "위지윅 모드" - TEXT_SWITCHER_CONFIRM: "본문 형식과 이미지가 삭제됩니다. 정말 진행하시겠습니까?" - SETTINGS_LABELS: - LABEL_PERSONAL_NAME: "개인" - LABEL_GENERAL_NAME: "일반" - LABEL_CONTACTS_NAME: "Contacts" - LABEL_FOLDERS_NAME: "메일함" - LABEL_ACCOUNTS_NAME: "계정" - LABEL_IDENTITY_NAME: "신원" - LABEL_IDENTITIES_NAME: "신원" - LABEL_FILTERS_NAME: "Filters" - LABEL_TEMPLATES_NAME: "Templates" - LABEL_SECURITY_NAME: "Security" - LABEL_SOCIAL_NAME: "소셜" - LABEL_THEMES_NAME: "테마" - LABEL_CHANGE_PASSWORD_NAME: "비밀번호" - LABEL_OPEN_PGP_NAME: "OpenPGP" - BUTTON_BACK: "뒤로" - SETTINGS_FILTERS: - LEGEND_FILTERS: "Filters" - BUTTON_SAVE: "Save" - BUTTON_ADD_FILTER: "Add a Filter" - BUTTON_DELETE: "Delete" - BUTTON_RAW_SCRIPT: "Use Custom User Script" - SUBNAME_NONE: "None" - SUBNAME_MOVE_TO: "Move to \"%FOLDER%\"" - SUBNAME_FORWARD_TO: "Forward to \"%EMAIL%\"" - SUBNAME_REJECT: "Reject" - SUBNAME_VACATION_MESSAGE: "Vacation message" - SUBNAME_DISCARD: "Discard" - CAPABILITY_LABEL: "Capability" - LOADING_PROCESS: "Updating filter list" - DELETING_ASK: "Are you sure?" - CHACHES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server." - SETTINGS_IDENTITY: - LEGEND_IDENTITY: "신원" - LABEL_DISPLAY_NAME: "이름" - LABEL_REPLY_TO: "답장" - LABEL_SIGNATURE: "서명" - LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages" - SETTINGS_SECURITY: - LEGEND_SECURITY: "Security" - LABEL_AUTOLOGOUT: "Auto Logout" - AUTOLOGIN_NEVER_OPTION_NAME: "Never" - AUTOLOGIN_MINUTES_OPTION_NAME: "%MINUTES% minute(s)" - SETTINGS_GENERAL: - LEGEND_GENERAL: "일반" - LABEL_LANGUAGE: "언어" - LABEL_IDENTITY: "Identity" - LABEL_LAYOUT: "Layout" - LABEL_LAYOUT_NO_SPLIT: "No Split" - LABEL_LAYOUT_VERTICAL_SPLIT: "Vertical Split" - LABEL_LAYOUT_HORIZONTAL_SPLIT: "Horizontal Split" - LABEL_EDITOR: "기본 본문 편집 도구" - LABEL_EDITOR_HTML: "Html 편집기" - LABEL_EDITOR_PLAIN: "텍스트 편집기" - LABEL_EDITOR_HTML_FORCED: "Html (forced)" - LABEL_EDITOR_PLAIN_FORCED: "Plain (forced)" - LABEL_ANIMATION: "인터페이스 애니메이션" - LABEL_ANIMATION_FULL: "최대 애니메이션" - LABEL_ANIMATION_NORMAL: "보통 애니메이션" - LABEL_ANIMATION_NONE: "없음" - LABEL_VIEW_OPTIONS: "화면 보기 설정" - LABEL_USE_PREVIEW_PANE: "미리보기 창 사용" - LABEL_USE_CHECKBOXES_IN_LIST: "목록에서 체크박스 보이기" - LABEL_USE_THREADS: "대화형식 사용" - LABEL_REPLY_SAME_FOLDER: "답장 메시지를 같은 폴더에 위치시킵니다." - LABEL_SHOW_IMAGES: "본문 내 외부 이미지를 항상 표시합니다." - LABEL_SHOW_ANIMATION: "애니메이션 보기" - LABEL_MESSAGE_PER_PAGE: "페이지 당 메시지 수" - LABEL_NOTIFICATIONS: "알림" - LABEL_SOUND_NOTIFICATION: "Sound notification" - LABEL_CHROME_NOTIFICATION_DESC: "새 메시지 알림 팝업 사용" - LABEL_CHROME_NOTIFICATION_DESC_DENIED: "(브라우저에 의해 차단됨)" - SETTINGS_CONTACTS: - LEGEND_CONTACTS: "Contacts" - LABEL_CONTACTS_AUTOSAVE: "Automatically add recipients to your address book" - LEGEND_CONTACTS_SYNC: "Remote Synchronization (CardDAV)" - LABEL_CONTACTS_SYNC_ENABLE: "Enable remote synchronization" - LABEL_CONTACTS_SYNC_SERVER: "Server" - LABEL_CONTACTS_SYNC_AB_URL: "Addressbook URL" - LABEL_CONTACTS_SYNC_USER: "User" - LABEL_CONTACTS_SYNC_PASSWORD: "Password" - SETTINGS_THEMES: - LEGEND_THEMES: "테마" - LEGEND_THEMES_CUSTOM: "사용자 테마 설정" - LABEL_CUSTOM_TYPE: "종류" - LABEL_CUSTOM_TYPE_LIGHT: "밝음" - LABEL_CUSTOM_TYPE_DARK: "어두움" - LABEL_CUSTOM_BACKGROUND_IMAGE: "배경" - BUTTON_UPLOAD_BACKGROUND_IMAGE: "배경 이미지 업로드 (JPG, PNG)" - ERROR_FILE_IS_TOO_BIG: "파일이 너무 큽니다 (1MB 초과)" - ERROR_FILE_TYPE_ERROR: "파일 형식이 잘못 되었습니다. (JPG 또는 PNG만 가능)" - ERROR_UNKNOWN: "파일 업로드 중 알 수 없는 오류가 발생했습니다." - SETTINGS_SOCIAL: - LEGEND_GOOGLE: "구글" - BUTTON_GOOGLE_CONNECT: "구글 계정에 연결" - BUTTON_GOOGLE_DISCONNECT: "구글 계정 연결 끊기" - MAIN_GOOGLE_DESC: "구글 계정에 연결을 활성화하면, 로그인 화면에서 구글 로그인 버튼을 통해 이 메일 계정에 로그인 할 수 있습니다." - LEGEND_FACEBOOK: "페이스북" - BUTTON_FACEBOOK_CONNECT: "페이스북 계정에 연결" - BUTTON_FACEBOOK_DISCONNECT: "페이스북 계정 연결 끊기" - MAIN_FACEBOOK_DESC: "페이스북 계정에 연결을 활성화하면, 로그인 화면에서 페이스북 로그인 버튼을 통해 이 메일 계정에 로그인 할 수 있습니다." - LEGEND_TWITTER: "트위터" - BUTTON_TWITTER_CONNECT: "트위터 계정에 연결" - BUTTON_TWITTER_DISCONNECT: "트위터 계정 연결 끊기" - MAIN_TWITTER_DESC: "트위터 계정에 연결을 활성화하면, 로그인 화면에서 트위터 로그인 버튼을 통해 이 메일 계정에 로그인 할 수 있습니다." - SETTINGS_FOLDERS: - LEGEND_FOLDERS: "폴더 목록" - BUTTON_CREATE: "새 폴더 만들기" - BUTTON_DELETE: "삭제" - BUTTON_SUBSCRIBE: "보기" - BUTTON_UNSUBSCRIBE: "보이지 않기" - LOADING_PROCESS: "폴더 목록을 업데이트하고 있습니다." - CREATING_PROCESS: "폴더를 생성하고 있습니다." - DELETING_PROCESS: "폴더를 삭제하고 있습니다." - RENAMING_PROCESS: "폴더명을 변경하고 있습니다." - DELETING_ASK: "정말로 삭제하시겠습니까?" - TO_MANY_FOLDERS_DESC_1: "You have too many folders!" - TO_MANY_FOLDERS_DESC_2: "We have shown only a part of them, to avoid performance problems." - HELP_DELETE_FOLDER: "Delete folder" - HELP_SHOW_HIDE_FOLDER: "Show/hide folder" - HELP_CHECK_FOR_NEW_MESSAGES: "Check/don't check for new messages" - SETTINGS_ACCOUNTS: - LEGEND_ACCOUNTS: "계정 목록" - LEGEND_IDENTITIES: "Identities" - LEGEND_ACCOUNTS_AND_IDENTITIES: "Accounts and Identities" - BUTTON_ADD_ACCOUNT: "계정 추가" - BUTTON_ADD_IDENTITY: "Add an Identity" - BUTTON_DELETE: "삭제" - LOADING_PROCESS: "계정 목록을 업데이트하고 있습니다." - DELETING_ASK: "정말로 삭제하시겠습니까?" - DEFAULT_IDENTITY_LABEL: "default" - SETTINGS_IDENTITIES: - LEGEND_IDENTITY: "신원" - LEGEND_IDENTITIES: "새 신원 추가" - LABEL_DEFAULT: "Default" - LABEL_DISPLAY_NAME: "이름" - LABEL_REPLY_TO: "답장" - LABEL_SIGNATURE: "서명" - LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages" - BUTTON_ADD_IDENTITY: "신원 추가" - BUTTON_DELETE: "삭제" - LOADING_PROCESS: "신원 목록을 업데이트하고 있습니다." - DELETING_ASK: "정말로 삭제하시겠습니까?" - SETTINGS_CHANGE_PASSWORD: - LEGEND_CHANGE_PASSWORD: "비밀번호 변경" - LABEL_CURRENT_PASSWORD: "현재 비밀번호" - LABEL_NEW_PASSWORD: "새 비밀번호" - LABEL_REPEAT_PASSWORD: "비밀번호 재입력" - BUTTON_UPDATE_PASSWORD: "비밀번호 변경" - ERROR_PASSWORD_MISMATCH: "Passwords do not match, please try again" - SETTINGS_OPEN_PGP: - LEGEND_OPEN_PGP: "OpenPGP" - BUTTON_ADD_OPEN_PGP_KEY: "Import OpenPGP Key" - BUTTON_GENERATE_OPEN_PGP_KEYS: "Generate OpenPGP Keys" - TITLE_PRIVATE: "Private" - TITLE_PUBLIC: "Public" - DELETING_ASK: "Are you sure?" - GENERATE_ONLY_HTTPS: "HTTPS only" - SHORTCUTS_HELP: - LEGEND_SHORTCUTS_HELP: "Keyboard shortcuts help" - TAB_MAILBOX: "Mailbox" - TAB_MESSAGE_LIST: "Message list" - TAB_MESSAGE_VIEW: "Message view" - TAB_COMPOSE: "Compose" - LABEL_OPEN_USER_DROPDOWN: "Open user dropdown" - LABEL_REPLY: "Reply" - LABEL_REPLY_ALL: "Reply All" - LABEL_FORWARD: "Forward" - LABEL_FORWARD_MULTIPLY: "Forward (multiply)" - LABEL_HELP: "Help" - LABEL_CHECK_ALL: "Select all messages" - LABEL_ARCHIVE: "Archive" - LABEL_DELETE: "Delete" - LABEL_OPEN_THREAD: "Open selected thread" - LABEL_MOVE: "Move" - LABEL_READ: "Read selected messages" - LABEL_UNREAD: "Unread selected messages" - LABEL_SEARCH: "Search" - LABEL_CANCEL_SEARCH: "Cancel search" - LABEL_FULLSCREEN_ENTER: "Fullscreen (Preview pane layout)" - LABEL_VIEW_MESSAGE_ENTER: "View message (No preview pane layout)" - LABEL_SWITCH_TO_MESSAGE: "Switch focus to selected message" - LABEL_SWITCH_TO_FOLDER_LIST: "Switch focus to folder list" - LABEL_FULLSCREEN_TOGGLE: "Toggle fullscreen mode" - LABEL_BLOCKQUOTES_TOGGLE: "Toggle message blockquotes" - LABEL_THREAD_NEXT: "Next message in thread" - LABEL_THREAD_PREV: "Previous message in thread" - LABEL_PRINT: "Print" - LABEL_EXIT_FULLSCREEN: "Exit fullscreen mode" - LABEL_CLOSE_MESSAGE: "Close message (No preview pane layout)" - LABEL_SWITCH_TO_LIST: "Switch focus back to message list" - LABEL_OPEN_COMPOSE_POPUP: "Open compose popup" - LABEL_MINIMIZE_COMPOSE_POPUP: "Minimize compose popup" - LABEL_OPEN_IDENTITIES_DROPDOWN: "Open identities dropdown" - LABEL_SAVE_MESSAGE: "Save message" - LABEL_SEND_MESSAGE: "Send message" - LABEL_CLOSE_COMPOSE: "Close compose" - PGP_NOTIFICATIONS: - NO_PUBLIC_KEYS_FOUND: "No public keys found" - NO_PUBLIC_KEYS_FOUND_FOR: "No public keys found for \"%EMAIL%\" email" - NO_PRIVATE_KEY_FOUND: "No private key found" - NO_PRIVATE_KEY_FOUND_FOR: "No private key found for \"%EMAIL%\" email" - ADD_A_PUBLICK_KEY: "Add a public key" - UNVERIFIRED_SIGNATURE: "Unverified signature" - DECRYPTION_ERROR: "OpenPGP decryption error" - GOOD_SIGNATURE: "Good signature from %USER%" - PGP_ERROR: "OpenPGP error: %ERROR%" - SPECIFY_FROM_EMAIL: "Please specify FROM email address" - SPECIFY_AT_LEAST_ONE_RECIPIENT: "Please specify at least one recipient" - NOTIFICATIONS: - INVALID_TOKEN: "잘못된 토큰입니다." - AUTH_ERROR: "인증 실패" - ACCESS_ERROR: "접근 오류" - CONNECTION_ERROR: "서버에 연결할 수 없습니다." - CAPTCHA_ERROR: "보안문자를 잘못 입력하였습니다." - SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE: >- - 이 페이스북 아이디는 아직 어떠한 이메일 계정에도 연결되지 않았습니다. 이메일 계정으로 로그인 하신 후 소셜 설정에서 소셜 계정에 연결해주세요. - SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE: >- - 이 트위터 아이디는 아직 어떠한 이메일 계정에도 연결되지 않았습니다. 이메일 계정으로 로그인 하신 후 소셜 설정에서 소셜 계정에 연결해주세요. - SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE: >- - 이 구글 아이디는 아직 어떠한 이메일 계정에도 연결되지 않았습니다. 이메일 계정으로 로그인 하신 후 소셜 설정에서 소셜 계정에 연결해주세요. - DOMAIN_NOT_ALLOWED: "허용된 도메인이 아닙니다." - ACCOUNT_NOT_ALLOWED: "허용된 계정이 아닙니다." - ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Two factor verification required" - ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Two factor verification error" - COULD_NOT_SAVE_NEW_PASSWORD: "Could not save new password" - CURRENT_PASSWORD_INCORRECT: "Current password incorrect" - NEW_PASSWORD_SHORT: "Password is too short" - NEW_PASSWORD_WEAK: "Password is too easy" - NEW_PASSWORD_FORBIDDENT: "Password contains forbidden characters" - CONTACTS_SYNC_ERROR: "Contacts synchronization error" - CANT_GET_MESSAGE_LIST: "메시지 목록을 불러 올 수 없습니다." - CANT_GET_MESSAGE: "메시지를 가져올 수 없습니다." - CANT_DELETE_MESSAGE: "메시지를 삭제할 수 없습니다." - CANT_MOVE_MESSAGE: "메시지를 이동할 수 없습니다." - CANT_SAVE_MESSAGE: "메시지를 저장할 수 없습니다." - CANT_SEND_MESSAGE: "메시지를 보낼 수 없습니다." - INVALID_RECIPIENTS: "수신인 오류" - CANT_SAVE_FILTERS: "Can't save filters" - CANT_GET_FILTERS: "Can't get filters" - FILTERS_ARE_NOT_CORRECT: "Filters are not correct" - CANT_CREATE_FOLDER: "폴더를 생성할 수 없습니다." - CANT_RENAME_FOLDER: "폴더명을 변경할 수 없습니다." - CANT_DELETE_FOLDER: "폴더를 삭제할 수 없습니다." - CANT_DELETE_NON_EMPTY_FOLDER: "비어있지 않은 디렉터리를 삭제할 수 없습니다." - CANT_SUBSCRIBE_FOLDER: "폴더를 볼 수 없습니다." - CANT_UNSUBSCRIBE_FOLDER: "폴더를 보이지 않게 할 수 없습니다." - CANT_SAVE_SETTINGS: "설정을 저장할 수 없습니다." - CANT_SAVE_PLUGIN_SETTINGS: "설정을 저장할 수 없습니다." - DOMAIN_ALREADY_EXISTS: "이미 존재하는 도메인입니다." - CANT_INSTALL_PACKAGE: "패키지 설치에 실패했습니다." - CANT_DELETE_PACKAGE: "패키지 제거에 실패했습니다." - INVALID_PLUGIN_PACKAGE: "정상적인 플러그인 패키지가 아닙니다." - UNSUPPORTED_PLUGIN_PACKAGE: "지원되지 않는 플러그인 패키지입니다." - LICENSING_SERVER_IS_UNAVAILABLE: "서버가 사용가능 상태가 아닙니다." - LICENSING_DOMAIN_EXPIRED: "이 도메인의 라이센스가 만료되었습니다." - LICENSING_DOMAIN_BANNED: "사용 금지된 도메인입니다." - DEMO_SEND_MESSAGE_ERROR: "이 테스트 계정은 외부 메일 발송이 금지되어있습니다." - DEMO_ACCOUNT_ERROR: "For security purposes, this account is not allowed for this action!" - ACCOUNT_ALREADY_EXISTS: "이미 존재하는 계정입니다." - MAIL_SERVER_ERROR: "메일 서버에 연결하는 중 오류가 발생했습니다." - INVALID_INPUT_ARGUMENT: "Invalid input argument" - UNKNOWN_ERROR: "알 수 없는 오류" - STATIC: - BACK_LINK: "새로고침" - DOMAIN_LIST_DESC: "접근이 허가된 도메인 목록입니다." - PHP_EXSTENSIONS_ERROR_DESC: "필요한 PHP 확장이 구성되지 않았습니다!" - PHP_VERSION_ERROR_DESC: "현재 사용 중인 PHP 버전 (%VERSION%)이 너무 낮습니다. 최소 5.3.0 이상을 설치해주세요!" - NO_SCRIPT_TITLE: "자바스크립트 필요" - NO_SCRIPT_DESC: |- - 사용 중인 브라우저가 자바스크립트를 지원하지 않습니다. 브라우저 설정을 확인하여 자바스크립트 사용을 활성화하고 다시 시도해주세요. - NO_COOKIE_TITLE: "이 어플리케이션을 사용하려면 쿠키 사용이 지원되야 합니다." - NO_COOKIE_DESC: |- - 사용 중인 브라우저가 쿠키를 지원하지 않습니다. 브라우저 설정을 확인하여 쿠키 사용을 활성화하고 다시 시도해주세요. - BAD_BROWSER_TITLE: "사용 중인 브라우저가 구버전입니다." - BAD_BROWSER_DESC: |- - 이 어플리케이션을 정상적으로 사용하시려면 아래의 브라우저들 중 하나를 설치해주세요: diff --git a/rainloop/app/rainloop/v/1.12.1/static/css/app.min.css b/rainloop/app/rainloop/v/1.12.1/static/css/app.min.css deleted file mode 100644 index add48211..00000000 --- a/rainloop/app/rainloop/v/1.12.1/static/css/app.min.css +++ /dev/null @@ -1,7 +0,0 @@ -@charset "UTF-8";/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}/*! jQuery UI - v1.10.3 - 2013-11-25 -* http://jqueryui.com -* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.autocomplete.css, jquery.ui.menu.css, jquery.ui.theme.css -* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:after,.ui-helper-clearfix:before{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:.1px;display:block}.ui-resizable-autohide .ui-resizable-handle,.ui-resizable-disabled .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted #000}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:0}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:400}.ui-menu .ui-menu-item a.ui-state-active,.ui-menu .ui-menu-item a.ui-state-focus{font-weight:400;margin:-1px}.ui-menu .ui-state-disabled{font-weight:400;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget button,.ui-widget input,.ui-widget select,.ui-widget textarea{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc;color:#222;font-weight:700}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ccc;background:#eee;font-weight:400;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-focus,.ui-state-hover,.ui-widget-content .ui-state-focus,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-focus,.ui-widget-header .ui-state-hover{border:1px solid #ccc;background:#eee;font-weight:400;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff;font-weight:400;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:700}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:400}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-corner-all,.ui-corner-left,.ui-corner-tl,.ui-corner-top{border-top-left-radius:2px}.ui-corner-all,.ui-corner-right,.ui-corner-top,.ui-corner-tr{border-top-right-radius:2px}.ui-corner-all,.ui-corner-bl,.ui-corner-bottom,.ui-corner-left{border-bottom-left-radius:2px}.ui-corner-all,.ui-corner-bottom,.ui-corner-br,.ui-corner-right{border-bottom-right-radius:2px}.ui-widget-overlay{background:#aaa;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px}@font-face{font-family:rainloop;src:url(fonts/rainloop.eot);src:url(fonts/rainloop.eot?#iefix) format("embedded-opentype"),url(fonts/rainloop.woff) format("woff"),url(fonts/rainloop.ttf) format("truetype"),url(fonts/rainloop.svg#rainloop) format("svg");font-weight:400;font-style:normal}[data-icon]:before{font-family:rainloop!important;content:attr(data-icon);font-style:normal!important;font-weight:400!important;font-variant:normal!important;text-transform:none!important;speak:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}[class*=" icon-"]:before,[class^=icon-]:before{font-family:rainloop!important;font-style:normal!important;font-weight:400!important;font-variant:normal!important;text-transform:none!important;speak:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-arrows-in:before{content:"\e000"}.icon-arrows-out:before{content:"\e001"}.icon-list:before{content:"\e002"}.icon-search:before{content:"\e003"}.icon-user:before{content:"\e004"}.icon-user-add:before{content:"\e005"}.icon-tags:before{content:"\e006"}.icon-paper-plane:before{content:"\e007"}.icon-reply:before{content:"\e008"}.icon-reply-all:before{content:"\e009"}.icon-forward:before{content:"\e00a"}.icon-info:before{content:"\e00b"}.icon-right-dir:before{content:"\e00c"}.icon-down-dir:before{content:"\e00d"}.icon-image:before{content:"\e00e"}.icon-print:before{content:"\e00f"}.icon-calendar:before{content:"\e010"}.icon-cog:before{content:"\e011"}.icon-wrench:before{content:"\e012"}.icon-rocket:before{content:"\e013"}.icon-fire:before{content:"\e014"}.icon-purchase:before{content:"\e015"}.icon-apple:before{content:"\e016"}.icon-dropbox:before{content:"\e017"}.icon-skype:before{content:"\e018"}.icon-creative-commons:before{content:"\e019"}.icon-ellipsis:before{content:"\e01a"}.icon-left:before{content:"\e01b"}.icon-right:before{content:"\e01c"}.icon-down:before{content:"\e01d"}.icon-right-mini:before{content:"\e01e"}.icon-down-mini:before{content:"\e01f"}.icon-up:before{content:"\e020"}.icon-star-empty:before{content:"\e021"}.icon-star:before{content:"\e022"}.icon-at:before{content:"\e023"}.icon-list-add:before{content:"\e024"}.icon-google:before{content:"\e025"}.icon-google-plus:before{content:"\e026"}.icon-twitter:before{content:"\e027"}.icon-youtube:before{content:"\e028"}.icon-warning:before{content:"\e029"}.icon-warning-alt:before{content:"\e02a"}.icon-power:before{content:"\e02b"}.icon-plus:before{content:"\e02c"}.icon-ok:before{content:"\e02d"}.icon-remove:before{content:"\e02e"}.icon-file:before{content:"\e02f"}.icon-file-code:before{content:"\e030"}.icon-file-chart-graph:before{content:"\e031"}.icon-file-zip:before{content:"\e032"}.icon-file-music:before{content:"\e033"}.icon-file-text:before{content:"\e034"}.icon-file-bookmark:before{content:"\e035"}.icon-file-image:before{content:"\e036"}.icon-file-analytics:before{content:"\e037"}.icon-file-certificate:before{content:"\e038"}.icon-attachment:before{content:"\e039"}.icon-file-excel:before{content:"\e03a"}.icon-file-movie:before{content:"\e03b"}.icon-folder-add:before{content:"\e03c"}.icon-folder:before{content:"\e03d"}.icon-floppy:before{content:"\e03e"}.icon-eye:before{content:"\e03f"}.icon-facebook-alt:before{content:"\e040"}.icon-facebook:before{content:"\e041"}.icon-bolt:before{content:"\e042"}.icon-download:before{content:"\e043"}.icon-upload:before{content:"\e044"}.icon-popup:before{content:"\e045"}.icon-github:before{content:"\e046"}.icon-telephone:before{content:"\e047"}.icon-mobile:before{content:"\e048"}.icon-pencil:before{content:"\e049"}.icon-trash:before{content:"\e04a"}.icon-left-middle:before{content:"\e04b"}.icon-right-middle:before{content:"\e04c"}.icon-repeat:before{content:"\e04d"}.icon-key:before{content:"\e04e"}.icon-lock:before{content:"\e04f"}.icon-home:before{content:"\e050"}.icon-address-book:before{content:"\e051"}.icon-share:before{content:"\e052"}.icon-suitcase:before{content:"\e053"}.icon-new-sign:before{content:"\e054"}.icon-users:before{content:"\e055"}.icon-earth:before{content:"\e056"}.icon-mail:before{content:"\e057"}.icon-checkbox-checked:before{content:"\e058"}.icon-checkbox-unchecked:before{content:"\e059"}.icon-checkbox-partial:before{content:"\e05a"}.icon-radio-checked:before{content:"\e05b"}.icon-radio-unchecked:before{content:"\e05c"}.icon-google-drive:before{content:"\e05d"}.icon-spinner:before{content:"\e05e"}.icon-archive:before{content:"\e05f"}.icon-buy-sign:before{content:"\e060"}.icon-filter:before{content:"\e061"}.icon-sync:before{content:"\e062"}.icon-ellipsis-alt:before{content:"\e063"}.icon-cloud-up:before{content:"\e064"}.icon-cloud-down:before{content:"\e065"}.icon-import:before{content:"\e066"}.icon-export:before{content:"\e067"}.icon-copy:before{content:"\e068"}.icon-angry-smiley:before{content:"\e069"}.icon-happy-smiley:before{content:"\e06a"}.icon-help:before{content:"\e06b"}.icon-resize-in:before{content:"\e06c"}.icon-resize-out:before{content:"\e06d"}.icon-world:before{content:"\e06f"}.icon-braille:before{content:"\e06e"}.icon-play:before{content:"\e070"}.icon-pause:before{content:"\e071"}.icon-stop:before{content:"\e072"}.icon-check-mark-circle-two:before{content:"\e073"}.icon-laptop:before{content:"\e075"}.nano{overflow:hidden!important}.nano .content{position:absolute;overflow:scroll;top:0;right:0;bottom:0;left:0;-webkit-overflow-scrolling:touch}.nano .content .content-wrapper{height:100%}.nano .content::-webkit-scrollbar{visibility:hidden}.has-scrollbar .content::-webkit-scrollbar{visibility:hidden}.nano-visibility-hidden::-webkit-scrollbar{visibility:hidden}.nano>.pane{background:0 0;position:absolute;width:5px;right:0;top:1px;bottom:1px;opacity:.01;-webkit-transition:.4s;-o-transition:.4s;transition:.4s;border-radius:5px;z-index:102;margin:2px}.nano>.pane2{background:0 0;position:absolute;height:5px;right:1px;left:1px;bottom:0;opacity:.01;-webkit-transition:.4s;-o-transition:.4s;transition:.4s;border-radius:5px;z-index:10000;margin:2px}.nano>.pane>.slider{background-color:#999;background-color:rgba(0,0,0,.3);position:relative;margin:0;border-radius:3px;width:5px}.nano>.pane2>.slider2{background-color:#999;background-color:rgba(0,0,0,.3);position:relative;margin:0;border-radius:3px;height:5px}.nano:hover>.pane,.nano:hover>.pane2,.pane.active,.pane.activescroll,.pane.flashed,.pane2.active,.pane2.activescroll,.pane2.flashed{opacity:.99}.nano>.pane.active,.nano>.pane:hover{background-color:rgba(0,0,0,.15)}.nano>.pane2.active,.nano>.pane2:hover{background-color:rgba(0,0,0,.15)}.nano>.pane.active>.slider,.nano>.pane:hover>.slider{background-color:rgba(0,0,0,.4)}.nano>.pane2.active>.slider2,.nano>.pane2:hover>.slider2{background-color:rgba(0,0,0,.4)}.letterfx{display:inline-block;margin:0;padding:0;-o-transition:all 1s;transition:all 1s;-ms-transition:all 1s;-webkit-transition:all 1s}.letterfx-spin-before{transform:rotate(3600deg);-ms-transform:rotate(3600deg);-webkit-transform:rotate(3600deg)}.letterfx-spin-after{-webkit-transform:none;-ms-transform:none;transform:none}.letterfx-fade-before{opacity:0}.letterfx-grow-before{transform:scale(0,0);-ms-transform:scale(0,0);-webkit-transform:scale(0,0)}.letterfx-grow-after{-webkit-transform:none;-ms-transform:none;transform:none}.letterfx-smear-before{color:transparent;text-shadow:-1px -1px 25px transparent}.letterfx-smear-after{color:inherit;text-shadow:0 0 #333}.letterfx-fall-before{visibility:hidden;transform:scale(3,3);-ms-transform:scale(3,3);-webkit-transform:scale(3,3)}.letterfx-fall-after{transform:scale(1,1);-ms-transform:scale(1,1);-webkit-transform:scale(1,1);text-shadow:0}.letterfx-swirl-before{visibility:hidden;transform:scale(3,3) rotate(3600deg);-ms-transform:scale(3,3) rotate(3600deg);-webkit-transform:scale(3,3) rotate(3600deg)}.letterfx-swirl-after{-webkit-transform:none;-ms-transform:none;transform:none;text-shadow:0}.letterfx-wave-container .letterfx{position:relative}.letterfx-wave-before{bottom:0}.letterfx-wave-after{bottom:15px}.letterfx-fly-bottom-container .letterfx,.letterfx-fly-left-container .letterfx,.letterfx-fly-right-container .letterfx,.letterfx-fly-top-container .letterfx{position:relative}.letterfx-fly-left-before{left:-50em}.letterfx-fly-left-after{left:0}.letterfx-fly-right-before{right:-50em}.letterfx-fly-right-after{right:0}.letterfx-fly-top-before{top:-20em}.letterfx-fly-top-after{top:0}.letterfx-fly-bottom-before{bottom:-20em}.letterfx-fly-bottom-after{bottom:0}.inputosaurus-container{background-color:#fff;border:1px solid #bcbec0;margin:0 5px 0 0;padding:0 3px;display:inline-block;cursor:text;font-size:14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.inputosaurus-container li{display:block;float:left;overflow:hidden;margin:2px 2px 0;padding:2px 3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis;-ms-text-overflow:ellipsis;background-color:#e5eff7;border:#a9cae4 solid 1px;border-radius:2px;color:#5b9bcd;-webkit-box-shadow:0 1px 0 rgba(255,255,255,.75) inset;box-shadow:0 1px 0 rgba(255,255,255,.75) inset;line-height:20px;cursor:default}.inputosaurus-container li.inputosaurus-selected{background-color:#bdd6eb}.inputosaurus-container li a{font-size:16px;color:#5b9bcd;padding:1px;text-decoration:none;outline:0}.inputosaurus-container .inputosaurus-input{border:none;-webkit-box-shadow:none;box-shadow:none;background-color:#fff;margin-top:3px}.inputosaurus-container .inputosaurus-input input{border:none;height:23px;font-size:14px;line-height:20px;color:#555;margin:0;outline:0;padding:0 0 1px 1px;width:25px;-webkit-box-shadow:none;box-shadow:none}.inputosaurus-container .inputosaurus-input input:hover{-webkit-box-shadow:none;box-shadow:none}.inputosaurus-input-hidden{display:none}.flag-wrapper{width:24px;height:16px;display:inline-block}.flag{width:16px;height:11px;display:inline-block;background:url(flags.png) no-repeat}.flag.flag-en{background-position:-144px -154px}.flag.flag-en_us{background-position:-144px -154px}.flag.flag-en_gb{background-position:-176px -44px}.flag.flag-en_uk{background-position:-176px -44px}.flag.flag-en_ca{background-position:-48px -22px}.flag.flag-el_gr{background-position:-112px -55px}.flag.flag-uk_ua{background-position:-96px -154px}.flag.flag-ru_ru{background-position:-224px -121px}.flag.flag-pt_br{background-position:-192px -11px}.flag.flag-pl_pl{background-position:-32px -121px}.flag.flag-nl_nl{background-position:-80px -110px}.flag.flag-nb_no{background-position:-96px -110px}.flag.flag-it_it{background-position:-208px -66px}.flag.flag-de_de{background-position:-80px -33px}.flag.flag-ro_ro{background-position:-192px -121px}.flag.flag-fi_fi{background-position:-64px -44px}.flag.flag-fr_fr{background-position:-144px -44px}.flag.flag-fr_ca{background-position:-144px -44px}.flag.flag-pt_pt{background-position:-112px -121px}.flag.flag-pt_br{background-position:-192px -11px}.flag.flag-ar_sa{background-position:0 -132px}.flag.flag-bg_bg{background-position:-80px -11px}.flag.flag-es_es{background-position:-16px -44px}.flag.flag-es_la{background-position:-16px -44px}.flag.flag-et_ee{background-position:-192px -33px}.flag.flag-fa_ir{background-position:-176px -66px}.flag.flag-lt_lt{background-position:-80px -88px}.flag.flag-lv_lv{background-position:-112px -88px}.flag.flag-is_is{background-position:-192px -66px}.flag.flag-hu_hu{background-position:-32px -66px}.flag.flag-ko_kr{background-position:-144px -77px}.flag.flag-ja_jp{background-position:-16px -77px}.flag.flag-sl_si{background-position:-128px -132px}.flag.flag-sk_sk{background-position:-144px -132px}.flag.flag-tr_tr{background-position:-16px -154px}.flag.flag-sv_se{background-position:-80px -132px}.flag.flag-cs_cz{background-position:-64px -33px}.flag.flag-zh_cn{background-position:-208px -22px}.flag.flag-zh_tw{background-position:-64px -154px}.flag.flag-zh_hk{background-position:-208px -22px}.flag.flag-da_dk{background-position:-112px -33px}.flag.flag-id_id{background-position:-64px -66px}.opentip-container,.opentip-container *{-webkit-box-sizing:border-box;box-sizing:border-box}.opentip-container{position:absolute;max-width:300px;z-index:100;-webkit-transition:-webkit-transform 1s ease-in-out;-o-transition:-o-transform 1s ease-in-out;transition:-webkit-transform 1s ease-in-out;-o-transition:transform 1s ease-in-out;transition:transform 1s ease-in-out;transition:transform 1s ease-in-out,-webkit-transform 1s ease-in-out;pointer-events:none;-webkit-transform:translateX(0) translateY(0);-ms-transform:translateX(0) translateY(0);transform:translateX(0) translateY(0)}.opentip-container.ot-fixed.ot-going-to-show.stem-top.stem-center,.opentip-container.ot-fixed.ot-hidden.stem-top.stem-center,.opentip-container.ot-fixed.ot-hiding.stem-top.stem-center{-webkit-transform:translateY(-5px);-ms-transform:translateY(-5px);transform:translateY(-5px)}.opentip-container.ot-fixed.ot-going-to-show.stem-top.stem-right,.opentip-container.ot-fixed.ot-hidden.stem-top.stem-right,.opentip-container.ot-fixed.ot-hiding.stem-top.stem-right{-webkit-transform:translateY(-5px) translateX(5px);-ms-transform:translateY(-5px) translateX(5px);transform:translateY(-5px) translateX(5px)}.opentip-container.ot-fixed.ot-going-to-show.stem-middle.stem-right,.opentip-container.ot-fixed.ot-hidden.stem-middle.stem-right,.opentip-container.ot-fixed.ot-hiding.stem-middle.stem-right{-webkit-transform:translateX(5px);-ms-transform:translateX(5px);transform:translateX(5px)}.opentip-container.ot-fixed.ot-going-to-show.stem-bottom.stem-right,.opentip-container.ot-fixed.ot-hidden.stem-bottom.stem-right,.opentip-container.ot-fixed.ot-hiding.stem-bottom.stem-right{-webkit-transform:translateY(5px) translateX(5px);-ms-transform:translateY(5px) translateX(5px);transform:translateY(5px) translateX(5px)}.opentip-container.ot-fixed.ot-going-to-show.stem-bottom.stem-center,.opentip-container.ot-fixed.ot-hidden.stem-bottom.stem-center,.opentip-container.ot-fixed.ot-hiding.stem-bottom.stem-center{-webkit-transform:translateY(5px);-ms-transform:translateY(5px);transform:translateY(5px)}.opentip-container.ot-fixed.ot-going-to-show.stem-bottom.stem-left,.opentip-container.ot-fixed.ot-hidden.stem-bottom.stem-left,.opentip-container.ot-fixed.ot-hiding.stem-bottom.stem-left{-webkit-transform:translateY(5px) translateX(-5px);-ms-transform:translateY(5px) translateX(-5px);transform:translateY(5px) translateX(-5px)}.opentip-container.ot-fixed.ot-going-to-show.stem-middle.stem-left,.opentip-container.ot-fixed.ot-hidden.stem-middle.stem-left,.opentip-container.ot-fixed.ot-hiding.stem-middle.stem-left{-webkit-transform:translateX(-5px);-ms-transform:translateX(-5px);transform:translateX(-5px)}.opentip-container.ot-fixed.ot-going-to-show.stem-top.stem-left,.opentip-container.ot-fixed.ot-hidden.stem-top.stem-left,.opentip-container.ot-fixed.ot-hiding.stem-top.stem-left{-webkit-transform:translateY(-5px) translateX(-5px);-ms-transform:translateY(-5px) translateX(-5px);transform:translateY(-5px) translateX(-5px)}.opentip-container.ot-fixed .opentip{pointer-events:auto}.opentip-container.ot-hidden{display:none}.opentip-container .opentip{position:relative;font-size:13px;line-height:120%;padding:9px 14px;color:#4f4b47;text-shadow:-1px -1px 0 rgba(255,255,255,.2)}.opentip-container .opentip .header{margin:0;padding:0}.opentip-container .opentip .ot-close{pointer-events:auto;display:block;position:absolute;top:-12px;left:60px;color:rgba(0,0,0,.5);background:rgba(0,0,0,0);text-decoration:none}.opentip-container .opentip .ot-close span{display:none}.opentip-container .opentip .ot-loading-indicator{display:none}.opentip-container.ot-loading .ot-loading-indicator{width:30px;height:30px;font-size:30px;line-height:30px;font-weight:700;display:block}.opentip-container.ot-loading .ot-loading-indicator span{display:block;-webkit-animation:otloading 2s linear infinite;animation:otloading 2s linear infinite;text-align:center}.opentip-container.style-alert .opentip,.opentip-container.style-dark .opentip{color:#f8f8f8;text-shadow:1px 1px 0 rgba(0,0,0,.2)}.opentip-container.style-glass .opentip{padding:15px 25px;color:#317cc5;text-shadow:1px 1px 8px rgba(0,94,153,.3)}.opentip-container.ot-hide-effect-fade{-webkit-transition:-webkit-transform .5s ease-in-out,opacity 1s ease-in-out;-o-transition:-o-transform .5s ease-in-out,opacity 1s ease-in-out;-webkit-transition:opacity 1s ease-in-out,-webkit-transform .5s ease-in-out;transition:opacity 1s ease-in-out,-webkit-transform .5s ease-in-out;-o-transition:transform .5s ease-in-out,opacity 1s ease-in-out;transition:transform .5s ease-in-out,opacity 1s ease-in-out;transition:transform .5s ease-in-out,opacity 1s ease-in-out,-webkit-transform .5s ease-in-out;opacity:1;-ms-filter:none;-webkit-filter:none;filter:none}.opentip-container.ot-hide-effect-fade.ot-hiding{opacity:0}.opentip-container.ot-show-effect-appear.ot-going-to-show,.opentip-container.ot-show-effect-appear.ot-showing{-webkit-transition:-webkit-transform .5s ease-in-out,opacity 1s ease-in-out;-o-transition:-o-transform .5s ease-in-out,opacity 1s ease-in-out;-webkit-transition:opacity 1s ease-in-out,-webkit-transform .5s ease-in-out;transition:opacity 1s ease-in-out,-webkit-transform .5s ease-in-out;-o-transition:transform .5s ease-in-out,opacity 1s ease-in-out;transition:transform .5s ease-in-out,opacity 1s ease-in-out;transition:transform .5s ease-in-out,opacity 1s ease-in-out,-webkit-transform .5s ease-in-out}.opentip-container.ot-show-effect-appear.ot-going-to-show{opacity:0}.opentip-container.ot-show-effect-appear.ot-showing{opacity:1;-ms-filter:none;-webkit-filter:none;filter:none}.opentip-container.ot-show-effect-appear.ot-visible{opacity:1;-ms-filter:none;-webkit-filter:none;filter:none}@-webkit-keyframes otloading{0%{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes otloading{0%{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}/*! - * Pikaday - * Copyright © 2014 David Bushell | BSD & MIT license | http://dbushell.com/ - */.pika-single{z-index:9999;display:block;position:relative;color:#333;background:#fff;border:1px solid #ccc;border-bottom-color:#bbb;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.pika-single:after,.pika-single:before{content:" ";display:table}.pika-single:after{clear:both}.pika-single.is-hidden{display:none}.pika-single.is-bound{position:absolute;-webkit-box-shadow:0 5px 15px -5px rgba(0,0,0,.5);box-shadow:0 5px 15px -5px rgba(0,0,0,.5)}.pika-lendar{float:left;width:240px;margin:8px}.pika-title{position:relative;text-align:center}.pika-label{display:inline-block;position:relative;z-index:9999;overflow:hidden;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:700;background-color:#fff}.pika-title select{cursor:pointer;position:absolute;z-index:9998;margin:0;left:0;top:5px;opacity:0}.pika-next,.pika-prev{display:block;cursor:pointer;position:relative;outline:0;border:0;padding:0;width:20px;height:30px;text-indent:20px;white-space:nowrap;overflow:hidden;background-color:transparent;background-position:center center;background-repeat:no-repeat;background-size:75% 75%;opacity:.5}.pika-next:hover,.pika-prev:hover{opacity:1}.is-rtl .pika-next,.pika-prev{float:left;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==)}.is-rtl .pika-prev,.pika-next{float:right;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=)}.pika-next.is-disabled,.pika-prev.is-disabled{cursor:default;opacity:.2}.pika-select{display:inline-block}.pika-table{width:100%;border-collapse:collapse;border-spacing:0;border:0}.pika-table td,.pika-table th{width:14.285714285714286%;padding:0}.pika-table th{color:#999;font-size:12px;line-height:25px;font-weight:700;text-align:center}.pika-button{cursor:pointer;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;-moz-box-sizing:border-box;outline:0;border:0;margin:0;width:100%;padding:5px;color:#666;font-size:12px;line-height:15px;text-align:right;background:#f5f5f5}.pika-week{font-size:11px;color:#999}.is-today .pika-button{color:#3af;font-weight:700}.has-event .pika-button,.is-selected .pika-button{color:#fff;font-weight:700;background:#3af;-webkit-box-shadow:inset 0 1px 3px #178fe5;box-shadow:inset 0 1px 3px #178fe5;border-radius:3px}.has-event .pika-button{background:#005da9;-webkit-box-shadow:inset 0 1px 3px #0076c9;box-shadow:inset 0 1px 3px #0076c9}.is-disabled .pika-button,.is-inrange .pika-button{background:#d5e9f7}.is-startrange .pika-button{color:#fff;background:#6cb31d;-webkit-box-shadow:none;box-shadow:none;border-radius:3px}.is-endrange .pika-button{color:#fff;background:#3af;-webkit-box-shadow:none;box-shadow:none;border-radius:3px}.is-disabled .pika-button{pointer-events:none;cursor:default;color:#999;opacity:.3}.is-outside-current-month .pika-button{color:#999;opacity:.3}.is-selection-disabled{pointer-events:none;cursor:default}.pika-button:hover,.pika-row.pick-whole-week:hover .pika-button{color:#fff;background:#ff8000;-webkit-box-shadow:none;box-shadow:none;border-radius:3px}.pika-table abbr{border-bottom:none;cursor:help}.lg-sub-html,.lg-toolbar{background-color:rgba(0,0,0,.45)}#lg-counter,.lg-outer .lg-video-cont{vertical-align:middle;display:inline-block}@font-face{font-family:lg;src:url(fonts/lg.eot?n1z373);src:url(fonts/lg.eot?#iefixn1z373) format("embedded-opentype"),url(fonts/lg.woff?n1z373) format("woff"),url(fonts/lg.ttf?n1z373) format("truetype"),url(fonts/lg.svg?n1z373#lg) format("svg");font-weight:400;font-style:normal}.lg-icon{font-family:lg;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.lg-actions .lg-next,.lg-actions .lg-prev{background-color:rgba(0,0,0,.45);border-radius:2px;color:#999;cursor:pointer;display:block;font-size:22px;margin-top:-10px;padding:8px 10px 9px;position:absolute;top:50%;z-index:1080}.lg-actions .lg-next.disabled,.lg-actions .lg-prev.disabled{pointer-events:none;opacity:.5}.lg-actions .lg-next:hover,.lg-actions .lg-prev:hover{color:#fff}.lg-actions .lg-next{right:20px}.lg-actions .lg-next:before{content:"\e095"}.lg-actions .lg-prev{left:20px}.lg-actions .lg-prev:after{content:"\e094"}@-webkit-keyframes lg-right-end{0%,100%{left:0}50%{left:-30px}}@keyframes lg-right-end{0%,100%{left:0}50%{left:-30px}}@-webkit-keyframes lg-left-end{0%,100%{left:0}50%{left:30px}}@keyframes lg-left-end{0%,100%{left:0}50%{left:30px}}.lg-outer.lg-right-end .lg-object{-webkit-animation:lg-right-end .3s;animation:lg-right-end .3s;position:relative}.lg-outer.lg-left-end .lg-object{-webkit-animation:lg-left-end .3s;animation:lg-left-end .3s;position:relative}.lg-toolbar{z-index:1082;left:0;position:absolute;top:0;width:100%}.lg-toolbar .lg-icon{color:#999;cursor:pointer;float:right;font-size:24px;height:47px;line-height:27px;padding:10px 0;text-align:center;width:50px;text-decoration:none!important;outline:0;-webkit-transition:color .2s linear;-o-transition:color .2s linear;transition:color .2s linear}.lg-toolbar .lg-icon:hover{color:#fff}.lg-toolbar .lg-close:after{content:"\e070"}.lg-toolbar .lg-download:after{content:"\e0f2"}.lg-sub-html{bottom:0;color:#eee;font-size:16px;left:0;padding:10px 40px;position:fixed;right:0;text-align:center;z-index:1080}.lg-sub-html h4{margin:0;font-size:13px;font-weight:700}.lg-sub-html p{font-size:12px;margin:5px 0 0}#lg-counter{color:#999;font-size:16px;padding-left:20px;padding-top:12px}.lg-next,.lg-prev,.lg-toolbar{opacity:1;-webkit-transition:-webkit-transform .35s cubic-bezier(0,0,.25,1) 0s,opacity .35s cubic-bezier(0,0,.25,1) 0s,color .2s linear;-o-transition:-o-transform .35s cubic-bezier(0,0,.25,1) 0s,opacity .35s cubic-bezier(0,0,.25,1) 0s,color .2s linear;-webkit-transition:opacity .35s cubic-bezier(0,0,.25,1) 0s,color .2s linear,-webkit-transform .35s cubic-bezier(0,0,.25,1) 0s;transition:opacity .35s cubic-bezier(0,0,.25,1) 0s,color .2s linear,-webkit-transform .35s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform .35s cubic-bezier(0,0,.25,1) 0s,opacity .35s cubic-bezier(0,0,.25,1) 0s,color .2s linear;transition:transform .35s cubic-bezier(0,0,.25,1) 0s,opacity .35s cubic-bezier(0,0,.25,1) 0s,color .2s linear;transition:transform .35s cubic-bezier(0,0,.25,1) 0s,opacity .35s cubic-bezier(0,0,.25,1) 0s,color .2s linear,-webkit-transform .35s cubic-bezier(0,0,.25,1) 0s}.lg-hide-items .lg-prev{opacity:0;-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}.lg-hide-items .lg-next{opacity:0;-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}.lg-hide-items .lg-toolbar{opacity:0;-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}body:not(.lg-from-hash) .lg-outer.lg-start-zoom .lg-object{-webkit-transform:scale3d(.5,.5,.5);transform:scale3d(.5,.5,.5);opacity:0;-webkit-transition:-webkit-transform 250ms cubic-bezier(0,0,.25,1) 0s,opacity 250ms cubic-bezier(0,0,.25,1)!important;-o-transition:-o-transform 250ms cubic-bezier(0,0,.25,1) 0s,opacity 250ms cubic-bezier(0,0,.25,1)!important;-webkit-transition:opacity 250ms cubic-bezier(0,0,.25,1),-webkit-transform 250ms cubic-bezier(0,0,.25,1) 0s!important;transition:opacity 250ms cubic-bezier(0,0,.25,1),-webkit-transform 250ms cubic-bezier(0,0,.25,1) 0s!important;-o-transition:transform 250ms cubic-bezier(0,0,.25,1) 0s,opacity 250ms cubic-bezier(0,0,.25,1)!important;transition:transform 250ms cubic-bezier(0,0,.25,1) 0s,opacity 250ms cubic-bezier(0,0,.25,1)!important;transition:transform 250ms cubic-bezier(0,0,.25,1) 0s,opacity 250ms cubic-bezier(0,0,.25,1),-webkit-transform 250ms cubic-bezier(0,0,.25,1) 0s!important;-webkit-transform-origin:50% 50%;-ms-transform-origin:50% 50%;transform-origin:50% 50%}body:not(.lg-from-hash) .lg-outer.lg-start-zoom .lg-item.lg-complete .lg-object{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1);opacity:1}.lg-outer .lg-thumb-outer{background-color:#0d0a0a;bottom:0;position:absolute;width:100%;z-index:1080;max-height:350px;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);-webkit-transition:-webkit-transform .25s cubic-bezier(0,0,.25,1) 0s;-o-transition:-o-transform .25s cubic-bezier(0,0,.25,1) 0s;transition:-webkit-transform .25s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform .25s cubic-bezier(0,0,.25,1) 0s;transition:transform .25s cubic-bezier(0,0,.25,1) 0s;transition:transform .25s cubic-bezier(0,0,.25,1) 0s,-webkit-transform .25s cubic-bezier(0,0,.25,1) 0s}.lg-outer .lg-thumb-outer.lg-grab .lg-thumb-item{cursor:-webkit-grab;cursor:-o-grab;cursor:-ms-grab;cursor:grab}.lg-outer .lg-thumb-outer.lg-grabbing .lg-thumb-item{cursor:move;cursor:-webkit-grabbing;cursor:-o-grabbing;cursor:-ms-grabbing;cursor:grabbing}.lg-outer .lg-thumb-outer.lg-dragging .lg-thumb{-webkit-transition-duration:0s!important;-o-transition-duration:0s!important;transition-duration:0s!important}.lg-outer.lg-thumb-open .lg-thumb-outer{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.lg-outer .lg-thumb{padding:10px 0;height:100%;margin-bottom:-5px}.lg-outer .lg-thumb-item{cursor:pointer;float:left;overflow:hidden;height:100%;border:2px solid #fff;border-radius:4px;margin-bottom:5px}@media (min-width:1025px){.lg-outer .lg-thumb-item{-webkit-transition:border-color .25s ease;-o-transition:border-color .25s ease;transition:border-color .25s ease}}.lg-outer .lg-thumb-item.active,.lg-outer .lg-thumb-item:hover{border-color:#a90707}.lg-outer .lg-thumb-item img{width:100%;height:100%;-o-object-fit:cover;object-fit:cover}.lg-outer.lg-has-thumb .lg-item{padding-bottom:120px}.lg-outer.lg-can-toggle .lg-item{padding-bottom:0}.lg-outer.lg-pull-caption-up .lg-sub-html{-webkit-transition:bottom .25s ease;-o-transition:bottom .25s ease;transition:bottom .25s ease}.lg-outer.lg-pull-caption-up.lg-thumb-open .lg-sub-html{bottom:100px}.lg-outer .lg-toogle-thumb{background-color:#0d0a0a;border-radius:2px 2px 0 0;color:#999;cursor:pointer;font-size:24px;height:39px;line-height:27px;padding:5px 0;position:absolute;right:20px;text-align:center;top:-39px;width:50px}.lg-outer .lg-toogle-thumb:after{content:"\e1ff"}.lg-outer .lg-toogle-thumb:hover{color:#fff}.lg-outer .lg-video-cont{max-width:1140px;max-height:100%;width:100%;padding:0 5px}.lg-outer .lg-video{width:100%;height:0;padding-bottom:56.25%;overflow:hidden;position:relative}.lg-outer .lg-video .lg-object{display:inline-block;position:absolute;top:0;left:0;width:100%!important;height:100%!important}.lg-outer .lg-video .lg-video-play{width:84px;height:59px;position:absolute;left:50%;top:50%;margin-left:-42px;margin-top:-30px;z-index:1080;cursor:pointer}.lg-outer .lg-has-vimeo .lg-video-play{background:url(img/vimeo-play.png) no-repeat}.lg-outer .lg-has-vimeo:hover .lg-video-play{background:url(img/vimeo-play.png) 0 -58px no-repeat}.lg-outer .lg-has-html5 .lg-video-play{background:url(img/video-play.png) no-repeat;height:64px;margin-left:-32px;margin-top:-32px;width:64px;opacity:.8}.lg-outer .lg-has-html5:hover .lg-video-play{opacity:1}.lg-outer .lg-has-youtube .lg-video-play{background:url(img/youtube-play.png) no-repeat}.lg-outer .lg-has-youtube:hover .lg-video-play{background:url(img/youtube-play.png) 0 -60px no-repeat}.lg-outer .lg-video-object{width:100%!important;height:100%!important;position:absolute;top:0;left:0}.lg-outer .lg-has-video .lg-video-object{visibility:hidden}.lg-outer .lg-has-video.lg-video-playing .lg-object,.lg-outer .lg-has-video.lg-video-playing .lg-video-play{display:none}.lg-outer .lg-has-video.lg-video-playing .lg-video-object{visibility:visible}.lg-progress-bar{background-color:#333;height:5px;left:0;position:absolute;top:0;width:100%;z-index:1083;opacity:0;-webkit-transition:opacity 80ms ease 0s;-o-transition:opacity 80ms ease 0s;transition:opacity 80ms ease 0s}.lg-progress-bar .lg-progress{background-color:#a90707;height:5px;width:0}.lg-progress-bar.lg-start .lg-progress{width:100%}.lg-show-autoplay .lg-progress-bar{opacity:1}.lg-autoplay-button:after{content:"\e01d"}.lg-show-autoplay .lg-autoplay-button:after{content:"\e01a"}.lg-outer.lg-css3.lg-zoom-dragging .lg-item.lg-complete.lg-zoomable .lg-image,.lg-outer.lg-css3.lg-zoom-dragging .lg-item.lg-complete.lg-zoomable .lg-img-wrap{-webkit-transition-duration:0s;-o-transition-duration:0s;transition-duration:0s}.lg-outer .lg-item.lg-complete.lg-zoomable .lg-img-wrap{-webkit-transition:left .3s cubic-bezier(0,0,.25,1) 0s,top .3s cubic-bezier(0,0,.25,1) 0s;-o-transition:left .3s cubic-bezier(0,0,.25,1) 0s,top .3s cubic-bezier(0,0,.25,1) 0s;transition:left .3s cubic-bezier(0,0,.25,1) 0s,top .3s cubic-bezier(0,0,.25,1) 0s;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-backface-visibility:hidden;backface-visibility:hidden}.lg-outer .lg-item.lg-complete.lg-zoomable .lg-image{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1);-webkit-transition:-webkit-transform .3s cubic-bezier(0,0,.25,1) 0s,opacity .15s!important;-o-transition:-o-transform .3s cubic-bezier(0,0,.25,1) 0s,opacity .15s!important;-webkit-transition:opacity .15s,-webkit-transform .3s cubic-bezier(0,0,.25,1) 0s!important;transition:opacity .15s,-webkit-transform .3s cubic-bezier(0,0,.25,1) 0s!important;-o-transition:transform .3s cubic-bezier(0,0,.25,1) 0s,opacity .15s!important;transition:transform .3s cubic-bezier(0,0,.25,1) 0s,opacity .15s!important;transition:transform .3s cubic-bezier(0,0,.25,1) 0s,opacity .15s,-webkit-transform .3s cubic-bezier(0,0,.25,1) 0s!important;-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;-webkit-backface-visibility:hidden;backface-visibility:hidden}#lg-zoom-in:after{content:"\e311"}#lg-actual-size{font-size:20px}#lg-actual-size:after{content:"\e033"}#lg-zoom-out{opacity:.5;pointer-events:none}#lg-zoom-out:after{content:"\e312"}.lg-zoomed #lg-zoom-out{opacity:1;pointer-events:auto}.lg-outer .lg-pager-outer{bottom:60px;left:0;position:absolute;right:0;text-align:center;z-index:1080;height:10px}.lg-outer .lg-pager-outer.lg-pager-hover .lg-pager-cont{overflow:visible}.lg-outer .lg-pager-cont{cursor:pointer;display:inline-block;overflow:hidden;position:relative;vertical-align:top;margin:0 5px}.lg-outer .lg-pager-cont:hover .lg-pager-thumb-cont{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.lg-outer .lg-pager-cont.lg-pager-active .lg-pager{-webkit-box-shadow:0 0 0 2px #fff inset;box-shadow:0 0 0 2px #fff inset}.lg-outer .lg-pager-thumb-cont{background-color:#fff;color:#fff;bottom:100%;height:83px;left:0;margin-bottom:20px;margin-left:-60px;opacity:0;padding:5px;position:absolute;width:120px;border-radius:3px;-webkit-transition:opacity .15s ease 0s,-webkit-transform .15s ease 0s;-o-transition:opacity .15s ease 0s,-o-transform .15s ease 0s;transition:opacity .15s ease 0s,-webkit-transform .15s ease 0s;-o-transition:opacity .15s ease 0s,transform .15s ease 0s;transition:opacity .15s ease 0s,transform .15s ease 0s;transition:opacity .15s ease 0s,transform .15s ease 0s,-webkit-transform .15s ease 0s;-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}.lg-outer .lg-pager-thumb-cont img{width:100%;height:100%}.lg-outer .lg-pager{background-color:rgba(255,255,255,.5);border-radius:50%;-webkit-box-shadow:0 0 0 8px rgba(255,255,255,.7) inset;box-shadow:0 0 0 8px rgba(255,255,255,.7) inset;display:block;height:12px;-webkit-transition:box-shadow .3s ease 0s;-o-transition:box-shadow .3s ease 0s;-webkit-transition:-webkit-box-shadow .3s ease 0s;transition:-webkit-box-shadow .3s ease 0s;transition:box-shadow .3s ease 0s;transition:box-shadow .3s ease 0s,-webkit-box-shadow .3s ease 0s;width:12px}.lg-outer .lg-pager:focus,.lg-outer .lg-pager:hover{-webkit-box-shadow:0 0 0 8px #fff inset;box-shadow:0 0 0 8px #fff inset}.lg-outer .lg-caret{border-left:10px solid transparent;border-right:10px solid transparent;border-top:10px dashed;bottom:-10px;display:inline-block;height:0;left:50%;margin-left:-5px;position:absolute;vertical-align:middle;width:0}.lg-outer,.lg-outer .lg,.lg-outer .lg-inner{width:100%;height:100%}.lg-fullscreen:after{content:"\e20c"}.lg-fullscreen-on .lg-fullscreen:after{content:"\e20d"}.group:after,.group:before{display:table;content:"";line-height:0}.group:after{clear:both}.lg-outer{position:fixed;top:0;left:0;z-index:1050;opacity:0;-webkit-transition:opacity .15s ease 0s;-o-transition:opacity .15s ease 0s;transition:opacity .15s ease 0s}.lg-outer *{-webkit-box-sizing:border-box;box-sizing:border-box}.lg-outer.lg-visible{opacity:1}.lg-outer.lg-css3 .lg-item.lg-current,.lg-outer.lg-css3 .lg-item.lg-next-slide,.lg-outer.lg-css3 .lg-item.lg-prev-slide{-webkit-transition-duration:inherit!important;-o-transition-duration:inherit!important;transition-duration:inherit!important;-webkit-transition-timing-function:inherit!important;-o-transition-timing-function:inherit!important;transition-timing-function:inherit!important}.lg-outer.lg-css3.lg-dragging .lg-item.lg-current,.lg-outer.lg-css3.lg-dragging .lg-item.lg-next-slide,.lg-outer.lg-css3.lg-dragging .lg-item.lg-prev-slide{-webkit-transition-duration:0s!important;-o-transition-duration:0s!important;transition-duration:0s!important;opacity:1}.lg-outer.lg-grab img.lg-object{cursor:-webkit-grab;cursor:-o-grab;cursor:-ms-grab;cursor:grab}.lg-outer.lg-grabbing img.lg-object{cursor:move;cursor:-webkit-grabbing;cursor:-o-grabbing;cursor:-ms-grabbing;cursor:grabbing}.lg-outer .lg{position:relative;overflow:hidden;margin-left:auto;margin-right:auto;max-width:100%;max-height:100%}.lg-outer .lg-inner{position:absolute;left:0;top:0;white-space:nowrap}.lg-outer .lg-item{background:url(img/loading.gif) center center no-repeat;display:none!important}.lg-outer.lg-css .lg-current,.lg-outer.lg-css3 .lg-current,.lg-outer.lg-css3 .lg-next-slide,.lg-outer.lg-css3 .lg-prev-slide{display:inline-block!important}.lg-outer .lg-img-wrap,.lg-outer .lg-item{display:inline-block;text-align:center;position:absolute;width:100%;height:100%}.lg-outer .lg-img-wrap:before,.lg-outer .lg-item:before{content:"";display:inline-block;height:50%;width:1px;margin-right:-1px}.lg-outer .lg-img-wrap{position:absolute;padding:0 5px;left:0;right:0;top:0;bottom:0}.lg-outer .lg-item.lg-complete{background-image:none}.lg-outer .lg-item.lg-current{z-index:1060}.lg-outer .lg-image{display:inline-block;vertical-align:middle;max-width:100%;max-height:100%;width:auto!important;height:auto!important}.lg-outer.lg-show-after-load .lg-item .lg-object,.lg-outer.lg-show-after-load .lg-item .lg-video-play{opacity:0;-webkit-transition:opacity .15s ease 0s;-o-transition:opacity .15s ease 0s;transition:opacity .15s ease 0s}.lg-outer.lg-show-after-load .lg-item.lg-complete .lg-object,.lg-outer.lg-show-after-load .lg-item.lg-complete .lg-video-play{opacity:1}.lg-outer .lg-empty-html,.lg-outer.lg-hide-download #lg-download{display:none}.lg-backdrop{position:fixed;top:0;left:0;right:0;bottom:0;z-index:1040;background-color:#000;opacity:0;-webkit-transition:opacity .15s ease 0s;-o-transition:opacity .15s ease 0s;transition:opacity .15s ease 0s}.lg-backdrop.in{opacity:1}.lg-css3.lg-no-trans .lg-current,.lg-css3.lg-no-trans .lg-next-slide,.lg-css3.lg-no-trans .lg-prev-slide{-webkit-transition:none 0s ease 0s!important;-o-transition:none 0s ease 0s!important;transition:none 0s ease 0s!important}.lg-css3.lg-use-css3 .lg-item,.lg-css3.lg-use-left .lg-item{-webkit-backface-visibility:hidden;backface-visibility:hidden}.lg-css3.lg-fade .lg-item{opacity:0}.lg-css3.lg-fade .lg-item.lg-current{opacity:1}.lg-css3.lg-fade .lg-item.lg-current,.lg-css3.lg-fade .lg-item.lg-next-slide,.lg-css3.lg-fade .lg-item.lg-prev-slide{-webkit-transition:opacity .1s ease 0s;-o-transition:opacity .1s ease 0s;transition:opacity .1s ease 0s}.lg-css3.lg-slide.lg-use-css3 .lg-item{opacity:0}.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-prev-slide{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-next-slide{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-current{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-current,.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-next-slide,.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide.lg-use-left .lg-item{opacity:0;position:absolute;left:0}.lg-css3.lg-slide.lg-use-left .lg-item.lg-prev-slide{left:-100%}.lg-css3.lg-slide.lg-use-left .lg-item.lg-next-slide{left:100%}.lg-css3.lg-slide.lg-use-left .lg-item.lg-current{left:0;opacity:1}.lg-css3.lg-slide.lg-use-left .lg-item.lg-current,.lg-css3.lg-slide.lg-use-left .lg-item.lg-next-slide,.lg-css3.lg-slide.lg-use-left .lg-item.lg-prev-slide{-webkit-transition:left 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:left 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:left 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s}.lg-css3.lg-zoom-in .lg-item{opacity:0}.lg-css3.lg-zoom-in .lg-item.lg-next-slide,.lg-css3.lg-zoom-in .lg-item.lg-prev-slide{-webkit-transform:scale3d(1.3,1.3,1.3);transform:scale3d(1.3,1.3,1.3)}.lg-css3.lg-zoom-in .lg-item.lg-current{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1);opacity:1}.lg-css3.lg-zoom-in .lg-item.lg-current,.lg-css3.lg-zoom-in .lg-item.lg-next-slide,.lg-css3.lg-zoom-in .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-zoom-in-big .lg-item{opacity:0}.lg-css3.lg-zoom-in-big .lg-item.lg-next-slide,.lg-css3.lg-zoom-in-big .lg-item.lg-prev-slide{-webkit-transform:scale3d(2,2,2);transform:scale3d(2,2,2)}.lg-css3.lg-zoom-in-big .lg-item.lg-current{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1);opacity:1}.lg-css3.lg-zoom-in-big .lg-item.lg-current,.lg-css3.lg-zoom-in-big .lg-item.lg-next-slide,.lg-css3.lg-zoom-in-big .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-zoom-out .lg-item{opacity:0}.lg-css3.lg-zoom-out .lg-item.lg-next-slide,.lg-css3.lg-zoom-out .lg-item.lg-prev-slide{-webkit-transform:scale3d(.7,.7,.7);transform:scale3d(.7,.7,.7)}.lg-css3.lg-zoom-out .lg-item.lg-current{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1);opacity:1}.lg-css3.lg-zoom-out .lg-item.lg-current,.lg-css3.lg-zoom-out .lg-item.lg-next-slide,.lg-css3.lg-zoom-out .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-zoom-out-big .lg-item{opacity:0}.lg-css3.lg-zoom-out-big .lg-item.lg-next-slide,.lg-css3.lg-zoom-out-big .lg-item.lg-prev-slide{-webkit-transform:scale3d(0,0,0);transform:scale3d(0,0,0)}.lg-css3.lg-zoom-out-big .lg-item.lg-current{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1);opacity:1}.lg-css3.lg-zoom-out-big .lg-item.lg-current,.lg-css3.lg-zoom-out-big .lg-item.lg-next-slide,.lg-css3.lg-zoom-out-big .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-zoom-out-in .lg-item{opacity:0}.lg-css3.lg-zoom-out-in .lg-item.lg-prev-slide{-webkit-transform:scale3d(0,0,0);transform:scale3d(0,0,0)}.lg-css3.lg-zoom-out-in .lg-item.lg-next-slide{-webkit-transform:scale3d(2,2,2);transform:scale3d(2,2,2)}.lg-css3.lg-zoom-out-in .lg-item.lg-current{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1);opacity:1}.lg-css3.lg-zoom-out-in .lg-item.lg-current,.lg-css3.lg-zoom-out-in .lg-item.lg-next-slide,.lg-css3.lg-zoom-out-in .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-zoom-in-out .lg-item{opacity:0}.lg-css3.lg-zoom-in-out .lg-item.lg-prev-slide{-webkit-transform:scale3d(2,2,2);transform:scale3d(2,2,2)}.lg-css3.lg-zoom-in-out .lg-item.lg-next-slide{-webkit-transform:scale3d(0,0,0);transform:scale3d(0,0,0)}.lg-css3.lg-zoom-in-out .lg-item.lg-current{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1);opacity:1}.lg-css3.lg-zoom-in-out .lg-item.lg-current,.lg-css3.lg-zoom-in-out .lg-item.lg-next-slide,.lg-css3.lg-zoom-in-out .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-soft-zoom .lg-item{opacity:0}.lg-css3.lg-soft-zoom .lg-item.lg-prev-slide{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}.lg-css3.lg-soft-zoom .lg-item.lg-next-slide{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}.lg-css3.lg-soft-zoom .lg-item.lg-current{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1);opacity:1}.lg-css3.lg-soft-zoom .lg-item.lg-current,.lg-css3.lg-soft-zoom .lg-item.lg-next-slide,.lg-css3.lg-soft-zoom .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-scale-up .lg-item{opacity:0}.lg-css3.lg-scale-up .lg-item.lg-next-slide,.lg-css3.lg-scale-up .lg-item.lg-prev-slide{-ms-transform:scale3d(.8,.8,.8) translate3d(0,10%,0);-webkit-transform:scale3d(.8,.8,.8) translate3d(0,10%,0);transform:scale3d(.8,.8,.8) translate3d(0,10%,0)}.lg-css3.lg-scale-up .lg-item.lg-current{-ms-transform:scale3d(1,1,1) translate3d(0,0,0);-webkit-transform:scale3d(1,1,1) translate3d(0,0,0);transform:scale3d(1,1,1) translate3d(0,0,0);opacity:1}.lg-css3.lg-scale-up .lg-item.lg-current,.lg-css3.lg-scale-up .lg-item.lg-next-slide,.lg-css3.lg-scale-up .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-circular .lg-item{opacity:0}.lg-css3.lg-slide-circular .lg-item.lg-prev-slide{-ms-transform:scale3d(0,0,0) translate3d(-100%,0,0);-webkit-transform:scale3d(0,0,0) translate3d(-100%,0,0);transform:scale3d(0,0,0) translate3d(-100%,0,0)}.lg-css3.lg-slide-circular .lg-item.lg-next-slide{-ms-transform:scale3d(0,0,0) translate3d(100%,0,0);-webkit-transform:scale3d(0,0,0) translate3d(100%,0,0);transform:scale3d(0,0,0) translate3d(100%,0,0)}.lg-css3.lg-slide-circular .lg-item.lg-current{-ms-transform:scale3d(1,1,1) translate3d(0,0,0);-webkit-transform:scale3d(1,1,1) translate3d(0,0,0);transform:scale3d(1,1,1) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-circular .lg-item.lg-current,.lg-css3.lg-slide-circular .lg-item.lg-next-slide,.lg-css3.lg-slide-circular .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-circular-up .lg-item{opacity:0}.lg-css3.lg-slide-circular-up .lg-item.lg-prev-slide{-ms-transform:scale3d(0,0,0) translate3d(-100%,-100%,0);-webkit-transform:scale3d(0,0,0) translate3d(-100%,-100%,0);transform:scale3d(0,0,0) translate3d(-100%,-100%,0)}.lg-css3.lg-slide-circular-up .lg-item.lg-next-slide{-ms-transform:scale3d(0,0,0) translate3d(100%,-100%,0);-webkit-transform:scale3d(0,0,0) translate3d(100%,-100%,0);transform:scale3d(0,0,0) translate3d(100%,-100%,0)}.lg-css3.lg-slide-circular-up .lg-item.lg-current{-ms-transform:scale3d(1,1,1) translate3d(0,0,0);-webkit-transform:scale3d(1,1,1) translate3d(0,0,0);transform:scale3d(1,1,1) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-circular-up .lg-item.lg-current,.lg-css3.lg-slide-circular-up .lg-item.lg-next-slide,.lg-css3.lg-slide-circular-up .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-circular-down .lg-item{opacity:0}.lg-css3.lg-slide-circular-down .lg-item.lg-prev-slide{-ms-transform:scale3d(0,0,0) translate3d(-100%,100%,0);-webkit-transform:scale3d(0,0,0) translate3d(-100%,100%,0);transform:scale3d(0,0,0) translate3d(-100%,100%,0)}.lg-css3.lg-slide-circular-down .lg-item.lg-next-slide{-ms-transform:scale3d(0,0,0) translate3d(100%,100%,0);-webkit-transform:scale3d(0,0,0) translate3d(100%,100%,0);transform:scale3d(0,0,0) translate3d(100%,100%,0)}.lg-css3.lg-slide-circular-down .lg-item.lg-current{-ms-transform:scale3d(1,1,1) translate3d(0,0,0);-webkit-transform:scale3d(1,1,1) translate3d(0,0,0);transform:scale3d(1,1,1) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-circular-down .lg-item.lg-current,.lg-css3.lg-slide-circular-down .lg-item.lg-next-slide,.lg-css3.lg-slide-circular-down .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-circular-vertical .lg-item{opacity:0}.lg-css3.lg-slide-circular-vertical .lg-item.lg-prev-slide{-ms-transform:scale3d(0,0,0) translate3d(0,-100%,0);-webkit-transform:scale3d(0,0,0) translate3d(0,-100%,0);transform:scale3d(0,0,0) translate3d(0,-100%,0)}.lg-css3.lg-slide-circular-vertical .lg-item.lg-next-slide{-ms-transform:scale3d(0,0,0) translate3d(0,100%,0);-webkit-transform:scale3d(0,0,0) translate3d(0,100%,0);transform:scale3d(0,0,0) translate3d(0,100%,0)}.lg-css3.lg-slide-circular-vertical .lg-item.lg-current{-ms-transform:scale3d(1,1,1) translate3d(0,0,0);-webkit-transform:scale3d(1,1,1) translate3d(0,0,0);transform:scale3d(1,1,1) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-circular-vertical .lg-item.lg-current,.lg-css3.lg-slide-circular-vertical .lg-item.lg-next-slide,.lg-css3.lg-slide-circular-vertical .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-circular-vertical-left .lg-item{opacity:0}.lg-css3.lg-slide-circular-vertical-left .lg-item.lg-prev-slide{-ms-transform:scale3d(0,0,0) translate3d(-100%,-100%,0);-webkit-transform:scale3d(0,0,0) translate3d(-100%,-100%,0);transform:scale3d(0,0,0) translate3d(-100%,-100%,0)}.lg-css3.lg-slide-circular-vertical-left .lg-item.lg-next-slide{-ms-transform:scale3d(0,0,0) translate3d(-100%,100%,0);-webkit-transform:scale3d(0,0,0) translate3d(-100%,100%,0);transform:scale3d(0,0,0) translate3d(-100%,100%,0)}.lg-css3.lg-slide-circular-vertical-left .lg-item.lg-current{-ms-transform:scale3d(1,1,1) translate3d(0,0,0);-webkit-transform:scale3d(1,1,1) translate3d(0,0,0);transform:scale3d(1,1,1) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-circular-vertical-left .lg-item.lg-current,.lg-css3.lg-slide-circular-vertical-left .lg-item.lg-next-slide,.lg-css3.lg-slide-circular-vertical-left .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-circular-vertical-down .lg-item{opacity:0}.lg-css3.lg-slide-circular-vertical-down .lg-item.lg-prev-slide{-ms-transform:scale3d(0,0,0) translate3d(100%,-100%,0);-webkit-transform:scale3d(0,0,0) translate3d(100%,-100%,0);transform:scale3d(0,0,0) translate3d(100%,-100%,0)}.lg-css3.lg-slide-circular-vertical-down .lg-item.lg-next-slide{-ms-transform:scale3d(0,0,0) translate3d(100%,100%,0);-webkit-transform:scale3d(0,0,0) translate3d(100%,100%,0);transform:scale3d(0,0,0) translate3d(100%,100%,0)}.lg-css3.lg-slide-circular-vertical-down .lg-item.lg-current{-ms-transform:scale3d(1,1,1) translate3d(0,0,0);-webkit-transform:scale3d(1,1,1) translate3d(0,0,0);transform:scale3d(1,1,1) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-circular-vertical-down .lg-item.lg-current,.lg-css3.lg-slide-circular-vertical-down .lg-item.lg-next-slide,.lg-css3.lg-slide-circular-vertical-down .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;-webkit-transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity 1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-vertical .lg-item{opacity:0}.lg-css3.lg-slide-vertical .lg-item.lg-prev-slide{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}.lg-css3.lg-slide-vertical .lg-item.lg-next-slide{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}.lg-css3.lg-slide-vertical .lg-item.lg-current{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-vertical .lg-item.lg-current,.lg-css3.lg-slide-vertical .lg-item.lg-next-slide,.lg-css3.lg-slide-vertical .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-vertical-growth .lg-item{opacity:0}.lg-css3.lg-slide-vertical-growth .lg-item.lg-prev-slide{-ms-transform:scale3d(.5,.5,.5) translate3d(0,-150%,0);-webkit-transform:scale3d(.5,.5,.5) translate3d(0,-150%,0);transform:scale3d(.5,.5,.5) translate3d(0,-150%,0)}.lg-css3.lg-slide-vertical-growth .lg-item.lg-next-slide{-ms-transform:scale3d(.5,.5,.5) translate3d(0,150%,0);-webkit-transform:scale3d(.5,.5,.5) translate3d(0,150%,0);transform:scale3d(.5,.5,.5) translate3d(0,150%,0)}.lg-css3.lg-slide-vertical-growth .lg-item.lg-current{-ms-transform:scale3d(1,1,1) translate3d(0,0,0);-webkit-transform:scale3d(1,1,1) translate3d(0,0,0);transform:scale3d(1,1,1) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-vertical-growth .lg-item.lg-current,.lg-css3.lg-slide-vertical-growth .lg-item.lg-next-slide,.lg-css3.lg-slide-vertical-growth .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew-only .lg-item{opacity:0}.lg-css3.lg-slide-skew-only .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-only .lg-item.lg-prev-slide{-ms-transform:skew(10deg,0deg);-webkit-transform:skew(10deg,0deg);transform:skew(10deg,0deg)}.lg-css3.lg-slide-skew-only .lg-item.lg-current{-ms-transform:skew(0deg,0deg);-webkit-transform:skew(0deg,0deg);transform:skew(0deg,0deg);opacity:1}.lg-css3.lg-slide-skew-only .lg-item.lg-current,.lg-css3.lg-slide-skew-only .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-only .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew-only-rev .lg-item{opacity:0}.lg-css3.lg-slide-skew-only-rev .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-only-rev .lg-item.lg-prev-slide{-ms-transform:skew(-10deg,0deg);-webkit-transform:skew(-10deg,0deg);transform:skew(-10deg,0deg)}.lg-css3.lg-slide-skew-only-rev .lg-item.lg-current{-ms-transform:skew(0deg,0deg);-webkit-transform:skew(0deg,0deg);transform:skew(0deg,0deg);opacity:1}.lg-css3.lg-slide-skew-only-rev .lg-item.lg-current,.lg-css3.lg-slide-skew-only-rev .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-only-rev .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew-only-y .lg-item{opacity:0}.lg-css3.lg-slide-skew-only-y .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-only-y .lg-item.lg-prev-slide{-ms-transform:skew(0deg,10deg);-webkit-transform:skew(0deg,10deg);transform:skew(0deg,10deg)}.lg-css3.lg-slide-skew-only-y .lg-item.lg-current{-ms-transform:skew(0deg,0deg);-webkit-transform:skew(0deg,0deg);transform:skew(0deg,0deg);opacity:1}.lg-css3.lg-slide-skew-only-y .lg-item.lg-current,.lg-css3.lg-slide-skew-only-y .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-only-y .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew-only-y-rev .lg-item{opacity:0}.lg-css3.lg-slide-skew-only-y-rev .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-only-y-rev .lg-item.lg-prev-slide{-ms-transform:skew(0deg,-10deg);-webkit-transform:skew(0deg,-10deg);transform:skew(0deg,-10deg)}.lg-css3.lg-slide-skew-only-y-rev .lg-item.lg-current{-ms-transform:skew(0deg,0deg);-webkit-transform:skew(0deg,0deg);transform:skew(0deg,0deg);opacity:1}.lg-css3.lg-slide-skew-only-y-rev .lg-item.lg-current,.lg-css3.lg-slide-skew-only-y-rev .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-only-y-rev .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew .lg-item{opacity:0}.lg-css3.lg-slide-skew .lg-item.lg-prev-slide{-ms-transform:skew(20deg,0deg) translate3d(-100%,0,0);-webkit-transform:skew(20deg,0deg) translate3d(-100%,0,0);transform:skew(20deg,0deg) translate3d(-100%,0,0)}.lg-css3.lg-slide-skew .lg-item.lg-next-slide{-ms-transform:skew(20deg,0deg) translate3d(100%,0,0);-webkit-transform:skew(20deg,0deg) translate3d(100%,0,0);transform:skew(20deg,0deg) translate3d(100%,0,0)}.lg-css3.lg-slide-skew .lg-item.lg-current{-ms-transform:skew(0deg,0deg) translate3d(0,0,0);-webkit-transform:skew(0deg,0deg) translate3d(0,0,0);transform:skew(0deg,0deg) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-skew .lg-item.lg-current,.lg-css3.lg-slide-skew .lg-item.lg-next-slide,.lg-css3.lg-slide-skew .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew-rev .lg-item{opacity:0}.lg-css3.lg-slide-skew-rev .lg-item.lg-prev-slide{-ms-transform:skew(-20deg,0deg) translate3d(-100%,0,0);-webkit-transform:skew(-20deg,0deg) translate3d(-100%,0,0);transform:skew(-20deg,0deg) translate3d(-100%,0,0)}.lg-css3.lg-slide-skew-rev .lg-item.lg-next-slide{-ms-transform:skew(-20deg,0deg) translate3d(100%,0,0);-webkit-transform:skew(-20deg,0deg) translate3d(100%,0,0);transform:skew(-20deg,0deg) translate3d(100%,0,0)}.lg-css3.lg-slide-skew-rev .lg-item.lg-current{-ms-transform:skew(0deg,0deg) translate3d(0,0,0);-webkit-transform:skew(0deg,0deg) translate3d(0,0,0);transform:skew(0deg,0deg) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-skew-rev .lg-item.lg-current,.lg-css3.lg-slide-skew-rev .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-rev .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew-cross .lg-item{opacity:0}.lg-css3.lg-slide-skew-cross .lg-item.lg-prev-slide{-ms-transform:skew(0deg,60deg) translate3d(-100%,0,0);-webkit-transform:skew(0deg,60deg) translate3d(-100%,0,0);transform:skew(0deg,60deg) translate3d(-100%,0,0)}.lg-css3.lg-slide-skew-cross .lg-item.lg-next-slide{-ms-transform:skew(0deg,60deg) translate3d(100%,0,0);-webkit-transform:skew(0deg,60deg) translate3d(100%,0,0);transform:skew(0deg,60deg) translate3d(100%,0,0)}.lg-css3.lg-slide-skew-cross .lg-item.lg-current{-ms-transform:skew(0deg,0deg) translate3d(0,0,0);-webkit-transform:skew(0deg,0deg) translate3d(0,0,0);transform:skew(0deg,0deg) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-skew-cross .lg-item.lg-current,.lg-css3.lg-slide-skew-cross .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-cross .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew-cross-rev .lg-item{opacity:0}.lg-css3.lg-slide-skew-cross-rev .lg-item.lg-prev-slide{-ms-transform:skew(0deg,-60deg) translate3d(-100%,0,0);-webkit-transform:skew(0deg,-60deg) translate3d(-100%,0,0);transform:skew(0deg,-60deg) translate3d(-100%,0,0)}.lg-css3.lg-slide-skew-cross-rev .lg-item.lg-next-slide{-ms-transform:skew(0deg,-60deg) translate3d(100%,0,0);-webkit-transform:skew(0deg,-60deg) translate3d(100%,0,0);transform:skew(0deg,-60deg) translate3d(100%,0,0)}.lg-css3.lg-slide-skew-cross-rev .lg-item.lg-current{-ms-transform:skew(0deg,0deg) translate3d(0,0,0);-webkit-transform:skew(0deg,0deg) translate3d(0,0,0);transform:skew(0deg,0deg) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-skew-cross-rev .lg-item.lg-current,.lg-css3.lg-slide-skew-cross-rev .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-cross-rev .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew-ver .lg-item{opacity:0}.lg-css3.lg-slide-skew-ver .lg-item.lg-prev-slide{-ms-transform:skew(60deg,0deg) translate3d(0,-100%,0);-webkit-transform:skew(60deg,0deg) translate3d(0,-100%,0);transform:skew(60deg,0deg) translate3d(0,-100%,0)}.lg-css3.lg-slide-skew-ver .lg-item.lg-next-slide{-ms-transform:skew(60deg,0deg) translate3d(0,100%,0);-webkit-transform:skew(60deg,0deg) translate3d(0,100%,0);transform:skew(60deg,0deg) translate3d(0,100%,0)}.lg-css3.lg-slide-skew-ver .lg-item.lg-current{-ms-transform:skew(0deg,0deg) translate3d(0,0,0);-webkit-transform:skew(0deg,0deg) translate3d(0,0,0);transform:skew(0deg,0deg) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-skew-ver .lg-item.lg-current,.lg-css3.lg-slide-skew-ver .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-ver .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew-ver-rev .lg-item{opacity:0}.lg-css3.lg-slide-skew-ver-rev .lg-item.lg-prev-slide{-ms-transform:skew(-60deg,0deg) translate3d(0,-100%,0);-webkit-transform:skew(-60deg,0deg) translate3d(0,-100%,0);transform:skew(-60deg,0deg) translate3d(0,-100%,0)}.lg-css3.lg-slide-skew-ver-rev .lg-item.lg-next-slide{-ms-transform:skew(-60deg,0deg) translate3d(0,100%,0);-webkit-transform:skew(-60deg,0deg) translate3d(0,100%,0);transform:skew(-60deg,0deg) translate3d(0,100%,0)}.lg-css3.lg-slide-skew-ver-rev .lg-item.lg-current{-ms-transform:skew(0deg,0deg) translate3d(0,0,0);-webkit-transform:skew(0deg,0deg) translate3d(0,0,0);transform:skew(0deg,0deg) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-skew-ver-rev .lg-item.lg-current,.lg-css3.lg-slide-skew-ver-rev .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-ver-rev .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew-ver-cross .lg-item{opacity:0}.lg-css3.lg-slide-skew-ver-cross .lg-item.lg-prev-slide{-ms-transform:skew(0deg,20deg) translate3d(0,-100%,0);-webkit-transform:skew(0deg,20deg) translate3d(0,-100%,0);transform:skew(0deg,20deg) translate3d(0,-100%,0)}.lg-css3.lg-slide-skew-ver-cross .lg-item.lg-next-slide{-ms-transform:skew(0deg,20deg) translate3d(0,100%,0);-webkit-transform:skew(0deg,20deg) translate3d(0,100%,0);transform:skew(0deg,20deg) translate3d(0,100%,0)}.lg-css3.lg-slide-skew-ver-cross .lg-item.lg-current{-ms-transform:skew(0deg,0deg) translate3d(0,0,0);-webkit-transform:skew(0deg,0deg) translate3d(0,0,0);transform:skew(0deg,0deg) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-skew-ver-cross .lg-item.lg-current,.lg-css3.lg-slide-skew-ver-cross .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-ver-cross .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-slide-skew-ver-cross-rev .lg-item{opacity:0}.lg-css3.lg-slide-skew-ver-cross-rev .lg-item.lg-prev-slide{-ms-transform:skew(0deg,-20deg) translate3d(0,-100%,0);-webkit-transform:skew(0deg,-20deg) translate3d(0,-100%,0);transform:skew(0deg,-20deg) translate3d(0,-100%,0)}.lg-css3.lg-slide-skew-ver-cross-rev .lg-item.lg-next-slide{-ms-transform:skew(0deg,-20deg) translate3d(0,100%,0);-webkit-transform:skew(0deg,-20deg) translate3d(0,100%,0);transform:skew(0deg,-20deg) translate3d(0,100%,0)}.lg-css3.lg-slide-skew-ver-cross-rev .lg-item.lg-current{-ms-transform:skew(0deg,0deg) translate3d(0,0,0);-webkit-transform:skew(0deg,0deg) translate3d(0,0,0);transform:skew(0deg,0deg) translate3d(0,0,0);opacity:1}.lg-css3.lg-slide-skew-ver-cross-rev .lg-item.lg-current,.lg-css3.lg-slide-skew-ver-cross-rev .lg-item.lg-next-slide,.lg-css3.lg-slide-skew-ver-cross-rev .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-lollipop .lg-item{opacity:0}.lg-css3.lg-lollipop .lg-item.lg-prev-slide{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.lg-css3.lg-lollipop .lg-item.lg-next-slide{-ms-transform:translate3d(0,0,0) scale(.5);-webkit-transform:translate3d(0,0,0) scale(.5);transform:translate3d(0,0,0) scale(.5)}.lg-css3.lg-lollipop .lg-item.lg-current{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}.lg-css3.lg-lollipop .lg-item.lg-current,.lg-css3.lg-lollipop .lg-item.lg-next-slide,.lg-css3.lg-lollipop .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-lollipop-rev .lg-item{opacity:0}.lg-css3.lg-lollipop-rev .lg-item.lg-prev-slide{-ms-transform:translate3d(0,0,0) scale(.5);-webkit-transform:translate3d(0,0,0) scale(.5);transform:translate3d(0,0,0) scale(.5)}.lg-css3.lg-lollipop-rev .lg-item.lg-next-slide{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.lg-css3.lg-lollipop-rev .lg-item.lg-current{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}.lg-css3.lg-lollipop-rev .lg-item.lg-current,.lg-css3.lg-lollipop-rev .lg-item.lg-next-slide,.lg-css3.lg-lollipop-rev .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-rotate .lg-item{opacity:0}.lg-css3.lg-rotate .lg-item.lg-prev-slide{-ms-transform:rotate(-360deg);-webkit-transform:rotate(-360deg);transform:rotate(-360deg)}.lg-css3.lg-rotate .lg-item.lg-next-slide{-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg);transform:rotate(360deg)}.lg-css3.lg-rotate .lg-item.lg-current{-ms-transform:rotate(0);-webkit-transform:rotate(0);transform:rotate(0);opacity:1}.lg-css3.lg-rotate .lg-item.lg-current,.lg-css3.lg-rotate .lg-item.lg-next-slide,.lg-css3.lg-rotate .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-rotate-rev .lg-item{opacity:0}.lg-css3.lg-rotate-rev .lg-item.lg-prev-slide{-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg);transform:rotate(360deg)}.lg-css3.lg-rotate-rev .lg-item.lg-next-slide{-ms-transform:rotate(-360deg);-webkit-transform:rotate(-360deg);transform:rotate(-360deg)}.lg-css3.lg-rotate-rev .lg-item.lg-current{-ms-transform:rotate(0);-webkit-transform:rotate(0);transform:rotate(0);opacity:1}.lg-css3.lg-rotate-rev .lg-item.lg-current,.lg-css3.lg-rotate-rev .lg-item.lg-next-slide,.lg-css3.lg-rotate-rev .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.lg-css3.lg-tube .lg-item{opacity:0}.lg-css3.lg-tube .lg-item.lg-prev-slide{-ms-transform:scale3d(1,0,1) translate3d(-100%,0,0);-webkit-transform:scale3d(1,0,1) translate3d(-100%,0,0);transform:scale3d(1,0,1) translate3d(-100%,0,0)}.lg-css3.lg-tube .lg-item.lg-next-slide{-ms-transform:scale3d(1,0,1) translate3d(100%,0,0);-webkit-transform:scale3d(1,0,1) translate3d(100%,0,0);transform:scale3d(1,0,1) translate3d(100%,0,0)}.lg-css3.lg-tube .lg-item.lg-current{-ms-transform:scale3d(1,1,1) translate3d(0,0,0);-webkit-transform:scale3d(1,1,1) translate3d(0,0,0);transform:scale3d(1,1,1) translate3d(0,0,0);opacity:1}.lg-css3.lg-tube .lg-item.lg-current,.lg-css3.lg-tube .lg-item.lg-next-slide,.lg-css3.lg-tube .lg-item.lg-prev-slide{-webkit-transition:-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-o-transition:-o-transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;-webkit-transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;transition:opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s;-o-transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s;transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s,-webkit-transform 1s cubic-bezier(0,0,.25,1) 0s}.progressjs-inner{width:0}.progressjs-progress{z-index:9999999}.progressjs-theme-blue .progressjs-inner{height:2px;-webkit-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db}.progressjs-theme-blue.progressjs-end{-webkit-transition:opacity .2s ease-out;-o-transition:opacity .2s ease-out;transition:opacity .2s ease-out;opacity:0}.progressjs-theme-blue .progressjs-percent{display:none}.progressjs-theme-blueOverlay{background-color:#fff;-webkit-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out}.progressjs-theme-blueOverlay .progressjs-inner{height:100%;-webkit-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db}.progressjs-theme-blueOverlay.progressjs-end{opacity:0!important}.progressjs-theme-blueOverlay .progressjs-percent{display:none}.progressjs-theme-blueOverlay{background-color:#fff;-webkit-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out}.progressjs-theme-blueOverlay .progressjs-inner{height:100%;-webkit-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db}.progressjs-theme-blueOverlay.progressjs-end{opacity:0!important}.progressjs-theme-blueOverlay .progressjs-percent{display:none}.progressjs-theme-blueOverlayRadius{background-color:#fff;-webkit-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out;border-radius:5px}.progressjs-theme-blueOverlayRadius .progressjs-inner{height:100%;-webkit-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db;border-radius:5px}.progressjs-theme-blueOverlayRadius.progressjs-end{opacity:0!important}.progressjs-theme-blueOverlayRadius .progressjs-percent{display:none}.progressjs-theme-blueOverlayRadiusHalfOpacity{background-color:#fff;opacity:.5;-webkit-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out;border-radius:5px}.progressjs-theme-blueOverlayRadiusHalfOpacity .progressjs-inner{height:100%;-webkit-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db;border-radius:5px}.progressjs-theme-blueOverlayRadiusHalfOpacity.progressjs-end{opacity:0!important}.progressjs-theme-blueOverlayRadiusHalfOpacity .progressjs-percent{display:none}.progressjs-theme-blueOverlayRadiusWithPercentBar{background-color:#fff;-webkit-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out;border-radius:5px}.progressjs-theme-blueOverlayRadiusWithPercentBar .progressjs-inner{height:100%;-webkit-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db;border-radius:5px}.progressjs-theme-blueOverlayRadiusWithPercentBar.progressjs-end{opacity:0!important}.progressjs-theme-blueOverlayRadiusWithPercentBar .progressjs-percent{width:70px;text-align:center;height:40px;position:absolute;right:50%;margin-right:-35px;top:50%;margin-top:-20px;font-size:30px;opacity:.5}.progressjs-theme-blackRadiusInputs{height:10px;border-radius:10px;overflow:hidden}.progressjs-theme-blackRadiusInputs .progressjs-inner{height:2px;-webkit-transition:all 1s ease-out;-o-transition:all 1s ease-out;transition:all 1s ease-out;background-color:#34495e}.progressjs-theme-blackRadiusInputs.progressjs-end{-webkit-transition:opacity .2s ease-out;-o-transition:opacity .2s ease-out;transition:opacity .2s ease-out;opacity:0}.progressjs-theme-blackRadiusInputs .progressjs-percent{display:none}.progressjs-theme-rainloop{z-index:2000}.progressjs-theme-rainloop .progressjs-inner{background-color:#939595;position:relative;z-index:2000;height:3px;overflow:hidden;-webkit-transition:width .5s;-o-transition:width .5s;transition:width .5s}.progressjs-theme-rainloop .progressjs-percent{position:absolute;top:0;left:0;right:-32px;bottom:0;background-image:-o-linear-gradient(45deg,rgba(255,255,255,.3) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.3) 50%,rgba(255,255,255,.3) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.3) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.3) 50%,rgba(255,255,255,.3) 75%,transparent 75%,transparent);background-size:32px 32px;-webkit-animation:simple-pace-stripe-animation .5s linear infinite;animation:simple-pace-stripe-animation .5s linear infinite}@-webkit-keyframes simple-pace-stripe-animation{0%{-webkit-transform:none;transform:none}100%{-webkit-transform:translate(-32px,0);transform:translate(-32px,0)}}@keyframes simple-pace-stripe-animation{0%{-webkit-transform:none;transform:none;transform:none}100%{-webkit-transform:translate(-32px,0);transform:translate(-32px,0);transform:translate(-32px,0)}}.clearfix:after,.clearfix:before{display:table;content:"";line-height:0}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.img-rounded{border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,.1);box-shadow:0 1px 3px rgba(0,0,0,.1)}.img-circle{border-radius:500px}.row{margin-left:-20px}.row:after,.row:before{display:table;content:"";line-height:0}.row:after{clear:both}[class*=span]{float:left;margin-left:20px}.container,.navbar-fixed-bottom .container,.navbar-fixed-top .container,.navbar-static-top .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%}.row-fluid:after,.row-fluid:before{display:table;content:"";line-height:0}.row-fluid:after{clear:both}.row-fluid [class*=span]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.12765957%}.row-fluid [class*=span]:first-child{margin-left:0}.row-fluid .span12{width:100%}.row-fluid .span11{width:91.4893617%}.row-fluid .span10{width:82.9787234%}.row-fluid .span9{width:74.46808511%}.row-fluid .span8{width:65.95744681%}.row-fluid .span7{width:57.44680851%}.row-fluid .span6{width:48.93617021%}.row-fluid .span5{width:40.42553191%}.row-fluid .span4{width:31.91489362%}.row-fluid .span3{width:23.40425532%}.row-fluid .span2{width:14.89361702%}.row-fluid .span1{width:6.38297872%}.row-fluid .offset12{margin-left:104.25531915%}.row-fluid .offset12:first-child{margin-left:102.12765957%}.row-fluid .offset11{margin-left:95.74468085%}.row-fluid .offset11:first-child{margin-left:93.61702128%}.row-fluid .offset10{margin-left:87.23404255%}.row-fluid .offset10:first-child{margin-left:85.10638298%}.row-fluid .offset9{margin-left:78.72340426%}.row-fluid .offset9:first-child{margin-left:76.59574468%}.row-fluid .offset8{margin-left:70.21276596%}.row-fluid .offset8:first-child{margin-left:68.08510638%}.row-fluid .offset7{margin-left:61.70212766%}.row-fluid .offset7:first-child{margin-left:59.57446809%}.row-fluid .offset6{margin-left:53.19148936%}.row-fluid .offset6:first-child{margin-left:51.06382979%}.row-fluid .offset5{margin-left:44.68085106%}.row-fluid .offset5:first-child{margin-left:42.55319149%}.row-fluid .offset4{margin-left:36.17021277%}.row-fluid .offset4:first-child{margin-left:34.04255319%}.row-fluid .offset3{margin-left:27.65957447%}.row-fluid .offset3:first-child{margin-left:25.53191489%}.row-fluid .offset2{margin-left:19.14893617%}.row-fluid .offset2:first-child{margin-left:17.0212766%}.row-fluid .offset1{margin-left:10.63829787%}.row-fluid .offset1:first-child{margin-left:8.5106383%}.row-fluid [class*=span].hide,[class*=span].hide{display:none}.row-fluid [class*=span].pull-right,[class*=span].pull-right{float:right}.container{margin-right:auto;margin-left:auto}.container:after,.container:before{display:table;content:"";line-height:0}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px}.container-fluid:after,.container-fluid:before{display:table;content:"";line-height:0}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:20px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:700}em{font-style:italic}cite{font-style:normal}.muted{color:#999}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:700;line-height:1;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:400;line-height:1;color:#999}h1{font-size:36px;line-height:40px}h2{font-size:30px;line-height:40px}h3{font-size:24px;line-height:40px}h4{font-size:18px;line-height:20px}h5{font-size:14px;line-height:20px}h6{font-size:12px;line-height:20px}h1 small{font-size:24px}h2 small{font-size:18px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ol,ul{padding:0;margin:0 0 10px 25px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}li{line-height:20px}ol.unstyled,ul.unstyled{margin-left:0;list-style:none}dl{margin-bottom:20px}dd,dt{line-height:20px}dt{font-weight:700}dd{margin-left:10px}.dl-horizontal dt{float:left;width:120px;clear:left;text-align:right;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:130px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}blockquote:after,blockquote:before,q:after,q:before{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;border-radius:3px}code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}button,input,label,select,textarea{font-size:14px;font-weight:400;line-height:20px}button,input,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}.uneditable-input,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{display:inline-block;height:20px;padding:4px 6px;margin-bottom:9px;font-size:14px;line-height:20px;color:#555;border-radius:3px}input,textarea{width:210px}textarea{height:auto}.uneditable-input,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],textarea{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;-webkit-transition:border linear .2s,-webkit-box-shadow linear .2s;transition:border linear .2s,-webkit-box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s,-webkit-box-shadow linear .2s}.uneditable-input:focus,input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus,textarea:focus{border-color:rgba(82,168,236,.8);outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.6)}input[type=checkbox],input[type=radio]{margin:4px 0 0;line-height:normal;cursor:pointer}input[type=button],input[type=checkbox],input[type=file],input[type=image],input[type=radio],input[type=reset],input[type=submit]{width:auto}input[type=file],select{height:30px;line-height:30px}select{width:220px;border:1px solid #bbb;background-color:#fff}select[multiple],select[size]{height:auto}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus,select:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.025);box-shadow:inset 0 1px 2px rgba(0,0,0,.025);cursor:not-allowed}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.checkbox,.radio{min-height:18px;padding-left:18px}.checkbox input[type=checkbox],.radio input[type=radio]{float:left;margin-left:-18px}.controls>.checkbox:first-child,.controls>.radio:first-child{padding-top:5px}.checkbox.inline,.radio.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.checkbox.inline+.checkbox.inline,.radio.inline+.radio.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}.row-fluid .uneditable-input[class*=span],.row-fluid input[class*=span],.row-fluid select[class*=span],.row-fluid textarea[class*=span],.uneditable-input[class*=span],input[class*=span],select[class*=span],textarea[class*=span]{float:none;margin-left:0}.input-append .uneditable-input[class*=span],.input-append input[class*=span],.input-prepend .uneditable-input[class*=span],.input-prepend input[class*=span],.row-fluid .input-append [class*=span],.row-fluid .input-prepend [class*=span],.row-fluid .uneditable-input[class*=span],.row-fluid input[class*=span],.row-fluid select[class*=span],.row-fluid textarea[class*=span]{display:inline-block}.uneditable-input,input,textarea{margin-left:0}.controls-row [class*=span]+[class*=span]{margin-left:20px}.uneditable-input.span12,input.span12,textarea.span12{width:926px}.uneditable-input.span11,input.span11,textarea.span11{width:846px}.uneditable-input.span10,input.span10,textarea.span10{width:766px}.uneditable-input.span9,input.span9,textarea.span9{width:686px}.uneditable-input.span8,input.span8,textarea.span8{width:606px}.uneditable-input.span7,input.span7,textarea.span7{width:526px}.uneditable-input.span6,input.span6,textarea.span6{width:446px}.uneditable-input.span5,input.span5,textarea.span5{width:366px}.uneditable-input.span4,input.span4,textarea.span4{width:286px}.uneditable-input.span3,input.span3,textarea.span3{width:206px}.uneditable-input.span2,input.span2,textarea.span2{width:126px}.uneditable-input.span1,input.span1,textarea.span1{width:46px}.controls-row:after,.controls-row:before{display:table;content:"";line-height:0}.controls-row:after{clear:both}.controls-row [class*=span]{float:left}input[disabled],input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type=checkbox][disabled],input[type=checkbox][readonly],input[type=radio][disabled],input[type=radio][readonly]{background-color:transparent}.control-group.warning .help-block,.control-group.warning .help-inline,.control-group.warning>label{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.control-group.warning .checkbox:focus,.control-group.warning .radio:focus,.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #dbc59e}.control-group.warning .input-append .add-on,.control-group.warning .input-prepend .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .help-block,.control-group.error .help-inline,.control-group.error>label{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.control-group.error .checkbox:focus,.control-group.error .radio:focus,.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d59392}.control-group.error .input-append .add-on,.control-group.error .input-prepend .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .help-block,.control-group.success .help-inline,.control-group.success>label{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.control-group.success .checkbox:focus,.control-group.success .radio:focus,.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7aba7b}.control-group.success .input-append .add-on,.control-group.success .input-prepend .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}input:focus:required:invalid,select:focus:required:invalid,textarea:focus:required:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:required:invalid:focus,select:focus:required:invalid:focus,textarea:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5}.form-actions:after,.form-actions:before{display:table;content:"";line-height:0}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;vertical-align:middle;padding-left:5px}.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap}.input-append .uneditable-input,.input-append input,.input-append select,.input-prepend .uneditable-input,.input-prepend input,.input-prepend select{position:relative;margin-bottom:0;font-size:14px;vertical-align:top;border-radius:0 3px 3px 0}.input-append .uneditable-input:focus,.input-append input:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-prepend input:focus,.input-prepend select:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:400;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-append .btn,.input-prepend .add-on,.input-prepend .btn{margin-left:-1px;vertical-align:top;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{border-radius:3px 0 0 3px}.input-append .uneditable-input,.input-append input,.input-append select{border-radius:3px 0 0 3px}.input-append .add-on:last-child,.input-append .btn:last-child{border-radius:0 3px 3px 0}.input-prepend.input-append .uneditable-input,.input-prepend.input-append input,.input-prepend.input-append select{border-radius:0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;border-radius:3px 0 0 3px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;border-radius:0 3px 3px 0}input.search-query{padding-right:14px;padding-left:14px;margin-bottom:0;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{border-radius:0}.form-search .input-append .search-query{border-radius:14px 0 0 14px}.form-search .input-append .btn{border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{border-radius:0 14px 14px 0}.form-search .input-prepend .btn{border-radius:14px 0 0 14px}.form-horizontal .help-inline,.form-horizontal .input-append,.form-horizontal .input-prepend,.form-horizontal .uneditable-input,.form-horizontal input,.form-horizontal select,.form-horizontal textarea,.form-inline .help-inline,.form-inline .input-append,.form-inline .input-prepend,.form-inline .uneditable-input,.form-inline input,.form-inline select,.form-inline textarea,.form-search .help-inline,.form-search .input-append,.form-search .input-prepend,.form-search .uneditable-input,.form-search input,.form-search select,.form-search textarea{display:inline-block;margin-bottom:0;vertical-align:middle}.form-horizontal .hide,.form-inline .hide,.form-search .hide{display:none}.form-inline .btn-group,.form-inline label,.form-search .btn-group,.form-search label{display:inline-block}.form-inline .input-append,.form-inline .input-prepend,.form-search .input-append,.form-search .input-prepend{margin-bottom:0}.form-inline .checkbox,.form-inline .radio,.form-search .checkbox,.form-search .radio{padding-left:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio],.form-search .checkbox input[type=checkbox],.form-search .radio input[type=radio]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px}.form-horizontal .control-group:after,.form-horizontal .control-group:before{display:table;content:"";line-height:0}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right}.form-horizontal .controls{margin-left:160px}.form-horizontal .help-block{margin-top:10px;margin-bottom:0}.form-horizontal .form-actions{padding-left:160px}.table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table td,.table th{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:700}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child td,.table caption+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table thead:first-child tr:first-child td,.table thead:first-child tr:first-child th{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table-condensed td,.table-condensed th{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;border-left:0;border-radius:4px}.table-bordered td,.table-bordered th{border-left:1px solid #ddd}.table-bordered caption+tbody tr:first-child td,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+thead tr:first-child th,.table-bordered tbody:first-child tr:first-child td,.table-bordered tbody:first-child tr:first-child th,.table-bordered thead:first-child tr:first-child th{border-top:0}.table-bordered tbody:first-child tr:first-child td:first-child,.table-bordered thead:first-child tr:first-child th:first-child{border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered tbody:first-child tr:first-child td:last-child,.table-bordered thead:first-child tr:first-child th:last-child{border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered tbody:last-child tr:last-child td:first-child,.table-bordered tfoot:last-child tr:last-child td:first-child,.table-bordered thead:last-child tr:last-child th:first-child{border-radius:0 0 0 4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered tbody:last-child tr:last-child td:last-child,.table-bordered tfoot:last-child tr:last-child td:last-child,.table-bordered thead:last-child tr:last-child th:last-child{border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered caption+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child{border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered caption+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child{border-top-right-radius:4px;-moz-border-right-topleft:4px}.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9}.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5}.row-fluid table [class*=span],table [class*=span]{display:table-cell;float:none;margin-left:0}table .span1{float:none;width:44px;margin-left:0}table .span2{float:none;width:124px;margin-left:0}table .span3{float:none;width:204px;margin-left:0}table .span4{float:none;width:284px;margin-left:0}table .span5{float:none;width:364px;margin-left:0}table .span6{float:none;width:444px;margin-left:0}table .span7{float:none;width:524px;margin-left:0}table .span8{float:none;width:604px;margin-left:0}table .span9{float:none;width:684px;margin-left:0}table .span10{float:none;width:764px;margin-left:0}table .span11{float:none;width:844px;margin-left:0}table .span12{float:none;width:924px;margin-left:0}table .span13{float:none;width:1004px;margin-left:0}table .span14{float:none;width:1084px;margin-left:0}table .span15{float:none;width:1164px;margin-left:0}table .span16{float:none;width:1244px;margin-left:0}table .span17{float:none;width:1324px;margin-left:0}table .span18{float:none;width:1404px;margin-left:0}table .span19{float:none;width:1484px;margin-left:0}table .span20{float:none;width:1564px;margin-left:0}table .span21{float:none;width:1644px;margin-left:0}table .span22{float:none;width:1724px;margin-left:0}table .span23{float:none;width:1804px;margin-left:0}table .span24{float:none;width:1884px;margin-left:0}.table tbody tr.success td{background-color:#dff0d8}.table tbody tr.error td{background-color:#f2dede}.table tbody tr.info td{background-color:#d9edf7}.dropdown,.dropup{position:relative}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu li>a:focus,.dropdown-menu li>a:hover,.dropdown-submenu:hover>a{text-decoration:none;color:#fff;background-color:#08c;background-color:#0081c2;background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,left top,left bottom,from(#08c),to(#0077b3));background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x}.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;outline:0;background-color:#08c;background-color:#0081c2;background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,left top,left bottom,from(#08c),to(#0077b3));background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x}.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999}.dropdown-menu .disabled>a:hover{text-decoration:none;background-color:transparent;cursor:default}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:"\2191"}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover .dropdown-menu{display:block}.dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#ccc;margin-top:5px;margin-right:-10px}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px}.typeahead{margin-top:2px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-large{padding:24px;border-radius:6px}.well-small{padding:9px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:700;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.btn{display:inline-block;padding:4px 14px;margin-bottom:0;font-size:14px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333;text-shadow:0 1px 1px rgba(255,255,255,.75);background-color:#f5f5f5;background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e6e6e6));background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);border:1px solid #bbb;border-bottom-color:#a2a2a2;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}.btn.active,.btn.disabled,.btn:active,.btn:hover,.btn[disabled]{color:#333;background-color:#e6e6e6}.btn:hover{color:#333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-color:#e6e6e6;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05)}.btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:.65;-webkit-box-shadow:none;box-shadow:none}.btn-large{padding:9px 14px;font-size:16px;line-height:normal;border-radius:5px}.btn-large [class^=icon-]{margin-top:2px}.btn-small{padding:3px 9px;font-size:12px;line-height:18px}.btn-small [class^=icon-]{margin-top:0}.btn-mini{padding:2px 6px;font-size:11px;line-height:16px}.btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}.btn-danger.active,.btn-info.active,.btn-inverse.active,.btn-primary.active,.btn-success.active,.btn-warning.active{color:rgba(255,255,255,.75)}.btn{border-color:#c5c5c5;border-color:rgba(0,0,0,.15) rgba(0,0,0,.15) rgba(0,0,0,.25)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#006dcc;background-image:-o-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,left top,left bottom,from(#08c),to(#04c));background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}.btn-primary.active,.btn-primary.disabled,.btn-primary:active,.btn-primary:hover,.btn-primary[disabled]{color:#fff;background-color:#04c}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#faa732;background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,left top,left bottom,from(#fbb450),to(#f89406));background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}.btn-warning.active,.btn-warning.disabled,.btn-warning:active,.btn-warning:hover,.btn-warning[disabled]{color:#fff;background-color:#f89406}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#da4f49;background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,left top,left bottom,from(#ee5f5b),to(#bd362f));background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}.btn-danger.active,.btn-danger.disabled,.btn-danger:active,.btn-danger:hover,.btn-danger[disabled]{color:#fff;background-color:#bd362f}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#5bb75b;background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,left top,left bottom,from(#62c462),to(#51a351));background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}.btn-success.active,.btn-success.disabled,.btn-success:active,.btn-success:hover,.btn-success[disabled]{color:#fff;background-color:#51a351}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#49afcd;background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2f96b4));background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}.btn-info.active,.btn-info.disabled,.btn-info:active,.btn-info:hover,.btn-info[disabled]{color:#fff;background-color:#2f96b4}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#363636;background-image:-o-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#222));background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}.btn-inverse.active,.btn-inverse.disabled,.btn-inverse:active,.btn-inverse:hover,.btn-inverse[disabled]{color:#fff;background-color:#222}button.btn::-moz-focus-inner,input[type=submit].btn::-moz-focus-inner{padding:0;border:0}.btn-link,.btn-link:active{background-color:transparent;background-image:none;-webkit-box-shadow:none;box-shadow:none}.btn-link{border-color:transparent;cursor:pointer;color:#08c;border-radius:0}.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.btn-group{position:relative;font-size:0;white-space:nowrap}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px}.btn-toolbar .btn-group{display:inline-block}.btn-toolbar .btn+.btn,.btn-toolbar .btn+.btn-group,.btn-toolbar .btn-group+.btn{margin-left:5px}.btn-group>.btn{position:relative;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu{font-size:14px}.btn-group>.btn-mini{font-size:11px}.btn-group>.btn-small{font-size:12px}.btn-group>.btn-large{font-size:16px}.btn-group>.btn:first-child{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{border-top-right-radius:4px;border-bottom-right-radius:4px}.btn-group>.btn.large:first-child{margin-left:0;border-top-left-radius:6px;border-bottom-left-radius:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{border-top-right-radius:6px;border-bottom-right-radius:6px}.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125),inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125),inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}.btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px}.btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret,.btn-mini .caret,.btn-small .caret{margin-top:6px}.btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px}.dropup .btn-large .caret{border-bottom:5px solid #000;border-top:0}.btn-danger .caret,.btn-info .caret,.btn-inverse .caret,.btn-primary .caret,.btn-success .caret,.btn-warning .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block}.btn-group-vertical .btn{display:block;float:none;width:100%;border-radius:0}.btn-group-vertical .btn+.btn{margin-left:0;margin-top:-1px}.btn-group-vertical .btn:first-child{border-radius:4px 4px 0 0}.btn-group-vertical .btn:last-child{border-radius:0 0 4px 4px}.btn-group-vertical .btn-large:first-child{border-radius:6px 6px 0 0}.btn-group-vertical .btn-large:last-child{border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,.5);background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px;color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847}.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-left:0;margin-bottom:20px;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:700;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0}.nav-list .nav-header,.nav-list>li>a{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255,255,255,.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.2);background-color:#08c}.nav-list [class^=icon-]{margin-right:2px}.nav-list .divider{height:1px;margin:9px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-pills:after,.nav-pills:before,.nav-tabs:after,.nav-tabs:before{display:table;content:"";line-height:0}.nav-pills:after,.nav-tabs:after{clear:both}.nav-pills>li,.nav-tabs>li{float:left}.nav-pills>li>a,.nav-tabs>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{border-top-right-radius:4px;border-top-left-radius:4px}.nav-tabs.nav-stacked>li:last-child>a{border-bottom-right-radius:4px;border-bottom-left-radius:4px}.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{border-radius:6px}.nav .dropdown-toggle .caret{border-top-color:#08c;border-bottom-color:#08c;margin-top:6px}.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover{cursor:pointer}.nav-pills .open .dropdown-toggle,.nav-tabs .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open.active .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1}.tabs-stacked .open>a:hover{border-color:#999}.tabbable:after,.tabbable:before{display:table;content:"";line-height:0}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-left>.nav-tabs,.tabs-right>.nav-tabs{border-bottom:0}.pill-content>.pill-pane,.tab-content>.tab-pane{display:none}.pill-content>.active,.tab-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover{text-decoration:none;background-color:transparent;cursor:default}.navbar{overflow:visible;margin-bottom:20px;color:#555}.navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f2f2f2));background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,.065);box-shadow:0 1px 4px rgba(0,0,0,.065)}.navbar .container{width:auto}.nav-collapse.collapse{height:auto}.navbar .brand{float:left;display:block;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#555;text-shadow:0 1px 0 #fff}.navbar .brand:hover{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px}.navbar-link{color:#555}.navbar-link:hover{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #fff}.navbar .btn,.navbar .btn-group{margin-top:6px}.navbar .btn-group .btn{margin:0}.navbar-form{margin-bottom:0}.navbar-form:after,.navbar-form:before{display:table;content:"";line-height:0}.navbar-form:after{clear:both}.navbar-form .checkbox,.navbar-form .radio,.navbar-form input,.navbar-form select{margin-top:5px}.navbar-form .btn,.navbar-form input,.navbar-form select{display:inline-block;margin-bottom:0}.navbar-form input[type=checkbox],.navbar-form input[type=image],.navbar-form input[type=radio]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:400;line-height:1;border-radius:15px}.navbar-static-top{position:static;width:100%;margin-bottom:0}.navbar-static-top .navbar-inner{border-radius:0}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-bottom .navbar-inner,.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border:0}.navbar-fixed-bottom .navbar-inner,.navbar-fixed-top .navbar-inner{padding-left:0;padding-right:0;border-radius:0}.navbar-fixed-bottom .container,.navbar-fixed-top .container,.navbar-static-top .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.1),0 1px 10px rgba(0,0,0,.1);box-shadow:inset 0 -1px 0 rgba(0,0,0,.1),0 1px 10px rgba(0,0,0,.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:inset 0 1px 0 rgba(0,0,0,.1),0 -1px 10px rgba(0,0,0,.1);box-shadow:inset 0 1px 0 rgba(0,0,0,.1),0 -1px 10px rgba(0,0,0,.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#555;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333;text-decoration:none}.navbar .nav>.active>a,.navbar .nav>.active>a:focus,.navbar .nav>.active>a:hover{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,.125);box-shadow:inset 0 3px 8px rgba(0,0,0,.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#ededed;background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2f2f2),to(#e5e5e5));background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.075)}.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar:active,.navbar .btn-navbar:hover,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.25);box-shadow:0 1px 0 rgba(0,0,0,.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);position:absolute;top:-7px;left:9px}.navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:10px}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);border-bottom:0;bottom:-7px;top:auto}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #fff;border-bottom:0;bottom:-6px;top:auto}.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle,.navbar .nav li.dropdown.open>.dropdown-toggle{background-color:#e5e5e5;color:#555}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .nav>li>.dropdown-menu.pull-right,.navbar .pull-right>li>.dropdown-menu{left:auto;right:0}.navbar .nav>li>.dropdown-menu.pull-right:before,.navbar .pull-right>li>.dropdown-menu:before{left:auto;right:12px}.navbar .nav>li>.dropdown-menu.pull-right:after,.navbar .pull-right>li>.dropdown-menu:after{left:auto;right:13px}.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu,.navbar .pull-right>li>.dropdown-menu .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;border-radius:6px 0 6px 6px}.navbar-inverse{color:#999}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-o-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,left top,left bottom,from(#222),to(#111));background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#fff}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#fff}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:focus,.navbar-inverse .nav .active>a:hover{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .divider-vertical{border-left-color:#111;border-right-color:#222}.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open>.dropdown-toggle{background-color:#111;color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1),0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1),0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query.focused,.navbar-inverse .navbar-search .search-query:focus{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,.15);box-shadow:0 0 3px rgba(0,0,0,.15);outline:0}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#0e0e0e;background-image:-o-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,left top,left bottom,from(#151515),to(#040404));background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb li{display:inline-block;text-shadow:0 1px 0 #fff}.breadcrumb .divider{padding:0 5px;color:#ccc}.breadcrumb .active{color:#999}.modal-open .dropdown-menu{z-index:2050}.modal-open .popover{z-index:2060}.modal-open .tooltip{z-index:2080}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8}.modal{position:fixed;top:50%;left:50%;z-index:1050;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.3);border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,.3);box-shadow:0 3px 7px rgba(0,0,0,.3);background-clip:padding-box}.modal.fade{-webkit-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out;top:-25%}.modal.fade.in{top:50%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{overflow-y:auto;max-height:400px;padding:15px}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:after,.modal-footer:before{display:table;content:"";line-height:0}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0}.tooltip.in{opacity:.8}.tooltip.top{margin-top:-3px}.tooltip.right{margin-left:3px}.tooltip.bottom{margin-top:3px}.tooltip.left{margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#eee;text-align:center;text-decoration:none;background-color:#333;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#333}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#333}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#333}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#333}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-bottom:10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-right:10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover-content ol,.popover-content p,.popover-content ul{margin-bottom:0}.popover .arrow,.popover .arrow:after{position:absolute;display:inline-block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow:after{content:"";z-index:-1}.popover.top .arrow{bottom:-10px;left:50%;margin-left:-10px;border-width:10px 10px 0;border-top-color:#fff}.popover.top .arrow:after{border-width:11px 11px 0;border-top-color:rgba(0,0,0,.25);bottom:-1px;left:-11px}.popover.right .arrow{top:50%;left:-10px;margin-top:-10px;border-width:10px 10px 10px 0;border-right-color:#fff}.popover.right .arrow:after{border-width:11px 11px 11px 0;border-right-color:rgba(0,0,0,.25);bottom:-11px;left:-1px}.popover.bottom .arrow{top:-10px;left:50%;margin-left:-10px;border-width:0 10px 10px;border-bottom-color:#fff}.popover.bottom .arrow:after{border-width:0 11px 11px;border-bottom-color:rgba(0,0,0,.25);top:-1px;left:-11px}.popover.left .arrow{top:50%;right:-10px;margin-top:-10px;border-width:10px 0 10px 10px;border-left-color:#fff}.popover.left .arrow:after{border-width:11px 0 11px 11px;border-left-color:rgba(0,0,0,.25);bottom:-11px;right:-1px}.badge,.label{font-size:11.844px;font-weight:700;line-height:14px;color:#fff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#999}.label{padding:1px 4px 2px;border-radius:3px}.badge{padding:1px 9px 2px;border-radius:9px}a.badge:hover,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.badge-important,.label-important{background-color:#b94a48}.badge-important[href],.label-important[href]{background-color:#953b39}.badge-warning,.label-warning{background-color:#f89406}.badge-warning[href],.label-warning[href]{background-color:#c67605}.badge-success,.label-success{background-color:#468847}.badge-success[href],.label-success[href]{background-color:#356635}.badge-info,.label-info{background-color:#3a87ad}.badge-info[href],.label-info[href]{background-color:#2d6987}.badge-inverse,.label-inverse{background-color:#333}.badge-inverse[href],.label-inverse[href]{background-color:#1a1a1a}.btn .badge,.btn .label{position:relative;top:-1px}.btn-mini .badge,.btn-mini .label{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#f9f9f9));background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1);border-radius:4px}.progress .bar{width:0%;height:100%;color:#fff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#0e90d2;background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,left top,left bottom,from(#149bdf),to(#0480be));background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15),inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15),inset 0 -1px 0 rgba(0,0,0,.15)}.progress-striped .bar{background-color:#149bdf;background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress .bar-danger,.progress-danger .bar{background-color:#dd514c;background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,left top,left bottom,from(#ee5f5b),to(#c43c35));background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress .bar-success,.progress-success .bar{background-color:#5eb95e;background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,left top,left bottom,from(#62c462),to(#57a957));background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x}.progress-striped .bar-success,.progress-success.progress-striped .bar{background-color:#62c462;background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress .bar-info,.progress-info .bar{background-color:#4bb1cf;background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#339bb9));background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress .bar-warning,.progress-warning .bar{background-color:#faa732;background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,left top,left bottom,from(#fbb450),to(#f89406));background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x}.progress-striped .bar-warning,.progress-warning.progress-striped .bar{background-color:#fbb450;background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}[class*=" icon-"],[class^=icon-]{display:inline-block;width:16px;height:16px;line-height:17px;font-size:16px;vertical-align:text-top}.btn[disabled] [class*=" icon-"],.btn[disabled] [class^=icon-],.disabled [class*=" icon-"],.disabled [class^=icon-]{color:grey}.btn[disabled] [class*=" icon-"].icon-white,.btn[disabled] [class^=icon-].icon-white,.disabled [class*=" icon-"].icon-white,.disabled [class^=icon-].icon-white{color:#fff}.icon-folder,.icon-folder-add,.icon-list{line-height:18px;font-size:18px;margin-top:-1px;margin-left:-1px;width:17px}.iconsize50{line-height:50px;font-size:50px;width:50px;height:50px}.iconsize24{line-height:24px;font-size:24px}.iconsize20{line-height:20px;font-size:20px}.icon-white,.nav>.active>a>[class*=" icon-"],.nav>.active>a>[class^=icon-]{color:#fff}.g-ui-menu .e-item:hover [class*=" icon-"],.g-ui-menu .e-item:hover [class^=icon-]{color:#fff}.icon-none{background-image:none!important}.icon-checkbox-checked,.icon-checkbox-partial,.icon-checkbox-unchecked,.icon-radio-checked,.icon-radio-unchecked{cursor:pointer;color:#555;font-size:1em}.icon-checkbox-checked:active,.icon-checkbox-checked:hover,.icon-checkbox-partial:active,.icon-checkbox-partial:hover,.icon-checkbox-unchecked:active,.icon-checkbox-unchecked:hover,.icon-radio-checked:active,.icon-radio-checked:hover,.icon-radio-unchecked:active,.icon-radio-unchecked:hover{color:#000}.icon-white.icon-checkbox-checked,.icon-white.icon-checkbox-partial,.icon-white.icon-checkbox-unchecked,.icon-white.icon-radio-checked,.icon-white.icon-radio-unchecked{color:#eee}.icon-white.icon-checkbox-checked:active,.icon-white.icon-checkbox-checked:hover,.icon-white.icon-checkbox-partial:active,.icon-white.icon-checkbox-partial:hover,.icon-white.icon-checkbox-unchecked:active,.icon-white.icon-checkbox-unchecked:hover,.icon-white.icon-radio-checked:active,.icon-white.icon-radio-checked:hover,.icon-white.icon-radio-unchecked:active,.icon-white.icon-radio-unchecked:hover{color:#fff}.iconcolor-display-none{display:none}.iconcolor-green{color:green}.iconcolor-red{color:red}.iconcolor-white{color:#fff}.iconcolor-grey{color:#aaa}.denied-by-browser{cursor:default}.denied-by-browser .icon-checkbox-checked,.denied-by-browser icon-checkbox-unchecked{cursor:default}.down-mini,.right-mini{width:16px;line-height:20px}@-webkit-keyframes rotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.icon-spinner{font-family:Arial;height:11px;width:11px;margin-right:-1px;background:0 0;border:3px solid #aaa;border-top-color:#333;border-radius:100%;-webkit-animation:none;animation:none}.icon-spinner:before{content:""}.icon-spinner.animated{border-color:transparent;border-top-color:#999;-webkit-animation:rotation .8s infinite ease-in-out;animation:rotation .8s infinite ease-in-out}.icon-spinner.big{height:13px;width:13px;margin-top:-2px;margin-left:-2px}.icon-spinner.icon-white,.icon-spinner.white{border-color:#fff;border-top-color:#999}.icon-spinner.icon-white.animated,.icon-spinner.white.animated{border-color:transparent;border-top-color:#fff}html.no-cssanimations .icon-spinner{background:0 0;background-image:url(images/sync.png);background-repeat:no-repeat;border:none;-webkit-box-shadow:none;box-shadow:none;height:16px;width:16px;font-family:Arial}html.no-cssanimations .icon-spinner:before{content:""}html.no-cssanimations .icon-spinner.animated{background:0 0;background-image:url(images/sync.gif)}body{background-color:transparent}label{cursor:pointer}label.inline,span.inline{display:inline-block}.close-custom{float:right;font-size:20px;font-weight:700;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2}.close-custom:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4}button.close-custom{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.minimize-custom{border:0 solid #333;border-bottom-width:3px;display:inline-block;float:right;height:20px;width:16px;font-size:20px;font-weight:700;line-height:20px;margin-right:15px;cursor:pointer}.legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}.legend small{font-size:15px;color:#999}.legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.input-append .uneditable-input,.input-append input,.input-append select{border-radius:3px}select{width:223px}.btn .svg-icon{vertical-align:middle}.btn-small.btn-small-small{padding:3px 9px;font-size:11px;line-height:11px}.btn.btn-thin{padding:4px 9px}.btn.btn-thin-2{padding:4px 7px}.btn.btn-nowrap{white-space:nowrap}.btn.btn-ellipsis{-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.btn.btn-transparent{background:0 0!important;border-color:transparent!important;text-shadow:none!important;-webkit-box-shadow:none!important;box-shadow:none!important;opacity:.6}.btn.btn-transparent [class^=icon-]{width:19px;height:19px;line-height:20px;font-size:19px}.btn.btn-transparent:hover{opacity:1}.btn-group.open .btn.btn-transparent.dropdown-toggle{color:#bd362f}.btn-group.open .btn.btn-transparent.dropdown-toggle .caret{border-top-color:#bd362f}.btn-group.open .btn.btn-transparent.dropdown-toggle [class^=icon-]:before{color:#bd362f}.btn.btn-narrow{padding-left:12px;padding-right:12px}.btn-group.btn-group-custom-margin>.btn+.btn{margin-left:0}.btn.btn-large{font-size:17px}.dropdown-menu{border-radius:3px}.btn-group+.btn-group{margin-left:3px}.btn{border-radius:3px;background-image:none;padding-left:13px;padding-right:13px;border-color:rgba(0,0,0,.25) rgba(0,0,0,.25) rgba(0,0,0,.25)}.btn.disabled,.btn[disabled]{opacity:.8;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}html.textshadow .btn{text-shadow:0 1px 0 #fff}html.textshadow .btn.btn-danger,html.textshadow .btn.btn-primary,html.textshadow .btn.btn-success,html.textshadow .btn.btn-warning{text-shadow:0 1px 0 rgba(0,0,0,.3)}.btn.btn-dark-disabled-border.disabled,.btn.btn-dark-disabled-border[disabled]{border-color:#aaa}.btn.btn-success{background-color:#84ab04}.btn-toolbar{margin-top:0;margin-bottom:0}.dropdown-menu{border-radius:0;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.2);box-shadow:0 1px 2px rgba(0,0,0,.2)}.tooltip{font-size:14px;z-index:2000!important;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis}.tooltip.in{opacity:1}.tooltip .tooltip-inner{max-width:380px;text-shadow:0 0 5px rgba(0,0,0,.2);padding:5px 10px;border-radius:2px;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis}.tooltip .tooltip-big{font-size:18px;padding:0 10px;white-space:nowrap}.popover{width:auto;min-width:250px;max-width:550px}.popover .popover-content pre{border:none;background:rgba(0,0,0,0);padding:0;word-break:normal}.btn-group>.btn{border-radius:0!important}.btn-group>.btn.single{border-radius:3px!important}.btn-group>.btn.first{border-top-left-radius:3px!important;border-bottom-left-radius:3px!important}.btn-group>.btn.last{border-top-right-radius:3px!important;border-bottom-right-radius:3px!important}.btn-group+.btn-group{margin-left:0}.btn-group{margin-right:3px}.btn-group.btn-group-last{margin-right:0}.dropdown.colored-toggle.open .btn.dropdown-toggle{color:#bd362f}.dropdown.colored-toggle.open .btn.dropdown-toggle .caret{border-top-color:#bd362f}.dropdown.colored-toggle.open .btn.dropdown-toggle [class^=icon-]:before{color:#bd362f}input[type=email],input[type=password],input[type=search],input[type=text],textarea{border:1px solid #ccc}input[type=email]:focus,input[type=password]:focus,input[type=search]:focus,input[type=text]:focus,textarea:focus{background-color:#fff;border:1px solid #999;-webkit-box-shadow:none;box-shadow:none}input[type=email],input[type=password],input[type=search],input[type=text]{height:20px;line-height:20px}select{border:1px solid #ccc}.alert a{text-decoration:underline}.alert.alert-null-left-margin{margin-left:0}.alert a{color:#c09853}.alert.alert-info a{color:#3a87ad}.alert.alert-error a{color:#b94a48}.nav-tabs>li>a{color:#555}.popover{z-index:2000}html.no-rgba .modal{border-width:0!important}.modal-backdrop,.modal-backdrop.fade.in{opacity:.2;-webkit-transform:none;-ms-transform:none;transform:none}.popups{position:absolute;top:0;bottom:0;left:0;right:0;z-index:1100;overflow:auto}.popups .modal{position:static;z-index:1101;margin:5% auto;background-color:transparent;overflow:hidden;-webkit-box-shadow:0 5px 80px rgba(0,0,0,.3);box-shadow:0 5px 80px rgba(0,0,0,.3)}.popups .modal .modal-body{background-color:#fff;max-height:none}.modal.fade{-webkit-transition:none;-o-transition:none;transition:none;top:0}.modal.fade.in{top:0}.modal.loginAdminContent .modal-body,.modal.loginContent .modal-body{background-color:transparent!important}.picker.modal-dialog-bg,.picker.picker-dialog-bg{z-index:2000!important}.picker.modal-dialog,.picker.picker-dialog{z-index:2001!important}.form-horizontal.long-label .control-group .control-label{width:160px}.form-horizontal.long-label .control-group .controls{margin-left:180px}.control-label.remove-padding-top{padding-top:0}html.rl-mobile .popups .modal{width:100%!important;width:calc(100% - 20px)!important}html.rl-mobile .b-settings-content{padding:10px;padding-left:20px}html.rl-mobile .list-table{width:100%;max-width:100%}html.rl-mobile .form-horizontal .control-group .control-label{text-align:left;float:none}html.rl-mobile .form-horizontal .control-group .controls{margin-left:0}.close-input-wrp{display:inline-block;position:relative}.close-input-wrp input{padding-right:15px}.close-input-wrp .close{position:absolute;right:0;top:5px;margin:0 7px;z-index:100;vertical-align:middle;opacity:.4}.close-input-wrp .close:hover{opacity:.6}.inputosaurus-container{width:99%;line-height:20px;padding:2px;border:1px solid #ccc;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;-webkit-transition:border linear .2s,-webkit-box-shadow linear .2s;transition:border linear .2s,-webkit-box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s,-webkit-box-shadow linear .2s}.inputosaurus-container.inputosaurus-focused{background-color:#fff;border:1px solid #999;-webkit-box-shadow:none;box-shadow:none}.inputosaurus-container li{max-width:500px;background-color:#eee;border:1px solid #aaa;line-height:18px;padding:2px 15px 2px 5px;margin:2px 2px 2px;color:#555;z-index:100;position:relative}.inputosaurus-container li.ui-draggable.ui-draggable-dragging{z-index:101}.inputosaurus-container li a{color:#999;font-size:12px;position:absolute;top:1px;right:2px}.inputosaurus-container li a:hover{color:#666}.inputosaurus-container li span{padding-right:3px}.inputosaurus-container li.inputosaurus-required{padding-right:5px}.inputosaurus-container li.inputosaurus-selected{background-color:#ddd}.inputosaurus-container li.pgp{background-color:#e5f3e2}.inputosaurus-container .inputosaurus-input{margin:1px 10px 1px 0;height:22px}.inputosaurus-container .inputosaurus-input input{border:0;height:21px;padding-left:0}.ui-autocomplete{z-index:2000}.inputosaurus-fake-span{position:absolute;top:0;left:-5000px}.cke_chrome{border:1px solid #ccc!important}.cke_toolgroup{padding-right:0!important;background:#fbfbfb!important}.cke_combo_button,.cke_toolgroup{border:1px solid #a6a6a6!important}.cke_top{padding:6px 4px 1px 6px!important;-webkit-box-shadow:none!important;box-shadow:none!important;border-bottom:1px solid #b6b6b6!important;background:#f0f0f0!important}.cke_combo_off a.cke_combo_button:active,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:hover,.cke_combo_on a.cke_combo_button{padding:1px!important;margin-left:0!important}.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after,.cke_toolgroup a.cke_button:last-child:after{border:none!important;height:0!important;width:0!important;margin:0!important;padding:0!important}.cke_button_on{background:#ddd!important}.cke_combo{margin-top:1px!important}.cke_combo__fontsize{margin-left:3px!important}.cke_combo__fontsize .cke_combo_text{width:40px!important}.cke_combo_text{line-height:24px!important;padding-left:8px!important}.cke_combo_button{background:#fbfbfb!important}.cke_source{font-family:Monaco,Menlo,Consolas,'Courier New',monospace!important;padding:10px!important;padding-right:0!important;-webkit-box-shadow:none!important;box-shadow:none!important}.cke_plain{background-color:#fff;outline:0;overflow:auto;z-index:1;margin:0;border:0;padding:10px;padding-right:0;white-space:pre-wrap;font-family:Monaco,Menlo,Consolas,'Courier New',monospace;font-size:13px;line-height:16px;color:#333;resize:none;border-radius:0;-webkit-box-shadow:none;box-shadow:none;-webkit-box-sizing:border-box;box-sizing:border-box}.cke_plain:focus,.cke_source:focus{border:0}.b-compose .cke_chrome{border-right:0;border-left:0;border-bottom:0;-webkit-box-shadow:none;box-shadow:none}.cke_wysiwyg_div{padding:10px!important;font-family:arial,sans-serif;font-size:13px;line-height:16px;color:#333}.cke_wysiwyg_div ul{padding-left:40px}.cke_wysiwyg_div ul li{list-style-type:disc!important}.cke_wysiwyg_div ol{padding-left:40px}.cke_wysiwyg_div ol li{list-style-type:decimal!important}.cke_wysiwyg_div code,.cke_wysiwyg_div pre{margin:0;padding:0;background:#fff;border:none;border-radius:0;font-family:Monaco,Menlo,Consolas,'Courier New',monospace;display:block;word-break:normal;word-wrap:break-word;background-color:#f9f9f9}.cke_wysiwyg_div code{display:inline;padding:2px 5px}.cke_wysiwyg_div pre{padding:5px 10px;border-radius:5px;background-color:#f9f9f9}.cke_wysiwyg_div pre>code{padding:0}.cke_wysiwyg_div blockquote{border:0;border-left:solid 2px #444;margin:5px 0 5px 5px;padding-left:5px}.cke_wysiwyg_div blockquote p{margin:0 0 10px;font-size:14px;line-height:20px}.cke_wysiwyg_div img{vertical-align:bottom}.cke_wysiwyg_div a{color:#00f;text-decoration:underline}.cke_wysiwyg_div a:visited{color:#609}.cke_wysiwyg_div a:active{color:red}.cke_dialog a:hover{text-decoration:none}.cke_dialog .cke_dialog_ui_labeled_content{margin-top:5px;margin-bottom:5px}.cke_dialog .cke_dialog_ui_input_select,.cke_dialog .cke_dialog_ui_input_text,.cke_dialog .cke_dialog_ui_input_textarea{-webkit-box-shadow:none;box-shadow:none;border-radius:2px}.cke_dialog .cke_dialog_ui_input_select:focus,.cke_dialog .cke_dialog_ui_input_text:focus,.cke_dialog .cke_dialog_ui_input_textarea:focus{outline:0;border:1px solid #999}.cke_dialog .cke_dialog_ui_input_select,.cke_dialog .cke_dialog_ui_input_text{height:25px;line-height:25px}.g-ui-user-select-allow{webkit-touch-callout:inherit;-webkit-user-select:inherit;-moz-user-select:inherit;-ms-user-select:inherit;user-select:inherit;standard-user-select:inherit;touch-callout:inherit}.g-ui-clearfix:after,.g-ui-clearfix:before{display:table;content:"";line-height:0}.g-ui-clearfix:after{clear:both}.g-ui-link{color:#369;text-decoration:underline;cursor:pointer;padding:2px}.g-ui-link:focus{outline:1px;outline-style:dotted}.g-ui-min-height-300{min-height:300px}.g-ui-100-proc-height{height:100%}.g-ui-absolute-reset{position:absolute;top:0;right:0;bottom:0;left:0;padding:0;margin:0;border:0;z-index:0}.g-ui-menu{max-height:400px;max-width:300px;overflow-y:auto;overflow-x:hidden}.g-ui-menu .e-link{text-decoration:none;cursor:pointer}.g-ui-menu .e-item.selected>.e-link{background-color:#eee!important}.g-ui-menu .e-item>.e-link:focus,.g-ui-menu .e-item>.e-link:hover{background-color:#555;background-image:none;color:#fff}.g-ui-menu .e-item.disabled>.e-link{cursor:not-allowed;background-color:#fff;background-image:none;color:grey}.g-ui-menu .e-item.disabled [class^=icon-]{color:grey}.g-ui-table{display:table;width:100%}.g-ui-table .e-row{display:table-row}.g-ui-table .e-cell{display:table-cell;vertical-align:top;text-align:left}.g-ui-height-100proc{height:100%}.g-ui-resizable-delimiter-highlight{border:none;border-right:6px solid #aaa}.e-pagenator .e-page{display:inline-block;color:#999;text-decoration:none;font-size:22px;padding:3px;cursor:pointer}.e-pagenator .e-page:hover .e-page-number{color:#555}.e-pagenator .e-page.current .e-page-number{font-size:25px;color:#333;border-bottom:2px solid #000}html.rgba .g-ui-resizable-delimiter-highlight{border-right-color:rgba(0,0,0,.2)}.settings-saved-trigger{display:inline-block;line-height:17px;font-size:16px}.settings-saved-trigger .animated{color:green}.settings-saved-trigger .success{color:green;-webkit-transition:opacity .5s linear;-o-transition:opacity .5s linear;transition:opacity .5s linear;opacity:0}.settings-saved-trigger .error{color:red;-webkit-transition:opacity .5s linear;-o-transition:opacity .5s linear;transition:opacity .5s linear;opacity:0}.settings-saved-trigger .visible{opacity:1}.settings-saved-trigger-input.success{border-color:green!important;-webkit-transition:border-color .5s linear;-o-transition:border-color .5s linear;transition:border-color .5s linear}.settings-saved-trigger-input.error{border-color:red!important;-webkit-transition:border-color .5s linear;-o-transition:border-color .5s linear;transition:border-color .5s linear}.display-none{display:none}.e-spinner{display:none}.e-mobile-switcher,.e-powered{margin-top:8px;color:#333}.e-mobile-switcher a,.e-powered a{color:#333;text-decoration:underline}.e-mobile-switcher a:hover,.e-powered a:hover{color:#333}.e-languages{margin-top:8px;color:#333}.e-languages .flag-name{color:#333;border-bottom:1px dashed #333;cursor:pointer;padding:2px 0}.e-languages .flag-name:focus{outline:1px;outline-style:dotted}html.cssanimations .e-spinner{display:block;margin:5px auto 0;width:100px;text-align:center}html.cssanimations .e-spinner .e-bounce{width:15px;height:15px;background-color:#ddd;margin:0 5px;-webkit-box-shadow:0 0 3px rgba(0,0,0,.3);box-shadow:0 0 3px rgba(0,0,0,.3);border-radius:100%;display:inline-block;-webkit-animation:bouncedelay 1.4s infinite ease-in-out;animation:bouncedelay 1.4s infinite ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}html.cssanimations .e-spinner .bounce1{-webkit-animation-delay:-.32s;animation-delay:-.32s}html.cssanimations .e-spinner .bounce2{-webkit-animation-delay:-.16s;animation-delay:-.16s}@-webkit-keyframes bouncedelay{0%,100%,80%{-webkit-transform:scale(0);transform:scale(0)}40%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes bouncedelay{0%,100%,80%{-webkit-transform:scale(0);transform:scale(0)}40%{-webkit-transform:scale(1);transform:scale(1)}}.command.command-disabled.hide-on-disabled-command{display:none}html{margin:0;padding:0;overflow:hidden;font-family:Arial,Verdana,Geneva,sans-serif;height:100%}body{margin:0;padding:0;overflow:hidden;background-color:#e3e3e3;font-family:Arial,Verdana,Geneva,sans-serif;-webkit-touch-callout:none;position:absolute;top:0;left:0;bottom:0;right:0;height:100%}textarea{resize:none}option:disabled{color:#aaa;cursor:not-allowed}body:before{content:"";position:fixed;top:-10px;left:0;width:100%;height:8px;z-index:100;-webkit-box-shadow:0 0 10px rgba(0,0,0,.6);box-shadow:0 0 10px rgba(0,0,0,.6)}*{outline:0}select:focus{outline:0}html.mobile *,html.rl-mobile *{-webkit-tap-highlight-color:transparent}input[type=search]{-webkit-box-sizing:content-box;box-sizing:content-box}input::-ms-clear,input::-ms-reveal{display:none}#rl-bg{z-index:-1;position:absolute;left:0;right:0;top:0;bottom:0}#rl-content{height:100%;width:100%}#rl-center{position:absolute;top:0;right:0;bottom:0;left:0;padding:0;margin:0;border:0;z-index:0;min-width:600px;min-height:400px}html.rl-mobile #rl-center{min-width:250px;min-height:250px}html.rl-mobile.rl-left-panel-enabled #rl-right{right:-150px}html.rl-mobile.rl-left-panel-disabled #rl-right{left:5px!important}#rl-top{position:absolute;top:0;right:0;bottom:0;left:0;padding:0;margin:0;border:0;z-index:0;bottom:auto;z-index:2}#rl-bottom{position:absolute;top:0;right:0;bottom:0;left:0;padding:0;margin:0;border:0;z-index:0;top:auto;z-index:1}#rl-left{position:absolute;top:0;right:0;bottom:0;left:0;padding:0;margin:0;border:0;z-index:0;width:200px;min-width:60px}#rl-right{position:absolute;top:0;right:0;bottom:0;left:0;padding:0;margin:0;border:0;z-index:0;z-index:1;left:200px}#rl-sub-left{position:absolute;top:0;bottom:0;left:0;width:500px}#rl-sub-right{position:absolute;top:0;bottom:0;right:0;left:500px}#rl-sub-right .b-message-view-backdrop{position:absolute;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.4);z-index:10}#rl-sub-right .b-message-view-backdrop .backdrop-message-wrp{position:absolute;top:calc(50% - 50px);left:0;right:0;text-align:center}#rl-sub-right .b-message-view-backdrop .backdrop-message-wrp .backdrop-message{display:inline-block;color:#fff;font-size:20px;line-height:30px;background:rgba(0,0,0,.6);padding:15px;border-radius:5px;text-shadow:0 1px 1px #000}html.ssm-state-desktop-large #rl-left{width:220px}html.ssm-state-desktop-large #rl-right{left:220px}html.ssm-state-desktop-large #rl-sub-left{width:500px}html.ssm-state-desktop-large #rl-sub-right{left:500px}html.ssm-state-desktop-large .b-compose.modal{width:1000px}html.ssm-state-desktop-large .b-contacts-content.modal{width:900px}html.ssm-state-desktop #rl-left{width:200px}html.ssm-state-desktop #rl-right{left:200px}html.ssm-state-desktop #rl-sub-left{width:400px}html.ssm-state-desktop #rl-sub-right{left:400px}html.ssm-state-desktop .b-compose.modal{width:1000px}html.ssm-state-desktop .b-contacts-content.modal{width:900px}html.ssm-state-mobile #rl-left,html.ssm-state-tablet #rl-left{width:155px}html.ssm-state-mobile #rl-right,html.ssm-state-tablet #rl-right{left:155px}html.ssm-state-mobile #rl-sub-left,html.ssm-state-tablet #rl-sub-left{width:310px}html.ssm-state-mobile #rl-sub-left .messageList .inputSearch,html.ssm-state-tablet #rl-sub-left .messageList .inputSearch{width:200px}html.ssm-state-mobile #rl-sub-right,html.ssm-state-tablet #rl-sub-right{left:310px}html.ssm-state-mobile .b-compose.modal,html.ssm-state-tablet .b-compose.modal{width:720px}html.ssm-state-mobile .b-contacts-content.modal,html.ssm-state-tablet .b-contacts-content.modal{width:700px}html.ssm-state-mobile .b-contacts-content.modal .contactValueInput,html.ssm-state-tablet .b-contacts-content.modal .contactValueInput{width:200px}html.ssm-state-tablet .b-compose.modal{width:720px}html.ssm-state-tablet .b-contacts-content.modal{width:800px}html.ssm-state-tablet .b-contacts-content.modal .contactValueInput{width:250px}.show-on-panel-disabled{display:none}html.rl-left-panel-disabled #rl-left{width:60px!important}html.rl-left-panel-disabled #rl-left .show-on-panel-disabled{display:block}html.rl-left-panel-disabled #rl-left .opacity-on-panel-disabled{opacity:.3}html.rl-left-panel-disabled #rl-left .visibility-hidden-on-panel-disabled{visibility:hidden}html.rl-left-panel-disabled #rl-left .hide-on-panel-disabled{display:none}html.rl-left-panel-disabled #rl-left.ui-state-disabled{opacity:1}html.rl-left-panel-disabled #rl-right{left:60px!important}html.rl-left-panel-short #rl-left{width:60px!important}html.rl-left-panel-short #rl-right{left:60px!important}html.rl-left-panel-none #rl-left{width:10px!important}html.rl-left-panel-none #rl-right{left:10px!important}.ui-resizable-helper-w{border-right:5px solid #777;border-right-color:rgba(255,255,255,.7)}.ui-resizable-helper-h{border-bottom:5px solid #ccc;border-bottom-color:rgba(0,0,0,.3)}.ui-resizable-handle:hover{background:#aaa;background:rgba(255,255,255,.5)}html.rl-no-preview-pane #rl-sub-left{right:5px!important;width:inherit}html.rl-no-preview-pane #rl-sub-left .messageList .inputSearch{width:300px!important}html.rl-no-preview-pane #rl-sub-right{left:0!important}html.rl-no-preview-pane #rl-right .ui-resizable-handle{display:none!important}html.rl-side-preview-pane #rl-right .ui-resizable-handle{display:none!important}html.rl-bottom-preview-pane #rl-sub-left{right:5px!important;width:inherit}html.rl-bottom-preview-pane #rl-sub-left .b-message-list-wrapper{bottom:inherit;height:300px;-webkit-box-shadow:none;box-shadow:none}html.rl-bottom-preview-pane #rl-sub-left .messageList .inputSearch{width:300px!important}html.rl-bottom-preview-pane #rl-sub-right{left:0!important}html.rl-bottom-preview-pane #rl-sub-right .messageView .top-toolbar{display:none}html.rl-bottom-preview-pane #rl-sub-right .b-message-view-wrapper{top:356px;left:0;right:5px;-webkit-box-shadow:none;box-shadow:none}.visible-on-ctrl,.visible-on-ctrl-btn{display:none}.hidden-on-ctrl-btn{display:inline-block}html.rl-ctrl-key-pressed .visible-on-ctrl{display:inline-block}html.rl-ctrl-key-pressed .btn-group.open .visible-on-ctrl-btn{display:inline-block}html.rl-ctrl-key-pressed .hidden-on-ctrl{display:none}html.rl-ctrl-key-pressed .btn-group.open .hidden-on-ctrl-btn{display:none}#rl-loading,#rl-loading-error{position:absolute;font-size:30px;line-height:130%;top:50%;width:100%;height:65px;margin:0;margin-top:-60px;background-color:transparent;text-align:center;color:#000}#rl-loading-error{background-image:none;display:none}#rl-loading-error-additional{margin-top:20px;font-size:20px}#rl-app{display:none}#rl-check{display:none}.rl-content-show{display:block!important}html.rl-mobile .hide-on-mobile{display:none!important}.show-on-mobile{display:none!important}html.rl-mobile .show-on-mobile{display:initial!important}html.rl-mobile .width100-on-mobile{width:100%!important}.nano.scroller-shadow-bottom:after,.nano.scroller-shadow-top:before{content:"";position:absolute;left:0;width:100%;height:10px;z-index:102;-webkit-box-shadow:0 0 20px rgba(0,0,0,.4);box-shadow:0 0 20px rgba(0,0,0,.4)}.nano.scroller-shadow-top:before{top:-10px}.nano.scroller-shadow-bottom:after{bottom:-10px}.nano.fixIndex.scroller-shadow-bottom:after,.nano.fixIndex.scroller-shadow-top:before{z-index:98}.e-component.e-select select:focus{outline:1px;outline-style:dotted}.e-component.e-checkbox{margin-bottom:6px;margin-left:-2px;padding:2px;cursor:pointer}.e-component.e-checkbox:focus{outline:1px;outline-style:dotted}.e-component.e-checkbox .e-checkbox-icon{padding:1px 0 0 1px}.e-component.e-checkbox.disabled{cursor:default;color:#999;outline:0;outline-style:none}.e-component.e-radio{cursor:pointer}.e-component.e-radio.disabled{cursor:default;color:#999}.e-component.material-design.e-checkbox{margin-top:2px;padding:2px 2px 1px 2px}.e-component.material-design.e-checkbox .sub-checkbox-container{display:inline-block;position:relative;-webkit-transform:translateZ(0);transform:translateZ(0);width:18px;height:18px;vertical-align:bottom;margin-bottom:3px}.e-component.material-design.e-checkbox .sub-label{padding-left:12px}.e-component.material-design.e-checkbox .sub-checkbox{position:absolute;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:1px;top:0;left:0;width:18px;height:18px;border:solid 2px #999;-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}.e-component.material-design.e-checkbox .sub-checkbox.checked{border-top:none;border-left:none;border-color:#0f9d58;top:-1px;left:5px;width:10px;height:18px;border-right-width:2px;border-bottom-width:2px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.e-component.material-design.e-checkbox .sub-checkbox.checked.box{border:solid 2px;-webkit-animation:box-shrink 140ms ease-out forwards;animation:box-shrink 140ms ease-out forwards}.e-component.material-design.e-checkbox .sub-checkbox.checked.checkmark{border-left:none;border-top:none;-webkit-animation:checkmark-expand 140ms ease-out forwards;animation:checkmark-expand 140ms ease-out forwards}.e-component.material-design.e-checkbox .sub-checkbox.unchecked.box{-webkit-animation:box-expand 140ms ease-out forwards;animation:box-expand 140ms ease-out forwards}.e-component.material-design.e-checkbox .sub-checkbox.unchecked.checkmark{border-left:none;border-top:none;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);-webkit-animation:checkmark-shrink 140ms ease-out forwards;animation:checkmark-shrink 140ms ease-out forwards}.e-component.material-design.e-checkbox.disabled .sub-checkbox{border-color:#aaa;cursor:not-allowed;color:#aaa}.e-component.material-design.e-checkbox.disabled .sub-label{cursor:not-allowed;color:#aaa}@-webkit-keyframes box-shrink{0%{top:0;left:0;width:18px;height:18px;border:solid 2px #999;-webkit-transform:rotate(0);transform:rotate(0)}100%{top:13px;left:5px;width:4px;height:4px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}}@keyframes box-shrink{0%{top:0;left:0;width:18px;height:18px;border:solid 2px #999;-webkit-transform:rotate(0);transform:rotate(0)}100%{top:13px;left:5px;width:4px;height:4px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}}@-webkit-keyframes checkmark-expand{0%{top:13px;left:5px;width:4px;height:4px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}100%{top:-1px;left:5px;width:10px;height:18px;border-right-width:2px;border-bottom-width:2px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}}@keyframes checkmark-expand{0%{top:13px;left:5px;width:4px;height:4px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}100%{top:-1px;left:5px;width:10px;height:18px;border-right-width:2px;border-bottom-width:2px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}}@-webkit-keyframes checkmark-shrink{0%{top:-1px;left:5px;width:10px;height:18px;border-right-width:2px;border-bottom-width:2px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}100%{top:13px;left:5px;width:4px;height:4px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}}@keyframes checkmark-shrink{0%{top:-1px;left:5px;width:10px;height:18px;border-right-width:2px;border-bottom-width:2px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}100%{top:13px;left:5px;width:4px;height:4px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}}@-webkit-keyframes box-expand{0%{top:13px;left:5px;width:4px;height:4px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}100%{top:0;left:0;width:18px;height:18px;border:solid 2px #999;-webkit-transform:rotate(0);transform:rotate(0)}}@keyframes box-expand{0%{top:13px;left:5px;width:4px;height:4px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}100%{top:0;left:0;width:18px;height:18px;border:solid 2px #999;-webkit-transform:rotate(0);transform:rotate(0)}}.b-system-drop-down .b-toolbar{position:absolute;top:0;right:0;height:30px;padding:10px 8px;z-index:103}.b-system-drop-down .e-facebook-name{display:inline-block;padding-top:4px}.b-system-drop-down .btn.system-dropdown{padding-left:10px;padding-right:10px}.b-system-drop-down .button-fb-logout{margin:5px}.b-system-drop-down .email-title{display:inline-block;max-width:200px;text-align:left;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;margin-right:28px;vertical-align:middle}.b-system-drop-down .logoPlace{margin:-5px 10px 0 0;font-size:25px;line-height:30px;height:40px}.b-system-drop-down .audioPlace{font-size:25px;line-height:30px;margin-right:10px;width:25px}.b-system-drop-down .audioPlace .playIcon,.b-system-drop-down .audioPlace .stopIcon{cursor:pointer;color:orange;text-shadow:0 1px 0 #555;float:right}.b-system-drop-down .audioPlace .playIcon{margin-top:5px}.b-system-drop-down .audioPlace .stopIcon{font-size:30px;line-height:30px;margin-right:10px}.b-system-drop-down .audioPlace .stopIcon{display:none}.b-system-drop-down .audioPlace:hover .playIcon{display:none}.b-system-drop-down .audioPlace:hover .stopIcon{display:inline-block}.b-system-drop-down .accountPlace{background-color:#000;background-color:rgba(0,0,0,.5);color:#fff;text-shadow:0 1px 0 #000;display:inline-block;height:29px;max-width:250px;font-size:16px;line-height:30px;padding:1px 8px;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;border-radius:4px;font-weight:700;margin-right:5px;white-space:nowrap}.b-system-drop-down .account-item .icon-ok{display:none}.b-system-drop-down .account-item.current .icon-ok{display:inline-block}.b-system-drop-down .account-item.current .icon-user{display:none}.b-system-drop-down .counter{display:inline-block}.b-system-drop-down .g-ui-menu .e-link.account-item{padding-right:5px}html.ssm-state-mobile .accountPlace{max-width:150px!important}@-webkit-keyframes firstBar{0%{height:30%}50%{height:100%}100%{height:30%}}@keyframes firstBar{0%{height:30%}50%{height:100%}100%{height:30%}}@-webkit-keyframes secondBar{0%{height:90%}50%{height:30%}100%{height:100%}}@keyframes secondBar{0%{height:90%}50%{height:30%}100%{height:100%}}@-webkit-keyframes thirdBar{0%{height:20%}40%{height:40%}60%{height:80%}100%{height:40%}}@keyframes thirdBar{0%{height:20%}40%{height:40%}60%{height:80%}100%{height:40%}}.equaliser{width:20px;height:20px;position:relative}.equaliser .bar{float:left;width:5px;height:5px;background:orange;position:absolute;bottom:0}.equaliser .first{left:0;-webkit-animation:none;animation:none}.equaliser .second{left:7px;-webkit-animation:none;animation:none}.equaliser .third{left:14px;-webkit-animation:none;animation:none}.equaliser.animated .first{-webkit-animation:firstBar 1s infinite;animation:firstBar 1s infinite}.equaliser.animated .second{-webkit-animation:secondBar 1s infinite;animation:secondBar 1s infinite}.equaliser.animated .third{-webkit-animation:thirdBar 1s infinite;animation:thirdBar 1s infinite}.b-login-content{height:100%;text-align:center}.b-login-content .loginFormWrapper{display:inline-block;vertical-align:middle;text-align:center;-webkit-perspective:500px;perspective:500px}.b-login-content .loginFormWrapper .descWrapper{margin-bottom:10px}.b-login-content .loginFormWrapper .descWrapper .desc{font-size:18px;padding:2px}.b-login-content .loginFormWrapper .alertError{max-width:450px}.b-login-content .loginFormWrapper .loginForm{background-color:#efefef;text-align:left;color:#333;margin:0;float:none;width:303px}.b-login-content .loginFormWrapper .loginWelcomeForm{display:none}.b-login-content .loginFormWrapper .welcome-on{display:block}.b-login-content .loginFormWrapper .welcome-off{display:none}.b-login-content .loginFormWrapper .control-group,.b-login-content .loginFormWrapper .controls{margin-bottom:25px}.b-login-content .loginFormWrapper .wrapper{padding:40px 40px 20px 40px}.b-login-content .loginFormWrapper #recaptcha_image img{border:1px solid #ccc;border-radius:3px}.b-login-content .loginFormWrapper .controls .inputAdditionalCode,.b-login-content .loginFormWrapper .controls .inputEmail,.b-login-content .loginFormWrapper .controls .inputLogin,.b-login-content .loginFormWrapper .controls .inputLoginForm,.b-login-content .loginFormWrapper .controls .inputPassword{font-size:18px;height:40px;line-height:20px;padding-left:12px;padding-right:12px}.b-login-content .loginFormWrapper .languageLabel{margin-top:5px}.b-login-content .loginFormWrapper .signMeLabel .e-checkbox{margin-top:5px}.b-login-content .loginFormWrapper .languageLabel{margin-right:5px}.b-login-content .loginFormWrapper .input-append .add-on{position:relative;height:30px;background:0 0;margin-left:-35px;z-index:1000;border:0}.b-login-content .loginFormWrapper .input-append .add-on i{font-size:17px;line-height:29px;color:#999}.b-login-content .loginFormWrapper .input-append .add-on i.login-submit-icon{font-size:24px;padding-top:2px;cursor:pointer}.b-login-content .loginFormWrapper .control-group.error .add-on i,.b-login-content .loginFormWrapper .controls.error .add-on i{color:#b94a48}.b-login-content .buttonLogin{margin:0}.b-login-content .alert{margin:0 0 20px 0;text-align:left}.b-login-content .loginAfter{display:inline-block;height:90%;vertical-align:middle;width:0}.b-login-content .flag-selector{margin-bottom:0}.b-login-content .social-buttons{margin-top:5px}.b-login-content .language-button,.b-login-content .social-button{padding:5px;outline:0}@-webkit-keyframes loginRotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes loginRotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.submitting-pane{position:relative}.submitting-pane.submitting:before{content:'';position:absolute;top:0;left:0;right:0;bottom:0;background:0 0;background:rgba(0,0,0,.3);z-index:1051;border-radius:8px}html.cssanimations .submitting-pane.submitting:after{content:'';position:absolute;width:60px;height:60px;top:50%;left:50%;margin-top:-30px;margin-left:-30px;border:8px solid transparent;border-color:transparent;border-top-color:#fff;-webkit-animation:loginRotation 1s infinite ease-in-out;animation:loginRotation 1s infinite ease-in-out;border-radius:50%;z-index:1052}.btn-submit-icon-wrp{border:none;background:0 0;display:inline-block;margin:0;padding:0;outline:0;cursor:pointer}.popups .b-welcom-page-content .modal-header{background-color:#fff}.popups .b-ask-content .modal-header{background-color:#fff}.popups .b-ask-content .modal-body{text-align:center}.popups .b-ask-content .desc-place{font-size:18px}.popups .b-shortcuts-content.modal{width:700px}.popups .b-shortcuts-content .modal-header{background-color:#fff}.b-folders .move-action-content-wrapper{z-index:-1;position:fixed;top:0;bottom:0;left:0;right:0;opacity:.05;background-color:#fff;background-size:60px 60px;background-image:-o-linear-gradient(315deg,#000 25%,transparent 25%,transparent 50%,#000 50%,#000 75%,transparent 75%,transparent);background-image:linear-gradient(135deg,#000 25%,transparent 25%,transparent 50%,#000 50%,#000 75%,transparent 75%,transparent)}.b-folders .b-folders-user .e-link.print-count.system .badge{display:none!important}.b-folders .b-toolbar{position:absolute;top:0;right:0;left:0;height:30px;padding:10px 0 0 8px;color:#fff;z-index:101}.b-folders .b-footer{position:absolute;bottom:10px;right:0;left:0;height:30px;padding:0 10px 0 5px;z-index:101;overflow:hidden;white-space:nowrap}.b-folders .b-content{position:absolute;top:58px;bottom:45px;left:0;right:0;overflow:hidden;overflow-y:auto;min-width:100px}.b-folders .b-content .content{-webkit-overflow-scrolling:touch}.b-folders .b-list-delimiter{margin:10px;border-top:0 solid #000;border-bottom:1px solid #999}.b-folders .b-content .e-item{overflow:hidden;white-space:nowrap}.b-folders .b-content .e-item .e-link{display:block;position:relative;z-index:1;height:34px;line-height:34px;background-color:transparent;vertical-align:middle;color:grey;cursor:not-allowed;font-size:14px;padding:0;padding-left:10px;padding-right:10px;outline:0;text-decoration:none}.b-folders .b-content .e-item .e-link .focused-poiner{float:left;display:inline-block;background-color:transparent;height:100%;width:3px;position:absolute;top:0;left:0}.b-folders .b-content .e-item .e-link .inbox-star-icon{display:none;margin-left:7px}.b-folders .b-content .e-item .e-link .inbox-star-icon .icon-star{display:none}.b-folders .b-content .e-item .e-link .inbox-star-icon .icon-star-empty{opacity:.5}.b-folders .b-content .e-item .e-link .inbox-star-icon .icon-star-empty:hover{opacity:1}.b-folders .b-content .e-item .e-link.is-inbox .inbox-star-icon{display:inline}.b-folders .b-content .e-item .e-link.selectable{color:#000;cursor:pointer}.b-folders .b-content .e-item .e-link.selectable.droppableHover,.b-folders .b-content .e-item .e-link.selectable.focused,.b-folders .b-content .e-item .e-link.selectable.selected,.b-folders .b-content .e-item .e-link.selectable:hover{background-color:#555;color:#fff}.b-folders .b-content .e-item .e-link.selectable.focused{color:#fff}.b-folders .b-content .e-item .e-link.focused{background-color:#888}.b-folders .b-content .e-item .e-link.focused .focused-poiner{background-color:#fff}.b-folders .b-content .e-item .e-link.system{cursor:default;color:grey}.b-folders .b-content .e-item .e-link .count{position:relative;display:none;margin-top:5px;line-height:19px}.b-folders .b-content .e-item .e-link.print-count{font-weight:700}.b-folders .b-content .e-item .e-link.print-count .count{display:inline}.b-folders .b-content .e-item .e-link.unread-sub{font-weight:700}.b-folders .b-content .e-item .e-link .e-collapsed-sign{cursor:pointer;width:22px;height:30px;line-height:30px;text-align:center;vertical-align:inherit}.b-folders .b-content .e-item .hidden.e-link{display:none}.b-folders .b-content .e-item .b-sub-folders.collapsed{max-height:0;height:0;display:none}.b-folders.inbox-is-starred .icon-star{color:orange;display:inline-block!important}.b-folders.inbox-is-starred .icon-star-empty{display:none}.b-folders .b-folder-system-item{font-weight:700}.b-folders .b-sub-folders .e-item .e-link{padding-left:25px}.b-folders .b-sub-folders .b-sub-folders .e-item .e-link{padding-left:40px}.b-folders .b-sub-folders .b-sub-folders .b-sub-folders .e-item .e-link{padding-left:55px}.b-folders .b-sub-folders .b-sub-folders .b-sub-folders .b-sub-folders .e-item .e-link{padding-left:70px}.b-folders.single-root-inbox .i-am-inbox.e-link{display:none!important}.b-folders.single-root-inbox .i-am-inbox-wrapper>.b-sub-folders{max-height:none!important;height:inherit!important;display:block!important}.b-folders.single-root-inbox .i-am-inbox-wrapper .b-sub-folders .e-item .e-link{padding-left:10px}.b-folders.single-root-inbox .i-am-inbox-wrapper .b-sub-folders .b-sub-folders .e-item .e-link{padding-left:25px}.b-folders.single-root-inbox .i-am-inbox-wrapper .b-sub-folders .b-sub-folders .b-sub-folders .e-item .e-link{padding-left:40px}.b-folders.single-root-inbox .i-am-inbox-wrapper .b-sub-folders .b-sub-folders .b-sub-folders .b-sub-folders .e-item .e-link{padding-left:55px}.btn .btn-text-wrp{padding-left:7px;white-space:normal}.btn.buttonCompose{width:calc(100% - 85px);max-width:-webkit-fit-content;max-width:-moz-fit-content;max-width:fit-content;white-space:nowrap;overflow:hidden;height:19px;display:inline-block;margin-top:1px}html.rl-left-panel-disabled .buttonComposeText,html.rl-left-panel-short .buttonComposeText{display:none}html.rl-left-panel-disabled .btn.buttonCompose,html.rl-left-panel-short .btn.buttonCompose{width:auto}html.rl-left-panel-disabled .btn.buttonContacts,html.rl-left-panel-short .btn.buttonContacts{margin-top:10px!important;margin-left:0!important}html.rl-left-panel-disabled.rl-mobile #rl-left,html.rl-left-panel-short.rl-mobile #rl-left{visibility:hidden}html.rl-mobile .btn.buttonCompose{width:100%}html.rl-mobile .btn.buttonContacts{display:none}.popups .b-folder-clear-content .modal-header{background-color:#fff}.popups .b-folder-create-content .modal-header{background-color:#fff}.popups .b-folder-system-content .modal-header{background-color:#fff}.popups .b-filter-content{width:750px}.popups .b-filter-content .modal-header{background-color:#fff}.popups .b-filter-content .button-delete{cursor:pointer}.popups .b-filter-content .setRecipientsBtn{margin-top:-2px;margin-left:5px}.popups .b-languages-content.modal{width:700px}.popups .b-languages-content.exp{width:701px}.popups .b-languages-content .modal-header{background-color:#fff}.popups .b-languages-content .lang-item{display:inline-block;padding:5px 15px;margin:2px 5px;width:180px;background-color:#fff;text-align:left;border:1px solid transparent;border-radius:2px}.popups .b-languages-content .lang-item.user{background-color:#fffddd;border-color:#fff555}.popups .b-languages-content .lang-item.selected{background-color:#f5f5f5;border-color:#ccc}.popups .b-languages-content .lang-item:hover{background-color:#eee;border-color:#ccc}html.rl-mobile .b-languages-content .lang-item{width:calc(100% - 40px)}.popups .b-account-add-content .modal-header{background-color:#fff}.popups .b-template-add-content.modal{width:750px}.popups .b-template-add-content .modal-header{background-color:#fff}.popups .b-template-add-content .e-template-place{height:300px}.popups .b-compose-open-pgp-content .modal-header,.popups .b-message-open-pgp-content .modal-header,.popups .b-open-pgp-key-add-content .modal-header,.popups .b-open-pgp-key-generate-content .modal-header,.popups .b-open-pgp-key-view-content .modal-header{background-color:#fff}.popups .b-compose-open-pgp-content.modal,.popups .b-message-open-pgp-content.modal,.popups .b-open-pgp-key-add-content.modal,.popups .b-open-pgp-key-generate-content.modal,.popups .b-open-pgp-key-view-content.modal{width:570px}.popups .b-compose-open-pgp-content .inputKey,.popups .b-message-open-pgp-content .inputKey,.popups .b-open-pgp-key-add-content .inputKey,.popups .b-open-pgp-key-generate-content .inputKey,.popups .b-open-pgp-key-view-content .inputKey{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}.popups .b-compose-open-pgp-content .key-viewer,.popups .b-message-open-pgp-content .key-viewer,.popups .b-open-pgp-key-add-content .key-viewer,.popups .b-open-pgp-key-generate-content .key-viewer,.popups .b-open-pgp-key-view-content .key-viewer{max-height:500px;overflow:auto}.popups .b-compose-open-pgp-content.modal{width:800px}.popups .b-compose-open-pgp-content .key-list{background-color:#f9f9f9;border-radius:5px;padding:10px 15px;margin-top:10px;min-height:40px}.popups .b-compose-open-pgp-content .key-list-wrp:hover{overflow:auto}.popups .b-compose-open-pgp-content .key-list-wrp:hover .key-list__item-name{overflow:visible}.popups .b-compose-open-pgp-content .key-list-wrp.empty{text-align:center;padding-top:10px;color:#aaa;font-size:16px}.popups .b-compose-open-pgp-content .key-list__item{color:#333;white-space:nowrap;padding-bottom:4px}.popups .b-compose-open-pgp-content .key-list__item:last-child{padding-bottom:0}.popups .b-compose-open-pgp-content .key-list__item-delete{cursor:pointer}.popups .b-compose-open-pgp-content .key-list__item-delete.disabled{cursor:not-allowed}.popups .b-compose-open-pgp-content .key-list__item-names{color:#333}.popups .b-compose-open-pgp-content .key-list__item-names.empty{color:red}.popups .b-compose-open-pgp-content .key-list__item-name{overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis}.popups .b-compose-open-pgp-content .key-list__item-error{color:red}.popups .b-compose-open-pgp-content .key-list__item-hash{color:#aaa}.popups .b-compose-open-pgp-content .key-actions{margin-top:10px;min-height:40px}.popups .b-compose-open-pgp-content .key-actions select option.even{background-color:#f5f5f5}.popups .b-message-open-pgp-content.modal{width:700px}.popups .b-message-open-pgp-content .key-list{margin-top:5px;overflow:hidden}.popups .b-message-open-pgp-content .key-list__item{color:#555;cursor:pointer;-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap}.popups .b-message-open-pgp-content .key-list__item__radio{padding:3px 5px 0 0;vertical-align:top}.popups .b-message-open-pgp-content .key-list__item__name{border-bottom:1px solid transparent}.popups .b-message-open-pgp-content .key-list__item__names{display:inline-block}.popups .b-message-open-pgp-content .key-list__item__names:hover .key-list__item__name{border-bottom:1px dashed #555}.popups .b-open-pgp-key-add-content.modal{width:645px}.popups .b-open-pgp-key-add-content.modal .inputKey{width:600px}.popups .b-two-factor-content{width:750px}.popups .b-two-factor-content .modal-body{min-height:100px}.popups .b-two-factor-content .modal-header{background-color:#fff}.popups .b-two-factor-test-content .modal-header{background-color:#fff}.popups .b-identity-content.modal{width:750px}.popups .b-identity-content .modal-header{background-color:#fff}.popups .b-identity-content .modal-body{overflow:hidden}.popups .b-identity-content .control-label{width:100px}.popups .b-identity-content .controls{margin-left:120px}.popups .b-identity-content .e-signature-place{height:200px}.popups .b-identity-content .textEmail{margin-top:5px;font-weight:700}.popups .b-advanced-search-content.modal{width:750px}.popups .b-advanced-search-content.modal .control-label{width:100px}.popups .b-advanced-search-content.modal .controls{margin-left:110px}.popups .b-advanced-search-content .modal-header{background-color:#fff}.attachmentItem{position:relative;display:inline-block;margin:5px;max-width:200px;min-width:60px;overflow:hidden;list-style:none;line-height:24px;border:0;background-color:#fff;-webkit-box-shadow:0 1px 4px #ccc;box-shadow:0 1px 4px #ccc;-webkit-box-shadow:0 1px 5px rgba(0,0,0,.2);box-shadow:0 1px 5px rgba(0,0,0,.2);-webkit-box-shadow:0 0 0 1px rgba(0,0,0,.04),0 1px 5px rgba(0,0,0,.1);box-shadow:0 0 0 1px rgba(0,0,0,.04),0 1px 5px rgba(0,0,0,.1);border-radius:3px}.attachmentItem.waiting{opacity:.6}.attachmentItem.checked{-webkit-box-shadow:0 1px 4px #00a;box-shadow:0 1px 4px #00a;-webkit-box-shadow:0 1px 5px rgba(0,0,255,.3);box-shadow:0 1px 5px rgba(0,0,255,.3);-webkit-box-shadow:0 0 0 1px rgba(0,0,255,.1),0 1px 5px rgba(0,0,255,.2);box-shadow:0 0 0 1px rgba(0,0,255,.1),0 1px 5px rgba(0,0,255,.2)}.attachmentItem .checkedParent{position:absolute;top:0;right:0;padding:1px 4px 0 5px;background:#fafafa;border:0 solid #ccc}.attachmentItem .attachmentSize{font-size:12px;color:#999}.attachmentItem.error .attachmentIcon,.attachmentItem.error .attachmentName,.attachmentItem.error .attachmentSize{color:red}.attachmentItem .attachmentIconParent{position:relative;height:56px;width:60px;background:0 0}.attachmentItem .attachmentIconParent .iconBG,.attachmentItem .attachmentIconParent .iconMain,.attachmentItem .attachmentIconParent .iconPreview,.attachmentItem .attachmentIconParent .iconProgress{position:absolute;top:0;left:0;display:inline-block;width:100%;height:100%}.attachmentItem .attachmentIconParent .iconProgress{background:#eee;width:0%}.attachmentItem .attachmentIconParent .iconBG{font-size:18px;text-align:center;color:#999;font-weight:700;line-height:55px;text-shadow:0 1px 0 #fff;text-shadow:0 1px 0 rgba(255,255,255,.8)}.attachmentItem .attachmentIconParent .iconPreview{display:none;background:#555;background-image:none;background:rgba(0,0,0,.5)!important}.attachmentItem .attachmentIconParent .iconPreview .attachmentIcon{color:#fff;text-shadow:0 1px 0 #000}.attachmentItem .attachmentNameParent{position:relative;margin-left:60px;padding:4px 4px 3px 6px;min-width:90px;cursor:pointer;color:#333;background:#fafafa;border-left:1px solid #ddd}.attachmentItem .attachmentIcon{margin:6px 0 0 13px;font-size:36px;width:36px;height:36px;color:#aaa}.attachmentItem .attachmentIcon.icon-none{display:none}.attachmentItem .attachmentIcon.icon-file-certificate{margin-left:15px}.attachmentItem .attachmentIconText{display:inline-block;font-size:28px;width:60px;height:56px;color:#aaa;line-height:56px;text-align:center;font-style:normal}.attachmentItem .attachmentIconParent.hasPreview:hover .iconPreview{display:inline-block}.attachmentItem .attachmentIconParent.hasPreview:hover .iconMain{display:none}.attachmentItem .attachmentIconParent.hasPreplay:hover .iconPreview{display:inline-block}.attachmentItem .attachmentIconParent.hasPreplay:hover .iconMain{display:none}.attachmentItem .showPreplay,.attachmentItem .showPreview{display:none;cursor:pointer}.attachmentItem .attachmentIconParent.hasPreview .showPreview{display:inline}.attachmentItem .attachmentIconParent.hasPreview .hidePreview{display:none}.attachmentItem .attachmentIconParent.hasPreplay .showPreplay{display:inline}.attachmentItem .attachmentIconParent.hasPreplay .hidePreview{display:none}html.rl-no-preview-pane .messageList.message-selected{display:none}.messageList .toolbar{position:absolute;top:0;right:0;left:0;height:30px;padding:10px 1px;z-index:102;white-space:nowrap}.messageList .b-footer{position:absolute;bottom:0;right:0;left:0;height:30px;padding:7px;z-index:101;background-color:#eee;border-bottom-right-radius:5px;border-bottom-left-radius:5px}.messageList .b-footer .e-quota{display:inline-block;margin-top:5px;margin-left:5px;font-size:18px;cursor:help}.messageList .b-footer .e-quota:hover{border-bottom:1px dashed #333}.messageList .inputSearch{width:258px}.messageList .btn.buttonMoreSearch{padding-left:8px;padding-right:8px}.messageList .b-message-list-wrapper{position:absolute;top:50px;right:0;left:0;bottom:5px;border:1px solid #aaa;-webkit-box-shadow:0 2px 8px rgba(0,0,0,.2);box-shadow:0 2px 8px rgba(0,0,0,.2);border-radius:5px;z-index:101}.messageList .second-toolbar{position:absolute;top:0;right:0;left:0;height:29px;padding:10px 8px 10px 11px;z-index:101;white-space:nowrap;background-color:#eee;border-top-right-radius:5px;border-top-left-radius:5px}.messageList .second-toolbar .checkboxCkeckAll{margin:5px 0}.messageList .line-loading{position:absolute;left:0;right:0;z-index:102;height:0;top:50px}.messageList .mainDelimiter{position:absolute;left:0;right:0;height:1px;z-index:101;background-color:#bbb}.messageList .toolbarDelimiter{top:49px}.messageList .footerDelimiter{bottom:44px}.messageList .b-content{position:absolute;top:50px;bottom:45px;left:0;right:0;padding:0;overflow-x:hidden;overflow-y:auto;z-index:101;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#fff}.messageList .b-content .content{-webkit-overflow-scrolling:touch}.messageList .b-content .listClear{color:#333;text-align:center;padding:10px;font-size:14px;line-height:13px}.messageList .b-content .listDragOver,.messageList .b-content .listEmptyList,.messageList .b-content .listEmptyListLoading,.messageList .b-content .listEmptySearchList,.messageList .b-content .listError{color:#999;text-align:center;padding:60px 10px;font-size:24px;line-height:30px}.messageList .b-content .listDragOver .e-icon,.messageList .b-content .listEmptyList .e-icon,.messageList .b-content .listEmptyListLoading .e-icon,.messageList .b-content .listEmptySearchList .e-icon,.messageList .b-content .listError .e-icon{font-size:24px;line-height:30px}.messageList .b-content .listDragOver{max-height:0;overflow:hidden;padding:0 10px}.messageList .b-content .listDragOver.viewAppendArea{max-height:120px;padding:30px 10px}.messageList .b-content .listDragOver.dragOverEnter{background-color:#e0fdda;color:#333}.messageList .b-content .listError{color:#da4f49}.messageList .b-content .listSearchDesc{font-size:18px;padding:15px;border-bottom:1px solid #eee}html.rl-mobile .messageList .b-content .listSearchDesc{font-size:16px;padding:12px}.messageList .b-content .listThreadUidDesc{font-size:16px;padding:7px 20px 6px 20px;background-color:#aaa;border-bottom:1px solid #888;color:#fff;cursor:pointer;text-shadow:0 1px 0 #000;text-align:center}.messageList .b-content .delimiter{display:block;height:1px;background-color:#e5e5e5}.messageList .b-content .messageListItem:last-child{border-bottom:1px solid #e5e5e5}.messageList .b-content .messageListItem:last-child.selected{border-bottom:1px solid #bfd5ef}.messageList .b-content .fullThreadsParent{height:25px;padding:3px 5px;background-color:#f4f4f4;text-align:center}.messageList .b-content .messageListItem{position:relative;height:52px;max-height:60px;font-size:12px;line-height:21px;overflow:hidden;cursor:pointer;margin:0;border:0 solid transparent;z-index:100;background-color:#f9f9f9}.messageList .b-content .messageListItem .delimiter{position:relative;display:block;height:1px;background-color:#999;opacity:.2}.messageList .b-content .messageListItem .wrapper{padding:5px 0}.messageList .b-content .messageListItem .sidebarParent{display:inline-block;width:6px;background-color:#eee;float:left;height:100%}.messageList .b-content .messageListItem.focused{background-color:#f5f5f5}.messageList .b-content .messageListItem.focused .sidebarParent{background-color:#ccc!important}.messageList .b-content .messageListItem .importantMark{display:none;color:red;margin-right:5px}.messageList .b-content .messageListItem.deleted-mark{opacity:.7}.messageList .b-content .messageListItem.deleted-mark .sender,.messageList .b-content .messageListItem.deleted-mark .subject,.messageList .b-content .messageListItem.deleted-mark .subject-prefix,.messageList .b-content .messageListItem.deleted-mark .subject-suffix{text-decoration:line-through}.messageList .b-content .messageListItem.important .importantMark{display:inline}.messageList .b-content .messageListItem.e-single-line{height:35px}.messageList .b-content .messageListItem.e-single-line .wrapper{line-height:25px;padding:5px}.messageList .b-content .messageListItem.new{max-height:0}.messageList .b-content .messageListItem.deleted{max-height:0;border-color:transparent!important}.messageList .b-content .messageListItem .checkedParent{display:inline-block;float:left;margin-top:11px;padding:0 8px 0 6px;font-size:14px}.messageList .b-content .messageListItem.e-single-line .checkedParent{margin-top:1px}.messageList .b-content .messageListItem .flagParent{display:inline-block;float:right;padding:0 10px 0 5px}.messageList .b-content .messageListItem.e-single-line .flagParent{float:left;padding:0 8px 0 2px}.messageList .b-content .messageListItem .dateParent{display:inline-block;float:right;position:relative;margin:0 5px;color:#999;font-size:11px}.messageList .b-content .messageListItem .threadsParent{display:inline-block;float:right;position:relative}.messageList .b-content .messageListItem .attachmentParent{display:inline-block;float:right;position:relative;margin:2px 10px 0 5px}.messageList .b-content .messageListItem.e-single-line .attachmentParent{float:left;margin:0 8px 0 0}.messageList .b-content .messageListItem .senderParent{display:block;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis}.messageList .b-content .messageListItem .threadsCountParent{display:inline;overflow:hidden;background-color:#eee;padding:1px 5px;margin-right:5px;border:1px solid #ccc;border-radius:5px}.messageList .b-content .messageListItem .threadsCountParent.lastSelected{background-color:#999;border-color:#999;color:#fff}.messageList .b-content .messageListItem .threadsCountParent:hover{border-color:#666}.messageList .b-content .messageListItem.e-single-line .senderParent{display:inline-block;-o-text-overflow:none;text-overflow:none;width:200px;float:left;font-weight:400}.messageList .b-content .messageListItem .subjectParent{display:block;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;color:#000}.messageList .b-content .messageListItem .dateParent,.messageList .b-content .messageListItem .senderParent,.messageList .b-content .messageListItem .subjectParent{white-space:nowrap}.messageList .b-content .messageListItem .subjectParent .emptySubjectText{display:none;font-style:italic;color:#999}.messageList .b-content .messageListItem.emptySubject .subjectParent .subject,.messageList .b-content .messageListItem.emptySubject .subjectParent .subject-prefix,.messageList .b-content .messageListItem.emptySubject .subjectParent .subject-suffix{display:none}.messageList .b-content .messageListItem.emptySubject .subjectParent .emptySubjectText{display:inline}.messageList .b-content .messageListItem .sender,.messageList .b-content .messageListItem .subject,.messageList .b-content .messageListItem .subject-suffix{overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis}.messageList .b-content .messageListItem .threads-len .threads-len-data{background-color:#eee;color:#666;border-radius:6px;padding:2px 0 1px 6px;margin-right:2px;border:1px solid #ccc}.messageList .b-content .messageListItem .threads-len .threads-len-data [class*=" icon-"],.messageList .b-content .messageListItem .threads-len .threads-len-data [class^=icon-]{font-size:14px}.messageList .b-content .messageListItem .threads-len .threads-len-data:hover{background-color:#aaa;border-color:#666;text-shadow:0 1px 0 #999;color:#fff}.messageList .b-content .messageListItem .subject-prefix{color:#888}.messageList .b-content .messageListItem .attachment{display:none}.messageList .b-content .messageListItem .flagOff,.messageList .b-content .messageListItem .flagOn,.messageList .b-content .messageListItem .flagOnHalf{cursor:pointer;display:inline-block}.messageList .b-content .messageListItem .flagOff{opacity:.5}.messageList .b-content .messageListItem .flagOff:hover{opacity:1}.messageList .b-content .messageListItem .flagOn,.messageList .b-content .messageListItem .flagOnHalf{display:none;color:orange}.messageList .b-content .messageListItem .forwardFlag,.messageList .b-content .messageListItem .replyFlag{display:none}.messageList .b-content .messageListItem.answered .replyFlag{display:inline-block}.messageList .b-content .messageListItem.forwarded .forwardFlag{display:inline-block}.messageList .b-content .messageListItem.withAttachments .attachment{display:inline-block;color:#666;text-shadow:0 1px 0 #eee}.messageList .b-content .messageListItem.hasUnseenSubMessage{background-color:#ffffd9}.messageList .b-content .messageListItem.hasUnseenSubMessage .sidebarParent{background-color:#ffdb99}.messageList .b-content .messageListItem.hasUnseenSubMessage.focused .sidebarParent{background-color:#cc8400!important}.messageList .b-content .messageListItem.unseen{background-color:#ffffd9}.messageList .b-content .messageListItem.unseen .sender,.messageList .b-content .messageListItem.unseen .subject,.messageList .b-content .messageListItem.unseen .subject-suffix{font-weight:700}.messageList .b-content .messageListItem.unseen .sidebarParent{background-color:orange}.messageList .b-content .messageListItem.unseen.focused .sidebarParent{background-color:#cc8400!important}.messageList .b-content .messageListItem.checked .sidebarParent{background-color:#69a8f5!important}.messageList .b-content .messageListItem.checked.focused .sidebarParent{background-color:#217ef0!important}.messageList .b-content .messageListItem.selected{background-color:#dfefff;z-index:101}.messageList .b-content .messageListItem.selected .sidebarParent{background-color:#398cf2!important}.messageList .b-content .messageListItem.selected .delimiter{background-color:#398cf2;opacity:.2}.messageList .b-content .messageListItem.selected+.messageListItem .delimiter{background-color:#398cf2;opacity:.3}.messageList .b-content .messageListItem.hasFlaggedSubMessage .flagOff,.messageList .b-content .messageListItem.hasFlaggedSubMessage .flagOn{display:none}.messageList .b-content .messageListItem.hasFlaggedSubMessage .flagOnHalf{display:inline-block}.messageList .b-content .messageListItem.flagged .flagOff,.messageList .b-content .messageListItem.flagged .flagOnHalf{display:none}.messageList .b-content .messageListItem.flagged .flagOn{display:inline-block}.messageList.message-focused .b-message-list-wrapper{background-color:#000}.messageList.message-focused .b-content{opacity:.97}.messageList.hideMessageListCheckbox .checkboxCkeckAll,.messageList.hideMessageListCheckbox .checkedParent{display:none!important}.messageList.hideMessageListCheckbox .sidebarParent{margin-right:10px!important}html.ssm-state-desktop-large .messageList .b-content .messageListItem{font-size:13px}html.ssm-state-desktop-large .messageList .b-content .messageListItem .dateParent{font-size:13px}html.cssanimations .messageList .line-loading{height:5px!important}.draggablePlace{z-index:10003;color:#fff;background-color:#333;background-color:rgba(0,0,0,.5);padding:4px 10px;min-width:30px;height:20px;cursor:pointer;cursor:move}html.rl-mobile #rl-sub-left .messageList .inputSearch{width:160px!important}html.rl-no-preview-pane .messageView{display:none}html.rl-no-preview-pane .messageView.message-selected{display:block}.messageView{z-index:100}.messageView .toolbar{position:absolute;top:0;right:0;left:0;height:30px;padding:10px 0;color:#fff}.messageView .b-content{position:absolute;margin:0;top:58px;bottom:13px;right:8px;left:-2px;border:1px solid #aaa;border-radius:3px;background-color:#fff}.messageView .b-content .b-message-view-checked-helper{text-align:center;font-size:70px;line-height:70px;padding-top:100px;color:#999}.messageView .b-content .b-message-view-checked-helper .icon-mail{font-size:100px;font-size:50px;line-height:90px;padding-left:10px}.messageView .b-content .logoPlace{text-align:center}.messageView .b-content .b-message-view-desc{text-align:center;font-size:24px;line-height:30px;color:#999;padding:120px 10px 0 10px}.messageView .b-content .b-message-view-desc.error{color:#da4f49}.messageView .b-content .b-message-view-iframe-backdrop{display:none;background:0 0;position:absolute;width:100%;height:100%;top:0;left:0;right:0;bottom:0;opacity:.1}.messageView .b-content .content{-webkit-overflow-scrolling:touch}.messageView .b-content .message-fixed-button-toolbar{z-index:100;position:absolute;top:33px;right:10px}.messageView .b-content .infoParent{cursor:pointer;margin:0 2px 0 5px;opacity:.3}.messageView .b-content .infoParent:hover{opacity:.6}.messageView .b-content .flagParent{cursor:pointer;margin:0 20px 0 2px}.messageView .b-content .flagParent .flagOn{color:orange}.messageView .b-content .flagParent .flagOff{opacity:.5}.messageView .b-content .flagParent .flagOff:hover{opacity:1}.messageView .b-content .messageItemHeader{position:absolute;padding:10px;background-color:#f8f8f8;border-top:0;border-bottom:1px solid #ddd;border-top-right-radius:5px;border-top-left-radius:5px;z-index:1;top:0;left:0;right:0}.messageView .b-content .messageItemHeader .fromPic{display:inline-block;width:50px;height:50px;float:left;padding:2px;margin:0 5px 0 0;background:#fff;border:1px solid #ccc;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box}.messageView .b-content .messageItemHeader .subjectParent{font-size:18px;font-weight:700;-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;margin-bottom:8px;line-height:100%;height:22px;vertical-align:middle}.messageView .b-content .messageItemHeader .messageButtons{margin-top:5px}.messageView .b-content .messageItemHeader .informationShort{margin:4px 0;margin-left:5px;margin-right:50px}.messageView .b-content .messageItemHeader .informationShort a{color:#369;text-decoration:underline;cursor:pointer;padding:2px}.messageView .b-content .messageItemHeader .informationShort a:focus{outline:1px;outline-style:dotted}html.rl-mobile .messageView .b-content .messageItemHeader .informationShort{-o-text-overflow:ellipsis;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.messageView .b-content .messageItemHeader .informationShortWrp{max-height:100px;overflow-y:auto;min-height:30px;margin-top:4px}.messageView .b-content .messageItemHeader .informationFull{margin-top:10px;border:1px solid #ddd;background-color:#fff;border-radius:5px;padding:8px 0;overflow:hidden}.messageView .b-content .messageItemHeader .informationFull .size{margin-left:4px}.messageView .b-content .messageItemHeader .informationFull table{width:100%}.messageView .b-content .messageItemHeader .informationFull table,.messageView .b-content .messageItemHeader .informationFull td,.messageView .b-content .messageItemHeader .informationFull tr{border-spacing:0}.messageView .b-content .messageItemHeader .informationFull td{padding:0 10px;vertical-align:top;min-width:43px}.messageView .b-content .messageItemHeader .informationFull td:first-child{border-right:1px solid #ddd;text-align:right;width:1%}.messageView .b-content .messageItemHeader .informationFull .uiLabel{white-space:nowrap}.messageView .b-content .messageItemHeader .informationFull .uiLabelValue{word-break:break-all}.messageView .b-content .messageItemHeader .emptySubjectText{display:none;font-style:italic;font-weight:400;color:#999}.messageView .b-content .messageItemHeader.emptySubject .emptySubjectText{display:inline}.messageView .b-content .messageItem{position:absolute;top:0;bottom:0;left:0;right:0;overflow:auto;-webkit-overflow-scrolling:touch;border-radius:3px}.messageView .b-content .messageItem .buttonFull,.messageView .b-content .messageItem .buttonUnFull,.messageView .b-content .messageItem .buttonUp{display:inline-block;position:fixed;right:25px;bottom:25px;height:30px;width:30px;text-align:center;vertical-align:middle;line-height:30px;background-color:transparent;background-color:#fff;border:1px solid #333;color:#333;z-index:2;cursor:pointer;border-radius:5px;opacity:.5}.messageView .b-content .messageItem .buttonFull:hover,.messageView .b-content .messageItem .buttonUnFull:hover,.messageView .b-content .messageItem .buttonUp:hover{opacity:.8;border-color:#666;background-color:#888;color:#fff}.messageView .b-content .messageItem .buttonUp{right:65px;z-index:0}.messageView .b-content .messageItem .buttonUnFull,.messageView .b-content .messageItem .buttonUp{display:none}.messageView .b-content .messageItem .loading{text-align:center;font-size:24px;color:grey;padding-top:50px}.messageView .b-content .messageItem .line-loading{height:0}.messageView .b-content .messageItem .pgpEncrypted,.messageView .b-content .messageItem .pgpSigned,.messageView .b-content .messageItem .readReceipt,.messageView .b-content .messageItem .showImages{cursor:pointer;padding:10px 15px;border-bottom:1px solid #ddd;background-color:#eee}.messageView .b-content .messageItem .pgpInfo{padding:5px 15px;border-bottom:1px solid #ddd;background-color:#fcf8e3}.messageView .b-content .messageItem .pgpInfo.success{background-color:#e9f4ff}.messageView .b-content .messageItem .readReceipt{background-color:#ffffd9}.messageView .b-content .messageItem .attachmentsPlace{padding:10px 10px 6px 10px;background:#eee;border-bottom:1px solid #ddd;position:relative}.messageView .b-content .messageItem .attachmentsPlace .attachmentList{margin:0}.messageView .b-content .messageItem .attachmentsPlace .checkedParent{display:none}.messageView .b-content .messageItem .attachmentsPlace.selection-mode .checkedParent{display:inline-block}.messageView .b-content .messageItem .attachmentsPlace.unselectedAttachmentsError .attachmentItem{-webkit-box-shadow:0 1px 4px red;box-shadow:0 1px 4px red;-webkit-box-shadow:0 1px 5px rgba(255,0,0,.4);box-shadow:0 1px 5px rgba(255,0,0,.4);-webkit-box-shadow:0 0 0 1px rgba(255,0,0,.2),0 1px 5px rgba(255,0,0,.3);box-shadow:0 0 0 1px rgba(255,0,0,.2),0 1px 5px rgba(255,0,0,.3)}.messageView .b-content .messageItem .attachmentsPlace .controls-handle{position:absolute;bottom:5px;right:8px;color:#999;cursor:pointer}.messageView .b-content .messageItem .attachmentsControls{padding:7px 5px 7px 14px;background:#e8e8e8;border-bottom:1px solid #ddd}.messageView .b-content .messageItem .rlBlockquoteSwitcher{background-color:#eee;border:1px solid #999;display:inline-block;width:30px;height:14px;line-height:14px;text-align:center;cursor:pointer;margin:10px 0;opacity:.5}.messageView .b-content .messageItem .rlBlockquoteSwitcher:hover{opacity:1}.messageView .b-content .messageItem .bodySubHeader{z-index:2}.messageView .b-content .messageItem .bodyText{color:#000;font-family:Arial,Verdana,Geneva,sans-serif}.messageView .b-content .messageItem .bodyText .b-text-part{height:100%}.messageView .b-content .messageItem .bodyText .b-text-part div[data-x-div-type=html]{height:100%}.messageView .b-content .messageItem .bodyText .b-text-part div[data-x-div-type=html] div[data-x-div-type=body]{height:100%}.messageView .b-content .messageItem .bodyText .b-text-part a{color:#00f;text-decoration:underline}.messageView .b-content .messageItem .bodyText .b-text-part a:visited{color:#609}.messageView .b-content .messageItem .bodyText .b-text-part a:active{color:red}.messageView .b-content .messageItem .bodyText .b-text-part blockquote{border-left:2px solid #000;padding:0 10px;margin:0}.messageView .b-content .messageItem .bodyText .b-text-part .rl-bq-switcher.hidden-bq{display:none}.messageView .b-content .messageItem .bodyText .b-text-part.html div[data-x-div-type=body]{margin:15px}.messageView .b-content .messageItem .bodyText .b-text-part.html code,.messageView .b-content .messageItem .bodyText .b-text-part.html pre{margin:0;padding:0;background:#fff;border:none;border-radius:0;font-family:Monaco,Menlo,Consolas,'Courier New',monospace;display:block;word-break:normal;word-wrap:break-word;background-color:#f9f9f9}.messageView .b-content .messageItem .bodyText .b-text-part.html code{display:inline;padding:2px 5px}.messageView .b-content .messageItem .bodyText .b-text-part.html pre{padding:5px 10px;border-radius:5px;background-color:#f9f9f9}.messageView .b-content .messageItem .bodyText .b-text-part.html pre>code{padding:0}.messageView .b-content .messageItem .bodyText .b-text-part.plain{padding:15px;font-family:Monaco,Menlo,Consolas,'Courier New',monospace}.messageView .b-content .messageItem .bodyText .b-text-part.plain pre{margin:0;padding:0;background:#fff;border:none;font-family:Monaco,Menlo,Consolas,'Courier New',monospace;display:block;word-break:normal}.messageView .b-content .messageItem .bodyText .b-text-part.plain pre.b-plain-openpgp{display:inline-block;padding:6px 10px;border:1px dashed #666;background:#fff;word-break:break-all}.messageView .b-content .messageItem .bodyText .b-text-part.plain pre.b-plain-openpgp.success{border-color:green;background-color:rgba(0,255,0,.03)}.messageView .b-content .messageItem .bodyText .b-text-part.plain pre.b-plain-openpgp.error{border-color:red;background-color:rgba(255,0,0,.03)}.messageView .b-content .messageItem .bodyText .b-text-part.plain blockquote{border-left:2px solid #00f;color:#00f}.messageView .b-content .messageItem .bodyText .b-text-part.plain blockquote blockquote{border-left:2px solid green;color:green}.messageView .b-content .messageItem .bodyText .b-text-part.plain blockquote blockquote blockquote{border-left:2px solid red;color:red}.messageView .b-content .messageItem .bodyText .b-text-part .b-openpgp-control{display:inline-block;cursor:pointer;color:#777}.messageView .b-content .messageItem .bodyText .b-text-part .b-openpgp-control:hover{color:#111}.messageView .b-content .messageItem .bodyText .b-text-part .b-openpgp-control.success{color:green;cursor:help}.messageView .b-content .messageItem .bodyText .b-text-part .b-openpgp-control.error{color:red}.messageView.message-focused .b-content{z-index:101;-webkit-box-shadow:0 2px 8px rgba(0,0,0,.2);box-shadow:0 2px 8px rgba(0,0,0,.2);border-radius:3px;border-color:#9d9d9d}.messageView .thread-controls .dropdown-toggle{padding-left:10px;padding-right:10px}.messageView .thread-controls.open .dropdown-toggle{padding-left:10px;padding-right:10px}.messageView .thread-list .e-link{padding:4px 8px 6px 10px}.messageView .thread-list.hide-more .thread-list-message.more-that{display:none}.messageView .thread-list .thread-date{font-size:13px;color:#999}.messageView .thread-list .more-threads{text-align:center;padding:8px;background-color:#f5f5f5;color:#555;text-decoration:underline;border-top:1px dashed #555}html.rl-resizer .b-message-view-iframe-backdrop{display:block!important}html.rl-no-preview-pane .messageView .toolbar{padding-left:1px}html.rl-no-preview-pane .messageView .b-content{top:50px;left:0;bottom:5px;right:5px;border:1px solid #aaa;-webkit-box-shadow:0 2px 8px rgba(0,0,0,.2);box-shadow:0 2px 8px rgba(0,0,0,.2);border-radius:5px}html.rl-bottom-preview-pane .messageView .b-content{bottom:5px}html.cssanimations .messageItem .line-loading{height:5px!important}html.rl-message-fullscreen #rl-bottom,html.rl-message-fullscreen #rl-left{display:none!important}html.rl-message-fullscreen #rl-right .RL-MailMessageList,html.rl-message-fullscreen #rl-right .RL-MailMessageView .messageView .toolbar,html.rl-message-fullscreen #rl-right .RL-SettingsPane,html.rl-message-fullscreen #rl-right .RL-SystemDropDown{display:none!important}html.rl-message-fullscreen .messageView .b-content{position:fixed!important;margin:5px!important;top:0!important;left:0!important;right:0!important;bottom:0!important;z-index:10000!important;border:1px solid #aaa!important;border-radius:3px!important}html .messageItem .buttonUp{display:none!important}html .messageItem.scroller-shadow-top .buttonUp{display:inline-block!important}html.rl-desktop .messageItem .buttonFull,html.rl-desktop .messageItem .buttonUp{display:none!important}html.rl-desktop .messageItem:hover .buttonFull,html.rl-desktop .messageItem:hover.scroller-shadow-top .buttonUp{display:inline-block!important}html.rl-message-fullscreen .messageItem .buttonUnFull{display:inline-block!important}html.rl-message-fullscreen .messageItem .buttonFull{display:none!important}html.rl-message-fullscreen .messageItem .buttonUp{display:none!important}html.rl-message-fullscreen .messageItem.scroller-shadow-top .buttonUp{display:inline-block!important}.b-contacts-content .control-group .control-label.fix-width{width:50px}.b-contacts-content .control-group .controls.fix-width{margin-left:70px}.b-contacts-content.modal{position:absolute;right:0;top:0;bottom:0;left:0;width:900px;min-height:300px;max-height:700px;margin:auto}.b-contacts-content.modal .modal-body{overflow:auto;height:100%;background-color:#f5f5f5;padding:0}.b-contacts-content.modal .b-header-toolbar{height:40px;background-color:#aaa;color:#fff;background-color:#333;background-color:rgba(0,0,0,.8)!important}.b-contacts-content.modal .b-header-toolbar .close,.b-contacts-content.modal .b-header-toolbar .close-custom{color:#fff;opacity:1}.b-contacts-content.modal .b-header-toolbar .btn{margin-top:4px}.b-contacts-content.modal .b-list-toolbar{padding:0;height:45px;text-align:right;width:220px;-webkit-box-shadow:inset 0 -1px 0 #ccc;box-shadow:inset 0 -1px 0 #ccc}.b-contacts-content.modal .b-list-toolbar .e-search{margin-top:7px;width:200px}.b-contacts-content.modal .b-list-footer-toolbar{position:absolute;left:0;bottom:0;height:105px;width:220px;background-color:#eee;-webkit-box-shadow:inset 0 1px 0 #ccc;box-shadow:inset 0 1px 0 #ccc}.b-contacts-content.modal .b-list-footer-toolbar .footer-pager{padding:8px 10px 0 0}.b-contacts-content.modal .b-list-content{position:absolute;top:45px;bottom:105px;left:0;width:220px;overflow:hidden;overflow-y:auto}.b-contacts-content.modal .b-list-content .content{-webkit-overflow-scrolling:touch}.b-contacts-content.modal .b-list-content .listClear{color:#333;text-align:center;padding:10px;font-size:14px;line-height:13px;background-color:#fff;-webkit-box-shadow:inset 0 -1px 0 #ccc;box-shadow:inset 0 -1px 0 #ccc}.b-contacts-content.modal .b-list-content .listEmptyList,.b-contacts-content.modal .b-list-content .listEmptyListLoading,.b-contacts-content.modal .b-list-content .listEmptySearchList{color:#999;text-align:center;padding:60px 10px;font-size:24px;line-height:30px}.b-contacts-content.modal .b-list-content.hideContactListCheckbox .checkboxCkeckAll,.b-contacts-content.modal .b-list-content.hideContactListCheckbox .checkedParent{display:none!important}.b-contacts-content.modal .b-list-content.hideContactListCheckbox .sidebarParent{margin-right:10px!important}.b-contacts-content.modal .b-list-content .e-contact-foreach{border-bottom:1px solid #ddd}.b-contacts-content.modal .b-list-content .e-contact-item{position:relative;height:45px;max-height:45px;line-height:45px;overflow:hidden;cursor:pointer;margin:0;border:0 solid transparent;z-index:100}.b-contacts-content.modal .b-list-content .e-contact-item .delimiter{position:relative;display:block;height:1px;background-color:#999;opacity:.2}.b-contacts-content.modal .b-list-content .e-contact-item .wrapper{padding:0}.b-contacts-content.modal .b-list-content .e-contact-item .sidebarParent{display:inline-block;width:6px;background-color:#eee;float:left;height:100%}.b-contacts-content.modal .b-list-content .e-contact-item.focused .sidebarParent{background-color:#bbb}.b-contacts-content.modal .b-list-content .e-contact-item.deleted{max-height:0;border-color:transparent!important}.b-contacts-content.modal .b-list-content .e-contact-item .checkedParent{display:inline-block;float:left;padding:0 8px 0 6px}.b-contacts-content.modal .b-list-content .e-contact-item .shareParent{display:none;float:right;position:relative;margin:2px 8px 0 5px}.b-contacts-content.modal .b-list-content .e-contact-item .nameParent{display:block;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;color:#333;font-size:16px}.b-contacts-content.modal .b-list-content .e-contact-item .emailParent,.b-contacts-content.modal .b-list-content .e-contact-item .nameParent{white-space:nowrap}.b-contacts-content.modal .b-list-content .e-contact-item .displayEmail,.b-contacts-content.modal .b-list-content .e-contact-item .displayName{overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis}.b-contacts-content.modal .b-list-content .e-contact-item .displayImg{display:inline-block;float:right;position:relative;margin:0 5px}.b-contacts-content.modal .b-list-content .e-contact-item.shared .shareParent{display:inline-block}.b-contacts-content.modal .b-list-content .e-contact-item.checked{z-index:101}.b-contacts-content.modal .b-list-content .e-contact-item.checked .sidebarParent{background-color:#69a8f5}.b-contacts-content.modal .b-list-content .e-contact-item.checked.focused .sidebarParent{background-color:#519af3!important}.b-contacts-content.modal .b-list-content .e-contact-item.selected{background-color:#fff;z-index:102}.b-contacts-content.modal .b-list-content .e-contact-item.selected .sidebarParent{background-color:#398cf2}.b-contacts-content.modal .b-list-content .e-contact-item.selected.focused .sidebarParent{background-color:#217ef0!important}.b-contacts-content.modal .b-view-content-toolbar{background-color:#f5f5f5;padding:7px;position:absolute;top:0;right:0;left:220px;height:31px;text-align:center;-webkit-box-shadow:inset 0 -1px 0 #ccc;box-shadow:inset 0 -1px 0 #ccc}.b-contacts-content.modal .b-view-content-toolbar .button-save-contact.no-disabled.dirty{color:#51a351;font-weight:700}.b-contacts-content.modal .b-view-content-toolbar.read-only .button-save-contact{display:none}.b-contacts-content.modal .b-view-content{position:absolute;top:45px;bottom:60px;left:220px;right:0;overflow:hidden;overflow-y:auto;background-color:#fff;border-left:1px solid #ddd}.b-contacts-content.modal .b-view-content .content{-webkit-overflow-scrolling:touch}.b-contacts-content.modal .b-view-content .contactValueLargeStatic,.b-contacts-content.modal .b-view-content .contactValueStatic,.b-contacts-content.modal .b-view-content .contactValueTextAreaStatic{height:20px;line-height:20px;font-size:18px;display:inline-block;padding:5px 7px;color:#555;display:none}.b-contacts-content.modal .b-view-content.read-only .contactValueLargeStatic,.b-contacts-content.modal .b-view-content.read-only .contactValueStatic,.b-contacts-content.modal .b-view-content.read-only .contactValueTextAreaStatic{display:inline-block}.b-contacts-content.modal .b-view-content.read-only .contactValueInput,.b-contacts-content.modal .b-view-content.read-only .contactValueInputLarge,.b-contacts-content.modal .b-view-content.read-only .contactValueTextArea{display:none}.b-contacts-content.modal .b-view-content .b-contact-view-desc{text-align:center;font-size:24px;line-height:30px;padding-top:120px;color:#999}.b-contacts-content.modal .b-view-content .top-part{padding-top:20px}.b-contacts-content.modal .b-view-content .property-line{margin-bottom:5px}.b-contacts-content.modal .b-view-content .top-row{padding:10px 0;height:30px}.b-contacts-content.modal .b-view-content .add-link{margin-left:2px;padding:5px;font-size:12px;color:#aaa}.b-contacts-content.modal .b-view-content .contactValueLargeStatic,.b-contacts-content.modal .b-view-content .contactValueStatic,.b-contacts-content.modal .b-view-content .contactValueTextAreaStatic{font-size:18px;display:none}.b-contacts-content.modal .b-view-content .contactValueInput,.b-contacts-content.modal .b-view-content .contactValueInputLarge,.b-contacts-content.modal .b-view-content .contactValueTextArea{-webkit-box-shadow:none;box-shadow:none;border-color:#fff;font-size:18px;width:300px}.b-contacts-content.modal .b-view-content .contactValueInput:hover,.b-contacts-content.modal .b-view-content .contactValueInputLarge:hover,.b-contacts-content.modal .b-view-content .contactValueTextArea:hover{-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);border-color:#ccc}.b-contacts-content.modal .b-view-content .contactValueInput:focus,.b-contacts-content.modal .b-view-content .contactValueInputLarge:focus,.b-contacts-content.modal .b-view-content .contactValueTextArea:focus{-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);border-color:#999}.b-contacts-content.modal .b-view-content .contactValueInput::-webkit-input-placeholder,.b-contacts-content.modal .b-view-content .contactValueInputLarge::-webkit-input-placeholder,.b-contacts-content.modal .b-view-content .contactValueTextArea::-webkit-input-placeholder{color:#ddd}.b-contacts-content.modal .b-view-content .contactValueInput::-moz-placeholder,.b-contacts-content.modal .b-view-content .contactValueInputLarge::-moz-placeholder,.b-contacts-content.modal .b-view-content .contactValueTextArea::-moz-placeholder{color:#ddd}.b-contacts-content.modal .b-view-content .contactValueInput:-moz-placeholder,.b-contacts-content.modal .b-view-content .contactValueInputLarge:-moz-placeholder,.b-contacts-content.modal .b-view-content .contactValueTextArea:-moz-placeholder{color:#ddd}.b-contacts-content.modal .b-view-content .contactValueInput:-ms-input-placeholder,.b-contacts-content.modal .b-view-content .contactValueInputLarge:-ms-input-placeholder,.b-contacts-content.modal .b-view-content .contactValueTextArea:-ms-input-placeholder{color:#ddd}.b-contacts-content.modal .b-view-content .contactValueTextArea{width:300px}.b-contacts-content.modal .b-view-content .contactValueInputLarge{width:400px}.b-contacts-content.modal .b-view-content .hasError .contactValueInput{color:#ee5f5b;border-color:#ee5f5b}.b-contacts-content.modal .b-view-content .e-save-trigger{position:absolute;top:25px;left:10px}.b-contacts-content.modal .b-view-content .e-read-only-sign{display:none;position:absolute;top:20px;right:40px}.b-contacts-content.modal .b-view-content .e-share-sign{position:absolute;top:20px;right:20px;cursor:pointer}.b-contacts-content.modal .b-view-content.read-only .e-read-only-sign{display:inline-block}.b-contacts-content.modal .b-view-content.read-only .e-share-sign{display:none}.b-contacts-content .e-contact-item{position:relative;height:55px;max-height:60px;line-height:22px;overflow:hidden;cursor:pointer;margin:0;border:0 solid transparent;z-index:100}html.rl-mobile .b-contacts-content .b-list-content,html.rl-mobile .b-contacts-content .b-list-footer-toolbar,html.rl-mobile .b-contacts-content .b-list-toolbar{width:170px}html.rl-mobile .b-contacts-content .b-list-toolbar .e-search{width:150px}html.rl-mobile .b-contacts-content .b-view-content,html.rl-mobile .b-contacts-content .b-view-content-toolbar{left:170px}.b-compose.modal{width:850px;margin:10px auto}.b-compose.modal .modal-body{overflow:auto;padding:0}.b-compose .attachmentAreaParent,.b-compose .textAreaParent{overflow:hidden;position:relative}.b-compose .attachmentAreaParent{padding:10px 10px 6px 10px;background:#ddd;border-top:1px solid #ccc;overflow-y:auto}.b-compose .attachmentAreaParent .no-attachments-desc{padding:50px 10px;text-align:center;font-size:24px;color:#666;text-shadow:0 1px 0 #fff;text-shadow:0 1px 0 rgba(255,255,255,.5)}.b-compose .attachmentAreaParent .attachmentList{margin:0;padding:10px}.b-compose .b-header-toolbar{height:40px;color:#fff;background-color:#aaa;background-color:#333;background-color:rgba(0,0,0,.8)!important}.b-compose .b-header-toolbar .close,.b-compose .b-header-toolbar .close-custom,.b-compose .b-header-toolbar .minimize-custom{opacity:1;color:#fff;border-color:#eee;font-size:24px;line-height:24px}.b-compose .b-header-toolbar .btn.disabled.button-delete{visibility:hidden}.b-compose .b-header-toolbar .button-delete,.b-compose .b-header-toolbar .button-save,.b-compose .b-header-toolbar .saved-text{margin-left:8px}.b-compose .b-header-toolbar .button-close,.b-compose .b-header-toolbar .button-skip{margin-left:8px}.b-compose .b-header-toolbar .disabled.button-delete{margin-left:0}.b-compose .b-header{padding:10px;background-color:#eee;color:#333}html.rl-mobile .b-compose .b-header{overflow:scroll}.b-compose .b-header .e-identity{color:#333;text-decoration:none;font-weight:700}.b-compose .b-header .e-identity:hover{color:#333;text-decoration:none}.b-compose .b-header .e-identity.multiply{cursor:pointer;border-bottom:1px dashed #555}.b-compose .b-header .e-row{line-height:30px}.b-compose .b-header .e-label{text-align:right;width:1%;min-width:70px;padding:6px 10px}html.rl-mobile .b-compose .b-header .e-label{min-width:50px;padding:6px 10px 6px 0}.b-compose .b-header .e-value{padding:2px 0}.b-compose .b-header .e-value input[type=text],.b-compose .b-header .e-value textarea{width:98%}.b-compose .b-header .e-value textarea{height:40px}.b-compose .b-header .error-desc{color:red}.b-compose .b-header .error-to{color:red;font-weight:700}.b-compose .b-header .b-appachments .b-attacment{line-height:20px;padding-bottom:10px}.b-compose .b-header .b-appachments .b-attacment-in-process{line-height:20px;padding-bottom:10px}.b-compose .b-header .b-appachments .b-attacment-in-process .uploading{display:none;padding-right:5px}.b-compose .b-header .b-appachments .b-attacment-in-process.uploading .uploading{display:inline}.b-compose .b-header .b-appachments .b-attacment-in-process .upload-progress{font-weight:700}.b-compose .b-header .b-appachments .b-attacment-in-process.error .namedStr{color:#888}.b-compose .b-header .b-appachments .b-attacment-in-process .error{color:red}.b-compose .b-header .b-appachments .b-attacment-in-process .close,.b-compose .b-header .b-appachments .b-attacment-in-process .close-custom{float:left;padding-right:13px}.b-compose .cke_chrome{border-left-width:0!important;border-right-width:0!important;border-bottom-width:0!important}.b-compose .b-attachment-button{display:inline-block}.b-compose .b-attachment-place{position:absolute;left:5px;right:5px;top:5px;bottom:5px;border:2px #777 dashed;z-index:300;line-height:119px;text-align:center;background-color:#efefef;font-size:24px;border-radius:10px}.b-compose .b-attachment-place.dragAndDropOver{background-color:#fff}.b-admin-left .b-toolbar{position:absolute;top:0;right:0;left:0;height:34px;padding:8px 0 0 8px}.b-admin-left .b-content{position:absolute;top:68px;bottom:8px;left:0;right:0;overflow:hidden}.b-admin-left .b-content .content{-webkit-overflow-scrolling:touch}.b-admin-menu .e-item{overflow:hidden;text-decoration:none;outline:0}.b-admin-menu .e-link{position:relative;display:block;height:30px;line-height:29px;cursor:pointer;font-size:18px;z-index:1;cursor:default;background-color:transparent;color:#888;padding:4px 10px;outline:0;text-decoration:none}.b-admin-menu .e-item.selectable .e-link{cursor:pointer}.b-admin-menu .e-item.selectable.selected .e-link,.b-admin-menu .e-item.selectable:hover .e-link{background-color:#555;color:#fff}.b-admin-right .b-toolbar{position:absolute;top:0;right:0;left:0;height:34px;padding:8px 8px;color:#fff;text-shadow:0 1px 1px #000}.b-admin-right .b-content{position:absolute;top:58px;bottom:8px;left:0;right:8px;overflow-y:auto;z-index:2;background-color:#fff;border:1px solid #aaa;-webkit-box-shadow:0 2px 8px rgba(0,0,0,.2);box-shadow:0 2px 8px rgba(0,0,0,.2);border-radius:5px}.b-admin-right .b-content .content{-webkit-overflow-scrolling:touch}.b-admin-right .b-settings-content{padding:20px;padding-left:30px}.b-admin-right .b-settings-content .legend{width:670px}.b-admin-right .b-settings-content .nav-tabs{width:670px}html.rl-mobile .b-settings-content .legend{width:auto}.b-admin-general .flag-selector{padding-top:5px}.b-admin-general .flag-name{border-bottom:1px dashed #555;cursor:pointer;padding:2px 0}.b-admin-general .flag-name:focus{outline:1px;outline-style:dotted}.b-admin-branding .disabled-form{opacity:.8}.b-admin-branding .custom-css-wrapper textarea{font-family:Monaco,Menlo,Consolas,'Courier New',monospace}.b-admin-domains .process-place{width:600px;padding:14px 0;text-align:center;visibility:hidden}.b-admin-domains-list-table{width:600px}.b-admin-domains-list-table .e-item .e-action{cursor:pointer}.b-admin-domains-list-table .e-item .domain-name{display:inline-block;word-break:break-all;-webkit-box-sizing:border-box;box-sizing:border-box}.b-admin-domains-list-table .e-item .domain-alias{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;color:#bbb;padding-left:5px}.b-admin-domains-list-table .e-item.disabled .domain-alias,.b-admin-domains-list-table .e-item.disabled .domain-name{color:#bbb}.b-admin-domains-list-table .e-item .button-delete{margin-right:15px;visibility:hidden;opacity:0}.b-admin-domains-list-table .e-item .delete-access.button-delete{visibility:visible;margin-right:0;opacity:1}.b-admin-domains-list-table .e-item .delete-domain,.b-admin-domains-list-table .e-item .disabled-domain{cursor:pointer;opacity:.5}.b-admin-domains-list-table .e-item.disabled .disabled-domain{opacity:.5}.b-admin-domains-list-table .e-item .delete-domain:hover,.b-admin-domains-list-table .e-item .disabled-domain:hover{opacity:1}.b-domain-alias-content.modal{width:330px}.b-domain-alias-content .modal-header{background-color:#fff}.b-domain-alias-content .error-desc{color:red}.b-domain-content.modal{width:810px}.b-domain-content .modal-header{background-color:#fff}.b-domain-content .modal-body{position:relative;overflow:hidden;width:1600px;height:400px;left:0}.b-domain-content.domain-edit .modal-body{height:340px}.b-domain-content.domain-second-page .modal-body{left:-800px}.b-domain-content .domain-desc{color:#666;line-height:20px;background-color:#f9f9f9;padding:8px;border:1px solid #eee;border-radius:3px;margin:-5px 0}.b-domain-content .domain-desc i{font-style:normal;color:red}.b-domain-content .error-desc{color:red}.b-domain-content .testing-done.imap-header,.b-domain-content .testing-done.sieve-header,.b-domain-content .testing-done.smtp-header{color:green;font-weight:700}.b-domain-content .testing-error.imap-header,.b-domain-content .testing-error.sieve-header,.b-domain-content .testing-error.smtp-header{color:red}.b-admin-packages .alert{width:650px}.b-admin-packages .process-place{visibility:hidden}.b-admin-packages-list-table{width:700px}.b-admin-packages-list-table .e-item .package-img{font-size:12px;margin-right:2px}.b-admin-packages-list-table .e-item .package-name.core{font-weight:700}.b-admin-packages-list-table .e-item .package-desc{color:#999;font-size:12px}.b-admin-packages-list-table .e-item .e-action{cursor:pointer}.b-admin-packages-list-table .e-item .package-actions-parent,.b-admin-packages-list-table .e-item .package-release-parent{text-align:center}.b-admin-packages-list-table .e-item .package-actions-parent{vertical-align:middle}.b-admin-plugins .process-place{visibility:hidden}.b-admin-plugins-list-table.disabled{opacity:.5;background-color:#eee}.b-admin-plugins-list-table .e-item .e-action{cursor:pointer}.b-admin-plugins-list-table .e-item .plugin-img{font-size:12px;margin-right:2px}.b-admin-plugins-list-table .e-item.disabled .plugin-img,.b-admin-plugins-list-table .e-item.disabled .plugin-name{color:#bbb}.b-admin-plugins-list-table .e-item.disabled .disabled-plugin{opacity:.5}.b-admin-plugin-property .help-block{margin-bottom:5px}.b-plugin-content.modal{width:660px}.b-plugin-content.modal .modal-body{overflow:auto}.b-plugin-content .modal-header{background-color:#fff}.b-plugin-content .information{display:inline-block;background-color:#ddd;border-radius:10px;cursor:pointer;height:25px;width:30px;text-align:center;padding-top:5px}.b-plugin-content textarea{width:400px;height:70px}.b-admin-about .rl-logo{display:inline-block;width:250px;height:250px;margin-top:-10px;margin-bottom:-10px;background-image:url(images/rainloop-logo.png)}.b-admin-about .rl-desc{margin-top:20px;margin-left:-20px}.popups .b-activate-content{width:700px}.popups .b-activate-content .modal-header{background-color:#fff}.popups .b-activate-content .help-inline{padding-left:0}.b-settins-left .b-toolbar{position:absolute;top:0;right:0;left:0;height:34px;padding:8px 0 0 8px}.b-settins-left .b-footer{position:absolute;bottom:20px;right:0;left:0;height:20px;padding:0 10px 0 5px;z-index:101}.b-settins-left .b-content{position:absolute;top:68px;bottom:8px;left:0;right:0;overflow:hidden}.b-settins-left .b-content .content{-webkit-overflow-scrolling:touch}.b-settings-menu .e-item{overflow:hidden;text-decoration:none;outline:0}.b-settings-menu .e-link{position:relative;display:block;height:30px;line-height:29px;font-size:18px;z-index:1;cursor:default;background-color:transparent;color:#888;padding:4px 10px;outline:0;text-decoration:none}.b-settings-menu .e-item.selectable .e-link{cursor:pointer}.b-settings-menu .e-item.selectable.selected .e-link,.b-settings-menu .e-item.selectable:hover .e-link{background-color:#555;color:#fff}.b-settins-right .b-toolbar{position:absolute;top:0;right:0;left:0;height:34px;padding:8px 5px;color:#fff}.b-settins-right .b-content{position:absolute;top:50px;bottom:8px;left:0;right:8px;overflow-y:auto;z-index:2;background-color:#fff;border:1px solid #aaa;-webkit-box-shadow:0 2px 8px rgba(0,0,0,.2);box-shadow:0 2px 8px rgba(0,0,0,.2);border-radius:5px}.b-settins-right .b-content .content{-webkit-overflow-scrolling:touch}.b-settins-right .b-settings-content{padding:20px;padding-left:30px}.b-settins-right .b-settings-content .legend{width:600px}html.rl-mobile .b-settings-content .legend{width:auto}html.rl-mobile .b-settings-general{margin-right:15px}.b-settings-general .notification-desc-denied{color:#999;display:none}.b-settings-general .denied-by-browser .notification-desc-denied{display:inline}.b-settings-general .denied-by-browser .notification-desc{color:#999}.b-settings-general .flag-selector{padding-top:5px}.b-settings-general .flag-name{border-bottom:1px dashed #555;cursor:pointer;padding:2px 0}.b-settings-general .flag-name:focus{outline:1px;outline-style:dotted}html.rl-mobile .b-settings-accounts{margin-right:15px}.b-settings-accounts .process-place{text-align:center;width:600px;padding:14px 0}.b-settings-accounts .list-table{width:600px}.b-settings-accounts .list-table td{padding:4px 8px;line-height:30px}.b-settings-accounts .list-table .drag-handle{color:#eee}.b-settings-accounts .list-table tr:hover .drag-handle{color:#aaa}.b-settings-accounts .list-table .account-img,.b-settings-accounts .list-table .identity-img{font-size:12px;margin-right:5px}.b-settings-accounts .list-table .account-name{display:inline-block;word-break:break-all;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:22px}.b-settings-accounts .list-table .identity-default{cursor:pointer;color:#ccc}.b-settings-accounts .list-table .identity-name{display:inline-block;word-break:break-all;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:22px;cursor:pointer}.b-settings-accounts .accounts-list-top-padding,.b-settings-accounts .identities-list-top-padding{display:inline-block;height:5px;width:5px}.b-settings-accounts .account-item{white-space:nowrap}.b-settings-accounts .account-item .e-action{cursor:pointer}.b-settings-accounts .account-item .drag-handle{cursor:pointer;cursor:all-scroll}.b-settings-accounts .account-item .button-delete{margin-right:15px;margin-top:5px;visibility:hidden;opacity:0}.b-settings-accounts .account-item .delete-access.button-delete{visibility:visible;margin-right:0;opacity:1}.b-settings-accounts .account-item .delete-account{cursor:pointer;opacity:.5}.b-settings-accounts .account-item.ui-sortable-helper{background:#f5f5f5;border:1px solid #ddd}.b-settings-accounts .account-item.ui-sortable-helper .button-delete,.b-settings-accounts .account-item.ui-sortable-helper .delete-account{display:none}.b-settings-accounts .account-item.ui-sortable-helper td{border-width:0}.b-settings-accounts .identity-item{white-space:nowrap}.b-settings-accounts .identity-item .e-action{cursor:pointer}.b-settings-accounts .identity-item .button-delete{margin-right:15px;margin-top:5px;visibility:hidden;opacity:0}.b-settings-accounts .identity-item .delete-access.button-delete{visibility:visible;margin-right:0;opacity:1}.b-settings-accounts .identity-item .delete-identity{cursor:pointer;opacity:.5}.b-settings-accounts .identity-item.ui-sortable-helper{background:#f5f5f5;border:1px solid #ddd}.b-settings-accounts .identity-item.ui-sortable-helper .button-delete,.b-settings-accounts .identity-item.ui-sortable-helper .delete-identity{display:none}.b-settings-accounts .identity-item.ui-sortable-helper td{border-width:0}html.rl-mobile .b-settings-templates{margin-right:15px}.b-settings-templates .process-place{text-align:center;width:600px;padding:14px 0}.b-settings-templates .list-table{width:600px}.b-settings-templates .list-table td{padding:4px 8px;line-height:30px}.b-settings-templates .list-table .drag-handle{color:#eee}.b-settings-templates .list-table tr:hover .drag-handle{color:#aaa}.b-settings-templates .list-table .template-img{font-size:12px;margin-right:5px}.b-settings-templates .list-table .template-name{display:inline-block;word-break:break-all;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:22px}.b-settings-templates .templates-list-top-padding{display:inline-block;height:5px;width:5px}.b-settings-templates .template-item .e-action{cursor:pointer}.b-settings-templates .template-item .drag-handle{cursor:pointer;cursor:all-scroll}.b-settings-templates .template-item .button-delete{margin-right:15px;margin-top:5px;visibility:hidden;opacity:0}.b-settings-templates .template-item .delete-access.button-delete{visibility:visible;margin-right:0;opacity:1}.b-settings-templates .template-item .delete-template{cursor:pointer;opacity:.5}.b-settings-templates .template-item.ui-sortable-helper{background:#f5f5f5;border:1px solid #ddd}.b-settings-templates .template-item.ui-sortable-helper .button-delete,.b-settings-templates .template-item.ui-sortable-helper .delete-template{display:none}.b-settings-templates .template-item.ui-sortable-helper td{border-width:0}html.rl-mobile .b-settings-open-pgp{margin-right:15px}.b-settings-open-pgp .process-place{text-align:center;width:600px;padding:14px 0}.b-settings-open-pgp .list-table{width:750px}.b-settings-open-pgp .list-table td{padding:4px 8px;line-height:30px}.b-settings-open-pgp .list-table .open-pgp-key-img{margin-right:10px;vertical-align:top}.b-settings-open-pgp .list-table .open-pgp-key-img .svg-icon{width:12px;height:12px}.b-settings-open-pgp .list-table .open-pgp-key-id,.b-settings-open-pgp .list-table .open-pgp-key-user{display:inline-block;word-break:break-all;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:22px;cursor:default}.b-settings-open-pgp .list-table .open-pgp-key-user-address:first-child{line-height:30px;margin-bottom:-4px}.b-settings-open-pgp .open-pgp-key-item .button-delete{margin-right:15px;margin-top:5px;visibility:hidden;opacity:0}.b-settings-open-pgp .open-pgp-key-item .delete-access.button-delete{visibility:visible;margin-right:0;opacity:1}.b-settings-open-pgp .open-pgp-key-item .delete-open-pgp-key,.b-settings-open-pgp .open-pgp-key-item .view-open-pgp-key{cursor:pointer;opacity:.7}.b-settings-open-pgp .open-pgp-key-item .delete-open-pgp-key:hover,.b-settings-open-pgp .open-pgp-key-item .view-open-pgp-key:hover{opacity:.9}html.rl-mobile .b-settings-folders{margin-right:35px}.b-settings-folders.ignore-folder-subscribe .subscribe-folder,.b-settings-folders.ignore-folder-subscribe .unsubscribe-folder{display:none}.b-settings-folders .process-place{text-align:center;width:600px;padding:14px 0}.b-settings-folders .folders-list-error{width:550px;margin:10px 0}.b-settings-folders .list-table{width:600px}.b-settings-folders .list-table .e-action{cursor:pointer}.b-settings-folders .list-table td{padding:4px 8px;line-height:30px}.b-settings-folders .list-table .folder-padding{display:inline-block;width:0}.b-settings-folders .list-table .folder-name{display:inline-block;word-break:break-all;white-space:pre-wrap;-webkit-box-sizing:border-box;box-sizing:border-box;margin-left:7px;line-height:22px;cursor:default}.b-settings-folders .list-table .folder-system-name{display:inline-block;line-height:22px;color:#999;cursor:default}.b-settings-folders .list-table .folder-name.can-be-edited:hover{border-bottom:1px dashed #333;cursor:pointer}.b-settings-folders .list-table .folder-name-input{border-width:1px;margin-bottom:0;margin-left:-4px}.b-settings-folders .folder-item.system .folder-name{font-weight:700}.b-settings-folders .folder-item .button-delete{margin-right:15px;margin-top:5px;visibility:hidden;opacity:0}.b-settings-folders .folder-item .delete-access.button-delete{visibility:visible;margin-right:0;opacity:1}.b-settings-folders .folder-item .check-folder,.b-settings-folders .folder-item .delete-folder,.b-settings-folders .folder-item .subscribe-folder,.b-settings-folders .folder-item .uncheck-folder,.b-settings-folders .folder-item .unsubscribe-folder{cursor:pointer;opacity:.6}.b-settings-folders .folder-item .unsubscribe-folder{opacity:.2}.b-settings-folders .folder-item .uncheck-folder{opacity:.2}.b-settings-folders .folder-padding.deep-1{width:25px}.b-settings-folders .folder-padding.deep-2{width:40px}.b-settings-folders .folder-padding.deep-3{width:55px}.b-settings-folders .folder-padding.deep-4{width:70px}.b-settings-folders .folder-padding.deep-5{width:85px}.b-settings-content .b-settings-themes .legend{width:100%}html.rl-mobile .b-settings-content .b-settings-theme .legend{width:auto}html.rl-mobile .b-themes-list{margin-right:15px}.b-themes-list .e-item{display:inline-block;border:2px solid transparent;cursor:pointer;color:#000;background-color:#fff;padding:16px;margin:5px}.b-themes-list .e-item:hover{border:2px solid grey}.b-themes-list .e-item.selected{background-color:#eee;border:2px solid #000}.b-themes-list .e-item .e-image{width:100px;height:100px;border:1px solid #ddd}html.rl-mobile .b-settings-filters{margin-right:15px}.b-settings-filters .process-place{text-align:center;width:600px;padding:14px 0}.b-settings-filters .list-table{width:600px}.b-settings-filters .list-table td{padding:4px 8px;line-height:30px}.b-settings-filters .list-table td.drag-wrapper{padding:4px 0}.b-settings-filters .list-table .drag-handle{color:#eee}.b-settings-filters .list-table tr:hover .drag-handle{color:#aaa}.b-settings-filters .list-table .filter-img{font-size:12px;margin-right:5px}.b-settings-filters .list-table .filter-name,.b-settings-filters .list-table .filter-sub-name{display:inline-block;word-break:break-all;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:22px;cursor:pointer}.b-settings-filters .list-table .filter-sub-name{color:#aaa}.b-settings-filters .filters-list-top-padding{display:inline-block;height:5px;width:5px}.b-settings-filters .filter-item{white-space:nowrap}.b-settings-filters .filter-item .e-action{cursor:pointer}.b-settings-filters .filter-item .drag-handle{cursor:pointer;cursor:all-scroll}.b-settings-filters .filter-item .button-delete{margin-right:15px;margin-top:5px;visibility:hidden;opacity:0}.b-settings-filters .filter-item .delete-access.button-delete{visibility:visible;margin-right:0;opacity:1}.b-settings-filters .filter-item .delete-filter{cursor:pointer;opacity:.5}.b-settings-filters .filter-item.ui-sortable-helper{background:#f5f5f5;border:1px solid #ddd}.b-settings-filters .filter-item.ui-sortable-helper .button-delete,.b-settings-filters .filter-item.ui-sortable-helper .delete-filter{display:none}.b-settings-filters .filter-item.ui-sortable-helper td{border-width:0}.rl-cmd{position:absolute;bottom:0;left:0;right:0;top:auto;height:0;z-index:10000;background:rgba(0,0,0,.85);border-top:1px solid #000;overflow:hidden;font-family:monospace;-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;transition:height .1s ease-out}.rl-cmd.opened{height:250px}.rl-cmd .rl-cmd-clr-error{color:#cd3131}.rl-cmd .rl-cmd-clr-info{color:#bfbf00}.rl-cmd .rl-cmd-clr-success{color:#31ff40}.rl-cmd .rl-cmd-wrp{position:relative;height:100%}.rl-cmd .rl-cmd-input-helper{color:#666}.rl-cmd .rl-cmd-input-prefix{color:#31ff40;display:inline-block}.rl-cmd .rl-cmd-input-wrp{position:absolute;bottom:0;left:10px;right:10px}.rl-cmd .rl-cmd-input{background:0 0;border:none;color:#fff;display:inline-block;width:calc(100% - 30px);font-family:monospace}.rl-cmd .rl-cmd-input:focus{background:0 0;border:none}.rl-cmd .rl-cmd-history{color:#fff;font-family:monospace;position:absolute;top:10px;bottom:60px;left:10px;right:-30px;overflow:hidden;overflow-x:hidden;overflow-y:auto}@-webkit-keyframes highlight-folder-row{0%{-webkit-transform:scale(1);transform:scale(1)}50%{-webkit-transform:scale(1.1);transform:scale(1.1)}100%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes highlight-folder-row{0%{-webkit-transform:scale(1);transform:scale(1)}50%{-webkit-transform:scale(1.1);transform:scale(1.1)}100%{-webkit-transform:scale(1);transform:scale(1)}}@-webkit-keyframes bounce-me{0%{-webkit-transform:scale(1);transform:scale(1)}50%{-webkit-transform:scale(1.2);transform:scale(1.2)}100%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes bounce-me{0%{-webkit-transform:scale(1);transform:scale(1)}50%{-webkit-transform:scale(1.2);transform:scale(1.2)}100%{-webkit-transform:scale(1);transform:scale(1)}}@-webkit-keyframes textLoadingAnimationKeyFrame{0%{opacity:1}33%{opacity:0}100%{opacity:1}}@keyframes textLoadingAnimationKeyFrame{0%{opacity:1}33%{opacity:0}100%{opacity:1}}@-webkit-keyframes animate-stripes{0%{background-position:0 0}100%{background-position:60px 0}}@keyframes animate-stripes{0%{background-position:0 0}100%{background-position:60px 0}}@-webkit-keyframes login-form-shake{0%{-webkit-transform:translateX(0);transform:translateX(0)}12.5%{-webkit-transform:translateX(-6px) rotateY(-5deg);transform:translateX(-6px) rotateY(-5deg)}37.5%{-webkit-transform:translateX(5px) rotateY(4deg);transform:translateX(5px) rotateY(4deg)}62.5%{-webkit-transform:translateX(-3px) rotateY(-2deg);transform:translateX(-3px) rotateY(-2deg)}87.5%{-webkit-transform:translateX(2px) rotateY(1deg);transform:translateX(2px) rotateY(1deg)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes login-form-shake{0%{-webkit-transform:translateX(0);transform:translateX(0)}12.5%{-webkit-transform:translateX(-6px) rotateY(-5deg);transform:translateX(-6px) rotateY(-5deg)}37.5%{-webkit-transform:translateX(5px) rotateY(4deg);transform:translateX(5px) rotateY(4deg)}62.5%{-webkit-transform:translateX(-3px) rotateY(-2deg);transform:translateX(-3px) rotateY(-2deg)}87.5%{-webkit-transform:translateX(2px) rotateY(1deg);transform:translateX(2px) rotateY(1deg)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}html.csstransitions.rl-started-trigger.no-mobile .b-login-content .loginFormWrapper{-webkit-transform:translateY(-20px);-ms-transform:translateY(-20px);transform:translateY(-20px);opacity:.5}#rl-loading{-webkit-transition:opacity .5s linear;-o-transition:opacity .5s linear;transition:opacity .5s linear}html.csstransitions.rl-started-delay #rl-left{-webkit-transition:width .3s ease-out;-o-transition:width .3s ease-out;transition:width .3s ease-out}html.csstransitions.rl-started-delay #rl-right{-webkit-transition:left .3s ease-out,right .3s ease-out;-o-transition:left .3s ease-out,right .3s ease-out;transition:left .3s ease-out,right .3s ease-out}html.csstransitions.rl-started-delay #rl-sub-left,html.csstransitions.rl-started-delay #rl-sub-left .messageList .inputSearch{-webkit-transition:width .3s ease-out;-o-transition:width .3s ease-out;transition:width .3s ease-out}html.csstransitions.rl-started-delay #rl-sub-right{-webkit-transition:left .3s ease-out;-o-transition:left .3s ease-out;transition:left .3s ease-out}html.rgba.cssanimations.backgroundsize .e-strip-animation{background-size:60px 60px;background-image:-o-linear-gradient(315deg,rgba(0,0,0,.1) 25%,transparent 25%,transparent 50%,rgba(0,0,0,.1) 50%,rgba(0,0,0,.1) 75%,transparent 75%,transparent);background-image:linear-gradient(135deg,rgba(0,0,0,.1) 25%,transparent 25%,transparent 50%,rgba(0,0,0,.1) 50%,rgba(0,0,0,.1) 75%,transparent 75%,transparent);-webkit-animation:animate-stripes 2s linear infinite;animation:animate-stripes 2s linear infinite}html.rl-anim .rl-animated-inited{opacity:1;-webkit-transition:opacity .5s linear;-o-transition:opacity .5s linear;transition:opacity .5s linear}html.rl-anim .rl-animated-inited.rl-animated-hidden{opacity:0}html.rl-anim.cssanimations.csstransitions.no-mobile .b-login-content .errorAnimated{-webkit-animation:login-form-shake .4s ease-in-out;animation:login-form-shake .4s ease-in-out}html.rl-anim.no-mobile .b-login-content .errorAnimated .buttonLogin{color:#b94a48;font-weight:700}html.rl-anim.cssanimations.csstransitions.no-mobile .b-login-content .afterLoginHide{opacity:0}html.rl-anim.csstransitions.no-mobile .btn-group.dropdown.colored-toggle.open .animate-this-icon-on-open{-webkit-animation:bounce-me .5s linear;animation:bounce-me .5s linear}html.rl-anim.csstransitions.no-mobile .b-login-content .loginFormWrapper{-webkit-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}html.rl-anim.csstransitions .button-delete-transitions{-webkit-transition:all .2s linear;-o-transition:all .2s linear;transition:all .2s linear}html.rl-anim.cssanimations .b-folders .e-item .anim-action-class{-webkit-animation:highlight-folder-row .5s linear;animation:highlight-folder-row .5s linear}html.rl-anim.csstransitions .b-folders .btn.buttonContacts{-webkit-transition:margin .3s linear;-o-transition:margin .3s linear;transition:margin .3s linear}html.rl-anim.csstransitions .b-folders .b-content.opacity-on-panel-disabled{-webkit-transition:opacity .3s linear;-o-transition:opacity .3s linear;transition:opacity .3s linear}html.rl-anim.csstransitions .messageList .messageListItem{-webkit-transition:max-height .4s ease;-o-transition:max-height .4s ease;transition:max-height .4s ease}html.rl-anim.csstransitions .messageList .listDragOver{-webkit-transition:all .4s ease;-o-transition:all .4s ease;transition:all .4s ease}html.rl-anim.csstransitions .b-list-content .e-contact-item{-webkit-transition:max-height .4s ease;-o-transition:max-height .4s ease;transition:max-height .4s ease}html.rl-anim.csstransitions .modal.b-domain-content .modal-body{-webkit-transition:left .5s ease;-o-transition:left .5s ease;transition:left .5s ease}html.rl-anim.csstransitions.rl-modal.rl-modal-animation .popups{overflow:hidden}html.rl-anim.csstransitions .modal.fade{-webkit-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out;-webkit-transform:translateY(-20px);-ms-transform:translateY(-20px);transform:translateY(-20px)}html.rl-anim.csstransitions .modal.fade.in{-webkit-transform:none;-ms-transform:none;transform:none}html.rl-anim.cssanimations .b-compose.loading .b-header-toolbar{background-size:60px 60px;background-image:-o-linear-gradient(315deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);background-image:linear-gradient(135deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);-webkit-animation:animate-stripes 2s linear infinite;animation:animate-stripes 2s linear infinite}.textLoadingAnimationD1,.textLoadingAnimationD2,.textLoadingAnimationD3{-webkit-animation:textLoadingAnimationKeyFrame 1s linear infinite 0s;animation:textLoadingAnimationKeyFrame 1s linear infinite 0s}.textLoadingAnimationD2{-webkit-animation-delay:.3s;animation-delay:.3s}.textLoadingAnimationD3{-webkit-animation-delay:.6s;animation-delay:.6s}.rl-view-model.RL-About,.rl-view-model.RL-AdminLogin,.rl-view-model.RL-Login,.rl-view-model.RL-LoginNew{position:relative;height:100%;z-index:5}.mfp-container .mfp-figure{min-height:300px;min-width:300px}.ui-resizable-e{right:-1px;width:5px}.pswp__error-msg{color:#ccc}.pswp__error-msg a,.pswp__error-msg a:hover{color:#fff}.pswp__img--placeholder{opacity:0}.opentip-container{z-index:2001!important}.opentip-container .ot-content{font-size:13px}.opentip-container.style-rainloopErrorTip .ot-content{color:red}.opentip-container.ot-hide-effect-none,.opentip-container.ot-show-effect-none{-webkit-transition:none!important;-o-transition:none!important;transition:none!important}.opentip-container.ot-show-effect-fade{-webkit-transition:none;-o-transition:none;transition:none}.opentip-container.ot-show-effect-fade.ot-hidden{opacity:0}.opentip-container.ot-show-effect-fade.ot-going-to-show{opacity:0;-webkit-transition:opacity .2s ease-in-out;-o-transition:opacity .2s ease-in-out;transition:opacity .2s ease-in-out}.opentip-container.ot-show-effect-fade.ot-showing{opacity:1;-webkit-transition:opacity .2s ease-in-out;-o-transition:opacity .2s ease-in-out;transition:opacity .2s ease-in-out}.opentip-container.ot-show-effect-fade.ot-visible{opacity:1;-webkit-transition:none;-o-transition:none;transition:none}svg-icon{display:none}.svg-icon{border:0;outline:0;height:16px;width:16px;display:inline-block;fill:#333}.svg-icon.svg-icon-archive{height:14px;width:14px}.lg-backdrop.in{opacity:.8}.btn .btn-text{padding-left:8px}.active-scale-transition{-webkit-transition:-webkit-transform .2s;transition:-webkit-transform .2s;-o-transition:transform .2s;transition:transform .2s;transition:transform .2s,-webkit-transform .2s}.active-scale-transition:active{-webkit-transform:scale(.95);-ms-transform:scale(.95);transform:scale(.95)}html.glass input:-webkit-autofill,html.glass input:-webkit-autofill:active,html.glass input:-webkit-autofill:focus,html.glass input:-webkit-autofill:hover{-webkit-transition-delay:9999s;-webkit-transition:color 9999s ease-out,background-color 9999s ease-out} diff --git a/rainloop/app/rainloop/v/1.12.1/static/js/admin.js b/rainloop/app/rainloop/v/1.12.1/static/js/admin.js deleted file mode 100644 index caf6fe63..00000000 --- a/rainloop/app/rainloop/v/1.12.1/static/js/admin.js +++ /dev/null @@ -1,1103 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under AGPL v3 */ -!function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="rainloop/v/0.0.0/static/js/",n(n.s=215)}([ -/*!*****************************!*\ - !*** ./dev/Common/Enums.js ***! - \*****************************/ -/*! exports provided: FileType, StorageResultType, Focused, State, StateType, Capa, KeyState, FolderType, ServerFolderType, LoginSignMeTypeAsString, LoginSignMeType, ComposeType, UploadErrorCode, SetSystemFoldersNotification, ClientSideKeyName, EventKeyCode, MessageSetAction, MessageSelectAction, DesktopNotification, MessagePriority, EditorDefaultType, ServerSecure, SearchDateType, SaveSettingsStep, Layout, FilterConditionField, FilterConditionType, FiltersAction, FilterRulesType, SignedVerifyStatus, ContactPropertyType, Magics, Ports, Notification */ -/*! all exports used */function(e,t,n){"use strict";n.r(t),n.d(t,"FileType",function(){return i}),n.d(t,"StorageResultType",function(){return o}),n.d(t,"Focused",function(){return a}),n.d(t,"State",function(){return r}),n.d(t,"StateType",function(){return s}),n.d(t,"Capa",function(){return c}),n.d(t,"KeyState",function(){return u}),n.d(t,"FolderType",function(){return l}),n.d(t,"ServerFolderType",function(){return d}),n.d(t,"LoginSignMeTypeAsString",function(){return p}),n.d(t,"LoginSignMeType",function(){return f}),n.d(t,"ComposeType",function(){return m}),n.d(t,"UploadErrorCode",function(){return h}),n.d(t,"SetSystemFoldersNotification",function(){return g}),n.d(t,"ClientSideKeyName",function(){return b}),n.d(t,"EventKeyCode",function(){return v}),n.d(t,"MessageSetAction",function(){return S}),n.d(t,"MessageSelectAction",function(){return y}),n.d(t,"DesktopNotification",function(){return w}),n.d(t,"MessagePriority",function(){return O}),n.d(t,"EditorDefaultType",function(){return A}),n.d(t,"ServerSecure",function(){return T}),n.d(t,"SearchDateType",function(){return C}),n.d(t,"SaveSettingsStep",function(){return _}),n.d(t,"Layout",function(){return E}),n.d(t,"FilterConditionField",function(){return D}),n.d(t,"FilterConditionType",function(){return N}),n.d(t,"FiltersAction",function(){return j}),n.d(t,"FilterRulesType",function(){return R}),n.d(t,"SignedVerifyStatus",function(){return I}),n.d(t,"ContactPropertyType",function(){return x}),n.d(t,"Magics",function(){return P}),n.d(t,"Ports",function(){return k}),n.d(t,"Notification",function(){return L});var i={Unknown:"unknown",Text:"text",Html:"html",Code:"code",Eml:"eml",WordText:"word-text",Pdf:"pdf",Image:"image",Audio:"audio",Video:"video",Sheet:"sheet",Presentation:"presentation",Certificate:"certificate",CertificateBin:"certificate-bin",Archive:"archive"},o={Success:"success",Abort:"abort",Error:"error",Unload:"unload"},a={None:"none",MessageList:"message-list",MessageView:"message-view",FolderList:"folder-list"},r={Empty:10,Login:20,Auth:30},s={Webmail:0,Admin:1},c={TwoFactor:"TWO_FACTOR",TwoFactorForce:"TWO_FACTOR_FORCE",OpenPGP:"OPEN_PGP",Prefetch:"PREFETCH",Gravatar:"GRAVATAR",Folders:"FOLDERS",Composer:"COMPOSER",Contacts:"CONTACTS",Reload:"RELOAD",Search:"SEARCH",SearchAdv:"SEARCH_ADV",MessageActions:"MESSAGE_ACTIONS",MessageListActions:"MESSAGELIST_ACTIONS",AttachmentsActions:"ATTACHMENTS_ACTIONS",DangerousActions:"DANGEROUS_ACTIONS",Settings:"SETTINGS",Help:"HELP",Themes:"THEMES",UserBackground:"USER_BACKGROUND",Sieve:"SIEVE",Filters:"FILTERS",AttachmentThumbnails:"ATTACHMENT_THUMBNAILS",Templates:"TEMPLATES",AutoLogout:"AUTOLOGOUT",AdditionalAccounts:"ADDITIONAL_ACCOUNTS",Identities:"IDENTITIES"},u={All:"all",None:"none",ContactList:"contact-list",MessageList:"message-list",FolderList:"folder-list",MessageView:"message-view",Compose:"compose",Settings:"settings",Menu:"menu",PopupComposeOpenPGP:"compose-open-pgp",PopupMessageOpenPGP:"message-open-pgp",PopupViewOpenPGP:"view-open-pgp",PopupKeyboardShortcutsHelp:"popup-keyboard-shortcuts-help",PopupAsk:"popup-ask"},l={Inbox:10,SentItems:11,Draft:12,Trash:13,Spam:14,Archive:15,NotSpam:80,User:99},d={USER:0,INBOX:1,SENT:2,DRAFTS:3,JUNK:4,TRASH:5,IMPORTANT:10,FLAGGED:11,ALL:12},p={DefaultOff:"defaultoff",DefaultOn:"defaulton",Unused:"unused"},f={DefaultOff:0,DefaultOn:1,Unused:2},m={Empty:"empty",Reply:"reply",ReplyAll:"replyall",Forward:"forward",ForwardAsAttachment:"forward-as-attachment",Draft:"draft",EditAsNew:"editasnew"},h={Normal:0,FileIsTooBig:1,FilePartiallyUploaded:2,FileNoUploaded:3,MissingTempFolder:4,FileOnSaveingError:5,FileType:98,Unknown:99},g={None:0,Sent:1,Draft:2,Spam:3,Trash:4,Archive:5},b={FoldersLashHash:0,MessagesInboxLastHash:1,MailBoxListSize:2,ExpandedFolders:3,FolderListSize:4,MessageListSize:5,LastReplyAction:6,LastSignMe:7,ComposeLastIdentityID:8,MessageHeaderFullInfo:9,MessageAttachmnetControls:10},v={Backspace:8,Tab:9,Enter:13,Esc:27,PageUp:33,PageDown:34,Left:37,Right:39,Up:38,Down:40,End:35,Home:36,Space:32,Insert:45,Delete:46,A:65,S:83},S={SetSeen:0,UnsetSeen:1,SetFlag:2,UnsetFlag:3},y={All:0,None:1,Invert:2,Unseen:3,Seen:4,Flagged:5,Unflagged:6},w={Allowed:0,NotAllowed:1,Denied:2,NotSupported:9},O={Low:5,Normal:3,High:1},A={Html:"Html",Plain:"Plain",HtmlForced:"HtmlForced",PlainForced:"PlainForced"},T={None:0,SSL:1,TLS:2},C={All:-1,Days3:3,Days7:7,Month:30},_={Animate:-2,Idle:-1,TrueResult:1,FalseResult:0},E={NoPreview:0,SidePreview:1,BottomPreview:2},D={From:"From",Recipient:"Recipient",Subject:"Subject",Header:"Header",Size:"Size"},N={Contains:"Contains",NotContains:"NotContains",EqualTo:"EqualTo",NotEqualTo:"NotEqualTo",Regex:"Regex",Over:"Over",Under:"Under"},j={None:"None",MoveTo:"MoveTo",Discard:"Discard",Vacation:"Vacation",Reject:"Reject",Forward:"Forward"},R={All:"All",Any:"Any"},I={UnknownPublicKeys:-4,UnknownPrivateKey:-3,Unverified:-2,Error:-1,None:0,Success:1},x={Unknown:0,FullName:10,FirstName:15,LastName:16,MiddleName:16,Nick:18,NamePrefix:20,NameSuffix:21,Email:30,Phone:31,Web:32,Birthday:40,Facebook:90,Skype:91,GitHub:92,Note:110,Custom:250},P={EventWhichMouseMiddle:3,ifvisibleIdle10s:10,BitLength2048:2048,BitLength1024:1024,Size350px:350,Size50px:50,Size20px:20,Size1px:1,Time30mInMin:30,Time60m:36e5,Time30m:18e5,Time20m:12e5,Time15m:9e5,Time10m:6e5,Time5m:3e5,Time3m:18e4,Time2m:12e4,Time1m:6e4,Time30s:3e4,Time10s:1e4,Time7s:7e3,Time5s:5e3,Time3s:3e3,Time1s:1e3,Time500ms:500,Time350ms:350,Time250ms:250,Time200ms:200,Time100ms:100,Time50ms:50,Time20ms:20,Time10ms:10,Time1ms:1},k={Imap:143,ImapSsl:993,Smtp:25,SmtpSsl:465,SmtpStartTls:587},L={InvalidToken:101,AuthError:102,AccessError:103,ConnectionError:104,CaptchaError:105,SocialFacebookLoginAccessDisable:106,SocialTwitterLoginAccessDisable:107,SocialGoogleLoginAccessDisable:108,DomainNotAllowed:109,AccountNotAllowed:110,AccountTwoFactorAuthRequired:120,AccountTwoFactorAuthError:121,CouldNotSaveNewPassword:130,CurrentPasswordIncorrect:131,NewPasswordShort:132,NewPasswordWeak:133,NewPasswordForbidden:134,ContactsSyncError:140,CantGetMessageList:201,CantGetMessage:202,CantDeleteMessage:203,CantMoveMessage:204,CantCopyMessage:205,CantSaveMessage:301,CantSendMessage:302,InvalidRecipients:303,CantSaveFilters:351,CantGetFilters:352,FiltersAreNotCorrect:355,CantCreateFolder:400,CantRenameFolder:401,CantDeleteFolder:402,CantSubscribeFolder:403,CantUnsubscribeFolder:404,CantDeleteNonEmptyFolder:405,CantSaveSettings:501,CantSavePluginSettings:502,DomainAlreadyExists:601,CantInstallPackage:701,CantDeletePackage:702,InvalidPluginPackage:703,UnsupportedPluginPackage:704,LicensingServerIsUnavailable:710,LicensingExpired:711,LicensingBanned:712,DemoSendMessageError:750,DemoAccountError:751,AccountAlreadyExists:801,AccountDoesNotExist:802,MailServerError:901,ClientViewError:902,InvalidInputArgument:903,AjaxFalse:950,AjaxAbort:951,AjaxParse:952,AjaxTimeout:953,UnknownNotification:999,UnknownError:999}}, -/*!****************************************!*\ - !*** ./dev/External/ko.js + 1 modules ***! - \****************************************/ -/*! exports provided: default */ -/*! exports used: default */ -/*! ModuleConcatenation bailout: Cannot concat with ./dev/Common/Enums.js because of ./dev/app.js */ -/*! ModuleConcatenation bailout: Cannot concat with ./node_modules/pikaday/pikaday.js (<- Module is not an ECMAScript module) */ -/*! ModuleConcatenation bailout: Cannot concat with external "window" (<- Module is not an ECMAScript module) */ -/*! ModuleConcatenation bailout: Cannot concat with external "window._" (<- Module is not an ECMAScript module) */ -/*! ModuleConcatenation bailout: Cannot concat with external "window.jQuery" (<- Module is not an ECMAScript module) */function(e,t,n){"use strict";var i=n(3),o=n.n(i),a=n(4),r=n.n(a),s=n(7),c=n.n(s),u=o.a.Opentip||{};u.styles=u.styles||{},u.styles.rainloop={extends:"standard",fixed:!0,target:!0,delay:.2,hideDelay:0,hideEffect:"fade",hideEffectDuration:.2,showEffect:"fade",showEffectDuration:.2,showOn:"mouseover click",removeElementsOnHide:!0,background:"#fff",shadow:!1,borderColor:"#999",borderRadius:2,borderWidth:1},u.styles.rainloopTip={extends:"rainloop",delay:.4,group:"rainloopTips"},u.styles.rainloopErrorTip={extends:"rainloop",className:"rainloopErrorTip"};var l=n(96),d=n.n(l),p=n(0),f=o.a.ko,m=c()(o.a);f.bindingHandlers.updateWidth={init:function(e,t){var n=c()(e),i=t(),a=function(){i(n.width()),o.a.setTimeout(function(){i(n.width())},p.Magics.Time500ms)};m.on("resize",a),a(),f.utils.domNodeDisposal.addDisposeCallback(e,function(){m.off("resize",a)})}},f.bindingHandlers.editor={init:function(e,t){var i=null,o=t(),a=n(/*! Common/HtmlEditor */95).default,r=function(){o&&o.__editor&&o.__editor.setHtmlOrPlain(o())},s=function(){o&&o.__editor&&o(o.__editor.getDataWithHtmlMark())};f.isObservable(o)&&a&&(i=new a(e,s,function(){o.__editor=i,r()},s),o.__fetchEditorValue=s,o.subscribe(r))}},f.bindingHandlers.json={init:function(e,t){c()(e).text(o.a.JSON.stringify(f.unwrap(t())))},update:function(e,t){c()(e).text(o.a.JSON.stringify(f.unwrap(t())))}},f.bindingHandlers.scrollerShadows={init:function(e){var t=c()(e),n=t.find("[data-scroller-shadows-content]")[0]||null,i=r.a.throttle(function(){t.toggleClass("scroller-shadow-top",8=n.left&&e.pageX<=n.left+t.width()){if(e.pageY>=i-100&&e.pageY<=i){var a=function(){t.scrollTop(t.scrollTop()+3),r.windowResize()};t.data("timerScroll",o.a.setInterval(a,10)),a()}if(e.pageY>=n.top&&e.pageY<=n.top+100){var s=function(){t.scrollTop(t.scrollTop()-3),r.windowResize()};t.data("timerScroll",o.a.setInterval(s,10)),s()}}})},l.stop=function(){c()(u).each(function(){var e=c()(this);o.a.clearInterval(e.data("timerScroll")),e.data("timerScroll",!1)})}),l.helper=function(e){return t()(e&&e.target?f.dataFor(e.target):null)},c()(e).draggable(l).on("mousedown.koDraggable",function(){r.removeInFocus()}),f.utils.domNodeDisposal.addDisposeCallback(e,function(){c()(e).off("mousedown.koDraggable").draggable("destroy")})}}},f.bindingHandlers.droppable={init:function(e,t,i){if(!n(/*! Common/Globals */6).bMobileDevice){var o=t(),a=i(),r=a&&a.droppableOver?a.droppableOver:null,s=a&&a.droppableOut?a.droppableOut:null,u={tolerance:"pointer",hoverClass:"droppableHover",drop:null,over:null,out:null};o&&(u.drop=function(e,t){o(e,t)},r&&(u.over=function(e,t){r(e,t)}),s&&(u.out=function(e,t){s(e,t)}),c()(e).droppable(u),f.utils.domNodeDisposal.addDisposeCallback(e,function(){c()(e).droppable("destroy")}))}}},f.bindingHandlers.nano={init:function(e){var t=n(/*! Common/Globals */6),i=n(/*! Storage/Settings */5);t.bDisableNanoScroll||i.appSettingsGet("useNativeScrollbars")||c()(e).addClass("nano").nanoScroller({iOSNativeScrolling:!1,preventPageScrolling:!0})}},f.bindingHandlers.saveTrigger={init:function(e){var t=c()(e);t.data("save-trigger-type",t.is("input[type=text],input[type=email],input[type=password],select,textarea")?"input":"custom"),"custom"===t.data("save-trigger-type")?t.append('  ').addClass("settings-saved-trigger"):t.addClass("settings-saved-trigger-input")},update:function(e,t){var n=f.unwrap(t()),i=c()(e);if("custom"===i.data("save-trigger-type"))switch(n.toString()){case"1":i.find(".animated,.error").hide().removeClass("visible").end().find(".success").show().addClass("visible");break;case"0":i.find(".animated,.success").hide().removeClass("visible").end().find(".error").show().addClass("visible");break;case"-2":i.find(".error,.success").hide().removeClass("visible").end().find(".animated").show().addClass("visible");break;default:i.find(".animated").hide().end().find(".error,.success").removeClass("visible")}else switch(n.toString()){case"1":i.addClass("success").removeClass("error");break;case"0":i.addClass("error").removeClass("success");break;case"-2":break;default:i.removeClass("error success")}}},f.bindingHandlers.emailsTags={init:function(e,t,i){var o=n(/*! Common/Utils */2),a=n(/*! Model/Email */45).default,s=c()(e),u=t(),l=i().autoCompleteSource||null,d=[",",";","\n"];s.inputosaurus({parseOnBlur:!0,allowDragAndDrop:!0,focusCallback:function(e){u&&u.focused&&u.focused(!!e)},inputDelimiters:d,autoCompleteSource:l,splitHook:function(e){var t=o.trim(e);return t&&-1=o&&(o=t),o===e()&&""+o!=""+n&&e(o+1),e(o)}});return o(e()),o},f.extenders.limitedList=function(e,t){var i=n(/*! Common/Utils */2),o=f.computed({read:e,write:function(n){var o=f.unwrap(e),a=f.unwrap(t);i.isNonEmptyArray(a)?-11&&void 0!==arguments[1])||arguments[1];return!!N(e)&&(t?/^[0-9]*$/.test(e.toString()):/^[1-9]+[0-9]*$/.test(e.toString()))}function R(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=N(e)&&""!==e?o.a.parseInt(e,10):t;return o.a.isNaN(n)?t:n}function I(e){return N(e)?""+e:""}function x(e){return!!e}function P(e){return e?"1":"0"}function k(e){return v(e)&&00&&void 0!==arguments[0]?arguments[0]:32,t="0123456789abcdefghijklmnopqrstuvwxyz",n=t.length;e=R(e);for(var i="";i.length1&&void 0!==arguments[1]?arguments[1]:100,n="",i="",o=e,a=0,r=0;o.length>t;)a=(i=o.substring(0,t)).lastIndexOf(" "),-1!==(r=i.lastIndexOf("\n"))&&(a=r),-1===a&&(a=t),n+=i.substring(0,a)+"\n",o=o.substring(a+1);return n+o}var q=function(){var e={};return function(t,n,i){e[t]=w(e[t])?0:e[t],o.a.clearTimeout(e[t]),e[t]=o.a.setTimeout(n,i)}}(),z=function(){var e={};return function(t,n,i){e[t]||(e[t]=o.a.setTimeout(function(){n(),e[t]=0},i))}}();function K(){try{if(o.a.document.activeElement)return w(o.a.document.activeElement.__inFocusCache)&&(o.a.document.activeElement.__inFocusCache=r()(o.a.document.activeElement).is("input,textarea,iframe,.cke_editable")),!!o.a.document.activeElement.__inFocusCache}catch(e){}return!1}function W(e){if(o.a.document&&o.a.document.activeElement&&o.a.document.activeElement.blur)try{var t=r()(o.a.document.activeElement);t&&t.is("input,textarea")?o.a.document.activeElement.blur():e&&o.a.document.activeElement.blur()}catch(e){}}function Y(){try{if(o.a&&o.a.getSelection){var e=o.a.getSelection();e&&e.removeAllRanges&&e.removeAllRanges()}else o.a.document&&o.a.document.selection&&o.a.document.selection.empty&&o.a.document.selection.empty()}catch(e){}}function $(e,t){e=g(e.toUpperCase()),t=g(t.replace(/[\s]+/g," "));var n=!1,i="RE"===e,o="FWD"===e,a=[],r=!o;return""!==t&&c.a.each(t.split(":"),function(e){var t=g(e);n||!/^(RE|FWD)$/i.test(t)&&!/^(RE|FWD)[\[\(][\d]+[\]\)]$/i.test(t)?(a.push(e),n=!0):(i||(i=!!/^RE/i.test(t)),o||(o=!!/^FWD/i.test(t)))}),r?i=!1:o=!1,g((r?"Re: ":"Fwd: ")+(i?"Re: ":"")+(o?"Fwd: ":"")+g(a.join(":")))}function J(e,t){return o.a.Math.round(e*o.a.Math.pow(10,t))/o.a.Math.pow(10,t)}function X(e){switch(e=R(e),!0){case 1073741824<=e:return J(e/1073741824,1)+"GB";case 1048576<=e:return J(e/1048576,1)+"MB";case 1024<=e:return J(e/1024,0)+"KB"}return e+"B"}function Q(e){o.a.console&&o.a.console.log&&o.a.console.log(e)}function Z(e,t,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;e&&e[t]&&(i=R(i),n=v(n)?n:[],0>=i?e[t].apply(e,n):c.a.delay(function(){e[t].apply(e,n)},i))}function ee(e){if((e=e||o.a.event)&&e.ctrlKey&&!e.shiftKey&&!e.altKey){var t=e.keyCode||e.which;if(t===f.EventKeyCode.S)return void e.preventDefault();if(t===f.EventKeyCode.A){var n=e.target||e.srcElement;if(n&&("true"==""+n.contentEditable||n.tagName&&n.tagName.match(/INPUT|TEXTAREA/i)))return;o.a.getSelection?o.a.getSelection().removeAllRanges():o.a.document.selection&&o.a.document.selection.clear&&o.a.document.selection.clear(),e.preventDefault()}}}function te(e,t){var n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],i=null;return(i=t?function(){for(var n=arguments.length,o=Array(n),a=0;a1&&void 0!==arguments[1]&&arguments[1];return n(/*! Common/Translator */10).i18n("LANGS_NAMES"+(!0===t?"_EN":"")+"/LANG_"+e.toUpperCase().replace(/[^a-zA-Z0-9]+/g,"_"),null,e)}function se(){return r()('
 
').appendTo("#rl-hidden")}function ce(e,t){t&&!w(t.disabled)&&e&&r()(e).toggleClass("disabled",t.disabled).prop("disabled",t.disabled)}function ue(e){e.find("blockquote.rl-bq-switcher").removeClass("rl-bq-switcher hidden-bq"),e.find(".rlBlockquoteSwitcher").off(".rlBlockquoteSwitcher").remove(),e.find("[data-html-editor-font-wrapper]").removeAttr("data-html-editor-font-wrapper")}function le(e,t,i,a){var r=e.title,s=e.subject,c=e.date,u=e.fromCreds,l=e.toCreds,d=e.toLabel,p=e.ccClass,f=e.ccCreds,m=e.ccLabel,h=o.a.open(""),g=h.document,b=t.clone(),v=i?"html":"plain";ue(b);var S=b?b.html():"";g.write(n(/*! Html/PreviewMessage.html */122).replace("{{title}}",B(r)).replace("{{subject}}",B(s)).replace("{{date}}",B(c)).replace("{{fromCreds}}",B(u)).replace("{{toCreds}}",B(l)).replace("{{toLabel}}",B(d)).replace("{{ccClass}}",B(p)).replace("{{ccCreds}}",B(f)).replace("{{ccLabel}}",B(m)).replace("{{bodyClass}}",v).replace("{{html}}",S)),g.close(),a&&o.a.setTimeout(function(){return h.print()},100)}function de(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1e3;return i=R(i),function(o,a,r,s,u){t.call(n,a&&a.Result?f.SaveSettingsStep.TrueResult:f.SaveSettingsStep.FalseResult),e&&e.call(n,o,a,r,s,u),c.a.delay(function(){t.call(n,f.SaveSettingsStep.Idle)},i)}}function pe(e,t){return de(null,e,t,1e3)}function fe(e,t,n,i){return function(o){if(e){switch(n){case"bool":case"boolean":o=o?"1":"0";break;case"int":case"integer":case"number":o=R(o);break;case"trim":o=g(o);break;default:o=I(o)}var a={};a[t]=o,e.saveAdminConfig?e.saveAdminConfig(i||null,a):e.saveSettings&&e.saveSettings(i||null,a)}}}function me(e){return d.a?d.a.link(e,{newWindow:!0,stripPrefix:!1,urls:!0,email:!0,mention:!1,phone:!1,hashtag:!1,replaceFn:function(e){return!(e&&"url"===e.getType()&&e.matchedText&&0!==e.matchedText.indexOf("http"))}}):e}function he(e){var t=0,n=0,i=0,o=0,a=0,r="",s=function(e){return(e="> "+g(e).replace(/\n/gm,"\n> ")).replace(/(^|\n)([> ]+)/gm,function(){for(var e=arguments.length,t=Array(e),n=0;n]*><\/p>/gi,"").replace(/]*>([\s\S\r\n\t]*)<\/pre>/gim,function(){for(var e=arguments.length,t=Array(e),n=0;n").replace(/[\r]/gm,""):""}).replace(/[\s]+/gm," ").replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gim,function(){for(var e=arguments.length,t=Array(e),n=0;n]*>/gim,"\n").replace(/<\/h[\d]>/gi,"\n").replace(/<\/p>/gi,"\n\n").replace(/]*>/gim,"\n").replace(/<\/ul>/gi,"\n").replace(/]*>/gim," * ").replace(/<\/li>/gi,"\n").replace(/<\/td>/gi,"\n").replace(/<\/tr>/gi,"\n").replace(/]*>/gim,"\n_______________________________\n\n").replace(/]*>([\s\S\r\n]*)<\/div>/gim,function e(){for(var t=arguments.length,n=Array(t),i=0;i]*>([\s\S\r\n]*)<\/div>/gim,e),o="\n"+g(o)+"\n"),o}return""}).replace(/]*>/gim,"\n__bq__start__\n").replace(/<\/blockquote>/gim,"\n__bq__end__\n").replace(/]*>([\s\S\r\n]*?)<\/a>/gim,function(){for(var e=arguments.length,t=Array(e),n=0;n/gi,"\n").replace(/ /gi," ").replace(/"/gi,'"').replace(/<[^>]*>/gm,""),r=V(r=(r=p.$div.html(r).text()).replace(/\n[ \t]+/gm,"\n").replace(/[\n]{3,}/gm,"\n\n").replace(/>/gi,">").replace(/</gi,"<").replace(/&/gi,"&")),t=0,n=800;01&&void 0!==arguments[1]&&arguments[1],n=!1,i=!0,o=!0,a=[],r="",s=0,c=(e=(e=e.toString().replace(/\r/g,"")).replace(/^>[> ]>+/gm,function(e){var t=e[0];return t?t.replace(/[ ]+/g,""):t})).split("\n");do{for(i=!1,a=[],s=0;s"===(r=c[s]).substr(0,1))&&!n?(i=!0,n=!0,a.push("~~~blockquote~~~"),a.push(r.substr(1))):!o&&n?""!==r?(n=!1,a.push("~~~/blockquote~~~"),a.push(r)):a.push(r):o&&n?a.push(r.substr(1)):a.push(r);n&&(n=!1,a.push("~~~/blockquote~~~")),c=a}while(i);return e=(e=c.join("\n")).replace(/&/g,"&").replace(/>/g,">").replace(/").replace(/[\s]*~~~\/blockquote~~~/g,"").replace(/\n/g,"
"),t?me(e):e}function be(e,t,n,i,a,r,s,c,u,l){var d=null,p=!1,m=0,h=0,g=[];for(l=!w(l)&&!!l,u=N(u)?u:00&&void 0!==arguments[0]&&arguments[0]?c.a.delay(e,100):e()}var we={};function Oe(e){we[e]||(we[e]=r()('script[type="application/json"][data-configuration="'+e+'"]'));try{return JSON.parse(we[e].text())}catch(e){}return{}}function Ae(e,t){var n=t||e;n&&"function"==typeof n.dispose&&n.dispose()}function Te(e){e&&(v(e.disposables)&&c.a.each(e.disposables,Ae),u.a.utils.objectForEach(e,Ae))}function Ce(e){e&&(v(e)?c.a.each(e,function(e){Ce(e)}):e&&e.onDestroy&&e.onDestroy())}function _e(e,t){return!(!e||!e[0])&&(e[0].styleSheet&&!w(e[0].styleSheet.cssText)?e[0].styleSheet.cssText=t:e.text(t),!0)}var Ee=0,De=null;function Ne(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:C,n=r()("#app-theme-link"),i=function(){Ee=o.a.setTimeout(function(){return t(f.SaveSettingsStep.Idle)},1e3),De=null},a=r()("#app-theme-style"),s=n.attr("href");s||(s=a.attr("data-href")),s&&("Json/"!==(s=(s=(s=s.toString().replace(/\/-\/[^\/]+\/\-\//,"/-/"+e+"/-/")).replace(/\/Css\/[^\/]+\/User\//,"/Css/0/User/")).replace(/\/Hash\/[^\/]+\//,"/Hash/-/")).substring(s.length-5,s.length)&&(s+="Json/"),o.a.clearTimeout(Ee),t(f.SaveSettingsStep.Animate),De&&De.abort&&De.abort(),De=r.a.ajax({url:s,dataType:"json"}).then(function(e){e&&v(e)&&2===e.length&&(!n||!n[0]||a&&a[0]||(a=r()(''),n.after(a),n.remove()),a&&a[0]&&_e(a,e[1])&&a.attr("data-href",s).attr("data-theme",e[0]),t(f.SaveSettingsStep.TrueResult))}).then(i,i))}function je(e,t){return function(){var n=e(),i=t(),o=[],a=function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",a={current:e===n,name:""===i?e.toString():i.toString(),custom:""!==i,title:""===i?"":e.toString(),value:e.toString()};t?o.push(a):o.unshift(a)},r=0,s=0,c=2;if(1=n||i-2<=n)&&(c+=2),a(n),r=n,s=n);0=s)a(s,!0),c-=1;else if(0>=r)break;3===r?a(2,!1):3s&&a(Math.round((i+s)/2),!0,"..."),1s&&a(i,!0)}return o}}function Re(e){var t=(e=g(e).toLowerCase()).split(".").pop();return t===e?"":t}function Ie(e){var t,n="application/octet-stream";return"winmail.dat"===(e=g(e).toLowerCase())?"application/ms-tnef":((t=Re(e))&&0this.height?[this.width-this.height,0]:[0,this.height-this.width],a.fillStyle="#fff",a.fillRect(0,0,t,t),a.drawImage(this,e[0]/2,e[1]/2,this.width-e[0],this.height-e[1],0,0,t,t),n(i.toDataURL("image/jpeg"))},i.src=e}function Le(e,t){if(e&&"mailto:"===e.toString().substr(0,7).toLowerCase()){if(!t)return!0;var i,o=[],a=null,r=null,s=(e=e.toString().substr(7)).replace(/\?.+$/,""),u=e.replace(/^[^\?]*\?/,""),l=n(/*! Model/Email */45).default;return i=H(u),w(i.to)?o=l.parseEmailLine(s):(o=l.parseEmailLine(M(s+","+i.to)),o=c.a.values(o.reduce(function(e,t){return t&&(e[t.email]&&e[t.email].name||(e[t.email]=t)),e},{}))),w(i.cc)||(a=l.parseEmailLine(M(i.cc))),w(i.bcc)||(r=l.parseEmailLine(M(i.bcc))),n(/*! Knoin/Knoin */9).showScreenPopup(t,[f.ComposeType.Empty,null,o,a,r,w(i.subject)?null:I(M(i.subject)),w(i.body)?null:ge(I(M(i.body)))]),!0}return!1}function Me(e){r()(function(){return e()})}var Fe=c.a.debounce(function(e){w(e)||O(e)?p.$win.resize():o.a.setTimeout(function(){p.$win.resize()},e)},50);function Ue(){Fe()}var He=o.a.String.substr;"b"!=="ab".substr(-1)&&(He=function(e,t,n){return t=0>t?e.length+t:t,e.substr(t,n)},o.a.String.substr=He)}, -/*!*************************!*\ - !*** external "window" ***! - \*************************/ -/*! no static exports found */ -/*! exports used: default */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){e.exports=window}, -/*!***************************!*\ - !*** external "window._" ***! - \***************************/ -/*! no static exports found */ -/*! exports used: default */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){e.exports=window._}, -/*!*********************************!*\ - !*** ./dev/Storage/Settings.js ***! - \*********************************/ -/*! exports provided: settingsGet, settingsSet, appSettingsGet, capa */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is referenced from these modules with unsupported syntax: ./dev/External/ko.js (referenced with cjs require) */function(e,t,n){"use strict";n.r(t),n.d(t,"settingsGet",function(){return c}),n.d(t,"settingsSet",function(){return u}),n.d(t,"appSettingsGet",function(){return l}),n.d(t,"capa",function(){return d});var i=n(/*! window */3),o=n.n(i),a=n(/*! Common/Utils */2),r=o.a.__rlah_data()||null,s=(r=Object(a.isNormal)(r)?r:{}).System||null;function c(e){return Object(a.isUnd)(r[e])?null:r[e]}function u(e,t){r[e]=t}function l(e){return Object(a.isUnd)(s[e])?null:s[e]}function d(e){var t=c("Capa");return Object(a.isArray)(t)&&Object(a.isNormal)(e)&&-1"),v=c()("
");v.attr("area","hidden").css({position:"absolute",left:-5e3}).appendTo(g);var S=(new o.a.Date).getTime(),y=!0,w=d.a.observable(!1).extend({rateLimit:0}),O=d.a.observable(!0),A="navigator"in o.a&&"userAgent"in o.a.navigator&&o.a.navigator.userAgent.toLowerCase()||"",T=-11&&void 0!==arguments[1])||arguments[1];return Object(h.createCommandLegacy)(null,e,t)}function O(e,t,n,i){var o=arguments.length>4&&void 0!==arguments[4]&&arguments[4];e.__rlSettingsData={Label:n,Template:t,Route:i,IsDefault:!!o},m.VIEW_MODELS.settings.push(e)}function A(e){m.VIEW_MODELS["settings-removed"].push(e)}function T(e){m.VIEW_MODELS["settings-disabled"].push(e)}function C(){u.a.changed.active=!1}function _(){u.a.changed.active=!0}function E(e){return""===e||Object(h.isUnd)(v[e])?null:v[e]}function D(e){var t=null;return e&&(t=e,e.default&&(t=e.default)),t}function N(e){var t=D(e);t&&t.__vm&&t.__dom&&t.__vm.modalVisibility(!1)}function j(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;o.a.each(t.__names,function(i){Object(f.f)(e,[i,t.__vm,n])})}function R(e,t){if(e&&!e.__builded){var n=null,i=new e(t),a=e.__type||"",c=a?r()("#rl-content #rl-"+a.toLowerCase()):null;e.__builded=!0,e.__vm=i,i.onShowTrigger=s.a.observable(!1),i.onHideTrigger=s.a.observable(!1),i.viewModelName=e.__name,i.viewModelNames=e.__names,i.viewModelTemplateID=e.__templateID,i.viewModelPosition=e.__type,c&&1===c.length?((n=r()("
").addClass("rl-view-model").addClass("RL-"+i.viewModelTemplateID).hide()).appendTo(c),i.viewModelDom=n,e.__dom=n,S.Popup===a&&(i.cancelCommand=i.closeCommand=w(function(){N(e)}),i.modalVisibility.subscribe(function(t){t?(i.viewModelDom.show(),i.storeAndSetKeyScope(),m.popupVisibilityNames.push(i.viewModelName),i.viewModelDom.css("z-index",3e3+Object(m.popupVisibilityNames)().length+10),i.onShowTrigger&&i.onShowTrigger(!i.onShowTrigger()),Object(h.delegateRun)(i,"onShowWithDelay",[],500)):(Object(h.delegateRun)(i,"onHide"),Object(h.delegateRun)(i,"onHideWithDelay",[],500),i.onHideTrigger&&i.onHideTrigger(!i.onHideTrigger()),i.restoreKeyScope(),j("view-model-on-hide",e),m.popupVisibilityNames.remove(i.viewModelName),i.viewModelDom.css("z-index",2e3),o.a.delay(function(){return i.viewModelDom.hide()},300))})),j("view-model-pre-build",e,n),s.a.applyBindingAccessorsToNode(n[0],{translatorInit:!0,template:function(){return{name:i.viewModelTemplateID}}},i),Object(h.delegateRun)(i,"onBuild",[n]),i&&S.Popup===a&&i.registerPopupKeyDown(),j("view-model-post-build",e,n)):Object(h.log)("Cannot find view model position: "+a)}return e?e.__vm:null}function I(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=D(e);n&&(R(n),n.__vm&&n.__dom&&(Object(h.delegateRun)(n.__vm,"onBeforeShow",t||[]),n.__vm.modalVisibility(!0),Object(h.delegateRun)(n.__vm,"onShow",t||[]),j("view-model-on-show",n,t||[])))}function x(e){var t=D(e);t&&(R(t),t.__vm&&t.__dom&&Object(h.delegateRun)(t.__vm,"onWarmUp"))}function P(e){var t=D(e);return!(!t||!t.__vm)&&t.__vm.modalVisibility()}function k(e,t){var n=null,i=!1,a=null;""===Object(h.pString)(e)&&(e=b),""!==e&&((n=E(e))||(n=E(b))&&(t=e+"/"+t,e=b),n&&n.__started&&(i=g&&n===g,n.__builded||(n.__builded=!0,Object(h.isNonEmptyArray)(n.viewModels())&&o.a.each(n.viewModels(),function(e){R(e,n)}),Object(h.delegateRun)(n,"onBuild")),o.a.defer(function(){g&&!i&&(Object(h.delegateRun)(g,"onHide"),Object(h.delegateRun)(g,"onHideWithDelay",[],500),g.onHideTrigger&&g.onHideTrigger(!g.onHideTrigger()),Object(h.isNonEmptyArray)(g.viewModels())&&o.a.each(g.viewModels(),function(e){e.__vm&&e.__dom&&S.Popup!==e.__vm.viewModelPosition&&(e.__dom.hide(),e.__vm.viewModelVisibility(!1),Object(h.delegateRun)(e.__vm,"onHide"),Object(h.delegateRun)(e.__vm,"onHideWithDelay",[],500),e.__vm.onHideTrigger&&e.__vm.onHideTrigger(!e.__vm.onHideTrigger()))})),(g=n)&&!i&&(Object(h.delegateRun)(g,"onShow"),g.onShowTrigger&&g.onShowTrigger(!g.onShowTrigger()),Object(f.f)("screen-on-show",[g.screenName(),g]),Object(h.isNonEmptyArray)(g.viewModels())&&o.a.each(g.viewModels(),function(e){e.__vm&&e.__dom&&S.Popup!==e.__vm.viewModelPosition&&(Object(h.delegateRun)(e.__vm,"onBeforeShow"),e.__dom.show(),e.__vm.viewModelVisibility(!0),Object(h.delegateRun)(e.__vm,"onShow"),e.__vm.onShowTrigger&&e.__vm.onShowTrigger(!e.__vm.onShowTrigger()),Object(h.delegateRun)(e.__vm,"onShowWithDelay",[],200),j("view-model-on-show",e))})),(a=n&&n.__cross?n.__cross():null)&&a.parse(t)})))}function L(e){o.a.each(e,function(e){if(e){var t=new e,n=t?t.screenName():"";t&&""!==n&&(""===b&&(b=n),v[n]=t)}}),o.a.each(v,function(e){e&&!e.__started&&e.__start&&(e.__started=!0,e.__start(),Object(f.f)("screen-pre-start",[e.screenName(),e]),Object(h.delegateRun)(e,"onStart"),Object(f.f)("screen-post-start",[e.screenName(),e]))});var t=d.a.create();t.addRoute(/^([a-zA-Z0-9\-]*)\/?(.*)$/,k),u.a.initialized.add(t.parse,t),u.a.changed.add(t.parse,t),u.a.init(),o.a.delay(function(){return m.$html.removeClass("rl-started-trigger").addClass("rl-started")},100),o.a.delay(function(){return m.$html.addClass("rl-started-delay")},200)}function M(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];e="/"===(e="#"===e.substr(0,1)?e.substr(1):e).substr(0,1)?e.substr(1):e;var i=n?"replaceHash":"setHash";t?(u.a.changed.active=!1,u.a[i](e),u.a.changed.active=!0):(u.a.changed.active=!0,u.a[i](e),u.a.setHash(e))}function F(e){var t=e.name,n=e.type,i=e.templateID;return function(e){e&&(t&&(Object(h.isArray)(t)?e.__names=t:e.__names=[t],e.__name=e.__names[0]),n&&(e.__type=n),i&&(e.__templateID=i))}}function U(e){var t=e.name,n=e.templateID;return F({name:t,type:S.Popup,templateID:n})}function H(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];return function(t,n,i){if(!n||!n.match(/Command$/))throw new Error('name "'+n+'" should end with Command suffix');var o=i.value||i.initializer(),a=Object(h.isFunc)(e)?e:function(){return!!e};return i.value=function(){if(a.call(this,this)){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]&&arguments[1];r.a.defer(function(){c()("[data-i18n]",e).each(function(e,t){y(t)}),t&&p.bAnimationSupported&&c()(".i18n-animation[data-i18n]",e).letterfx({fx:"fall fade",backwards:!1,timing:50,fx_duration:"50ms",letter_end:"restore",element_end:"restore"})})}var O=function(){o.a.rainloopI18N&&(h=o.a.rainloopI18N||{},w(o.a.document,!0),Object(f.reload)(),v(!v())),o.a.rainloopI18N=null};function A(){b.forEach(function(e){g[e[0]]=S(e[1])})}function T(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;e&&e(),t?v.subscribe(function(){e&&e(),t&&t()}):e&&v.subscribe(e)}function C(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;return e=o.a.parseInt(e,10)||0,l.Notification.ClientViewError===e&&t?t:(n=n&&o.a.parseInt(n,10)||0,Object(d.isUnd)(g[e])?n&&Object(d.isUnd)(g[n])?g[n]:"":g[e])}function _(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:l.Notification.UnknownNotification;return e&&e.ErrorCode?C(Object(d.pInt)(e.ErrorCode),e.ErrorMessage||""):C(t)}function E(e){var t="";switch(o.a.parseInt(e,10)||0){case l.UploadErrorCode.FileIsTooBig:t=S("UPLOAD/ERROR_FILE_IS_TOO_BIG");break;case l.UploadErrorCode.FilePartiallyUploaded:t=S("UPLOAD/ERROR_FILE_PARTIALLY_UPLOADED");break;case l.UploadErrorCode.FileNoUploaded:t=S("UPLOAD/ERROR_NO_FILE_UPLOADED");break;case l.UploadErrorCode.MissingTempFolder:t=S("UPLOAD/ERROR_MISSING_TEMP_FOLDER");break;case l.UploadErrorCode.FileOnSaveingError:t=S("UPLOAD/ERROR_ON_SAVING_FILE");break;case l.UploadErrorCode.FileType:t=S("UPLOAD/ERROR_FILE_TYPE");break;default:t=S("UPLOAD/ERROR_UNKNOWN")}return t}function D(e,t){var n=Object(d.microtime)();return p.$html.addClass("rl-changing-language"),new o.a.Promise(function(i,a){c.a.ajax({url:Object(m.n)(t,e),dataType:"script",cache:!0}).then(function(){r.a.delay(function(){O();var e=-10&&void 0!==arguments[0]?arguments[0]:"";return c+Object(a.pString)(e)}function w(){return h?s:u+g}function O(){return s}function A(e,t,n){return n=Object(a.isUnd)(n)?b:n,u+"/Raw/"+l+"/"+n+"/"+e+"/"+l+"/"+t}function T(e,t){return A("Download",e,t)}function C(e,t){return A("View",e,t)}function _(e,t){return A("ViewThumbnail",e,t)}function E(e,t){return A("ViewAsPlain",e,t)}function D(e,t){return A("FramedView",e,t)}function N(e){return u+"/"+e+"/"+l+"/"+b+"/"}function j(){return N("Upload")}function R(){return N("UploadContacts")}function I(){return N("UploadBackground")}function x(){return N("Append")}function P(e){return N("Change")+Object(a.encodeURIComponent)(e)+"/"}function k(e){return N("Ajax")+e}function L(e){return u+"/Raw/"+l+"/"+b+"/ViewAsPlain/"+l+"/"+e}function M(e){return u+"/Raw/"+l+"/"+b+"/Download/"+l+"/"+e}function F(e){return u+"/Raw/0/Avatar/"+Object(a.encodeURIComponent)(e)+"/"}function U(e){return u+"/Raw/"+l+"/"+b+"/UserBackground/"+l+"/"+e}function H(){return u+"/Info"}function G(e,t){return u+"/Lang/0/"+(t?"Admin":"App")+"/"+o.a.encodeURI(e)+"/"+d+"/"}function B(){return u+"/Raw/"+l+"/"+b+"/ContactsVcf/"}function V(){return u+"/Raw/"+l+"/"+b+"/ContactsCsv/"}function q(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return u+"SocialGoogle"+(""!==b?"/"+l+"/"+b+"/":"")+(e?"&xauth=1":"")}function z(){return u+"SocialTwitter"+(""!==b?"/"+l+"/"+b+"/":"")}function K(){return u+"SocialFacebook"+(""!==b?"/"+l+"/"+b+"/":"")}function W(e){return m+e}function Y(){return W("css/images/empty-contact.png")}function $(e){return W("sounds/"+e)}function J(){return W("css/images/icom-message-notification.png")}function X(){return W("js/min/openpgp.min.js")}function Q(){return W("js/min/openpgp.worker.min.js")}function Z(e){var t=f;return"@custom"===e.substr(-7)&&(e=Object(a.trim)(e.substring(0,e.length-7)),t=p),t+"themes/"+o.a.encodeURI(e)+"/images/preview.png"}function ee(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"INBOX";return c+"mailbox/"+e}function te(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return c+"settings"+(e?"/"+e:"")}function ne(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";t=Object(a.isNormal)(t)?Object(a.pInt)(t):1,n=Object(a.pString)(n);var r=c+"mailbox/";if(""!==e){var s=Object(a.pInt)(i);r+=o.a.encodeURI(e)+(01&&void 0!==arguments[1])||arguments[1];this.defaultRequest(e,"AdminDomainList",{IncludeAliases:t?"1":"0"})},t.prototype.pluginList=function(e){this.defaultRequest(e,"AdminPluginList")},t.prototype.packagesList=function(e){this.defaultRequest(e,"AdminPackagesList")},t.prototype.coreData=function(e){this.defaultRequest(e,"AdminCoreData")},t.prototype.updateCoreData=function(e){this.defaultRequest(e,"AdminUpdateCoreData",{},9e4)},t.prototype.packageInstall=function(e,t){this.defaultRequest(e,"AdminPackageInstall",{Id:t.id,Type:t.type,File:t.file},6e4)},t.prototype.packageDelete=function(e,t){this.defaultRequest(e,"AdminPackageDelete",{Id:t.id})},t.prototype.domain=function(e,t){this.defaultRequest(e,"AdminDomainLoad",{Name:t})},t.prototype.plugin=function(e,t){this.defaultRequest(e,"AdminPluginLoad",{Name:t})},t.prototype.domainDelete=function(e,t){this.defaultRequest(e,"AdminDomainDelete",{Name:t})},t.prototype.domainDisable=function(e,t,n){return this.defaultRequest(e,"AdminDomainDisable",{Name:t,Disabled:n?"1":"0"})},t.prototype.pluginSettingsUpdate=function(e,t){return this.defaultRequest(e,"AdminPluginSettingsUpdate",t)},t.prototype.licensing=function(e,t){return this.defaultRequest(e,"AdminLicensing",{Force:t?"1":"0"})},t.prototype.licensingActivate=function(e,t,n){return this.defaultRequest(e,"AdminLicensingActivate",{Domain:t,Key:n})},t.prototype.pluginDisable=function(e,t,n){return this.defaultRequest(e,"AdminPluginDisable",{Name:t,Disabled:n?"1":"0"})},t.prototype.createDomainAlias=function(e,t,n){this.defaultRequest(e,"AdminDomainAliasSave",{Name:t,Alias:n})},t.prototype.createOrUpdateDomain=function(e,t,n,i,o,a,r,s,c,u,l,d,p,f,m,h,g,b,v){this.defaultRequest(e,"AdminDomainSave",{Create:t?"1":"0",Name:n,IncHost:i,IncPort:o,IncSecure:a,IncShortLogin:r?"1":"0",UseSieve:s?"1":"0",SieveAllowRaw:c?"1":"0",SieveHost:u,SievePort:l,SieveSecure:d,OutHost:p,OutPort:f,OutSecure:m,OutShortLogin:h?"1":"0",OutAuth:g?"1":"0",OutUsePhpMail:b?"1":"0",WhiteList:v})},t.prototype.testConnectionForDomain=function(e,t,n,i,o,a,r,s,c,u,l,d,p,f){this.defaultRequest(e,"AdminDomainTest",{Name:t,IncHost:n,IncPort:i,IncSecure:o,UseSieve:a?"1":"0",SieveHost:r,SievePort:s,SieveSecure:c,OutHost:u,OutPort:l,OutSecure:d,OutAuth:p?"1":"0",OutUsePhpMail:f?"1":"0"})},t.prototype.testContacts=function(e,t){this.defaultRequest(e,"AdminContactsTest",t)},t.prototype.saveNewAdminPassword=function(e,t){this.defaultRequest(e,"AdminPasswordUpdate",t)},t.prototype.adminPing=function(e){this.defaultRequest(e,"AdminPing")},t}(n(/*! Remote/AbstractAjax */115).a);t.a=new u}, -/*!******************************!*\ - !*** ./dev/Common/Events.js ***! - \******************************/ -/*! exports provided: sub, pub */ -/*! exports used: pub, sub */function(e,t,n){"use strict";n.d(t,"b",function(){return c}),n.d(t,"a",function(){return u});var i=n(/*! _ */4),o=n.n(i),a=n(/*! Common/Utils */2),r=n(/*! Common/Plugins */29),s={};function c(e,t,n){Object(a.isObject)(e)?(n=t||null,t=null,o.a.each(e,function(e,t){c(t,e,n)})):(Object(a.isUnd)(s[e])&&(s[e]=[]),s[e].push([t,n]))}function u(e,t){r.f("rl-pub",[e,t]),Object(a.isUnd)(s[e])||o.a.each(s[e],function(e){e[0]&&e[0].apply(e[1]||null,t||[])})}}, -/*!******************************!*\ - !*** ./dev/Common/Consts.js ***! - \******************************/ -/*! exports provided: MESSAGES_PER_PAGE, MESSAGES_PER_PAGE_VALUES, CONTACTS_PER_PAGE, DEFAULT_AJAX_TIMEOUT, SEARCH_AJAX_TIMEOUT, SEND_MESSAGE_AJAX_TIMEOUT, SAVE_MESSAGE_AJAX_TIMEOUT, CONTACTS_SYNC_AJAX_TIMEOUT, UNUSED_OPTION_VALUE, CLIENT_SIDE_STORAGE_INDEX_NAME, IMAP_DEFAULT_PORT, IMAP_DEFAULT_SECURE_PORT, SMTP_DEFAULT_PORT, SMTP_DEFAULT_SECURE_PORT, SIEVE_DEFAULT_PORT, MESSAGE_BODY_CACHE_LIMIT, AJAX_ERROR_LIMIT, TOKEN_ERROR_LIMIT, RAINLOOP_TRIAL_KEY, DATA_IMAGE_USER_DOT_PIC, DATA_IMAGE_TRANSP_PIC, DATA_IMAGE_LAZY_PLACEHOLDER_PIC */ -/*! exports used: AJAX_ERROR_LIMIT, CLIENT_SIDE_STORAGE_INDEX_NAME, CONTACTS_PER_PAGE, CONTACTS_SYNC_AJAX_TIMEOUT, DATA_IMAGE_LAZY_PLACEHOLDER_PIC, DATA_IMAGE_USER_DOT_PIC, DEFAULT_AJAX_TIMEOUT, IMAP_DEFAULT_PORT, MESSAGES_PER_PAGE, MESSAGES_PER_PAGE_VALUES, MESSAGE_BODY_CACHE_LIMIT, SAVE_MESSAGE_AJAX_TIMEOUT, SEARCH_AJAX_TIMEOUT, SEND_MESSAGE_AJAX_TIMEOUT, SIEVE_DEFAULT_PORT, SMTP_DEFAULT_PORT, TOKEN_ERROR_LIMIT, UNUSED_OPTION_VALUE */function(e,t,n){"use strict";n.d(t,"i",function(){return i}),n.d(t,"j",function(){return o}),n.d(t,"c",function(){return a}),n.d(t,"g",function(){return r}),n.d(t,"m",function(){return s}),n.d(t,"n",function(){return c}),n.d(t,"l",function(){return u}),n.d(t,"d",function(){return l}),n.d(t,"r",function(){return d}),n.d(t,"b",function(){return p}),n.d(t,"h",function(){return f}),n.d(t,"p",function(){return m}),n.d(t,"o",function(){return h}),n.d(t,"k",function(){return g}),n.d(t,"a",function(){return b}),n.d(t,"q",function(){return v}),n.d(t,"f",function(){return S}),n.d(t,"e",function(){return y});var i=20,o=[10,20,30,50,100],a=50,r=3e4,s=3e5,c=3e5,u=2e5,l=2e5,d="__UNUSE__",p="rlcsc",f=143,m=25,h=4190,g=15,b=7,v=10,S="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAHHklEQVRoQ7VZW08bVxCeXRuwIbTGXIwNtBBaqjwgVUiR8lDlbza9qe1DpVZ9aNQ/0KpPeaJK07SpcuEeCEmUAObm21bfrL9lONjexSYrWfbunj37zXdmvpkz9oIgCKTD0Wg0xPd94TDP83Q0zvWa50vzklSrdanVanqf4/D84GBGr+F+Op3S8fqoJxLOdnZgTvsO/nYhenHA+UC7CWF1uXwkb9++ldPTUwVerVbVqFQqpR8YPjQ0JCMjI5LNDijoRgP3PQVu5+5Eor2XGLg7IV4GkIdHJ/LmzRs5ODiIwNbrdR0O0GCcq4Xz4eFhmZyclP7+tDQaIik/BG5XKQn4SwG3zJTLZXn9+rUclI8UHD5YVoDDN8bSzXhONwL48fFxGR4eilzFZT1uFRIB5yT8BqCdnR3Z3d0VP9Un6XRawYJpggVrZBv38ME4XKtUKnLt2jUplUoy1PR/l3U7T6sVSAQcgMAkj8PDQ9ne3pajoyMRL7zeKsYZWHgWYDGmv78/mmdwcFA+mJlSgziHDWrERrsjEXDXegTi1tZW+DLxI2bxIrqFNYTXyDyCFweMAHCwb8e4RnTNuOsqe3t7sra21pTD0Kct666E8XlcZyzw9/RUUXK5nK5oUinUQI6TQ3cynO/v78vq6qrKXCNwlTiJJpyNGc3nZHp6uqV2dwrQWOCtZBDAV1ZWwsQk7f0wiQn5kffbAu/0/KWBYzIC1+XukfGx0RGZmppKlC2tIV0Bh4aDcZW7HhkfH8urLLZL7T2pihvlkMNnz56FiadHxicL41IsFpN41bkxsYxbRdFo9jwB8KdPn14J8KnSpBQKhQs63nPmbCVRcBUAR2Lq1VVmpksyMTFxAXjcEsQybiegESionjx5osCZOeNe1O4+EhCAX7bQSgQcxRHTMgAgcz5+/Dis/hL4uHU3/B4YGNASGHIKxuEql0k+l05AeIAF1vPnz5VxFFmdDlaJrMtZITJeSsXCOTlMunKxjLtMYOKNjQ158eJFuAuKkUOb5sEwgff19SkJUBVkThZUbnXZrtCKBQ6gbnWIkjZpyne3ejAWoGnA7Icz6irvBLgbOMicCM6TkxPx/LAkbXfgWcsazuE2kFRsKD5Z+CiqDumKncpZvieWcS6dDVD8xiYCNflpJdwcdwJOf9airLmVQ7DPzMxIYWLsXGXoVqLt5k0M3K3JUVPDZdbWNzsCp48TPFdvdnZWUz32nDha7bJ63kgAJPzSdRks9/Kf9xMJAQ1gq2NpaUmy2Yz4zar4nQC3xb99AQwCcGzLAAwuhG8YiWvcOKts+r4GOe5nMhm5efOm9lUA3E3vSZJRrKvE0fnPv//Jy5cvo5cTHIPQbSjhOoqq69evS19f6lxDKK4+sVhigZPtKJqbrQeqxd5+WR4+fKgqgT0k2XX3nhiPgETWXFhYkFzuPZ2yVq1GTSOXpE47/VjgNnD4m4GG7/LhsTx69EiwD4Vr2MwIIxgbAH18fKx1yfz8vEogNvGtWnCuhLZa9UTAreVWFsHy/b/+Vrbdl7E5REMQD2jDoUbByty+/ZnU64GkU2HzyJLhktU1cLv8nARgkYS2d3ajAgwG8qU2oLmDZ92CMaOjo7K4uCiZgbDWaRWgnZhPxLhrMUCvr69riwKZk1LHF7XqrWAO9hJxH6ozNzcnCx/PqztZg9mf6SQMscCtm2C5ke4BGMlHWTUp36036AJajDVrFMzBrhhWslQsSrFYiOqVpMriNYIgqFRq2j3FAb/zffT6zuxFXxsNzs3NTXn16lW4gYiW96w1FyedF+83xG/2FNGCRpU4NjamMsn+OZ9xE5RXqdaDdPpib6RWCzuwKF9RxqI2AVNQBwQYJoK0wdBejnqtEikP3pfP51XjUTESl12FqJEKxsEorARYDD44ONTeID7YpsEnrRvQfWAI2e8WfDaTUSIwJ0iBCmFOtOUAHvVMPp/TPwvYFVYFIuP8l+DBgwdaa2Miqwa0GgYwfeMltovbDfh6c1vIgMYcliSsKv4IWFr6VDHxvldvBAH+1sA+cnl5WYOPmmr9ir+1l9I0Cgz0yjhXjfJJ0JROnmezWbl165ayr/5fqwcBNr7IfhjMqKcvESSM4eRcCasQ3bDNObmKPLdGUGpZsN24cUNLBm9zazu4d++e6qpNBFaTuUS26U5dpuR1CxyA7J9ddrMRqlz4pwLLYawymPd++/2PADt2ugcGwq9gCCdhQ96C6xWwa6j1ceuq+I0EhW0i8MAIVJfeL3d/DVD8EKi12P6/2S2jV/EccVB54O/ejz/9HGCpoBBMta5rXMXLu53D1XAwjhXwvvv+h4BAXVe4bOu3O3ChxF08LiZFG3fel199G9CH3fLyqv24NcB44MRhpdK788U3CpyKwsCw590xmfSpzsBt0Fqc3ud3vtZigxWcVZCklVpSiN0w3q5E/h9TGMIUuA3+EQAAAABJRU5ErkJggg==",y="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC"}, -/*!***************************************!*\ - !*** ./dev/Knoin/AbstractViewNext.js ***! - \***************************************/ -/*! exports provided: AbstractViewNext */ -/*! exports used: AbstractViewNext */function(e,t,n){"use strict";n.d(t,"a",function(){return u});var i=n(/*! babel-runtime/helpers/classCallCheck */8),o=n.n(i),a=n(/*! ko */1),r=n(/*! Common/Utils */2),s=n(/*! Common/Enums */0),c=n(/*! Common/Globals */6),u=function(){function e(){o()(this,e),this.bDisabeCloseOnEsc=!1,this.sDefaultKeyScope=s.KeyState.None,this.sCurrentKeyScope=s.KeyState.None,this.viewModelVisibility=a.a.observable(!1),this.modalVisibility=a.a.observable(!1).extend({rateLimit:0}),this.viewModelName="",this.viewModelNames=[],this.viewModelDom=null}return e.prototype.storeAndSetKeyScope=function(){this.sCurrentKeyScope=Object(c.keyScope)(),Object(c.keyScope)(this.sDefaultKeyScope)},e.prototype.restoreKeyScope=function(){Object(c.keyScope)(this.sCurrentKeyScope)},e.prototype.registerPopupKeyDown=function(){var e=this;c.$win.on("keydown",function(t){if(t&&e.modalVisibility&&e.modalVisibility()){if(!e.bDisabeCloseOnEsc&&s.EventKeyCode.Esc===t.keyCode)return Object(r.delegateRun)(e,"cancelCommand"),!1;if(s.EventKeyCode.Backspace===t.keyCode&&!Object(r.inFocus)())return!1}return!0})},e.prototype.cancelCommand=function(){},e.prototype.closeCommand=function(){},e}()}, -/*!******************************!*\ - !*** ./dev/Stores/Social.js ***! - \******************************/ -/*! exports provided: default */ -/*! exports used: default */function(e,t,n){"use strict";var i=n(/*! babel-runtime/helpers/classCallCheck */8),o=n.n(i),a=n(/*! window */3),r=n.n(a),s=n(/*! ko */1),c=n(/*! $ */7),u=n.n(c),l=n(/*! Storage/Settings */5),d=function(){function e(){var t=this;o()(this,e),this.google={},this.twitter={},this.facebook={},this.dropbox={},this.google.enabled=s.a.observable(!1),this.google.clientID=s.a.observable(""),this.google.clientSecret=s.a.observable(""),this.google.apiKey=s.a.observable(""),this.google.loading=s.a.observable(!1),this.google.userName=s.a.observable(""),this.google.loggined=s.a.computed(function(){return""!==t.google.userName()}),this.google.capa={},this.google.capa.auth=s.a.observable(!1),this.google.capa.authFast=s.a.observable(!1),this.google.capa.drive=s.a.observable(!1),this.google.capa.preview=s.a.observable(!1),this.google.require={},this.google.require.clientSettings=s.a.computed(function(){return t.google.enabled()&&(t.google.capa.auth()||t.google.capa.drive())}),this.google.require.apiKeySettings=s.a.computed(function(){return t.google.enabled()&&t.google.capa.drive()}),this.facebook.enabled=s.a.observable(!1),this.facebook.appID=s.a.observable(""),this.facebook.appSecret=s.a.observable(""),this.facebook.loading=s.a.observable(!1),this.facebook.userName=s.a.observable(""),this.facebook.supported=s.a.observable(!1),this.facebook.loggined=s.a.computed(function(){return""!==t.facebook.userName()}),this.twitter.enabled=s.a.observable(!1),this.twitter.consumerKey=s.a.observable(""),this.twitter.consumerSecret=s.a.observable(""),this.twitter.loading=s.a.observable(!1),this.twitter.userName=s.a.observable(""),this.twitter.loggined=s.a.computed(function(){return""!==t.twitter.userName()}),this.dropbox.enabled=s.a.observable(!1),this.dropbox.apiKey=s.a.observable("")}return e.prototype.populate=function(){this.google.enabled(!!l.settingsGet("AllowGoogleSocial")),this.google.clientID(l.settingsGet("GoogleClientID")),this.google.clientSecret(l.settingsGet("GoogleClientSecret")),this.google.apiKey(l.settingsGet("GoogleApiKey")),this.google.capa.auth(!!l.settingsGet("AllowGoogleSocialAuth")),this.google.capa.authFast(!!l.settingsGet("AllowGoogleSocialAuthFast")),this.google.capa.drive(!!l.settingsGet("AllowGoogleSocialDrive")),this.google.capa.preview(!!l.settingsGet("AllowGoogleSocialPreview")),this.facebook.enabled(!!l.settingsGet("AllowFacebookSocial")),this.facebook.appID(l.settingsGet("FacebookAppID")),this.facebook.appSecret(l.settingsGet("FacebookAppSecret")),this.facebook.supported(!!l.settingsGet("SupportedFacebookSocial")),this.twitter.enabled=s.a.observable(!!l.settingsGet("AllowTwitterSocial")),this.twitter.consumerKey=s.a.observable(l.settingsGet("TwitterConsumerKey")),this.twitter.consumerSecret=s.a.observable(l.settingsGet("TwitterConsumerSecret")),this.dropbox.enabled(!!l.settingsGet("AllowDropboxSocial")),this.dropbox.apiKey(l.settingsGet("DropboxApiKey"))},e.prototype.appendDropbox=function(){if(!r.a.Dropbox&&this.dropbox.enabled()&&this.dropbox.apiKey()&&!r.a.document.getElementById("dropboxjs")){var e=r.a.document.createElement("script");e.type="text/javascript",e.src="https://www.dropbox.com/static/api/2/dropins.js",u()(e).attr("id","dropboxjs").attr("data-app-key",this.dropbox.apiKey()),r.a.document.body.appendChild(e)}},e}();t.a=new d}, -/*!***********************************!*\ - !*** ./dev/Component/Abstract.js ***! - \***********************************/ -/*! exports provided: AbstractComponent, componentExportHelper */ -/*! exports used: AbstractComponent, componentExportHelper */, -/*!***********************************!*\ - !*** ./dev/Component/Abstract.js ***! - \***********************************/ -/*! exports provided: AbstractComponent, componentExportHelper */ -/*! exports used: AbstractComponent, componentExportHelper */function(e,t,n){"use strict";n.d(t,"a",function(){return l}),n.d(t,"b",function(){return d});var i=n(/*! babel-runtime/helpers/classCallCheck */8),o=n.n(i),a=n(/*! $ */7),r=n.n(a),s=n(/*! ko */1),c=n(/*! Common/Utils */2),u=n(/*! Common/Translator */10),l=function(){function e(){o()(this,e),this.disposable=[]}return e.prototype.dispose=function(){this.disposable.forEach(function(e){e&&e.dispose&&e.dispose()})},e}(),d=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return{template:t?{element:t}:"",viewModel:{createViewModel:function(t,n){return(t=t||{}).element=null,n&&n.element&&(t.component=n,t.element=r()(n.element),Object(u.i18nToNodes)(t.element),!Object(c.isUnd)(t.inline)&&s.a.unwrap(t.inline)&&t.element.css("display","inline-block")),new e(t)}}}}}, -/*!*******************************!*\ - !*** ./dev/Common/Plugins.js ***! - \*******************************/ -/*! exports provided: addHook, runHook, mainSettingsGet, remoteRequest, addSettingsViewModel, addSettingsViewModelForAdmin, runSettingsViewModelHooks, settingsGet */ -/*! exports used: addHook, addSettingsViewModel, addSettingsViewModelForAdmin, mainSettingsGet, remoteRequest, runHook, runSettingsViewModelHooks, settingsGet */, -/*!*******************************!*\ - !*** ./dev/Common/Plugins.js ***! - \*******************************/ -/*! exports provided: addHook, runHook, mainSettingsGet, remoteRequest, addSettingsViewModel, addSettingsViewModelForAdmin, runSettingsViewModelHooks, settingsGet */ -/*! exports used: addHook, addSettingsViewModel, addSettingsViewModelForAdmin, mainSettingsGet, remoteRequest, runHook, runSettingsViewModelHooks, settingsGet */function(e,t,n){"use strict";n.d(t,"a",function(){return d}),n.d(t,"f",function(){return p}),n.d(t,"d",function(){return f}),n.d(t,"e",function(){return m}),n.d(t,"b",function(){return h}),n.d(t,"c",function(){return g}),n.d(t,"g",function(){return b}),n.d(t,"h",function(){return v});var i=n(/*! _ */4),o=n.n(i),a=n(/*! Common/Utils */2),r=n(/*! Common/Globals */6),s=n(/*! Storage/Settings */5),c={},u=[],l=[];function d(e,t){Object(a.isFunc)(t)&&(Object(a.isArray)(c[e])||(c[e]=[]),c[e].push(t))}function p(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];Object(a.isArray)(c[e])&&o.a.each(c[e],function(e){e.apply(void 0,t)})}function f(e){return s.settingsGet(e)}function m(e,t,n,i){r.data.__APP__&&r.data.__APP__.remote().defaultRequest(e,"Plugin"+t,n,i)}function h(e,t,n,i){u.push([e,t,n,i])}function g(e,t,n,i){l.push([e,t,n,i])}function b(e){var t=n(/*! Knoin/Knoin */9);o.a.each(e?l:u,function(e){t.addSettingsViewModel(e[0],e[1],e[2],e[3])})}function v(e,t){var n=s.settingsGet("Plugins");return(n=n&&!Object(a.isUnd)(n[e])?n[e]:null)?Object(a.isUnd)(n[t])?null:n[t]:null}},, -/*!********************************!*\ - !*** ./dev/Stores/Language.js ***! - \********************************/ -/*! exports provided: default */ -/*! exports used: default */, -/*!********************************!*\ - !*** ./dev/Stores/Language.js ***! - \********************************/ -/*! exports provided: default */ -/*! exports used: default */function(e,t,n){"use strict";var i=n(/*! babel-runtime/helpers/classCallCheck */8),o=n.n(i),a=n(/*! ko */1),r=n(/*! Common/Utils */2),s=n(/*! Storage/Settings */5),c=function(){function e(){o()(this,e),this.languages=a.a.observableArray([]),this.languagesAdmin=a.a.observableArray([]),this.language=a.a.observable("").extend({limitedList:this.languages}).extend({reversible:!0}),this.languageAdmin=a.a.observable("").extend({limitedList:this.languagesAdmin}).extend({reversible:!0}),this.userLanguage=a.a.observable(""),this.userLanguageAdmin=a.a.observable("")}return e.prototype.populate=function(){var e=s.appSettingsGet("languages"),t=s.appSettingsGet("languagesAdmin");this.languages(Object(r.isArray)(e)?e:[]),this.languagesAdmin(Object(r.isArray)(t)?t:[]),this.language(s.settingsGet("Language")),this.languageAdmin(s.settingsGet("LanguageAdmin")),this.userLanguage(s.settingsGet("UserLanguage")),this.userLanguageAdmin(s.settingsGet("UserLanguageAdmin"))},e}();t.a=new c}, -/*!********************************!*\ - !*** ./dev/Common/Momentor.js ***! - \********************************/ -/*! exports provided: momentNow, momentNowUnix, searchSubtractFormatDateHelper, format, momentToNode, reload */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is referenced from these modules with unsupported syntax: ./dev/External/ko.js (referenced with cjs require) */, -/*!********************************!*\ - !*** ./dev/Common/Momentor.js ***! - \********************************/ -/*! exports provided: momentNow, momentNowUnix, searchSubtractFormatDateHelper, format, momentToNode, reload */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is referenced from these modules with unsupported syntax: ./dev/External/ko.js (referenced with cjs require) */function(e,t,n){"use strict";n.r(t),n.d(t,"momentNow",function(){return g}),n.d(t,"momentNowUnix",function(){return b}),n.d(t,"searchSubtractFormatDateHelper",function(){return v}),n.d(t,"format",function(){return S}),n.d(t,"momentToNode",function(){return y}),n.d(t,"reload",function(){return w});var i=n(/*! window */3),o=n.n(i),a=n(/*! _ */4),r=n.n(a),s=n(/*! $ */7),c=n.n(s),u=n(/*! moment */54),l=n.n(u),d=n(/*! Common/Translator */10),p=null,f=0,m=r.a.debounce(function(){p=l()()},500,!0),h=r.a.debounce(function(){f=l()().unix()},500,!0);function g(){return m(),p||l()()}function b(){return h(),f||0}function v(e){return g().clone().subtract(e,"days").format("YYYY.MM.DD")}function S(e,t){var n=null,i="",o=b();if((n=0<(e=o<(e=0=t.diff(e,"hours"):return e.fromNow();case t.format("L")===e.format("L"):return Object(d.i18n)("MESSAGE_LIST/TODAY_AT",{TIME:e.format("LT")});case t.clone().subtract(1,"days").format("L")===e.format("L"):return Object(d.i18n)("MESSAGE_LIST/YESTERDAY_AT",{TIME:e.format("LT")});case t.year()===e.year():return e.format("D MMM.")}return e?e.format("LL"):""}(n);break;case"FULL":i=n.format("LLL");break;default:i=n.format(t)}return i}function y(e){var t,n="",i=c()(e);(t=i.data("moment-time"))&&((n=i.data("moment-format"))&&i.text(S(t,n)),(n=i.data("moment-format-title"))&&i.attr("title",S(t,n)))}function w(){r.a.defer(function(){c()(".moment",o.a.document).each(function(e,t){y(t)})})}}, -/*!********************************!*\ - !*** external "window.hasher" ***! - \********************************/ -/*! no static exports found */ -/*! exports used: default */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){e.exports=window.hasher}, -/*!**********************************!*\ - !*** ./dev/Helper/Apps/Admin.js ***! - \**********************************/ -/*! exports provided: getApp */ -/*! exports used: getApp */, -/*!**********************************!*\ - !*** ./dev/Helper/Apps/Admin.js ***! - \**********************************/ -/*! exports provided: getApp */ -/*! exports used: getApp */function(e,t,n){"use strict";function i(){return n(/*! App/Admin */173).default}n.d(t,"a",function(){return i})}, -/*!*******************************************************!*\ - !*** ./node_modules/core-js/library/modules/_core.js ***! - \*******************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){var n=e.exports={version:"2.5.7"};"number"==typeof __e&&(__e=n)}, -/*!*********************************!*\ - !*** ./dev/Stores/Admin/App.js ***! - \*********************************/ -/*! exports provided: default */ -/*! exports used: default */function(e,t,n){"use strict";var i=n(/*! babel-runtime/helpers/classCallCheck */8),o=n.n(i),a=n(/*! babel-runtime/helpers/possibleConstructorReturn */11),r=n.n(a),s=n(/*! babel-runtime/helpers/inherits */12),c=n.n(s),u=n(/*! window */3),l=n.n(u),d=n(/*! $ */7),p=n.n(d),f=n(/*! ko */1),m=n(/*! Storage/Settings */5),h=function(e){function t(){o()(this,t);var n=r()(this,e.call(this));return n.determineUserLanguage=f.a.observable(!1),n.determineUserDomain=f.a.observable(!1),n.weakPassword=f.a.observable(!1),n.useLocalProxyForExternalImages=f.a.observable(!1),n.dataFolderAccess=f.a.observable(!1),n}return c()(t,e),t.prototype.populate=function(){var t=this;e.prototype.populate.call(this),this.determineUserLanguage(!!Object(m.settingsGet)("DetermineUserLanguage")),this.determineUserDomain(!!Object(m.settingsGet)("DetermineUserDomain")),this.weakPassword(!!Object(m.settingsGet)("WeakPassword")),this.useLocalProxyForExternalImages(!!Object(m.settingsGet)("UseLocalProxyForExternalImages")),Object(m.settingsGet)("Auth")&&p.a.get("./data/VERSION?"+l.a.Math.random()).then(function(){return t.dataFolderAccess(!0)})},t}(n(/*! Stores/AbstractApp */114).a);t.a=new h}, -/*!*****************************!*\ - !*** ./dev/Stores/Theme.js ***! - \*****************************/ -/*! exports provided: default */ -/*! exports used: default */function(e,t,n){"use strict";var i=n(/*! babel-runtime/helpers/classCallCheck */8),o=n.n(i),a=n(/*! ko */1),r=n(/*! Common/Utils */2),s=n(/*! Storage/Settings */5),c=function(){function e(){o()(this,e),this.themes=a.a.observableArray([]),this.themeBackgroundName=a.a.observable(""),this.themeBackgroundHash=a.a.observable(""),this.theme=a.a.observable("").extend({limitedList:this.themes})}return e.prototype.populate=function(){var e=s.appSettingsGet("themes");this.themes(Object(r.isArray)(e)?e:[]),this.theme(s.settingsGet("Theme")),this.themeBackgroundName(s.settingsGet("UserBackgroundName")),this.themeBackgroundHash(s.settingsGet("UserBackgroundHash"))},e}();t.a=new c}, -/*!*********************************************************!*\ - !*** ./node_modules/core-js/library/modules/_global.js ***! - \*********************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)}, -/*!**************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_descriptors.js ***! - \**************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t,n){e.exports=!n(/*! ./_fails */53)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})}, -/*!******************************************************!*\ - !*** ./node_modules/core-js/library/modules/_has.js ***! - \******************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){var n={}.hasOwnProperty;e.exports=function(e,t){return n.call(e,t)}}, -/*!*************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_to-iobject.js ***! - \*************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t,n){var i=n(/*! ./_iobject */104),o=n(/*! ./_defined */70);e.exports=function(e){return i(o(e))}}, -/*!****************************!*\ - !*** ./dev/Model/Email.js ***! - \****************************/ -/*! exports provided: EmailModel, default */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is referenced from these modules with unsupported syntax: ./dev/Common/Utils.js (referenced with cjs require), ./dev/External/ko.js (referenced with cjs require) */function(e,t,n){"use strict";n.r(t),n.d(t,"EmailModel",function(){return l}),n.d(t,"default",function(){return l});var i=n(/*! babel-runtime/helpers/classCallCheck */8),o=n.n(i),a=n(/*! _ */4),r=n.n(a),s=n(/*! emailjs-addressparser */77),c=n.n(s),u=n(/*! Common/Utils */2),l=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"none",a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";o()(this,e),this.email="",this.name="",this.dkimStatus="",this.dkimValue="",this.email=t,this.name=n,this.dkimStatus=i,this.dkimValue=a,this.clearDuplicateName()}return e.newInstanceFromJson=function(t){var n=new e;return n.initByJson(t)?n:null},e.prototype.clear=function(){this.email="",this.name="",this.dkimStatus="none",this.dkimValue=""},e.prototype.validate=function(){return""!==this.name||""!==this.email},e.prototype.hash=function(){return"#"+(arguments.length>0&&void 0!==arguments[0]&&arguments[0]?"":this.name)+"#"+this.email+"#"},e.prototype.clearDuplicateName=function(){this.name===this.email&&(this.name="")},e.prototype.search=function(e){return-1<(this.name+" "+this.email).toLowerCase().indexOf(e.toLowerCase())},e.prototype.initByJson=function(e){var t=!1;return e&&"Object/Email"===e["@Object"]&&(this.name=Object(u.trim)(e.Name),this.email=Object(u.trim)(e.Email),this.dkimStatus=Object(u.trim)(e.DkimStatus||""),this.dkimValue=Object(u.trim)(e.DkimValue||""),t=""!==this.email,this.clearDuplicateName()),t},e.prototype.toLine=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i="";return""!==this.email&&(e&&""!==this.name?i=t?'
")+'" target="_blank" tabindex="-1">'+Object(u.encodeHtml)(this.name)+"":n?Object(u.encodeHtml)(this.name):this.name:(i=this.email,""!==this.name?t?i=Object(u.encodeHtml)('"'+this.name+'" <')+'")+'" target="_blank" tabindex="-1">'+Object(u.encodeHtml)(i)+""+Object(u.encodeHtml)(">"):(i='"'+this.name+'" <'+i+">",n&&(i=Object(u.encodeHtml)(i))):t&&(i=''+Object(u.encodeHtml)(this.email)+""))),i},e.splitEmailLine=function(t){var n=c()(t);if(Object(u.isNonEmptyArray)(n)){var i=[],o=!1;return n.forEach(function(t){var n=t.address?new e(t.address.replace(/^[<]+(.*)[>]+$/g,"$1"),t.name||""):null;n&&n.email&&(o=!0),i.push(n?n.toLine(!1):t.name)}),o?i:null}return null},e.parseEmailLine=function(t){var n=c()(t);return Object(u.isNonEmptyArray)(n)?r.a.compact(n.map(function(t){return t.address?new e(t.address.replace(/^[<]+(.*)[>]+$/g,"$1"),t.name||""):null})):[]},e.prototype.parse=function(e){if(""===(e=Object(u.trim)(e)))return!1;var t=c()(e);return!(!Object(u.isNonEmptyArray)(t)||!t[0])&&(this.name=t[0].name||"",this.email=t[0].address||"",this.clearDuplicateName(),!0)},e}()}, -/*!************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_is-object.js ***! - \************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */, -/*!************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_is-object.js ***! - \************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}}, -/*!****************************************!*\ - !*** ./dev/Component/AbstractInput.js ***! - \****************************************/ -/*! exports provided: AbstractInput, default */ -/*! exports used: AbstractInput */function(e,t,n){"use strict";n.d(t,"a",function(){return p});var i=n(/*! babel-runtime/helpers/classCallCheck */8),o=n.n(i),a=n(/*! babel-runtime/helpers/possibleConstructorReturn */11),r=n.n(a),s=n(/*! babel-runtime/helpers/inherits */12),c=n.n(s),u=n(/*! ko */1),l=n(/*! Common/Utils */2),d=n(/*! Common/Enums */0),p=function(e){function t(n){o()(this,t);var i=r()(this,e.call(this));return i.value=n.value||"",i.size=n.size||0,i.label=n.label||"",i.preLabel=n.preLabel||"",i.enable=!!Object(l.isUnd)(n.enable)||n.enable,i.trigger=n.trigger&&n.trigger.subscribe?n.trigger:null,i.placeholder=n.placeholder||"",i.labeled=!Object(l.isUnd)(n.label),i.preLabeled=!Object(l.isUnd)(n.preLabel),i.triggered=!Object(l.isUnd)(n.trigger)&&!!i.trigger,i.classForTrigger=u.a.observable(""),i.className=u.a.computed(function(){var e=u.a.unwrap(i.size),t=i.trigger?" "+Object(l.trim)("settings-saved-trigger-input "+i.classForTrigger()):"";return(01&&void 0!==arguments[1]&&arguments[1];if(!o.a.Promise||!o.a.Promise.all)throw new Error("Promises are not available your environment.");if(!e)throw new Error("src should not be empty.");return new o.a.Promise(function(n,i){var a=o.a.document.createElement("script");a.onload=function(){n(e)},a.onerror=function(){i(new Error(e))},a.async=!0===t,a.src=e,o.a.document.body.appendChild(a)})}}, -/*!************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_an-object.js ***! - \************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t,n){var i=n(/*! ./_is-object */47);e.exports=function(e){if(!i(e))throw TypeError(e+" is not an object!");return e}}, -/*!******************************************************!*\ - !*** ./node_modules/core-js/library/modules/_wks.js ***! - \******************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t,n){var i=n(/*! ./_shared */89)("wks"),o=n(/*! ./_uid */74),a=n(/*! ./_global */41).Symbol,r="function"==typeof a;(e.exports=function(e){return i[e]||(i[e]=r&&a[e]||(r?a:o)("Symbol."+e))}).store=i}, -/*!****************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_property-desc.js ***! - \****************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */, -/*!****************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_property-desc.js ***! - \****************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}}, -/*!*************************************!*\ - !*** ./dev/Knoin/AbstractScreen.js ***! - \*************************************/ -/*! exports provided: AbstractScreen */ -/*! exports used: AbstractScreen */, -/*!*************************************!*\ - !*** ./dev/Knoin/AbstractScreen.js ***! - \*************************************/ -/*! exports provided: AbstractScreen */ -/*! exports used: AbstractScreen */function(e,t,n){"use strict";n.d(t,"a",function(){return l});var i=n(/*! babel-runtime/helpers/classCallCheck */8),o=n.n(i),a=n(/*! _ */4),r=n.n(a),s=n(/*! crossroads */75),c=n.n(s),u=n(/*! Common/Utils */2),l=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];o()(this,e),this.oCross=null,this.sScreenName=t,this.aViewModels=Object(u.isArray)(n)?n:[]}return e.prototype.viewModels=function(){return this.aViewModels},e.prototype.screenName=function(){return this.sScreenName},e.prototype.routes=function(){return null},e.prototype.__cross=function(){return this.oCross},e.prototype.__start=function(){var e=null,t=null,n=this.routes();Object(u.isNonEmptyArray)(n)&&(t=r.a.bind(this.onRoute||u.noop,this),e=c.a.create(),n.forEach(function(n){n&&e&&(e.addRoute(n[0],t).rules=n[1])}),this.oCross=e)},e}()}, -/*!*****************************!*\ - !*** external "window.ssm" ***! - \*****************************/ -/*! no static exports found */ -/*! exports used: default */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){e.exports=window.ssm}, -/*!***************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_to-primitive.js ***! - \***************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t,n){var i=n(/*! ./_is-object */47);e.exports=function(e,t){if(!i(e))return e;var n,o;if(t&&"function"==typeof(n=e.toString)&&!i(o=n.call(e)))return o;if("function"==typeof(n=e.valueOf)&&!i(o=n.call(e)))return o;if(!t&&"function"==typeof(n=e.toString)&&!i(o=n.call(e)))return o;throw TypeError("Can't convert object to primitive value")}}, -/*!************************************!*\ - !*** ./dev/Stores/Admin/Domain.js ***! - \************************************/ -/*! exports provided: default */ -/*! exports used: default */, -/*!************************************!*\ - !*** ./dev/Stores/Admin/Domain.js ***! - \************************************/ -/*! exports provided: default */ -/*! exports used: default */function(e,t,n){"use strict";var i=n(/*! babel-runtime/helpers/classCallCheck */8),o=n.n(i),a=n(/*! ko */1);t.a=new function e(){o()(this,e),this.domains=a.a.observableArray([]),this.domains.loading=a.a.observable(!1).extend({throttle:100}),this.domainsWithoutAliases=this.domains.filter(function(e){return e&&!e.alias})}}, -/*!**********************************************************!*\ - !*** ./node_modules/core-js/library/modules/_defined.js ***! - \**********************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}}, -/*!**************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_object-gopd.js ***! - \**************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t,n){var i=n(/*! ./_object-pie */72),o=n(/*! ./_property-desc */63),a=n(/*! ./_to-iobject */44),r=n(/*! ./_to-primitive */67),s=n(/*! ./_has */43),c=n(/*! ./_ie8-dom-define */78),u=Object.getOwnPropertyDescriptor;t.f=n(/*! ./_descriptors */42)?u:function(e,t){if(e=a(e),t=r(t,!0),c)try{return u(e,t)}catch(e){}if(s(e,t))return o(!i.f.call(e,t),e[t])}}, -/*!*************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_object-pie.js ***! - \*************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){t.f={}.propertyIsEnumerable}, -/*!**********************************************************!*\ - !*** ./node_modules/core-js/library/modules/_library.js ***! - \**********************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){e.exports=!0}, -/*!******************************************************!*\ - !*** ./node_modules/core-js/library/modules/_uid.js ***! - \******************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){var n=0,i=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+i).toString(36))}}, -/*!************************************!*\ - !*** external "window.crossroads" ***! - \************************************/ -/*! no static exports found */ -/*! exports used: default */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){e.exports=window.crossroads}, -/*!******************************************!*\ - !*** ./dev/Component/AbstracCheckbox.js ***! - \******************************************/ -/*! exports provided: AbstracCheckbox, default */ -/*! exports used: AbstracCheckbox */function(e,t,n){"use strict";n.d(t,"a",function(){return d});var i=n(/*! babel-runtime/helpers/classCallCheck */8),o=n.n(i),a=n(/*! babel-runtime/helpers/possibleConstructorReturn */11),r=n.n(a),s=n(/*! babel-runtime/helpers/inherits */12),c=n.n(s),u=n(/*! ko */1),l=n(/*! Common/Utils */2),d=function(e){function t(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};o()(this,t);var i=r()(this,e.call(this));return i.value=n.value,!Object(l.isUnd)(i.value)&&i.value.subscribe||(i.value=u.a.observable(!Object(l.isUnd)(i.value)&&!!i.value)),i.enable=n.enable,!Object(l.isUnd)(i.enable)&&i.enable.subscribe||(i.enable=u.a.observable(!!Object(l.isUnd)(i.enable)||!!i.enable)),i.disable=n.disable,!Object(l.isUnd)(i.disable)&&i.disable.subscribe||(i.disable=u.a.observable(!Object(l.isUnd)(i.disable)&&!!i.disable)),i.label=n.label||"",i.inline=!Object(l.isUnd)(n.inline)&&n.inline,i.readOnly=!Object(l.isUnd)(n.readOnly)&&!!n.readOnly,i.inverted=!Object(l.isUnd)(n.inverted)&&!!n.inverted,i.labeled=!Object(l.isUnd)(n.label),i.labelAnimated=!!n.labelAnimated,i}return c()(t,e),t.prototype.click=function(){this.readOnly||!this.enable()||this.disable()||this.value(!this.value())},t}(n(/*! Component/Abstract */27).a)}, -/*!******************************************************************!*\ - !*** ./node_modules/emailjs-addressparser/dist/addressparser.js ***! - \******************************************************************/ -/*! no static exports found */ -/*! exports used: default */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n=0;l--)if(r.text[l].match(/^[^@\s]+@[^@\s]+$/)){r.address=r.text.splice(l,1);break}var d=function(e){return r.address.length?e:(r.address=[e.trim()]," ")};if(!r.address.length)for(var p=r.text.length-1;p>=0&&(r.text[p]=r.text[p].replace(/\s*\b[^@\s]+@[^@\s]+\b\s*/,d).trim(),!r.address.length);p--);}if(!r.text.length&&r.comment.length&&(r.text=r.comment,r.comment=[]),r.address.length>1&&(r.text=r.text.concat(r.address.splice(1))),r.text=r.text.join(" "),r.address=r.address.join(" "),!r.address&&t)return[];(i={address:r.address||r.text||"",name:r.text||r.address||""}).address===i.name&&((i.address||"").match(/@/)?i.name="":i.address=""),a.push(i)}return a}(e)).length&&(i=i.concat(e))}),i}t.default=o;var a={'"':'"',"(":")","<":">",",":"",":":";",";":""},r=function(){function e(t){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.str=(t||"").toString(),this.operatorCurrent="",this.operatorExpecting="",this.node=null,this.escaped=!1,this.list=[]}return i(e,[{key:"tokenize",value:function(){for(var e=void 0,t=[],n=0,i=this.str.length;n0?i:n)(e)}}, -/*!************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_iterators.js ***! - \************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t){e.exports={}}, -/*!****************************************************************!*\ - !*** ./node_modules/core-js/library/modules/_object-create.js ***! - \****************************************************************/ -/*! no static exports found */ -/*! all exports used */ -/*! ModuleConcatenation bailout: Module is not an ECMAScript module */function(e,t,n){var i=n(/*! ./_an-object */60),o=n(/*! ./_object-dps */128),a=n(/*! ./_enum-bug-keys */90),r=n(/*! ./_shared-key */88)("IE_PROTO"),s=function(){},c=function(){var e,t=n(/*! ./_dom-create */82)("iframe"),i=a.length;for(t.style.display="none",n(/*! ./_html */132).appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write("', '<\/script>', - \str_replace($aJsonReplaces[0], $aJsonReplaces[1], $sText)); - } - - /** - * @param array $aInput - */ - public static function ClearArrayUtf8Values(&$aInput) - { - if (\is_array($aInput)) - { - foreach ($aInput as $mKey => $mItem) - { - if (\is_string($mItem)) - { - $aInput[$mKey] = \MailSo\Base\Utils::Utf8Clear($mItem); - } - else if (\is_array($mItem)) - { - \MailSo\Base\Utils::ClearArrayUtf8Values($mItem); - $aInput[$mKey] = $mItem; - } - } - } - } - - /** - * @param mixed $mInput - * @param \MailSo\Log\Logger|null $oLogger = null - * - * @return string - */ - public static function Php2js($mInput, $oLogger = null) - { - static $iOpt = null; - if (null === $iOpt) - { - $iOpt = \defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 0; - } - - $sResult = @\json_encode($mInput, $iOpt); - if (!\is_string($sResult) || '' === $sResult) - { - if (!$oLogger && \MailSo\Log\Logger::IsSystemEnabled()) - { - $oLogger = \MailSo\Config::$SystemLogger; - } - - if (!($oLogger instanceof \MailSo\Log\Logger)) - { - $oLogger = null; - } - - if ($oLogger) - { - $oLogger->Write('json_encode: '.\trim( - (\MailSo\Base\Utils::FunctionExistsAndEnabled('json_last_error') ? ' [Error Code: '.\json_last_error().']' : ''). - (\MailSo\Base\Utils::FunctionExistsAndEnabled('json_last_error_msg') ? ' [Error Message: '.\json_last_error_msg().']' : '') - ), \MailSo\Log\Enumerations\Type::WARNING, 'JSON' - ); - } - - if (\is_array($mInput)) - { - if ($oLogger) - { - $oLogger->WriteDump($mInput, \MailSo\Log\Enumerations\Type::INFO, 'JSON'); - $oLogger->Write('Trying to clear Utf8 before json_encode', \MailSo\Log\Enumerations\Type::INFO, 'JSON'); - } - - \MailSo\Base\Utils::ClearArrayUtf8Values($mInput); - $sResult = @\json_encode($mInput, $iOpt); - } - } - - return $sResult; - } - - /** - * @param string $sFileName - * - * @return string - */ - public static function ClearFileName($sFileName) - { - return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite( - \MailSo\Base\Utils::StripSpaces( - \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sFileName)))); - } - - /** - * @param string $sValue - * - * @return string - */ - public static function ClearXss($sValue) - { - return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite( - \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sValue))); - } - - /** - * @param string $sValue - * - * @return string - */ - public static function Trim($sValue) - { - return \trim(\preg_replace('/^[\x00-\x1F]+/u', '', - \preg_replace('/[\x00-\x1F]+$/u', '', \trim($sValue)))); - } - - /** - * @param string $sDir - * - * @return bool - */ - public static function RecRmDir($sDir) - { - if (@\is_dir($sDir)) - { - $aObjects = \scandir($sDir); - foreach ($aObjects as $sObject) - { - if ('.' !== $sObject && '..' !== $sObject) - { -// if ('dir' === \filetype($sDir.'/'.$sObject)) - if (\is_dir($sDir.'/'.$sObject)) - { - self::RecRmDir($sDir.'/'.$sObject); - } - else - { - @\unlink($sDir.'/'.$sObject); - } - } - } - - return @\rmdir($sDir); - } - - return false; - } - - /** - * @param string $sSource - * @param string $sDestination - */ - public static function CopyDir($sSource, $sDestination) - { - if (\is_dir($sSource)) - { - if (!\is_dir($sDestination)) - { - \mkdir($sDestination); - } - - $oDirectory = \dir($sSource); - if ($oDirectory) - { - while (false !== ($sRead = $oDirectory->read())) - { - if ('.' === $sRead || '..' === $sRead) - { - continue; - } - - $sPathDir = $sSource.'/'.$sRead; - if (\is_dir($sPathDir)) - { - \MailSo\Base\Utils::CopyDir($sPathDir, $sDestination.'/'.$sRead); - continue; - } - - \copy($sPathDir, $sDestination.'/'.$sRead); - } - - $oDirectory->close(); - } - } - } - - /** - * @param string $sTempPath - * @param int $iTime2Kill - * @param int $iNow - * - * @return bool - */ - public static function RecTimeDirRemove($sTempPath, $iTime2Kill, $iNow) - { - $iFileCount = 0; - - $sTempPath = rtrim($sTempPath, '\\/'); - if (@\is_dir($sTempPath)) - { - $rDirH = @\opendir($sTempPath); - if ($rDirH) - { - $bRemoveAllDirs = true; - while (($sFile = @\readdir($rDirH)) !== false) - { - if ('.' !== $sFile && '..' !== $sFile) - { - if (@\is_dir($sTempPath.'/'.$sFile)) - { - if (!\MailSo\Base\Utils::RecTimeDirRemove($sTempPath.'/'.$sFile, $iTime2Kill, $iNow)) - { - $bRemoveAllDirs = false; - } - } - else - { - $iFileCount++; - } - } - } - - @\closedir($rDirH); - } - - if ($iFileCount > 0) - { - if (\MailSo\Base\Utils::TimeFilesRemove($sTempPath, $iTime2Kill, $iNow)) - { - return @\rmdir($sTempPath); - } - } - else - { - return $bRemoveAllDirs ? @\rmdir($sTempPath) : false; - } - - return false; - } - - return true; - } - - /** - * @param string $sTempPath - * @param int $iTime2Kill - * @param int $iNow - */ - public static function TimeFilesRemove($sTempPath, $iTime2Kill, $iNow) - { - $bResult = true; - - $sTempPath = rtrim($sTempPath, '\\/'); - if (@\is_dir($sTempPath)) - { - $rDirH = @\opendir($sTempPath); - if ($rDirH) - { - while (($sFile = @\readdir($rDirH)) !== false) - { - if ($sFile !== '.' && $sFile !== '..') - { - if ($iNow - \filemtime($sTempPath.'/'.$sFile) > $iTime2Kill) - { - @\unlink($sTempPath.'/'.$sFile); - } - else - { - $bResult = false; - } - } - } - - @\closedir($rDirH); - } - } - - return $bResult; - } - - /** - * @param string $sUtfString - * @param int $iLength - * - * @return string - */ - public static function Utf8Truncate($sUtfString, $iLength) - { - if (\strlen($sUtfString) <= $iLength) - { - return $sUtfString; - } - - while ($iLength >= 0) - { - if ((\ord($sUtfString[$iLength]) < 0x80) || (\ord($sUtfString[$iLength]) >= 0xC0)) - { - return \substr($sUtfString, 0, $iLength); - } - - $iLength--; - } - - return ''; - } - - /** - * @param string $sUtfString - * @param string $sReplaceOn = '' - * - * @return string - */ - public static function Utf8Clear($sUtfString, $sReplaceOn = '') - { - if ('' === $sUtfString) - { - return $sUtfString; - } - - $sUtfString = \preg_replace(\MailSo\Base\Utils::$sValidUtf8Regexp, '$1', $sUtfString); - - $sUtfString = \preg_replace( - '/\xE0[\x80-\x9F][\x80-\xBF]'. - '|\xEF\xBF\xBF'. - '|\xED[\xA0-\xBF][\x80-\xBF]/S', $sReplaceOn, $sUtfString); - - $sUtfString = \preg_replace('/\xEF\xBF\xBD/', '?', $sUtfString); - - $sNewUtfString = false; - if (false === $sNewUtfString && \MailSo\Base\Utils::IsMbStringSupported()) - { - $sNewUtfString = \MailSo\Base\Utils::MbConvertEncoding($sUtfString, 'UTF-8', 'UTF-8'); - } - - if (false === $sNewUtfString && \MailSo\Base\Utils::IsIconvSupported()) - { - $sNewUtfString = \MailSo\Base\Utils::IconvConvertEncoding($sUtfString, 'UTF-8', 'UTF-8'); - } - - if (false !== $sNewUtfString) - { - $sUtfString = $sNewUtfString; - } - - return $sUtfString; - } - - /** - * @param string $sUtfString - * - * @return bool - */ - public static function IsRTL($sUtfString) - { - // \x{0591}-\x{05F4} - Hebrew - // \x{0600}-\x{068F} - Arabic - // \x{0750}-\x{077F} - Arabic - // \x{08A0}-\x{08FF} - Arabic - // \x{103A0}-\x{103DF} - Old Persian - return 0 < (int) preg_match('/[\x{0591}-\x{05F4}\x{0600}-\x{068F}\x{0750}-\x{077F}\x{08A0}-\x{08FF}\x{103A0}-\x{103DF}]/u', $sUtfString); - } - - /** - * @param string $sString - * - * @return string - */ - public static function Base64Decode($sString) - { - $sResultString = \base64_decode($sString, true); - if (false === $sResultString) - { - $sString = \str_replace(array(' ', "\r", "\n", "\t"), '', $sString); - $sString = \preg_replace('/[^a-zA-Z0-9=+\/](.*)$/', '', $sString); - - if (false !== \strpos(\trim(\trim($sString), '='), '=')) - { - $sString = \preg_replace('/=([^=])/', '= $1', $sString); - $aStrings = \explode(' ', $sString); - foreach ($aStrings as $iIndex => $sParts) - { - $aStrings[$iIndex] = \base64_decode($sParts); - } - - $sResultString = \implode('', $aStrings); - } - else - { - $sResultString = \base64_decode($sString); - } - } - - return $sResultString; - } - - /** - * @param string $sValue - * - * @return string - */ - public static function UrlSafeBase64Encode($sValue) - { - return \rtrim(\strtr(\base64_encode($sValue), '+/', '-_'), '='); - } - - /** - * @param string $sValue - * - * @return string - */ - public static function UrlSafeBase64Decode($sValue) - { - $sValue = \rtrim(\strtr($sValue, '-_.', '+/='), '='); - return \MailSo\Base\Utils::Base64Decode(\str_pad($sValue, \strlen($sValue) + (\strlen($sValue) % 4), '=', STR_PAD_RIGHT)); - } - - /** - * @param string $sSequence - * - * @return array - */ - public static function ParseFetchSequence($sSequence) - { - $aResult = array(); - $sSequence = \trim($sSequence); - if (0 < \strlen($sSequence)) - { - $aSequence = \explode(',', $sSequence); - foreach ($aSequence as $sItem) - { - if (false === \strpos($sItem, ':')) - { - $aResult[] = (int) $sItem; - } - else - { - $aItems = \explode(':', $sItem); - $iMax = \max($aItems[0], $aItems[1]); - - for ($iIndex = $aItems[0]; $iIndex <= $iMax; $iIndex++) - { - $aResult[] = (int) $iIndex; - } - } - } - } - - return $aResult; - } - /** - * @param array $aSequence - * - * @return string - */ - public static function PrepearFetchSequence($aSequence) - { - $aResult = array(); - if (\is_array($aSequence) && 0 < \count($aSequence)) - { - $iStart = null; - $iPrev = null; - - foreach ($aSequence as $sItem) - { - // simple protection - if (false !== \strpos($sItem, ':')) - { - $aResult[] = $sItem; - continue; - } - - $iItem = (int) $sItem; - if (null === $iStart || null === $iPrev) - { - $iStart = $iItem; - $iPrev = $iItem; - continue; - } - - if ($iPrev === $iItem - 1) - { - $iPrev = $iItem; - } - else - { - $aResult[] = $iStart === $iPrev ? $iStart : $iStart.':'.$iPrev; - $iStart = $iItem; - $iPrev = $iItem; - } - } - - if (null !== $iStart && null !== $iPrev) - { - $aResult[] = $iStart === $iPrev ? $iStart : $iStart.':'.$iPrev; - } - } - - return \implode(',', $aResult); - } - - /** - * - * @param resource $fResource - * @param int $iBufferLen = 8192 - * - * @return bool - */ - public static function FpassthruWithTimeLimitReset($fResource, $iBufferLen = 8192) - { - $bResult = false; - if (\is_resource($fResource)) - { - while (!\feof($fResource)) - { - $sBuffer = @\fread($fResource, $iBufferLen); - if (false !== $sBuffer) - { - echo $sBuffer; - \MailSo\Base\Utils::ResetTimeLimit(); - continue; - } - - break; - } - - $bResult = true; - } - - return $bResult; - } - - /** - * @param resource $rRead - * @param array $aWrite - * @param int $iBufferLen = 8192 - * @param bool $bResetTimeLimit = true - * @param bool $bFixCrLf = false - * @param bool $bRewindOnComplete = false - * - * @return int|bool - */ - public static function MultipleStreamWriter($rRead, $aWrite, $iBufferLen = 8192, $bResetTimeLimit = true, $bFixCrLf = false, $bRewindOnComplete = false) - { - $mResult = false; - if ($rRead && \is_array($aWrite) && 0 < \count($aWrite)) - { - $mResult = 0; - while (!\feof($rRead)) - { - $sBuffer = \fread($rRead, $iBufferLen); - if (false === $sBuffer) - { - $mResult = false; - break; - } - - if (0 === $iBufferLen || '' === $sBuffer) - { - break; - } - - if ($bFixCrLf) - { - $sBuffer = \str_replace("\n", "\r\n", \str_replace("\r", '', $sBuffer)); - } - - $mResult += \strlen($sBuffer); - - foreach ($aWrite as $rWriteStream) - { - $mWriteResult = \fwrite($rWriteStream, $sBuffer); - if (false === $mWriteResult) - { - $mResult = false; - break 2; - } - } - - if ($bResetTimeLimit) - { - \MailSo\Base\Utils::ResetTimeLimit(); - } - } - } - - if ($mResult && $bRewindOnComplete) - { - foreach ($aWrite as $rWriteStream) - { - if (\is_resource($rWriteStream)) - { - @\rewind($rWriteStream); - } - } - } - - return $mResult; - } - - /** - * @param string $sUtfModifiedString - * - * @return string - */ - public static function ModifiedToPlainUtf7($sUtfModifiedString) - { - $sUtf = ''; - $bBase = false; - - for ($iIndex = 0, $iLen = \strlen($sUtfModifiedString); $iIndex < $iLen; $iIndex++) - { - if ('&' === $sUtfModifiedString[$iIndex]) - { - if (isset($sUtfModifiedString[$iIndex+1]) && '-' === $sUtfModifiedString[$iIndex + 1]) - { - $sUtf .= '&'; - $iIndex++; - } - else - { - $sUtf .= '+'; - $bBase = true; - } - } - else if ($sUtfModifiedString[$iIndex] == '-' && $bBase) - { - $bBase = false; - } - else - { - if ($bBase && ',' === $sUtfModifiedString[$iIndex]) - { - $sUtf .= '/'; - } - else if (!$bBase && '+' === $sUtfModifiedString[$iIndex]) - { - $sUtf .= '+-'; - } - else - { - $sUtf .= $sUtfModifiedString[$iIndex]; - } - } - } - - return $sUtf; - } - - /** - * @param string $sStr - * - * @return string|bool - */ - public static function Utf7ModifiedToUtf8($sStr) - { - $aArray = 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); - - $sResult = ''; - $bError = false; - $iLen = \strlen($sStr); - - for ($iIndex = 0; $iLen > 0; $iIndex++, $iLen--) - { - $sChar = $sStr{$iIndex}; - if ($sChar == '&') - { - $iIndex++; - $iLen--; - - $sChar = isset($sStr{$iIndex}) ? $sStr{$iIndex} : null; - if ($sChar === null) - { - break; - } - - if ($iLen && $sChar == '-') - { - $sResult .= '&'; - continue; - } - - $iCh = 0; - $iK = 10; - for (; $iLen > 0; $iIndex++, $iLen--) - { - $sChar = $sStr{$iIndex}; - - $iB = $aArray[\ord($sChar)]; - if ((\ord($sChar) & 0x80) || $iB == -1) - { - break; - } - - if ($iK > 0) - { - $iCh |= $iB << $iK; - $iK -= 6; - } - else - { - $iCh |= $iB >> (-$iK); - if ($iCh < 0x80) - { - if (0x20 <= $iCh && $iCh < 0x7f) - { - return $bError; - } - - $sResult .= \chr($iCh); - } - else if ($iCh < 0x800) - { - $sResult .= \chr(0xc0 | ($iCh >> 6)); - $sResult .= \chr(0x80 | ($iCh & 0x3f)); - } - else - { - $sResult .= \chr(0xe0 | ($iCh >> 12)); - $sResult .= \chr(0x80 | (($iCh >> 6) & 0x3f)); - $sResult .= \chr(0x80 | ($iCh & 0x3f)); - } - - $iCh = ($iB << (16 + $iK)) & 0xffff; - $iK += 10; - } - } - - if (($iCh || $iK < 6) || - (!$iLen || $sChar != '-') || - ($iLen > 2 && '&' === $sStr{$iIndex+1} && '-' !== $sStr{$iIndex+2})) - { - return $bError; - } - } - else if (\ord($sChar) < 0x20 || \ord($sChar) >= 0x7f) - { - return $bError; - } - else - { - $sResult .= $sChar; - } - } - - return $sResult; - } - - /** - * @param string $sStr - * - * @return string|bool - */ - public static function Utf8ToUtf7Modified($sStr) - { - $sArray = 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','+',','); - - $sLen = \strlen($sStr); - $bIsB = false; - $iIndex = $iN = 0; - $sReturn = ''; - $bError = false; - $iCh = $iB = $iK = 0; - - while ($sLen) - { - $iC = \ord($sStr{$iIndex}); - if ($iC < 0x80) - { - $iCh = $iC; - $iN = 0; - } - else if ($iC < 0xc2) - { - return $bError; - } - else if ($iC < 0xe0) - { - $iCh = $iC & 0x1f; - $iN = 1; - } - else if ($iC < 0xf0) - { - $iCh = $iC & 0x0f; - $iN = 2; - } - else if ($iC < 0xf8) - { - $iCh = $iC & 0x07; - $iN = 3; - } - else if ($iC < 0xfc) - { - $iCh = $iC & 0x03; - $iN = 4; - } - else if ($iC < 0xfe) - { - $iCh = $iC & 0x01; - $iN = 5; - } - else - { - return $bError; - } - - $iIndex++; - $sLen--; - - if ($iN > $sLen) - { - return $bError; - } - - for ($iJ = 0; $iJ < $iN; $iJ++) - { - $iO = \ord($sStr{$iIndex+$iJ}); - if (($iO & 0xc0) != 0x80) - { - return $bError; - } - - $iCh = ($iCh << 6) | ($iO & 0x3f); - } - - if ($iN > 1 && !($iCh >> ($iN * 5 + 1))) - { - return $bError; - } - - $iIndex += $iN; - $sLen -= $iN; - - if ($iCh < 0x20 || $iCh >= 0x7f) - { - if (!$bIsB) - { - $sReturn .= '&'; - $bIsB = true; - $iB = 0; - $iK = 10; - } - - if ($iCh & ~0xffff) - { - $iCh = 0xfffe; - } - - $sReturn .= $sArray[($iB | $iCh >> $iK)]; - $iK -= 6; - for (; $iK >= 0; $iK -= 6) - { - $sReturn .= $sArray[(($iCh >> $iK) & 0x3f)]; - } - - $iB = ($iCh << (-$iK)) & 0x3f; - $iK += 16; - } - else - { - if ($bIsB) - { - if ($iK > 10) - { - $sReturn .= $sArray[$iB]; - } - $sReturn .= '-'; - $bIsB = false; - } - - $sReturn .= \chr($iCh); - if ('&' === \chr($iCh)) - { - $sReturn .= '-'; - } - } - } - - if ($bIsB) - { - if ($iK > 10) - { - $sReturn .= $sArray[$iB]; - } - - $sReturn .= '-'; - } - - return $sReturn; - } - - /** - * @param string|array $mFunctionNameOrNames - * - * @return bool - */ - public static function FunctionExistsAndEnabled($mFunctionNameOrNames) - { - static $aCache = null; - - if (\is_array($mFunctionNameOrNames)) - { - foreach ($mFunctionNameOrNames as $sFunctionName) - { - if (!\MailSo\Base\Utils::FunctionExistsAndEnabled($sFunctionName)) - { - return false; - } - } - - return true; - } - - if (empty($mFunctionNameOrNames) || !\function_exists($mFunctionNameOrNames) || !\is_callable($mFunctionNameOrNames)) - { - return false; - } - - if (null === $aCache) - { - $sDisableFunctions = @\ini_get('disable_functions'); - $sDisableFunctions = \is_string($sDisableFunctions) && 0 < \strlen($sDisableFunctions) ? $sDisableFunctions : ''; - - $aCache = \explode(',', $sDisableFunctions); - $aCache = \is_array($aCache) && 0 < \count($aCache) ? $aCache : array(); - - if (\extension_loaded('suhosin')) - { - $sSuhosin = @\ini_get('suhosin.executor.func.blacklist'); - $sSuhosin = \is_string($sSuhosin) && 0 < \strlen($sSuhosin) ? $sSuhosin : ''; - - $aSuhosinCache = \explode(',', $sSuhosin); - $aSuhosinCache = \is_array($aSuhosinCache) && 0 < \count($aSuhosinCache) ? $aSuhosinCache : array(); - - if (0 < \count($aSuhosinCache)) - { - $aCache = \array_merge($aCache, $aSuhosinCache); - $aCache = \array_unique($aCache); - } - } - } - - return !\in_array($mFunctionNameOrNames, $aCache); - } - - /** - * @param string $mValue - * - * @return string - */ - public static function ClearNullBite($mValue) - { - return \str_replace('%00', '', $mValue); - } - - /** - * @param mixed $mValue - * @param bool $bClearNullBite = false - * - * @return mixed - */ - public static function StripSlashesValue($mValue, $bClearNullBite = false) - { - static $bIsMagicQuotesOn = null; - if (null === $bIsMagicQuotesOn) - { - $bIsMagicQuotesOn = (bool) @\ini_get('magic_quotes_gpc'); - } - - if (!$bIsMagicQuotesOn) - { - return $bClearNullBite && \is_string($mValue) ? \MailSo\Base\Utils::ClearNullBite($mValue) : $mValue; - } - - $sType = \gettype($mValue); - if ('string' === $sType) - { - return \stripslashes($bClearNullBite ? \MailSo\Base\Utils::ClearNullBite($mValue) : $mValue); - } - else if ('array' === $sType) - { - $aReturnValue = array(); - $mValueKeys = \array_keys($mValue); - foreach ($mValueKeys as $sKey) - { - $aReturnValue[$sKey] = \MailSo\Base\Utils::StripSlashesValue($mValue[$sKey], $bClearNullBite); - } - - return $aReturnValue; - } - - return $mValue; - } - - /** - * @param string $sStr - * - * @return string - */ - public static function CharsetDetect($sStr) - { - $mResult = ''; - if (!\MailSo\Base\Utils::IsAscii($sStr)) - { - $mResult = \MailSo\Base\Utils::IsMbStringSupported() && - \MailSo\Base\Utils::FunctionExistsAndEnabled('mb_detect_encoding') ? - @\mb_detect_encoding($sStr, 'auto', true) : false; - - if (false === $mResult && \MailSo\Base\Utils::IsIconvSupported()) - { - $mResult = \md5(@\iconv('utf-8', 'utf-8//IGNORE', $sStr)) === \md5($sStr) ? 'utf-8' : ''; - } - } - - return \is_string($mResult) && 0 < \strlen($mResult) ? $mResult : ''; - } - - /** - * @param string $sAdditionalSalt = '' - * - * @return string - */ - public static function Md5Rand($sAdditionalSalt = '') - { - return \md5(\microtime(true).\rand(10000, 99999). - \md5($sAdditionalSalt).\rand(10000, 99999).\microtime(true)); - } - - /** - * @param string $sAdditionalSalt = '' - * - * @return string - */ - public static function Sha1Rand($sAdditionalSalt = '') - { - return \sha1(\microtime(true).\rand(10000, 99999). - \sha1($sAdditionalSalt).\rand(10000, 99999).\microtime(true)); - } - - /** - * @param string $sData - * @param string $sKey - * - * @return string - */ - public static function Hmac($sData, $sKey) - { - if (\function_exists('hash_hmac')) - { - return \hash_hmac('md5', $sData, $sKey); - } - - $iLen = 64; - if ($iLen < \strlen($sKey)) - { - $sKey = \pack('H*', \md5($sKey)); - } - - $sKey = \str_pad($sKey, $iLen, \chr(0x00)); - $sIpad = \str_pad('', $iLen, \chr(0x36)); - $sOpad = \str_pad('', $iLen, \chr(0x5c)); - - return \md5(($sKey ^ $sOpad).\pack('H*', \md5(($sKey ^ $sIpad).$sData))); - } - - /** - * @param string $sDomain - * @param bool $bSimple = false - * - * @return bool - */ - public static function ValidateDomain($sDomain, $bSimple = false) - { - $aMatch = array(); - if ($bSimple) - { - return \preg_match('/.+(\.[a-zA-Z]+)$/', $sDomain, $aMatch) && !empty($aMatch[1]); - } - - return \preg_match('/.+(\.[a-zA-Z]+)$/', $sDomain, $aMatch) && !empty($aMatch[1]) && \in_array($aMatch[1], \explode(' ', - '.academy .actor .agency .audio .bar .beer .bike .blue .boutique .cab .camera .camp .capital .cards .careers .cash .catering .center .cheap .city .cleaning .clinic .clothing .club .coffee .community .company .computer .construction .consulting .contractors .cool .credit .dance .dating .democrat .dental .diamonds .digital .direct .directory .discount .domains .education .email .energy .equipment .estate .events .expert .exposed .fail .farm .fish .fitness .florist .fund .futbol .gallery .gift .glass .graphics .guru .help .holdings .holiday .host .hosting .house .institute .international .kitchen .land .life .lighting .limo .link .management .market .marketing .media .menu .moda .partners .parts .photo .photography .photos .pics .pink .press .productions .pub .red .rentals .repair .report .rest .sexy .shoes .social .solar .solutions .space .support .systems .tattoo .tax .technology .tips .today .tools .town .toys .trade .training .university .uno .vacations .vision .vodka .voyage .watch .webcam .wiki .work .works .wtf .zone .aero .asia .biz .cat .com .coop .edu .gov .info .int .jobs .mil .mobi .museum .name .net .org .pro .tel .travel .xxx .xyz '. - '.ac .ad .ae .af .ag .ai .al .am .an .ao .aq .ar .as .at .au .aw .ax .az .ba .bb .bd .be .bf .bg .bh .bi .bj .bm .bn .bo .br .bs .bt .bv .bw .by .bz .ca .cc .cd .cf .cg .ch .ci .ck .cl .cm .cn .co .cr .cs .cu .cv .cx .cy .cz .dd .de .dj .dk .dm .do .dz .ec .ee .eg .er .es .et .eu .fi .fj .fk .fm .fo .fr .ga .gb .gd .ge .gf .gg .gh .gi .gl .gm .gn .gp .gq .gr .gs .gt .gu .gw .gy .hk .hm .hn .hr .ht .hu .id .ie .il .im .in .io .iq .ir .is .it .je .jm .jo .jp .ke .kg .kh .ki .km .kn .kp .kr .kw .ky .kz .la .lb .lc .li .lk .lr .ls .lt .lu .lv .ly .ma .mc .md .me .mg .mh .mk .ml .mm .mn .mo .mp .mq .mr .ms .mt .mu .mv .mw .mx .my .mz .na .nc .ne .nf .ng .ni .nl .no .np .nr .nu .nz .om .pa .pe .pf .pg .ph .pk .pl .pm .pn .pr .ps .pt .pw .py .qa .re .ro .rs .ru . .rw .sa .sb .sc .sd .se .sg .sh .si .sj .sk .sl .sm .sn .so .sr .st .su .sv .sy .sz .tc .td .tf .tg .th .tj .tk .tl .tm .tn .to .tp .tr .tt .tv .tw .tz .ua .ug .uk .us .uy .uz .va .vc .ve .vg .vi .vn .vu .wf .ws .ye .yt .za .zm .zw' - )); - } - - /** - * @param string $sIp - * - * @return bool - */ - public static function ValidateIP($sIp) - { - return !empty($sIp) && $sIp === @\filter_var($sIp, FILTER_VALIDATE_IP); - } - - /** - * @return \Net_IDNA2 - */ - private static function idn() - { - static $oIdn = null; - if (null === $oIdn) - { - include_once MAILSO_LIBRARY_ROOT_PATH.'Vendors/Net/IDNA2.php'; - $oIdn = new \Net_IDNA2(); - $oIdn->setParams('utf8', true); - } - - return $oIdn; - } - - /** - * @param string $sStr - * @param bool $bLowerIfAscii = false - * - * @return string - */ - public static function IdnToUtf8($sStr, $bLowerIfAscii = false) - { - if (0 < \strlen($sStr) && \preg_match('/(^|\.|@)xn--/i', $sStr)) - { - try - { - $sStr = self::idn()->decode($sStr); - } - catch (\Exception $oException) {} - } - - return $bLowerIfAscii ? \MailSo\Base\Utils::StrMailDomainToLowerIfAscii($sStr) : $sStr; - } - - /** - * @param string $sStr - * @param bool $bLowerIfAscii = false - * - * @return string - */ - public static function IdnToAscii($sStr, $bLowerIfAscii = false) - { - $sStr = $bLowerIfAscii ? \MailSo\Base\Utils::StrMailDomainToLowerIfAscii($sStr) : $sStr; - - $sUser = ''; - $sDomain = $sStr; - if (false !== \strpos($sStr, '@')) - { - $sUser = \MailSo\Base\Utils::GetAccountNameFromEmail($sStr); - $sDomain = \MailSo\Base\Utils::GetDomainFromEmail($sStr); - } - - if (0 < \strlen($sDomain) && \preg_match('/[^\x20-\x7E]/', $sDomain)) - { - try - { - $sDomain = self::idn()->encode($sDomain); - } - catch (\Exception $oException) {} - } - - return ('' === $sUser ? '' : $sUser.'@').$sDomain; - } - - /** - * @param string $sHash - * @param string $sSalt - * - * @return int - */ - public static function HashToId($sHash, $sSalt = '') - { - $sData = $sHash ? @\MailSo\Base\Crypt::XxteaDecrypt(\hex2bin($sHash), \md5($sSalt)) : null; - - $aMatch = array(); - if ($sData && preg_match('/^id:(\d+)$/', $sData, $aMatch) && isset($aMatch[1])) - { - return is_numeric($aMatch[1]) ? (int) $aMatch[1] : null; - } - - return null; - } - - /** - * @param int $iID - * @param string $sSalt - * - * @return string - */ - public static function IdToHash($iID, $sSalt = '') - { - return is_int($iID) ? - \bin2hex(\MailSo\Base\Crypt::XxteaEncrypt('id:'.$iID, \md5($sSalt))) : null - ; - } - - /** - * @param string $sPassword - * - * @return bool - */ - public static function PasswordWeaknessCheck($sPassword) - { - $sPassword = \trim($sPassword); - if (6 > \strlen($sPassword)) - { - return false; - } - - $sLine = 'password 123.456 12345678 abc123 qwerty monkey letmein dragon 111.111 baseball iloveyou trustno1 1234567 sunshine master 123.123 welcome shadow ashley football jesus michael ninja mustang password1 123456 123456789 qwerty 111111 1234567 666666 12345678 7777777 123321 654321 1234567890 123123 555555 vkontakte gfhjkm 159753 777777 temppassword qazwsx 1q2w3e 1234 112233 121212 qwertyuiop qq18ww899 987654321 12345 zxcvbn zxcvbnm 999999 samsung ghbdtn 1q2w3e4r 1111111 123654 159357 131313 qazwsxedc 123qwe 222222 asdfgh 333333 9379992 asdfghjkl 4815162342 12344321 88888888 11111111 knopka 789456 qwertyu 1q2w3e4r5t iloveyou vfhbyf marina password qweasdzxc 10203 987654 yfnfif cjkysirj nikita 888888 vfrcbv k.,jdm qwertyuiop[] qwe123 qweasd natasha 123123123 fylhtq q1w2e3 stalker 1111111111 q1w2e3r4 nastya 147258369 147258 fyfcnfcbz 1234554321 1qaz2wsx andrey 111222 147852 genius sergey 7654321 232323 123789 fktrcfylh spartak admin test 123 azerty abc123 lol123 easytocrack1 hello saravn holysh!t test123 tundra_cool2 456 dragon thomas killer root 1111 pass master aaaaaa a monkey daniel asdasd e10adc3949ba59abbe56e057f20f883e changeme computer jessica letmein mirage loulou lol superman shadow admin123 secret administrator sophie kikugalanetroot doudou liverpool hallo sunshine charlie parola 100827092 michael andrew password1 fuckyou matrix cjmasterinf internet hallo123 eminem demo gewinner pokemon abcd1234 guest ngockhoa martin sandra asdf hejsan george qweqwe lollipop lovers q1q1q1 tecktonik naruto 12 password12 password123 password1234 password12345 password123456 password1234567 password12345678 password123456789 000000 maximius 123abc baseball1 football1 soccer princess slipknot 11111 nokia super star 666999 12341234 1234321 135790 159951 212121 zzzzzz 121314 134679 142536 19921992 753951 7007 1111114 124578 19951995 258456 qwaszx zaqwsx 55555 77777 54321 qwert 22222 33333 99999 88888 66666'; - return false === \strpos($sLine, \strtolower($sPassword)); - } -} + 'utf-8', + '.20127' => 'iso-8859-1', + + '.1250' => 'windows-1250', + '.cp1250' => 'windows-1250', + '.cp-1250' => 'windows-1250', + '.1251' => 'windows-1251', + '.cp1251' => 'windows-1251', + '.cp-1251' => 'windows-1251', + '.1252' => 'windows-1252', + '.cp1252' => 'windows-1252', + '.cp-1252' => 'windows-1252', + '.1253' => 'windows-1253', + '.cp1253' => 'windows-1253', + '.cp-1253' => 'windows-1253', + '.1254' => 'windows-1254', + '.cp1254' => 'windows-1254', + '.cp-1254' => 'windows-1254', + '.1255' => 'windows-1255', + '.cp1255' => 'windows-1255', + '.cp-1255' => 'windows-1255', + '.1256' => 'windows-1256', + '.cp1256' => 'windows-1256', + '.cp-1256' => 'windows-1256', + '.1257' => 'windows-1257', + '.cp1257' => 'windows-1257', + '.cp-1257' => 'windows-1257', + '.1258' => 'windows-1258', + '.cp1258' => 'windows-1258', + '.cp-1258' => 'windows-1258', + + '.28591' => 'iso-8859-1', + '.28592' => 'iso-8859-2', + '.28593' => 'iso-8859-3', + '.28594' => 'iso-8859-4', + '.28595' => 'iso-8859-5', + '.28596' => 'iso-8859-6', + '.28597' => 'iso-8859-7', + '.28598' => 'iso-8859-8', + '.28599' => 'iso-8859-9', + '.28603' => 'iso-8859-13', + '.28605' => 'iso-8859-15', + + '.1125' => 'cp1125', + '.20866' => 'koi8-r', + '.21866' => 'koi8-u', + '.950' => 'big5', + '.936' => 'euc-cn', + '.20932' => 'euc-js', + '.949' => 'euc-kr', + ); + + /** + * @access private + */ + private function __construct() + { + } + + /** + * @return string + */ + public static function DetectSystemCharset() + { + $sResult = ''; + $sLocale = @\setlocale(LC_ALL, ''); + $sLocaleLower = \strtolower(\trim($sLocale)); + + foreach (\MailSo\Base\Utils::$aLocaleMapping as $sKey => $sValue) + { + if (false !== \strpos($sLocaleLower, $sKey) || + false !== \strpos($sLocaleLower, '.'.$sValue)) + { + $sResult = $sValue; + break; + } + } + + return $sResult; + } + + /** + * @return string + */ + public static function ConvertSystemString($sSrt) + { + $sSrt = \trim($sSrt); + if (!empty($sSrt) && !\MailSo\Base\Utils::IsUtf8($sSrt)) + { + $sCharset = \MailSo\Base\Utils::DetectSystemCharset(); + if (!empty($sCharset)) + { + $sSrt = \MailSo\Base\Utils::ConvertEncoding( + $sSrt, $sCharset, \MailSo\Base\Enumerations\Charset::UTF_8); + } + else + { + $sSrt = @\utf8_encode($sSrt); + } + } + + return $sSrt; + } + + /** + * @param string $sEncoding + * @param bool $bAsciAsUtf8 = false + * + * @return string + */ + public static function NormalizeCharset($sEncoding, $bAsciAsUtf8 = false) + { + $sEncoding = \strtolower($sEncoding); + + $sEncoding = \preg_replace('/^iso8/', 'iso-8', $sEncoding); + $sEncoding = \preg_replace('/^cp-([\d])/', 'cp$1', $sEncoding); + $sEncoding = \preg_replace('/^windows?12/', 'windows-12', $sEncoding); + + switch ($sEncoding) + { + case 'asci': + case 'ascii': + case 'us-asci': + case 'us-ascii': + $sEncoding = $bAsciAsUtf8 ? \MailSo\Base\Enumerations\Charset::UTF_8 : + \MailSo\Base\Enumerations\Charset::ISO_8859_1; + break; + case 'unicode-1-1-utf-7': + case 'unicode-1-utf-7': + case 'unicode-utf-7': + $sEncoding = \MailSo\Base\Enumerations\Charset::UTF_7; + break; + case 'utf8': + case 'utf-8': + $sEncoding = \MailSo\Base\Enumerations\Charset::UTF_8; + break; + case 'utf7imap': + case 'utf-7imap': + case 'utf7-imap': + case 'utf-7-imap': + $sEncoding = \MailSo\Base\Enumerations\Charset::UTF_7_IMAP; + break; + case 'ks-c-5601-1987': + case 'ks_c_5601-1987': + case 'ks_c_5601_1987': + $sEncoding = 'euc-kr'; + break; + case 'x-gbk': + $sEncoding = 'gb2312'; + break; + case 'iso-8859-i': + case 'iso-8859-8-i': + $sEncoding = \MailSo\Base\Enumerations\Charset::ISO_8859_8; + break; + } + + return $sEncoding; + } + + /** + * @param string $sCharset + * @param string $sValue + * + * @return string + */ + public static function NormalizeCharsetByValue($sCharset, $sValue) + { + $sCharset = \MailSo\Base\Utils::NormalizeCharset($sCharset); + + if (\MailSo\Base\Enumerations\Charset::UTF_8 !== $sCharset && + \MailSo\Base\Utils::IsUtf8($sValue) && + false === \strpos($sCharset, \MailSo\Base\Enumerations\Charset::ISO_2022_JP) + ) + { + $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8; + } + + return $sCharset; + } + + /** + * @param string $sFilePath + * @param function $fFileExistsCallback = null + * + * @return string + */ + public static function SmartFileExists($sFilePath, $fFileExistsCallback = null) + { + $sFilePath = \str_replace('\\', '/', \trim($sFilePath)); + if (!$fFileExistsCallback) + { + $fFileExistsCallback = function ($sPath) { + return \file_exists($sPath); + }; + } + + if (!\call_user_func($fFileExistsCallback, $sFilePath)) + { + return $sFilePath; + } + + $aFileInfo = \pathinfo($sFilePath); + + $iIndex = 0; + + do + { + $iIndex++; + + $sFilePathNew = $aFileInfo['dirname'].'/'. + \preg_replace('/\(\d{1,2}\)$/', '', $aFileInfo['filename']). + ' ('.$iIndex.')'. + (empty($aFileInfo['extension']) ? '' : '.'.$aFileInfo['extension']) + ; + + if (!\call_user_func($fFileExistsCallback, $sFilePathNew)) + { + $sFilePath = $sFilePathNew; + break; + } + else if (10 < $iIndex) + { + break; + } + } + while (true); + + return $sFilePath; + } + + /** + * @return bool + */ + public static function IsMbStringSupported() + { + return \MailSo\Config::$MBSTRING && + \MailSo\Base\Utils::FunctionExistsAndEnabled('mb_convert_encoding'); + } + + /** + * @return bool + */ + public static function IsIconvSupported() + { + return \MailSo\Config::$ICONV && + \MailSo\Base\Utils::FunctionExistsAndEnabled('iconv'); + } + + /** + * @return bool + */ + public static function IsIconvIgnoreSupported() + { + static $bCache = null; + if (null !== $bCache) + { + return $bCache; + } + + $bCache = false; + if (\MailSo\Base\Utils::IsIconvSupported()) + { + if (false !== @\iconv('', '//IGNORE', '')) + { + $bCache = true; + } + } + + return $bCache; + } + + /** + * @return bool + */ + public static function IsIconvTranslitSupported() + { + static $bCache = null; + if (null !== $bCache) + { + return $bCache; + } + + $bCache = false; + if (\MailSo\Base\Utils::IsIconvSupported()) + { + if (false !== @\iconv('', '//TRANSLIT', '')) + { + $bCache = true; + } + } + + return $bCache; + } + + /** + * @param string $sCharset + * + * @return bool + */ + public static function ValidateCharsetName($sCharset) + { + $sCharset = \strtolower(\MailSo\Base\Utils::NormalizeCharset($sCharset)); + return 0 < \strlen($sCharset) && (\in_array($sCharset, array(\MailSo\Base\Enumerations\Charset::UTF_7_IMAP)) || + \in_array($sCharset, \MailSo\Base\Utils::$SuppostedCharsets)); + } + + /** + * @param string $sInputString + * @param string $sInputFromEncoding + * @param string $sInputToEncoding + * + * @return string|bool + */ + public static function IconvConvertEncoding($sInputString, $sInputFromEncoding, $sInputToEncoding) + { + $sIconvOptions = ''; + if (\MailSo\Base\Utils::IsIconvIgnoreSupported()) + { + $sIconvOptions .= '//IGNORE'; + } +// if (\MailSo\Base\Utils::IsIconvTranslitSupported()) +// { +// $sIconvOptions .= '//TRANSLIT'; +// } + + $mResult = @\iconv(\strtoupper($sInputFromEncoding), \strtoupper($sInputToEncoding).$sIconvOptions, $sInputString); + if (false === $mResult) + { + if (\MailSo\Log\Logger::IsSystemEnabled()) + { + \MailSo\Log\Logger::SystemLog(array( + 'inc' => \strtoupper($sInputFromEncoding), + 'out' => \strtoupper($sInputToEncoding).$sIconvOptions, + 'val' => 500 < \strlen($sInputString) ? \substr($sInputString, 0, 500) : $sInputString, + 'hex' => 500 < \strlen($sInputString) ? '-- to long --' : \bin2hex($sInputString) + ), \MailSo\Log\Enumerations\Type::NOTICE); + } + + if (\MailSo\Config::$FixIconvByMbstring && \MailSo\Base\Utils::IsMbStringSupported()) + { + $mResult = \MailSo\Base\Utils::MbConvertEncoding($sInputString, $sInputFromEncoding, $sInputToEncoding); + } + } + return $mResult; + } + + /** + * @param string $sInputString + * @param string $sInputFromEncoding + * @param string $sInputToEncoding + * + * @return string|bool + */ + public static function MbConvertEncoding($sInputString, $sInputFromEncoding, $sInputToEncoding) + { + static $sMbstringSubCh = null; + if (null === $sMbstringSubCh) + { + $sMbstringSubCh = \mb_substitute_character(); + } + + \mb_substitute_character('none'); + $sResult = @\mb_convert_encoding($sInputString, \strtoupper($sInputToEncoding), \strtoupper($sInputFromEncoding)); + \mb_substitute_character($sMbstringSubCh); + + return $sResult; + } + + /** + * @param string $sInputString + * @param string $sInputFromEncoding + * @param string $sInputToEncoding + * + * @return string + */ + public static function ConvertEncoding($sInputString, $sInputFromEncoding, $sInputToEncoding) + { + $sResult = $sInputString; + + $sFromEncoding = \MailSo\Base\Utils::NormalizeCharset($sInputFromEncoding); + $sToEncoding = \MailSo\Base\Utils::NormalizeCharset($sInputToEncoding); + + if ('' === \trim($sResult) || ($sFromEncoding === $sToEncoding && \MailSo\Base\Enumerations\Charset::UTF_8 !== $sFromEncoding)) + { + return $sResult; + } + + $bUnknown = false; + switch (true) + { + default: + $bUnknown = true; + break; + + case ($sFromEncoding === \MailSo\Base\Enumerations\Charset::ISO_8859_1 && + $sToEncoding === \MailSo\Base\Enumerations\Charset::UTF_8 && + \function_exists('utf8_encode')): + + $sResult = \utf8_encode($sResult); + break; + + case ($sFromEncoding === \MailSo\Base\Enumerations\Charset::UTF_8 && + $sToEncoding === \MailSo\Base\Enumerations\Charset::ISO_8859_1 && + \function_exists('utf8_decode')): + + $sResult = \utf8_decode($sResult); + break; + + case ($sFromEncoding === \MailSo\Base\Enumerations\Charset::UTF_7_IMAP && + $sToEncoding === \MailSo\Base\Enumerations\Charset::UTF_8): + + $sResult = \MailSo\Base\Utils::Utf7ModifiedToUtf8($sResult); + if (false === $sResult) + { + $sResult = $sInputString; + } + break; + + case ($sFromEncoding === \MailSo\Base\Enumerations\Charset::UTF_8 && + $sToEncoding === \MailSo\Base\Enumerations\Charset::UTF_7_IMAP): + + $sResult = \MailSo\Base\Utils::Utf8ToUtf7Modified($sResult); + if (false === $sResult) + { + $sResult = $sInputString; + } + break; + + case ($sFromEncoding === \MailSo\Base\Enumerations\Charset::UTF_7_IMAP): + + $sResult = \MailSo\Base\Utils::ConvertEncoding( + \MailSo\Base\Utils::ModifiedToPlainUtf7($sResult), + \MailSo\Base\Enumerations\Charset::UTF_7, + $sToEncoding + ); + break; + + case (\in_array(\strtolower($sFromEncoding), \MailSo\Base\Utils::$SuppostedCharsets)): + + if (\MailSo\Base\Utils::IsIconvSupported()) + { + $sResult = \MailSo\Base\Utils::IconvConvertEncoding($sResult, $sFromEncoding, $sToEncoding); + } + else if (\MailSo\Base\Utils::IsMbStringSupported()) + { + $sResult = \MailSo\Base\Utils::MbConvertEncoding($sResult, $sFromEncoding, $sToEncoding); + } + + $sResult = (false !== $sResult) ? $sResult : $sInputString; + break; + } + + if ($bUnknown && \MailSo\Base\Utils::IsMbStringSupported()) + { + $sResult = @\mb_convert_encoding($sResult, $sToEncoding); + } + + return $sResult; + } + + /** + * @param string $sValue + * + * @return bool + */ + public static function IsAscii($sValue) + { + if ('' === \trim($sValue)) + { + return true; + } + + return !\preg_match('/[^\x09\x10\x13\x0A\x0D\x20-\x7E]/', $sValue); + } + + /** + * @param string $sValue + * + * @return string + */ + public static function StrToLowerIfAscii($sValue) + { + return \MailSo\Base\Utils::IsAscii($sValue) ? \strtolower($sValue) : $sValue; + } + + /** + * @param string $sValue + * + * @return string + */ + public static function StrToUpperIfAscii($sValue) + { + return \MailSo\Base\Utils::IsAscii($sValue) ? \strtoupper($sValue) : $sValue; + } + + /** + * @param string $sValue + * + * @return string + */ + public static function StrMailDomainToLowerIfAscii($sValue) + { + $aParts = \explode('@', $sValue, 2); + if (!empty($aParts[1])) + { + $aParts[1] = \MailSo\Base\Utils::IsAscii($aParts[1]) ? \strtolower($aParts[1]) : $aParts[1]; + } + + return \implode('@', $aParts); + } + + /** + * @param string $sValue + * + * @return string + */ + public static function StripSpaces($sValue) + { + return \MailSo\Base\Utils::Trim( + \preg_replace('/[\s]+/u', ' ', $sValue)); + } + + /** + * @param string $sValue + * + * @return bool + */ + public static function IsUtf8($sValue) + { + return (bool) (\function_exists('mb_check_encoding') ? + \mb_check_encoding($sValue, 'UTF-8') : \preg_match('//u', $sValue)); + } + + /** + * @param int $iSize + * @param int $iRound + * + * @return string + */ + public static function FormatFileSize($iSize, $iRound = 0) + { + $aSizes = array('B', 'KB', 'MB'); + for ($iIndex = 0; $iSize > 1024 && isset($aSizes[$iIndex + 1]); $iIndex++) + { + $iSize /= 1024; + } + return \round($iSize, $iRound).$aSizes[$iIndex]; + } + + /** + * @param string $sEncodedValue + * @param string $sEncodeingType + * + * @return string + */ + public static function DecodeEncodingValue($sEncodedValue, $sEncodeingType) + { + $sResult = $sEncodedValue; + switch (\strtolower($sEncodeingType)) + { + case 'q': + case 'quoted_printable': + case 'quoted-printable': + $sResult = \quoted_printable_decode($sResult); + break; + case 'b': + case 'base64': + $sResult = \MailSo\Base\Utils::Base64Decode($sResult); + break; + } + return $sResult; + } + + /** + * @param string $sInputValue + * + * @return string + */ + public static function DecodeFlowedFormat($sInputValue) + { + return \preg_replace('/ ([\r]?[\n])/m', ' ', $sInputValue); + } + + /** + * @param string $sEncodedValue + * @param string $sIncomingCharset = '' + * @param string $sForcedIncomingCharset = '' + * + * @return string + */ + public static function DecodeHeaderValue($sEncodedValue, $sIncomingCharset = '', $sForcedIncomingCharset = '') + { + $sValue = $sEncodedValue; + if (0 < \strlen($sIncomingCharset)) + { + $sIncomingCharset = \MailSo\Base\Utils::NormalizeCharsetByValue($sIncomingCharset, $sValue); + + $sValue = \MailSo\Base\Utils::ConvertEncoding($sValue, $sIncomingCharset, + \MailSo\Base\Enumerations\Charset::UTF_8); + } + + $sValue = \preg_replace('/\?=[\n\r\t\s]{1,5}=\?/m', '?==?', $sValue); + $sValue = \preg_replace('/[\r\n\t]+/m', ' ', $sValue); + + $aEncodeArray = array(''); + $aMatch = array(); +// \preg_match_all('/=\?[^\?]+\?[q|b|Q|B]\?[^\?]*?\?=/', $sValue, $aMatch); + \preg_match_all('/=\?[^\?]+\?[q|b|Q|B]\?.*?\?=/', $sValue, $aMatch); + + if (isset($aMatch[0]) && \is_array($aMatch[0])) + { + for ($iIndex = 0, $iLen = \count($aMatch[0]); $iIndex < $iLen; $iIndex++) + { + if (isset($aMatch[0][$iIndex])) + { + $iPos = @\strpos($aMatch[0][$iIndex], '*'); + if (false !== $iPos) + { + $aMatch[0][$iIndex][0] = \substr($aMatch[0][$iIndex][0], 0, $iPos); + } + } + } + + $aEncodeArray = $aMatch[0]; + } + + $aParts = array(); + + $sMainCharset = ''; + $bOneCharset = true; + + for ($iIndex = 0, $iLen = \count($aEncodeArray); $iIndex < $iLen; $iIndex++) + { + $aTempArr = array('', $aEncodeArray[$iIndex]); + if ('=?' === \substr(\trim($aTempArr[1]), 0, 2)) + { + $iPos = \strpos($aTempArr[1], '?', 2); + $aTempArr[0] = \substr($aTempArr[1], 2, $iPos - 2); + $sEncType = \strtoupper($aTempArr[1]{$iPos + 1}); + switch ($sEncType) + { + case 'Q': + $sHeaderValuePart = \str_replace('_', ' ', $aTempArr[1]); + $aTempArr[1] = \quoted_printable_decode(\substr( + $sHeaderValuePart, $iPos + 3, \strlen($sHeaderValuePart) - $iPos - 5)); + break; + case 'B': + $sHeaderValuePart = $aTempArr[1]; + $aTempArr[1] = \MailSo\Base\Utils::Base64Decode(\substr( + $sHeaderValuePart, $iPos + 3, \strlen($sHeaderValuePart) - $iPos - 5)); + break; + } + } + + if (0 < \strlen($aTempArr[0])) + { + $sCharset = 0 === \strlen($sForcedIncomingCharset) ? $aTempArr[0] : $sForcedIncomingCharset; + $sCharset = \MailSo\Base\Utils::NormalizeCharset($sCharset, true); + + if ('' === $sMainCharset) + { + $sMainCharset = $sCharset; + } + else if ($sMainCharset !== $sCharset) + { + $bOneCharset = false; + } + } + + $aParts[] = array( + $aEncodeArray[$iIndex], + $aTempArr[1], + $sCharset + ); + + unset($aTempArr); + } + + for ($iIndex = 0, $iLen = \count($aParts); $iIndex < $iLen; $iIndex++) + { + if ($bOneCharset) + { + $sValue = \str_replace($aParts[$iIndex][0], $aParts[$iIndex][1], $sValue); + } + else + { + $aParts[$iIndex][2] = \MailSo\Base\Utils::NormalizeCharsetByValue($aParts[$iIndex][2], $aParts[$iIndex][1]); + + $sValue = \str_replace($aParts[$iIndex][0], + \MailSo\Base\Utils::ConvertEncoding($aParts[$iIndex][1], $aParts[$iIndex][2], \MailSo\Base\Enumerations\Charset::UTF_8), + $sValue); + } + } + + if ($bOneCharset && 0 < \strlen($sMainCharset)) + { + $sMainCharset = \MailSo\Base\Utils::NormalizeCharsetByValue($sMainCharset, $sValue); + $sValue = \MailSo\Base\Utils::ConvertEncoding($sValue, $sMainCharset, \MailSo\Base\Enumerations\Charset::UTF_8); + } + + return $sValue; + } + + /** + * @param string $sIncHeaders + * @param string $aHeadersToRemove = array() + * + * @return string + */ + public static function RemoveHeaderFromHeaders($sIncHeaders, $aHeadersToRemove = array()) + { + $sResultHeaders = $sIncHeaders; + + if (\is_array($aHeadersToRemove) && 0 < \count($aHeadersToRemove)) + { + $aHeadersToRemove = \array_map('strtolower', $aHeadersToRemove); + + $sIncHeaders = \preg_replace('/[\r\n]+/', "\n", $sIncHeaders); + $aHeaders = \explode("\n", $sIncHeaders); + + $bSkip = false; + $aResult = array(); + + foreach ($aHeaders as $sLine) + { + if (0 < \strlen($sLine)) + { + $sFirst = \substr($sLine,0,1); + if (' ' === $sFirst || "\t" === $sFirst) + { + if (!$bSkip) + { + $aResult[] = $sLine; + } + } + else + { + $bSkip = false; + $aParts = \explode(':', $sLine, 2); + + if (!empty($aParts) && !empty($aParts[0])) + { + if (\in_array(\strtolower(\trim($aParts[0])), $aHeadersToRemove)) + { + $bSkip = true; + } + else + { + $aResult[] = $sLine; + } + } + } + } + } + + $sResultHeaders = \implode("\r\n", $aResult); + } + + return $sResultHeaders; + } + + /** + * @param string $sEncodeType + * @param string $sValue + * + * @return string + */ + public static function EncodeUnencodedValue($sEncodeType, $sValue) + { + $sValue = \trim($sValue); + if (0 < \strlen($sValue) && !\MailSo\Base\Utils::IsAscii($sValue)) + { + switch (\strtoupper($sEncodeType)) + { + case 'B': + $sValue = '=?'.\strtolower(\MailSo\Base\Enumerations\Charset::UTF_8). + '?B?'.\base64_encode($sValue).'?='; + break; + + case 'Q': + $sValue = '=?'.\strtolower(\MailSo\Base\Enumerations\Charset::UTF_8). + '?Q?'.\str_replace(array('?', ' ', '_'), array('=3F', '_', '=5F'), + \quoted_printable_encode($sValue)).'?='; + break; + } + } + + return $sValue; + } + + /** + * @unused + * + * @param string $sEncodeType + * @param string $sEncodeCharset + * @param string $sValue + * + * @return string + */ + public static function EncodeHeaderValue($sEncodeType, $sEncodeCharset, $sValue) + { + $sValue = \trim($sValue); + if (0 < \strlen($sValue) && !\MailSo\Base\Utils::IsAscii($sValue)) + { + switch (\strtoupper($sEncodeType)) + { + case 'B': + $sValue = '=?'.\strtolower($sEncodeCharset).'?B?'.\base64_encode($sValue).'?='; + break; + + case 'Q': + $sValue = '=?'.\strtolower($sEncodeCharset).'?Q?'.\str_replace( + array('?', ' ', '_'), array('=3F', '_', '=5F'), + \quoted_printable_encode($sValue)).'?='; + break; + } + } + + return \trim($sValue); + } + + /** + * @param string $sAttrName + * @param string $sValue = 'utf-8' + * @param string $sCharset = '' + * @param string $sLang = '' + * @param int $iLen = 78 + * + * @return string|bool + */ + public static function AttributeRfc2231Encode($sAttrName, $sValue, $sCharset = 'utf-8', $sLang = '', $iLen = 1000) + { + $sValue = \strtoupper($sCharset).'\''.$sLang.'\''. + \preg_replace_callback('/[\x00-\x20*\'%()<>@,;:\\\\"\/[\]?=\x80-\xFF]/', function ($match) { + return \rawurlencode($match[0]); + }, $sValue); + + $iNlen = \strlen($sAttrName); + $iVlen = \strlen($sValue); + + if (\strlen($sAttrName) + $iVlen > $iLen - 3) + { + $sections = array(); + $section = 0; + + for ($i = 0, $j = 0; $i < $iVlen; $i += $j) + { + $j = $iLen - $iNlen - \strlen($section) - 4; + $sections[$section++] = \substr($sValue, $i, $j); + } + + for ($i = 0, $n = $section; $i < $n; $i++) + { + $sections[$i] = ' '.$sAttrName.'*'.$i.'*='.$sections[$i]; + } + + return \implode(";\r\n", $sections); + } + else + { + return $sAttrName.'*='.$sValue; + } + } + /** + * @param string $sAttrName + * @param string $sValue + * + * @return string + */ + public static function EncodeHeaderUtf8AttributeValue($sAttrName, $sValue) + { + $sAttrName = \trim($sAttrName); + $sValue = \trim($sValue); + + if (0 < \strlen($sValue) && !\MailSo\Base\Utils::IsAscii($sValue)) + { + if (!empty($_SERVER['HTTP_USER_AGENT']) && 0 < \strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) + { + $sValue = $sAttrName.'="'.\preg_replace('/[+\s]+/', '%20', \urlencode($sValue)).'"'; + } + else + { + $sValue = \MailSo\Base\Utils::AttributeRfc2231Encode($sAttrName, $sValue); + } + } + else + { + $sValue = $sAttrName.'="'.\str_replace('"', '\\"', $sValue).'"'; + } + + return \trim($sValue); + } + + /** + * @param string $sEmail + * + * @return string + */ + public static function GetAccountNameFromEmail($sEmail) + { + $sResult = ''; + if (0 < \strlen($sEmail)) + { + $iPos = \strrpos($sEmail, '@'); + $sResult = (false === $iPos) ? $sEmail : \substr($sEmail, 0, $iPos); + } + + return $sResult; + } + + /** + * @param string $sEmail + * + * @return string + */ + public static function GetDomainFromEmail($sEmail) + { + $sResult = ''; + if (0 < \strlen($sEmail)) + { + $iPos = \strrpos($sEmail, '@'); + if (false !== $iPos && 0 < $iPos) + { + $sResult = \substr($sEmail, $iPos + 1); + } + } + + return $sResult; + } + + /** + * @param string $sDomain + * + * @return string + */ + public static function GetClearDomainName($sDomain) + { + $sResultDomain = \preg_replace( + '/^(webmail|email|mail|www|imap4|pop3|imap|pop|demo|client|ssl|secure|test|cloud|box|m)\./i', + '', $sDomain); + + return false === \strpos($sResultDomain, '.') ? $sDomain : $sResultDomain; + } + + /** + * @param string $sFileName + * + * @return string + */ + public static function GetFileExtension($sFileName) + { + $iLast = \strrpos($sFileName, '.'); + return false === $iLast ? '' : \strtolower(\substr($sFileName, $iLast + 1)); + } + + /** + * @param string $sFileName + * + * @return string + */ + public static function MimeContentType($sFileName) + { + $sResult = 'application/octet-stream'; + $sFileName = \trim(\strtolower($sFileName)); + + if ('winmail.dat' === $sFileName) + { + return 'application/ms-tnef'; + } + + $aMimeTypes = array( + + 'eml' => 'message/rfc822', + 'mime' => 'message/rfc822', + 'txt' => 'text/plain', + 'text' => 'text/plain', + 'def' => 'text/plain', + 'list' => 'text/plain', + 'in' => 'text/plain', + 'ini' => 'text/plain', + 'log' => 'text/plain', + 'sql' => 'text/plain', + 'cfg' => 'text/plain', + 'conf' => 'text/plain', + 'asc' => 'text/plain', + 'rtx' => 'text/richtext', + 'vcard' => 'text/vcard', + 'vcf' => 'text/vcard', + 'htm' => 'text/html', + 'html' => 'text/html', + 'csv' => 'text/csv', + 'ics' => 'text/calendar', + 'ifb' => 'text/calendar', + 'xml' => 'text/xml', + 'json' => 'application/json', + 'swf' => 'application/x-shockwave-flash', + 'hlp' => 'application/winhlp', + 'wgt' => 'application/widget', + 'chm' => 'application/vnd.ms-htmlhelp', + 'p10' => 'application/pkcs10', + 'p7c' => 'application/pkcs7-mime', + 'p7m' => 'application/pkcs7-mime', + 'p7s' => 'application/pkcs7-signature', + 'torrent' => 'application/x-bittorrent', + + // scripts + 'js' => 'application/javascript', + 'pl' => 'text/perl', + 'css' => 'text/css', + 'asp' => 'text/asp', + 'php' => 'application/x-httpd-php', + 'php3' => 'application/x-httpd-php', + 'php4' => 'application/x-httpd-php', + 'php5' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + + // images + 'png' => 'image/png', + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'jfif' => 'image/jpeg', + 'gif' => 'image/gif', + 'bmp' => 'image/bmp', + 'cgm' => 'image/cgm', + 'ief' => 'image/ief', + 'ico' => 'image/x-icon', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'webp' => 'image/webp', + + // archives + 'zip' => 'application/zip', + '7z' => 'application/x-7z-compressed', + 'rar' => 'application/x-rar-compressed', + 'exe' => 'application/x-msdownload', + 'dll' => 'application/x-msdownload', + 'scr' => 'application/x-msdownload', + 'com' => 'application/x-msdownload', + 'bat' => 'application/x-msdownload', + 'msi' => 'application/x-msdownload', + 'cab' => 'application/vnd.ms-cab-compressed', + 'gz' => 'application/x-gzip', + 'tgz' => 'application/x-gzip', + 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', + 'deb' => 'application/x-debian-package', + + // fonts + 'psf' => 'application/x-font-linux-psf', + 'otf' => 'application/x-font-otf', + 'pcf' => 'application/x-font-pcf', + 'snf' => 'application/x-font-snf', + 'ttf' => 'application/x-font-ttf', + 'ttc' => 'application/x-font-ttf', + + // audio + 'mp3' => 'audio/mpeg', + 'amr' => 'audio/amr', + 'aac' => 'audio/x-aac', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'wav' => 'audio/x-wav', + 'wma' => 'audio/x-ms-wma', + 'wax' => 'audio/x-ms-wax', + 'midi' => 'audio/midi', + 'mp4a' => 'audio/mp4', + 'ogg' => 'audio/ogg', + 'weba' => 'audio/webm', + 'ra' => 'audio/x-pn-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'rmp' => 'audio/x-pn-realaudio-plugin', + 'm3u' => 'audio/x-mpegurl', + + // video + 'flv' => 'video/x-flv', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'avi' => 'video/x-msvideo', + 'mpg' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'm1v' => 'video/mpeg', + 'm2v' => 'video/mpeg', + '3gp' => 'video/3gpp', + '3g2' => 'video/3gpp2', + 'h261' => 'video/h261', + 'h263' => 'video/h263', + 'h264' => 'video/h264', + 'jpgv' => 'video/jpgv', + 'mp4' => 'video/mp4', + 'mp4v' => 'video/mp4', + 'mpg4' => 'video/mp4', + 'ogv' => 'video/ogg', + 'webm' => 'video/webm', + 'm4v' => 'video/x-m4v', + 'asf' => 'video/x-ms-asf', + 'asx' => 'video/x-ms-asf', + 'wm' => 'video/x-ms-wm', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wvx' => 'video/x-ms-wvx', + 'movie' => 'video/x-sgi-movie', + + // adobe + 'pdf' => 'application/pdf', + 'psd' => 'image/vnd.adobe.photoshop', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + + // ms office + 'doc' => 'application/msword', + 'dot' => 'application/msword', + 'rtf' => 'application/rtf', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + + // open office + 'odt' => 'application/vnd.oasis.opendocument.text', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet' + + ); + + $sExt = \MailSo\Base\Utils::GetFileExtension($sFileName); + if (0 < \strlen($sExt) && isset($aMimeTypes[$sExt])) + { + $sResult = $aMimeTypes[$sExt]; + } + + return $sResult; + } + + /** + * @param string $sContentType + * @param string $sFileName + * + * @return string + */ + public static function ContentTypeType($sContentType, $sFileName) + { + $sResult = ''; + $sContentType = \strtolower($sContentType); + if (0 === \strpos($sContentType, 'image/')) + { + $sResult = 'image'; + } + else + { + switch ($sContentType) + { + case 'application/zip': + case 'application/x-7z-compressed': + case 'application/x-rar-compressed': + case 'application/x-msdownload': + case 'application/vnd.ms-cab-compressed': + case 'application/x-gzip': + case 'application/x-bzip': + case 'application/x-bzip2': + case 'application/x-debian-package': + $sResult = 'archive'; + break; + case 'application/msword': + case 'application/rtf': + case 'application/vnd.ms-excel': + case 'application/vnd.ms-powerpoint': + case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': + case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': + case 'application/vnd.openxmlformats-officedocument.wordprocessingml.template': + case 'application/vnd.openxmlformats-officedocument.presentationml.presentation': + case 'application/vnd.oasis.opendocument.text': + case 'application/vnd.oasis.opendocument.spreadsheet': + $sResult = 'doc'; + break; + case 'application/pdf': + case 'application/x-pdf': + $sResult = 'pdf'; + break; + } + + if ('' === $sResult) + { + switch (\strtolower(\MailSo\Base\Utils::GetFileExtension($sFileName))) + { + case 'zip': + case '7z': + case 'rar': + $sResult = 'archive'; + break; + } + } + } + + return $sResult; + } + + /** + * @staticvar bool $bValidateAction + * + * @param int $iTimeToReset = 15 + * @param int $iTimeToAdd = 120 + * + * @return bool + */ + public static function ResetTimeLimit($iTimeToReset = 15, $iTimeToAdd = 120) + { + $iTime = \time(); + if ($iTime < \MailSo\Base\Loader::$InitTime + 5) + { + // do nothing first 5s + return true; + } + + static $bValidateAction = null; + static $iResetTimer = null; + + if (null === $bValidateAction) + { + $iResetTimer = 0; + + $sSafeMode = \strtolower(\trim(@\ini_get('safe_mode'))); + $bSafeMode = 'on' === $sSafeMode || '1' === $sSafeMode || 'true' === $sSafeMode; + + $bValidateAction = !$bSafeMode && \MailSo\Base\Utils::FunctionExistsAndEnabled('set_time_limit'); + } + + if ($bValidateAction && $iTimeToReset < $iTime - $iResetTimer) + { + $iResetTimer = $iTime; + if (!@\set_time_limit($iTimeToAdd)) + { + $bValidateAction = false; + return false; + } + + return true; + } + + return false; + } + + /** + * @param string $sText + * + * @return string + */ + public static function InlineRebuildStringToJsString($sText) + { + static $aJsonReplaces = array( + array('\\', "\n", "\t", "\r", '\b', "\f", '"'), + array('\\\\', '\\n', '\\t', '\\r', '\\b', '\\f', '\"') + ); + + return \str_replace('', '<\/script>', + \str_replace($aJsonReplaces[0], $aJsonReplaces[1], $sText)); + } + + /** + * @param array $aInput + */ + public static function ClearArrayUtf8Values(&$aInput) + { + if (\is_array($aInput)) + { + foreach ($aInput as $mKey => $mItem) + { + if (\is_string($mItem)) + { + $aInput[$mKey] = \MailSo\Base\Utils::Utf8Clear($mItem); + } + else if (\is_array($mItem)) + { + \MailSo\Base\Utils::ClearArrayUtf8Values($mItem); + $aInput[$mKey] = $mItem; + } + } + } + } + + /** + * @param mixed $mInput + * @param \MailSo\Log\Logger|null $oLogger = null + * + * @return string + */ + public static function Php2js($mInput, $oLogger = null) + { + static $iOpt = null; + if (null === $iOpt) + { + $iOpt = \defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 0; + } + + $sResult = @\json_encode($mInput, $iOpt); + if (!\is_string($sResult) || '' === $sResult) + { + if (!$oLogger && \MailSo\Log\Logger::IsSystemEnabled()) + { + $oLogger = \MailSo\Config::$SystemLogger; + } + + if (!($oLogger instanceof \MailSo\Log\Logger)) + { + $oLogger = null; + } + + if ($oLogger) + { + $oLogger->Write('json_encode: '.\trim( + (\MailSo\Base\Utils::FunctionExistsAndEnabled('json_last_error') ? ' [Error Code: '.\json_last_error().']' : ''). + (\MailSo\Base\Utils::FunctionExistsAndEnabled('json_last_error_msg') ? ' [Error Message: '.\json_last_error_msg().']' : '') + ), \MailSo\Log\Enumerations\Type::WARNING, 'JSON' + ); + } + + if (\is_array($mInput)) + { + if ($oLogger) + { + $oLogger->WriteDump($mInput, \MailSo\Log\Enumerations\Type::INFO, 'JSON'); + $oLogger->Write('Trying to clear Utf8 before json_encode', \MailSo\Log\Enumerations\Type::INFO, 'JSON'); + } + + \MailSo\Base\Utils::ClearArrayUtf8Values($mInput); + $sResult = @\json_encode($mInput, $iOpt); + } + } + + return $sResult; + } + + /** + * @param string $sFileName + * + * @return string + */ + public static function ClearFileName($sFileName) + { + return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite( + \MailSo\Base\Utils::StripSpaces( + \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sFileName)))); + } + + /** + * @param string $sValue + * + * @return string + */ + public static function ClearXss($sValue) + { + return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite( + \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sValue))); + } + + /** + * @param string $sValue + * + * @return string + */ + public static function Trim($sValue) + { + return \trim(\preg_replace('/^[\x00-\x1F]+/u', '', + \preg_replace('/[\x00-\x1F]+$/u', '', \trim($sValue)))); + } + + /** + * @param string $sDir + * + * @return bool + */ + public static function RecRmDir($sDir) + { + if (@\is_dir($sDir)) + { + $aObjects = \scandir($sDir); + foreach ($aObjects as $sObject) + { + if ('.' !== $sObject && '..' !== $sObject) + { +// if ('dir' === \filetype($sDir.'/'.$sObject)) + if (\is_dir($sDir.'/'.$sObject)) + { + self::RecRmDir($sDir.'/'.$sObject); + } + else + { + @\unlink($sDir.'/'.$sObject); + } + } + } + + return @\rmdir($sDir); + } + + return false; + } + + /** + * @param string $sSource + * @param string $sDestination + */ + public static function CopyDir($sSource, $sDestination) + { + if (\is_dir($sSource)) + { + if (!\is_dir($sDestination)) + { + \mkdir($sDestination); + } + + $oDirectory = \dir($sSource); + if ($oDirectory) + { + while (false !== ($sRead = $oDirectory->read())) + { + if ('.' === $sRead || '..' === $sRead) + { + continue; + } + + $sPathDir = $sSource.'/'.$sRead; + if (\is_dir($sPathDir)) + { + \MailSo\Base\Utils::CopyDir($sPathDir, $sDestination.'/'.$sRead); + continue; + } + + \copy($sPathDir, $sDestination.'/'.$sRead); + } + + $oDirectory->close(); + } + } + } + + /** + * @param string $sTempPath + * @param int $iTime2Kill + * @param int $iNow + * + * @return bool + */ + public static function RecTimeDirRemove($sTempPath, $iTime2Kill, $iNow) + { + $iFileCount = 0; + + $sTempPath = rtrim($sTempPath, '\\/'); + if (@\is_dir($sTempPath)) + { + $rDirH = @\opendir($sTempPath); + if ($rDirH) + { + $bRemoveAllDirs = true; + while (($sFile = @\readdir($rDirH)) !== false) + { + if ('.' !== $sFile && '..' !== $sFile) + { + if (@\is_dir($sTempPath.'/'.$sFile)) + { + if (!\MailSo\Base\Utils::RecTimeDirRemove($sTempPath.'/'.$sFile, $iTime2Kill, $iNow)) + { + $bRemoveAllDirs = false; + } + } + else + { + $iFileCount++; + } + } + } + + @\closedir($rDirH); + } + + if ($iFileCount > 0) + { + if (\MailSo\Base\Utils::TimeFilesRemove($sTempPath, $iTime2Kill, $iNow)) + { + return @\rmdir($sTempPath); + } + } + else + { + return $bRemoveAllDirs ? @\rmdir($sTempPath) : false; + } + + return false; + } + + return true; + } + + /** + * @param string $sTempPath + * @param int $iTime2Kill + * @param int $iNow + */ + public static function TimeFilesRemove($sTempPath, $iTime2Kill, $iNow) + { + $bResult = true; + + $sTempPath = rtrim($sTempPath, '\\/'); + if (@\is_dir($sTempPath)) + { + $rDirH = @\opendir($sTempPath); + if ($rDirH) + { + while (($sFile = @\readdir($rDirH)) !== false) + { + if ($sFile !== '.' && $sFile !== '..') + { + if ($iNow - \filemtime($sTempPath.'/'.$sFile) > $iTime2Kill) + { + @\unlink($sTempPath.'/'.$sFile); + } + else + { + $bResult = false; + } + } + } + + @\closedir($rDirH); + } + } + + return $bResult; + } + + /** + * @param string $sUtfString + * @param int $iLength + * + * @return string + */ + public static function Utf8Truncate($sUtfString, $iLength) + { + if (\strlen($sUtfString) <= $iLength) + { + return $sUtfString; + } + + while ($iLength >= 0) + { + if ((\ord($sUtfString[$iLength]) < 0x80) || (\ord($sUtfString[$iLength]) >= 0xC0)) + { + return \substr($sUtfString, 0, $iLength); + } + + $iLength--; + } + + return ''; + } + + /** + * @param string $sUtfString + * @param string $sReplaceOn = '' + * + * @return string + */ + public static function Utf8Clear($sUtfString, $sReplaceOn = '') + { + if ('' === $sUtfString) + { + return $sUtfString; + } + + $sUtfString = \preg_replace(\MailSo\Base\Utils::$sValidUtf8Regexp, '$1', $sUtfString); + + $sUtfString = \preg_replace( + '/\xE0[\x80-\x9F][\x80-\xBF]'. + '|\xEF\xBF\xBF'. + '|\xED[\xA0-\xBF][\x80-\xBF]/S', $sReplaceOn, $sUtfString); + + $sUtfString = \preg_replace('/\xEF\xBF\xBD/', '?', $sUtfString); + + $sNewUtfString = false; + if (false === $sNewUtfString && \MailSo\Base\Utils::IsMbStringSupported()) + { + $sNewUtfString = \MailSo\Base\Utils::MbConvertEncoding($sUtfString, 'UTF-8', 'UTF-8'); + } + + if (false === $sNewUtfString && \MailSo\Base\Utils::IsIconvSupported()) + { + $sNewUtfString = \MailSo\Base\Utils::IconvConvertEncoding($sUtfString, 'UTF-8', 'UTF-8'); + } + + if (false !== $sNewUtfString) + { + $sUtfString = $sNewUtfString; + } + + return $sUtfString; + } + + /** + * @param string $sUtfString + * + * @return bool + */ + public static function IsRTL($sUtfString) + { + // \x{0591}-\x{05F4} - Hebrew + // \x{0600}-\x{068F} - Arabic + // \x{0750}-\x{077F} - Arabic + // \x{08A0}-\x{08FF} - Arabic + // \x{103A0}-\x{103DF} - Old Persian + return 0 < (int) preg_match('/[\x{0591}-\x{05F4}\x{0600}-\x{068F}\x{0750}-\x{077F}\x{08A0}-\x{08FF}\x{103A0}-\x{103DF}]/u', $sUtfString); + } + + /** + * @param string $sString + * + * @return string + */ + public static function Base64Decode($sString) + { + $sResultString = \base64_decode($sString, true); + if (false === $sResultString) + { + $sString = \str_replace(array(' ', "\r", "\n", "\t"), '', $sString); + $sString = \preg_replace('/[^a-zA-Z0-9=+\/](.*)$/', '', $sString); + + if (false !== \strpos(\trim(\trim($sString), '='), '=')) + { + $sString = \preg_replace('/=([^=])/', '= $1', $sString); + $aStrings = \explode(' ', $sString); + foreach ($aStrings as $iIndex => $sParts) + { + $aStrings[$iIndex] = \base64_decode($sParts); + } + + $sResultString = \implode('', $aStrings); + } + else + { + $sResultString = \base64_decode($sString); + } + } + + return $sResultString; + } + + /** + * @param string $sValue + * + * @return string + */ + public static function UrlSafeBase64Encode($sValue) + { + return \rtrim(\strtr(\base64_encode($sValue), '+/', '-_'), '='); + } + + /** + * @param string $sValue + * + * @return string + */ + public static function UrlSafeBase64Decode($sValue) + { + $sValue = \rtrim(\strtr($sValue, '-_.', '+/='), '='); + return \MailSo\Base\Utils::Base64Decode(\str_pad($sValue, \strlen($sValue) + (\strlen($sValue) % 4), '=', STR_PAD_RIGHT)); + } + + /** + * @param string $sSequence + * + * @return array + */ + public static function ParseFetchSequence($sSequence) + { + $aResult = array(); + $sSequence = \trim($sSequence); + if (0 < \strlen($sSequence)) + { + $aSequence = \explode(',', $sSequence); + foreach ($aSequence as $sItem) + { + if (false === \strpos($sItem, ':')) + { + $aResult[] = (int) $sItem; + } + else + { + $aItems = \explode(':', $sItem); + $iMax = \max($aItems[0], $aItems[1]); + + for ($iIndex = $aItems[0]; $iIndex <= $iMax; $iIndex++) + { + $aResult[] = (int) $iIndex; + } + } + } + } + + return $aResult; + } + /** + * @param array $aSequence + * + * @return string + */ + public static function PrepearFetchSequence($aSequence) + { + $aResult = array(); + if (\is_array($aSequence) && 0 < \count($aSequence)) + { + $iStart = null; + $iPrev = null; + + foreach ($aSequence as $sItem) + { + // simple protection + if (false !== \strpos($sItem, ':')) + { + $aResult[] = $sItem; + continue; + } + + $iItem = (int) $sItem; + if (null === $iStart || null === $iPrev) + { + $iStart = $iItem; + $iPrev = $iItem; + continue; + } + + if ($iPrev === $iItem - 1) + { + $iPrev = $iItem; + } + else + { + $aResult[] = $iStart === $iPrev ? $iStart : $iStart.':'.$iPrev; + $iStart = $iItem; + $iPrev = $iItem; + } + } + + if (null !== $iStart && null !== $iPrev) + { + $aResult[] = $iStart === $iPrev ? $iStart : $iStart.':'.$iPrev; + } + } + + return \implode(',', $aResult); + } + + /** + * + * @param resource $fResource + * @param int $iBufferLen = 8192 + * + * @return bool + */ + public static function FpassthruWithTimeLimitReset($fResource, $iBufferLen = 8192) + { + $bResult = false; + if (\is_resource($fResource)) + { + while (!\feof($fResource)) + { + $sBuffer = @\fread($fResource, $iBufferLen); + if (false !== $sBuffer) + { + echo $sBuffer; + \MailSo\Base\Utils::ResetTimeLimit(); + continue; + } + + break; + } + + $bResult = true; + } + + return $bResult; + } + + /** + * @param resource $rRead + * @param array $aWrite + * @param int $iBufferLen = 8192 + * @param bool $bResetTimeLimit = true + * @param bool $bFixCrLf = false + * @param bool $bRewindOnComplete = false + * + * @return int|bool + */ + public static function MultipleStreamWriter($rRead, $aWrite, $iBufferLen = 8192, $bResetTimeLimit = true, $bFixCrLf = false, $bRewindOnComplete = false) + { + $mResult = false; + if ($rRead && \is_array($aWrite) && 0 < \count($aWrite)) + { + $mResult = 0; + while (!\feof($rRead)) + { + $sBuffer = \fread($rRead, $iBufferLen); + if (false === $sBuffer) + { + $mResult = false; + break; + } + + if (0 === $iBufferLen || '' === $sBuffer) + { + break; + } + + if ($bFixCrLf) + { + $sBuffer = \str_replace("\n", "\r\n", \str_replace("\r", '', $sBuffer)); + } + + $mResult += \strlen($sBuffer); + + foreach ($aWrite as $rWriteStream) + { + $mWriteResult = \fwrite($rWriteStream, $sBuffer); + if (false === $mWriteResult) + { + $mResult = false; + break 2; + } + } + + if ($bResetTimeLimit) + { + \MailSo\Base\Utils::ResetTimeLimit(); + } + } + } + + if ($mResult && $bRewindOnComplete) + { + foreach ($aWrite as $rWriteStream) + { + if (\is_resource($rWriteStream)) + { + @\rewind($rWriteStream); + } + } + } + + return $mResult; + } + + /** + * @param string $sUtfModifiedString + * + * @return string + */ + public static function ModifiedToPlainUtf7($sUtfModifiedString) + { + $sUtf = ''; + $bBase = false; + + for ($iIndex = 0, $iLen = \strlen($sUtfModifiedString); $iIndex < $iLen; $iIndex++) + { + if ('&' === $sUtfModifiedString[$iIndex]) + { + if (isset($sUtfModifiedString[$iIndex+1]) && '-' === $sUtfModifiedString[$iIndex + 1]) + { + $sUtf .= '&'; + $iIndex++; + } + else + { + $sUtf .= '+'; + $bBase = true; + } + } + else if ($sUtfModifiedString[$iIndex] == '-' && $bBase) + { + $bBase = false; + } + else + { + if ($bBase && ',' === $sUtfModifiedString[$iIndex]) + { + $sUtf .= '/'; + } + else if (!$bBase && '+' === $sUtfModifiedString[$iIndex]) + { + $sUtf .= '+-'; + } + else + { + $sUtf .= $sUtfModifiedString[$iIndex]; + } + } + } + + return $sUtf; + } + + /** + * @param string $sStr + * + * @return string|bool + */ + public static function Utf7ModifiedToUtf8($sStr) + { + $aArray = 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); + + $sResult = ''; + $bError = false; + $iLen = \strlen($sStr); + + for ($iIndex = 0; $iLen > 0; $iIndex++, $iLen--) + { + $sChar = $sStr{$iIndex}; + if ($sChar == '&') + { + $iIndex++; + $iLen--; + + $sChar = isset($sStr{$iIndex}) ? $sStr{$iIndex} : null; + if ($sChar === null) + { + break; + } + + if ($iLen && $sChar == '-') + { + $sResult .= '&'; + continue; + } + + $iCh = 0; + $iK = 10; + for (; $iLen > 0; $iIndex++, $iLen--) + { + $sChar = $sStr{$iIndex}; + + $iB = $aArray[\ord($sChar)]; + if ((\ord($sChar) & 0x80) || $iB == -1) + { + break; + } + + if ($iK > 0) + { + $iCh |= $iB << $iK; + $iK -= 6; + } + else + { + $iCh |= $iB >> (-$iK); + if ($iCh < 0x80) + { + if (0x20 <= $iCh && $iCh < 0x7f) + { + return $bError; + } + + $sResult .= \chr($iCh); + } + else if ($iCh < 0x800) + { + $sResult .= \chr(0xc0 | ($iCh >> 6)); + $sResult .= \chr(0x80 | ($iCh & 0x3f)); + } + else + { + $sResult .= \chr(0xe0 | ($iCh >> 12)); + $sResult .= \chr(0x80 | (($iCh >> 6) & 0x3f)); + $sResult .= \chr(0x80 | ($iCh & 0x3f)); + } + + $iCh = ($iB << (16 + $iK)) & 0xffff; + $iK += 10; + } + } + + if (($iCh || $iK < 6) || + (!$iLen || $sChar != '-') || + ($iLen > 2 && '&' === $sStr{$iIndex+1} && '-' !== $sStr{$iIndex+2})) + { + return $bError; + } + } + else if (\ord($sChar) < 0x20 || \ord($sChar) >= 0x7f) + { + return $bError; + } + else + { + $sResult .= $sChar; + } + } + + return $sResult; + } + + /** + * @param string $sStr + * + * @return string|bool + */ + public static function Utf8ToUtf7Modified($sStr) + { + $sArray = 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','+',','); + + $sLen = \strlen($sStr); + $bIsB = false; + $iIndex = $iN = 0; + $sReturn = ''; + $bError = false; + $iCh = $iB = $iK = 0; + + while ($sLen) + { + $iC = \ord($sStr{$iIndex}); + if ($iC < 0x80) + { + $iCh = $iC; + $iN = 0; + } + else if ($iC < 0xc2) + { + return $bError; + } + else if ($iC < 0xe0) + { + $iCh = $iC & 0x1f; + $iN = 1; + } + else if ($iC < 0xf0) + { + $iCh = $iC & 0x0f; + $iN = 2; + } + else if ($iC < 0xf8) + { + $iCh = $iC & 0x07; + $iN = 3; + } + else if ($iC < 0xfc) + { + $iCh = $iC & 0x03; + $iN = 4; + } + else if ($iC < 0xfe) + { + $iCh = $iC & 0x01; + $iN = 5; + } + else + { + return $bError; + } + + $iIndex++; + $sLen--; + + if ($iN > $sLen) + { + return $bError; + } + + for ($iJ = 0; $iJ < $iN; $iJ++) + { + $iO = \ord($sStr{$iIndex+$iJ}); + if (($iO & 0xc0) != 0x80) + { + return $bError; + } + + $iCh = ($iCh << 6) | ($iO & 0x3f); + } + + if ($iN > 1 && !($iCh >> ($iN * 5 + 1))) + { + return $bError; + } + + $iIndex += $iN; + $sLen -= $iN; + + if ($iCh < 0x20 || $iCh >= 0x7f) + { + if (!$bIsB) + { + $sReturn .= '&'; + $bIsB = true; + $iB = 0; + $iK = 10; + } + + if ($iCh & ~0xffff) + { + $iCh = 0xfffe; + } + + $sReturn .= $sArray[($iB | $iCh >> $iK)]; + $iK -= 6; + for (; $iK >= 0; $iK -= 6) + { + $sReturn .= $sArray[(($iCh >> $iK) & 0x3f)]; + } + + $iB = ($iCh << (-$iK)) & 0x3f; + $iK += 16; + } + else + { + if ($bIsB) + { + if ($iK > 10) + { + $sReturn .= $sArray[$iB]; + } + $sReturn .= '-'; + $bIsB = false; + } + + $sReturn .= \chr($iCh); + if ('&' === \chr($iCh)) + { + $sReturn .= '-'; + } + } + } + + if ($bIsB) + { + if ($iK > 10) + { + $sReturn .= $sArray[$iB]; + } + + $sReturn .= '-'; + } + + return $sReturn; + } + + /** + * @param string|array $mFunctionNameOrNames + * + * @return bool + */ + public static function FunctionExistsAndEnabled($mFunctionNameOrNames) + { + static $aCache = null; + + if (\is_array($mFunctionNameOrNames)) + { + foreach ($mFunctionNameOrNames as $sFunctionName) + { + if (!\MailSo\Base\Utils::FunctionExistsAndEnabled($sFunctionName)) + { + return false; + } + } + + return true; + } + + if (empty($mFunctionNameOrNames) || !\function_exists($mFunctionNameOrNames) || !\is_callable($mFunctionNameOrNames)) + { + return false; + } + + if (null === $aCache) + { + $sDisableFunctions = @\ini_get('disable_functions'); + $sDisableFunctions = \is_string($sDisableFunctions) && 0 < \strlen($sDisableFunctions) ? $sDisableFunctions : ''; + + $aCache = \explode(',', $sDisableFunctions); + $aCache = \is_array($aCache) && 0 < \count($aCache) ? $aCache : array(); + + if (\extension_loaded('suhosin')) + { + $sSuhosin = @\ini_get('suhosin.executor.func.blacklist'); + $sSuhosin = \is_string($sSuhosin) && 0 < \strlen($sSuhosin) ? $sSuhosin : ''; + + $aSuhosinCache = \explode(',', $sSuhosin); + $aSuhosinCache = \is_array($aSuhosinCache) && 0 < \count($aSuhosinCache) ? $aSuhosinCache : array(); + + if (0 < \count($aSuhosinCache)) + { + $aCache = \array_merge($aCache, $aSuhosinCache); + $aCache = \array_unique($aCache); + } + } + } + + return !\in_array($mFunctionNameOrNames, $aCache); + } + + /** + * @param string $mValue + * + * @return string + */ + public static function ClearNullBite($mValue) + { + return \str_replace('%00', '', $mValue); + } + + /** + * @param mixed $mValue + * @param bool $bClearNullBite = false + * + * @return mixed + */ + public static function StripSlashesValue($mValue, $bClearNullBite = false) + { + static $bIsMagicQuotesOn = null; + if (null === $bIsMagicQuotesOn) + { + $bIsMagicQuotesOn = (bool) @\ini_get('magic_quotes_gpc'); + } + + if (!$bIsMagicQuotesOn) + { + return $bClearNullBite && \is_string($mValue) ? \MailSo\Base\Utils::ClearNullBite($mValue) : $mValue; + } + + $sType = \gettype($mValue); + if ('string' === $sType) + { + return \stripslashes($bClearNullBite ? \MailSo\Base\Utils::ClearNullBite($mValue) : $mValue); + } + else if ('array' === $sType) + { + $aReturnValue = array(); + $mValueKeys = \array_keys($mValue); + foreach ($mValueKeys as $sKey) + { + $aReturnValue[$sKey] = \MailSo\Base\Utils::StripSlashesValue($mValue[$sKey], $bClearNullBite); + } + + return $aReturnValue; + } + + return $mValue; + } + + /** + * @param string $sStr + * + * @return string + */ + public static function CharsetDetect($sStr) + { + $mResult = ''; + if (!\MailSo\Base\Utils::IsAscii($sStr)) + { + $mResult = \MailSo\Base\Utils::IsMbStringSupported() && + \MailSo\Base\Utils::FunctionExistsAndEnabled('mb_detect_encoding') ? + @\mb_detect_encoding($sStr, 'auto', true) : false; + + if (false === $mResult && \MailSo\Base\Utils::IsIconvSupported()) + { + $mResult = \md5(@\iconv('utf-8', 'utf-8//IGNORE', $sStr)) === \md5($sStr) ? 'utf-8' : ''; + } + } + + return \is_string($mResult) && 0 < \strlen($mResult) ? $mResult : ''; + } + + /** + * @param string $sAdditionalSalt = '' + * + * @return string + */ + public static function Md5Rand($sAdditionalSalt = '') + { + return \md5(\microtime(true).\rand(10000, 99999). + \md5($sAdditionalSalt).\rand(10000, 99999).\microtime(true)); + } + + /** + * @param string $sAdditionalSalt = '' + * + * @return string + */ + public static function Sha1Rand($sAdditionalSalt = '') + { + return \sha1(\microtime(true).\rand(10000, 99999). + \sha1($sAdditionalSalt).\rand(10000, 99999).\microtime(true)); + } + + /** + * @param string $sData + * @param string $sKey + * + * @return string + */ + public static function Hmac($sData, $sKey) + { + if (\function_exists('hash_hmac')) + { + return \hash_hmac('md5', $sData, $sKey); + } + + $iLen = 64; + if ($iLen < \strlen($sKey)) + { + $sKey = \pack('H*', \md5($sKey)); + } + + $sKey = \str_pad($sKey, $iLen, \chr(0x00)); + $sIpad = \str_pad('', $iLen, \chr(0x36)); + $sOpad = \str_pad('', $iLen, \chr(0x5c)); + + return \md5(($sKey ^ $sOpad).\pack('H*', \md5(($sKey ^ $sIpad).$sData))); + } + + /** + * @param string $sDomain + * @param bool $bSimple = false + * + * @return bool + */ + public static function ValidateDomain($sDomain, $bSimple = false) + { + $aMatch = array(); + if ($bSimple) + { + return \preg_match('/.+(\.[a-zA-Z]+)$/', $sDomain, $aMatch) && !empty($aMatch[1]); + } + + return \preg_match('/.+(\.[a-zA-Z]+)$/', $sDomain, $aMatch) && !empty($aMatch[1]) && \in_array($aMatch[1], \explode(' ', + '.academy .actor .agency .audio .bar .beer .bike .blue .boutique .cab .camera .camp .capital .cards .careers .cash .catering .center .cheap .city .cleaning .clinic .clothing .club .coffee .community .company .computer .construction .consulting .contractors .cool .credit .dance .dating .democrat .dental .diamonds .digital .direct .directory .discount .domains .education .email .energy .equipment .estate .events .expert .exposed .fail .farm .fish .fitness .florist .fund .futbol .gallery .gift .glass .graphics .guru .help .holdings .holiday .host .hosting .house .institute .international .kitchen .land .life .lighting .limo .link .management .market .marketing .media .menu .moda .partners .parts .photo .photography .photos .pics .pink .press .productions .pub .red .rentals .repair .report .rest .sexy .shoes .social .solar .solutions .space .support .systems .tattoo .tax .technology .tips .today .tools .town .toys .trade .training .university .uno .vacations .vision .vodka .voyage .watch .webcam .wiki .work .works .wtf .zone .aero .asia .biz .cat .com .coop .edu .gov .info .int .jobs .mil .mobi .museum .name .net .org .pro .tel .travel .xxx .xyz '. + '.ac .ad .ae .af .ag .ai .al .am .an .ao .aq .ar .as .at .au .aw .ax .az .ba .bb .bd .be .bf .bg .bh .bi .bj .bm .bn .bo .br .bs .bt .bv .bw .by .bz .ca .cc .cd .cf .cg .ch .ci .ck .cl .cm .cn .co .cr .cs .cu .cv .cx .cy .cz .dd .de .dj .dk .dm .do .dz .ec .ee .eg .er .es .et .eu .fi .fj .fk .fm .fo .fr .ga .gb .gd .ge .gf .gg .gh .gi .gl .gm .gn .gp .gq .gr .gs .gt .gu .gw .gy .hk .hm .hn .hr .ht .hu .id .ie .il .im .in .io .iq .ir .is .it .je .jm .jo .jp .ke .kg .kh .ki .km .kn .kp .kr .kw .ky .kz .la .lb .lc .li .lk .lr .ls .lt .lu .lv .ly .ma .mc .md .me .mg .mh .mk .ml .mm .mn .mo .mp .mq .mr .ms .mt .mu .mv .mw .mx .my .mz .na .nc .ne .nf .ng .ni .nl .no .np .nr .nu .nz .om .pa .pe .pf .pg .ph .pk .pl .pm .pn .pr .ps .pt .pw .py .qa .re .ro .rs .ru . .rw .sa .sb .sc .sd .se .sg .sh .si .sj .sk .sl .sm .sn .so .sr .st .su .sv .sy .sz .tc .td .tf .tg .th .tj .tk .tl .tm .tn .to .tp .tr .tt .tv .tw .tz .ua .ug .uk .us .uy .uz .va .vc .ve .vg .vi .vn .vu .wf .ws .ye .yt .za .zm .zw' + )); + } + + /** + * @param string $sIp + * + * @return bool + */ + public static function ValidateIP($sIp) + { + return !empty($sIp) && $sIp === @\filter_var($sIp, FILTER_VALIDATE_IP); + } + + /** + * @return \Net_IDNA2 + */ + private static function idn() + { + static $oIdn = null; + if (null === $oIdn) + { + include_once MAILSO_LIBRARY_ROOT_PATH.'Vendors/Net/IDNA2.php'; + $oIdn = new \Net_IDNA2(); + $oIdn->setParams('utf8', true); + } + + return $oIdn; + } + + /** + * @param string $sStr + * @param bool $bLowerIfAscii = false + * + * @return string + */ + public static function IdnToUtf8($sStr, $bLowerIfAscii = false) + { + if (0 < \strlen($sStr) && \preg_match('/(^|\.|@)xn--/i', $sStr)) + { + try + { + $sStr = self::idn()->decode($sStr); + } + catch (\Exception $oException) {} + } + + return $bLowerIfAscii ? \MailSo\Base\Utils::StrMailDomainToLowerIfAscii($sStr) : $sStr; + } + + /** + * @param string $sStr + * @param bool $bLowerIfAscii = false + * + * @return string + */ + public static function IdnToAscii($sStr, $bLowerIfAscii = false) + { + $sStr = $bLowerIfAscii ? \MailSo\Base\Utils::StrMailDomainToLowerIfAscii($sStr) : $sStr; + + $sUser = ''; + $sDomain = $sStr; + if (false !== \strpos($sStr, '@')) + { + $sUser = \MailSo\Base\Utils::GetAccountNameFromEmail($sStr); + $sDomain = \MailSo\Base\Utils::GetDomainFromEmail($sStr); + } + + if (0 < \strlen($sDomain) && \preg_match('/[^\x20-\x7E]/', $sDomain)) + { + try + { + $sDomain = self::idn()->encode($sDomain); + } + catch (\Exception $oException) {} + } + + return ('' === $sUser ? '' : $sUser.'@').$sDomain; + } + + /** + * @param string $sHash + * @param string $sSalt + * + * @return int + */ + public static function HashToId($sHash, $sSalt = '') + { + $sData = $sHash ? @\MailSo\Base\Crypt::XxteaDecrypt(\hex2bin($sHash), \md5($sSalt)) : null; + + $aMatch = array(); + if ($sData && preg_match('/^id:(\d+)$/', $sData, $aMatch) && isset($aMatch[1])) + { + return is_numeric($aMatch[1]) ? (int) $aMatch[1] : null; + } + + return null; + } + + /** + * @param int $iID + * @param string $sSalt + * + * @return string + */ + public static function IdToHash($iID, $sSalt = '') + { + return is_int($iID) ? + \bin2hex(\MailSo\Base\Crypt::XxteaEncrypt('id:'.$iID, \md5($sSalt))) : null + ; + } + + /** + * @param string $sPassword + * + * @return bool + */ + public static function PasswordWeaknessCheck($sPassword) + { + $sPassword = \trim($sPassword); + if (6 > \strlen($sPassword)) + { + return false; + } + + $sLine = 'password 123.456 12345678 abc123 qwerty monkey letmein dragon 111.111 baseball iloveyou trustno1 1234567 sunshine master 123.123 welcome shadow ashley football jesus michael ninja mustang password1 123456 123456789 qwerty 111111 1234567 666666 12345678 7777777 123321 654321 1234567890 123123 555555 vkontakte gfhjkm 159753 777777 temppassword qazwsx 1q2w3e 1234 112233 121212 qwertyuiop qq18ww899 987654321 12345 zxcvbn zxcvbnm 999999 samsung ghbdtn 1q2w3e4r 1111111 123654 159357 131313 qazwsxedc 123qwe 222222 asdfgh 333333 9379992 asdfghjkl 4815162342 12344321 88888888 11111111 knopka 789456 qwertyu 1q2w3e4r5t iloveyou vfhbyf marina password qweasdzxc 10203 987654 yfnfif cjkysirj nikita 888888 vfrcbv k.,jdm qwertyuiop[] qwe123 qweasd natasha 123123123 fylhtq q1w2e3 stalker 1111111111 q1w2e3r4 nastya 147258369 147258 fyfcnfcbz 1234554321 1qaz2wsx andrey 111222 147852 genius sergey 7654321 232323 123789 fktrcfylh spartak admin test 123 azerty abc123 lol123 easytocrack1 hello saravn holysh!t test123 tundra_cool2 456 dragon thomas killer root 1111 pass master aaaaaa a monkey daniel asdasd e10adc3949ba59abbe56e057f20f883e changeme computer jessica letmein mirage loulou lol superman shadow admin123 secret administrator sophie kikugalanetroot doudou liverpool hallo sunshine charlie parola 100827092 michael andrew password1 fuckyou matrix cjmasterinf internet hallo123 eminem demo gewinner pokemon abcd1234 guest ngockhoa martin sandra asdf hejsan george qweqwe lollipop lovers q1q1q1 tecktonik naruto 12 password12 password123 password1234 password12345 password123456 password1234567 password12345678 password123456789 000000 maximius 123abc baseball1 football1 soccer princess slipknot 11111 nokia super star 666999 12341234 1234321 135790 159951 212121 zzzzzz 121314 134679 142536 19921992 753951 7007 1111114 124578 19951995 258456 qwaszx zaqwsx 55555 77777 54321 qwert 22222 33333 99999 88888 66666'; + return false === \strpos($sLine, \strtolower($sPassword)); + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Base/Validator.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Base/Validator.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Base/Validator.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Base/Validator.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Cache/CacheClient.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Cache/CacheClient.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Cache/CacheClient.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Cache/CacheClient.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Cache/DriverInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Cache/DriverInterface.php similarity index 93% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Cache/DriverInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Cache/DriverInterface.php index 8751ba1d..4789cd6c 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Cache/DriverInterface.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Cache/DriverInterface.php @@ -1,48 +1,48 @@ -oImapResponse = $oImapResponse; - $this->aEnvelopeCache = null; - } - - /** - * @param \MailSo\Imap\Response $oImapResponse - * @return \MailSo\Imap\FetchResponse - */ - public static function NewInstance($oImapResponse) - { - return new self($oImapResponse); - } - - /** - * @param bool $bForce = false - * - * @return array|null - */ - public function GetEnvelope($bForce = false) - { - if (null === $this->aEnvelopeCache || $bForce) - { - $this->aEnvelopeCache = $this->GetFetchValue(Enumerations\FetchType::ENVELOPE); - } - return $this->aEnvelopeCache; - } - - /** - * @param int $iIndex - * @param mixed $mNullResult = null - * - * @return mixed - */ - public function GetFetchEnvelopeValue($iIndex, $mNullResult) - { - return self::findEnvelopeIndex($this->GetEnvelope(), $iIndex, $mNullResult); - } - - /** - * @param int $iIndex - * @param string $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1 - * - * @return \MailSo\Mime\EmailCollection|null - */ - public function GetFetchEnvelopeEmailCollection($iIndex, $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1) - { - $oResult = null; - $aEmails = $this->GetFetchEnvelopeValue($iIndex, null); - if (is_array($aEmails) && 0 < count($aEmails)) - { - $oResult = \MailSo\Mime\EmailCollection::NewInstance(); - foreach ($aEmails as $aEmailItem) - { - if (is_array($aEmailItem) && 4 === count($aEmailItem)) - { - $sDisplayName = \MailSo\Base\Utils::DecodeHeaderValue( - self::findEnvelopeIndex($aEmailItem, 0, ''), $sParentCharset); - -// $sRemark = \MailSo\Base\Utils::DecodeHeaderValue( -// self::findEnvelopeIndex($aEmailItem, 1, ''), $sParentCharset); - - $sLocalPart = self::findEnvelopeIndex($aEmailItem, 2, ''); - $sDomainPart = self::findEnvelopeIndex($aEmailItem, 3, ''); - - if (0 < strlen($sLocalPart) && 0 < strlen($sDomainPart)) - { - $oResult->Add( - \MailSo\Mime\Email::NewInstance($sLocalPart.'@'.$sDomainPart, $sDisplayName) - ); - } - } - } - } - - return $oResult; - } - - /** - * @param string $sRfc822SubMimeIndex = '' - * - * @return \MailSo\Imap\BodyStructure|null - */ - public function GetFetchBodyStructure($sRfc822SubMimeIndex = '') - { - $oBodyStructure = null; - $aBodyStructureArray = $this->GetFetchValue(Enumerations\FetchType::BODYSTRUCTURE); - - if (is_array($aBodyStructureArray)) - { - if (0 < strlen($sRfc822SubMimeIndex)) - { - $oBodyStructure = BodyStructure::NewInstanceFromRfc822SubPart($aBodyStructureArray, $sRfc822SubMimeIndex); - } - else - { - $oBodyStructure = BodyStructure::NewInstance($aBodyStructureArray); - } - } - - return $oBodyStructure; - } - - /** - * @param string $sFetchItemName - * - * @return mixed - */ - public function GetFetchValue($sFetchItemName) - { - $mReturn = null; - $bNextIsValue = false; - - if (Enumerations\FetchType::INDEX === $sFetchItemName) - { - $mReturn = $this->oImapResponse->ResponseList[1]; - } - else if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3])) - { - foreach ($this->oImapResponse->ResponseList[3] as $mItem) - { - if ($bNextIsValue) - { - $mReturn = $mItem; - break; - } - - if ($sFetchItemName === $mItem) - { - $bNextIsValue = true; - } - } - } - - return $mReturn; - } - - /** - * @param string $sRfc822SubMimeIndex = '' - * - * @return string - */ - public function GetHeaderFieldsValue($sRfc822SubMimeIndex = '') - { - $sReturn = ''; - $bNextIsValue = false; - - $sRfc822SubMimeIndex = 0 < \strlen($sRfc822SubMimeIndex) ? ''.$sRfc822SubMimeIndex.'.' : ''; - - if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3])) - { - foreach ($this->oImapResponse->ResponseList[3] as $mItem) - { - if ($bNextIsValue) - { - $sReturn = (string) $mItem; - break; - } - - if (\is_string($mItem) && ( - $mItem === 'BODY['.$sRfc822SubMimeIndex.'HEADER]' || - 0 === \strpos($mItem, 'BODY['.$sRfc822SubMimeIndex.'HEADER.FIELDS') || - $mItem === 'BODY['.$sRfc822SubMimeIndex.'MIME]')) - { - $bNextIsValue = true; - } - } - } - - return $sReturn; - } - - private static function findFetchUidAndSize($aList) - { - $bUid = false; - $bSize = false; - if (is_array($aList)) - { - foreach ($aList as $mItem) - { - if (\MailSo\Imap\Enumerations\FetchType::UID === $mItem) - { - $bUid = true; - } - else if (\MailSo\Imap\Enumerations\FetchType::RFC822_SIZE === $mItem) - { - $bSize = true; - } - } - } - - return $bUid && $bSize; - } - - /** - * @param \MailSo\Imap\Response $oImapResponse - * - * @return bool - */ - public static function IsValidFetchImapResponse($oImapResponse) - { - return ( - $oImapResponse - && true !== $oImapResponse->IsStatusResponse - && \MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType - && 3 < count($oImapResponse->ResponseList) && 'FETCH' === $oImapResponse->ResponseList[2] - && is_array($oImapResponse->ResponseList[3]) - ); - } - - /** - * @param \MailSo\Imap\Response $oImapResponse - * - * @return bool - */ - public static function IsNotEmptyFetchImapResponse($oImapResponse) - { - return ( - $oImapResponse - && self::IsValidFetchImapResponse($oImapResponse) - && isset($oImapResponse->ResponseList[3]) - && self::findFetchUidAndSize($oImapResponse->ResponseList[3]) - ); - } - - /** - * @param array $aEnvelope - * @param int $iIndex - * @param mixed $mNullResult = null - * - * @return mixed - */ - private static function findEnvelopeIndex($aEnvelope, $iIndex, $mNullResult) - { - return (isset($aEnvelope[$iIndex]) && 'NIL' !== $aEnvelope[$iIndex] && '' !== $aEnvelope[$iIndex]) - ? $aEnvelope[$iIndex] : $mNullResult; - } -} +oImapResponse = $oImapResponse; + $this->aEnvelopeCache = null; + } + + /** + * @param \MailSo\Imap\Response $oImapResponse + * @return \MailSo\Imap\FetchResponse + */ + public static function NewInstance($oImapResponse) + { + return new self($oImapResponse); + } + + /** + * @param bool $bForce = false + * + * @return array|null + */ + public function GetEnvelope($bForce = false) + { + if (null === $this->aEnvelopeCache || $bForce) + { + $this->aEnvelopeCache = $this->GetFetchValue(Enumerations\FetchType::ENVELOPE); + } + return $this->aEnvelopeCache; + } + + /** + * @param int $iIndex + * @param mixed $mNullResult = null + * + * @return mixed + */ + public function GetFetchEnvelopeValue($iIndex, $mNullResult) + { + return self::findEnvelopeIndex($this->GetEnvelope(), $iIndex, $mNullResult); + } + + /** + * @param int $iIndex + * @param string $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1 + * + * @return \MailSo\Mime\EmailCollection|null + */ + public function GetFetchEnvelopeEmailCollection($iIndex, $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1) + { + $oResult = null; + $aEmails = $this->GetFetchEnvelopeValue($iIndex, null); + if (is_array($aEmails) && 0 < count($aEmails)) + { + $oResult = \MailSo\Mime\EmailCollection::NewInstance(); + foreach ($aEmails as $aEmailItem) + { + if (is_array($aEmailItem) && 4 === count($aEmailItem)) + { + $sDisplayName = \MailSo\Base\Utils::DecodeHeaderValue( + self::findEnvelopeIndex($aEmailItem, 0, ''), $sParentCharset); + +// $sRemark = \MailSo\Base\Utils::DecodeHeaderValue( +// self::findEnvelopeIndex($aEmailItem, 1, ''), $sParentCharset); + + $sLocalPart = self::findEnvelopeIndex($aEmailItem, 2, ''); + $sDomainPart = self::findEnvelopeIndex($aEmailItem, 3, ''); + + if (0 < strlen($sLocalPart) && 0 < strlen($sDomainPart)) + { + $oResult->Add( + \MailSo\Mime\Email::NewInstance($sLocalPart.'@'.$sDomainPart, $sDisplayName) + ); + } + } + } + } + + return $oResult; + } + + /** + * @param string $sRfc822SubMimeIndex = '' + * + * @return \MailSo\Imap\BodyStructure|null + */ + public function GetFetchBodyStructure($sRfc822SubMimeIndex = '') + { + $oBodyStructure = null; + $aBodyStructureArray = $this->GetFetchValue(Enumerations\FetchType::BODYSTRUCTURE); + + if (is_array($aBodyStructureArray)) + { + if (0 < strlen($sRfc822SubMimeIndex)) + { + $oBodyStructure = BodyStructure::NewInstanceFromRfc822SubPart($aBodyStructureArray, $sRfc822SubMimeIndex); + } + else + { + $oBodyStructure = BodyStructure::NewInstance($aBodyStructureArray); + } + } + + return $oBodyStructure; + } + + /** + * @param string $sFetchItemName + * + * @return mixed + */ + public function GetFetchValue($sFetchItemName) + { + $mReturn = null; + $bNextIsValue = false; + + if (Enumerations\FetchType::INDEX === $sFetchItemName) + { + $mReturn = $this->oImapResponse->ResponseList[1]; + } + else if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3])) + { + foreach ($this->oImapResponse->ResponseList[3] as $mItem) + { + if ($bNextIsValue) + { + $mReturn = $mItem; + break; + } + + if ($sFetchItemName === $mItem) + { + $bNextIsValue = true; + } + } + } + + return $mReturn; + } + + /** + * @param string $sRfc822SubMimeIndex = '' + * + * @return string + */ + public function GetHeaderFieldsValue($sRfc822SubMimeIndex = '') + { + $sReturn = ''; + $bNextIsValue = false; + + $sRfc822SubMimeIndex = 0 < \strlen($sRfc822SubMimeIndex) ? ''.$sRfc822SubMimeIndex.'.' : ''; + + if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3])) + { + foreach ($this->oImapResponse->ResponseList[3] as $mItem) + { + if ($bNextIsValue) + { + $sReturn = (string) $mItem; + break; + } + + if (\is_string($mItem) && ( + $mItem === 'BODY['.$sRfc822SubMimeIndex.'HEADER]' || + 0 === \strpos($mItem, 'BODY['.$sRfc822SubMimeIndex.'HEADER.FIELDS') || + $mItem === 'BODY['.$sRfc822SubMimeIndex.'MIME]')) + { + $bNextIsValue = true; + } + } + } + + return $sReturn; + } + + private static function findFetchUidAndSize($aList) + { + $bUid = false; + $bSize = false; + if (is_array($aList)) + { + foreach ($aList as $mItem) + { + if (\MailSo\Imap\Enumerations\FetchType::UID === $mItem) + { + $bUid = true; + } + else if (\MailSo\Imap\Enumerations\FetchType::RFC822_SIZE === $mItem) + { + $bSize = true; + } + } + } + + return $bUid && $bSize; + } + + /** + * @param \MailSo\Imap\Response $oImapResponse + * + * @return bool + */ + public static function IsValidFetchImapResponse($oImapResponse) + { + return ( + $oImapResponse + && true !== $oImapResponse->IsStatusResponse + && \MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType + && 3 < count($oImapResponse->ResponseList) && 'FETCH' === $oImapResponse->ResponseList[2] + && is_array($oImapResponse->ResponseList[3]) + ); + } + + /** + * @param \MailSo\Imap\Response $oImapResponse + * + * @return bool + */ + public static function IsNotEmptyFetchImapResponse($oImapResponse) + { + return ( + $oImapResponse + && self::IsValidFetchImapResponse($oImapResponse) + && isset($oImapResponse->ResponseList[3]) + && self::findFetchUidAndSize($oImapResponse->ResponseList[3]) + ); + } + + /** + * @param array $aEnvelope + * @param int $iIndex + * @param mixed $mNullResult = null + * + * @return mixed + */ + private static function findEnvelopeIndex($aEnvelope, $iIndex, $mNullResult) + { + return (isset($aEnvelope[$iIndex]) && 'NIL' !== $aEnvelope[$iIndex] && '' !== $aEnvelope[$iIndex]) + ? $aEnvelope[$iIndex] : $mNullResult; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/Folder.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/Folder.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/Folder.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/Folder.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/FolderInformation.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/FolderInformation.php similarity index 93% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/FolderInformation.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/FolderInformation.php index d8fe5a0e..bc7118d5 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/FolderInformation.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/FolderInformation.php @@ -1,112 +1,112 @@ -FolderName = $sFolderName; - $this->IsWritable = $bIsWritable; - $this->Exists = null; - $this->Recent = null; - $this->Flags = array(); - $this->PermanentFlags = array(); - - $this->Unread = null; - $this->Uidnext = null; - $this->HighestModSeq = null; - } - - /** - * @param string $sFolderName - * @param bool $bIsWritable - * - * @return \MailSo\Imap\FolderInformation - */ - public static function NewInstance($sFolderName, $bIsWritable) - { - return new self($sFolderName, $bIsWritable); - } - - /** - * @param string $sFlag - * - * @return bool - */ - public function IsFlagSupported($sFlag) - { - return \in_array('\\*', $this->PermanentFlags) || - \in_array($sFlag, $this->PermanentFlags) || - \in_array($sFlag, $this->Flags); - } -} +FolderName = $sFolderName; + $this->IsWritable = $bIsWritable; + $this->Exists = null; + $this->Recent = null; + $this->Flags = array(); + $this->PermanentFlags = array(); + + $this->Unread = null; + $this->Uidnext = null; + $this->HighestModSeq = null; + } + + /** + * @param string $sFolderName + * @param bool $bIsWritable + * + * @return \MailSo\Imap\FolderInformation + */ + public static function NewInstance($sFolderName, $bIsWritable) + { + return new self($sFolderName, $bIsWritable); + } + + /** + * @param string $sFlag + * + * @return bool + */ + public function IsFlagSupported($sFlag) + { + return \in_array('\\*', $this->PermanentFlags) || + \in_array($sFlag, $this->PermanentFlags) || + \in_array($sFlag, $this->Flags); + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/ImapClient.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/ImapClient.php similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/ImapClient.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/ImapClient.php index 19aa9a51..65aba038 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/ImapClient.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/ImapClient.php @@ -1,2667 +1,2669 @@ -iTagCount = 0; - $this->aCapabilityItems = null; - $this->oCurrentFolderInfo = null; - $this->aFetchCallbacks = null; - $this->iResponseBufParsedPos = 0; - - $this->aLastResponse = array(); - $this->bNeedNext = true; - $this->aPartialResponses = array(); - - $this->aTagTimeouts = array(); - - $this->bIsLoggined = false; - $this->bIsSelected = false; - $this->sLogginedUser = ''; - - $this->__FORCE_SELECT_ON_EXAMINE__ = false; - - @\ini_set('xdebug.max_nesting_level', 500); - } - - /** - * @return \MailSo\Imap\ImapClient - */ - public static function NewInstance() - { - return new self(); - } - - /** - * @return string - */ - public function GetLogginedUser() - { - return $this->sLogginedUser; - } - - /** - * @param string $sServerName - * @param int $iPort = 143 - * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT - * @param bool $bVerifySsl = false - * @param bool $bAllowSelfSigned = true - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function Connect($sServerName, $iPort = 143, - $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, - $bVerifySsl = false, $bAllowSelfSigned = true) - { - $this->aTagTimeouts['*'] = \microtime(true); - - parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned); - - $this->parseResponseWithValidation('*', true); - - if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS( - $this->IsSupported('STARTTLS'), $this->iSecurityType)) - { - $this->SendRequestWithCheck('STARTTLS'); - $this->EnableCrypto(); - - $this->aCapabilityItems = null; - } - else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType) - { - $this->writeLogException( - new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - return $this; - } - - 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; - } - - /** - * @param string $sLogin - * @param string $sPassword - * @param string $sProxyAuthUser = '' - * @param bool $bUseAuthPlainIfSupported = true - * @param bool $bUseAuthCramMd5IfSupported = true - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function Login($sLogin, $sPassword, $sProxyAuthUser = '', - $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true) - { - if (!\MailSo\Base\Validator::NotEmptyString($sLogin, true) || - !\MailSo\Base\Validator::NotEmptyString($sPassword, true)) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin)); - - $sPassword = $sPassword; - - $this->sLogginedUser = $sLogin; - - try - { - if ($bUseAuthCramMd5IfSupported && $this->IsSupported('AUTH=CRAM-MD5')) - { - $this->SendRequest('AUTHENTICATE', array('CRAM-MD5')); - - $aResponse = $this->parseResponseWithValidation(); - if ($aResponse && \is_array($aResponse) && 0 < \count($aResponse) && - \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $aResponse[\count($aResponse) - 1]->ResponseType) - { - $oContinuationResponse = null; - foreach ($aResponse as $oResponse) - { - if ($oResponse && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oResponse->ResponseType) - { - $oContinuationResponse = $oResponse; - } - } - - if ($oContinuationResponse && !empty($oContinuationResponse->ResponseList[1])) - { - $sTicket = @\base64_decode($oContinuationResponse->ResponseList[1]); - $this->oLogger->Write('ticket: '.$sTicket); - - $sToken = \base64_encode($sLogin.' '.\MailSo\Base\Utils::Hmac($sTicket, $sPassword)); - - if ($this->oLogger) - { - $this->oLogger->AddSecret($sToken); - } - - $this->sendRaw($sToken, true, '*******'); - $this->parseResponseWithValidation(); - } - else - { - $this->writeLogException( - new \MailSo\Imap\Exceptions\LoginException(), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - } - else - { - $this->writeLogException( - new \MailSo\Imap\Exceptions\LoginException(), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - } - else if ($bUseAuthPlainIfSupported && $this->IsSupported('AUTH=PLAIN')) - { - $sToken = \base64_encode("\0".$sLogin."\0".$sPassword); - if ($this->oLogger) - { - $this->oLogger->AddSecret($sToken); - } - - if ($this->IsSupported('AUTH=SASL-IR') && false) - { - $this->SendRequestWithCheck('AUTHENTICATE', array('PLAIN', $sToken)); - } - else - { - $this->SendRequest('AUTHENTICATE', array('PLAIN')); - $this->parseResponseWithValidation(); - - $this->sendRaw($sToken, true, '*******'); - $this->parseResponseWithValidation(); - } - } - else - { - if ($this->oLogger) - { - $this->oLogger->AddSecret($this->EscapeString($sPassword)); - } - - $this->SendRequestWithCheck('LOGIN', - array( - $this->EscapeString($sLogin), - $this->EscapeString($sPassword) - )); - } -// else -// { -// $this->writeLogException( -// new \MailSo\Imap\Exceptions\LoginBadMethodException(), -// \MailSo\Log\Enumerations\Type::NOTICE, true); -// } - - if (0 < \strlen($sProxyAuthUser)) - { - $this->SendRequestWithCheck('PROXYAUTH', array($this->EscapeString($sProxyAuthUser))); - } - } - catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Imap\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), '', 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - - $this->bIsLoggined = true; - $this->aCapabilityItems = null; - - return $this; - } - - /** - * @param string $sXOAuth2Token - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function LoginWithXOauth2($sXOAuth2Token) - { - if (!\MailSo\Base\Validator::NotEmptyString($sXOAuth2Token, true)) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - if (!$this->IsSupported('AUTH=XOAUTH2')) - { - $this->writeLogException( - new \MailSo\Imap\Exceptions\LoginBadMethodException(), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - - try - { - $this->SendRequest('AUTHENTICATE', array('XOAUTH2', \trim($sXOAuth2Token))); - $aR = $this->parseResponseWithValidation(); - - if (\is_array($aR) && 0 < \count($aR) && isset($aR[\count($aR) - 1])) - { - $oR = $aR[\count($aR) - 1]; - if (\MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oR->ResponseType) - { - if (!empty($oR->ResponseList[1]) && preg_match('/^[a-zA-Z0-9=+\/]+$/', $oR->ResponseList[1])) - { - $this->Logger()->Write(\base64_decode($oR->ResponseList[1]), - \MailSo\Log\Enumerations\Type::WARNING); - } - - $this->sendRaw(''); - $this->parseResponseWithValidation(); - } - } - } - catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Imap\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), '', 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - - $this->bIsLoggined = true; - $this->aCapabilityItems = null; - - return $this; - } - - /** - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Net\Exceptions\Exception - */ - public function Logout() - { - if ($this->bIsLoggined) - { - $this->bIsLoggined = false; - $this->SendRequestWithCheck('LOGOUT', array()); - } - - return $this; - } - - /** - * @return \MailSo\Imap\ImapClient - */ - public function ForceCloseConnection() - { - $this->Disconnect(); - - return $this; - } - - /** - * @return bool - */ - public function IsLoggined() - { - return $this->IsConnected() && $this->bIsLoggined; - } - - /** - * @return bool - */ - public function IsSelected() - { - return $this->IsLoggined() && $this->bIsSelected; - } - - /** - * @return array|null - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function Capability() - { - $this->SendRequestWithCheck('CAPABILITY', array(), true); - return $this->aCapabilityItems; - } - - /** - * @param string $sExtentionName - * @return bool - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function IsSupported($sExtentionName) - { - $bResult = \MailSo\Base\Validator::NotEmptyString($sExtentionName, true); - if ($bResult && null === $this->aCapabilityItems) - { - $this->aCapabilityItems = $this->Capability(); - } - - return $bResult && \is_array($this->aCapabilityItems) && - \in_array(\strtoupper($sExtentionName), $this->aCapabilityItems); - } - - /** - * @return \MailSo\Imap\NamespaceResult|null - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function GetNamespace() - { - if (!$this->IsSupported('NAMESPACE')) - { - return null; - } - - $oReturn = false; - - $this->SendRequest('NAMESPACE'); - $aResult = $this->parseResponseWithValidation(); - - $oImapResponse = null; - foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType && - 'NAMESPACE' === $oImapResponse->StatusOrIndex) - { - $oReturn = NamespaceResult::NewInstance(); - $oReturn->InitByImapResponse($oImapResponse); - break; - } - } - - if (false === $oReturn) - { - $this->writeLogException( - new \MailSo\Imap\Exceptions\ResponseException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - return $oReturn; - } - - /** - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function Noop() - { - return $this->SendRequestWithCheck('NOOP'); - } - - /** - * @param string $sFolderName - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderCreate($sFolderName) - { - return $this->SendRequestWithCheck('CREATE', - array($this->EscapeString($sFolderName))); - } - - /** - * @param string $sFolderName - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderDelete($sFolderName) - { - return $this->SendRequestWithCheck('DELETE', - array($this->EscapeString($sFolderName))); - } - - /** - * @param string $sFolderName - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderSubscribe($sFolderName) - { - return $this->SendRequestWithCheck('SUBSCRIBE', - array($this->EscapeString($sFolderName))); - } - - /** - * @param string $sFolderName - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderUnSubscribe($sFolderName) - { - return $this->SendRequestWithCheck('UNSUBSCRIBE', - array($this->EscapeString($sFolderName))); - } - - /** - * @param string $sOldFolderName - * @param string $sNewFolderName - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderRename($sOldFolderName, $sNewFolderName) - { - return $this->SendRequestWithCheck('RENAME', array( - $this->EscapeString($sOldFolderName), - $this->EscapeString($sNewFolderName))); - } - - /** - * @param array $aResult - * - * @return array - */ - protected function getStatusFolderInformation($aResult) - { - $aReturn = array(); - - if (\is_array($aResult)) - { - $oImapResponse = null; - foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType && - 'STATUS' === $oImapResponse->StatusOrIndex && isset($oImapResponse->ResponseList[3]) && - \is_array($oImapResponse->ResponseList[3])) - { - $sName = null; - foreach ($oImapResponse->ResponseList[3] as $sArrayItem) - { - if (null === $sName) - { - $sName = $sArrayItem; - } - else - { - $aReturn[$sName] = $sArrayItem; - $sName = null; - } - } - } - } - } - - return $aReturn; - } - - /** - * @param string $sFolderName - * @param array $aStatusItems - * - * @return array|bool - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderStatus($sFolderName, array $aStatusItems) - { - $aResult = false; - if (\count($aStatusItems) > 0) - { - $this->SendRequest('STATUS', - array($this->EscapeString($sFolderName), $aStatusItems)); - - $aResult = $this->getStatusFolderInformation( - $this->parseResponseWithValidation()); - } - - return $aResult; - } - - /** - * @param array $aResult - * @param string $sStatus - * @param bool $bUseListStatus = false - * - * @return array - */ - private function getFoldersFromResult(array $aResult, $sStatus, $bUseListStatus = false) - { - $aReturn = array(); - - $sDelimiter = ''; - $bInbox = false; - - $oImapResponse = null; - foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType && - $sStatus === $oImapResponse->StatusOrIndex && 5 === count($oImapResponse->ResponseList)) - { - try - { - $oFolder = Folder::NewInstance($oImapResponse->ResponseList[4], - $oImapResponse->ResponseList[3], $oImapResponse->ResponseList[2]); - - if ($oFolder->IsInbox()) - { - $bInbox = true; - } - - if (empty($sDelimiter)) - { - $sDelimiter = $oFolder->Delimiter(); - } - - $aReturn[] = $oFolder; - } - catch (\MailSo\Base\Exceptions\InvalidArgumentException $oException) - { - $this->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false); - } - } - } - - if (!$bInbox && !empty($sDelimiter)) - { - $aReturn[] = Folder::NewInstance('INBOX', $sDelimiter); - } - - if ($bUseListStatus) - { - foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType && - 'STATUS' === $oImapResponse->StatusOrIndex && - isset($oImapResponse->ResponseList[2]) && - isset($oImapResponse->ResponseList[3]) && - \is_array($oImapResponse->ResponseList[3])) - { - $sFolderNameRaw = $oImapResponse->ResponseList[2]; - - $oCurrentFolder = null; - foreach ($aReturn as &$oFolder) - { - if ($oFolder && $sFolderNameRaw === $oFolder->FullNameRaw()) - { - $oCurrentFolder =& $oFolder; - break; - } - } - - if (null !== $oCurrentFolder) - { - $sName = null; - $aStatus = array(); - - foreach ($oImapResponse->ResponseList[3] as $sArrayItem) - { - if (null === $sName) - { - $sName = $sArrayItem; - } - else - { - $aStatus[$sName] = $sArrayItem; - $sName = null; - } - } - - if (0 < count($aStatus)) - { - $oCurrentFolder->SetExtended('STATUS', $aStatus); - } - } - - unset($oCurrentFolder); - } - } - } - - return $aReturn; - } - - /** - * @param bool $bIsSubscribeList - * @param string $sParentFolderName = '' - * @param string $sListPattern = '*' - * @param bool $bUseListStatus = false - * - * @return array - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - private function specificFolderList($bIsSubscribeList, $sParentFolderName = '', $sListPattern = '*', $bUseListStatus = false) - { - $sCmd = 'LSUB'; - if (!$bIsSubscribeList) - { - $sCmd = 'LIST'; - } - - $sListPattern = 0 === strlen(trim($sListPattern)) ? '*' : $sListPattern; - - $aParameters = array( - $this->EscapeString($sParentFolderName), - $this->EscapeString($sListPattern) - ); - - if ($bUseListStatus && !$bIsSubscribeList && $this->IsSupported('LIST-STATUS')) - { - $aL = array( - \MailSo\Imap\Enumerations\FolderStatus::MESSAGES, - \MailSo\Imap\Enumerations\FolderStatus::UNSEEN, - \MailSo\Imap\Enumerations\FolderStatus::UIDNEXT - ); - -// if ($this->IsSupported('CONDSTORE')) -// { -// $aL[] = \MailSo\Imap\Enumerations\FolderStatus::HIGHESTMODSEQ; -// } - - $aParameters[] = 'RETURN'; - $aParameters[] = array('STATUS', $aL); - } - else - { - $bUseListStatus = false; - } - - $this->SendRequest($sCmd, $aParameters); - - return $this->getFoldersFromResult( - $this->parseResponseWithValidation(), $sCmd, $bUseListStatus); - } - - /** - * @param string $sParentFolderName = '' - * @param string $sListPattern = '*' - * - * @return array - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderList($sParentFolderName = '', $sListPattern = '*') - { - return $this->specificFolderList(false, $sParentFolderName, $sListPattern); - } - - /** - * @param string $sParentFolderName = '' - * @param string $sListPattern = '*' - * - * @return array - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderSubscribeList($sParentFolderName = '', $sListPattern = '*') - { - return $this->specificFolderList(true, $sParentFolderName, $sListPattern); - } - - /** - * @param string $sParentFolderName = '' - * @param string $sListPattern = '*' - * - * @return array - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderStatusList($sParentFolderName = '', $sListPattern = '*') - { - return $this->specificFolderList(false, $sParentFolderName, $sListPattern, true); - } - - /** - * @param array $aResult - * @param string $sFolderName - * @param bool $bIsWritable - * - * @return void - */ - protected function initCurrentFolderInformation($aResult, $sFolderName, $bIsWritable) - { - if (\is_array($aResult)) - { - $oImapResponse = null; - $oResult = FolderInformation::NewInstance($sFolderName, $bIsWritable); - - foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType) - { - if (\count($oImapResponse->ResponseList) > 2 && - 'FLAGS' === $oImapResponse->ResponseList[1] && \is_array($oImapResponse->ResponseList[2])) - { - $oResult->Flags = $oImapResponse->ResponseList[2]; - } - - if (is_array($oImapResponse->OptionalResponse) && \count($oImapResponse->OptionalResponse) > 1) - { - if ('PERMANENTFLAGS' === $oImapResponse->OptionalResponse[0] && - is_array($oImapResponse->OptionalResponse[1])) - { - $oResult->PermanentFlags = $oImapResponse->OptionalResponse[1]; - } - else if ('UIDVALIDITY' === $oImapResponse->OptionalResponse[0] && - isset($oImapResponse->OptionalResponse[1])) - { - $oResult->Uidvalidity = $oImapResponse->OptionalResponse[1]; - } - else if ('UNSEEN' === $oImapResponse->OptionalResponse[0] && - isset($oImapResponse->OptionalResponse[1]) && - is_numeric($oImapResponse->OptionalResponse[1])) - { - $oResult->Unread = (int) $oImapResponse->OptionalResponse[1]; - } - else if ('UIDNEXT' === $oImapResponse->OptionalResponse[0] && - isset($oImapResponse->OptionalResponse[1])) - { - $oResult->Uidnext = $oImapResponse->OptionalResponse[1]; - } - else if ('HIGHESTMODSEQ' === $oImapResponse->OptionalResponse[0] && - isset($oImapResponse->OptionalResponse[1]) && - \is_numeric($oImapResponse->OptionalResponse[1])) - { - $oResult->HighestModSeq = \trim($oImapResponse->OptionalResponse[1]); - } - } - - if (\count($oImapResponse->ResponseList) > 2 && - \is_string($oImapResponse->ResponseList[2]) && - \is_numeric($oImapResponse->ResponseList[1])) - { - switch($oImapResponse->ResponseList[2]) - { - case 'EXISTS': - $oResult->Exists = (int) $oImapResponse->ResponseList[1]; - break; - case 'RECENT': - $oResult->Recent = (int) $oImapResponse->ResponseList[1]; - break; - } - } - } - } - - $this->oCurrentFolderInfo = $oResult; - } - } - - /** - * @param string $sFolderName - * @param bool $bIsWritable - * @param bool $bReSelectSameFolders - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - protected function selectOrExamineFolder($sFolderName, $bIsWritable, $bReSelectSameFolders) - { - if (!$bReSelectSameFolders) - { - if ($this->oCurrentFolderInfo && - $sFolderName === $this->oCurrentFolderInfo->FolderName && - $bIsWritable === $this->oCurrentFolderInfo->IsWritable) - { - return $this; - } - } - - if (!\MailSo\Base\Validator::NotEmptyString($sFolderName, true)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->SendRequest(($bIsWritable) ? 'SELECT' : 'EXAMINE', - array($this->EscapeString($sFolderName))); - - $this->initCurrentFolderInformation( - $this->parseResponseWithValidation(), $sFolderName, $bIsWritable); - - $this->bIsSelected = true; - - return $this; - } - - /** - * @param string $sFolderName - * @param bool $bReSelectSameFolders = false - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderSelect($sFolderName, $bReSelectSameFolders = false) - { - return $this->selectOrExamineFolder($sFolderName, true, $bReSelectSameFolders); - } - - /** - * @param string $sFolderName - * @param bool $bReSelectSameFolders = false - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderExamine($sFolderName, $bReSelectSameFolders = false) - { - return $this->selectOrExamineFolder($sFolderName, $this->__FORCE_SELECT_ON_EXAMINE__, $bReSelectSameFolders); - } - - /** - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderUnSelect() - { - if ($this->IsSelected() && $this->IsSupported('UNSELECT')) - { - $this->SendRequestWithCheck('UNSELECT'); - $this->bIsSelected = false; - } - - return $this; - } - - /** - * @param array $aInputFetchItems - * @param string $sIndexRange - * @param bool $bIndexIsUid - * - * @return array - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function Fetch(array $aInputFetchItems, $sIndexRange, $bIndexIsUid) - { - $sIndexRange = (string) $sIndexRange; - if (!\MailSo\Base\Validator::NotEmptyString($sIndexRange, true)) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $aFetchItems = \MailSo\Imap\Enumerations\FetchType::ChangeFetchItemsBefourRequest($aInputFetchItems); - foreach ($aFetchItems as $sName => $mItem) - { - if (0 < \strlen($sName) && '' !== $mItem) - { - if (null === $this->aFetchCallbacks) - { - $this->aFetchCallbacks = array(); - } - - $this->aFetchCallbacks[$sName] = $mItem; - } - } - - $this->SendRequest((($bIndexIsUid) ? 'UID ' : '').'FETCH', array($sIndexRange, \array_keys($aFetchItems))); - $aResult = $this->validateResponse($this->parseResponse()); - $this->aFetchCallbacks = null; - - $aReturn = array(); - $oImapResponse = null; - foreach ($aResult as $oImapResponse) - { - if (FetchResponse::IsValidFetchImapResponse($oImapResponse)) - { - if (FetchResponse::IsNotEmptyFetchImapResponse($oImapResponse)) - { - $aReturn[] = FetchResponse::NewInstance($oImapResponse); - } - else - { - if ($this->oLogger) - { - $this->oLogger->Write('Skipped Imap Response! ['.$oImapResponse->ToLine().']', \MailSo\Log\Enumerations\Type::NOTICE); - } - } - } - } - - return $aReturn; - } - - - /** - * @return array|false - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function Quota() - { - $aReturn = false; - if ($this->IsSupported('QUOTA')) - { - $this->SendRequest('GETQUOTAROOT "INBOX"'); - $aResult = $this->parseResponseWithValidation(); - - $aReturn = array(0, 0); - $oImapResponse = null; - foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType - && 'QUOTA' === $oImapResponse->StatusOrIndex - && \is_array($oImapResponse->ResponseList) - && isset($oImapResponse->ResponseList[3]) - && \is_array($oImapResponse->ResponseList[3]) - && 2 < \count($oImapResponse->ResponseList[3]) - && 'STORAGE' === \strtoupper($oImapResponse->ResponseList[3][0]) - && \is_numeric($oImapResponse->ResponseList[3][1]) - && \is_numeric($oImapResponse->ResponseList[3][2]) - ) - { - $aReturn = array( - (int) $oImapResponse->ResponseList[3][1], - (int) $oImapResponse->ResponseList[3][2], - 0, - 0 - ); - - if (5 < \count($oImapResponse->ResponseList[3]) - && 'MESSAGE' === \strtoupper($oImapResponse->ResponseList[3][3]) - && \is_numeric($oImapResponse->ResponseList[3][4]) - && \is_numeric($oImapResponse->ResponseList[3][5]) - ) - { - $aReturn[2] = (int) $oImapResponse->ResponseList[3][4]; - $aReturn[3] = (int) $oImapResponse->ResponseList[3][5]; - } - } - } - } - - return $aReturn; - } - - /** - * @param array $aSortTypes - * @param string $sSearchCriterias - * @param bool $bReturnUid - * - * @return array - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageSimpleSort($aSortTypes, $sSearchCriterias = 'ALL', $bReturnUid = true) - { - $sCommandPrefix = ($bReturnUid) ? 'UID ' : ''; - $sSearchCriterias = !\MailSo\Base\Validator::NotEmptyString($sSearchCriterias, true) || '*' === $sSearchCriterias - ? 'ALL' : $sSearchCriterias; - - if (!\is_array($aSortTypes) || 0 === \count($aSortTypes)) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - else if (!$this->IsSupported('SORT')) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $aRequest = array(); - $aRequest[] = $aSortTypes; - $aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8'; - $aRequest[] = $sSearchCriterias; - - $sCmd = 'SORT'; - - $this->SendRequest($sCommandPrefix.$sCmd, $aRequest); - $aResult = $this->parseResponseWithValidation(); - - $aReturn = array(); - $oImapResponse = null; - foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType - && ($sCmd === $oImapResponse->StatusOrIndex || - ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) && - $sCmd === $oImapResponse->ResponseList[2]) - && \is_array($oImapResponse->ResponseList) - && 2 < \count($oImapResponse->ResponseList)) - { - $iStart = 2; - if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex && - !empty($oImapResponse->ResponseList[2]) && - $sCmd === $oImapResponse->ResponseList[2]) - { - $iStart = 3; - } - - for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++) - { - $aReturn[] = (int) $oImapResponse->ResponseList[$iIndex]; - } - } - } - - return $aReturn; - } - - /** - * @param bool $bSort = false - * @param string $sSearchCriterias = 'ALL' - * @param array $aSearchOrSortReturn = null - * @param bool $bReturnUid = true - * @param string $sLimit = '' - * @param string $sCharset = '' - * @param array $aSortTypes = null - * - * @return array - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - private function simpleESearchOrESortHelper($bSort = false, $sSearchCriterias = 'ALL', $aSearchOrSortReturn = null, $bReturnUid = true, $sLimit = '', $sCharset = '', $aSortTypes = null) - { - $sCommandPrefix = ($bReturnUid) ? 'UID ' : ''; - $sSearchCriterias = 0 === \strlen($sSearchCriterias) || '*' === $sSearchCriterias - ? 'ALL' : $sSearchCriterias; - - $sCmd = $bSort ? 'SORT': 'SEARCH'; - if ($bSort && (!\is_array($aSortTypes) || 0 === \count($aSortTypes) || !$this->IsSupported('SORT'))) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - if (!$this->IsSupported($bSort ? 'ESORT' : 'ESEARCH')) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - if (!\is_array($aSearchOrSortReturn) || 0 === \count($aSearchOrSortReturn)) - { - $aSearchOrSortReturn = array('ALL'); - } - - $aRequest = array(); - if ($bSort) - { - $aRequest[] = 'RETURN'; - $aRequest[] = $aSearchOrSortReturn; - - $aRequest[] = $aSortTypes; - $aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8'; - } - else - { - if (0 < \strlen($sCharset)) - { - $aRequest[] = 'CHARSET'; - $aRequest[] = \strtoupper($sCharset); - } - - $aRequest[] = 'RETURN'; - $aRequest[] = $aSearchOrSortReturn; - } - - $aRequest[] = $sSearchCriterias; - - if (0 < \strlen($sLimit)) - { - $aRequest[] = $sLimit; - } - - $this->SendRequest($sCommandPrefix.$sCmd, $aRequest); - $sRequestTag = $this->getCurrentTag(); - - $aResult = array(); - $aResponse = $this->parseResponseWithValidation(); - - if (\is_array($aResponse)) - { - $oImapResponse = null; - foreach ($aResponse as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType - && ('ESEARCH' === $oImapResponse->StatusOrIndex || 'ESORT' === $oImapResponse->StatusOrIndex) - && \is_array($oImapResponse->ResponseList) - && isset($oImapResponse->ResponseList[2], $oImapResponse->ResponseList[2][0], $oImapResponse->ResponseList[2][1]) - && 'TAG' === $oImapResponse->ResponseList[2][0] && $sRequestTag === $oImapResponse->ResponseList[2][1] - && (!$bReturnUid || ($bReturnUid && !empty($oImapResponse->ResponseList[3]) && 'UID' === $oImapResponse->ResponseList[3])) - ) - { - $iStart = 3; - foreach ($oImapResponse->ResponseList as $iIndex => $mItem) - { - if ($iIndex >= $iStart) - { - switch ($mItem) - { - case 'ALL': - case 'MAX': - case 'MIN': - case 'COUNT': - if (isset($oImapResponse->ResponseList[$iIndex + 1])) - { - $aResult[$mItem] = $oImapResponse->ResponseList[$iIndex + 1]; - } - break; - } - } - } - } - } - } - - return $aResult; - } - - /** - * @param string $sSearchCriterias = 'ALL' - * @param array $aSearchReturn = null - * @param bool $bReturnUid = true - * @param string $sLimit = '' - * @param string $sCharset = '' - * - * @return array - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageSimpleESearch($sSearchCriterias = 'ALL', $aSearchReturn = null, $bReturnUid = true, $sLimit = '', $sCharset = '') - { - return $this->simpleESearchOrESortHelper(false, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, $sCharset); - } - - /** - * @param array $aSortTypes - * @param string $sSearchCriterias = 'ALL' - * @param array $aSearchReturn = null - * @param bool $bReturnUid = true - * @param string $sLimit = '' - * - * @return array - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageSimpleESort($aSortTypes, $sSearchCriterias = 'ALL', $aSearchReturn = null, $bReturnUid = true, $sLimit = '') - { - return $this->simpleESearchOrESortHelper(true, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, '', $aSortTypes); - } - - /** - * @param array $aResult - * @return \MailSo\Imap\Response - */ - private function findLastResponse($aResult) - { - $oResult = null; - if (\is_array($aResult) && 0 < \count($aResult)) - { - $oResult = $aResult[\count($aResult) - 1]; - if (!($oResult instanceof \MailSo\Imap\Response)) - { - $oResult = null; - } - } - - return $oResult; - } - - /** - * @param string $sSearchCriterias - * @param bool $bReturnUid = true - * @param string $sCharset = '' - * - * @return array - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageSimpleSearch($sSearchCriterias = 'ALL', $bReturnUid = true, $sCharset = '') - { - $sCommandPrefix = ($bReturnUid) ? 'UID ' : ''; - $sSearchCriterias = 0 === \strlen($sSearchCriterias) || '*' === $sSearchCriterias - ? 'ALL' : $sSearchCriterias; - - $aRequest = array(); - if (0 < \strlen($sCharset)) - { - $aRequest[] = 'CHARSET'; - $aRequest[] = \strtoupper($sCharset); - } - - $aRequest[] = $sSearchCriterias; - - $sCmd = 'SEARCH'; - - $sCont = $this->SendRequest($sCommandPrefix.$sCmd, $aRequest, true); - if ('' !== $sCont) - { - $aResult = $this->parseResponseWithValidation(); - $oItem = $this->findLastResponse($aResult); - - if ($oItem && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oItem->ResponseType) - { - $aParts = explode("\r\n", $sCont); - foreach ($aParts as $sLine) - { - $this->sendRaw($sLine); - - $aResult = $this->parseResponseWithValidation(); - $oItem = $this->findLastResponse($aResult); - if ($oItem && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oItem->ResponseType) - { - continue; - } - } - } - } - else - { - $aResult = $this->parseResponseWithValidation(); - } - - $aReturn = array(); - $oImapResponse = null; - foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType - && ($sCmd === $oImapResponse->StatusOrIndex || - ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) && - $sCmd === $oImapResponse->ResponseList[2]) - && \is_array($oImapResponse->ResponseList) - && 2 < count($oImapResponse->ResponseList)) - { - $iStart = 2; - if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex && - !empty($oImapResponse->ResponseList[2]) && - $sCmd === $oImapResponse->ResponseList[2]) - { - $iStart = 3; - } - - for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++) - { - $aReturn[] = (int) $oImapResponse->ResponseList[$iIndex]; - } - } - } - - $aReturn = \array_reverse($aReturn); - return $aReturn; - } - - /** - * @param mixed $aValue - * - * @return mixed - */ - private function validateThreadItem($aValue) - { - $mResult = false; - if (\is_numeric($aValue)) - { - $mResult = (int) $aValue; - if (0 >= $mResult) - { - $mResult = false; - } - } - else if (\is_array($aValue)) - { - if (1 === \count($aValue) && \is_numeric($aValue[0])) - { - $mResult = (int) $aValue[0]; - if (0 >= $mResult) - { - $mResult = false; - } - } - else - { - $mResult = array(); - foreach ($aValue as $aValueItem) - { - $mTemp = $this->validateThreadItem($aValueItem); - if (false !== $mTemp) - { - $mResult[] = $mTemp; - } - } - } - } - - return $mResult; - } - - /** - * @param string $sSearchCriterias = 'ALL' - * @param bool $bReturnUid = true - * @param string $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8 - * - * @return array - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageSimpleThread($sSearchCriterias = 'ALL', $bReturnUid = true, $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8) - { - $sCommandPrefix = ($bReturnUid) ? 'UID ' : ''; - $sSearchCriterias = !\MailSo\Base\Validator::NotEmptyString($sSearchCriterias, true) || '*' === $sSearchCriterias - ? 'ALL' : $sSearchCriterias; - - $sThreadType = ''; - switch (true) - { - case $this->IsSupported('THREAD=REFS'): - $sThreadType = 'REFS'; - break; - case $this->IsSupported('THREAD=REFERENCES'): - $sThreadType = 'REFERENCES'; - break; - case $this->IsSupported('THREAD=ORDEREDSUBJECT'): - $sThreadType = 'ORDEREDSUBJECT'; - break; - default: - $this->writeLogException( - new Exceptions\RuntimeException('Thread is not supported'), - \MailSo\Log\Enumerations\Type::ERROR, true); - break; - } - - $aRequest = array(); - $aRequest[] = $sThreadType; - $aRequest[] = \strtoupper($sCharset); - $aRequest[] = $sSearchCriterias; - - $sCmd = 'THREAD'; - - $this->SendRequest($sCommandPrefix.$sCmd, $aRequest); - $aResult = $this->parseResponseWithValidation(); - - $aReturn = array(); - $oImapResponse = null; - - foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType - && ($sCmd === $oImapResponse->StatusOrIndex || - ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) && - $sCmd === $oImapResponse->ResponseList[2]) - && \is_array($oImapResponse->ResponseList) - && 2 < \count($oImapResponse->ResponseList)) - { - $iStart = 2; - if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex && - !empty($oImapResponse->ResponseList[2]) && - $sCmd === $oImapResponse->ResponseList[2]) - { - $iStart = 3; - } - - for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++) - { - $aNewValue = $this->validateThreadItem($oImapResponse->ResponseList[$iIndex]); - if (false !== $aNewValue) - { - $aReturn[] = $aNewValue; - } - } - } - } - - return $aReturn; - } - - /** - * @param string $sToFolder - * @param string $sIndexRange - * @param bool $bIndexIsUid - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageCopy($sToFolder, $sIndexRange, $bIndexIsUid) - { - if (0 === \strlen($sIndexRange)) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $sCommandPrefix = ($bIndexIsUid) ? 'UID ' : ''; - return $this->SendRequestWithCheck($sCommandPrefix.'COPY', - array($sIndexRange, $this->EscapeString($sToFolder))); - } - - /** - * @param string $sToFolder - * @param string $sIndexRange - * @param bool $bIndexIsUid - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageMove($sToFolder, $sIndexRange, $bIndexIsUid) - { - if (0 === \strlen($sIndexRange)) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - if (!$this->IsSupported('MOVE')) - { - $this->writeLogException( - new Exceptions\RuntimeException('Move is not supported'), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $sCommandPrefix = ($bIndexIsUid) ? 'UID ' : ''; - return $this->SendRequestWithCheck($sCommandPrefix.'MOVE', - array($sIndexRange, $this->EscapeString($sToFolder))); - } - - /** - * @param string $sUidRangeIfSupported = '' - * @param bool $bForceUidExpunge = false - * @param bool $bExpungeAll = false - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageExpunge($sUidRangeIfSupported = '', $bForceUidExpunge = false, $bExpungeAll = false) - { - $sUidRangeIfSupported = \trim($sUidRangeIfSupported); - - $sCmd = 'EXPUNGE'; - $aArguments = array(); - - if (!$bExpungeAll && $bForceUidExpunge && 0 < \strlen($sUidRangeIfSupported) && $this->IsSupported('UIDPLUS')) - { - $sCmd = 'UID '.$sCmd; - $aArguments = array($sUidRangeIfSupported); - } - - return $this->SendRequestWithCheck($sCmd, $aArguments); - } - - /** - * @param string $sIndexRange - * @param bool $bIndexIsUid - * @param array $aInputStoreItems - * @param string $sStoreAction - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageStoreFlag($sIndexRange, $bIndexIsUid, $aInputStoreItems, $sStoreAction) - { - if (!\MailSo\Base\Validator::NotEmptyString($sIndexRange, true) || - !\MailSo\Base\Validator::NotEmptyString($sStoreAction, true) || - 0 === \count($aInputStoreItems)) - { - return false; - } - - $sCmd = ($bIndexIsUid) ? 'UID STORE' : 'STORE'; - return $this->SendRequestWithCheck($sCmd, array($sIndexRange, $sStoreAction, $aInputStoreItems)); - } - - /** - * @param string $sFolderName - * @param resource $rMessageAppendStream - * @param int $iStreamSize - * @param array $aAppendFlags = null - * @param int $iUid = null - * @param int $sDateTime = 0 - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageAppendStream($sFolderName, $rMessageAppendStream, $iStreamSize, $aAppendFlags = null, &$iUid = null, $sDateTime = 0) - { - $aData = array($this->EscapeString($sFolderName), $aAppendFlags); - if (0 < $sDateTime) - { - $aData[] = $this->EscapeString(\gmdate('d-M-Y H:i:s', $sDateTime).' +0000'); - } - - $aData[] = '{'.$iStreamSize.'}'; - - $this->SendRequest('APPEND', $aData); - $this->parseResponseWithValidation(); - - $this->writeLog('Write to connection stream', \MailSo\Log\Enumerations\Type::NOTE); - - \MailSo\Base\Utils::MultipleStreamWriter($rMessageAppendStream, array($this->rConnect)); - - $this->sendRaw(''); - $this->parseResponseWithValidation(); - - if (null !== $iUid) - { - $aLastResponse = $this->GetLastResponse(); - if (\is_array($aLastResponse) && 0 < \count($aLastResponse) && $aLastResponse[\count($aLastResponse) - 1]) - { - $oLast = $aLastResponse[count($aLastResponse) - 1]; - if ($oLast && \MailSo\Imap\Enumerations\ResponseType::TAGGED === $oLast->ResponseType && \is_array($oLast->OptionalResponse)) - { - if (0 < \strlen($oLast->OptionalResponse[0]) && - 0 < \strlen($oLast->OptionalResponse[2]) && - 'APPENDUID' === strtoupper($oLast->OptionalResponse[0]) && - \is_numeric($oLast->OptionalResponse[2]) - ) - { - $iUid = (int) $oLast->OptionalResponse[2]; - } - } - } - } - - return $this; - } - - /** - * @return \MailSo\Imap\FolderInformation - */ - public function FolderCurrentInformation() - { - return $this->oCurrentFolderInfo; - } - - /** - * @param string $sCommand - * @param array $aParams = array() - * @param bool $bBreakOnLiteral = false - * - * @return string - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - */ - public function SendRequest($sCommand, $aParams = array(), $bBreakOnLiteral = false) - { - if (!\MailSo\Base\Validator::NotEmptyString($sCommand, true) || !\is_array($aParams)) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $this->IsConnected(true); - - $sTag = $this->getNewTag(); - - $sCommand = \trim($sCommand); - $sRealCommand = $sTag.' '.$sCommand.$this->prepearParamLine($aParams); - - $sFakeCommand = ''; - $aFakeParams = $this->secureRequestParams($sCommand, $aParams); - if (null !== $aFakeParams) - { - $sFakeCommand = $sTag.' '.$sCommand.$this->prepearParamLine($aFakeParams); - } - - $this->aTagTimeouts[$sTag] = \microtime(true); - - if ($bBreakOnLiteral && !\preg_match('/\d\+\}\r\n/', $sRealCommand)) - { - $iPos = \strpos($sRealCommand, "}\r\n"); - if (false !== $iPos) - { - $iFakePos = \strpos($sFakeCommand, "}\r\n"); - - $this->sendRaw(\substr($sRealCommand, 0, $iPos + 1), true, - false !== $iFakePos ? \substr($sFakeCommand, 0, $iFakePos + 3) : ''); - - return \substr($sRealCommand, $iPos + 3); - } - } - - $this->sendRaw($sRealCommand, true, $sFakeCommand); - return ''; - } - - /** - * @param string $sCommand - * @param array $aParams - * - * @return array|null - */ - private function secureRequestParams($sCommand, $aParams) - { - $aResult = null; - switch ($sCommand) - { - case 'LOGIN': - $aResult = $aParams; - if (\is_array($aResult) && 2 === count($aResult)) - { - $aResult[1] = '"********"'; - } - break; - } - - return $aResult; - } - - /** - * @param string $sCommand - * @param array $aParams = array() - * @param bool $bFindCapa = false - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function SendRequestWithCheck($sCommand, $aParams = array(), $bFindCapa = false) - { - $this->SendRequest($sCommand, $aParams); - $this->parseResponseWithValidation(null, $bFindCapa); - - return $this; - } - - /** - * @return array - */ - public function GetLastResponse() - { - return $this->aLastResponse; - } - - /** - * @param mixed $aResult - * - * @return array - * - * @throws \MailSo\Imap\Exceptions\ResponseNotFoundException - * @throws \MailSo\Imap\Exceptions\InvalidResponseException - * @throws \MailSo\Imap\Exceptions\NegativeResponseException - */ - private function validateResponse($aResult) - { - if (!\is_array($aResult) || 0 === $iCnt = \count($aResult)) - { - $this->writeLogException( - new Exceptions\ResponseNotFoundException(), - \MailSo\Log\Enumerations\Type::WARNING, true); - } - - if ($aResult[$iCnt - 1]->ResponseType !== \MailSo\Imap\Enumerations\ResponseType::CONTINUATION) - { - if (!$aResult[$iCnt - 1]->IsStatusResponse) - { - $this->writeLogException( - new Exceptions\InvalidResponseException($aResult), - \MailSo\Log\Enumerations\Type::WARNING, true); - } - - if (\MailSo\Imap\Enumerations\ResponseStatus::OK !== $aResult[$iCnt - 1]->StatusOrIndex) - { - $this->writeLogException( - new Exceptions\NegativeResponseException($aResult), - \MailSo\Log\Enumerations\Type::WARNING, true); - } - } - - return $aResult; - } - - /** - * @param string $sEndTag = null - * @param bool $bFindCapa = false - * - * @return array|bool - */ - protected function parseResponse($sEndTag = null, $bFindCapa = false) - { - if (\is_resource($this->rConnect)) - { - $oImapResponse = null; - $sEndTag = (null === $sEndTag) ? $this->getCurrentTag() : $sEndTag; - - while (true) - { - $oImapResponse = Response::NewInstance(); - - $this->partialParseResponseBranch($oImapResponse); - - if ($oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNKNOWN === $oImapResponse->ResponseType) - { - return false; - } - - if ($bFindCapa) - { - $this->initCapabilityImapResponse($oImapResponse); - } - - $this->aPartialResponses[] = $oImapResponse; - if ($sEndTag === $oImapResponse->Tag || \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oImapResponse->ResponseType) - { - if (isset($this->aTagTimeouts[$sEndTag])) - { - $this->writeLog((\microtime(true) - $this->aTagTimeouts[$sEndTag]).' ('.$sEndTag.')', - \MailSo\Log\Enumerations\Type::TIME); - - unset($this->aTagTimeouts[$sEndTag]); - } - - break; - } - } - else - { - return false; - } - - unset($oImapResponse); - } - } - - $this->iResponseBufParsedPos = 0; - $this->aLastResponse = $this->aPartialResponses; - $this->aPartialResponses = array(); - - return $this->aLastResponse; - } - - /** - * @param string $sEndTag = null - * @param bool $bFindCapa = false - * - * @return array - */ - private function parseResponseWithValidation($sEndTag = null, $bFindCapa = false) - { - return $this->validateResponse($this->parseResponse($sEndTag, $bFindCapa)); - } - - /** - * @param \MailSo\Imap\Response $oImapResponse - * - * @return void - */ - private function initCapabilityImapResponse($oImapResponse) - { - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType - && \is_array($oImapResponse->ResponseList)) - { - $aList = null; - if (isset($oImapResponse->ResponseList[1]) && \is_string($oImapResponse->ResponseList[1]) && - 'CAPABILITY' === \strtoupper($oImapResponse->ResponseList[1])) - { - $aList = \array_slice($oImapResponse->ResponseList, 2); - } - else if ($oImapResponse->OptionalResponse && \is_array($oImapResponse->OptionalResponse) && - 1 < \count($oImapResponse->OptionalResponse) && \is_string($oImapResponse->OptionalResponse[0]) && - 'CAPABILITY' === \strtoupper($oImapResponse->OptionalResponse[0])) - { - $aList = \array_slice($oImapResponse->OptionalResponse, 1); - } - - if (\is_array($aList) && 0 < \count($aList)) - { - $this->aCapabilityItems = \array_map('strtoupper', $aList); - } - } - } - - /** - * @return array|string - * - * @throws \MailSo\Net\Exceptions\Exception - */ - private function partialParseResponseBranch(&$oImapResponse, $iStackIndex = -1, - $bTreatAsAtom = false, $sParentToken = '', $sOpenBracket = '') - { - $mNull = null; - - $iStackIndex++; - $iPos = $this->iResponseBufParsedPos; - - $sPreviousAtomUpperCase = null; - $bIsEndOfList = false; - $bIsClosingBracketSquare = false; - $iLiteralLen = 0; - $iBufferEndIndex = 0; - $iDebugCount = 0; - - $rImapLiteralStream = null; - - $bIsGotoDefault = false; - $bIsGotoLiteral = false; - $bIsGotoLiteralEnd = false; - $bIsGotoAtomBracket = false; - $bIsGotoNotAtomBracket = false; - - $bCountOneInited = false; - $bCountTwoInited = false; - - $sAtomBuilder = $bTreatAsAtom ? '' : null; - $aList = array(); - if (null !== $oImapResponse) - { - $aList =& $oImapResponse->ResponseList; - } - - while (!$bIsEndOfList) - { - $iDebugCount++; - if (100000 === $iDebugCount) - { - $this->Logger()->Write('PartialParseOver: '.$iDebugCount, \MailSo\Log\Enumerations\Type::ERROR); - } - - if ($this->bNeedNext) - { - $iPos = 0; - $this->getNextBuffer(); - $this->iResponseBufParsedPos = $iPos; - $this->bNeedNext = false; - } - - $sChar = null; - if ($bIsGotoDefault) - { - $sChar = 'GOTO_DEFAULT'; - $bIsGotoDefault = false; - } - else if ($bIsGotoLiteral) - { - $bIsGotoLiteral = false; - $bIsGotoLiteralEnd = true; - - if ($this->partialResponseLiteralCallbackCallable( - $sParentToken, null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $this->rConnect, $iLiteralLen)) - { - if (!$bTreatAsAtom) - { - $aList[] = ''; - } - } - else - { - $sLiteral = ''; - $iRead = $iLiteralLen; - - while (0 < $iRead) - { - $sAddRead = \fread($this->rConnect, $iRead); - if (false === $sAddRead) - { - $sLiteral = false; - break; - } - - $sLiteral .= $sAddRead; - $iRead -= \strlen($sAddRead); - - \MailSo\Base\Utils::ResetTimeLimit(); - } - - if (false !== $sLiteral) - { - $iLiteralSize = \strlen($sLiteral); - \MailSo\Base\Loader::IncStatistic('NetRead', $iLiteralSize); - if ($iLiteralLen !== $iLiteralSize) - { - $this->writeLog('Literal stream read warning "read '.$iLiteralSize.' of '. - $iLiteralLen.'" bytes', \MailSo\Log\Enumerations\Type::WARNING); - } - - if (!$bTreatAsAtom) - { - $aList[] = $sLiteral; - - if (\MailSo\Config::$LogSimpleLiterals) - { - $this->writeLog('{'.\strlen($sLiteral).'} '.$sLiteral, \MailSo\Log\Enumerations\Type::INFO); - } - } - } - else - { - $this->writeLog('Can\'t read imap stream', \MailSo\Log\Enumerations\Type::NOTE); - } - - unset($sLiteral); - } - - continue; - } - else if ($bIsGotoLiteralEnd) - { - $rImapLiteralStream = null; - $sPreviousAtomUpperCase = null; - $this->bNeedNext = true; - $bIsGotoLiteralEnd = false; - - continue; - } - else if ($bIsGotoAtomBracket) - { - if ($bTreatAsAtom) - { - $sAtomBlock = $this->partialParseResponseBranch($mNull, $iStackIndex, true, - null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $sOpenBracket); - - $sAtomBuilder .= $sAtomBlock; - $iPos = $this->iResponseBufParsedPos; - $sAtomBuilder .= ($bIsClosingBracketSquare) ? ']' : ')'; - } - - $sPreviousAtomUpperCase = null; - $bIsGotoAtomBracket = false; - - continue; - } - else if ($bIsGotoNotAtomBracket) - { - $aSubItems = $this->partialParseResponseBranch($mNull, $iStackIndex, false, - null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $sOpenBracket); - - $aList[] = $aSubItems; - $iPos = $this->iResponseBufParsedPos; - $sPreviousAtomUpperCase = null; - if (null !== $oImapResponse && $oImapResponse->IsStatusResponse) - { - $oImapResponse->OptionalResponse = $aSubItems; - - $bIsGotoDefault = true; - $bIsGotoNotAtomBracket = false; - continue; - } - $bIsGotoNotAtomBracket = false; - - continue; - } - else - { - $iBufferEndIndex = \strlen($this->sResponseBuffer) - 3; - $this->bResponseBufferChanged = false; - - if ($iPos > $iBufferEndIndex) - { - break; - } - - $sChar = $this->sResponseBuffer[$iPos]; - } - - switch (true) - { - case ']' === $sChar: - $iPos++; - $sPreviousAtomUpperCase = null; - $bIsEndOfList = true; - break; - case ')' === $sChar: - $iPos++; - $sPreviousAtomUpperCase = null; - $bIsEndOfList = true; - break; - case ' ' === $sChar: - if ($bTreatAsAtom) - { - $sAtomBuilder .= ' '; - } - $iPos++; - break; - case '[' === $sChar: - $bIsClosingBracketSquare = true; - case '(' === $sChar: - if ('(' === $sChar) - { - $bIsClosingBracketSquare = false; - } - - if ($bTreatAsAtom) - { - $sAtomBuilder .= $bIsClosingBracketSquare ? '[' : '('; - } - $iPos++; - - $this->iResponseBufParsedPos = $iPos; - if ($bTreatAsAtom) - { - $bIsGotoAtomBracket = true; - $sOpenBracket = $bIsClosingBracketSquare ? '[' : '('; - } - else - { - $bIsGotoNotAtomBracket = true; - $sOpenBracket = $bIsClosingBracketSquare ? '[' : '('; - } - break; - case '{' === $sChar: - $bIsLiteralParsed = false; - $mLiteralEndPos = \strpos($this->sResponseBuffer, '}', $iPos); - if (false !== $mLiteralEndPos && $mLiteralEndPos > $iPos) - { - $sLiteralLenAsString = \substr($this->sResponseBuffer, $iPos + 1, $mLiteralEndPos - $iPos - 1); - if (\is_numeric($sLiteralLenAsString)) - { - $iLiteralLen = (int) $sLiteralLenAsString; - $bIsLiteralParsed = true; - $iPos = $mLiteralEndPos + 3; - $bIsGotoLiteral = true; - break; - } - } - if (!$bIsLiteralParsed) - { - $iPos = $iBufferEndIndex; - } - $sPreviousAtomUpperCase = null; - break; - case '"' === $sChar: - $bIsQuotedParsed = false; - while (true) - { - $iClosingPos = $iPos + 1; - if ($iClosingPos > $iBufferEndIndex) - { - break; - } - - while (true) - { - $iClosingPos = \strpos($this->sResponseBuffer, '"', $iClosingPos); - if (false === $iClosingPos) - { - break; - } - - // TODO - $iClosingPosNext = $iClosingPos + 1; - if ( - isset($this->sResponseBuffer[$iClosingPosNext]) && - ' ' !== $this->sResponseBuffer[$iClosingPosNext] && - "\r" !== $this->sResponseBuffer[$iClosingPosNext] && - "\n" !== $this->sResponseBuffer[$iClosingPosNext] && - ']' !== $this->sResponseBuffer[$iClosingPosNext] && - ')' !== $this->sResponseBuffer[$iClosingPosNext] - ) - { - $iClosingPos++; - continue; - } - - $iSlashCount = 0; - while ('\\' === $this->sResponseBuffer[$iClosingPos - $iSlashCount - 1]) - { - $iSlashCount++; - } - - if ($iSlashCount % 2 == 1) - { - $iClosingPos++; - continue; - } - else - { - break; - } - } - - if (false === $iClosingPos) - { - break; - } - else - { -// $iSkipClosingPos = 0; - $bIsQuotedParsed = true; - if ($bTreatAsAtom) - { - $sAtomBuilder .= \strtr( - \substr($this->sResponseBuffer, $iPos, $iClosingPos - $iPos + 1), - array('\\\\' => '\\', '\\"' => '"') - ); - } - else - { - $aList[] = \strtr( - \substr($this->sResponseBuffer, $iPos + 1, $iClosingPos - $iPos - 1), - array('\\\\' => '\\', '\\"' => '"') - ); - } - - $iPos = $iClosingPos + 1; - break; - } - } - - if (!$bIsQuotedParsed) - { - $iPos = $iBufferEndIndex; - } - - $sPreviousAtomUpperCase = null; - break; - - case 'GOTO_DEFAULT' === $sChar: - default: - $iCharBlockStartPos = $iPos; - - if (null !== $oImapResponse && $oImapResponse->IsStatusResponse) - { - $iPos = $iBufferEndIndex; - - while ($iPos > $iCharBlockStartPos && $this->sResponseBuffer[$iCharBlockStartPos] === ' ') - { - $iCharBlockStartPos++; - } - } - - $bIsAtomDone = false; - while (!$bIsAtomDone && ($iPos <= $iBufferEndIndex)) - { - $sCharDef = $this->sResponseBuffer[$iPos]; - switch (true) - { - case '[' === $sCharDef: - if (null === $sAtomBuilder) - { - $sAtomBuilder = ''; - } - - $sAtomBuilder .= \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos + 1); - - $iPos++; - $this->iResponseBufParsedPos = $iPos; - - $sListBlock = $this->partialParseResponseBranch($mNull, $iStackIndex, true, - null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), '['); - - if (null !== $sListBlock) - { - $sAtomBuilder .= $sListBlock.']'; - } - - $iPos = $this->iResponseBufParsedPos; - $iCharBlockStartPos = $iPos; - break; - case ' ' === $sCharDef: - case ')' === $sCharDef && '(' === $sOpenBracket: - case ']' === $sCharDef && '[' === $sOpenBracket: - $bIsAtomDone = true; - break; - default: - $iPos++; - break; - } - } - - if ($iPos > $iCharBlockStartPos || null !== $sAtomBuilder) - { - $sLastCharBlock = \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos); - if (null === $sAtomBuilder) - { - $aList[] = $sLastCharBlock; - $sPreviousAtomUpperCase = $sLastCharBlock; - } - else - { - $sAtomBuilder .= $sLastCharBlock; - - if (!$bTreatAsAtom) - { - $aList[] = $sAtomBuilder; - $sPreviousAtomUpperCase = $sAtomBuilder; - $sAtomBuilder = null; - } - } - - if (null !== $oImapResponse) - { -// if (1 === \count($aList)) - if (!$bCountOneInited && 1 === \count($aList)) -// if (isset($aList[0]) && !isset($aList[1])) // fast 1 === \count($aList) - { - $bCountOneInited = true; - - $oImapResponse->Tag = $aList[0]; - if ('+' === $oImapResponse->Tag) - { - $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::CONTINUATION; - } - else if ('*' === $oImapResponse->Tag) - { - $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::UNTAGGED; - } - else if ($this->getCurrentTag() === $oImapResponse->Tag) - { - $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::TAGGED; - } - else - { - $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::UNKNOWN; - } - } -// else if (2 === \count($aList)) - else if (!$bCountTwoInited && 2 === \count($aList)) -// else if (isset($aList[1]) && !isset($aList[2])) // fast 2 === \count($aList) - { - $bCountTwoInited = true; - - $oImapResponse->StatusOrIndex = strtoupper($aList[1]); - - if ($oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::OK || - $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::NO || - $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::BAD || - $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::BYE || - $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::PREAUTH) - { - $oImapResponse->IsStatusResponse = true; - } - } - else if (\MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oImapResponse->ResponseType) - { - $oImapResponse->HumanReadable = $sLastCharBlock; - } - else if ($oImapResponse->IsStatusResponse) - { - $oImapResponse->HumanReadable = $sLastCharBlock; - } - } - } - } - } - - $this->iResponseBufParsedPos = $iPos; - if (null !== $oImapResponse) - { - $this->bNeedNext = true; - $this->iResponseBufParsedPos = 0; - } - - if (100000 < $iDebugCount) - { - $this->Logger()->Write('PartialParseOverResult: '.$iDebugCount, \MailSo\Log\Enumerations\Type::ERROR); - } - - return $bTreatAsAtom ? $sAtomBuilder : $aList; - } - - /** - * @param string $sParent - * @param string $sLiteralAtomUpperCase - * @param resource $rImapStream - * @param int $iLiteralLen - * - * @return bool - */ - private function partialResponseLiteralCallbackCallable($sParent, $sLiteralAtomUpperCase, $rImapStream, $iLiteralLen) - { - $sLiteralAtomUpperCasePeek = ''; - if (0 === \strpos($sLiteralAtomUpperCase, 'BODY')) - { - $sLiteralAtomUpperCasePeek = \str_replace('BODY', 'BODY.PEEK', $sLiteralAtomUpperCase); - } - - $sFetchKey = ''; - if (\is_array($this->aFetchCallbacks)) - { - if (0 < \strlen($sLiteralAtomUpperCasePeek) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCasePeek])) - { - $sFetchKey = $sLiteralAtomUpperCasePeek; - } - else if (0 < \strlen($sLiteralAtomUpperCase) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCase])) - { - $sFetchKey = $sLiteralAtomUpperCase; - } - } - - $bResult = false; - if (0 < \strlen($sFetchKey) && '' !== $this->aFetchCallbacks[$sFetchKey] && - \is_callable($this->aFetchCallbacks[$sFetchKey])) - { - $rImapLiteralStream = - \MailSo\Base\StreamWrappers\Literal::CreateStream($rImapStream, $iLiteralLen); - - $bResult = true; - $this->writeLog('Start Callback for '.$sParent.' / '.$sLiteralAtomUpperCase. - ' - try to read '.$iLiteralLen.' bytes.', \MailSo\Log\Enumerations\Type::NOTE); - - $this->bRunningCallback = true; - - try - { - \call_user_func($this->aFetchCallbacks[$sFetchKey], - $sParent, $sLiteralAtomUpperCase, $rImapLiteralStream); - } - catch (\Exception $oException) - { - $this->writeLog('Callback Exception', \MailSo\Log\Enumerations\Type::NOTICE); - $this->writeLogException($oException); - } - - if (\is_resource($rImapLiteralStream)) - { - $iNotReadLiteralLen = 0; - - $bFeof = \feof($rImapLiteralStream); - $this->writeLog('End Callback for '.$sParent.' / '.$sLiteralAtomUpperCase. - ' - feof = '.($bFeof ? 'good' : 'BAD'), $bFeof ? - \MailSo\Log\Enumerations\Type::NOTE : \MailSo\Log\Enumerations\Type::WARNING); - - if (!$bFeof) - { - while (!@\feof($rImapLiteralStream)) - { - $sBuf = @\fread($rImapLiteralStream, 1024 * 1024); - if (false === $sBuf || 0 === \strlen($sBuf) || null === $sBuf) - { - break; - } - - \MailSo\Base\Utils::ResetTimeLimit(); - $iNotReadLiteralLen += \strlen($sBuf); - } - - if (\is_resource($rImapLiteralStream) && !@\feof($rImapLiteralStream)) - { - @\stream_get_contents($rImapLiteralStream); - } - } - - if (\is_resource($rImapLiteralStream)) - { - @\fclose($rImapLiteralStream); - } - - if ($iNotReadLiteralLen > 0) - { - $this->writeLog('Not read literal size is '.$iNotReadLiteralLen.' bytes.', - \MailSo\Log\Enumerations\Type::WARNING); - } - } - else - { - $this->writeLog('Literal stream is not resource after callback.', - \MailSo\Log\Enumerations\Type::WARNING); - } - - \MailSo\Base\Loader::IncStatistic('NetRead', $iLiteralLen); - - $this->bRunningCallback = false; - } - - return $bResult; - } - - /** - * @param array $aParams = null - * - * @return string - */ - private function prepearParamLine($aParams = array()) - { - $sReturn = ''; - if (\is_array($aParams) && 0 < \count($aParams)) - { - foreach ($aParams as $mParamItem) - { - if (\is_array($mParamItem) && 0 < \count($mParamItem)) - { - $sReturn .= ' ('.\trim($this->prepearParamLine($mParamItem)).')'; - } - else if (\is_string($mParamItem)) - { - $sReturn .= ' '.$mParamItem; - } - } - } - return $sReturn; - } - - /** - * @return string - */ - private function getNewTag() - { - $this->iTagCount++; - return $this->getCurrentTag(); - } - - /** - * @return string - */ - private function getCurrentTag() - { - return self::TAG_PREFIX.$this->iTagCount; - } - - /** - * @param string $sStringForEscape - * - * @return string - */ - public function EscapeString($sStringForEscape) - { - return '"'.\str_replace(array('\\', '"'), array('\\\\', '\\"'), $sStringForEscape).'"'; - } - - /** - * @return string - */ - protected function getLogName() - { - return 'IMAP'; - } - - /** - * @param \MailSo\Log\Logger $oLogger - * - * @return \MailSo\Imap\ImapClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function SetLogger($oLogger) - { - parent::SetLogger($oLogger); - - return $this; - } - - /** - * @param resource $rConnect - * @param array $aCapabilityItems = array() - * - * @return \MailSo\Imap\ImapClient - */ - public function TestSetValues($rConnect, $aCapabilityItems = array()) - { - $this->rConnect = $rConnect; - $this->aCapabilityItems = $aCapabilityItems; - - return $this; - } - - /** - * @param string $sEndTag = null - * @param string $bFindCapa = false - * - * @return array - */ - public function TestParseResponseWithValidationProxy($sEndTag = null, $bFindCapa = false) - { - return $this->parseResponseWithValidation($sEndTag, $bFindCapa); - } -} +iTagCount = 0; + $this->aCapabilityItems = null; + $this->oCurrentFolderInfo = null; + $this->aFetchCallbacks = null; + $this->iResponseBufParsedPos = 0; + + $this->aLastResponse = array(); + $this->bNeedNext = true; + $this->aPartialResponses = array(); + + $this->aTagTimeouts = array(); + + $this->bIsLoggined = false; + $this->bIsSelected = false; + $this->sLogginedUser = ''; + + $this->__FORCE_SELECT_ON_EXAMINE__ = false; + + @\ini_set('xdebug.max_nesting_level', 500); + } + + /** + * @return \MailSo\Imap\ImapClient + */ + public static function NewInstance() + { + return new self(); + } + + /** + * @return string + */ + public function GetLogginedUser() + { + return $this->sLogginedUser; + } + + /** + * @param string $sServerName + * @param int $iPort = 143 + * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT + * @param bool $bVerifySsl = false + * @param bool $bAllowSelfSigned = true + * @param string $sClientCert = '' + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function Connect($sServerName, $iPort = 143, + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, + $bVerifySsl = false, $bAllowSelfSigned = true, + $sClientCert = '') + { + $this->aTagTimeouts['*'] = \microtime(true); + + parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned, $sClientCert); + + $this->parseResponseWithValidation('*', true); + + if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS( + $this->IsSupported('STARTTLS'), $this->iSecurityType)) + { + $this->SendRequestWithCheck('STARTTLS'); + $this->EnableCrypto(); + + $this->aCapabilityItems = null; + } + else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType) + { + $this->writeLogException( + new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + return $this; + } + + 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; + } + + /** + * @param string $sLogin + * @param string $sPassword + * @param string $sProxyAuthUser = '' + * @param bool $bUseAuthPlainIfSupported = true + * @param bool $bUseAuthCramMd5IfSupported = true + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function Login($sLogin, $sPassword, $sProxyAuthUser = '', + $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true) + { + if (!\MailSo\Base\Validator::NotEmptyString($sLogin, true) || + !\MailSo\Base\Validator::NotEmptyString($sPassword, true)) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin)); + + $sPassword = $sPassword; + + $this->sLogginedUser = $sLogin; + + try + { + if ($bUseAuthCramMd5IfSupported && $this->IsSupported('AUTH=CRAM-MD5')) + { + $this->SendRequest('AUTHENTICATE', array('CRAM-MD5')); + + $aResponse = $this->parseResponseWithValidation(); + if ($aResponse && \is_array($aResponse) && 0 < \count($aResponse) && + \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $aResponse[\count($aResponse) - 1]->ResponseType) + { + $oContinuationResponse = null; + foreach ($aResponse as $oResponse) + { + if ($oResponse && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oResponse->ResponseType) + { + $oContinuationResponse = $oResponse; + } + } + + if ($oContinuationResponse && !empty($oContinuationResponse->ResponseList[1])) + { + $sTicket = @\base64_decode($oContinuationResponse->ResponseList[1]); + $this->oLogger->Write('ticket: '.$sTicket); + + $sToken = \base64_encode($sLogin.' '.\MailSo\Base\Utils::Hmac($sTicket, $sPassword)); + + if ($this->oLogger) + { + $this->oLogger->AddSecret($sToken); + } + + $this->sendRaw($sToken, true, '*******'); + $this->parseResponseWithValidation(); + } + else + { + $this->writeLogException( + new \MailSo\Imap\Exceptions\LoginException(), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + } + else + { + $this->writeLogException( + new \MailSo\Imap\Exceptions\LoginException(), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + } + else if ($bUseAuthPlainIfSupported && $this->IsSupported('AUTH=PLAIN')) + { + $sToken = \base64_encode("\0".$sLogin."\0".$sPassword); + if ($this->oLogger) + { + $this->oLogger->AddSecret($sToken); + } + + if ($this->IsSupported('AUTH=SASL-IR') && false) + { + $this->SendRequestWithCheck('AUTHENTICATE', array('PLAIN', $sToken)); + } + else + { + $this->SendRequest('AUTHENTICATE', array('PLAIN')); + $this->parseResponseWithValidation(); + + $this->sendRaw($sToken, true, '*******'); + $this->parseResponseWithValidation(); + } + } + else + { + if ($this->oLogger) + { + $this->oLogger->AddSecret($this->EscapeString($sPassword)); + } + + $this->SendRequestWithCheck('LOGIN', + array( + $this->EscapeString($sLogin), + $this->EscapeString($sPassword) + )); + } +// else +// { +// $this->writeLogException( +// new \MailSo\Imap\Exceptions\LoginBadMethodException(), +// \MailSo\Log\Enumerations\Type::NOTICE, true); +// } + + if (0 < \strlen($sProxyAuthUser)) + { + $this->SendRequestWithCheck('PROXYAUTH', array($this->EscapeString($sProxyAuthUser))); + } + } + catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Imap\Exceptions\LoginBadCredentialsException( + $oException->GetResponses(), '', 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + + $this->bIsLoggined = true; + $this->aCapabilityItems = null; + + return $this; + } + + /** + * @param string $sXOAuth2Token + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function LoginWithXOauth2($sXOAuth2Token) + { + if (!\MailSo\Base\Validator::NotEmptyString($sXOAuth2Token, true)) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + if (!$this->IsSupported('AUTH=XOAUTH2')) + { + $this->writeLogException( + new \MailSo\Imap\Exceptions\LoginBadMethodException(), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + + try + { + $this->SendRequest('AUTHENTICATE', array('XOAUTH2', \trim($sXOAuth2Token))); + $aR = $this->parseResponseWithValidation(); + + if (\is_array($aR) && 0 < \count($aR) && isset($aR[\count($aR) - 1])) + { + $oR = $aR[\count($aR) - 1]; + if (\MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oR->ResponseType) + { + if (!empty($oR->ResponseList[1]) && preg_match('/^[a-zA-Z0-9=+\/]+$/', $oR->ResponseList[1])) + { + $this->Logger()->Write(\base64_decode($oR->ResponseList[1]), + \MailSo\Log\Enumerations\Type::WARNING); + } + + $this->sendRaw(''); + $this->parseResponseWithValidation(); + } + } + } + catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Imap\Exceptions\LoginBadCredentialsException( + $oException->GetResponses(), '', 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + + $this->bIsLoggined = true; + $this->aCapabilityItems = null; + + return $this; + } + + /** + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Net\Exceptions\Exception + */ + public function Logout() + { + if ($this->bIsLoggined) + { + $this->bIsLoggined = false; + $this->SendRequestWithCheck('LOGOUT', array()); + } + + return $this; + } + + /** + * @return \MailSo\Imap\ImapClient + */ + public function ForceCloseConnection() + { + $this->Disconnect(); + + return $this; + } + + /** + * @return bool + */ + public function IsLoggined() + { + return $this->IsConnected() && $this->bIsLoggined; + } + + /** + * @return bool + */ + public function IsSelected() + { + return $this->IsLoggined() && $this->bIsSelected; + } + + /** + * @return array|null + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function Capability() + { + $this->SendRequestWithCheck('CAPABILITY', array(), true); + return $this->aCapabilityItems; + } + + /** + * @param string $sExtentionName + * @return bool + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function IsSupported($sExtentionName) + { + $bResult = \MailSo\Base\Validator::NotEmptyString($sExtentionName, true); + if ($bResult && null === $this->aCapabilityItems) + { + $this->aCapabilityItems = $this->Capability(); + } + + return $bResult && \is_array($this->aCapabilityItems) && + \in_array(\strtoupper($sExtentionName), $this->aCapabilityItems); + } + + /** + * @return \MailSo\Imap\NamespaceResult|null + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function GetNamespace() + { + if (!$this->IsSupported('NAMESPACE')) + { + return null; + } + + $oReturn = false; + + $this->SendRequest('NAMESPACE'); + $aResult = $this->parseResponseWithValidation(); + + $oImapResponse = null; + foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType && + 'NAMESPACE' === $oImapResponse->StatusOrIndex) + { + $oReturn = NamespaceResult::NewInstance(); + $oReturn->InitByImapResponse($oImapResponse); + break; + } + } + + if (false === $oReturn) + { + $this->writeLogException( + new \MailSo\Imap\Exceptions\ResponseException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + return $oReturn; + } + + /** + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function Noop() + { + return $this->SendRequestWithCheck('NOOP'); + } + + /** + * @param string $sFolderName + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderCreate($sFolderName) + { + return $this->SendRequestWithCheck('CREATE', + array($this->EscapeString($sFolderName))); + } + + /** + * @param string $sFolderName + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderDelete($sFolderName) + { + return $this->SendRequestWithCheck('DELETE', + array($this->EscapeString($sFolderName))); + } + + /** + * @param string $sFolderName + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderSubscribe($sFolderName) + { + return $this->SendRequestWithCheck('SUBSCRIBE', + array($this->EscapeString($sFolderName))); + } + + /** + * @param string $sFolderName + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderUnSubscribe($sFolderName) + { + return $this->SendRequestWithCheck('UNSUBSCRIBE', + array($this->EscapeString($sFolderName))); + } + + /** + * @param string $sOldFolderName + * @param string $sNewFolderName + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderRename($sOldFolderName, $sNewFolderName) + { + return $this->SendRequestWithCheck('RENAME', array( + $this->EscapeString($sOldFolderName), + $this->EscapeString($sNewFolderName))); + } + + /** + * @param array $aResult + * + * @return array + */ + protected function getStatusFolderInformation($aResult) + { + $aReturn = array(); + + if (\is_array($aResult)) + { + $oImapResponse = null; + foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType && + 'STATUS' === $oImapResponse->StatusOrIndex && isset($oImapResponse->ResponseList[3]) && + \is_array($oImapResponse->ResponseList[3])) + { + $sName = null; + foreach ($oImapResponse->ResponseList[3] as $sArrayItem) + { + if (null === $sName) + { + $sName = $sArrayItem; + } + else + { + $aReturn[$sName] = $sArrayItem; + $sName = null; + } + } + } + } + } + + return $aReturn; + } + + /** + * @param string $sFolderName + * @param array $aStatusItems + * + * @return array|bool + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderStatus($sFolderName, array $aStatusItems) + { + $aResult = false; + if (\count($aStatusItems) > 0) + { + $this->SendRequest('STATUS', + array($this->EscapeString($sFolderName), $aStatusItems)); + + $aResult = $this->getStatusFolderInformation( + $this->parseResponseWithValidation()); + } + + return $aResult; + } + + /** + * @param array $aResult + * @param string $sStatus + * @param bool $bUseListStatus = false + * + * @return array + */ + private function getFoldersFromResult(array $aResult, $sStatus, $bUseListStatus = false) + { + $aReturn = array(); + + $sDelimiter = ''; + $bInbox = false; + + $oImapResponse = null; + foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType && + $sStatus === $oImapResponse->StatusOrIndex && 5 === count($oImapResponse->ResponseList)) + { + try + { + $oFolder = Folder::NewInstance($oImapResponse->ResponseList[4], + $oImapResponse->ResponseList[3], $oImapResponse->ResponseList[2]); + + if ($oFolder->IsInbox()) + { + $bInbox = true; + } + + if (empty($sDelimiter)) + { + $sDelimiter = $oFolder->Delimiter(); + } + + $aReturn[] = $oFolder; + } + catch (\MailSo\Base\Exceptions\InvalidArgumentException $oException) + { + $this->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false); + } + } + } + + if (!$bInbox && !empty($sDelimiter)) + { + $aReturn[] = Folder::NewInstance('INBOX', $sDelimiter); + } + + if ($bUseListStatus) + { + foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType && + 'STATUS' === $oImapResponse->StatusOrIndex && + isset($oImapResponse->ResponseList[2]) && + isset($oImapResponse->ResponseList[3]) && + \is_array($oImapResponse->ResponseList[3])) + { + $sFolderNameRaw = $oImapResponse->ResponseList[2]; + + $oCurrentFolder = null; + foreach ($aReturn as &$oFolder) + { + if ($oFolder && $sFolderNameRaw === $oFolder->FullNameRaw()) + { + $oCurrentFolder =& $oFolder; + break; + } + } + + if (null !== $oCurrentFolder) + { + $sName = null; + $aStatus = array(); + + foreach ($oImapResponse->ResponseList[3] as $sArrayItem) + { + if (null === $sName) + { + $sName = $sArrayItem; + } + else + { + $aStatus[$sName] = $sArrayItem; + $sName = null; + } + } + + if (0 < count($aStatus)) + { + $oCurrentFolder->SetExtended('STATUS', $aStatus); + } + } + + unset($oCurrentFolder); + } + } + } + + return $aReturn; + } + + /** + * @param bool $bIsSubscribeList + * @param string $sParentFolderName = '' + * @param string $sListPattern = '*' + * @param bool $bUseListStatus = false + * + * @return array + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + private function specificFolderList($bIsSubscribeList, $sParentFolderName = '', $sListPattern = '*', $bUseListStatus = false) + { + $sCmd = 'LSUB'; + if (!$bIsSubscribeList) + { + $sCmd = 'LIST'; + } + + $sListPattern = 0 === strlen(trim($sListPattern)) ? '*' : $sListPattern; + + $aParameters = array( + $this->EscapeString($sParentFolderName), + $this->EscapeString($sListPattern) + ); + + if ($bUseListStatus && !$bIsSubscribeList && $this->IsSupported('LIST-STATUS')) + { + $aL = array( + \MailSo\Imap\Enumerations\FolderStatus::MESSAGES, + \MailSo\Imap\Enumerations\FolderStatus::UNSEEN, + \MailSo\Imap\Enumerations\FolderStatus::UIDNEXT + ); + +// if ($this->IsSupported('CONDSTORE')) +// { +// $aL[] = \MailSo\Imap\Enumerations\FolderStatus::HIGHESTMODSEQ; +// } + + $aParameters[] = 'RETURN'; + $aParameters[] = array('STATUS', $aL); + } + else + { + $bUseListStatus = false; + } + + $this->SendRequest($sCmd, $aParameters); + + return $this->getFoldersFromResult( + $this->parseResponseWithValidation(), $sCmd, $bUseListStatus); + } + + /** + * @param string $sParentFolderName = '' + * @param string $sListPattern = '*' + * + * @return array + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderList($sParentFolderName = '', $sListPattern = '*') + { + return $this->specificFolderList(false, $sParentFolderName, $sListPattern); + } + + /** + * @param string $sParentFolderName = '' + * @param string $sListPattern = '*' + * + * @return array + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderSubscribeList($sParentFolderName = '', $sListPattern = '*') + { + return $this->specificFolderList(true, $sParentFolderName, $sListPattern); + } + + /** + * @param string $sParentFolderName = '' + * @param string $sListPattern = '*' + * + * @return array + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderStatusList($sParentFolderName = '', $sListPattern = '*') + { + return $this->specificFolderList(false, $sParentFolderName, $sListPattern, true); + } + + /** + * @param array $aResult + * @param string $sFolderName + * @param bool $bIsWritable + * + * @return void + */ + protected function initCurrentFolderInformation($aResult, $sFolderName, $bIsWritable) + { + if (\is_array($aResult)) + { + $oImapResponse = null; + $oResult = FolderInformation::NewInstance($sFolderName, $bIsWritable); + + foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType) + { + if (\count($oImapResponse->ResponseList) > 2 && + 'FLAGS' === $oImapResponse->ResponseList[1] && \is_array($oImapResponse->ResponseList[2])) + { + $oResult->Flags = $oImapResponse->ResponseList[2]; + } + + if (is_array($oImapResponse->OptionalResponse) && \count($oImapResponse->OptionalResponse) > 1) + { + if ('PERMANENTFLAGS' === $oImapResponse->OptionalResponse[0] && + is_array($oImapResponse->OptionalResponse[1])) + { + $oResult->PermanentFlags = $oImapResponse->OptionalResponse[1]; + } + else if ('UIDVALIDITY' === $oImapResponse->OptionalResponse[0] && + isset($oImapResponse->OptionalResponse[1])) + { + $oResult->Uidvalidity = $oImapResponse->OptionalResponse[1]; + } + else if ('UNSEEN' === $oImapResponse->OptionalResponse[0] && + isset($oImapResponse->OptionalResponse[1]) && + is_numeric($oImapResponse->OptionalResponse[1])) + { + $oResult->Unread = (int) $oImapResponse->OptionalResponse[1]; + } + else if ('UIDNEXT' === $oImapResponse->OptionalResponse[0] && + isset($oImapResponse->OptionalResponse[1])) + { + $oResult->Uidnext = $oImapResponse->OptionalResponse[1]; + } + else if ('HIGHESTMODSEQ' === $oImapResponse->OptionalResponse[0] && + isset($oImapResponse->OptionalResponse[1]) && + \is_numeric($oImapResponse->OptionalResponse[1])) + { + $oResult->HighestModSeq = \trim($oImapResponse->OptionalResponse[1]); + } + } + + if (\count($oImapResponse->ResponseList) > 2 && + \is_string($oImapResponse->ResponseList[2]) && + \is_numeric($oImapResponse->ResponseList[1])) + { + switch($oImapResponse->ResponseList[2]) + { + case 'EXISTS': + $oResult->Exists = (int) $oImapResponse->ResponseList[1]; + break; + case 'RECENT': + $oResult->Recent = (int) $oImapResponse->ResponseList[1]; + break; + } + } + } + } + + $this->oCurrentFolderInfo = $oResult; + } + } + + /** + * @param string $sFolderName + * @param bool $bIsWritable + * @param bool $bReSelectSameFolders + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + protected function selectOrExamineFolder($sFolderName, $bIsWritable, $bReSelectSameFolders) + { + if (!$bReSelectSameFolders) + { + if ($this->oCurrentFolderInfo && + $sFolderName === $this->oCurrentFolderInfo->FolderName && + $bIsWritable === $this->oCurrentFolderInfo->IsWritable) + { + return $this; + } + } + + if (!\MailSo\Base\Validator::NotEmptyString($sFolderName, true)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->SendRequest(($bIsWritable) ? 'SELECT' : 'EXAMINE', + array($this->EscapeString($sFolderName))); + + $this->initCurrentFolderInformation( + $this->parseResponseWithValidation(), $sFolderName, $bIsWritable); + + $this->bIsSelected = true; + + return $this; + } + + /** + * @param string $sFolderName + * @param bool $bReSelectSameFolders = false + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderSelect($sFolderName, $bReSelectSameFolders = false) + { + return $this->selectOrExamineFolder($sFolderName, true, $bReSelectSameFolders); + } + + /** + * @param string $sFolderName + * @param bool $bReSelectSameFolders = false + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderExamine($sFolderName, $bReSelectSameFolders = false) + { + return $this->selectOrExamineFolder($sFolderName, $this->__FORCE_SELECT_ON_EXAMINE__, $bReSelectSameFolders); + } + + /** + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderUnSelect() + { + if ($this->IsSelected() && $this->IsSupported('UNSELECT')) + { + $this->SendRequestWithCheck('UNSELECT'); + $this->bIsSelected = false; + } + + return $this; + } + + /** + * @param array $aInputFetchItems + * @param string $sIndexRange + * @param bool $bIndexIsUid + * + * @return array + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function Fetch(array $aInputFetchItems, $sIndexRange, $bIndexIsUid) + { + $sIndexRange = (string) $sIndexRange; + if (!\MailSo\Base\Validator::NotEmptyString($sIndexRange, true)) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $aFetchItems = \MailSo\Imap\Enumerations\FetchType::ChangeFetchItemsBefourRequest($aInputFetchItems); + foreach ($aFetchItems as $sName => $mItem) + { + if (0 < \strlen($sName) && '' !== $mItem) + { + if (null === $this->aFetchCallbacks) + { + $this->aFetchCallbacks = array(); + } + + $this->aFetchCallbacks[$sName] = $mItem; + } + } + + $this->SendRequest((($bIndexIsUid) ? 'UID ' : '').'FETCH', array($sIndexRange, \array_keys($aFetchItems))); + $aResult = $this->validateResponse($this->parseResponse()); + $this->aFetchCallbacks = null; + + $aReturn = array(); + $oImapResponse = null; + foreach ($aResult as $oImapResponse) + { + if (FetchResponse::IsValidFetchImapResponse($oImapResponse)) + { + if (FetchResponse::IsNotEmptyFetchImapResponse($oImapResponse)) + { + $aReturn[] = FetchResponse::NewInstance($oImapResponse); + } + else + { + if ($this->oLogger) + { + $this->oLogger->Write('Skipped Imap Response! ['.$oImapResponse->ToLine().']', \MailSo\Log\Enumerations\Type::NOTICE); + } + } + } + } + + return $aReturn; + } + + + /** + * @return array|false + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function Quota() + { + $aReturn = false; + if ($this->IsSupported('QUOTA')) + { + $this->SendRequest('GETQUOTAROOT "INBOX"'); + $aResult = $this->parseResponseWithValidation(); + + $aReturn = array(0, 0); + $oImapResponse = null; + foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType + && 'QUOTA' === $oImapResponse->StatusOrIndex + && \is_array($oImapResponse->ResponseList) + && isset($oImapResponse->ResponseList[3]) + && \is_array($oImapResponse->ResponseList[3]) + && 2 < \count($oImapResponse->ResponseList[3]) + && 'STORAGE' === \strtoupper($oImapResponse->ResponseList[3][0]) + && \is_numeric($oImapResponse->ResponseList[3][1]) + && \is_numeric($oImapResponse->ResponseList[3][2]) + ) + { + $aReturn = array( + (int) $oImapResponse->ResponseList[3][1], + (int) $oImapResponse->ResponseList[3][2], + 0, + 0 + ); + + if (5 < \count($oImapResponse->ResponseList[3]) + && 'MESSAGE' === \strtoupper($oImapResponse->ResponseList[3][3]) + && \is_numeric($oImapResponse->ResponseList[3][4]) + && \is_numeric($oImapResponse->ResponseList[3][5]) + ) + { + $aReturn[2] = (int) $oImapResponse->ResponseList[3][4]; + $aReturn[3] = (int) $oImapResponse->ResponseList[3][5]; + } + } + } + } + + return $aReturn; + } + + /** + * @param array $aSortTypes + * @param string $sSearchCriterias + * @param bool $bReturnUid + * + * @return array + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageSimpleSort($aSortTypes, $sSearchCriterias = 'ALL', $bReturnUid = true) + { + $sCommandPrefix = ($bReturnUid) ? 'UID ' : ''; + $sSearchCriterias = !\MailSo\Base\Validator::NotEmptyString($sSearchCriterias, true) || '*' === $sSearchCriterias + ? 'ALL' : $sSearchCriterias; + + if (!\is_array($aSortTypes) || 0 === \count($aSortTypes)) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + else if (!$this->IsSupported('SORT')) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $aRequest = array(); + $aRequest[] = $aSortTypes; + $aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8'; + $aRequest[] = $sSearchCriterias; + + $sCmd = 'SORT'; + + $this->SendRequest($sCommandPrefix.$sCmd, $aRequest); + $aResult = $this->parseResponseWithValidation(); + + $aReturn = array(); + $oImapResponse = null; + foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType + && ($sCmd === $oImapResponse->StatusOrIndex || + ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) && + $sCmd === $oImapResponse->ResponseList[2]) + && \is_array($oImapResponse->ResponseList) + && 2 < \count($oImapResponse->ResponseList)) + { + $iStart = 2; + if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex && + !empty($oImapResponse->ResponseList[2]) && + $sCmd === $oImapResponse->ResponseList[2]) + { + $iStart = 3; + } + + for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++) + { + $aReturn[] = (int) $oImapResponse->ResponseList[$iIndex]; + } + } + } + + return $aReturn; + } + + /** + * @param bool $bSort = false + * @param string $sSearchCriterias = 'ALL' + * @param array $aSearchOrSortReturn = null + * @param bool $bReturnUid = true + * @param string $sLimit = '' + * @param string $sCharset = '' + * @param array $aSortTypes = null + * + * @return array + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + private function simpleESearchOrESortHelper($bSort = false, $sSearchCriterias = 'ALL', $aSearchOrSortReturn = null, $bReturnUid = true, $sLimit = '', $sCharset = '', $aSortTypes = null) + { + $sCommandPrefix = ($bReturnUid) ? 'UID ' : ''; + $sSearchCriterias = 0 === \strlen($sSearchCriterias) || '*' === $sSearchCriterias + ? 'ALL' : $sSearchCriterias; + + $sCmd = $bSort ? 'SORT': 'SEARCH'; + if ($bSort && (!\is_array($aSortTypes) || 0 === \count($aSortTypes) || !$this->IsSupported('SORT'))) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + if (!$this->IsSupported($bSort ? 'ESORT' : 'ESEARCH')) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + if (!\is_array($aSearchOrSortReturn) || 0 === \count($aSearchOrSortReturn)) + { + $aSearchOrSortReturn = array('ALL'); + } + + $aRequest = array(); + if ($bSort) + { + $aRequest[] = 'RETURN'; + $aRequest[] = $aSearchOrSortReturn; + + $aRequest[] = $aSortTypes; + $aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8'; + } + else + { + if (0 < \strlen($sCharset)) + { + $aRequest[] = 'CHARSET'; + $aRequest[] = \strtoupper($sCharset); + } + + $aRequest[] = 'RETURN'; + $aRequest[] = $aSearchOrSortReturn; + } + + $aRequest[] = $sSearchCriterias; + + if (0 < \strlen($sLimit)) + { + $aRequest[] = $sLimit; + } + + $this->SendRequest($sCommandPrefix.$sCmd, $aRequest); + $sRequestTag = $this->getCurrentTag(); + + $aResult = array(); + $aResponse = $this->parseResponseWithValidation(); + + if (\is_array($aResponse)) + { + $oImapResponse = null; + foreach ($aResponse as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType + && ('ESEARCH' === $oImapResponse->StatusOrIndex || 'ESORT' === $oImapResponse->StatusOrIndex) + && \is_array($oImapResponse->ResponseList) + && isset($oImapResponse->ResponseList[2], $oImapResponse->ResponseList[2][0], $oImapResponse->ResponseList[2][1]) + && 'TAG' === $oImapResponse->ResponseList[2][0] && $sRequestTag === $oImapResponse->ResponseList[2][1] + && (!$bReturnUid || ($bReturnUid && !empty($oImapResponse->ResponseList[3]) && 'UID' === $oImapResponse->ResponseList[3])) + ) + { + $iStart = 3; + foreach ($oImapResponse->ResponseList as $iIndex => $mItem) + { + if ($iIndex >= $iStart) + { + switch ($mItem) + { + case 'ALL': + case 'MAX': + case 'MIN': + case 'COUNT': + if (isset($oImapResponse->ResponseList[$iIndex + 1])) + { + $aResult[$mItem] = $oImapResponse->ResponseList[$iIndex + 1]; + } + break; + } + } + } + } + } + } + + return $aResult; + } + + /** + * @param string $sSearchCriterias = 'ALL' + * @param array $aSearchReturn = null + * @param bool $bReturnUid = true + * @param string $sLimit = '' + * @param string $sCharset = '' + * + * @return array + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageSimpleESearch($sSearchCriterias = 'ALL', $aSearchReturn = null, $bReturnUid = true, $sLimit = '', $sCharset = '') + { + return $this->simpleESearchOrESortHelper(false, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, $sCharset); + } + + /** + * @param array $aSortTypes + * @param string $sSearchCriterias = 'ALL' + * @param array $aSearchReturn = null + * @param bool $bReturnUid = true + * @param string $sLimit = '' + * + * @return array + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageSimpleESort($aSortTypes, $sSearchCriterias = 'ALL', $aSearchReturn = null, $bReturnUid = true, $sLimit = '') + { + return $this->simpleESearchOrESortHelper(true, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, '', $aSortTypes); + } + + /** + * @param array $aResult + * @return \MailSo\Imap\Response + */ + private function findLastResponse($aResult) + { + $oResult = null; + if (\is_array($aResult) && 0 < \count($aResult)) + { + $oResult = $aResult[\count($aResult) - 1]; + if (!($oResult instanceof \MailSo\Imap\Response)) + { + $oResult = null; + } + } + + return $oResult; + } + + /** + * @param string $sSearchCriterias + * @param bool $bReturnUid = true + * @param string $sCharset = '' + * + * @return array + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageSimpleSearch($sSearchCriterias = 'ALL', $bReturnUid = true, $sCharset = '') + { + $sCommandPrefix = ($bReturnUid) ? 'UID ' : ''; + $sSearchCriterias = 0 === \strlen($sSearchCriterias) || '*' === $sSearchCriterias + ? 'ALL' : $sSearchCriterias; + + $aRequest = array(); + if (0 < \strlen($sCharset)) + { + $aRequest[] = 'CHARSET'; + $aRequest[] = \strtoupper($sCharset); + } + + $aRequest[] = $sSearchCriterias; + + $sCmd = 'SEARCH'; + + $sCont = $this->SendRequest($sCommandPrefix.$sCmd, $aRequest, true); + if ('' !== $sCont) + { + $aResult = $this->parseResponseWithValidation(); + $oItem = $this->findLastResponse($aResult); + + if ($oItem && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oItem->ResponseType) + { + $aParts = explode("\r\n", $sCont); + foreach ($aParts as $sLine) + { + $this->sendRaw($sLine); + + $aResult = $this->parseResponseWithValidation(); + $oItem = $this->findLastResponse($aResult); + if ($oItem && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oItem->ResponseType) + { + continue; + } + } + } + } + else + { + $aResult = $this->parseResponseWithValidation(); + } + + $aReturn = array(); + $oImapResponse = null; + foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType + && ($sCmd === $oImapResponse->StatusOrIndex || + ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) && + $sCmd === $oImapResponse->ResponseList[2]) + && \is_array($oImapResponse->ResponseList) + && 2 < count($oImapResponse->ResponseList)) + { + $iStart = 2; + if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex && + !empty($oImapResponse->ResponseList[2]) && + $sCmd === $oImapResponse->ResponseList[2]) + { + $iStart = 3; + } + + for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++) + { + $aReturn[] = (int) $oImapResponse->ResponseList[$iIndex]; + } + } + } + + $aReturn = \array_reverse($aReturn); + return $aReturn; + } + + /** + * @param mixed $aValue + * + * @return mixed + */ + private function validateThreadItem($aValue) + { + $mResult = false; + if (\is_numeric($aValue)) + { + $mResult = (int) $aValue; + if (0 >= $mResult) + { + $mResult = false; + } + } + else if (\is_array($aValue)) + { + if (1 === \count($aValue) && \is_numeric($aValue[0])) + { + $mResult = (int) $aValue[0]; + if (0 >= $mResult) + { + $mResult = false; + } + } + else + { + $mResult = array(); + foreach ($aValue as $aValueItem) + { + $mTemp = $this->validateThreadItem($aValueItem); + if (false !== $mTemp) + { + $mResult[] = $mTemp; + } + } + } + } + + return $mResult; + } + + /** + * @param string $sSearchCriterias = 'ALL' + * @param bool $bReturnUid = true + * @param string $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8 + * + * @return array + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageSimpleThread($sSearchCriterias = 'ALL', $bReturnUid = true, $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8) + { + $sCommandPrefix = ($bReturnUid) ? 'UID ' : ''; + $sSearchCriterias = !\MailSo\Base\Validator::NotEmptyString($sSearchCriterias, true) || '*' === $sSearchCriterias + ? 'ALL' : $sSearchCriterias; + + $sThreadType = ''; + switch (true) + { + case $this->IsSupported('THREAD=REFS'): + $sThreadType = 'REFS'; + break; + case $this->IsSupported('THREAD=REFERENCES'): + $sThreadType = 'REFERENCES'; + break; + case $this->IsSupported('THREAD=ORDEREDSUBJECT'): + $sThreadType = 'ORDEREDSUBJECT'; + break; + default: + $this->writeLogException( + new Exceptions\RuntimeException('Thread is not supported'), + \MailSo\Log\Enumerations\Type::ERROR, true); + break; + } + + $aRequest = array(); + $aRequest[] = $sThreadType; + $aRequest[] = \strtoupper($sCharset); + $aRequest[] = $sSearchCriterias; + + $sCmd = 'THREAD'; + + $this->SendRequest($sCommandPrefix.$sCmd, $aRequest); + $aResult = $this->parseResponseWithValidation(); + + $aReturn = array(); + $oImapResponse = null; + + foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType + && ($sCmd === $oImapResponse->StatusOrIndex || + ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) && + $sCmd === $oImapResponse->ResponseList[2]) + && \is_array($oImapResponse->ResponseList) + && 2 < \count($oImapResponse->ResponseList)) + { + $iStart = 2; + if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex && + !empty($oImapResponse->ResponseList[2]) && + $sCmd === $oImapResponse->ResponseList[2]) + { + $iStart = 3; + } + + for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++) + { + $aNewValue = $this->validateThreadItem($oImapResponse->ResponseList[$iIndex]); + if (false !== $aNewValue) + { + $aReturn[] = $aNewValue; + } + } + } + } + + return $aReturn; + } + + /** + * @param string $sToFolder + * @param string $sIndexRange + * @param bool $bIndexIsUid + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageCopy($sToFolder, $sIndexRange, $bIndexIsUid) + { + if (0 === \strlen($sIndexRange)) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $sCommandPrefix = ($bIndexIsUid) ? 'UID ' : ''; + return $this->SendRequestWithCheck($sCommandPrefix.'COPY', + array($sIndexRange, $this->EscapeString($sToFolder))); + } + + /** + * @param string $sToFolder + * @param string $sIndexRange + * @param bool $bIndexIsUid + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageMove($sToFolder, $sIndexRange, $bIndexIsUid) + { + if (0 === \strlen($sIndexRange)) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + if (!$this->IsSupported('MOVE')) + { + $this->writeLogException( + new Exceptions\RuntimeException('Move is not supported'), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $sCommandPrefix = ($bIndexIsUid) ? 'UID ' : ''; + return $this->SendRequestWithCheck($sCommandPrefix.'MOVE', + array($sIndexRange, $this->EscapeString($sToFolder))); + } + + /** + * @param string $sUidRangeIfSupported = '' + * @param bool $bForceUidExpunge = false + * @param bool $bExpungeAll = false + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageExpunge($sUidRangeIfSupported = '', $bForceUidExpunge = false, $bExpungeAll = false) + { + $sUidRangeIfSupported = \trim($sUidRangeIfSupported); + + $sCmd = 'EXPUNGE'; + $aArguments = array(); + + if (!$bExpungeAll && $bForceUidExpunge && 0 < \strlen($sUidRangeIfSupported) && $this->IsSupported('UIDPLUS')) + { + $sCmd = 'UID '.$sCmd; + $aArguments = array($sUidRangeIfSupported); + } + + return $this->SendRequestWithCheck($sCmd, $aArguments); + } + + /** + * @param string $sIndexRange + * @param bool $bIndexIsUid + * @param array $aInputStoreItems + * @param string $sStoreAction + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageStoreFlag($sIndexRange, $bIndexIsUid, $aInputStoreItems, $sStoreAction) + { + if (!\MailSo\Base\Validator::NotEmptyString($sIndexRange, true) || + !\MailSo\Base\Validator::NotEmptyString($sStoreAction, true) || + 0 === \count($aInputStoreItems)) + { + return false; + } + + $sCmd = ($bIndexIsUid) ? 'UID STORE' : 'STORE'; + return $this->SendRequestWithCheck($sCmd, array($sIndexRange, $sStoreAction, $aInputStoreItems)); + } + + /** + * @param string $sFolderName + * @param resource $rMessageAppendStream + * @param int $iStreamSize + * @param array $aAppendFlags = null + * @param int $iUid = null + * @param int $sDateTime = 0 + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageAppendStream($sFolderName, $rMessageAppendStream, $iStreamSize, $aAppendFlags = null, &$iUid = null, $sDateTime = 0) + { + $aData = array($this->EscapeString($sFolderName), $aAppendFlags); + if (0 < $sDateTime) + { + $aData[] = $this->EscapeString(\gmdate('d-M-Y H:i:s', $sDateTime).' +0000'); + } + + $aData[] = '{'.$iStreamSize.'}'; + + $this->SendRequest('APPEND', $aData); + $this->parseResponseWithValidation(); + + $this->writeLog('Write to connection stream', \MailSo\Log\Enumerations\Type::NOTE); + + \MailSo\Base\Utils::MultipleStreamWriter($rMessageAppendStream, array($this->rConnect)); + + $this->sendRaw(''); + $this->parseResponseWithValidation(); + + if (null !== $iUid) + { + $aLastResponse = $this->GetLastResponse(); + if (\is_array($aLastResponse) && 0 < \count($aLastResponse) && $aLastResponse[\count($aLastResponse) - 1]) + { + $oLast = $aLastResponse[count($aLastResponse) - 1]; + if ($oLast && \MailSo\Imap\Enumerations\ResponseType::TAGGED === $oLast->ResponseType && \is_array($oLast->OptionalResponse)) + { + if (0 < \strlen($oLast->OptionalResponse[0]) && + 0 < \strlen($oLast->OptionalResponse[2]) && + 'APPENDUID' === strtoupper($oLast->OptionalResponse[0]) && + \is_numeric($oLast->OptionalResponse[2]) + ) + { + $iUid = (int) $oLast->OptionalResponse[2]; + } + } + } + } + + return $this; + } + + /** + * @return \MailSo\Imap\FolderInformation + */ + public function FolderCurrentInformation() + { + return $this->oCurrentFolderInfo; + } + + /** + * @param string $sCommand + * @param array $aParams = array() + * @param bool $bBreakOnLiteral = false + * + * @return string + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + */ + public function SendRequest($sCommand, $aParams = array(), $bBreakOnLiteral = false) + { + if (!\MailSo\Base\Validator::NotEmptyString($sCommand, true) || !\is_array($aParams)) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $this->IsConnected(true); + + $sTag = $this->getNewTag(); + + $sCommand = \trim($sCommand); + $sRealCommand = $sTag.' '.$sCommand.$this->prepearParamLine($aParams); + + $sFakeCommand = ''; + $aFakeParams = $this->secureRequestParams($sCommand, $aParams); + if (null !== $aFakeParams) + { + $sFakeCommand = $sTag.' '.$sCommand.$this->prepearParamLine($aFakeParams); + } + + $this->aTagTimeouts[$sTag] = \microtime(true); + + if ($bBreakOnLiteral && !\preg_match('/\d\+\}\r\n/', $sRealCommand)) + { + $iPos = \strpos($sRealCommand, "}\r\n"); + if (false !== $iPos) + { + $iFakePos = \strpos($sFakeCommand, "}\r\n"); + + $this->sendRaw(\substr($sRealCommand, 0, $iPos + 1), true, + false !== $iFakePos ? \substr($sFakeCommand, 0, $iFakePos + 3) : ''); + + return \substr($sRealCommand, $iPos + 3); + } + } + + $this->sendRaw($sRealCommand, true, $sFakeCommand); + return ''; + } + + /** + * @param string $sCommand + * @param array $aParams + * + * @return array|null + */ + private function secureRequestParams($sCommand, $aParams) + { + $aResult = null; + switch ($sCommand) + { + case 'LOGIN': + $aResult = $aParams; + if (\is_array($aResult) && 2 === count($aResult)) + { + $aResult[1] = '"********"'; + } + break; + } + + return $aResult; + } + + /** + * @param string $sCommand + * @param array $aParams = array() + * @param bool $bFindCapa = false + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function SendRequestWithCheck($sCommand, $aParams = array(), $bFindCapa = false) + { + $this->SendRequest($sCommand, $aParams); + $this->parseResponseWithValidation(null, $bFindCapa); + + return $this; + } + + /** + * @return array + */ + public function GetLastResponse() + { + return $this->aLastResponse; + } + + /** + * @param mixed $aResult + * + * @return array + * + * @throws \MailSo\Imap\Exceptions\ResponseNotFoundException + * @throws \MailSo\Imap\Exceptions\InvalidResponseException + * @throws \MailSo\Imap\Exceptions\NegativeResponseException + */ + private function validateResponse($aResult) + { + if (!\is_array($aResult) || 0 === $iCnt = \count($aResult)) + { + $this->writeLogException( + new Exceptions\ResponseNotFoundException(), + \MailSo\Log\Enumerations\Type::WARNING, true); + } + + if ($aResult[$iCnt - 1]->ResponseType !== \MailSo\Imap\Enumerations\ResponseType::CONTINUATION) + { + if (!$aResult[$iCnt - 1]->IsStatusResponse) + { + $this->writeLogException( + new Exceptions\InvalidResponseException($aResult), + \MailSo\Log\Enumerations\Type::WARNING, true); + } + + if (\MailSo\Imap\Enumerations\ResponseStatus::OK !== $aResult[$iCnt - 1]->StatusOrIndex) + { + $this->writeLogException( + new Exceptions\NegativeResponseException($aResult), + \MailSo\Log\Enumerations\Type::WARNING, true); + } + } + + return $aResult; + } + + /** + * @param string $sEndTag = null + * @param bool $bFindCapa = false + * + * @return array|bool + */ + protected function parseResponse($sEndTag = null, $bFindCapa = false) + { + if (\is_resource($this->rConnect)) + { + $oImapResponse = null; + $sEndTag = (null === $sEndTag) ? $this->getCurrentTag() : $sEndTag; + + while (true) + { + $oImapResponse = Response::NewInstance(); + + $this->partialParseResponseBranch($oImapResponse); + + if ($oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNKNOWN === $oImapResponse->ResponseType) + { + return false; + } + + if ($bFindCapa) + { + $this->initCapabilityImapResponse($oImapResponse); + } + + $this->aPartialResponses[] = $oImapResponse; + if ($sEndTag === $oImapResponse->Tag || \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oImapResponse->ResponseType) + { + if (isset($this->aTagTimeouts[$sEndTag])) + { + $this->writeLog((\microtime(true) - $this->aTagTimeouts[$sEndTag]).' ('.$sEndTag.')', + \MailSo\Log\Enumerations\Type::TIME); + + unset($this->aTagTimeouts[$sEndTag]); + } + + break; + } + } + else + { + return false; + } + + unset($oImapResponse); + } + } + + $this->iResponseBufParsedPos = 0; + $this->aLastResponse = $this->aPartialResponses; + $this->aPartialResponses = array(); + + return $this->aLastResponse; + } + + /** + * @param string $sEndTag = null + * @param bool $bFindCapa = false + * + * @return array + */ + private function parseResponseWithValidation($sEndTag = null, $bFindCapa = false) + { + return $this->validateResponse($this->parseResponse($sEndTag, $bFindCapa)); + } + + /** + * @param \MailSo\Imap\Response $oImapResponse + * + * @return void + */ + private function initCapabilityImapResponse($oImapResponse) + { + if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType + && \is_array($oImapResponse->ResponseList)) + { + $aList = null; + if (isset($oImapResponse->ResponseList[1]) && \is_string($oImapResponse->ResponseList[1]) && + 'CAPABILITY' === \strtoupper($oImapResponse->ResponseList[1])) + { + $aList = \array_slice($oImapResponse->ResponseList, 2); + } + else if ($oImapResponse->OptionalResponse && \is_array($oImapResponse->OptionalResponse) && + 1 < \count($oImapResponse->OptionalResponse) && \is_string($oImapResponse->OptionalResponse[0]) && + 'CAPABILITY' === \strtoupper($oImapResponse->OptionalResponse[0])) + { + $aList = \array_slice($oImapResponse->OptionalResponse, 1); + } + + if (\is_array($aList) && 0 < \count($aList)) + { + $this->aCapabilityItems = \array_map('strtoupper', $aList); + } + } + } + + /** + * @return array|string + * + * @throws \MailSo\Net\Exceptions\Exception + */ + private function partialParseResponseBranch(&$oImapResponse, $iStackIndex = -1, + $bTreatAsAtom = false, $sParentToken = '', $sOpenBracket = '') + { + $mNull = null; + + $iStackIndex++; + $iPos = $this->iResponseBufParsedPos; + + $sPreviousAtomUpperCase = null; + $bIsEndOfList = false; + $bIsClosingBracketSquare = false; + $iLiteralLen = 0; + $iBufferEndIndex = 0; + $iDebugCount = 0; + + $rImapLiteralStream = null; + + $bIsGotoDefault = false; + $bIsGotoLiteral = false; + $bIsGotoLiteralEnd = false; + $bIsGotoAtomBracket = false; + $bIsGotoNotAtomBracket = false; + + $bCountOneInited = false; + $bCountTwoInited = false; + + $sAtomBuilder = $bTreatAsAtom ? '' : null; + $aList = array(); + if (null !== $oImapResponse) + { + $aList =& $oImapResponse->ResponseList; + } + + while (!$bIsEndOfList) + { + $iDebugCount++; + if (100000 === $iDebugCount) + { + $this->Logger()->Write('PartialParseOver: '.$iDebugCount, \MailSo\Log\Enumerations\Type::ERROR); + } + + if ($this->bNeedNext) + { + $iPos = 0; + $this->getNextBuffer(); + $this->iResponseBufParsedPos = $iPos; + $this->bNeedNext = false; + } + + $sChar = null; + if ($bIsGotoDefault) + { + $sChar = 'GOTO_DEFAULT'; + $bIsGotoDefault = false; + } + else if ($bIsGotoLiteral) + { + $bIsGotoLiteral = false; + $bIsGotoLiteralEnd = true; + + if ($this->partialResponseLiteralCallbackCallable( + $sParentToken, null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $this->rConnect, $iLiteralLen)) + { + if (!$bTreatAsAtom) + { + $aList[] = ''; + } + } + else + { + $sLiteral = ''; + $iRead = $iLiteralLen; + + while (0 < $iRead) + { + $sAddRead = \fread($this->rConnect, $iRead); + if (false === $sAddRead) + { + $sLiteral = false; + break; + } + + $sLiteral .= $sAddRead; + $iRead -= \strlen($sAddRead); + + \MailSo\Base\Utils::ResetTimeLimit(); + } + + if (false !== $sLiteral) + { + $iLiteralSize = \strlen($sLiteral); + \MailSo\Base\Loader::IncStatistic('NetRead', $iLiteralSize); + if ($iLiteralLen !== $iLiteralSize) + { + $this->writeLog('Literal stream read warning "read '.$iLiteralSize.' of '. + $iLiteralLen.'" bytes', \MailSo\Log\Enumerations\Type::WARNING); + } + + if (!$bTreatAsAtom) + { + $aList[] = $sLiteral; + + if (\MailSo\Config::$LogSimpleLiterals) + { + $this->writeLog('{'.\strlen($sLiteral).'} '.$sLiteral, \MailSo\Log\Enumerations\Type::INFO); + } + } + } + else + { + $this->writeLog('Can\'t read imap stream', \MailSo\Log\Enumerations\Type::NOTE); + } + + unset($sLiteral); + } + + continue; + } + else if ($bIsGotoLiteralEnd) + { + $rImapLiteralStream = null; + $sPreviousAtomUpperCase = null; + $this->bNeedNext = true; + $bIsGotoLiteralEnd = false; + + continue; + } + else if ($bIsGotoAtomBracket) + { + if ($bTreatAsAtom) + { + $sAtomBlock = $this->partialParseResponseBranch($mNull, $iStackIndex, true, + null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $sOpenBracket); + + $sAtomBuilder .= $sAtomBlock; + $iPos = $this->iResponseBufParsedPos; + $sAtomBuilder .= ($bIsClosingBracketSquare) ? ']' : ')'; + } + + $sPreviousAtomUpperCase = null; + $bIsGotoAtomBracket = false; + + continue; + } + else if ($bIsGotoNotAtomBracket) + { + $aSubItems = $this->partialParseResponseBranch($mNull, $iStackIndex, false, + null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $sOpenBracket); + + $aList[] = $aSubItems; + $iPos = $this->iResponseBufParsedPos; + $sPreviousAtomUpperCase = null; + if (null !== $oImapResponse && $oImapResponse->IsStatusResponse) + { + $oImapResponse->OptionalResponse = $aSubItems; + + $bIsGotoDefault = true; + $bIsGotoNotAtomBracket = false; + continue; + } + $bIsGotoNotAtomBracket = false; + + continue; + } + else + { + $iBufferEndIndex = \strlen($this->sResponseBuffer) - 3; + $this->bResponseBufferChanged = false; + + if ($iPos > $iBufferEndIndex) + { + break; + } + + $sChar = $this->sResponseBuffer[$iPos]; + } + + switch (true) + { + case ']' === $sChar: + $iPos++; + $sPreviousAtomUpperCase = null; + $bIsEndOfList = true; + break; + case ')' === $sChar: + $iPos++; + $sPreviousAtomUpperCase = null; + $bIsEndOfList = true; + break; + case ' ' === $sChar: + if ($bTreatAsAtom) + { + $sAtomBuilder .= ' '; + } + $iPos++; + break; + case '[' === $sChar: + $bIsClosingBracketSquare = true; + case '(' === $sChar: + if ('(' === $sChar) + { + $bIsClosingBracketSquare = false; + } + + if ($bTreatAsAtom) + { + $sAtomBuilder .= $bIsClosingBracketSquare ? '[' : '('; + } + $iPos++; + + $this->iResponseBufParsedPos = $iPos; + if ($bTreatAsAtom) + { + $bIsGotoAtomBracket = true; + $sOpenBracket = $bIsClosingBracketSquare ? '[' : '('; + } + else + { + $bIsGotoNotAtomBracket = true; + $sOpenBracket = $bIsClosingBracketSquare ? '[' : '('; + } + break; + case '{' === $sChar: + $bIsLiteralParsed = false; + $mLiteralEndPos = \strpos($this->sResponseBuffer, '}', $iPos); + if (false !== $mLiteralEndPos && $mLiteralEndPos > $iPos) + { + $sLiteralLenAsString = \substr($this->sResponseBuffer, $iPos + 1, $mLiteralEndPos - $iPos - 1); + if (\is_numeric($sLiteralLenAsString)) + { + $iLiteralLen = (int) $sLiteralLenAsString; + $bIsLiteralParsed = true; + $iPos = $mLiteralEndPos + 3; + $bIsGotoLiteral = true; + break; + } + } + if (!$bIsLiteralParsed) + { + $iPos = $iBufferEndIndex; + } + $sPreviousAtomUpperCase = null; + break; + case '"' === $sChar: + $bIsQuotedParsed = false; + while (true) + { + $iClosingPos = $iPos + 1; + if ($iClosingPos > $iBufferEndIndex) + { + break; + } + + while (true) + { + $iClosingPos = \strpos($this->sResponseBuffer, '"', $iClosingPos); + if (false === $iClosingPos) + { + break; + } + + // TODO + $iClosingPosNext = $iClosingPos + 1; + if ( + isset($this->sResponseBuffer[$iClosingPosNext]) && + ' ' !== $this->sResponseBuffer[$iClosingPosNext] && + "\r" !== $this->sResponseBuffer[$iClosingPosNext] && + "\n" !== $this->sResponseBuffer[$iClosingPosNext] && + ']' !== $this->sResponseBuffer[$iClosingPosNext] && + ')' !== $this->sResponseBuffer[$iClosingPosNext] + ) + { + $iClosingPos++; + continue; + } + + $iSlashCount = 0; + while ('\\' === $this->sResponseBuffer[$iClosingPos - $iSlashCount - 1]) + { + $iSlashCount++; + } + + if ($iSlashCount % 2 == 1) + { + $iClosingPos++; + continue; + } + else + { + break; + } + } + + if (false === $iClosingPos) + { + break; + } + else + { +// $iSkipClosingPos = 0; + $bIsQuotedParsed = true; + if ($bTreatAsAtom) + { + $sAtomBuilder .= \strtr( + \substr($this->sResponseBuffer, $iPos, $iClosingPos - $iPos + 1), + array('\\\\' => '\\', '\\"' => '"') + ); + } + else + { + $aList[] = \strtr( + \substr($this->sResponseBuffer, $iPos + 1, $iClosingPos - $iPos - 1), + array('\\\\' => '\\', '\\"' => '"') + ); + } + + $iPos = $iClosingPos + 1; + break; + } + } + + if (!$bIsQuotedParsed) + { + $iPos = $iBufferEndIndex; + } + + $sPreviousAtomUpperCase = null; + break; + + case 'GOTO_DEFAULT' === $sChar: + default: + $iCharBlockStartPos = $iPos; + + if (null !== $oImapResponse && $oImapResponse->IsStatusResponse) + { + $iPos = $iBufferEndIndex; + + while ($iPos > $iCharBlockStartPos && $this->sResponseBuffer[$iCharBlockStartPos] === ' ') + { + $iCharBlockStartPos++; + } + } + + $bIsAtomDone = false; + while (!$bIsAtomDone && ($iPos <= $iBufferEndIndex)) + { + $sCharDef = $this->sResponseBuffer[$iPos]; + switch (true) + { + case '[' === $sCharDef: + if (null === $sAtomBuilder) + { + $sAtomBuilder = ''; + } + + $sAtomBuilder .= \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos + 1); + + $iPos++; + $this->iResponseBufParsedPos = $iPos; + + $sListBlock = $this->partialParseResponseBranch($mNull, $iStackIndex, true, + null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), '['); + + if (null !== $sListBlock) + { + $sAtomBuilder .= $sListBlock.']'; + } + + $iPos = $this->iResponseBufParsedPos; + $iCharBlockStartPos = $iPos; + break; + case ' ' === $sCharDef: + case ')' === $sCharDef && '(' === $sOpenBracket: + case ']' === $sCharDef && '[' === $sOpenBracket: + $bIsAtomDone = true; + break; + default: + $iPos++; + break; + } + } + + if ($iPos > $iCharBlockStartPos || null !== $sAtomBuilder) + { + $sLastCharBlock = \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos); + if (null === $sAtomBuilder) + { + $aList[] = $sLastCharBlock; + $sPreviousAtomUpperCase = $sLastCharBlock; + } + else + { + $sAtomBuilder .= $sLastCharBlock; + + if (!$bTreatAsAtom) + { + $aList[] = $sAtomBuilder; + $sPreviousAtomUpperCase = $sAtomBuilder; + $sAtomBuilder = null; + } + } + + if (null !== $oImapResponse) + { +// if (1 === \count($aList)) + if (!$bCountOneInited && 1 === \count($aList)) +// if (isset($aList[0]) && !isset($aList[1])) // fast 1 === \count($aList) + { + $bCountOneInited = true; + + $oImapResponse->Tag = $aList[0]; + if ('+' === $oImapResponse->Tag) + { + $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::CONTINUATION; + } + else if ('*' === $oImapResponse->Tag) + { + $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::UNTAGGED; + } + else if ($this->getCurrentTag() === $oImapResponse->Tag) + { + $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::TAGGED; + } + else + { + $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::UNKNOWN; + } + } +// else if (2 === \count($aList)) + else if (!$bCountTwoInited && 2 === \count($aList)) +// else if (isset($aList[1]) && !isset($aList[2])) // fast 2 === \count($aList) + { + $bCountTwoInited = true; + + $oImapResponse->StatusOrIndex = strtoupper($aList[1]); + + if ($oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::OK || + $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::NO || + $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::BAD || + $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::BYE || + $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::PREAUTH) + { + $oImapResponse->IsStatusResponse = true; + } + } + else if (\MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oImapResponse->ResponseType) + { + $oImapResponse->HumanReadable = $sLastCharBlock; + } + else if ($oImapResponse->IsStatusResponse) + { + $oImapResponse->HumanReadable = $sLastCharBlock; + } + } + } + } + } + + $this->iResponseBufParsedPos = $iPos; + if (null !== $oImapResponse) + { + $this->bNeedNext = true; + $this->iResponseBufParsedPos = 0; + } + + if (100000 < $iDebugCount) + { + $this->Logger()->Write('PartialParseOverResult: '.$iDebugCount, \MailSo\Log\Enumerations\Type::ERROR); + } + + return $bTreatAsAtom ? $sAtomBuilder : $aList; + } + + /** + * @param string $sParent + * @param string $sLiteralAtomUpperCase + * @param resource $rImapStream + * @param int $iLiteralLen + * + * @return bool + */ + private function partialResponseLiteralCallbackCallable($sParent, $sLiteralAtomUpperCase, $rImapStream, $iLiteralLen) + { + $sLiteralAtomUpperCasePeek = ''; + if (0 === \strpos($sLiteralAtomUpperCase, 'BODY')) + { + $sLiteralAtomUpperCasePeek = \str_replace('BODY', 'BODY.PEEK', $sLiteralAtomUpperCase); + } + + $sFetchKey = ''; + if (\is_array($this->aFetchCallbacks)) + { + if (0 < \strlen($sLiteralAtomUpperCasePeek) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCasePeek])) + { + $sFetchKey = $sLiteralAtomUpperCasePeek; + } + else if (0 < \strlen($sLiteralAtomUpperCase) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCase])) + { + $sFetchKey = $sLiteralAtomUpperCase; + } + } + + $bResult = false; + if (0 < \strlen($sFetchKey) && '' !== $this->aFetchCallbacks[$sFetchKey] && + \is_callable($this->aFetchCallbacks[$sFetchKey])) + { + $rImapLiteralStream = + \MailSo\Base\StreamWrappers\Literal::CreateStream($rImapStream, $iLiteralLen); + + $bResult = true; + $this->writeLog('Start Callback for '.$sParent.' / '.$sLiteralAtomUpperCase. + ' - try to read '.$iLiteralLen.' bytes.', \MailSo\Log\Enumerations\Type::NOTE); + + $this->bRunningCallback = true; + + try + { + \call_user_func($this->aFetchCallbacks[$sFetchKey], + $sParent, $sLiteralAtomUpperCase, $rImapLiteralStream); + } + catch (\Exception $oException) + { + $this->writeLog('Callback Exception', \MailSo\Log\Enumerations\Type::NOTICE); + $this->writeLogException($oException); + } + + if (\is_resource($rImapLiteralStream)) + { + $iNotReadLiteralLen = 0; + + $bFeof = \feof($rImapLiteralStream); + $this->writeLog('End Callback for '.$sParent.' / '.$sLiteralAtomUpperCase. + ' - feof = '.($bFeof ? 'good' : 'BAD'), $bFeof ? + \MailSo\Log\Enumerations\Type::NOTE : \MailSo\Log\Enumerations\Type::WARNING); + + if (!$bFeof) + { + while (!@\feof($rImapLiteralStream)) + { + $sBuf = @\fread($rImapLiteralStream, 1024 * 1024); + if (false === $sBuf || 0 === \strlen($sBuf) || null === $sBuf) + { + break; + } + + \MailSo\Base\Utils::ResetTimeLimit(); + $iNotReadLiteralLen += \strlen($sBuf); + } + + if (\is_resource($rImapLiteralStream) && !@\feof($rImapLiteralStream)) + { + @\stream_get_contents($rImapLiteralStream); + } + } + + if (\is_resource($rImapLiteralStream)) + { + @\fclose($rImapLiteralStream); + } + + if ($iNotReadLiteralLen > 0) + { + $this->writeLog('Not read literal size is '.$iNotReadLiteralLen.' bytes.', + \MailSo\Log\Enumerations\Type::WARNING); + } + } + else + { + $this->writeLog('Literal stream is not resource after callback.', + \MailSo\Log\Enumerations\Type::WARNING); + } + + \MailSo\Base\Loader::IncStatistic('NetRead', $iLiteralLen); + + $this->bRunningCallback = false; + } + + return $bResult; + } + + /** + * @param array $aParams = null + * + * @return string + */ + private function prepearParamLine($aParams = array()) + { + $sReturn = ''; + if (\is_array($aParams) && 0 < \count($aParams)) + { + foreach ($aParams as $mParamItem) + { + if (\is_array($mParamItem) && 0 < \count($mParamItem)) + { + $sReturn .= ' ('.\trim($this->prepearParamLine($mParamItem)).')'; + } + else if (\is_string($mParamItem)) + { + $sReturn .= ' '.$mParamItem; + } + } + } + return $sReturn; + } + + /** + * @return string + */ + private function getNewTag() + { + $this->iTagCount++; + return $this->getCurrentTag(); + } + + /** + * @return string + */ + private function getCurrentTag() + { + return self::TAG_PREFIX.$this->iTagCount; + } + + /** + * @param string $sStringForEscape + * + * @return string + */ + public function EscapeString($sStringForEscape) + { + return '"'.\str_replace(array('\\', '"'), array('\\\\', '\\"'), $sStringForEscape).'"'; + } + + /** + * @return string + */ + protected function getLogName() + { + return 'IMAP'; + } + + /** + * @param \MailSo\Log\Logger $oLogger + * + * @return \MailSo\Imap\ImapClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function SetLogger($oLogger) + { + parent::SetLogger($oLogger); + + return $this; + } + + /** + * @param resource $rConnect + * @param array $aCapabilityItems = array() + * + * @return \MailSo\Imap\ImapClient + */ + public function TestSetValues($rConnect, $aCapabilityItems = array()) + { + $this->rConnect = $rConnect; + $this->aCapabilityItems = $aCapabilityItems; + + return $this; + } + + /** + * @param string $sEndTag = null + * @param string $bFindCapa = false + * + * @return array + */ + public function TestParseResponseWithValidationProxy($sEndTag = null, $bFindCapa = false) + { + return $this->parseResponseWithValidation($sEndTag, $bFindCapa); + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/NamespaceResult.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/NamespaceResult.php similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/NamespaceResult.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/NamespaceResult.php index 7d053f21..f53bd74f 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/NamespaceResult.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/NamespaceResult.php @@ -1,132 +1,132 @@ -sPersonal = ''; - $this->sPersonalDelimiter = ''; - $this->sOtherUser = ''; - $this->sOtherUserDelimiter = ''; - $this->sShared = ''; - $this->sSharedDelimiter = ''; - } - - /** - * @return \MailSo\Imap\NamespaceResult - */ - public static function NewInstance() - { - return new self(); - } - - /** - * @param \MailSo\Imap\Response $oImapResponse - * - * @return \MailSo\Imap\NamespaceResult - */ - public function InitByImapResponse($oImapResponse) - { - if ($oImapResponse && $oImapResponse instanceof \MailSo\Imap\Response) - { - if (isset($oImapResponse->ResponseList[2][0]) && - \is_array($oImapResponse->ResponseList[2][0]) && - 2 <= \count($oImapResponse->ResponseList[2][0])) - { - $this->sPersonal = $oImapResponse->ResponseList[2][0][0]; - $this->sPersonalDelimiter = $oImapResponse->ResponseList[2][0][1]; - - $this->sPersonal = 'INBOX'.$this->sPersonalDelimiter === \substr(\strtoupper($this->sPersonal), 0, 6) ? - 'INBOX'.$this->sPersonalDelimiter.\substr($this->sPersonal, 6) : $this->sPersonal; - } - - if (isset($oImapResponse->ResponseList[3][0]) && - \is_array($oImapResponse->ResponseList[3][0]) && - 2 <= \count($oImapResponse->ResponseList[3][0])) - { - $this->sOtherUser = $oImapResponse->ResponseList[3][0][0]; - $this->sOtherUserDelimiter = $oImapResponse->ResponseList[3][0][1]; - - $this->sOtherUser = 'INBOX'.$this->sOtherUserDelimiter === \substr(\strtoupper($this->sOtherUser), 0, 6) ? - 'INBOX'.$this->sOtherUserDelimiter.\substr($this->sOtherUser, 6) : $this->sOtherUser; - } - - if (isset($oImapResponse->ResponseList[4][0]) && - \is_array($oImapResponse->ResponseList[4][0]) && - 2 <= \count($oImapResponse->ResponseList[4][0])) - { - $this->sShared = $oImapResponse->ResponseList[4][0][0]; - $this->sSharedDelimiter = $oImapResponse->ResponseList[4][0][1]; - - $this->sShared = 'INBOX'.$this->sSharedDelimiter === \substr(\strtoupper($this->sShared), 0, 6) ? - 'INBOX'.$this->sSharedDelimiter.\substr($this->sShared, 6) : $this->sShared; - } - } - - return $this; - } - - /** - * @return string - */ - public function GetPersonalNamespace() - { - return $this->sPersonal; - } - - /** - * @return string - */ - public function GetPersonalNamespaceDelimiter() - { - return $this->sPersonalDelimiter; - } -} +sPersonal = ''; + $this->sPersonalDelimiter = ''; + $this->sOtherUser = ''; + $this->sOtherUserDelimiter = ''; + $this->sShared = ''; + $this->sSharedDelimiter = ''; + } + + /** + * @return \MailSo\Imap\NamespaceResult + */ + public static function NewInstance() + { + return new self(); + } + + /** + * @param \MailSo\Imap\Response $oImapResponse + * + * @return \MailSo\Imap\NamespaceResult + */ + public function InitByImapResponse($oImapResponse) + { + if ($oImapResponse && $oImapResponse instanceof \MailSo\Imap\Response) + { + if (isset($oImapResponse->ResponseList[2][0]) && + \is_array($oImapResponse->ResponseList[2][0]) && + 2 <= \count($oImapResponse->ResponseList[2][0])) + { + $this->sPersonal = $oImapResponse->ResponseList[2][0][0]; + $this->sPersonalDelimiter = $oImapResponse->ResponseList[2][0][1]; + + $this->sPersonal = 'INBOX'.$this->sPersonalDelimiter === \substr(\strtoupper($this->sPersonal), 0, 6) ? + 'INBOX'.$this->sPersonalDelimiter.\substr($this->sPersonal, 6) : $this->sPersonal; + } + + if (isset($oImapResponse->ResponseList[3][0]) && + \is_array($oImapResponse->ResponseList[3][0]) && + 2 <= \count($oImapResponse->ResponseList[3][0])) + { + $this->sOtherUser = $oImapResponse->ResponseList[3][0][0]; + $this->sOtherUserDelimiter = $oImapResponse->ResponseList[3][0][1]; + + $this->sOtherUser = 'INBOX'.$this->sOtherUserDelimiter === \substr(\strtoupper($this->sOtherUser), 0, 6) ? + 'INBOX'.$this->sOtherUserDelimiter.\substr($this->sOtherUser, 6) : $this->sOtherUser; + } + + if (isset($oImapResponse->ResponseList[4][0]) && + \is_array($oImapResponse->ResponseList[4][0]) && + 2 <= \count($oImapResponse->ResponseList[4][0])) + { + $this->sShared = $oImapResponse->ResponseList[4][0][0]; + $this->sSharedDelimiter = $oImapResponse->ResponseList[4][0][1]; + + $this->sShared = 'INBOX'.$this->sSharedDelimiter === \substr(\strtoupper($this->sShared), 0, 6) ? + 'INBOX'.$this->sSharedDelimiter.\substr($this->sShared, 6) : $this->sShared; + } + } + + return $this; + } + + /** + * @return string + */ + public function GetPersonalNamespace() + { + return $this->sPersonal; + } + + /** + * @return string + */ + public function GetPersonalNamespaceDelimiter() + { + return $this->sPersonalDelimiter; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/Response.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/Response.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/Response.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Imap/Response.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/LICENSE b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/LICENSE similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/LICENSE rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/LICENSE diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Driver.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Driver.php similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Driver.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Driver.php index fd313fc2..457b78c4 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Driver.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Driver.php @@ -1,408 +1,408 @@ -sDatePattern = 'H:i:s'; - $this->sName = 'INFO'; - $this->sNewLine = "\r\n"; - $this->bTimePrefix = true; - $this->bTypedPrefix = true; - $this->bGuidPrefix = true; - - $this->sTimeOffset = '0'; - - $this->iWriteOnTimeoutOnly = 0; - $this->bWriteOnErrorOnly = false; - $this->bWriteOnPhpErrorOnly = false; - $this->bFlushCache = false; - $this->aCache = array(); - - $this->aPrefixes = array( - \MailSo\Log\Enumerations\Type::INFO => '[DATA]', - \MailSo\Log\Enumerations\Type::SECURE => '[SECURE]', - \MailSo\Log\Enumerations\Type::NOTE => '[NOTE]', - \MailSo\Log\Enumerations\Type::TIME => '[TIME]', - \MailSo\Log\Enumerations\Type::TIME_DELTA => '[TIME]', - \MailSo\Log\Enumerations\Type::MEMORY => '[MEMORY]', - \MailSo\Log\Enumerations\Type::NOTICE => '[NOTICE]', - \MailSo\Log\Enumerations\Type::WARNING => '[WARNING]', - \MailSo\Log\Enumerations\Type::ERROR => '[ERROR]', - - \MailSo\Log\Enumerations\Type::NOTICE_PHP => '[NOTICE]', - \MailSo\Log\Enumerations\Type::WARNING_PHP => '[WARNING]', - \MailSo\Log\Enumerations\Type::ERROR_PHP => '[ERROR]', - ); - } - - /** - * @param string $sTimeOffset - * - * @return \MailSo\Log\Driver - */ - public function SetTimeOffset($sTimeOffset) - { - $this->sTimeOffset = (string) $sTimeOffset; - return $this; - } - - /** - * @return \MailSo\Log\Driver - */ - public function DisableGuidPrefix() - { - $this->bGuidPrefix = false; - return $this; - } - - /** - * @return \MailSo\Log\Driver - */ - public function DisableTimePrefix() - { - $this->bTimePrefix = false; - return $this; - } - - /** - * @param bool $bValue - * - * @return \MailSo\Log\Driver - */ - public function WriteOnErrorOnly($bValue) - { - $this->bWriteOnErrorOnly = !!$bValue; - return $this; - } - - /** - * @param bool $bValue - * - * @return \MailSo\Log\Driver - */ - public function WriteOnPhpErrorOnly($bValue) - { - $this->bWriteOnPhpErrorOnly = !!$bValue; - return $this; - } - - /** - * @param int $iTimeout - * - * @return \MailSo\Log\Driver - */ - public function WriteOnTimeoutOnly($iTimeout) - { - $this->iWriteOnTimeoutOnly = (int) $iTimeout; - if (0 > $this->iWriteOnTimeoutOnly) - { - $this->iWriteOnTimeoutOnly = 0; - } - - return $this; - } - - /** - * @return \MailSo\Log\Driver - */ - public function DisableTypedPrefix() - { - $this->bTypedPrefix = false; - return $this; - } - - /** - * @param string|array $mDesc - * @return bool - */ - abstract protected function writeImplementation($mDesc); - - /** - * @return bool - */ - protected function writeEmptyLineImplementation() - { - return $this->writeImplementation(''); - } - - /** - * @param string $sTimePrefix - * @param string $sDesc - * @param int $iType = \MailSo\Log\Enumerations\Type::INFO - * @param array $sName = '' - * - * @return string - */ - protected function loggerLineImplementation($sTimePrefix, $sDesc, - $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '') - { - return \ltrim( - ($this->bTimePrefix ? '['.$sTimePrefix.']' : ''). - ($this->bGuidPrefix ? '['.\MailSo\Log\Logger::Guid().']' : ''). - ($this->bTypedPrefix ? ' '.$this->getTypedPrefix($iType, $sName) : '') - ).$sDesc; - } - - /** - * @return bool - */ - protected function clearImplementation() - { - return true; - } - - /** - * @return string - */ - protected function getTimeWithMicroSec() - { - $aMicroTimeItems = \explode(' ', \microtime()); - return \MailSo\Log\Logger::DateHelper($this->sDatePattern, $this->sTimeOffset, $aMicroTimeItems[1]).'.'. - \str_pad((int) ($aMicroTimeItems[0] * 1000), 3, '0', STR_PAD_LEFT); - } - - /** - * @param int $iType - * @param string $sName = '' - * - * @return string - */ - protected function getTypedPrefix($iType, $sName = '') - { - $sName = 0 < \strlen($sName) ? $sName : $this->sName; - return isset($this->aPrefixes[$iType]) ? $sName.$this->aPrefixes[$iType].': ' : ''; - } - - /** - * @param string|array $mDesc - * @param bool $bDiplayCrLf = false - * - * @return string - */ - protected function localWriteImplementation($mDesc, $bDiplayCrLf = false) - { - if ($bDiplayCrLf) - { - if (\is_array($mDesc)) - { - foreach ($mDesc as &$sLine) - { - $sLine = \strtr($sLine, array("\r" => '\r', "\n" => '\n'.$this->sNewLine)); - $sLine = \rtrim($sLine); - } - } - else - { - $mDesc = \strtr($mDesc, array("\r" => '\r', "\n" => '\n'.$this->sNewLine)); - $mDesc = \rtrim($mDesc); - } - } - - return $this->writeImplementation($mDesc); - } - - /** - * @final - * @param string $sDesc - * @param int $iType = \MailSo\Log\Enumerations\Type::INFO - * @param string $sName = '' - * @param bool $bDiplayCrLf = false - * - * @return bool - */ - final public function Write($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '', $bDiplayCrLf = false) - { - $bResult = true; - if (!$this->bFlushCache && ($this->bWriteOnErrorOnly || $this->bWriteOnPhpErrorOnly || 0 < $this->iWriteOnTimeoutOnly)) - { - $bErrorPhp = false; - - $bError = $this->bWriteOnErrorOnly && \in_array($iType, array( - \MailSo\Log\Enumerations\Type::NOTICE, - \MailSo\Log\Enumerations\Type::NOTICE_PHP, - \MailSo\Log\Enumerations\Type::WARNING, - \MailSo\Log\Enumerations\Type::WARNING_PHP, - \MailSo\Log\Enumerations\Type::ERROR, - \MailSo\Log\Enumerations\Type::ERROR_PHP - )); - - if (!$bError) - { - $bErrorPhp = $this->bWriteOnPhpErrorOnly && \in_array($iType, array( - \MailSo\Log\Enumerations\Type::NOTICE_PHP, - \MailSo\Log\Enumerations\Type::WARNING_PHP, - \MailSo\Log\Enumerations\Type::ERROR_PHP - )); - } - - if ($bError || $bErrorPhp) - { - $sFlush = '--- FlushLogCache: '.($bError ? 'WriteOnErrorOnly' : 'WriteOnPhpErrorOnly'); - if (isset($this->aCache[0]) && empty($this->aCache[0])) - { - $this->aCache[0] = $sFlush; - \array_unshift($this->aCache, ''); - } - else - { - \array_unshift($this->aCache, $sFlush); - } - - $this->aCache[] = '--- FlushLogCache: Trigger'; - $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName); - - $this->bFlushCache = true; - $bResult = $this->localWriteImplementation($this->aCache, $bDiplayCrLf); - $this->aCache = array(); - } - else if (0 < $this->iWriteOnTimeoutOnly && \time() - APP_START_TIME > $this->iWriteOnTimeoutOnly) - { - $sFlush = '--- FlushLogCache: WriteOnTimeoutOnly ['.(\time() - APP_START_TIME).'sec]'; - if (isset($this->aCache[0]) && empty($this->aCache[0])) - { - $this->aCache[0] = $sFlush; - \array_unshift($this->aCache, ''); - } - else - { - \array_unshift($this->aCache, $sFlush); - } - - $this->aCache[] = '--- FlushLogCache: Trigger'; - $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName); - - $this->bFlushCache = true; - $bResult = $this->localWriteImplementation($this->aCache, $bDiplayCrLf); - $this->aCache = array(); - } - else - { - $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName); - } - } - else - { - $bResult = $this->localWriteImplementation( - $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName), $bDiplayCrLf); - } - - return $bResult; - } - - /** - * @return string - */ - public function GetNewLine() - { - return $this->sNewLine; - } - - /** - * @final - * @return bool - */ - final public function Clear() - { - return $this->clearImplementation(); - } - - /** - * @final - * @return void - */ - final public function WriteEmptyLine() - { - if (!$this->bFlushCache && ($this->bWriteOnErrorOnly || $this->bWriteOnPhpErrorOnly || 0 < $this->iWriteOnTimeoutOnly)) - { - $this->aCache[] = ''; - } - else - { - $this->writeEmptyLineImplementation(); - } - } -} +sDatePattern = 'H:i:s'; + $this->sName = 'INFO'; + $this->sNewLine = "\r\n"; + $this->bTimePrefix = true; + $this->bTypedPrefix = true; + $this->bGuidPrefix = true; + + $this->sTimeOffset = '0'; + + $this->iWriteOnTimeoutOnly = 0; + $this->bWriteOnErrorOnly = false; + $this->bWriteOnPhpErrorOnly = false; + $this->bFlushCache = false; + $this->aCache = array(); + + $this->aPrefixes = array( + \MailSo\Log\Enumerations\Type::INFO => '[DATA]', + \MailSo\Log\Enumerations\Type::SECURE => '[SECURE]', + \MailSo\Log\Enumerations\Type::NOTE => '[NOTE]', + \MailSo\Log\Enumerations\Type::TIME => '[TIME]', + \MailSo\Log\Enumerations\Type::TIME_DELTA => '[TIME]', + \MailSo\Log\Enumerations\Type::MEMORY => '[MEMORY]', + \MailSo\Log\Enumerations\Type::NOTICE => '[NOTICE]', + \MailSo\Log\Enumerations\Type::WARNING => '[WARNING]', + \MailSo\Log\Enumerations\Type::ERROR => '[ERROR]', + + \MailSo\Log\Enumerations\Type::NOTICE_PHP => '[NOTICE]', + \MailSo\Log\Enumerations\Type::WARNING_PHP => '[WARNING]', + \MailSo\Log\Enumerations\Type::ERROR_PHP => '[ERROR]', + ); + } + + /** + * @param string $sTimeOffset + * + * @return \MailSo\Log\Driver + */ + public function SetTimeOffset($sTimeOffset) + { + $this->sTimeOffset = (string) $sTimeOffset; + return $this; + } + + /** + * @return \MailSo\Log\Driver + */ + public function DisableGuidPrefix() + { + $this->bGuidPrefix = false; + return $this; + } + + /** + * @return \MailSo\Log\Driver + */ + public function DisableTimePrefix() + { + $this->bTimePrefix = false; + return $this; + } + + /** + * @param bool $bValue + * + * @return \MailSo\Log\Driver + */ + public function WriteOnErrorOnly($bValue) + { + $this->bWriteOnErrorOnly = !!$bValue; + return $this; + } + + /** + * @param bool $bValue + * + * @return \MailSo\Log\Driver + */ + public function WriteOnPhpErrorOnly($bValue) + { + $this->bWriteOnPhpErrorOnly = !!$bValue; + return $this; + } + + /** + * @param int $iTimeout + * + * @return \MailSo\Log\Driver + */ + public function WriteOnTimeoutOnly($iTimeout) + { + $this->iWriteOnTimeoutOnly = (int) $iTimeout; + if (0 > $this->iWriteOnTimeoutOnly) + { + $this->iWriteOnTimeoutOnly = 0; + } + + return $this; + } + + /** + * @return \MailSo\Log\Driver + */ + public function DisableTypedPrefix() + { + $this->bTypedPrefix = false; + return $this; + } + + /** + * @param string|array $mDesc + * @return bool + */ + abstract protected function writeImplementation($mDesc); + + /** + * @return bool + */ + protected function writeEmptyLineImplementation() + { + return $this->writeImplementation(''); + } + + /** + * @param string $sTimePrefix + * @param string $sDesc + * @param int $iType = \MailSo\Log\Enumerations\Type::INFO + * @param array $sName = '' + * + * @return string + */ + protected function loggerLineImplementation($sTimePrefix, $sDesc, + $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '') + { + return \ltrim( + ($this->bTimePrefix ? '['.$sTimePrefix.']' : ''). + ($this->bGuidPrefix ? '['.\MailSo\Log\Logger::Guid().']' : ''). + ($this->bTypedPrefix ? ' '.$this->getTypedPrefix($iType, $sName) : '') + ).$sDesc; + } + + /** + * @return bool + */ + protected function clearImplementation() + { + return true; + } + + /** + * @return string + */ + protected function getTimeWithMicroSec() + { + $aMicroTimeItems = \explode(' ', \microtime()); + return \MailSo\Log\Logger::DateHelper($this->sDatePattern, $this->sTimeOffset, $aMicroTimeItems[1]).'.'. + \str_pad((int) ($aMicroTimeItems[0] * 1000), 3, '0', STR_PAD_LEFT); + } + + /** + * @param int $iType + * @param string $sName = '' + * + * @return string + */ + protected function getTypedPrefix($iType, $sName = '') + { + $sName = 0 < \strlen($sName) ? $sName : $this->sName; + return isset($this->aPrefixes[$iType]) ? $sName.$this->aPrefixes[$iType].': ' : ''; + } + + /** + * @param string|array $mDesc + * @param bool $bDiplayCrLf = false + * + * @return string + */ + protected function localWriteImplementation($mDesc, $bDiplayCrLf = false) + { + if ($bDiplayCrLf) + { + if (\is_array($mDesc)) + { + foreach ($mDesc as &$sLine) + { + $sLine = \strtr($sLine, array("\r" => '\r', "\n" => '\n'.$this->sNewLine)); + $sLine = \rtrim($sLine); + } + } + else + { + $mDesc = \strtr($mDesc, array("\r" => '\r', "\n" => '\n'.$this->sNewLine)); + $mDesc = \rtrim($mDesc); + } + } + + return $this->writeImplementation($mDesc); + } + + /** + * @final + * @param string $sDesc + * @param int $iType = \MailSo\Log\Enumerations\Type::INFO + * @param string $sName = '' + * @param bool $bDiplayCrLf = false + * + * @return bool + */ + final public function Write($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '', $bDiplayCrLf = false) + { + $bResult = true; + if (!$this->bFlushCache && ($this->bWriteOnErrorOnly || $this->bWriteOnPhpErrorOnly || 0 < $this->iWriteOnTimeoutOnly)) + { + $bErrorPhp = false; + + $bError = $this->bWriteOnErrorOnly && \in_array($iType, array( + \MailSo\Log\Enumerations\Type::NOTICE, + \MailSo\Log\Enumerations\Type::NOTICE_PHP, + \MailSo\Log\Enumerations\Type::WARNING, + \MailSo\Log\Enumerations\Type::WARNING_PHP, + \MailSo\Log\Enumerations\Type::ERROR, + \MailSo\Log\Enumerations\Type::ERROR_PHP + )); + + if (!$bError) + { + $bErrorPhp = $this->bWriteOnPhpErrorOnly && \in_array($iType, array( + \MailSo\Log\Enumerations\Type::NOTICE_PHP, + \MailSo\Log\Enumerations\Type::WARNING_PHP, + \MailSo\Log\Enumerations\Type::ERROR_PHP + )); + } + + if ($bError || $bErrorPhp) + { + $sFlush = '--- FlushLogCache: '.($bError ? 'WriteOnErrorOnly' : 'WriteOnPhpErrorOnly'); + if (isset($this->aCache[0]) && empty($this->aCache[0])) + { + $this->aCache[0] = $sFlush; + \array_unshift($this->aCache, ''); + } + else + { + \array_unshift($this->aCache, $sFlush); + } + + $this->aCache[] = '--- FlushLogCache: Trigger'; + $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName); + + $this->bFlushCache = true; + $bResult = $this->localWriteImplementation($this->aCache, $bDiplayCrLf); + $this->aCache = array(); + } + else if (0 < $this->iWriteOnTimeoutOnly && \time() - APP_START_TIME > $this->iWriteOnTimeoutOnly) + { + $sFlush = '--- FlushLogCache: WriteOnTimeoutOnly ['.(\time() - APP_START_TIME).'sec]'; + if (isset($this->aCache[0]) && empty($this->aCache[0])) + { + $this->aCache[0] = $sFlush; + \array_unshift($this->aCache, ''); + } + else + { + \array_unshift($this->aCache, $sFlush); + } + + $this->aCache[] = '--- FlushLogCache: Trigger'; + $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName); + + $this->bFlushCache = true; + $bResult = $this->localWriteImplementation($this->aCache, $bDiplayCrLf); + $this->aCache = array(); + } + else + { + $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName); + } + } + else + { + $bResult = $this->localWriteImplementation( + $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName), $bDiplayCrLf); + } + + return $bResult; + } + + /** + * @return string + */ + public function GetNewLine() + { + return $this->sNewLine; + } + + /** + * @final + * @return bool + */ + final public function Clear() + { + return $this->clearImplementation(); + } + + /** + * @final + * @return void + */ + final public function WriteEmptyLine() + { + if (!$this->bFlushCache && ($this->bWriteOnErrorOnly || $this->bWriteOnPhpErrorOnly || 0 < $this->iWriteOnTimeoutOnly)) + { + $this->aCache[] = ''; + } + else + { + $this->writeEmptyLineImplementation(); + } + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Callback.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Drivers/Callback.php similarity index 94% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Callback.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Drivers/Callback.php index 46e87893..021d7e82 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Callback.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Drivers/Callback.php @@ -1,83 +1,83 @@ -fWriteCallback = \is_callable($fWriteCallback) ? $fWriteCallback : null; - $this->fClearCallback = \is_callable($fClearCallback) ? $fClearCallback : null; - } - - /** - * @param mixed $fWriteCallback - * @param mixed $fClearCallback = null - * - * @return \MailSo\Log\Drivers\Callback - */ - public static function NewInstance($fWriteCallback, $fClearCallback = null) - { - return new self($fWriteCallback, $fClearCallback); - } - - /** - * @param string|array $mDesc - * - * @return bool - */ - protected function writeImplementation($mDesc) - { - if ($this->fWriteCallback) - { - \call_user_func_array($this->fWriteCallback, array($mDesc)); - } - - return true; - } - - /** - * @return bool - */ - protected function clearImplementation() - { - if ($this->fClearCallback) - { - \call_user_func($this->fClearCallback); - } - - return true; - } -} +fWriteCallback = \is_callable($fWriteCallback) ? $fWriteCallback : null; + $this->fClearCallback = \is_callable($fClearCallback) ? $fClearCallback : null; + } + + /** + * @param mixed $fWriteCallback + * @param mixed $fClearCallback = null + * + * @return \MailSo\Log\Drivers\Callback + */ + public static function NewInstance($fWriteCallback, $fClearCallback = null) + { + return new self($fWriteCallback, $fClearCallback); + } + + /** + * @param string|array $mDesc + * + * @return bool + */ + protected function writeImplementation($mDesc) + { + if ($this->fWriteCallback) + { + \call_user_func_array($this->fWriteCallback, array($mDesc)); + } + + return true; + } + + /** + * @return bool + */ + protected function clearImplementation() + { + if ($this->fClearCallback) + { + \call_user_func($this->fClearCallback); + } + + return true; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/File.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Drivers/File.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/File.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Drivers/File.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Inline.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Drivers/Inline.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Inline.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Drivers/Inline.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Syslog.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Drivers/Syslog.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Syslog.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Drivers/Syslog.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Enumerations/Type.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Enumerations/Type.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Enumerations/Type.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Enumerations/Type.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Logger.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Logger.php similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Logger.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Logger.php index 82cbf541..cb5dea68 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Logger.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Log/Logger.php @@ -1,431 +1,431 @@ -bUsed = false; - $this->aForbiddenTypes = array(); - $this->aSecretWords = array(); - $this->bShowSecter = false; - $this->bHideErrorNotices = false; - - if ($bRegPhpErrorHandler) - { - \set_error_handler(array(&$this, '__phpErrorHandler')); - } - - \register_shutdown_function(array(&$this, '__loggerShutDown')); - } - - /** - * @param bool $bRegPhpErrorHandler = false - * - * @return \MailSo\Log\Logger - */ - public static function NewInstance($bRegPhpErrorHandler = false) - { - return new self($bRegPhpErrorHandler); - } - - /** - * @staticvar \MailSo\Log\Logger $oInstance; - * - * @return \MailSo\Log\Logger - */ - public static function SingletonInstance() - { - static $oInstance = null; - if (null === $oInstance) - { - $oInstance = self::NewInstance(); - } - - return $oInstance; - } - - /** - * @param string $sFormat - * @param string $sTimeOffset = '0' - * @param int $iTimestamp = 0 - * - * @return string - */ - public static function DateHelper($sFormat, $sTimeOffset = '0', $iTimestamp = null) - { - $iTimestamp = null === $iTimestamp ? \time() : (int) $iTimestamp; - return \gmdate($sFormat, $iTimestamp + \MailSo\Base\DateTimeHelper::TimeToSec((string) $sTimeOffset)); - } - - /** - * @return bool - */ - public static function IsSystemEnabled() - { - return !!(\MailSo\Config::$SystemLogger instanceof \MailSo\Log\Logger); - } - - /** - * @param mixed $mData - * @param int $iType = \MailSo\Log\Enumerations\Type::INFO - */ - public static function SystemLog($mData, $iType = \MailSo\Log\Enumerations\Type::INFO) - { - if (\MailSo\Config::$SystemLogger instanceof \MailSo\Log\Logger) - { - \MailSo\Config::$SystemLogger->WriteMixed($mData, $iType); - } - } - - /** - * @staticvar string $sCache; - * - * @return string - */ - public static function Guid() - { - static $sCache = null; - if (null === $sCache) - { - $sCache = \substr(\MailSo\Base\Utils::Md5Rand(), -8); - } - - return $sCache; - } - - /** - * @return bool - */ - public function Ping() - { - return true; - } - - /** - * @return bool - */ - public function IsEnabled() - { - return 0 < $this->Count(); - } - - /** - * @param string $sWord - * - * @return bool - */ - public function AddSecret($sWord) - { - if (\is_string($sWord) && 0 < \strlen(\trim($sWord))) - { - $this->aSecretWords[] = $sWord; - $this->aSecretWords = \array_unique($this->aSecretWords); - } - } - - /** - * @param bool $bShow - * - * @return \MailSo\Log\Logger - */ - public function SetShowSecter($bShow) - { - $this->bShowSecter = !!$bShow; - return $this; - } - - /** - * @param bool $bValue - * - * @return \MailSo\Log\Logger - */ - public function HideErrorNotices($bValue) - { - $this->bHideErrorNotices = !!$bValue; - return $this; - } - - /** - * @return bool - */ - public function IsShowSecter() - { - return $this->bShowSecter; - } - - /** - * @param int $iType - * - * @return \MailSo\Log\Logger - */ - public function AddForbiddenType($iType) - { - $this->aForbiddenTypes[$iType] = true; - - return $this; - } - - /** - * @param int $iType - * - * @return \MailSo\Log\Logger - */ - public function RemoveForbiddenType($iType) - { - $this->aForbiddenTypes[$iType] = false; - return $this; - } - - /** - * @param int $iErrNo - * @param string $sErrStr - * @param string $sErrFile - * @param int $iErrLine - * - * @return bool - */ - public function __phpErrorHandler($iErrNo, $sErrStr, $sErrFile, $iErrLine) - { - $iType = \MailSo\Log\Enumerations\Type::NOTICE_PHP; - switch ($iErrNo) - { - case E_USER_ERROR: - $iType = \MailSo\Log\Enumerations\Type::ERROR_PHP; - break; - case E_USER_WARNING: - $iType = \MailSo\Log\Enumerations\Type::WARNING_PHP; - break; - } - - $this->Write($sErrFile.' [line:'.$iErrLine.', code:'.$iErrNo.']', $iType, 'PHP'); - $this->Write('Error: '.$sErrStr, $iType, 'PHP'); - - return !!(\MailSo\Log\Enumerations\Type::NOTICE === $iType && $this->bHideErrorNotices); - } - - /** - * @return void - */ - public function __loggerShutDown() - { - if ($this->bUsed) - { - $aStatistic = \MailSo\Base\Loader::Statistic(); - if (\is_array($aStatistic)) - { - if (isset($aStatistic['php']['memory_get_peak_usage'])) - { - $this->Write('Memory peak usage: '.$aStatistic['php']['memory_get_peak_usage'], - \MailSo\Log\Enumerations\Type::MEMORY); - } - - if (isset($aStatistic['time'])) - { - $this->Write('Time delta: '.$aStatistic['time'], \MailSo\Log\Enumerations\Type::TIME_DELTA); - } - } - } - } - - /** - * @return bool - */ - public function WriteEmptyLine() - { - $iResult = 1; - - $aLoggers =& $this->GetAsArray(); - foreach ($aLoggers as /* @var $oLogger \MailSo\Log\Driver */ &$oLogger) - { - $iResult &= $oLogger->WriteEmptyLine(); - } - - return (bool) $iResult; - } - - /** - * @param string $sDesc - * @param int $iType = \MailSo\Log\Enumerations\Type::INFO - * @param string $sName = '' - * @param bool $bSearchSecretWords = true - * @param bool $bDiplayCrLf = false - * - * @return bool - */ - public function Write($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO, - $sName = '', $bSearchSecretWords = true, $bDiplayCrLf = false) - { - if (isset($this->aForbiddenTypes[$iType]) && true === $this->aForbiddenTypes[$iType]) - { - return true; - } - - $this->bUsed = true; - - $oLogger = null; - $aLoggers = array(); - $iResult = 1; - - if ($bSearchSecretWords && !$this->bShowSecter && 0 < \count($this->aSecretWords)) - { - $sDesc = \str_replace($this->aSecretWords, '*******', $sDesc); - } - - $aLoggers =& $this->GetAsArray(); - foreach ($aLoggers as /* @var $oLogger \MailSo\Log\Driver */ $oLogger) - { - $iResult &= $oLogger->Write($sDesc, $iType, $sName, $bDiplayCrLf); - } - - return (bool) $iResult; - } - - /** - * @param mixed $oValue - * @param int $iType = \MailSo\Log\Enumerations\Type::INFO - * @param string $sName = '' - * @param bool $bSearchSecretWords = false - * @param bool $bDiplayCrLf = false - * - * @return bool - */ - public function WriteDump($oValue, $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '', - $bSearchSecretWords = false, $bDiplayCrLf = false) - { - return $this->Write(\print_r($oValue, true), $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); - } - - /** - * @param \Exception $oException - * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE - * @param string $sName = '' - * @param bool $bSearchSecretWords = true - * @param bool $bDiplayCrLf = false - * - * @return bool - */ - public function WriteException($oException, $iType = \MailSo\Log\Enumerations\Type::NOTICE, $sName = '', - $bSearchSecretWords = true, $bDiplayCrLf = false) - { - if ($oException instanceof \Exception) - { - if (isset($oException->__LOGINNED__)) - { - return true; - } - - $oException->__LOGINNED__ = true; - - return $this->Write((string) $oException, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); - } - - return false; - } - - /** - * @param \Exception $oException - * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE - * @param string $sName = '' - * @param bool $bSearchSecretWords = true - * @param bool $bDiplayCrLf = false - * - * @return bool - */ - public function WriteExceptionShort($oException, $iType = \MailSo\Log\Enumerations\Type::NOTICE, $sName = '', - $bSearchSecretWords = true, $bDiplayCrLf = false) - { - if ($oException instanceof \Exception) - { - if (isset($oException->__LOGINNED__)) - { - return true; - } - - $oException->__LOGINNED__ = true; - - return $this->Write($oException->getMessage(), $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); - } - - return false; - } - - /** - * @param mixed $mData - * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE - * @param string $sName = '' - * @param bool $bSearchSecretWords = true - * @param bool $bDiplayCrLf = false - * - * @return bool - */ - public function WriteMixed($mData, $iType = null, $sName = '', - $bSearchSecretWords = true, $bDiplayCrLf = false) - { - $iType = null === $iType ? \MailSo\Log\Enumerations\Type::INFO : $iType; - if (\is_array($mData) || \is_object($mData)) - { - if ($mData instanceof \Exception) - { - $iType = null === $iType ? \MailSo\Log\Enumerations\Type::NOTICE : $iType; - return $this->WriteException($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); - } - else - { - return $this->WriteDump($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); - } - } - else - { - return $this->Write($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); - } - - return false; - } -} +bUsed = false; + $this->aForbiddenTypes = array(); + $this->aSecretWords = array(); + $this->bShowSecter = false; + $this->bHideErrorNotices = false; + + if ($bRegPhpErrorHandler) + { + \set_error_handler(array(&$this, '__phpErrorHandler')); + } + + \register_shutdown_function(array(&$this, '__loggerShutDown')); + } + + /** + * @param bool $bRegPhpErrorHandler = false + * + * @return \MailSo\Log\Logger + */ + public static function NewInstance($bRegPhpErrorHandler = false) + { + return new self($bRegPhpErrorHandler); + } + + /** + * @staticvar \MailSo\Log\Logger $oInstance; + * + * @return \MailSo\Log\Logger + */ + public static function SingletonInstance() + { + static $oInstance = null; + if (null === $oInstance) + { + $oInstance = self::NewInstance(); + } + + return $oInstance; + } + + /** + * @param string $sFormat + * @param string $sTimeOffset = '0' + * @param int $iTimestamp = 0 + * + * @return string + */ + public static function DateHelper($sFormat, $sTimeOffset = '0', $iTimestamp = null) + { + $iTimestamp = null === $iTimestamp ? \time() : (int) $iTimestamp; + return \gmdate($sFormat, $iTimestamp + \MailSo\Base\DateTimeHelper::TimeToSec((string) $sTimeOffset)); + } + + /** + * @return bool + */ + public static function IsSystemEnabled() + { + return !!(\MailSo\Config::$SystemLogger instanceof \MailSo\Log\Logger); + } + + /** + * @param mixed $mData + * @param int $iType = \MailSo\Log\Enumerations\Type::INFO + */ + public static function SystemLog($mData, $iType = \MailSo\Log\Enumerations\Type::INFO) + { + if (\MailSo\Config::$SystemLogger instanceof \MailSo\Log\Logger) + { + \MailSo\Config::$SystemLogger->WriteMixed($mData, $iType); + } + } + + /** + * @staticvar string $sCache; + * + * @return string + */ + public static function Guid() + { + static $sCache = null; + if (null === $sCache) + { + $sCache = \substr(\MailSo\Base\Utils::Md5Rand(), -8); + } + + return $sCache; + } + + /** + * @return bool + */ + public function Ping() + { + return true; + } + + /** + * @return bool + */ + public function IsEnabled() + { + return 0 < $this->Count(); + } + + /** + * @param string $sWord + * + * @return bool + */ + public function AddSecret($sWord) + { + if (\is_string($sWord) && 0 < \strlen(\trim($sWord))) + { + $this->aSecretWords[] = $sWord; + $this->aSecretWords = \array_unique($this->aSecretWords); + } + } + + /** + * @param bool $bShow + * + * @return \MailSo\Log\Logger + */ + public function SetShowSecter($bShow) + { + $this->bShowSecter = !!$bShow; + return $this; + } + + /** + * @param bool $bValue + * + * @return \MailSo\Log\Logger + */ + public function HideErrorNotices($bValue) + { + $this->bHideErrorNotices = !!$bValue; + return $this; + } + + /** + * @return bool + */ + public function IsShowSecter() + { + return $this->bShowSecter; + } + + /** + * @param int $iType + * + * @return \MailSo\Log\Logger + */ + public function AddForbiddenType($iType) + { + $this->aForbiddenTypes[$iType] = true; + + return $this; + } + + /** + * @param int $iType + * + * @return \MailSo\Log\Logger + */ + public function RemoveForbiddenType($iType) + { + $this->aForbiddenTypes[$iType] = false; + return $this; + } + + /** + * @param int $iErrNo + * @param string $sErrStr + * @param string $sErrFile + * @param int $iErrLine + * + * @return bool + */ + public function __phpErrorHandler($iErrNo, $sErrStr, $sErrFile, $iErrLine) + { + $iType = \MailSo\Log\Enumerations\Type::NOTICE_PHP; + switch ($iErrNo) + { + case E_USER_ERROR: + $iType = \MailSo\Log\Enumerations\Type::ERROR_PHP; + break; + case E_USER_WARNING: + $iType = \MailSo\Log\Enumerations\Type::WARNING_PHP; + break; + } + + $this->Write($sErrFile.' [line:'.$iErrLine.', code:'.$iErrNo.']', $iType, 'PHP'); + $this->Write('Error: '.$sErrStr, $iType, 'PHP'); + + return !!(\MailSo\Log\Enumerations\Type::NOTICE === $iType && $this->bHideErrorNotices); + } + + /** + * @return void + */ + public function __loggerShutDown() + { + if ($this->bUsed) + { + $aStatistic = \MailSo\Base\Loader::Statistic(); + if (\is_array($aStatistic)) + { + if (isset($aStatistic['php']['memory_get_peak_usage'])) + { + $this->Write('Memory peak usage: '.$aStatistic['php']['memory_get_peak_usage'], + \MailSo\Log\Enumerations\Type::MEMORY); + } + + if (isset($aStatistic['time'])) + { + $this->Write('Time delta: '.$aStatistic['time'], \MailSo\Log\Enumerations\Type::TIME_DELTA); + } + } + } + } + + /** + * @return bool + */ + public function WriteEmptyLine() + { + $iResult = 1; + + $aLoggers =& $this->GetAsArray(); + foreach ($aLoggers as /* @var $oLogger \MailSo\Log\Driver */ &$oLogger) + { + $iResult &= $oLogger->WriteEmptyLine(); + } + + return (bool) $iResult; + } + + /** + * @param string $sDesc + * @param int $iType = \MailSo\Log\Enumerations\Type::INFO + * @param string $sName = '' + * @param bool $bSearchSecretWords = true + * @param bool $bDiplayCrLf = false + * + * @return bool + */ + public function Write($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO, + $sName = '', $bSearchSecretWords = true, $bDiplayCrLf = false) + { + if (isset($this->aForbiddenTypes[$iType]) && true === $this->aForbiddenTypes[$iType]) + { + return true; + } + + $this->bUsed = true; + + $oLogger = null; + $aLoggers = array(); + $iResult = 1; + + if ($bSearchSecretWords && !$this->bShowSecter && 0 < \count($this->aSecretWords)) + { + $sDesc = \str_replace($this->aSecretWords, '*******', $sDesc); + } + + $aLoggers =& $this->GetAsArray(); + foreach ($aLoggers as /* @var $oLogger \MailSo\Log\Driver */ $oLogger) + { + $iResult &= $oLogger->Write($sDesc, $iType, $sName, $bDiplayCrLf); + } + + return (bool) $iResult; + } + + /** + * @param mixed $oValue + * @param int $iType = \MailSo\Log\Enumerations\Type::INFO + * @param string $sName = '' + * @param bool $bSearchSecretWords = false + * @param bool $bDiplayCrLf = false + * + * @return bool + */ + public function WriteDump($oValue, $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '', + $bSearchSecretWords = false, $bDiplayCrLf = false) + { + return $this->Write(\print_r($oValue, true), $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); + } + + /** + * @param \Exception $oException + * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE + * @param string $sName = '' + * @param bool $bSearchSecretWords = true + * @param bool $bDiplayCrLf = false + * + * @return bool + */ + public function WriteException($oException, $iType = \MailSo\Log\Enumerations\Type::NOTICE, $sName = '', + $bSearchSecretWords = true, $bDiplayCrLf = false) + { + if ($oException instanceof \Exception) + { + if (isset($oException->__LOGINNED__)) + { + return true; + } + + $oException->__LOGINNED__ = true; + + return $this->Write((string) $oException, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); + } + + return false; + } + + /** + * @param \Exception $oException + * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE + * @param string $sName = '' + * @param bool $bSearchSecretWords = true + * @param bool $bDiplayCrLf = false + * + * @return bool + */ + public function WriteExceptionShort($oException, $iType = \MailSo\Log\Enumerations\Type::NOTICE, $sName = '', + $bSearchSecretWords = true, $bDiplayCrLf = false) + { + if ($oException instanceof \Exception) + { + if (isset($oException->__LOGINNED__)) + { + return true; + } + + $oException->__LOGINNED__ = true; + + return $this->Write($oException->getMessage(), $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); + } + + return false; + } + + /** + * @param mixed $mData + * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE + * @param string $sName = '' + * @param bool $bSearchSecretWords = true + * @param bool $bDiplayCrLf = false + * + * @return bool + */ + public function WriteMixed($mData, $iType = null, $sName = '', + $bSearchSecretWords = true, $bDiplayCrLf = false) + { + $iType = null === $iType ? \MailSo\Log\Enumerations\Type::INFO : $iType; + if (\is_array($mData) || \is_object($mData)) + { + if ($mData instanceof \Exception) + { + $iType = null === $iType ? \MailSo\Log\Enumerations\Type::NOTICE : $iType; + return $this->WriteException($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); + } + else + { + return $this->WriteDump($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); + } + } + else + { + return $this->Write($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf); + } + + return false; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Attachment.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Attachment.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Attachment.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Attachment.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/AttachmentCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/AttachmentCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/AttachmentCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/AttachmentCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Exceptions/Exception.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/Exception.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Exceptions/Exception.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/NonEmptyFolder.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Exceptions/NonEmptyFolder.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/NonEmptyFolder.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Exceptions/NonEmptyFolder.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/RuntimeException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Exceptions/RuntimeException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/RuntimeException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Exceptions/RuntimeException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Folder.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Folder.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Folder.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Folder.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/FolderCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/FolderCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/FolderCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/FolderCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/MailClient.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/MailClient.php similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/MailClient.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/MailClient.php index ff0500fa..2803d219 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/MailClient.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/MailClient.php @@ -1,2677 +1,2678 @@ -oLogger = null; - - $this->oImapClient = \MailSo\Imap\ImapClient::NewInstance(); - $this->oImapClient->SetTimeOuts(10, \MailSo\Config::$ImapTimeout); - } - - /** - * @return \MailSo\Mail\MailClient - */ - public static function NewInstance() - { - return new self(); - } - - /** - * @return \MailSo\Imap\ImapClient - */ - public function ImapClient() - { - return $this->oImapClient; - } - - /** - * @param string $sServerName - * @param int $iPort = 143 - * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT - * @param bool $bVerifySsl = false - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function Connect($sServerName, $iPort = 143, - $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false) - { - $this->oImapClient->Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl); - return $this; - } - - /** - * @param string $sLogin - * @param string $sPassword - * @param string $sProxyAuthUser = '' - * @param bool $bUseAuthPlainIfSupported = true - * @param bool $bUseAuthCramMd5IfSupported = true - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\LoginException - */ - public function Login($sLogin, $sPassword, $sProxyAuthUser = '', - $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true) - { - $this->oImapClient->Login($sLogin, $sPassword, $sProxyAuthUser, $bUseAuthPlainIfSupported, $bUseAuthCramMd5IfSupported); - return $this; - } - - /** - * @param string $sXOAuth2Token - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\LoginException - */ - public function LoginWithXOauth2($sXOAuth2Token) - { - $this->oImapClient->LoginWithXOauth2($sXOAuth2Token); - return $this; - } - - /** - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Net\Exceptions\Exception - */ - public function Logout() - { - $this->oImapClient->Logout(); - return $this; - } - - /** - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Net\Exceptions\Exception - */ - public function Disconnect() - { - $this->oImapClient->Disconnect(); - return $this; - } - - /** - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Net\Exceptions\Exception - */ - public function LogoutAndDisconnect() - { - return $this->Logout()->Disconnect(); - } - - /** - * @return bool - */ - public function IsConnected() - { - return $this->oImapClient->IsConnected(); - } - - /** - * @return bool - */ - public function IsLoggined() - { - return $this->oImapClient->IsLoggined(); - } - - /** - * @return string - */ - private function getEnvelopeOrHeadersRequestStringForSimpleList() - { - return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( - \MailSo\Mime\Enumerations\Header::RETURN_PATH, - \MailSo\Mime\Enumerations\Header::RECEIVED, - \MailSo\Mime\Enumerations\Header::MIME_VERSION, - \MailSo\Mime\Enumerations\Header::FROM_, - \MailSo\Mime\Enumerations\Header::TO_, - \MailSo\Mime\Enumerations\Header::CC, - \MailSo\Mime\Enumerations\Header::SENDER, - \MailSo\Mime\Enumerations\Header::REPLY_TO, - \MailSo\Mime\Enumerations\Header::DATE, - \MailSo\Mime\Enumerations\Header::SUBJECT, - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, - \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE, - ), true); - } - - /** - * @return string - */ - private function getEnvelopeOrHeadersRequestString() - { - if (\MailSo\Config::$MessageAllHeaders) - { - return \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK; - } - - return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( - \MailSo\Mime\Enumerations\Header::RETURN_PATH, - \MailSo\Mime\Enumerations\Header::RECEIVED, - \MailSo\Mime\Enumerations\Header::MIME_VERSION, - \MailSo\Mime\Enumerations\Header::MESSAGE_ID, - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, - \MailSo\Mime\Enumerations\Header::FROM_, - \MailSo\Mime\Enumerations\Header::TO_, - \MailSo\Mime\Enumerations\Header::CC, - \MailSo\Mime\Enumerations\Header::BCC, - \MailSo\Mime\Enumerations\Header::SENDER, - \MailSo\Mime\Enumerations\Header::REPLY_TO, - \MailSo\Mime\Enumerations\Header::DELIVERED_TO, - \MailSo\Mime\Enumerations\Header::IN_REPLY_TO, - \MailSo\Mime\Enumerations\Header::REFERENCES, - \MailSo\Mime\Enumerations\Header::DATE, - \MailSo\Mime\Enumerations\Header::SUBJECT, - \MailSo\Mime\Enumerations\Header::SENSITIVITY, - \MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY, - \MailSo\Mime\Enumerations\Header::IMPORTANCE, - \MailSo\Mime\Enumerations\Header::X_PRIORITY, - \MailSo\Mime\Enumerations\Header::X_DRAFT_INFO, - \MailSo\Mime\Enumerations\Header::RETURN_RECEIPT_TO, - \MailSo\Mime\Enumerations\Header::DISPOSITION_NOTIFICATION_TO, - \MailSo\Mime\Enumerations\Header::X_CONFIRM_READING_TO, - \MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS, - \MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS, - \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE, - ), true); -// -// return \MailSo\Imap\Enumerations\FetchType::ENVELOPE; - } - - /** - * @param string $sFolderName - * @param string $sMessageFlag - * @param bool $bSetAction = true - * @param bool $sSkipUnsupportedFlag = false - * @param array $aCustomUids = null - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - * @throws \MailSo\Mail\Exceptions\Exception - */ - public function MessageSetFlagToAll($sFolderName, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false, $aCustomUids = null) - { - $this->oImapClient->FolderSelect($sFolderName); - - $oFolderInfo = $this->oImapClient->FolderCurrentInformation(); - if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag)) - { - if (!$sSkipUnsupportedFlag) - { - throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.'); - } - } - - if ($oFolderInfo && 0 < $oFolderInfo->Exists) - { - $sStoreAction = $bSetAction - ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT - : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT - ; - - if (is_array($aCustomUids)) - { - if (0 < count($aCustomUids)) - { - $this->oImapClient->MessageStoreFlag(implode(',', $aCustomUids), true, array($sMessageFlag), $sStoreAction); - } - } - else - { - $this->oImapClient->MessageStoreFlag('1:*', false, array($sMessageFlag), $sStoreAction); - } - } - } - - /** - * @param string $sFolderName - * @param array $aIndexRange - * @param bool $bIndexIsUid - * @param string $sMessageFlag - * @param bool $bSetAction = true - * @param bool $sSkipUnsupportedFlag = false - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - * @throws \MailSo\Mail\Exceptions\Exception - */ - public function MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false) - { - $this->oImapClient->FolderSelect($sFolderName); - - $oFolderInfo = $this->oImapClient->FolderCurrentInformation(); - if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag)) - { - if (!$sSkipUnsupportedFlag) - { - throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.'); - } - } - else - { - $sStoreAction = $bSetAction - ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT - : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT - ; - - $this->oImapClient->MessageStoreFlag(\MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), - $bIndexIsUid, array($sMessageFlag), $sStoreAction); - } - } - - /** - * @param string $sFolderName - * @param array $aIndexRange - * @param bool $bIndexIsUid - * @param bool $bSetAction = true - * @param bool $sSkipUnsupportedFlag = false - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageSetFlagged($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true, $sSkipUnsupportedFlag = false) - { - $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, - \MailSo\Imap\Enumerations\MessageFlag::FLAGGED, $bSetAction, $sSkipUnsupportedFlag); - } - - /** - * @param string $sFolderName - * @param bool $bSetAction = true - * @param array $aCustomUids = null - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageSetSeenToAll($sFolderName, $bSetAction = true, $aCustomUids = null) - { - $this->MessageSetFlagToAll($sFolderName, \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true, $aCustomUids); - } - - /** - * @param string $sFolderName - * @param array $aIndexRange - * @param bool $bIndexIsUid - * @param bool $bSetAction = true - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageSetSeen($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true) - { - $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, - \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true); - } - - /** - * @param string $sFolderName - * @param int $iIndex - * @param bool $bIndexIsUid = true - * @param \MailSo\Cache\CacheClient $oCacher = null - * @param int $iBodyTextLimit = null - * - * @return \MailSo\Mail\Message|false - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function Message($sFolderName, $iIndex, $bIndexIsUid = true, $oCacher = null, $iBodyTextLimit = null) - { - if (!\MailSo\Base\Validator::RangeInt($iIndex, 1)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderSelect($sFolderName); - - $oBodyStructure = null; - $oMessage = false; - - $aBodyPeekMimeIndexes = array(); - $aSignatureMimeIndexes = array(); - - $aFetchResponse = $this->oImapClient->Fetch(array(\MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE), $iIndex, $bIndexIsUid); - if (0 < \count($aFetchResponse) && isset($aFetchResponse[0])) - { - $oBodyStructure = $aFetchResponse[0]->GetFetchBodyStructure(); - if ($oBodyStructure) - { - $aTextParts = $oBodyStructure->SearchHtmlOrPlainParts(); - if (is_array($aTextParts) && 0 < \count($aTextParts)) - { - foreach ($aTextParts as $oPart) - { - $aBodyPeekMimeIndexes[] = array($oPart->PartID(), $oPart->Size()); - } - } - - $aSignatureParts = $oBodyStructure->SearchByContentType('application/pgp-signature'); - if (is_array($aSignatureParts) && 0 < \count($aSignatureParts)) - { - foreach ($aSignatureParts as $oPart) - { - $aSignatureMimeIndexes[] = $oPart->PartID(); - } - } - } - } - - $aFetchItems = array( - \MailSo\Imap\Enumerations\FetchType::INDEX, - \MailSo\Imap\Enumerations\FetchType::UID, - \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, - \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, - \MailSo\Imap\Enumerations\FetchType::FLAGS, - $this->getEnvelopeOrHeadersRequestString() - ); - - if (0 < \count($aBodyPeekMimeIndexes)) - { - foreach ($aBodyPeekMimeIndexes as $aTextMimeData) - { - $sLine = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$aTextMimeData[0].']'; - if (\is_numeric($iBodyTextLimit) && 0 < $iBodyTextLimit && $iBodyTextLimit < $aTextMimeData[1]) - { - $sLine .= '<0.'.((int) $iBodyTextLimit).'>'; - } - - $aFetchItems[] = $sLine; - } - } - - if (0 < \count($aSignatureMimeIndexes)) - { - foreach ($aSignatureMimeIndexes as $sTextMimeIndex) - { - $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sTextMimeIndex.']'; - } - } - - if (!$oBodyStructure) - { - $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE; - } - - $aFetchResponse = $this->oImapClient->Fetch($aFetchItems, $iIndex, $bIndexIsUid); - if (0 < \count($aFetchResponse)) - { - $oMessage = \MailSo\Mail\Message::NewFetchResponseInstance( - $sFolderName, $aFetchResponse[0], $oBodyStructure); - } - - return $oMessage; - } - - /** - * @param mixed $mCallback - * @param string $sFolderName - * @param int $iIndex - * @param bool $bIndexIsUid = true, - * @param string $sMimeIndex = '' - * - * @return bool - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageMimeStream($mCallback, $sFolderName, $iIndex, $bIndexIsUid = true, $sMimeIndex = '') - { - if (!is_callable($mCallback)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderSelect($sFolderName); - - $sFileName = ''; - $sContentType = ''; - $sMailEncodingName = ''; - - $sMimeIndex = trim($sMimeIndex); - $aFetchResponse = $this->oImapClient->Fetch(array( - 0 === \strlen($sMimeIndex) - ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK - : \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.'.MIME]' - ), $iIndex, $bIndexIsUid); - - if (0 < \count($aFetchResponse)) - { - $sMime = $aFetchResponse[0]->GetFetchValue( - 0 === \strlen($sMimeIndex) - ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER - : \MailSo\Imap\Enumerations\FetchType::BODY.'['.$sMimeIndex.'.MIME]' - ); - - if (0 < \strlen($sMime)) - { - $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sMime); - - if (0 < \strlen($sMimeIndex)) - { - $sFileName = $oHeaders->ParameterValue( - \MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION, - \MailSo\Mime\Enumerations\Parameter::FILENAME); - - if (0 === \strlen($sFileName)) - { - $sFileName = $oHeaders->ParameterValue( - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, - \MailSo\Mime\Enumerations\Parameter::NAME); - } - - $sMailEncodingName = $oHeaders->ValueByName( - \MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING); - - $sContentType = $oHeaders->ValueByName( - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE); - } - else - { - $sSubject = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT); - - $sFileName = 0 === \strlen($sSubject) ? (string) $iIndex : $sSubject; - $sFileName .= '.eml'; - - $sContentType = 'message/rfc822'; - } - } - } - - $aFetchResponse = $this->oImapClient->Fetch(array( - array(\MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.']', - function ($sParent, $sLiteralAtomUpperCase, $rImapLiteralStream) use ($mCallback, $sMimeIndex, $sMailEncodingName, $sContentType, $sFileName) - { - if (0 < \strlen($sLiteralAtomUpperCase)) - { - if (is_resource($rImapLiteralStream) && 'FETCH' === $sParent) - { - $rMessageMimeIndexStream = (0 === \strlen($sMailEncodingName)) - ? $rImapLiteralStream - : \MailSo\Base\StreamWrappers\Binary::CreateStream($rImapLiteralStream, - \MailSo\Base\StreamWrappers\Binary::GetInlineDecodeOrEncodeFunctionName( - $sMailEncodingName, true)); - - \call_user_func($mCallback, $rMessageMimeIndexStream, $sContentType, $sFileName, $sMimeIndex); - } - } - } - )), $iIndex, $bIndexIsUid); - - return ($aFetchResponse && 1 === \count($aFetchResponse)); - } - - /** - * @param string $sFolder - * @param array $aIndexRange - * @param bool $bIndexIsUid - * @param bool $bUseExpunge = true - * @param bool $bExpungeAll = false - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageDelete($sFolder, $aIndexRange, $bIndexIsUid, $bUseExpunge = true, $bExpungeAll = false) - { - if (0 === \strlen($sFolder) || !\is_array($aIndexRange) || 0 === \count($aIndexRange)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderSelect($sFolder); - - $sIndexRange = \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange); - - $this->oImapClient->MessageStoreFlag($sIndexRange, $bIndexIsUid, - array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), - \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT - ); - - if ($bUseExpunge) - { - $this->oImapClient->MessageExpunge($bIndexIsUid ? $sIndexRange : '', $bIndexIsUid, $bExpungeAll); - } - - return $this; - } - - /** - * @param string $sFromFolder - * @param string $sToFolder - * @param array $aIndexRange - * @param bool $bIndexIsUid - * @param bool $bUseMoveSupported = false - * @param bool $bExpungeAll = false - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageMove($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid, $bUseMoveSupported = false, $bExpungeAll = false) - { - if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) || - !\is_array($aIndexRange) || 0 === \count($aIndexRange)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderSelect($sFromFolder); - - if ($bUseMoveSupported && $this->oImapClient->IsSupported('MOVE')) - { - $this->oImapClient->MessageMove($sToFolder, - \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); - } - else - { - $this->oImapClient->MessageCopy($sToFolder, - \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); - - $this->MessageDelete($sFromFolder, $aIndexRange, $bIndexIsUid, true, $bExpungeAll); - } - - return $this; - } - - /** - * @param string $sFromFolder - * @param string $sToFolder - * @param array $aIndexRange - * @param bool $bIndexIsUid - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageCopy($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid) - { - if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) || - !\is_array($aIndexRange) || 0 === \count($aIndexRange)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderSelect($sFromFolder); - $this->oImapClient->MessageCopy($sToFolder, - \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); - - return $this; - } - - /** - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderUnSelect() - { - if ($this->oImapClient->IsSelected()) - { - $this->oImapClient->FolderUnSelect(); - } - - return $this; - } - - /** - * @param resource $rMessageStream - * @param int $iMessageStreamSize - * @param string $sFolderToSave - * @param array $aAppendFlags = null - * @param int $iUid = null - * - * @return \MailSo\Mail\MailClient - */ - public function MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags = null, &$iUid = null) - { - if (!\is_resource($rMessageStream) || 0 === \strlen($sFolderToSave)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->MessageAppendStream( - $sFolderToSave, $rMessageStream, $iMessageStreamSize, $aAppendFlags, $iUid); - - return $this; - } - - /** - * @param string $sMessageFileName - * @param string $sFolderToSave - * @param array $aAppendFlags = null - * @param int &$iUid = null - * - * @return \MailSo\Mail\MailClient - */ - public function MessageAppendFile($sMessageFileName, $sFolderToSave, $aAppendFlags = null, &$iUid = null) - { - if (!@\is_file($sMessageFileName) || !@\is_readable($sMessageFileName)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $iMessageStreamSize = \filesize($sMessageFileName); - $rMessageStream = \fopen($sMessageFileName, 'rb'); - - $this->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags, $iUid); - - if (\is_resource($rMessageStream)) - { - @fclose($rMessageStream); - } - - return $this; - } - - /** - * @param string $sFolderName - * @param int $iCount - * @param int $iUnseenCount - * @param string $sUidNext - * @param string $sHighestModSeq - * - * @return void - */ - protected function initFolderValues($sFolderName, &$iCount, &$iUnseenCount, - &$sUidNext, &$sHighestModSeq = '') - { - $aTypes = array( - \MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES, - \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN, - \MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT - ); - - if ($this->oImapClient->IsSupported('CONDSTORE')) - { - $aTypes[] = \MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ; - } - - $aFolderStatus = $this->oImapClient->FolderStatus($sFolderName, $aTypes); - - $iCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES]) - ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES] : 0; - - $iUnseenCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) - ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0; - - $sUidNext = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT]) - ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT] : '0'; - - $sHighestModSeq = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ]) - ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ] : ''; - - if ($this->IsGmail() && - ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7)))) - { - $oFolder = $this->oImapClient->FolderCurrentInformation(); - if ($oFolder && null !== $oFolder->Exists && $oFolder->FolderName === $sFolderName) - { - $iSubCount = (int) $oFolder->Exists; - if (0 < $iSubCount && $iSubCount < $iCount) - { - $iCount = $iSubCount; - } - } - } - } - - /** - * @return string - */ - public function GenerateImapClientHash() - { - return \md5('ImapClientHash/'. - $this->oImapClient->GetLogginedUser().'@'. - $this->oImapClient->GetConnectedHost().':'. - $this->oImapClient->GetConnectedPort() - ); - } - - /** - * @param string $sFolder - * @param int $iCount - * @param int $iUnseenCount - * @param string $sUidNext - * @param string $sHighestModSeq = '' - * - * @return string - */ - public function GenerateFolderHash($sFolder, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq = '') - { - $iUnseenCount = 0; // unneccessery - return \md5('FolderHash/'.$sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext.'-'. - $sHighestModSeq.'-'.$this->GenerateImapClientHash().'-'. - \MailSo\Config::$MessageListPermanentFilter - ); - } - - /** - * @param string $sFolderName - * @param string $sPrevUidNext - * @param string $sCurrentUidNext - * - * @return array - */ - private function getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sCurrentUidNext) - { - $aNewMessages = array(); - - if (0 < \strlen($sPrevUidNext) && (string) $sPrevUidNext !== (string) $sCurrentUidNext) - { - $this->oImapClient->FolderSelect($sFolderName); - - $aFetchResponse = $this->oImapClient->Fetch(array( - \MailSo\Imap\Enumerations\FetchType::INDEX, - \MailSo\Imap\Enumerations\FetchType::UID, - \MailSo\Imap\Enumerations\FetchType::FLAGS, - \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( - \MailSo\Mime\Enumerations\Header::FROM_, - \MailSo\Mime\Enumerations\Header::SUBJECT, - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE - )) - ), $sPrevUidNext.':*', true); - - if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) - { - foreach ($aFetchResponse as /* @var $oFetchResponse \MailSo\Imap\FetchResponse */ $oFetchResponse) - { - $aFlags = \array_map('strtolower', $oFetchResponse->GetFetchValue( - \MailSo\Imap\Enumerations\FetchType::FLAGS)); - - if (!\in_array(\strtolower(\MailSo\Imap\Enumerations\MessageFlag::SEEN), $aFlags)) - { - $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); - $sHeaders = $oFetchResponse->GetHeaderFieldsValue(); - - $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sHeaders); - - $sContentTypeCharset = $oHeaders->ParameterValue( - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, - \MailSo\Mime\Enumerations\Parameter::CHARSET - ); - - $sCharset = ''; - if (0 < \strlen($sContentTypeCharset)) - { - $sCharset = $sContentTypeCharset; - } - - if (0 < \strlen($sCharset)) - { - $oHeaders->SetParentCharset($sCharset); - } - - $aNewMessages[] = array( - 'Folder' => $sFolderName, - 'Uid' => $sUid, - 'Subject' => $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT, 0 === \strlen($sCharset)), - 'From' => $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::FROM_, 0 === \strlen($sCharset)) - ); - } - } - } - } - - return $aNewMessages; - } - - /** - * @param string $sFolderName - * @param string $sPrevUidNext = '' - * @param array $aUids = '' - * - * @return string - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderInformation($sFolderName, $sPrevUidNext = '', $aUids = array()) - { - $aFlags = array(); - - $bSelect = false; - if ($this->IsGmail() && - ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7)))) - { - $this->oImapClient->FolderSelect($sFolderName); - $bSelect = true; - } - - if (\is_array($aUids) && 0 < \count($aUids)) - { - if (!$bSelect) - { - $this->oImapClient->FolderSelect($sFolderName); - } - - $aFetchResponse = $this->oImapClient->Fetch(array( - \MailSo\Imap\Enumerations\FetchType::INDEX, - \MailSo\Imap\Enumerations\FetchType::UID, - \MailSo\Imap\Enumerations\FetchType::FLAGS - ), \MailSo\Base\Utils::PrepearFetchSequence($aUids), true); - - if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) - { - foreach ($aFetchResponse as $oFetchResponse) - { - $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); - $aFlags[(\is_numeric($sUid) ? (int) $sUid : 0)] = - $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS); - } - } - } - - $iCount = 0; - $iUnseenCount = 0; - $sUidNext = '0'; - $sHighestModSeq = ''; - - $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); - - $aResult = array( - 'Folder' => $sFolderName, - 'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq), - 'MessageCount' => $iCount, - 'MessageUnseenCount' => $iUnseenCount, - 'UidNext' => $sUidNext, - 'Flags' => $aFlags, - 'HighestModSeq' => $sHighestModSeq, - 'NewMessages' => 'INBOX' === $sFolderName && \MailSo\Config::$CheckNewMessages ? - $this->getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sUidNext) : array() - ); - - return $aResult; - } - - /** - * @param string $sFolderName - * - * @return string - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderHash($sFolderName) - { - $iCount = 0; - $iUnseenCount = 0; - $sUidNext = '0'; - $sHighestModSeq = ''; - - $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); - - return $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); - } - - /** - * @return int - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function InboxUnreadCount() - { - $aFolderStatus = $this->oImapClient->FolderStatus('INBOX', array( - \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN - )); - - $iResult = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) ? - (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0; - - return 0 < $iResult ? $iResult : 0; - } - - /** - * @return bool - */ - public function IsGmail() - { - return 'ssl://imap.gmail.com' === \strtolower($this->oImapClient->GetConnectedHost()); - } - - /** - * @param string $sSearch - * @param bool $bDetectGmail = true - * - * @return string - */ - private function escapeSearchString($sSearch, $bDetectGmail = true) - { - return !\MailSo\Base\Utils::IsAscii($sSearch) - ? '{'.\strlen($sSearch).'}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch); -// return ($bDetectGmail && !\MailSo\Base\Utils::IsAscii($sSearch) && $this->IsGmail()) -// ? '{'.\strlen($sSearch).'+}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch); - } - - /** - * @param string $sDate - * @param int $iTimeZoneOffset - * - * @return int - */ - private function parseSearchDate($sDate, $iTimeZoneOffset) - { - $iResult = 0; - if (0 < \strlen($sDate)) - { - $oDateTime = \DateTime::createFromFormat('Y.m.d', $sDate, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject()); - return $oDateTime ? $oDateTime->getTimestamp() - $iTimeZoneOffset : 0; - } - - return $iResult; - } - - /** - * @param string $sSize - * - * @return int - */ - private function parseFriendlySize($sSize) - { - $sSize = preg_replace('/[^0-9bBkKmM]/', '', $sSize); - - $iResult = 0; - $aMatch = array(); - - if (\preg_match('/([\d]+)(B|KB|M|MB|G|GB)$/i', $sSize, $aMatch) && isset($aMatch[1], $aMatch[2])) - { - $iResult = (int) $aMatch[1]; - switch (\strtoupper($aMatch[2])) - { - case 'K': - case 'KB': - $iResult *= 1024; - case 'M': - case 'MB': - $iResult *= 1024; - case 'G': - case 'GB': - $iResult *= 1024; - } - } - else - { - $iResult = (int) $sSize; - } - - return $iResult; - } - - /** - * @param string $sSearch - * - * @return array - */ - private function parseSearchString($sSearch) - { - $aResult = array( - 'OTHER' => '' - ); - - $aCache = array(); - - $sReg = 'e?mail|from|to|subject|has|is|date|text|body|size|larger|bigger|smaller|maxsize|minsize'; - - $sSearch = \MailSo\Base\Utils::StripSpaces($sSearch); - $sSearch = \trim(\preg_replace('/('.$sReg.'): /i', '\\1:', $sSearch)); - - $mMatch = array(); - \preg_match_all('/".*?(? $sName) - { - if (isset($mMatch[2][$iIndex]) && 0 < \strlen($mMatch[2][$iIndex])) - { - $sName = \strtoupper($sName); - $sValue = $mMatch[2][$iIndex]; - switch ($sName) - { - case 'TEXT': - case 'BODY': - case 'EMAIL': - case 'MAIL': - case 'FROM': - case 'TO': - case 'SUBJECT': - case 'IS': - case 'HAS': - case 'SIZE': - case 'SMALLER': - case 'LARGER': - case 'BIGGER': - case 'MAXSIZE': - case 'MINSIZE': - case 'DATE': - if ('MAIL' === $sName) - { - $sName = 'EMAIL'; - } - if ('BODY' === $sName) - { - $sName = 'TEXT'; - } - if ('SIZE' === $sName || 'BIGGER' === $sName || 'MINSIZE' === $sName) - { - $sName = 'LARGER'; - } - if ('MAXSIZE' === $sName) - { - $sName = 'SMALLER'; - } - $aResult[$sName] = $sValue; - break; - } - } - } - } - - $aResult['OTHER'] = $sSearch; - foreach ($aResult as $sName => $sValue) - { - if (isset($aCache[$sValue])) - { - $aResult[$sName] = \trim($aCache[$sValue], '"\' '); - } - } - - return $aResult; - } - - /** - * @param string $sSearch - * @param string $sFilter - * @param int $iTimeZoneOffset = 0 - * @param bool $bUseCache = true - * - * @return string - */ - private function getImapSearchCriterias($sSearch, $sFilter, $iTimeZoneOffset = 0, &$bUseCache = true) - { - $bUseCache = true; - $iTimeFilter = 0; - $aCriteriasResult = array(); - - if (0 < \MailSo\Config::$MessageListDateFilter) - { - $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter; - $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD)); - } - - if (0 < \strlen(\trim($sSearch))) - { - $sGmailRawSearch = ''; - $sResultBodyTextSearch = ''; - - $aLines = $this->parseSearchString($sSearch); - $bIsGmail = $this->oImapClient->IsSupported('X-GM-EXT-1'); - - if (1 === \count($aLines) && isset($aLines['OTHER'])) - { - $sValue = $this->escapeSearchString($aLines['OTHER']); - - if (\MailSo\Config::$MessageListFastSimpleSearch) - { - $aCriteriasResult[] = 'OR OR OR'; - $aCriteriasResult[] = 'FROM'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'TO'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'CC'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'SUBJECT'; - $aCriteriasResult[] = $sValue; - } - else - { - $aCriteriasResult[] = 'TEXT'; - $aCriteriasResult[] = $sValue; - } - } - else - { - if (isset($aLines['EMAIL'])) - { - $sValue = $this->escapeSearchString($aLines['EMAIL']); - - $aCriteriasResult[] = 'OR OR'; - $aCriteriasResult[] = 'FROM'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'TO'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'CC'; - $aCriteriasResult[] = $sValue; - - unset($aLines['EMAIL']); - } - - if (isset($aLines['TO'])) - { - $sValue = $this->escapeSearchString($aLines['TO']); - - $aCriteriasResult[] = 'OR'; - $aCriteriasResult[] = 'TO'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'CC'; - $aCriteriasResult[] = $sValue; - - unset($aLines['TO']); - } - - $sMainText = ''; - foreach ($aLines as $sName => $sRawValue) - { - if ('' === \trim($sRawValue)) - { - continue; - } - - $sValue = $this->escapeSearchString($sRawValue); - switch ($sName) - { - case 'FROM': - $aCriteriasResult[] = 'FROM'; - $aCriteriasResult[] = $sValue; - break; - case 'SUBJECT': - $aCriteriasResult[] = 'SUBJECT'; - $aCriteriasResult[] = $sValue; - break; - case 'OTHER': - case 'TEXT': - $sMainText .= ' '.$sRawValue; - break; - case 'HAS': - $aValue = \explode(',', \strtolower($sRawValue)); - $aValue = \array_map('trim', $aValue); - - $aCompareArray = array('file', 'files', 'attach', 'attachs', 'attachment', 'attachments'); - if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) - { - if ($bIsGmail) - { - $sGmailRawSearch .= ' has:attachment'; - } - else - { - // Simple, is not detailed search (Sometimes doesn't work) - $aCriteriasResult[] = 'OR OR OR'; - $aCriteriasResult[] = 'HEADER Content-Type application/'; - $aCriteriasResult[] = 'HEADER Content-Type multipart/m'; - $aCriteriasResult[] = 'HEADER Content-Type multipart/signed'; - $aCriteriasResult[] = 'HEADER Content-Type multipart/report'; - } - } - - case 'IS': - $aValue = \explode(',', \strtolower($sRawValue)); - $aValue = \array_map('trim', $aValue); - - $aCompareArray = array('flag', 'flagged', 'star', 'starred', 'pinned'); - $aCompareArray2 = array('unflag', 'unflagged', 'unstar', 'unstarred', 'unpinned'); - if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) - { - $aCriteriasResult[] = 'FLAGGED'; - $bUseCache = false; - } - else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue))) - { - $aCriteriasResult[] = 'UNFLAGGED'; - $bUseCache = false; - } - - $aCompareArray = array('unread', 'unseen'); - $aCompareArray2 = array('read', 'seen'); - if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) - { - $aCriteriasResult[] = 'UNSEEN'; - $bUseCache = false; - } - else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue))) - { - $aCriteriasResult[] = 'SEEN'; - $bUseCache = false; - } - break; - - case 'LARGER': - $aCriteriasResult[] = 'LARGER'; - $aCriteriasResult[] = $this->parseFriendlySize($sRawValue); - break; - case 'SMALLER': - $aCriteriasResult[] = 'SMALLER'; - $aCriteriasResult[] = $this->parseFriendlySize($sRawValue); - break; - case 'DATE': - $iDateStampFrom = $iDateStampTo = 0; - - $sDate = $sRawValue; - $aDate = \explode('/', $sDate); - - if (\is_array($aDate) && 2 === \count($aDate)) - { - if (0 < \strlen($aDate[0])) - { - $iDateStampFrom = $this->parseSearchDate($aDate[0], $iTimeZoneOffset); - } - - if (0 < \strlen($aDate[1])) - { - $iDateStampTo = $this->parseSearchDate($aDate[1], $iTimeZoneOffset); - $iDateStampTo += 60 * 60 * 24; - } - } - else - { - if (0 < \strlen($sDate)) - { - $iDateStampFrom = $this->parseSearchDate($sDate, $iTimeZoneOffset); - $iDateStampTo = $iDateStampFrom + 60 * 60 * 24; - } - } - - if (0 < $iDateStampFrom) - { - $aCriteriasResult[] = 'SINCE'; - $aCriteriasResult[] = \gmdate('j-M-Y', $iTimeFilter > $iDateStampFrom ? - $iTimeFilter : $iDateStampFrom); - - $iTimeFilter = 0; - } - - if (0 < $iDateStampTo) - { - $aCriteriasResult[] = 'BEFORE'; - $aCriteriasResult[] = \gmdate('j-M-Y', $iDateStampTo); - } - break; - } - } - - if ('' !== \trim($sMainText)) - { - $sMainText = \trim(\MailSo\Base\Utils::StripSpaces($sMainText), '"'); - if ($bIsGmail) - { - $sGmailRawSearch .= ' '.$sMainText; - } - else - { - $sResultBodyTextSearch .= ' '.$sMainText; - } - } - } - - $sGmailRawSearch = \trim($sGmailRawSearch); - if ($bIsGmail && 0 < \strlen($sGmailRawSearch)) - { - $aCriteriasResult[] = 'X-GM-RAW'; - $aCriteriasResult[] = $this->escapeSearchString($sGmailRawSearch, false); - } - - $sResultBodyTextSearch = \trim($sResultBodyTextSearch); - if (0 < \strlen($sResultBodyTextSearch)) - { - $aCriteriasResult[] = 'BODY'; - $aCriteriasResult[] = $this->escapeSearchString($sResultBodyTextSearch); - } - } - - $sCriteriasResult = \trim(\implode(' ', $aCriteriasResult)); - - if (0 < $iTimeFilter) - { - $sCriteriasResult .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter); - } - - $sCriteriasResult = \trim($sCriteriasResult); - if (\MailSo\Config::$MessageListUndeletedOnly) - { - $sCriteriasResult = \trim($sCriteriasResult.' UNDELETED'); - } - - $sFilter = \trim($sFilter); - if ('' !== $sFilter) - { - $sCriteriasResult .= ' '.$sFilter; - } - - $sCriteriasResult = \trim($sCriteriasResult); - if ('' !== \MailSo\Config::$MessageListPermanentFilter) - { - $sCriteriasResult = \trim($sCriteriasResult.' '.\MailSo\Config::$MessageListPermanentFilter); - } - - $sCriteriasResult = \trim($sCriteriasResult); - if ('' === $sCriteriasResult) - { - $sCriteriasResult = 'ALL'; - } - - return $sCriteriasResult; - } - - /** - * @param array $aThreads - * @return array - */ - private function threadArrayMap($aThreads) - { - $aNew = array(); - foreach ($aThreads as $mItem) - { - if (!\is_array($mItem)) - { - $aNew[] = $mItem; - } - else - { - $mMap = $this->threadArrayMap($mItem); - if (\is_array($mMap) && 0 < \count($mMap)) - { - $aNew = \array_merge($aNew, $mMap); - } - } - } - - return $aNew; - } - - /** - * @param array $aThreads - * - * @return array - */ - private function compileThreadArray($aThreads) - { - $aResult = array(); - foreach ($aThreads as $mItem) - { - if (\is_array($mItem)) - { - $aMap = $this->threadArrayMap($mItem); - if (\is_array($aMap)) - { - if (1 < \count($aMap)) - { - $aResult[] = $aMap; - } - else if (0 < \count($aMap)) - { - $aResult[] = $aMap[0]; - } - } - } - else - { - $aResult[] = $mItem; - } - } - - return $aResult; - } - - /** - * @param string $sFolderName - * @param string $sFolderHash - * @param array $aIndexOrUids - * @param \MailSo\Cache\CacheClient $oCacher - * @param bool $bCacheOnly = false - * - * @return array - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageListThreadsMap($sFolderName, $sFolderHash, $aIndexOrUids, $oCacher, $bCacheOnly = false) - { - $iThreadLimit = \MailSo\Config::$LargeThreadLimit; - - $sSearchHash = ''; - if (0 < \MailSo\Config::$MessageListDateFilter) - { - $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter; - $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD)); - - $sSearchHash .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter); - } - - if ('' === \trim($sSearchHash)) - { - $sSearchHash = 'ALL'; - } - - if ($oCacher && $oCacher->IsInited()) - { - $sSerializedHashKey = - 'ThreadsMapSorted/'.$sSearchHash.'/'. - 'Limit='.$iThreadLimit.'/'.$sFolderName.'/'.$sFolderHash; - - if ($this->oLogger) - { - $this->oLogger->Write($sSerializedHashKey); - } - - $sSerializedUids = $oCacher->Get($sSerializedHashKey); - if (!empty($sSerializedUids)) - { - $aSerializedUids = @\json_decode($sSerializedUids, true); - if (isset($aSerializedUids['ThreadsUids']) && \is_array($aSerializedUids['ThreadsUids'])) - { - if ($this->oLogger) - { - $this->oLogger->Write('Get Serialized Thread UIDS from cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aSerializedUids['ThreadsUids']).']'); - } - - return $aSerializedUids['ThreadsUids']; - } - } - } - - if ($bCacheOnly) - { - return null; - } - - $this->oImapClient->FolderExamine($sFolderName); - - $aThreadUids = array(); - try - { - $aThreadUids = $this->oImapClient->MessageSimpleThread($sSearchHash); - } - catch (\MailSo\Imap\Exceptions\RuntimeException $oException) - { - unset($oException); - $aThreadUids = array(); - } - - $aResult = array(); - $aCompiledThreads = $this->compileThreadArray($aThreadUids); - - foreach ($aCompiledThreads as $mData) - { - if (\is_array($mData)) - { - foreach ($mData as $mSubData) - { - $aResult[(int) $mSubData] = - \array_diff($mData, array((int) $mSubData)); - } - } - else if (\is_int($mData) || \is_string($mData)) - { - $aResult[(int) $mData] = (int) $mData; - } - } - - $aParentsMap = array(); - foreach ($aIndexOrUids as $iUid) - { - if (isset($aResult[$iUid]) && \is_array($aResult[$iUid])) - { - foreach ($aResult[$iUid] as $iTempUid) - { - $aParentsMap[$iTempUid] = $iUid; - if (isset($aResult[$iTempUid])) - { - unset($aResult[$iTempUid]); - } - } - } - } - - $aSortedThreads = array(); - foreach ($aIndexOrUids as $iUid) - { - if (isset($aResult[$iUid])) - { - $aSortedThreads[$iUid] = $iUid; - } - } - - foreach ($aIndexOrUids as $iUid) - { - if (!isset($aSortedThreads[$iUid]) && - isset($aParentsMap[$iUid]) && - isset($aSortedThreads[$aParentsMap[$iUid]])) - { - if (!\is_array($aSortedThreads[$aParentsMap[$iUid]])) - { - $aSortedThreads[$aParentsMap[$iUid]] = array(); - } - - $aSortedThreads[$aParentsMap[$iUid]][] = $iUid; - } - } - - $aResult = $aSortedThreads; - unset($aParentsMap, $aSortedThreads); - - $aTemp = array(); - foreach ($aResult as $iUid => $mValue) - { - if (0 < $iThreadLimit && \is_array($mValue) && $iThreadLimit < \count($mValue)) - { - $aParts = \array_chunk($mValue, $iThreadLimit); - if (0 < count($aParts)) - { - foreach ($aParts as $iIndex => $aItem) - { - if (0 === $iIndex) - { - $aResult[$iUid] = $aItem; - } - else if (0 < $iIndex && \is_array($aItem)) - { - $mFirst = \array_shift($aItem); - if (!empty($mFirst)) - { - $aTemp[$mFirst] = 0 < \count($aItem) ? $aItem : $mFirst; - } - } - } - } - } - } - - foreach ($aTemp as $iUid => $mValue) - { - $aResult[$iUid] = $mValue; - } - - unset($aTemp); - - $aLastResult = array(); - foreach ($aIndexOrUids as $iUid) - { - if (isset($aResult[$iUid])) - { - $aLastResult[$iUid] = $aResult[$iUid]; - } - } - - $aResult = $aLastResult; - unset($aLastResult); - - if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey)) - { - $oCacher->Set($sSerializedHashKey, @\json_encode(array( - 'ThreadsUids' => $aResult - ))); - - if ($this->oLogger) - { - $this->oLogger->Write('Save Serialized Thread UIDS to cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aResult).']'); - } - } - - return $aResult; - } - - /** - * @param \MailSo\Mail\MessageCollection &$oMessageCollection - * @param array $aRequestIndexOrUids - * @param bool $bIndexAsUid - * @param bool $bSimple = false - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageListByRequestIndexOrUids(&$oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid, $bSimple = false) - { - if (\is_array($aRequestIndexOrUids) && 0 < \count($aRequestIndexOrUids)) - { - $aFetchResponse = $this->oImapClient->Fetch(array( - \MailSo\Imap\Enumerations\FetchType::INDEX, - \MailSo\Imap\Enumerations\FetchType::UID, - \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, - \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, - \MailSo\Imap\Enumerations\FetchType::FLAGS, - \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE, - $bSimple ? - $this->getEnvelopeOrHeadersRequestStringForSimpleList() : - $this->getEnvelopeOrHeadersRequestString() - ), \MailSo\Base\Utils::PrepearFetchSequence($aRequestIndexOrUids), $bIndexAsUid); - - if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) - { - $aFetchIndexArray = array(); - $oFetchResponseItem = null; - foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem) - { - $aFetchIndexArray[($bIndexAsUid) - ? $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID) - : $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::INDEX)] =& $oFetchResponseItem; - - unset($oFetchResponseItem); - } - - foreach ($aRequestIndexOrUids as $iFUid) - { - if (isset($aFetchIndexArray[$iFUid])) - { - $oMessageCollection->Add( - Message::NewFetchResponseInstance( - $oMessageCollection->FolderName, $aFetchIndexArray[$iFUid])); - } - } - } - } - } - - /** - * @return bool - * - * @throws \MailSo\Net\Exceptions\Exception - */ - public function IsThreadsSupported() - { - return $this->oImapClient->IsSupported('THREAD=REFS') || - $this->oImapClient->IsSupported('THREAD=REFERENCES') || - $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT'); - } - - /** - * @param string $sFolderName - * @param array $aUids - * - * @return \MailSo\Mail\MessageCollection - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageListSimple($sFolderName, $aUids) - { - if (0 === \strlen($sFolderName) || !\MailSo\Base\Validator::NotEmptyArray($aUids)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderExamine($sFolderName); - - $oMessageCollection = \MailSo\Mail\MessageCollection::NewInstance(); - $oMessageCollection->FolderName = $sFolderName; - - $this->MessageListByRequestIndexOrUids($oMessageCollection, $aUids, true, true); - - return $oMessageCollection->GetAsArray(); - } - - /** - * @param \MailSo\Cache\CacheClient|null $oCacher - * @param string $sSearch - * @param string $sFilter - * @param string $sFolderName - * @param string $sFolderHash - * @param bool $bUseSortIfSupported = false - * - * @return array - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function GetUids($oCacher, $sSearch, $sFilter, $sFolderName, $sFolderHash, $bUseSortIfSupported = false) - { - $aResultUids = false; - $bUidsFromCacher = false; - $bUseCacheAfterSearch = true; - - $sSerializedHash = ''; - $sSerializedLog = ''; - - $bUseSortIfSupported = $bUseSortIfSupported ? !!$this->oImapClient->IsSupported('SORT') : false; - - if (0 < \strlen($sSearch)) - { - $bUseSortIfSupported = false; - } - - $sSearchCriterias = $this->getImapSearchCriterias($sSearch, $sFilter, 0, $bUseCacheAfterSearch); - if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited()) - { - $sSerializedHash = 'GetUids/'. - ($bUseSortIfSupported ? 'S': 'N').'/'. - $this->GenerateImapClientHash().'/'. - $sFolderName.'/'.$sSearchCriterias; - - $sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.''; - - $sSerialized = $oCacher->Get($sSerializedHash); - if (!empty($sSerialized)) - { - $aSerialized = @\json_decode($sSerialized, true); - if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) && - $sFolderHash === $aSerialized['FolderHash'] && - \is_array($aSerialized['Uids']) - ) - { - if ($this->oLogger) - { - $this->oLogger->Write('Get Serialized UIDS from cache ('.$sSerializedLog.') [count:'.\count($aSerialized['Uids']).']'); - } - - $aResultUids = $aSerialized['Uids']; - $bUidsFromCacher = true; - } - } - } - - if (!\is_array($aResultUids)) - { - $aResultUids = $bUseSortIfSupported ? - $this->oImapClient->MessageSimpleSort(array('REVERSE ARRIVAL'), $sSearchCriterias, true) : - $this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8') - ; - - if (!$bUidsFromCacher && $bUseCacheAfterSearch && \is_array($aResultUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash)) - { - $oCacher->Set($sSerializedHash, @\json_encode(array( - 'FolderHash' => $sFolderHash, - 'Uids' => $aResultUids - ))); - - if ($this->oLogger) - { - $this->oLogger->Write('Save Serialized UIDS to cache ('.$sSerializedLog.') [count:'.\count($aResultUids).']'); - } - } - } - - return \is_array($aResultUids) ? $aResultUids : array(); - } - - /** - * @param string $sFolderName - * @param int $iOffset = 0 - * @param int $iLimit = 10 - * @param string $sSearch = '' - * @param string $sPrevUidNext = '' - * @param \MailSo\Cache\CacheClient|null $oCacher = null - * @param bool $bUseSortIfSupported = false - * @param bool $bUseThreadSortIfSupported = false - * @param bool $bUseESearchOrESortRequest = false - * @param string $sThreadUid = '' - * @param string $sFilter = '' - * - * @return \MailSo\Mail\MessageCollection - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '', $oCacher = null, - $bUseSortIfSupported = false, $bUseThreadSortIfSupported = false, $sThreadUid = '', $sFilter = '') - { - $sFilter = \trim($sFilter); - $sSearch = \trim($sSearch); - if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) || - !\MailSo\Base\Validator::RangeInt($iLimit, 0, 999)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $bUseFilter = '' !== $sFilter; - - $this->oImapClient->FolderSelect($sFolderName); - - $oMessageCollection = MessageCollection::NewInstance(); - $oMessageCollection->FolderName = $sFolderName; - $oMessageCollection->Offset = $iOffset; - $oMessageCollection->Limit = $iLimit; - $oMessageCollection->Search = $sSearch; - $oMessageCollection->ThreadUid = $sThreadUid; - $oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter; - - $aUids = array(); - $mAllSortedUids = null; - $mAllThreads = null; - - $iThreadUid = empty($sThreadUid) ? 0 : (int) $sThreadUid; - - $iMessageRealCount = 0; - $iMessageUnseenCount = 0; - $sUidNext = '0'; - $sHighestModSeq = ''; - - $bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false; - - $bUseThreadSortIfSupported = $bUseThreadSortIfSupported ? - ($this->oImapClient->IsSupported('THREAD=REFS') || $this->oImapClient->IsSupported('THREAD=REFERENCES') || $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT')) : false; - - if (!empty($sThreadUid) && !$bUseThreadSortIfSupported) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - if (!$oCacher || !($oCacher instanceof \MailSo\Cache\CacheClient)) - { - $oCacher = null; - } - - $this->initFolderValues($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq); - - if ($bUseFilter) - { - $iMessageUnseenCount = 0; - } - - $oMessageCollection->FolderHash = $this->GenerateFolderHash( - $sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq); - - $oMessageCollection->UidNext = $sUidNext; - - if (empty($sThreadUid) && 0 < \strlen($sPrevUidNext) && 'INBOX' === $sFolderName) - { - $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation( - $sFolderName, $sPrevUidNext, $sUidNext); - } - - $bSearch = false; - $bMessageListOptimization = 0 < \MailSo\Config::$MessageListCountLimitTrigger && - \MailSo\Config::$MessageListCountLimitTrigger < $iMessageRealCount; - - if ($bMessageListOptimization) - { - $bUseSortIfSupported = false; - $bUseThreadSortIfSupported = false; - } - - if (0 < $iMessageRealCount && !$bMessageListOptimization) - { - $mAllSortedUids = $this->GetUids($oCacher, '', $sFilter, - $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported); - - $mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap( - $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null; - - if ($bUseThreadSortIfSupported && 0 < $iThreadUid && \is_array($mAllThreads)) - { - $aUids = array(); - $iResultRootUid = 0; - - if (isset($mAllThreads[$iThreadUid])) - { - $iResultRootUid = $iThreadUid; - if (\is_array($mAllThreads[$iThreadUid])) - { - $aUids = $mAllThreads[$iThreadUid]; - } - } - else - { - foreach ($mAllThreads as $iRootUid => $mSubUids) - { - if (\is_array($mSubUids) && \in_array($iThreadUid, $mSubUids)) - { - $iResultRootUid = $iRootUid; - $aUids = $mSubUids; - continue; - } - } - } - - if (0 < $iResultRootUid && \in_array($iResultRootUid, $mAllSortedUids)) - { - \array_unshift($aUids, $iResultRootUid); - } - } - else if ($bUseThreadSortIfSupported && \is_array($mAllThreads)) - { - $aUids = \array_keys($mAllThreads); - } - else - { - $bUseThreadSortIfSupported = false; - $aUids = $mAllSortedUids; - } - - if (0 < \strlen($sSearch) && \is_array($aUids)) - { - $aSearchedUids = $this->GetUids($oCacher, $sSearch, $sFilter, - $oMessageCollection->FolderName, $oMessageCollection->FolderHash); - - if (\is_array($aSearchedUids) && 0 < \count($aSearchedUids)) - { - $aFlippedSearchedUids = \array_flip($aSearchedUids); - - $bSearch = true; - $aNewUids = array(); - - foreach ($aUids as $iUid) - { - if (isset($aFlippedSearchedUids[$iUid])) - { - $aNewUids[] = $iUid; - } - else if ($bUseThreadSortIfSupported && 0 === $iThreadUid && isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid])) - { - foreach ($mAllThreads[$iUid] as $iSubUid) - { - if (isset($aFlippedSearchedUids[$iSubUid])) - { - $aNewUids[] = $iUid; - continue; - } - } - } - } - - $aUids = \array_unique($aNewUids); - unset($aNewUids); - } - else - { - $aUids = array(); - } - } - - if (\is_array($aUids)) - { - $oMessageCollection->MessageCount = $iMessageRealCount; - $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount; - $oMessageCollection->MessageResultCount = \count($aUids); - - if (0 < \count($aUids)) - { - $aRequestUids = \array_slice($aUids, $iOffset, $iLimit); - $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true); - } - } - } - else if (0 < $iMessageRealCount) - { - if ($this->oLogger) - { - $this->oLogger->Write('List optimization (count: '.$iMessageRealCount. - ', limit:'.\MailSo\Config::$MessageListCountLimitTrigger.')'); - } - - $oMessageCollection->MessageCount = $iMessageRealCount; - $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount; - - if (0 < \strlen($sSearch) || $bUseFilter) - { - $aUids = $this->GetUids($oCacher, $sSearch, $sFilter, - $oMessageCollection->FolderName, $oMessageCollection->FolderHash); - - if (0 < \count($aUids)) - { - $oMessageCollection->MessageResultCount = \count($aUids); - - $aRequestUids = \array_slice($aUids, $iOffset, $iLimit); - $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true); - } - else - { - $oMessageCollection->MessageResultCount = 0; - } - } - else - { - $oMessageCollection->MessageResultCount = $iMessageRealCount; - - if (1 < $iMessageRealCount) - { - $aRequestIndexes = \array_slice(array_reverse(range(1, $iMessageRealCount)), $iOffset, $iLimit); - } - else - { - $aRequestIndexes = \array_slice(array(1), $iOffset, $iLimit); - } - - $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestIndexes, false); - } - } - - if ($bUseThreadSortIfSupported && 0 === $iThreadUid && \is_array($mAllThreads) && 0 < \count($mAllThreads)) - { - $oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use ($mAllThreads) { - - $iUid = $oMessage->Uid(); - if (isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid]) && 0 < \count($mAllThreads[$iUid])) - { - $aSubThreads = $mAllThreads[$iUid]; - \array_unshift($aSubThreads, $iUid); - - $oMessage->SetThreads(\array_map('trim', $aSubThreads)); - unset($aSubThreads); - } - }); - } - - return $oMessageCollection; - } - - /** - * @return array|false - */ - public function Quota() - { - return $this->oImapClient->Quota(); - } - - /** - * @param string $sFolderName - * @param string $sMessageId - * - * @return int|null - */ - public function FindMessageUidByMessageId($sFolderName, $sMessageId) - { - if (0 === \strlen($sMessageId)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderExamine($sFolderName); - - $aUids = $this->oImapClient->MessageSimpleSearch( - 'HEADER Message-ID '.$sMessageId, true); - - return \is_array($aUids) && 1 === \count($aUids) && \is_numeric($aUids[0]) ? (int) $aUids[0] : null; - } - - /** - * @param array $aMailFoldersHelper - * @param int $iOptimizationLimit = 0 - * - * @return array - */ - public function folderListOptimization($aMailFoldersHelper, $iOptimizationLimit = 0) - { - // optimization - if (10 < $iOptimizationLimit && \is_array($aMailFoldersHelper) && $iOptimizationLimit < \count($aMailFoldersHelper)) - { - if ($this->oLogger) - { - $this->oLogger->Write('Start optimization (limit:'.$iOptimizationLimit.') for '.\count($aMailFoldersHelper).' folders'); - } - - $iForeachLimit = 1; - - $aFilteredNames = array( - 'inbox', - 'sent', 'send', 'outbox', 'sentmail', 'sendmail', - 'drafts', 'draft', - 'junk', 'spam', 'spambucket', - 'trash', 'bin', 'deleted', - 'archives', 'archive', 'allmail', 'all', - 'starred', 'flagged', 'important', - 'contacts', 'chats' - ); - - $aNewMailFoldersHelper = array(); - - $iCountLimit = $iForeachLimit; - - foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) - { - // mandatory folders - if ($oFolder && \in_array(\str_replace(' ', '', \strtolower($oFolder->NameRaw())), $aFilteredNames)) - { - $aNewMailFoldersHelper[] = $oFolder; - $aMailFoldersHelper[$iIndex] = null; - } - } - - foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) - { - // subscribed folders - if ($oFolder && $oFolder->IsSubscribed()) - { - $aNewMailFoldersHelper[] = $oFolder; - - $aMailFoldersHelper[$iIndex] = null; - $iCountLimit--; - } - - if (0 > $iCountLimit) - { - if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) - { - break; - } - else - { - $iCountLimit = $iForeachLimit; - } - } - } - - $iCountLimit = $iForeachLimit; - if ($iOptimizationLimit >= \count($aNewMailFoldersHelper)) - { - // name filter - foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) - { - if ($oFolder && !\preg_match('/[{}\[\]]/', $oFolder->NameRaw())) - { - $aNewMailFoldersHelper[] = $oFolder; - - $aMailFoldersHelper[$iIndex] = null; - $iCountLimit--; - } - - if (0 > $iCountLimit) - { - if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) - { - break; - } - else - { - $iCountLimit = $iForeachLimit; - } - } - } - } - - $iCountLimit = $iForeachLimit; - if ($iOptimizationLimit >= \count($aNewMailFoldersHelper)) - { - // other - foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) - { - if ($oFolder) - { - $aNewMailFoldersHelper[] = $oFolder; - - $aMailFoldersHelper[$iIndex] = null; - $iCountLimit--; - } - - if (0 > $iCountLimit) - { - if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) - { - break; - } - else - { - $iCountLimit = $iForeachLimit; - } - } - } - } - - $aMailFoldersHelper = $aNewMailFoldersHelper; - - if ($this->oLogger) - { - $this->oLogger->Write('Result optimization: '.\count($aMailFoldersHelper).' folders'); - } - } - - return $aMailFoldersHelper; - } - - /** - * @param string $sParent = '' - * @param string $sListPattern = '*' - * @param bool $bUseListSubscribeStatus = false - * @param int $iOptimizationLimit = 0 - * - * @return \MailSo\Mail\FolderCollection|false - */ - public function Folders($sParent = '', $sListPattern = '*', $bUseListSubscribeStatus = true, $iOptimizationLimit = 0) - { - $oFolderCollection = false; - - $aSubscribedFolders = null; - if ($bUseListSubscribeStatus) - { - try - { - $aSubscribedFolders = $this->oImapClient->FolderSubscribeList($sParent, $sListPattern); - } - catch (\Exception $oException) - { - unset($oException); - } - } - - $aImapSubscribedFoldersHelper = null; - if (\is_array($aSubscribedFolders)) - { - $aImapSubscribedFoldersHelper = array(); - foreach ($aSubscribedFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) - { - $aImapSubscribedFoldersHelper[] = $oImapFolder->FullNameRaw(); - } - } - - $aFolders = $this->oImapClient->FolderList($sParent, $sListPattern); - - $bOptimized = false; - $aMailFoldersHelper = null; - - if (\is_array($aFolders)) - { - $aMailFoldersHelper = array(); - - foreach ($aFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) - { - $aMailFoldersHelper[] = Folder::NewInstance($oImapFolder, - (null === $aImapSubscribedFoldersHelper || \in_array($oImapFolder->FullNameRaw(), $aImapSubscribedFoldersHelper)) || - $oImapFolder->IsInbox() - ); - } - - $iCount = \count($aMailFoldersHelper); - $aMailFoldersHelper = $this->folderListOptimization($aMailFoldersHelper, $iOptimizationLimit); - - $bOptimized = $iCount !== \count($aMailFoldersHelper); - } - - if (\is_array($aMailFoldersHelper)) - { - $oFolderCollection = FolderCollection::NewInstance(); - $oFolderCollection->InitByUnsortedMailFolderArray($aMailFoldersHelper); - - $oFolderCollection->Optimized = $bOptimized; - } - - if ($oFolderCollection) - { - $oFolderCollection->SortByCallback(function ($oFolderA, $oFolderB) { - $sA = \strtoupper($oFolderA->FullNameRaw()); - $sB = \strtoupper($oFolderB->FullNameRaw()); - switch (true) - { - case 'INBOX' === $sA: - return -1; - case 'INBOX' === $sB: - return 1; - case '[GMAIL]' === $sA: - return -1; - case '[GMAIL]' === $sB: - return 1; - } - - return \strnatcasecmp($oFolderA->FullName(), $oFolderB->FullName()); - }); - - $oNamespace = $this->oImapClient->GetNamespace(); - if ($oNamespace) - { - $oFolderCollection->SetNamespace($oNamespace->GetPersonalNamespace()); - } - - $oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported(); - } - - return $oFolderCollection; - } - - /** - * @param string $sFolderNameInUtf8 - * @param string $sFolderParentFullNameRaw = '' - * @param bool $bSubscribeOnCreation = true - * @param string $sDelimiter = '' - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function FolderCreate($sFolderNameInUtf8, $sFolderParentFullNameRaw = '', $bSubscribeOnCreation = true, $sDelimiter = '') - { - if (!\MailSo\Base\Validator::NotEmptyString($sFolderNameInUtf8, true) || - !\is_string($sFolderParentFullNameRaw)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $sFolderNameInUtf8 = \trim($sFolderNameInUtf8); - - if (0 === \strlen($sDelimiter) || 0 < \strlen(\trim($sFolderParentFullNameRaw))) - { - $aFolders = $this->oImapClient->FolderList('', 0 === \strlen(\trim($sFolderParentFullNameRaw)) ? 'INBOX' : $sFolderParentFullNameRaw); - if (!\is_array($aFolders) || !isset($aFolders[0])) - { - // TODO - throw new \MailSo\Mail\Exceptions\RuntimeException( - 0 === \strlen(trim($sFolderParentFullNameRaw)) - ? 'Cannot get folder delimiter' - : 'Cannot create folder in non-existen parent folder'); - } - - $sDelimiter = $aFolders[0]->Delimiter(); - if (0 < \strlen($sDelimiter) && 0 < \strlen(\trim($sFolderParentFullNameRaw))) - { - $sFolderParentFullNameRaw .= $sDelimiter; - } - } - - $sFullNameRawToCreate = \MailSo\Base\Utils::ConvertEncoding($sFolderNameInUtf8, - \MailSo\Base\Enumerations\Charset::UTF_8, - \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); - - if (0 < \strlen($sDelimiter) && false !== \strpos($sFullNameRawToCreate, $sDelimiter)) - { - // TODO - throw new \MailSo\Mail\Exceptions\RuntimeException( - 'New folder name contains delimiter'); - } - - $sFullNameRawToCreate = $sFolderParentFullNameRaw.$sFullNameRawToCreate; - - $this->oImapClient->FolderCreate($sFullNameRawToCreate); - - if ($bSubscribeOnCreation) - { - $this->oImapClient->FolderSubscribe($sFullNameRawToCreate); - } - - return $this; - } - - /** - * @param string $sPrevFolderFullNameRaw - * @param string $sNextFolderFullNameInUtf - * @param bool $bSubscribeOnMove = true - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function FolderMove($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, $bSubscribeOnMove = true) - { - return $this->folderModify($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, false, $bSubscribeOnMove); - } - - /** - * @param string $sPrevFolderFullNameRaw - * @param string $sNewTopFolderNameInUtf - * @param bool $bSubscribeOnRename = true - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function FolderRename($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, $bSubscribeOnRename = true) - { - return $this->folderModify($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, true, $bSubscribeOnRename); - } - - /** - * @param string $sPrevFolderFullNameRaw - * @param string $sNextFolderNameInUtf - * @param bool $bRenameOrMove - * @param bool $bSubscribeOnModify - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function folderModify($sPrevFolderFullNameRaw, $sNextFolderNameInUtf, $bRenameOrMove, $bSubscribeOnModify) - { - if (0 === \strlen($sPrevFolderFullNameRaw) || 0 === \strlen($sNextFolderNameInUtf)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $aFolders = $this->oImapClient->FolderList('', $sPrevFolderFullNameRaw); - if (!\is_array($aFolders) || !isset($aFolders[0])) - { - // TODO - throw new \MailSo\Mail\Exceptions\RuntimeException('Cannot rename non-existen folder'); - } - - $sDelimiter = $aFolders[0]->Delimiter(); - $iLast = \strrpos($sPrevFolderFullNameRaw, $sDelimiter); - - $mSubscribeFolders = null; - if ($bSubscribeOnModify) - { - $mSubscribeFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullNameRaw, '*'); - if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders)) - { - foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) - { - $this->oImapClient->FolderUnSubscribe($oFolder->FullNameRaw()); - } - } - } - - $sNewFolderFullNameRaw = \MailSo\Base\Utils::ConvertEncoding($sNextFolderNameInUtf, - \MailSo\Base\Enumerations\Charset::UTF_8, - \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); - - if($bRenameOrMove) - { - if (0 < \strlen($sDelimiter) && false !== \strpos($sNewFolderFullNameRaw, $sDelimiter)) - { - // TODO - throw new \MailSo\Mail\Exceptions\RuntimeException('New folder name contains delimiter'); - } - - $sFolderParentFullNameRaw = false === $iLast ? '' : \substr($sPrevFolderFullNameRaw, 0, $iLast + 1); - $sNewFolderFullNameRaw = $sFolderParentFullNameRaw.$sNewFolderFullNameRaw; - } - - $this->oImapClient->FolderRename($sPrevFolderFullNameRaw, $sNewFolderFullNameRaw); - - if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders)) - { - foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) - { - $sFolderFullNameRawForResubscrine = $oFolder->FullNameRaw(); - if (0 === \strpos($sFolderFullNameRawForResubscrine, $sPrevFolderFullNameRaw)) - { - $sNewFolderFullNameRawForResubscrine = $sNewFolderFullNameRaw. - \substr($sFolderFullNameRawForResubscrine, \strlen($sPrevFolderFullNameRaw)); - - $this->oImapClient->FolderSubscribe($sNewFolderFullNameRawForResubscrine); - } - } - } - - return $this; - } - - /** - * @param string $sFolderFullNameRaw - * @param bool $bUnsubscribeOnDeletion = true - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Mail\Exceptions\RuntimeException - */ - public function FolderDelete($sFolderFullNameRaw, $bUnsubscribeOnDeletion = true) - { - if (0 === \strlen($sFolderFullNameRaw) || 'INBOX' === $sFolderFullNameRaw) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderExamine($sFolderFullNameRaw); - - $aIndexOrUids = $this->oImapClient->MessageSimpleSearch('ALL'); - if (0 < \count($aIndexOrUids)) - { - throw new \MailSo\Mail\Exceptions\NonEmptyFolder(); - } - - $this->oImapClient->FolderExamine('INBOX'); - - if ($bUnsubscribeOnDeletion) - { - $this->oImapClient->FolderUnSubscribe($sFolderFullNameRaw); - } - - $this->oImapClient->FolderDelete($sFolderFullNameRaw); - - return $this; - } - - /** - * @param string $sFolderFullNameRaw - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function FolderClear($sFolderFullNameRaw) - { - $this->oImapClient->FolderSelect($sFolderFullNameRaw); - - $oFolderInformation = $this->oImapClient->FolderCurrentInformation(); - if ($oFolderInformation && $oFolderInformation->Exists && 0 < $oFolderInformation->Exists) // STATUS? - { - $this->oImapClient->MessageStoreFlag('1:*', false, - array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), - \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT - ); - - $this->oImapClient->MessageExpunge(); - } - - return $this; - } - - /** - * @param string $sFolderFullNameRaw - * @param bool $bSubscribe - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function FolderSubscribe($sFolderFullNameRaw, $bSubscribe) - { - if (0 === \strlen($sFolderFullNameRaw)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->{($bSubscribe) ? 'FolderSubscribe' : 'FolderUnSubscribe'}($sFolderFullNameRaw); - - return $this; - } - - /** - * @param \MailSo\Log\Logger $oLogger - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function SetLogger($oLogger) - { - if (!($oLogger instanceof \MailSo\Log\Logger)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oLogger = $oLogger; - $this->oImapClient->SetLogger($this->oLogger); - - return $this; - } -} +oLogger = null; + + $this->oImapClient = \MailSo\Imap\ImapClient::NewInstance(); + $this->oImapClient->SetTimeOuts(10, \MailSo\Config::$ImapTimeout); + } + + /** + * @return \MailSo\Mail\MailClient + */ + public static function NewInstance() + { + return new self(); + } + + /** + * @return \MailSo\Imap\ImapClient + */ + public function ImapClient() + { + return $this->oImapClient; + } + + /** + * @param string $sServerName + * @param int $iPort = 143 + * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT + * @param bool $bVerifySsl = false + * @param string $sClientCert = "" + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function Connect($sServerName, $iPort = 143, + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false, $bAllowSelfSigned = false, $sClientCert = '') + { + $this->oImapClient->Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned, $sClientCert); + return $this; + } + + /** + * @param string $sLogin + * @param string $sPassword + * @param string $sProxyAuthUser = '' + * @param bool $bUseAuthPlainIfSupported = true + * @param bool $bUseAuthCramMd5IfSupported = true + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\LoginException + */ + public function Login($sLogin, $sPassword, $sProxyAuthUser = '', + $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true) + { + $this->oImapClient->Login($sLogin, $sPassword, $sProxyAuthUser, $bUseAuthPlainIfSupported, $bUseAuthCramMd5IfSupported); + return $this; + } + + /** + * @param string $sXOAuth2Token + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\LoginException + */ + public function LoginWithXOauth2($sXOAuth2Token) + { + $this->oImapClient->LoginWithXOauth2($sXOAuth2Token); + return $this; + } + + /** + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Net\Exceptions\Exception + */ + public function Logout() + { + $this->oImapClient->Logout(); + return $this; + } + + /** + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Net\Exceptions\Exception + */ + public function Disconnect() + { + $this->oImapClient->Disconnect(); + return $this; + } + + /** + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Net\Exceptions\Exception + */ + public function LogoutAndDisconnect() + { + return $this->Logout()->Disconnect(); + } + + /** + * @return bool + */ + public function IsConnected() + { + return $this->oImapClient->IsConnected(); + } + + /** + * @return bool + */ + public function IsLoggined() + { + return $this->oImapClient->IsLoggined(); + } + + /** + * @return string + */ + private function getEnvelopeOrHeadersRequestStringForSimpleList() + { + return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( + \MailSo\Mime\Enumerations\Header::RETURN_PATH, + \MailSo\Mime\Enumerations\Header::RECEIVED, + \MailSo\Mime\Enumerations\Header::MIME_VERSION, + \MailSo\Mime\Enumerations\Header::FROM_, + \MailSo\Mime\Enumerations\Header::TO_, + \MailSo\Mime\Enumerations\Header::CC, + \MailSo\Mime\Enumerations\Header::SENDER, + \MailSo\Mime\Enumerations\Header::REPLY_TO, + \MailSo\Mime\Enumerations\Header::DATE, + \MailSo\Mime\Enumerations\Header::SUBJECT, + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, + \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE, + ), true); + } + + /** + * @return string + */ + private function getEnvelopeOrHeadersRequestString() + { + if (\MailSo\Config::$MessageAllHeaders) + { + return \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK; + } + + return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( + \MailSo\Mime\Enumerations\Header::RETURN_PATH, + \MailSo\Mime\Enumerations\Header::RECEIVED, + \MailSo\Mime\Enumerations\Header::MIME_VERSION, + \MailSo\Mime\Enumerations\Header::MESSAGE_ID, + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, + \MailSo\Mime\Enumerations\Header::FROM_, + \MailSo\Mime\Enumerations\Header::TO_, + \MailSo\Mime\Enumerations\Header::CC, + \MailSo\Mime\Enumerations\Header::BCC, + \MailSo\Mime\Enumerations\Header::SENDER, + \MailSo\Mime\Enumerations\Header::REPLY_TO, + \MailSo\Mime\Enumerations\Header::DELIVERED_TO, + \MailSo\Mime\Enumerations\Header::IN_REPLY_TO, + \MailSo\Mime\Enumerations\Header::REFERENCES, + \MailSo\Mime\Enumerations\Header::DATE, + \MailSo\Mime\Enumerations\Header::SUBJECT, + \MailSo\Mime\Enumerations\Header::SENSITIVITY, + \MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY, + \MailSo\Mime\Enumerations\Header::IMPORTANCE, + \MailSo\Mime\Enumerations\Header::X_PRIORITY, + \MailSo\Mime\Enumerations\Header::X_DRAFT_INFO, + \MailSo\Mime\Enumerations\Header::RETURN_RECEIPT_TO, + \MailSo\Mime\Enumerations\Header::DISPOSITION_NOTIFICATION_TO, + \MailSo\Mime\Enumerations\Header::X_CONFIRM_READING_TO, + \MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS, + \MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS, + \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE, + ), true); +// +// return \MailSo\Imap\Enumerations\FetchType::ENVELOPE; + } + + /** + * @param string $sFolderName + * @param string $sMessageFlag + * @param bool $bSetAction = true + * @param bool $sSkipUnsupportedFlag = false + * @param array $aCustomUids = null + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + * @throws \MailSo\Mail\Exceptions\Exception + */ + public function MessageSetFlagToAll($sFolderName, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false, $aCustomUids = null) + { + $this->oImapClient->FolderSelect($sFolderName); + + $oFolderInfo = $this->oImapClient->FolderCurrentInformation(); + if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag)) + { + if (!$sSkipUnsupportedFlag) + { + throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.'); + } + } + + if ($oFolderInfo && 0 < $oFolderInfo->Exists) + { + $sStoreAction = $bSetAction + ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT + : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT + ; + + if (is_array($aCustomUids)) + { + if (0 < count($aCustomUids)) + { + $this->oImapClient->MessageStoreFlag(implode(',', $aCustomUids), true, array($sMessageFlag), $sStoreAction); + } + } + else + { + $this->oImapClient->MessageStoreFlag('1:*', false, array($sMessageFlag), $sStoreAction); + } + } + } + + /** + * @param string $sFolderName + * @param array $aIndexRange + * @param bool $bIndexIsUid + * @param string $sMessageFlag + * @param bool $bSetAction = true + * @param bool $sSkipUnsupportedFlag = false + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + * @throws \MailSo\Mail\Exceptions\Exception + */ + public function MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false) + { + $this->oImapClient->FolderSelect($sFolderName); + + $oFolderInfo = $this->oImapClient->FolderCurrentInformation(); + if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag)) + { + if (!$sSkipUnsupportedFlag) + { + throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.'); + } + } + else + { + $sStoreAction = $bSetAction + ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT + : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT + ; + + $this->oImapClient->MessageStoreFlag(\MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), + $bIndexIsUid, array($sMessageFlag), $sStoreAction); + } + } + + /** + * @param string $sFolderName + * @param array $aIndexRange + * @param bool $bIndexIsUid + * @param bool $bSetAction = true + * @param bool $sSkipUnsupportedFlag = false + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageSetFlagged($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true, $sSkipUnsupportedFlag = false) + { + $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, + \MailSo\Imap\Enumerations\MessageFlag::FLAGGED, $bSetAction, $sSkipUnsupportedFlag); + } + + /** + * @param string $sFolderName + * @param bool $bSetAction = true + * @param array $aCustomUids = null + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageSetSeenToAll($sFolderName, $bSetAction = true, $aCustomUids = null) + { + $this->MessageSetFlagToAll($sFolderName, \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true, $aCustomUids); + } + + /** + * @param string $sFolderName + * @param array $aIndexRange + * @param bool $bIndexIsUid + * @param bool $bSetAction = true + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageSetSeen($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true) + { + $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, + \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true); + } + + /** + * @param string $sFolderName + * @param int $iIndex + * @param bool $bIndexIsUid = true + * @param \MailSo\Cache\CacheClient $oCacher = null + * @param int $iBodyTextLimit = null + * + * @return \MailSo\Mail\Message|false + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function Message($sFolderName, $iIndex, $bIndexIsUid = true, $oCacher = null, $iBodyTextLimit = null) + { + if (!\MailSo\Base\Validator::RangeInt($iIndex, 1)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderSelect($sFolderName); + + $oBodyStructure = null; + $oMessage = false; + + $aBodyPeekMimeIndexes = array(); + $aSignatureMimeIndexes = array(); + + $aFetchResponse = $this->oImapClient->Fetch(array(\MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE), $iIndex, $bIndexIsUid); + if (0 < \count($aFetchResponse) && isset($aFetchResponse[0])) + { + $oBodyStructure = $aFetchResponse[0]->GetFetchBodyStructure(); + if ($oBodyStructure) + { + $aTextParts = $oBodyStructure->SearchHtmlOrPlainParts(); + if (is_array($aTextParts) && 0 < \count($aTextParts)) + { + foreach ($aTextParts as $oPart) + { + $aBodyPeekMimeIndexes[] = array($oPart->PartID(), $oPart->Size()); + } + } + + $aSignatureParts = $oBodyStructure->SearchByContentType('application/pgp-signature'); + if (is_array($aSignatureParts) && 0 < \count($aSignatureParts)) + { + foreach ($aSignatureParts as $oPart) + { + $aSignatureMimeIndexes[] = $oPart->PartID(); + } + } + } + } + + $aFetchItems = array( + \MailSo\Imap\Enumerations\FetchType::INDEX, + \MailSo\Imap\Enumerations\FetchType::UID, + \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, + \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, + \MailSo\Imap\Enumerations\FetchType::FLAGS, + $this->getEnvelopeOrHeadersRequestString() + ); + + if (0 < \count($aBodyPeekMimeIndexes)) + { + foreach ($aBodyPeekMimeIndexes as $aTextMimeData) + { + $sLine = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$aTextMimeData[0].']'; + if (\is_numeric($iBodyTextLimit) && 0 < $iBodyTextLimit && $iBodyTextLimit < $aTextMimeData[1]) + { + $sLine .= '<0.'.((int) $iBodyTextLimit).'>'; + } + + $aFetchItems[] = $sLine; + } + } + + if (0 < \count($aSignatureMimeIndexes)) + { + foreach ($aSignatureMimeIndexes as $sTextMimeIndex) + { + $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sTextMimeIndex.']'; + } + } + + if (!$oBodyStructure) + { + $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE; + } + + $aFetchResponse = $this->oImapClient->Fetch($aFetchItems, $iIndex, $bIndexIsUid); + if (0 < \count($aFetchResponse)) + { + $oMessage = \MailSo\Mail\Message::NewFetchResponseInstance( + $sFolderName, $aFetchResponse[0], $oBodyStructure); + } + + return $oMessage; + } + + /** + * @param mixed $mCallback + * @param string $sFolderName + * @param int $iIndex + * @param bool $bIndexIsUid = true, + * @param string $sMimeIndex = '' + * + * @return bool + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageMimeStream($mCallback, $sFolderName, $iIndex, $bIndexIsUid = true, $sMimeIndex = '') + { + if (!is_callable($mCallback)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderSelect($sFolderName); + + $sFileName = ''; + $sContentType = ''; + $sMailEncodingName = ''; + + $sMimeIndex = trim($sMimeIndex); + $aFetchResponse = $this->oImapClient->Fetch(array( + 0 === \strlen($sMimeIndex) + ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK + : \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.'.MIME]' + ), $iIndex, $bIndexIsUid); + + if (0 < \count($aFetchResponse)) + { + $sMime = $aFetchResponse[0]->GetFetchValue( + 0 === \strlen($sMimeIndex) + ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER + : \MailSo\Imap\Enumerations\FetchType::BODY.'['.$sMimeIndex.'.MIME]' + ); + + if (0 < \strlen($sMime)) + { + $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sMime); + + if (0 < \strlen($sMimeIndex)) + { + $sFileName = $oHeaders->ParameterValue( + \MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION, + \MailSo\Mime\Enumerations\Parameter::FILENAME); + + if (0 === \strlen($sFileName)) + { + $sFileName = $oHeaders->ParameterValue( + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, + \MailSo\Mime\Enumerations\Parameter::NAME); + } + + $sMailEncodingName = $oHeaders->ValueByName( + \MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING); + + $sContentType = $oHeaders->ValueByName( + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE); + } + else + { + $sSubject = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT); + + $sFileName = 0 === \strlen($sSubject) ? (string) $iIndex : $sSubject; + $sFileName .= '.eml'; + + $sContentType = 'message/rfc822'; + } + } + } + + $aFetchResponse = $this->oImapClient->Fetch(array( + array(\MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.']', + function ($sParent, $sLiteralAtomUpperCase, $rImapLiteralStream) use ($mCallback, $sMimeIndex, $sMailEncodingName, $sContentType, $sFileName) + { + if (0 < \strlen($sLiteralAtomUpperCase)) + { + if (is_resource($rImapLiteralStream) && 'FETCH' === $sParent) + { + $rMessageMimeIndexStream = (0 === \strlen($sMailEncodingName)) + ? $rImapLiteralStream + : \MailSo\Base\StreamWrappers\Binary::CreateStream($rImapLiteralStream, + \MailSo\Base\StreamWrappers\Binary::GetInlineDecodeOrEncodeFunctionName( + $sMailEncodingName, true)); + + \call_user_func($mCallback, $rMessageMimeIndexStream, $sContentType, $sFileName, $sMimeIndex); + } + } + } + )), $iIndex, $bIndexIsUid); + + return ($aFetchResponse && 1 === \count($aFetchResponse)); + } + + /** + * @param string $sFolder + * @param array $aIndexRange + * @param bool $bIndexIsUid + * @param bool $bUseExpunge = true + * @param bool $bExpungeAll = false + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageDelete($sFolder, $aIndexRange, $bIndexIsUid, $bUseExpunge = true, $bExpungeAll = false) + { + if (0 === \strlen($sFolder) || !\is_array($aIndexRange) || 0 === \count($aIndexRange)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderSelect($sFolder); + + $sIndexRange = \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange); + + $this->oImapClient->MessageStoreFlag($sIndexRange, $bIndexIsUid, + array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), + \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT + ); + + if ($bUseExpunge) + { + $this->oImapClient->MessageExpunge($bIndexIsUid ? $sIndexRange : '', $bIndexIsUid, $bExpungeAll); + } + + return $this; + } + + /** + * @param string $sFromFolder + * @param string $sToFolder + * @param array $aIndexRange + * @param bool $bIndexIsUid + * @param bool $bUseMoveSupported = false + * @param bool $bExpungeAll = false + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageMove($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid, $bUseMoveSupported = false, $bExpungeAll = false) + { + if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) || + !\is_array($aIndexRange) || 0 === \count($aIndexRange)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderSelect($sFromFolder); + + if ($bUseMoveSupported && $this->oImapClient->IsSupported('MOVE')) + { + $this->oImapClient->MessageMove($sToFolder, + \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); + } + else + { + $this->oImapClient->MessageCopy($sToFolder, + \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); + + $this->MessageDelete($sFromFolder, $aIndexRange, $bIndexIsUid, true, $bExpungeAll); + } + + return $this; + } + + /** + * @param string $sFromFolder + * @param string $sToFolder + * @param array $aIndexRange + * @param bool $bIndexIsUid + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageCopy($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid) + { + if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) || + !\is_array($aIndexRange) || 0 === \count($aIndexRange)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderSelect($sFromFolder); + $this->oImapClient->MessageCopy($sToFolder, + \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); + + return $this; + } + + /** + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderUnSelect() + { + if ($this->oImapClient->IsSelected()) + { + $this->oImapClient->FolderUnSelect(); + } + + return $this; + } + + /** + * @param resource $rMessageStream + * @param int $iMessageStreamSize + * @param string $sFolderToSave + * @param array $aAppendFlags = null + * @param int $iUid = null + * + * @return \MailSo\Mail\MailClient + */ + public function MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags = null, &$iUid = null) + { + if (!\is_resource($rMessageStream) || 0 === \strlen($sFolderToSave)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->MessageAppendStream( + $sFolderToSave, $rMessageStream, $iMessageStreamSize, $aAppendFlags, $iUid); + + return $this; + } + + /** + * @param string $sMessageFileName + * @param string $sFolderToSave + * @param array $aAppendFlags = null + * @param int &$iUid = null + * + * @return \MailSo\Mail\MailClient + */ + public function MessageAppendFile($sMessageFileName, $sFolderToSave, $aAppendFlags = null, &$iUid = null) + { + if (!@\is_file($sMessageFileName) || !@\is_readable($sMessageFileName)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $iMessageStreamSize = \filesize($sMessageFileName); + $rMessageStream = \fopen($sMessageFileName, 'rb'); + + $this->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags, $iUid); + + if (\is_resource($rMessageStream)) + { + @fclose($rMessageStream); + } + + return $this; + } + + /** + * @param string $sFolderName + * @param int $iCount + * @param int $iUnseenCount + * @param string $sUidNext + * @param string $sHighestModSeq + * + * @return void + */ + protected function initFolderValues($sFolderName, &$iCount, &$iUnseenCount, + &$sUidNext, &$sHighestModSeq = '') + { + $aTypes = array( + \MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES, + \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN, + \MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT + ); + + if ($this->oImapClient->IsSupported('CONDSTORE')) + { + $aTypes[] = \MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ; + } + + $aFolderStatus = $this->oImapClient->FolderStatus($sFolderName, $aTypes); + + $iCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES]) + ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES] : 0; + + $iUnseenCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) + ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0; + + $sUidNext = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT]) + ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT] : '0'; + + $sHighestModSeq = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ]) + ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ] : ''; + + if ($this->IsGmail() && + ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7)))) + { + $oFolder = $this->oImapClient->FolderCurrentInformation(); + if ($oFolder && null !== $oFolder->Exists && $oFolder->FolderName === $sFolderName) + { + $iSubCount = (int) $oFolder->Exists; + if (0 < $iSubCount && $iSubCount < $iCount) + { + $iCount = $iSubCount; + } + } + } + } + + /** + * @return string + */ + public function GenerateImapClientHash() + { + return \md5('ImapClientHash/'. + $this->oImapClient->GetLogginedUser().'@'. + $this->oImapClient->GetConnectedHost().':'. + $this->oImapClient->GetConnectedPort() + ); + } + + /** + * @param string $sFolder + * @param int $iCount + * @param int $iUnseenCount + * @param string $sUidNext + * @param string $sHighestModSeq = '' + * + * @return string + */ + public function GenerateFolderHash($sFolder, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq = '') + { + $iUnseenCount = 0; // unneccessery + return \md5('FolderHash/'.$sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext.'-'. + $sHighestModSeq.'-'.$this->GenerateImapClientHash().'-'. + \MailSo\Config::$MessageListPermanentFilter + ); + } + + /** + * @param string $sFolderName + * @param string $sPrevUidNext + * @param string $sCurrentUidNext + * + * @return array + */ + private function getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sCurrentUidNext) + { + $aNewMessages = array(); + + if (0 < \strlen($sPrevUidNext) && (string) $sPrevUidNext !== (string) $sCurrentUidNext) + { + $this->oImapClient->FolderSelect($sFolderName); + + $aFetchResponse = $this->oImapClient->Fetch(array( + \MailSo\Imap\Enumerations\FetchType::INDEX, + \MailSo\Imap\Enumerations\FetchType::UID, + \MailSo\Imap\Enumerations\FetchType::FLAGS, + \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( + \MailSo\Mime\Enumerations\Header::FROM_, + \MailSo\Mime\Enumerations\Header::SUBJECT, + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE + )) + ), $sPrevUidNext.':*', true); + + if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) + { + foreach ($aFetchResponse as /* @var $oFetchResponse \MailSo\Imap\FetchResponse */ $oFetchResponse) + { + $aFlags = \array_map('strtolower', $oFetchResponse->GetFetchValue( + \MailSo\Imap\Enumerations\FetchType::FLAGS)); + + if (!\in_array(\strtolower(\MailSo\Imap\Enumerations\MessageFlag::SEEN), $aFlags)) + { + $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); + $sHeaders = $oFetchResponse->GetHeaderFieldsValue(); + + $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sHeaders); + + $sContentTypeCharset = $oHeaders->ParameterValue( + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, + \MailSo\Mime\Enumerations\Parameter::CHARSET + ); + + $sCharset = ''; + if (0 < \strlen($sContentTypeCharset)) + { + $sCharset = $sContentTypeCharset; + } + + if (0 < \strlen($sCharset)) + { + $oHeaders->SetParentCharset($sCharset); + } + + $aNewMessages[] = array( + 'Folder' => $sFolderName, + 'Uid' => $sUid, + 'Subject' => $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT, 0 === \strlen($sCharset)), + 'From' => $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::FROM_, 0 === \strlen($sCharset)) + ); + } + } + } + } + + return $aNewMessages; + } + + /** + * @param string $sFolderName + * @param string $sPrevUidNext = '' + * @param array $aUids = '' + * + * @return string + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderInformation($sFolderName, $sPrevUidNext = '', $aUids = array()) + { + $aFlags = array(); + + $bSelect = false; + if ($this->IsGmail() && + ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7)))) + { + $this->oImapClient->FolderSelect($sFolderName); + $bSelect = true; + } + + if (\is_array($aUids) && 0 < \count($aUids)) + { + if (!$bSelect) + { + $this->oImapClient->FolderSelect($sFolderName); + } + + $aFetchResponse = $this->oImapClient->Fetch(array( + \MailSo\Imap\Enumerations\FetchType::INDEX, + \MailSo\Imap\Enumerations\FetchType::UID, + \MailSo\Imap\Enumerations\FetchType::FLAGS + ), \MailSo\Base\Utils::PrepearFetchSequence($aUids), true); + + if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) + { + foreach ($aFetchResponse as $oFetchResponse) + { + $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); + $aFlags[(\is_numeric($sUid) ? (int) $sUid : 0)] = + $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS); + } + } + } + + $iCount = 0; + $iUnseenCount = 0; + $sUidNext = '0'; + $sHighestModSeq = ''; + + $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); + + $aResult = array( + 'Folder' => $sFolderName, + 'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq), + 'MessageCount' => $iCount, + 'MessageUnseenCount' => $iUnseenCount, + 'UidNext' => $sUidNext, + 'Flags' => $aFlags, + 'HighestModSeq' => $sHighestModSeq, + 'NewMessages' => 'INBOX' === $sFolderName && \MailSo\Config::$CheckNewMessages ? + $this->getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sUidNext) : array() + ); + + return $aResult; + } + + /** + * @param string $sFolderName + * + * @return string + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderHash($sFolderName) + { + $iCount = 0; + $iUnseenCount = 0; + $sUidNext = '0'; + $sHighestModSeq = ''; + + $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); + + return $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); + } + + /** + * @return int + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function InboxUnreadCount() + { + $aFolderStatus = $this->oImapClient->FolderStatus('INBOX', array( + \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN + )); + + $iResult = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) ? + (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0; + + return 0 < $iResult ? $iResult : 0; + } + + /** + * @return bool + */ + public function IsGmail() + { + return 'ssl://imap.gmail.com' === \strtolower($this->oImapClient->GetConnectedHost()); + } + + /** + * @param string $sSearch + * @param bool $bDetectGmail = true + * + * @return string + */ + private function escapeSearchString($sSearch, $bDetectGmail = true) + { + return !\MailSo\Base\Utils::IsAscii($sSearch) + ? '{'.\strlen($sSearch).'}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch); +// return ($bDetectGmail && !\MailSo\Base\Utils::IsAscii($sSearch) && $this->IsGmail()) +// ? '{'.\strlen($sSearch).'+}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch); + } + + /** + * @param string $sDate + * @param int $iTimeZoneOffset + * + * @return int + */ + private function parseSearchDate($sDate, $iTimeZoneOffset) + { + $iResult = 0; + if (0 < \strlen($sDate)) + { + $oDateTime = \DateTime::createFromFormat('Y.m.d', $sDate, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject()); + return $oDateTime ? $oDateTime->getTimestamp() - $iTimeZoneOffset : 0; + } + + return $iResult; + } + + /** + * @param string $sSize + * + * @return int + */ + private function parseFriendlySize($sSize) + { + $sSize = preg_replace('/[^0-9bBkKmM]/', '', $sSize); + + $iResult = 0; + $aMatch = array(); + + if (\preg_match('/([\d]+)(B|KB|M|MB|G|GB)$/i', $sSize, $aMatch) && isset($aMatch[1], $aMatch[2])) + { + $iResult = (int) $aMatch[1]; + switch (\strtoupper($aMatch[2])) + { + case 'K': + case 'KB': + $iResult *= 1024; + case 'M': + case 'MB': + $iResult *= 1024; + case 'G': + case 'GB': + $iResult *= 1024; + } + } + else + { + $iResult = (int) $sSize; + } + + return $iResult; + } + + /** + * @param string $sSearch + * + * @return array + */ + private function parseSearchString($sSearch) + { + $aResult = array( + 'OTHER' => '' + ); + + $aCache = array(); + + $sReg = 'e?mail|from|to|subject|has|is|date|text|body|size|larger|bigger|smaller|maxsize|minsize'; + + $sSearch = \MailSo\Base\Utils::StripSpaces($sSearch); + $sSearch = \trim(\preg_replace('/('.$sReg.'): /i', '\\1:', $sSearch)); + + $mMatch = array(); + \preg_match_all('/".*?(? $sName) + { + if (isset($mMatch[2][$iIndex]) && 0 < \strlen($mMatch[2][$iIndex])) + { + $sName = \strtoupper($sName); + $sValue = $mMatch[2][$iIndex]; + switch ($sName) + { + case 'TEXT': + case 'BODY': + case 'EMAIL': + case 'MAIL': + case 'FROM': + case 'TO': + case 'SUBJECT': + case 'IS': + case 'HAS': + case 'SIZE': + case 'SMALLER': + case 'LARGER': + case 'BIGGER': + case 'MAXSIZE': + case 'MINSIZE': + case 'DATE': + if ('MAIL' === $sName) + { + $sName = 'EMAIL'; + } + if ('BODY' === $sName) + { + $sName = 'TEXT'; + } + if ('SIZE' === $sName || 'BIGGER' === $sName || 'MINSIZE' === $sName) + { + $sName = 'LARGER'; + } + if ('MAXSIZE' === $sName) + { + $sName = 'SMALLER'; + } + $aResult[$sName] = $sValue; + break; + } + } + } + } + + $aResult['OTHER'] = $sSearch; + foreach ($aResult as $sName => $sValue) + { + if (isset($aCache[$sValue])) + { + $aResult[$sName] = \trim($aCache[$sValue], '"\' '); + } + } + + return $aResult; + } + + /** + * @param string $sSearch + * @param string $sFilter + * @param int $iTimeZoneOffset = 0 + * @param bool $bUseCache = true + * + * @return string + */ + private function getImapSearchCriterias($sSearch, $sFilter, $iTimeZoneOffset = 0, &$bUseCache = true) + { + $bUseCache = true; + $iTimeFilter = 0; + $aCriteriasResult = array(); + + if (0 < \MailSo\Config::$MessageListDateFilter) + { + $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter; + $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD)); + } + + if (0 < \strlen(\trim($sSearch))) + { + $sGmailRawSearch = ''; + $sResultBodyTextSearch = ''; + + $aLines = $this->parseSearchString($sSearch); + $bIsGmail = $this->oImapClient->IsSupported('X-GM-EXT-1'); + + if (1 === \count($aLines) && isset($aLines['OTHER'])) + { + $sValue = $this->escapeSearchString($aLines['OTHER']); + + if (\MailSo\Config::$MessageListFastSimpleSearch) + { + $aCriteriasResult[] = 'OR OR OR'; + $aCriteriasResult[] = 'FROM'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'TO'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'CC'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'SUBJECT'; + $aCriteriasResult[] = $sValue; + } + else + { + $aCriteriasResult[] = 'TEXT'; + $aCriteriasResult[] = $sValue; + } + } + else + { + if (isset($aLines['EMAIL'])) + { + $sValue = $this->escapeSearchString($aLines['EMAIL']); + + $aCriteriasResult[] = 'OR OR'; + $aCriteriasResult[] = 'FROM'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'TO'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'CC'; + $aCriteriasResult[] = $sValue; + + unset($aLines['EMAIL']); + } + + if (isset($aLines['TO'])) + { + $sValue = $this->escapeSearchString($aLines['TO']); + + $aCriteriasResult[] = 'OR'; + $aCriteriasResult[] = 'TO'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'CC'; + $aCriteriasResult[] = $sValue; + + unset($aLines['TO']); + } + + $sMainText = ''; + foreach ($aLines as $sName => $sRawValue) + { + if ('' === \trim($sRawValue)) + { + continue; + } + + $sValue = $this->escapeSearchString($sRawValue); + switch ($sName) + { + case 'FROM': + $aCriteriasResult[] = 'FROM'; + $aCriteriasResult[] = $sValue; + break; + case 'SUBJECT': + $aCriteriasResult[] = 'SUBJECT'; + $aCriteriasResult[] = $sValue; + break; + case 'OTHER': + case 'TEXT': + $sMainText .= ' '.$sRawValue; + break; + case 'HAS': + $aValue = \explode(',', \strtolower($sRawValue)); + $aValue = \array_map('trim', $aValue); + + $aCompareArray = array('file', 'files', 'attach', 'attachs', 'attachment', 'attachments'); + if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) + { + if ($bIsGmail) + { + $sGmailRawSearch .= ' has:attachment'; + } + else + { + // Simple, is not detailed search (Sometimes doesn't work) + $aCriteriasResult[] = 'OR OR OR'; + $aCriteriasResult[] = 'HEADER Content-Type application/'; + $aCriteriasResult[] = 'HEADER Content-Type multipart/m'; + $aCriteriasResult[] = 'HEADER Content-Type multipart/signed'; + $aCriteriasResult[] = 'HEADER Content-Type multipart/report'; + } + } + + case 'IS': + $aValue = \explode(',', \strtolower($sRawValue)); + $aValue = \array_map('trim', $aValue); + + $aCompareArray = array('flag', 'flagged', 'star', 'starred', 'pinned'); + $aCompareArray2 = array('unflag', 'unflagged', 'unstar', 'unstarred', 'unpinned'); + if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) + { + $aCriteriasResult[] = 'FLAGGED'; + $bUseCache = false; + } + else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue))) + { + $aCriteriasResult[] = 'UNFLAGGED'; + $bUseCache = false; + } + + $aCompareArray = array('unread', 'unseen'); + $aCompareArray2 = array('read', 'seen'); + if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) + { + $aCriteriasResult[] = 'UNSEEN'; + $bUseCache = false; + } + else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue))) + { + $aCriteriasResult[] = 'SEEN'; + $bUseCache = false; + } + break; + + case 'LARGER': + $aCriteriasResult[] = 'LARGER'; + $aCriteriasResult[] = $this->parseFriendlySize($sRawValue); + break; + case 'SMALLER': + $aCriteriasResult[] = 'SMALLER'; + $aCriteriasResult[] = $this->parseFriendlySize($sRawValue); + break; + case 'DATE': + $iDateStampFrom = $iDateStampTo = 0; + + $sDate = $sRawValue; + $aDate = \explode('/', $sDate); + + if (\is_array($aDate) && 2 === \count($aDate)) + { + if (0 < \strlen($aDate[0])) + { + $iDateStampFrom = $this->parseSearchDate($aDate[0], $iTimeZoneOffset); + } + + if (0 < \strlen($aDate[1])) + { + $iDateStampTo = $this->parseSearchDate($aDate[1], $iTimeZoneOffset); + $iDateStampTo += 60 * 60 * 24; + } + } + else + { + if (0 < \strlen($sDate)) + { + $iDateStampFrom = $this->parseSearchDate($sDate, $iTimeZoneOffset); + $iDateStampTo = $iDateStampFrom + 60 * 60 * 24; + } + } + + if (0 < $iDateStampFrom) + { + $aCriteriasResult[] = 'SINCE'; + $aCriteriasResult[] = \gmdate('j-M-Y', $iTimeFilter > $iDateStampFrom ? + $iTimeFilter : $iDateStampFrom); + + $iTimeFilter = 0; + } + + if (0 < $iDateStampTo) + { + $aCriteriasResult[] = 'BEFORE'; + $aCriteriasResult[] = \gmdate('j-M-Y', $iDateStampTo); + } + break; + } + } + + if ('' !== \trim($sMainText)) + { + $sMainText = \trim(\MailSo\Base\Utils::StripSpaces($sMainText), '"'); + if ($bIsGmail) + { + $sGmailRawSearch .= ' '.$sMainText; + } + else + { + $sResultBodyTextSearch .= ' '.$sMainText; + } + } + } + + $sGmailRawSearch = \trim($sGmailRawSearch); + if ($bIsGmail && 0 < \strlen($sGmailRawSearch)) + { + $aCriteriasResult[] = 'X-GM-RAW'; + $aCriteriasResult[] = $this->escapeSearchString($sGmailRawSearch, false); + } + + $sResultBodyTextSearch = \trim($sResultBodyTextSearch); + if (0 < \strlen($sResultBodyTextSearch)) + { + $aCriteriasResult[] = 'BODY'; + $aCriteriasResult[] = $this->escapeSearchString($sResultBodyTextSearch); + } + } + + $sCriteriasResult = \trim(\implode(' ', $aCriteriasResult)); + + if (0 < $iTimeFilter) + { + $sCriteriasResult .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter); + } + + $sCriteriasResult = \trim($sCriteriasResult); + if (\MailSo\Config::$MessageListUndeletedOnly) + { + $sCriteriasResult = \trim($sCriteriasResult.' UNDELETED'); + } + + $sFilter = \trim($sFilter); + if ('' !== $sFilter) + { + $sCriteriasResult .= ' '.$sFilter; + } + + $sCriteriasResult = \trim($sCriteriasResult); + if ('' !== \MailSo\Config::$MessageListPermanentFilter) + { + $sCriteriasResult = \trim($sCriteriasResult.' '.\MailSo\Config::$MessageListPermanentFilter); + } + + $sCriteriasResult = \trim($sCriteriasResult); + if ('' === $sCriteriasResult) + { + $sCriteriasResult = 'ALL'; + } + + return $sCriteriasResult; + } + + /** + * @param array $aThreads + * @return array + */ + private function threadArrayMap($aThreads) + { + $aNew = array(); + foreach ($aThreads as $mItem) + { + if (!\is_array($mItem)) + { + $aNew[] = $mItem; + } + else + { + $mMap = $this->threadArrayMap($mItem); + if (\is_array($mMap) && 0 < \count($mMap)) + { + $aNew = \array_merge($aNew, $mMap); + } + } + } + + return $aNew; + } + + /** + * @param array $aThreads + * + * @return array + */ + private function compileThreadArray($aThreads) + { + $aResult = array(); + foreach ($aThreads as $mItem) + { + if (\is_array($mItem)) + { + $aMap = $this->threadArrayMap($mItem); + if (\is_array($aMap)) + { + if (1 < \count($aMap)) + { + $aResult[] = $aMap; + } + else if (0 < \count($aMap)) + { + $aResult[] = $aMap[0]; + } + } + } + else + { + $aResult[] = $mItem; + } + } + + return $aResult; + } + + /** + * @param string $sFolderName + * @param string $sFolderHash + * @param array $aIndexOrUids + * @param \MailSo\Cache\CacheClient $oCacher + * @param bool $bCacheOnly = false + * + * @return array + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageListThreadsMap($sFolderName, $sFolderHash, $aIndexOrUids, $oCacher, $bCacheOnly = false) + { + $iThreadLimit = \MailSo\Config::$LargeThreadLimit; + + $sSearchHash = ''; + if (0 < \MailSo\Config::$MessageListDateFilter) + { + $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter; + $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD)); + + $sSearchHash .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter); + } + + if ('' === \trim($sSearchHash)) + { + $sSearchHash = 'ALL'; + } + + if ($oCacher && $oCacher->IsInited()) + { + $sSerializedHashKey = + 'ThreadsMapSorted/'.$sSearchHash.'/'. + 'Limit='.$iThreadLimit.'/'.$sFolderName.'/'.$sFolderHash; + + if ($this->oLogger) + { + $this->oLogger->Write($sSerializedHashKey); + } + + $sSerializedUids = $oCacher->Get($sSerializedHashKey); + if (!empty($sSerializedUids)) + { + $aSerializedUids = @\json_decode($sSerializedUids, true); + if (isset($aSerializedUids['ThreadsUids']) && \is_array($aSerializedUids['ThreadsUids'])) + { + if ($this->oLogger) + { + $this->oLogger->Write('Get Serialized Thread UIDS from cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aSerializedUids['ThreadsUids']).']'); + } + + return $aSerializedUids['ThreadsUids']; + } + } + } + + if ($bCacheOnly) + { + return null; + } + + $this->oImapClient->FolderExamine($sFolderName); + + $aThreadUids = array(); + try + { + $aThreadUids = $this->oImapClient->MessageSimpleThread($sSearchHash); + } + catch (\MailSo\Imap\Exceptions\RuntimeException $oException) + { + unset($oException); + $aThreadUids = array(); + } + + $aResult = array(); + $aCompiledThreads = $this->compileThreadArray($aThreadUids); + + foreach ($aCompiledThreads as $mData) + { + if (\is_array($mData)) + { + foreach ($mData as $mSubData) + { + $aResult[(int) $mSubData] = + \array_diff($mData, array((int) $mSubData)); + } + } + else if (\is_int($mData) || \is_string($mData)) + { + $aResult[(int) $mData] = (int) $mData; + } + } + + $aParentsMap = array(); + foreach ($aIndexOrUids as $iUid) + { + if (isset($aResult[$iUid]) && \is_array($aResult[$iUid])) + { + foreach ($aResult[$iUid] as $iTempUid) + { + $aParentsMap[$iTempUid] = $iUid; + if (isset($aResult[$iTempUid])) + { + unset($aResult[$iTempUid]); + } + } + } + } + + $aSortedThreads = array(); + foreach ($aIndexOrUids as $iUid) + { + if (isset($aResult[$iUid])) + { + $aSortedThreads[$iUid] = $iUid; + } + } + + foreach ($aIndexOrUids as $iUid) + { + if (!isset($aSortedThreads[$iUid]) && + isset($aParentsMap[$iUid]) && + isset($aSortedThreads[$aParentsMap[$iUid]])) + { + if (!\is_array($aSortedThreads[$aParentsMap[$iUid]])) + { + $aSortedThreads[$aParentsMap[$iUid]] = array(); + } + + $aSortedThreads[$aParentsMap[$iUid]][] = $iUid; + } + } + + $aResult = $aSortedThreads; + unset($aParentsMap, $aSortedThreads); + + $aTemp = array(); + foreach ($aResult as $iUid => $mValue) + { + if (0 < $iThreadLimit && \is_array($mValue) && $iThreadLimit < \count($mValue)) + { + $aParts = \array_chunk($mValue, $iThreadLimit); + if (0 < count($aParts)) + { + foreach ($aParts as $iIndex => $aItem) + { + if (0 === $iIndex) + { + $aResult[$iUid] = $aItem; + } + else if (0 < $iIndex && \is_array($aItem)) + { + $mFirst = \array_shift($aItem); + if (!empty($mFirst)) + { + $aTemp[$mFirst] = 0 < \count($aItem) ? $aItem : $mFirst; + } + } + } + } + } + } + + foreach ($aTemp as $iUid => $mValue) + { + $aResult[$iUid] = $mValue; + } + + unset($aTemp); + + $aLastResult = array(); + foreach ($aIndexOrUids as $iUid) + { + if (isset($aResult[$iUid])) + { + $aLastResult[$iUid] = $aResult[$iUid]; + } + } + + $aResult = $aLastResult; + unset($aLastResult); + + if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey)) + { + $oCacher->Set($sSerializedHashKey, @\json_encode(array( + 'ThreadsUids' => $aResult + ))); + + if ($this->oLogger) + { + $this->oLogger->Write('Save Serialized Thread UIDS to cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aResult).']'); + } + } + + return $aResult; + } + + /** + * @param \MailSo\Mail\MessageCollection &$oMessageCollection + * @param array $aRequestIndexOrUids + * @param bool $bIndexAsUid + * @param bool $bSimple = false + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageListByRequestIndexOrUids(&$oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid, $bSimple = false) + { + if (\is_array($aRequestIndexOrUids) && 0 < \count($aRequestIndexOrUids)) + { + $aFetchResponse = $this->oImapClient->Fetch(array( + \MailSo\Imap\Enumerations\FetchType::INDEX, + \MailSo\Imap\Enumerations\FetchType::UID, + \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, + \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, + \MailSo\Imap\Enumerations\FetchType::FLAGS, + \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE, + $bSimple ? + $this->getEnvelopeOrHeadersRequestStringForSimpleList() : + $this->getEnvelopeOrHeadersRequestString() + ), \MailSo\Base\Utils::PrepearFetchSequence($aRequestIndexOrUids), $bIndexAsUid); + + if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) + { + $aFetchIndexArray = array(); + $oFetchResponseItem = null; + foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem) + { + $aFetchIndexArray[($bIndexAsUid) + ? $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID) + : $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::INDEX)] =& $oFetchResponseItem; + + unset($oFetchResponseItem); + } + + foreach ($aRequestIndexOrUids as $iFUid) + { + if (isset($aFetchIndexArray[$iFUid])) + { + $oMessageCollection->Add( + Message::NewFetchResponseInstance( + $oMessageCollection->FolderName, $aFetchIndexArray[$iFUid])); + } + } + } + } + } + + /** + * @return bool + * + * @throws \MailSo\Net\Exceptions\Exception + */ + public function IsThreadsSupported() + { + return $this->oImapClient->IsSupported('THREAD=REFS') || + $this->oImapClient->IsSupported('THREAD=REFERENCES') || + $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT'); + } + + /** + * @param string $sFolderName + * @param array $aUids + * + * @return \MailSo\Mail\MessageCollection + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageListSimple($sFolderName, $aUids) + { + if (0 === \strlen($sFolderName) || !\MailSo\Base\Validator::NotEmptyArray($aUids)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderExamine($sFolderName); + + $oMessageCollection = \MailSo\Mail\MessageCollection::NewInstance(); + $oMessageCollection->FolderName = $sFolderName; + + $this->MessageListByRequestIndexOrUids($oMessageCollection, $aUids, true, true); + + return $oMessageCollection->GetAsArray(); + } + + /** + * @param \MailSo\Cache\CacheClient|null $oCacher + * @param string $sSearch + * @param string $sFilter + * @param string $sFolderName + * @param string $sFolderHash + * @param bool $bUseSortIfSupported = false + * + * @return array + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function GetUids($oCacher, $sSearch, $sFilter, $sFolderName, $sFolderHash, $bUseSortIfSupported = false) + { + $aResultUids = false; + $bUidsFromCacher = false; + $bUseCacheAfterSearch = true; + + $sSerializedHash = ''; + $sSerializedLog = ''; + + $bUseSortIfSupported = $bUseSortIfSupported ? !!$this->oImapClient->IsSupported('SORT') : false; + + if (0 < \strlen($sSearch)) + { + $bUseSortIfSupported = false; + } + + $sSearchCriterias = $this->getImapSearchCriterias($sSearch, $sFilter, 0, $bUseCacheAfterSearch); + if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited()) + { + $sSerializedHash = 'GetUids/'. + ($bUseSortIfSupported ? 'S': 'N').'/'. + $this->GenerateImapClientHash().'/'. + $sFolderName.'/'.$sSearchCriterias; + + $sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.''; + + $sSerialized = $oCacher->Get($sSerializedHash); + if (!empty($sSerialized)) + { + $aSerialized = @\json_decode($sSerialized, true); + if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) && + $sFolderHash === $aSerialized['FolderHash'] && + \is_array($aSerialized['Uids']) + ) + { + if ($this->oLogger) + { + $this->oLogger->Write('Get Serialized UIDS from cache ('.$sSerializedLog.') [count:'.\count($aSerialized['Uids']).']'); + } + + $aResultUids = $aSerialized['Uids']; + $bUidsFromCacher = true; + } + } + } + + if (!\is_array($aResultUids)) + { + $aResultUids = $bUseSortIfSupported ? + $this->oImapClient->MessageSimpleSort(array('REVERSE ARRIVAL'), $sSearchCriterias, true) : + $this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8') + ; + + if (!$bUidsFromCacher && $bUseCacheAfterSearch && \is_array($aResultUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash)) + { + $oCacher->Set($sSerializedHash, @\json_encode(array( + 'FolderHash' => $sFolderHash, + 'Uids' => $aResultUids + ))); + + if ($this->oLogger) + { + $this->oLogger->Write('Save Serialized UIDS to cache ('.$sSerializedLog.') [count:'.\count($aResultUids).']'); + } + } + } + + return \is_array($aResultUids) ? $aResultUids : array(); + } + + /** + * @param string $sFolderName + * @param int $iOffset = 0 + * @param int $iLimit = 10 + * @param string $sSearch = '' + * @param string $sPrevUidNext = '' + * @param \MailSo\Cache\CacheClient|null $oCacher = null + * @param bool $bUseSortIfSupported = false + * @param bool $bUseThreadSortIfSupported = false + * @param bool $bUseESearchOrESortRequest = false + * @param string $sThreadUid = '' + * @param string $sFilter = '' + * + * @return \MailSo\Mail\MessageCollection + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '', $oCacher = null, + $bUseSortIfSupported = false, $bUseThreadSortIfSupported = false, $sThreadUid = '', $sFilter = '') + { + $sFilter = \trim($sFilter); + $sSearch = \trim($sSearch); + if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) || + !\MailSo\Base\Validator::RangeInt($iLimit, 0, 999)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $bUseFilter = '' !== $sFilter; + + $this->oImapClient->FolderSelect($sFolderName); + + $oMessageCollection = MessageCollection::NewInstance(); + $oMessageCollection->FolderName = $sFolderName; + $oMessageCollection->Offset = $iOffset; + $oMessageCollection->Limit = $iLimit; + $oMessageCollection->Search = $sSearch; + $oMessageCollection->ThreadUid = $sThreadUid; + $oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter; + + $aUids = array(); + $mAllSortedUids = null; + $mAllThreads = null; + + $iThreadUid = empty($sThreadUid) ? 0 : (int) $sThreadUid; + + $iMessageRealCount = 0; + $iMessageUnseenCount = 0; + $sUidNext = '0'; + $sHighestModSeq = ''; + + $bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false; + + $bUseThreadSortIfSupported = $bUseThreadSortIfSupported ? + ($this->oImapClient->IsSupported('THREAD=REFS') || $this->oImapClient->IsSupported('THREAD=REFERENCES') || $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT')) : false; + + if (!empty($sThreadUid) && !$bUseThreadSortIfSupported) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + if (!$oCacher || !($oCacher instanceof \MailSo\Cache\CacheClient)) + { + $oCacher = null; + } + + $this->initFolderValues($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq); + + if ($bUseFilter) + { + $iMessageUnseenCount = 0; + } + + $oMessageCollection->FolderHash = $this->GenerateFolderHash( + $sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq); + + $oMessageCollection->UidNext = $sUidNext; + + if (empty($sThreadUid) && 0 < \strlen($sPrevUidNext) && 'INBOX' === $sFolderName) + { + $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation( + $sFolderName, $sPrevUidNext, $sUidNext); + } + + $bSearch = false; + $bMessageListOptimization = 0 < \MailSo\Config::$MessageListCountLimitTrigger && + \MailSo\Config::$MessageListCountLimitTrigger < $iMessageRealCount; + + if ($bMessageListOptimization) + { + $bUseSortIfSupported = false; + $bUseThreadSortIfSupported = false; + } + + if (0 < $iMessageRealCount && !$bMessageListOptimization) + { + $mAllSortedUids = $this->GetUids($oCacher, '', $sFilter, + $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported); + + $mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap( + $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null; + + if ($bUseThreadSortIfSupported && 0 < $iThreadUid && \is_array($mAllThreads)) + { + $aUids = array(); + $iResultRootUid = 0; + + if (isset($mAllThreads[$iThreadUid])) + { + $iResultRootUid = $iThreadUid; + if (\is_array($mAllThreads[$iThreadUid])) + { + $aUids = $mAllThreads[$iThreadUid]; + } + } + else + { + foreach ($mAllThreads as $iRootUid => $mSubUids) + { + if (\is_array($mSubUids) && \in_array($iThreadUid, $mSubUids)) + { + $iResultRootUid = $iRootUid; + $aUids = $mSubUids; + continue; + } + } + } + + if (0 < $iResultRootUid && \in_array($iResultRootUid, $mAllSortedUids)) + { + \array_unshift($aUids, $iResultRootUid); + } + } + else if ($bUseThreadSortIfSupported && \is_array($mAllThreads)) + { + $aUids = \array_keys($mAllThreads); + } + else + { + $bUseThreadSortIfSupported = false; + $aUids = $mAllSortedUids; + } + + if (0 < \strlen($sSearch) && \is_array($aUids)) + { + $aSearchedUids = $this->GetUids($oCacher, $sSearch, $sFilter, + $oMessageCollection->FolderName, $oMessageCollection->FolderHash); + + if (\is_array($aSearchedUids) && 0 < \count($aSearchedUids)) + { + $aFlippedSearchedUids = \array_flip($aSearchedUids); + + $bSearch = true; + $aNewUids = array(); + + foreach ($aUids as $iUid) + { + if (isset($aFlippedSearchedUids[$iUid])) + { + $aNewUids[] = $iUid; + } + else if ($bUseThreadSortIfSupported && 0 === $iThreadUid && isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid])) + { + foreach ($mAllThreads[$iUid] as $iSubUid) + { + if (isset($aFlippedSearchedUids[$iSubUid])) + { + $aNewUids[] = $iUid; + continue; + } + } + } + } + + $aUids = \array_unique($aNewUids); + unset($aNewUids); + } + else + { + $aUids = array(); + } + } + + if (\is_array($aUids)) + { + $oMessageCollection->MessageCount = $iMessageRealCount; + $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount; + $oMessageCollection->MessageResultCount = \count($aUids); + + if (0 < \count($aUids)) + { + $aRequestUids = \array_slice($aUids, $iOffset, $iLimit); + $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true); + } + } + } + else if (0 < $iMessageRealCount) + { + if ($this->oLogger) + { + $this->oLogger->Write('List optimization (count: '.$iMessageRealCount. + ', limit:'.\MailSo\Config::$MessageListCountLimitTrigger.')'); + } + + $oMessageCollection->MessageCount = $iMessageRealCount; + $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount; + + if (0 < \strlen($sSearch) || $bUseFilter) + { + $aUids = $this->GetUids($oCacher, $sSearch, $sFilter, + $oMessageCollection->FolderName, $oMessageCollection->FolderHash); + + if (0 < \count($aUids)) + { + $oMessageCollection->MessageResultCount = \count($aUids); + + $aRequestUids = \array_slice($aUids, $iOffset, $iLimit); + $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true); + } + else + { + $oMessageCollection->MessageResultCount = 0; + } + } + else + { + $oMessageCollection->MessageResultCount = $iMessageRealCount; + + if (1 < $iMessageRealCount) + { + $aRequestIndexes = \array_slice(array_reverse(range(1, $iMessageRealCount)), $iOffset, $iLimit); + } + else + { + $aRequestIndexes = \array_slice(array(1), $iOffset, $iLimit); + } + + $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestIndexes, false); + } + } + + if ($bUseThreadSortIfSupported && 0 === $iThreadUid && \is_array($mAllThreads) && 0 < \count($mAllThreads)) + { + $oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use ($mAllThreads) { + + $iUid = $oMessage->Uid(); + if (isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid]) && 0 < \count($mAllThreads[$iUid])) + { + $aSubThreads = $mAllThreads[$iUid]; + \array_unshift($aSubThreads, $iUid); + + $oMessage->SetThreads(\array_map('trim', $aSubThreads)); + unset($aSubThreads); + } + }); + } + + return $oMessageCollection; + } + + /** + * @return array|false + */ + public function Quota() + { + return $this->oImapClient->Quota(); + } + + /** + * @param string $sFolderName + * @param string $sMessageId + * + * @return int|null + */ + public function FindMessageUidByMessageId($sFolderName, $sMessageId) + { + if (0 === \strlen($sMessageId)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderExamine($sFolderName); + + $aUids = $this->oImapClient->MessageSimpleSearch( + 'HEADER Message-ID '.$sMessageId, true); + + return \is_array($aUids) && 1 === \count($aUids) && \is_numeric($aUids[0]) ? (int) $aUids[0] : null; + } + + /** + * @param array $aMailFoldersHelper + * @param int $iOptimizationLimit = 0 + * + * @return array + */ + public function folderListOptimization($aMailFoldersHelper, $iOptimizationLimit = 0) + { + // optimization + if (10 < $iOptimizationLimit && \is_array($aMailFoldersHelper) && $iOptimizationLimit < \count($aMailFoldersHelper)) + { + if ($this->oLogger) + { + $this->oLogger->Write('Start optimization (limit:'.$iOptimizationLimit.') for '.\count($aMailFoldersHelper).' folders'); + } + + $iForeachLimit = 1; + + $aFilteredNames = array( + 'inbox', + 'sent', 'send', 'outbox', 'sentmail', 'sendmail', + 'drafts', 'draft', + 'junk', 'spam', 'spambucket', + 'trash', 'bin', 'deleted', + 'archives', 'archive', 'allmail', 'all', + 'starred', 'flagged', 'important', + 'contacts', 'chats' + ); + + $aNewMailFoldersHelper = array(); + + $iCountLimit = $iForeachLimit; + + foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) + { + // mandatory folders + if ($oFolder && \in_array(\str_replace(' ', '', \strtolower($oFolder->NameRaw())), $aFilteredNames)) + { + $aNewMailFoldersHelper[] = $oFolder; + $aMailFoldersHelper[$iIndex] = null; + } + } + + foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) + { + // subscribed folders + if ($oFolder && $oFolder->IsSubscribed()) + { + $aNewMailFoldersHelper[] = $oFolder; + + $aMailFoldersHelper[$iIndex] = null; + $iCountLimit--; + } + + if (0 > $iCountLimit) + { + if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) + { + break; + } + else + { + $iCountLimit = $iForeachLimit; + } + } + } + + $iCountLimit = $iForeachLimit; + if ($iOptimizationLimit >= \count($aNewMailFoldersHelper)) + { + // name filter + foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) + { + if ($oFolder && !\preg_match('/[{}\[\]]/', $oFolder->NameRaw())) + { + $aNewMailFoldersHelper[] = $oFolder; + + $aMailFoldersHelper[$iIndex] = null; + $iCountLimit--; + } + + if (0 > $iCountLimit) + { + if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) + { + break; + } + else + { + $iCountLimit = $iForeachLimit; + } + } + } + } + + $iCountLimit = $iForeachLimit; + if ($iOptimizationLimit >= \count($aNewMailFoldersHelper)) + { + // other + foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) + { + if ($oFolder) + { + $aNewMailFoldersHelper[] = $oFolder; + + $aMailFoldersHelper[$iIndex] = null; + $iCountLimit--; + } + + if (0 > $iCountLimit) + { + if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) + { + break; + } + else + { + $iCountLimit = $iForeachLimit; + } + } + } + } + + $aMailFoldersHelper = $aNewMailFoldersHelper; + + if ($this->oLogger) + { + $this->oLogger->Write('Result optimization: '.\count($aMailFoldersHelper).' folders'); + } + } + + return $aMailFoldersHelper; + } + + /** + * @param string $sParent = '' + * @param string $sListPattern = '*' + * @param bool $bUseListSubscribeStatus = false + * @param int $iOptimizationLimit = 0 + * + * @return \MailSo\Mail\FolderCollection|false + */ + public function Folders($sParent = '', $sListPattern = '*', $bUseListSubscribeStatus = true, $iOptimizationLimit = 0) + { + $oFolderCollection = false; + + $aSubscribedFolders = null; + if ($bUseListSubscribeStatus) + { + try + { + $aSubscribedFolders = $this->oImapClient->FolderSubscribeList($sParent, $sListPattern); + } + catch (\Exception $oException) + { + unset($oException); + } + } + + $aImapSubscribedFoldersHelper = null; + if (\is_array($aSubscribedFolders)) + { + $aImapSubscribedFoldersHelper = array(); + foreach ($aSubscribedFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) + { + $aImapSubscribedFoldersHelper[] = $oImapFolder->FullNameRaw(); + } + } + + $aFolders = $this->oImapClient->FolderList($sParent, $sListPattern); + + $bOptimized = false; + $aMailFoldersHelper = null; + + if (\is_array($aFolders)) + { + $aMailFoldersHelper = array(); + + foreach ($aFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) + { + $aMailFoldersHelper[] = Folder::NewInstance($oImapFolder, + (null === $aImapSubscribedFoldersHelper || \in_array($oImapFolder->FullNameRaw(), $aImapSubscribedFoldersHelper)) || + $oImapFolder->IsInbox() + ); + } + + $iCount = \count($aMailFoldersHelper); + $aMailFoldersHelper = $this->folderListOptimization($aMailFoldersHelper, $iOptimizationLimit); + + $bOptimized = $iCount !== \count($aMailFoldersHelper); + } + + if (\is_array($aMailFoldersHelper)) + { + $oFolderCollection = FolderCollection::NewInstance(); + $oFolderCollection->InitByUnsortedMailFolderArray($aMailFoldersHelper); + + $oFolderCollection->Optimized = $bOptimized; + } + + if ($oFolderCollection) + { + $oFolderCollection->SortByCallback(function ($oFolderA, $oFolderB) { + $sA = \strtoupper($oFolderA->FullNameRaw()); + $sB = \strtoupper($oFolderB->FullNameRaw()); + switch (true) + { + case 'INBOX' === $sA: + return -1; + case 'INBOX' === $sB: + return 1; + case '[GMAIL]' === $sA: + return -1; + case '[GMAIL]' === $sB: + return 1; + } + + return \strnatcasecmp($oFolderA->FullName(), $oFolderB->FullName()); + }); + + $oNamespace = $this->oImapClient->GetNamespace(); + if ($oNamespace) + { + $oFolderCollection->SetNamespace($oNamespace->GetPersonalNamespace()); + } + + $oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported(); + } + + return $oFolderCollection; + } + + /** + * @param string $sFolderNameInUtf8 + * @param string $sFolderParentFullNameRaw = '' + * @param bool $bSubscribeOnCreation = true + * @param string $sDelimiter = '' + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function FolderCreate($sFolderNameInUtf8, $sFolderParentFullNameRaw = '', $bSubscribeOnCreation = true, $sDelimiter = '') + { + if (!\MailSo\Base\Validator::NotEmptyString($sFolderNameInUtf8, true) || + !\is_string($sFolderParentFullNameRaw)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $sFolderNameInUtf8 = \trim($sFolderNameInUtf8); + + if (0 === \strlen($sDelimiter) || 0 < \strlen(\trim($sFolderParentFullNameRaw))) + { + $aFolders = $this->oImapClient->FolderList('', 0 === \strlen(\trim($sFolderParentFullNameRaw)) ? 'INBOX' : $sFolderParentFullNameRaw); + if (!\is_array($aFolders) || !isset($aFolders[0])) + { + // TODO + throw new \MailSo\Mail\Exceptions\RuntimeException( + 0 === \strlen(trim($sFolderParentFullNameRaw)) + ? 'Cannot get folder delimiter' + : 'Cannot create folder in non-existen parent folder'); + } + + $sDelimiter = $aFolders[0]->Delimiter(); + if (0 < \strlen($sDelimiter) && 0 < \strlen(\trim($sFolderParentFullNameRaw))) + { + $sFolderParentFullNameRaw .= $sDelimiter; + } + } + + $sFullNameRawToCreate = \MailSo\Base\Utils::ConvertEncoding($sFolderNameInUtf8, + \MailSo\Base\Enumerations\Charset::UTF_8, + \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); + + if (0 < \strlen($sDelimiter) && false !== \strpos($sFullNameRawToCreate, $sDelimiter)) + { + // TODO + throw new \MailSo\Mail\Exceptions\RuntimeException( + 'New folder name contains delimiter'); + } + + $sFullNameRawToCreate = $sFolderParentFullNameRaw.$sFullNameRawToCreate; + + $this->oImapClient->FolderCreate($sFullNameRawToCreate); + + if ($bSubscribeOnCreation) + { + $this->oImapClient->FolderSubscribe($sFullNameRawToCreate); + } + + return $this; + } + + /** + * @param string $sPrevFolderFullNameRaw + * @param string $sNextFolderFullNameInUtf + * @param bool $bSubscribeOnMove = true + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function FolderMove($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, $bSubscribeOnMove = true) + { + return $this->folderModify($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, false, $bSubscribeOnMove); + } + + /** + * @param string $sPrevFolderFullNameRaw + * @param string $sNewTopFolderNameInUtf + * @param bool $bSubscribeOnRename = true + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function FolderRename($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, $bSubscribeOnRename = true) + { + return $this->folderModify($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, true, $bSubscribeOnRename); + } + + /** + * @param string $sPrevFolderFullNameRaw + * @param string $sNextFolderNameInUtf + * @param bool $bRenameOrMove + * @param bool $bSubscribeOnModify + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function folderModify($sPrevFolderFullNameRaw, $sNextFolderNameInUtf, $bRenameOrMove, $bSubscribeOnModify) + { + if (0 === \strlen($sPrevFolderFullNameRaw) || 0 === \strlen($sNextFolderNameInUtf)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $aFolders = $this->oImapClient->FolderList('', $sPrevFolderFullNameRaw); + if (!\is_array($aFolders) || !isset($aFolders[0])) + { + // TODO + throw new \MailSo\Mail\Exceptions\RuntimeException('Cannot rename non-existen folder'); + } + + $sDelimiter = $aFolders[0]->Delimiter(); + $iLast = \strrpos($sPrevFolderFullNameRaw, $sDelimiter); + + $mSubscribeFolders = null; + if ($bSubscribeOnModify) + { + $mSubscribeFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullNameRaw, '*'); + if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders)) + { + foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) + { + $this->oImapClient->FolderUnSubscribe($oFolder->FullNameRaw()); + } + } + } + + $sNewFolderFullNameRaw = \MailSo\Base\Utils::ConvertEncoding($sNextFolderNameInUtf, + \MailSo\Base\Enumerations\Charset::UTF_8, + \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); + + if($bRenameOrMove) + { + if (0 < \strlen($sDelimiter) && false !== \strpos($sNewFolderFullNameRaw, $sDelimiter)) + { + // TODO + throw new \MailSo\Mail\Exceptions\RuntimeException('New folder name contains delimiter'); + } + + $sFolderParentFullNameRaw = false === $iLast ? '' : \substr($sPrevFolderFullNameRaw, 0, $iLast + 1); + $sNewFolderFullNameRaw = $sFolderParentFullNameRaw.$sNewFolderFullNameRaw; + } + + $this->oImapClient->FolderRename($sPrevFolderFullNameRaw, $sNewFolderFullNameRaw); + + if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders)) + { + foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) + { + $sFolderFullNameRawForResubscrine = $oFolder->FullNameRaw(); + if (0 === \strpos($sFolderFullNameRawForResubscrine, $sPrevFolderFullNameRaw)) + { + $sNewFolderFullNameRawForResubscrine = $sNewFolderFullNameRaw. + \substr($sFolderFullNameRawForResubscrine, \strlen($sPrevFolderFullNameRaw)); + + $this->oImapClient->FolderSubscribe($sNewFolderFullNameRawForResubscrine); + } + } + } + + return $this; + } + + /** + * @param string $sFolderFullNameRaw + * @param bool $bUnsubscribeOnDeletion = true + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Mail\Exceptions\RuntimeException + */ + public function FolderDelete($sFolderFullNameRaw, $bUnsubscribeOnDeletion = true) + { + if (0 === \strlen($sFolderFullNameRaw) || 'INBOX' === $sFolderFullNameRaw) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderExamine($sFolderFullNameRaw); + + $aIndexOrUids = $this->oImapClient->MessageSimpleSearch('ALL'); + if (0 < \count($aIndexOrUids)) + { + throw new \MailSo\Mail\Exceptions\NonEmptyFolder(); + } + + $this->oImapClient->FolderExamine('INBOX'); + + if ($bUnsubscribeOnDeletion) + { + $this->oImapClient->FolderUnSubscribe($sFolderFullNameRaw); + } + + $this->oImapClient->FolderDelete($sFolderFullNameRaw); + + return $this; + } + + /** + * @param string $sFolderFullNameRaw + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function FolderClear($sFolderFullNameRaw) + { + $this->oImapClient->FolderSelect($sFolderFullNameRaw); + + $oFolderInformation = $this->oImapClient->FolderCurrentInformation(); + if ($oFolderInformation && $oFolderInformation->Exists && 0 < $oFolderInformation->Exists) // STATUS? + { + $this->oImapClient->MessageStoreFlag('1:*', false, + array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), + \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT + ); + + $this->oImapClient->MessageExpunge(); + } + + return $this; + } + + /** + * @param string $sFolderFullNameRaw + * @param bool $bSubscribe + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function FolderSubscribe($sFolderFullNameRaw, $bSubscribe) + { + if (0 === \strlen($sFolderFullNameRaw)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->{($bSubscribe) ? 'FolderSubscribe' : 'FolderUnSubscribe'}($sFolderFullNameRaw); + + return $this; + } + + /** + * @param \MailSo\Log\Logger $oLogger + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function SetLogger($oLogger) + { + if (!($oLogger instanceof \MailSo\Log\Logger)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oLogger = $oLogger; + $this->oImapClient->SetLogger($this->oLogger); + + return $this; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Message.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Message.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Message.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/Message.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/MessageCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/MessageCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/MessageCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mail/MessageCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/MailSo.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/MailSo.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/MailSo.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/MailSo.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Attachment.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Attachment.php similarity index 94% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Attachment.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Attachment.php index ed1c2ace..4d15555d 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Attachment.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Attachment.php @@ -1,197 +1,197 @@ -rResource = $rResource; - $this->sFileName = $sFileName; - $this->iFileSize = $iFileSize; - $this->bIsInline = $bIsInline; - $this->bIsLinked = $bIsLinked; - $this->sCID = $sCID; - $this->aCustomContentTypeParams = $aCustomContentTypeParams; - $this->sContentLocation = $sContentLocation; - } - - /** - * @param resource $rResource - * @param string $sFileName = '' - * @param int $iFileSize = 0 - * @param bool $bIsInline = false - * @param bool $bIsLinked = false - * @param string $sCID = '' - * @param array $aCustomContentTypeParams = array() - * @param string $sContentLocation = '' - * - * @return \MailSo\Mime\Attachment - */ - public static function NewInstance($rResource, $sFileName = '', $iFileSize = 0, $bIsInline = false, - $bIsLinked = false, $sCID = '', $aCustomContentTypeParams = array(), $sContentLocation = '') - { - return new self($rResource, $sFileName, $iFileSize, $bIsInline, $bIsLinked, $sCID, $aCustomContentTypeParams, $sContentLocation); - } - - /** - * @return resource - */ - public function Resource() - { - return $this->rResource; - } - - /** - * @return string - */ - public function ContentType() - { - return \MailSo\Base\Utils::MimeContentType($this->sFileName); - } - - /** - * @return array - */ - public function CustomContentTypeParams() - { - return $this->aCustomContentTypeParams; - } - - /** - * @return string - */ - public function CID() - { - return $this->sCID; - } - - /** - * @return string - */ - public function ContentLocation() - { - return $this->sContentLocation; - } - - /** - * @return string - */ - public function FileName() - { - return $this->sFileName; - } - - /** - * @return int - */ - public function FileSize() - { - return $this->iFileSize; - } - - /** - * @return bool - */ - public function IsInline() - { - return $this->bIsInline; - } - - /** - * @return bool - */ - public function IsImage() - { - return 'image' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName()); - } - - /** - * @return bool - */ - public function IsArchive() - { - return 'archive' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName()); - } - - /** - * @return bool - */ - public function IsPdf() - { - return 'pdf' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName()); - } - - /** - * @return bool - */ - public function IsDoc() - { - return 'doc' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName()); - } - - /** - * @return bool - */ - public function IsLinked() - { - return $this->bIsLinked && 0 < \strlen($this->sCID); - } +rResource = $rResource; + $this->sFileName = $sFileName; + $this->iFileSize = $iFileSize; + $this->bIsInline = $bIsInline; + $this->bIsLinked = $bIsLinked; + $this->sCID = $sCID; + $this->aCustomContentTypeParams = $aCustomContentTypeParams; + $this->sContentLocation = $sContentLocation; + } + + /** + * @param resource $rResource + * @param string $sFileName = '' + * @param int $iFileSize = 0 + * @param bool $bIsInline = false + * @param bool $bIsLinked = false + * @param string $sCID = '' + * @param array $aCustomContentTypeParams = array() + * @param string $sContentLocation = '' + * + * @return \MailSo\Mime\Attachment + */ + public static function NewInstance($rResource, $sFileName = '', $iFileSize = 0, $bIsInline = false, + $bIsLinked = false, $sCID = '', $aCustomContentTypeParams = array(), $sContentLocation = '') + { + return new self($rResource, $sFileName, $iFileSize, $bIsInline, $bIsLinked, $sCID, $aCustomContentTypeParams, $sContentLocation); + } + + /** + * @return resource + */ + public function Resource() + { + return $this->rResource; + } + + /** + * @return string + */ + public function ContentType() + { + return \MailSo\Base\Utils::MimeContentType($this->sFileName); + } + + /** + * @return array + */ + public function CustomContentTypeParams() + { + return $this->aCustomContentTypeParams; + } + + /** + * @return string + */ + public function CID() + { + return $this->sCID; + } + + /** + * @return string + */ + public function ContentLocation() + { + return $this->sContentLocation; + } + + /** + * @return string + */ + public function FileName() + { + return $this->sFileName; + } + + /** + * @return int + */ + public function FileSize() + { + return $this->iFileSize; + } + + /** + * @return bool + */ + public function IsInline() + { + return $this->bIsInline; + } + + /** + * @return bool + */ + public function IsImage() + { + return 'image' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName()); + } + + /** + * @return bool + */ + public function IsArchive() + { + return 'archive' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName()); + } + + /** + * @return bool + */ + public function IsPdf() + { + return 'pdf' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName()); + } + + /** + * @return bool + */ + public function IsDoc() + { + return 'doc' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName()); + } + + /** + * @return bool + */ + public function IsLinked() + { + return $this->bIsLinked && 0 < \strlen($this->sCID); + } } \ No newline at end of file diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/AttachmentCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/AttachmentCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/AttachmentCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/AttachmentCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Email.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Email.php similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Email.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Email.php index 6347f0f8..9dd393f5 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Email.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Email.php @@ -1,315 +1,315 @@ -sEmail = \MailSo\Base\Utils::IdnToAscii( - \MailSo\Base\Utils::Trim($sEmail), true); - - $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName); - - $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE; - $this->sDkimValue = ''; - } - - /** - * @param string $sEmail - * @param string $sDisplayName = '' - * - * @return \MailSo\Mime\Email - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public static function NewInstance($sEmail, $sDisplayName = '') - { - return new self($sEmail, $sDisplayName); - } - - /** - * @param string $sEmailAddress - * @return \MailSo\Mime\Email - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public static function Parse($sEmailAddress) - { - $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress); - if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $sName = ''; - $sEmail = ''; - $sComment = ''; - - $bInName = false; - $bInAddress = false; - $bInComment = false; - - $iStartIndex = 0; - $iEndIndex = 0; - $iCurrentIndex = 0; - - while ($iCurrentIndex < \strlen($sEmailAddress)) - { - switch ($sEmailAddress{$iCurrentIndex}) - { -// case '\'': - case '"': -// $sQuoteChar = $sEmailAddress{$iCurrentIndex}; - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - $bInName = true; - $iStartIndex = $iCurrentIndex; - } - else if ((!$bInAddress) && (!$bInComment)) - { - $iEndIndex = $iCurrentIndex; - $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInName = false; - } - break; - case '<': - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - if ($iCurrentIndex > 0 && \strlen($sName) === 0) - { - $sName = \substr($sEmailAddress, 0, $iCurrentIndex); - } - - $bInAddress = true; - $iStartIndex = $iCurrentIndex; - } - break; - case '>': - if ($bInAddress) - { - $iEndIndex = $iCurrentIndex; - $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInAddress = false; - } - break; - case '(': - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - $bInComment = true; - $iStartIndex = $iCurrentIndex; - } - break; - case ')': - if ($bInComment) - { - $iEndIndex = $iCurrentIndex; - $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInComment = false; - } - break; - case '\\': - $iCurrentIndex++; - break; - } - - $iCurrentIndex++; - } - - if (\strlen($sEmail) === 0) - { - $aRegs = array(''); - if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0])) - { - $sEmail = $aRegs[0]; - } - else - { - $sName = $sEmailAddress; - } - } - - if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0)) - { - $sName = \str_replace($sEmail, '', $sEmailAddress); - } - - $sEmail = \trim(\trim($sEmail), '<>'); - $sEmail = \rtrim(\trim($sEmail), '.'); - $sEmail = \trim($sEmail); - - $sName = \trim(\trim($sName), '"'); - $sName = \trim($sName, '\''); - $sComment = \trim(\trim($sComment), '()'); - - // Remove backslash - $sName = \preg_replace('/\\\\(.)/s', '$1', $sName); - $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment); - - return Email::NewInstance($sEmail, $sName); - } - - /** - * @param bool $bIdn = false - * - * @return string - */ - public function GetEmail($bIdn = false) - { - return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail; - } - - /** - * @return string - */ - public function GetDisplayName() - { - return $this->sDisplayName; - } - - /** - * @return string - */ - public function GetDkimStatus() - { - return $this->sDkimStatus; - } - - /** - * @return string - */ - public function GetDkimValue() - { - return $this->sDkimValue; - } - - /** - * @return string - */ - public function GetAccountName() - { - return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false)); - } - - /** - * @param bool $bIdn = false - * - * @return string - */ - public function GetDomain($bIdn = false) - { - return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn)); - } - - /** - * @param string $sDkimStatus - * @param string $sDkimValue = '' - */ - public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '') - { - $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus); - $this->sDkimValue = $sDkimValue; - } - - /** - * @param bool $bIdn = false - * @param bool $bDkim = true - * - * @return array - */ - public function ToArray($bIdn = false, $bDkim = true) - { - return $bDkim ? - array($this->sDisplayName, $this->GetEmail($bIdn), $this->sDkimStatus, $this->sDkimValue) : - array($this->sDisplayName, $this->GetEmail($bIdn)); - } - - /** - * @param bool $bConvertSpecialsName = false - * @param bool $bIdn = false - * - * @return string - */ - public function ToString($bConvertSpecialsName = false, $bIdn = false) - { - $sReturn = ''; - - $sDisplayName = \str_replace('"', '\"', $this->sDisplayName); - if ($bConvertSpecialsName) - { - $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue( - \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, - $sDisplayName); - } - - $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"'; - if (0 < \strlen($this->sEmail)) - { - $sReturn = $this->GetEmail($bIdn); - if (0 < \strlen($sDisplayName)) - { - $sReturn = $sDisplayName.' <'.$sReturn.'>'; - } - } - - return \trim($sReturn); - } -} +sEmail = \MailSo\Base\Utils::IdnToAscii( + \MailSo\Base\Utils::Trim($sEmail), true); + + $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName); + + $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE; + $this->sDkimValue = ''; + } + + /** + * @param string $sEmail + * @param string $sDisplayName = '' + * + * @return \MailSo\Mime\Email + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public static function NewInstance($sEmail, $sDisplayName = '') + { + return new self($sEmail, $sDisplayName); + } + + /** + * @param string $sEmailAddress + * @return \MailSo\Mime\Email + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public static function Parse($sEmailAddress) + { + $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress); + if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $sName = ''; + $sEmail = ''; + $sComment = ''; + + $bInName = false; + $bInAddress = false; + $bInComment = false; + + $iStartIndex = 0; + $iEndIndex = 0; + $iCurrentIndex = 0; + + while ($iCurrentIndex < \strlen($sEmailAddress)) + { + switch ($sEmailAddress{$iCurrentIndex}) + { +// case '\'': + case '"': +// $sQuoteChar = $sEmailAddress{$iCurrentIndex}; + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + $bInName = true; + $iStartIndex = $iCurrentIndex; + } + else if ((!$bInAddress) && (!$bInComment)) + { + $iEndIndex = $iCurrentIndex; + $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInName = false; + } + break; + case '<': + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + if ($iCurrentIndex > 0 && \strlen($sName) === 0) + { + $sName = \substr($sEmailAddress, 0, $iCurrentIndex); + } + + $bInAddress = true; + $iStartIndex = $iCurrentIndex; + } + break; + case '>': + if ($bInAddress) + { + $iEndIndex = $iCurrentIndex; + $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInAddress = false; + } + break; + case '(': + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + $bInComment = true; + $iStartIndex = $iCurrentIndex; + } + break; + case ')': + if ($bInComment) + { + $iEndIndex = $iCurrentIndex; + $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInComment = false; + } + break; + case '\\': + $iCurrentIndex++; + break; + } + + $iCurrentIndex++; + } + + if (\strlen($sEmail) === 0) + { + $aRegs = array(''); + if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0])) + { + $sEmail = $aRegs[0]; + } + else + { + $sName = $sEmailAddress; + } + } + + if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0)) + { + $sName = \str_replace($sEmail, '', $sEmailAddress); + } + + $sEmail = \trim(\trim($sEmail), '<>'); + $sEmail = \rtrim(\trim($sEmail), '.'); + $sEmail = \trim($sEmail); + + $sName = \trim(\trim($sName), '"'); + $sName = \trim($sName, '\''); + $sComment = \trim(\trim($sComment), '()'); + + // Remove backslash + $sName = \preg_replace('/\\\\(.)/s', '$1', $sName); + $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment); + + return Email::NewInstance($sEmail, $sName); + } + + /** + * @param bool $bIdn = false + * + * @return string + */ + public function GetEmail($bIdn = false) + { + return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail; + } + + /** + * @return string + */ + public function GetDisplayName() + { + return $this->sDisplayName; + } + + /** + * @return string + */ + public function GetDkimStatus() + { + return $this->sDkimStatus; + } + + /** + * @return string + */ + public function GetDkimValue() + { + return $this->sDkimValue; + } + + /** + * @return string + */ + public function GetAccountName() + { + return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false)); + } + + /** + * @param bool $bIdn = false + * + * @return string + */ + public function GetDomain($bIdn = false) + { + return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn)); + } + + /** + * @param string $sDkimStatus + * @param string $sDkimValue = '' + */ + public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '') + { + $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus); + $this->sDkimValue = $sDkimValue; + } + + /** + * @param bool $bIdn = false + * @param bool $bDkim = true + * + * @return array + */ + public function ToArray($bIdn = false, $bDkim = true) + { + return $bDkim ? + array($this->sDisplayName, $this->GetEmail($bIdn), $this->sDkimStatus, $this->sDkimValue) : + array($this->sDisplayName, $this->GetEmail($bIdn)); + } + + /** + * @param bool $bConvertSpecialsName = false + * @param bool $bIdn = false + * + * @return string + */ + public function ToString($bConvertSpecialsName = false, $bIdn = false) + { + $sReturn = ''; + + $sDisplayName = \str_replace('"', '\"', $this->sDisplayName); + if ($bConvertSpecialsName) + { + $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue( + \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, + $sDisplayName); + } + + $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"'; + if (0 < \strlen($this->sEmail)) + { + $sReturn = $this->GetEmail($bIdn); + if (0 < \strlen($sDisplayName)) + { + $sReturn = $sDisplayName.' <'.$sReturn.'>'; + } + } + + return \trim($sReturn); + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/EmailCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/EmailCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/EmailCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/EmailCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/EmailDep.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/EmailDep.php similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/EmailDep.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/EmailDep.php index 7a923fae..64173bed 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/EmailDep.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/EmailDep.php @@ -1,339 +1,339 @@ -sEmail = \MailSo\Base\Utils::IdnToAscii( - \MailSo\Base\Utils::Trim($sEmail), true); - - $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName); - $this->sRemark = \MailSo\Base\Utils::Trim($sRemark); - - $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE; - $this->sDkimValue = ''; - } - - /** - * @param string $sEmail - * @param string $sDisplayName = '' - * @param string $sRemark = '' - * - * @return \MailSo\Mime\Email - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public static function NewInstance($sEmail, $sDisplayName = '', $sRemark = '') - { - return new self($sEmail, $sDisplayName, $sRemark); - } - - /** - * @param string $sEmailAddress - * @return \MailSo\Mime\Email - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public static function Parse($sEmailAddress) - { - $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress); - if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $sName = ''; - $sEmail = ''; - $sComment = ''; - - $bInName = false; - $bInAddress = false; - $bInComment = false; - - $iStartIndex = 0; - $iEndIndex = 0; - $iCurrentIndex = 0; - - while ($iCurrentIndex < \strlen($sEmailAddress)) - { - switch ($sEmailAddress{$iCurrentIndex}) - { -// case '\'': - case '"': -// $sQuoteChar = $sEmailAddress{$iCurrentIndex}; - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - $bInName = true; - $iStartIndex = $iCurrentIndex; - } - else if ((!$bInAddress) && (!$bInComment)) - { - $iEndIndex = $iCurrentIndex; - $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInName = false; - } - break; - case '<': - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - if ($iCurrentIndex > 0 && \strlen($sName) === 0) - { - $sName = \substr($sEmailAddress, 0, $iCurrentIndex); - } - - $bInAddress = true; - $iStartIndex = $iCurrentIndex; - } - break; - case '>': - if ($bInAddress) - { - $iEndIndex = $iCurrentIndex; - $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInAddress = false; - } - break; - case '(': - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - $bInComment = true; - $iStartIndex = $iCurrentIndex; - } - break; - case ')': - if ($bInComment) - { - $iEndIndex = $iCurrentIndex; - $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInComment = false; - } - break; - case '\\': - $iCurrentIndex++; - break; - } - - $iCurrentIndex++; - } - - if (\strlen($sEmail) === 0) - { - $aRegs = array(''); - if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0])) - { - $sEmail = $aRegs[0]; - } - else - { - $sName = $sEmailAddress; - } - } - - if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0)) - { - $sName = \str_replace($sEmail, '', $sEmailAddress); - } - - $sEmail = \trim(\trim($sEmail), '<>'); - $sEmail = \rtrim(\trim($sEmail), '.'); - $sEmail = \trim($sEmail); - - $sName = \trim(\trim($sName), '"'); - $sName = \trim($sName, '\''); - $sComment = \trim(\trim($sComment), '()'); - - // Remove backslash - $sName = \preg_replace('/\\\\(.)/s', '$1', $sName); - $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment); - - return Email::NewInstance($sEmail, $sName, $sComment); - } - - /** - * @param bool $bIdn = false - * - * @return string - */ - public function GetEmail($bIdn = false) - { - return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail; - } - - /** - * @return string - */ - public function GetDisplayName() - { - return $this->sDisplayName; - } - - /** - * @return string - */ - public function GetRemark() - { - return $this->sRemark; - } - - /** - * @return string - */ - public function GetDkimStatus() - { - return $this->sDkimStatus; - } - - /** - * @return string - */ - public function GetDkimValue() - { - return $this->sDkimValue; - } - - /** - * @return string - */ - public function GetAccountName() - { - return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false)); - } - - /** - * @param bool $bIdn = false - * - * @return string - */ - public function GetDomain($bIdn = false) - { - return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn)); - } - - /** - * @param string $sDkimStatus - * @param string $sDkimValue = '' - */ - public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '') - { - $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus); - $this->sDkimValue = $sDkimValue; - } - - /** - * @param bool $bIdn = false - * @param bool $bDkim = true - * - * @return array - */ - public function ToArray($bIdn = false, $bDkim = true) - { - return $bDkim ? array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark, $this->sDkimStatus, $this->sDkimValue) : - array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark); - } - - /** - * @param bool $bConvertSpecialsName = false - * @param bool $bIdn = false - * - * @return string - */ - public function ToString($bConvertSpecialsName = false, $bIdn = false) - { - $sReturn = ''; - - $sRemark = \str_replace(')', '\)', $this->sRemark); - $sDisplayName = \str_replace('"', '\"', $this->sDisplayName); - - if ($bConvertSpecialsName) - { - $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue( - \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, - $sDisplayName); - - $sRemark = 0 === \strlen($sRemark) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue( - \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, - $sRemark); - } - - $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"'; - $sRemark = 0 === \strlen($sRemark) ? '' : '('.$sRemark.')'; - - if (0 < \strlen($this->sEmail)) - { - $sReturn = $this->GetEmail($bIdn); - if (0 < \strlen($sDisplayName.$sRemark)) - { - $sReturn = $sDisplayName.' <'.$sReturn.'> '.$sRemark; - } - } - - return \trim($sReturn); - } -} +sEmail = \MailSo\Base\Utils::IdnToAscii( + \MailSo\Base\Utils::Trim($sEmail), true); + + $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName); + $this->sRemark = \MailSo\Base\Utils::Trim($sRemark); + + $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE; + $this->sDkimValue = ''; + } + + /** + * @param string $sEmail + * @param string $sDisplayName = '' + * @param string $sRemark = '' + * + * @return \MailSo\Mime\Email + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public static function NewInstance($sEmail, $sDisplayName = '', $sRemark = '') + { + return new self($sEmail, $sDisplayName, $sRemark); + } + + /** + * @param string $sEmailAddress + * @return \MailSo\Mime\Email + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public static function Parse($sEmailAddress) + { + $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress); + if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $sName = ''; + $sEmail = ''; + $sComment = ''; + + $bInName = false; + $bInAddress = false; + $bInComment = false; + + $iStartIndex = 0; + $iEndIndex = 0; + $iCurrentIndex = 0; + + while ($iCurrentIndex < \strlen($sEmailAddress)) + { + switch ($sEmailAddress{$iCurrentIndex}) + { +// case '\'': + case '"': +// $sQuoteChar = $sEmailAddress{$iCurrentIndex}; + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + $bInName = true; + $iStartIndex = $iCurrentIndex; + } + else if ((!$bInAddress) && (!$bInComment)) + { + $iEndIndex = $iCurrentIndex; + $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInName = false; + } + break; + case '<': + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + if ($iCurrentIndex > 0 && \strlen($sName) === 0) + { + $sName = \substr($sEmailAddress, 0, $iCurrentIndex); + } + + $bInAddress = true; + $iStartIndex = $iCurrentIndex; + } + break; + case '>': + if ($bInAddress) + { + $iEndIndex = $iCurrentIndex; + $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInAddress = false; + } + break; + case '(': + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + $bInComment = true; + $iStartIndex = $iCurrentIndex; + } + break; + case ')': + if ($bInComment) + { + $iEndIndex = $iCurrentIndex; + $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInComment = false; + } + break; + case '\\': + $iCurrentIndex++; + break; + } + + $iCurrentIndex++; + } + + if (\strlen($sEmail) === 0) + { + $aRegs = array(''); + if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0])) + { + $sEmail = $aRegs[0]; + } + else + { + $sName = $sEmailAddress; + } + } + + if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0)) + { + $sName = \str_replace($sEmail, '', $sEmailAddress); + } + + $sEmail = \trim(\trim($sEmail), '<>'); + $sEmail = \rtrim(\trim($sEmail), '.'); + $sEmail = \trim($sEmail); + + $sName = \trim(\trim($sName), '"'); + $sName = \trim($sName, '\''); + $sComment = \trim(\trim($sComment), '()'); + + // Remove backslash + $sName = \preg_replace('/\\\\(.)/s', '$1', $sName); + $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment); + + return Email::NewInstance($sEmail, $sName, $sComment); + } + + /** + * @param bool $bIdn = false + * + * @return string + */ + public function GetEmail($bIdn = false) + { + return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail; + } + + /** + * @return string + */ + public function GetDisplayName() + { + return $this->sDisplayName; + } + + /** + * @return string + */ + public function GetRemark() + { + return $this->sRemark; + } + + /** + * @return string + */ + public function GetDkimStatus() + { + return $this->sDkimStatus; + } + + /** + * @return string + */ + public function GetDkimValue() + { + return $this->sDkimValue; + } + + /** + * @return string + */ + public function GetAccountName() + { + return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false)); + } + + /** + * @param bool $bIdn = false + * + * @return string + */ + public function GetDomain($bIdn = false) + { + return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn)); + } + + /** + * @param string $sDkimStatus + * @param string $sDkimValue = '' + */ + public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '') + { + $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus); + $this->sDkimValue = $sDkimValue; + } + + /** + * @param bool $bIdn = false + * @param bool $bDkim = true + * + * @return array + */ + public function ToArray($bIdn = false, $bDkim = true) + { + return $bDkim ? array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark, $this->sDkimStatus, $this->sDkimValue) : + array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark); + } + + /** + * @param bool $bConvertSpecialsName = false + * @param bool $bIdn = false + * + * @return string + */ + public function ToString($bConvertSpecialsName = false, $bIdn = false) + { + $sReturn = ''; + + $sRemark = \str_replace(')', '\)', $this->sRemark); + $sDisplayName = \str_replace('"', '\"', $this->sDisplayName); + + if ($bConvertSpecialsName) + { + $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue( + \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, + $sDisplayName); + + $sRemark = 0 === \strlen($sRemark) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue( + \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, + $sRemark); + } + + $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"'; + $sRemark = 0 === \strlen($sRemark) ? '' : '('.$sRemark.')'; + + if (0 < \strlen($this->sEmail)) + { + $sReturn = $this->GetEmail($bIdn); + if (0 < \strlen($sDisplayName.$sRemark)) + { + $sReturn = $sDisplayName.' <'.$sReturn.'> '.$sRemark; + } + } + + return \trim($sReturn); + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Enumerations/Constants.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Enumerations/Constants.php similarity index 94% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Enumerations/Constants.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Enumerations/Constants.php index 41da5818..7f52ee89 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Enumerations/Constants.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Enumerations/Constants.php @@ -1,25 +1,25 @@ -sRawHeaders = ''; - $this->sParentCharset = ''; - - if (0 < \strlen($sRawHeaders)) - { - $this->Parse($sRawHeaders, $bStoreRawHeaders); - } - } - - /** - * @param string $sRawHeaders = '' - * @param bool $bStoreRawHeaders = true - * - * @return \MailSo\Mime\HeaderCollection - */ - public static function NewInstance($sRawHeaders = '', $bStoreRawHeaders = true) - { - return new self($sRawHeaders, $bStoreRawHeaders); - } - - /** - * @param string $sName - * @param string $sValue - * @param bool $bToTop = false - * - * @return \MailSo\Mime\HeaderCollection - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function AddByName($sName, $sValue, $bToTop = false) - { - return $this->Add(Header::NewInstance($sName, $sValue), $bToTop); - } - - /** - * @param string $sName - * @param string $sValue - * @param bool $bToTop = false - * - * @return \MailSo\Mime\HeaderCollection - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function SetByName($sName, $sValue, $bToTop = false) - { - return $this->RemoveByName($sName)->Add(Header::NewInstance($sName, $sValue), $bToTop); - } - - /** - * @return \MailSo\Mime\Header | null - */ - public function &GetByIndex($iIndex) - { - $mResult = null; - $mResult =& parent::GetByIndex($iIndex); - return $mResult; - } - - /** - * @param string $sHeaderName - * @param bool $bCharsetAutoDetect = false - * @return string - */ - public function ValueByName($sHeaderName, $bCharsetAutoDetect = false) - { - $oHeader = null; - $oHeader =& $this->GetByName($sHeaderName); - return (null !== $oHeader) ? ($bCharsetAutoDetect ? $oHeader->ValueWithCharsetAutoDetect() : $oHeader->Value()) : ''; - } - - /** - * @param string $sHeaderName - * @param bool $bCharsetAutoDetect = false - * @return array - */ - public function ValuesByName($sHeaderName, $bCharsetAutoDetect = false) - { - $aResult = array(); - $oHeader = null; - - $sHeaderNameLower = \strtolower($sHeaderName); - $aHeaders =& $this->GetAsArray(); - foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader) - { - if ($sHeaderNameLower === \strtolower($oHeader->Name())) - { - $aResult[] = $bCharsetAutoDetect ? $oHeader->ValueWithCharsetAutoDetect() : $oHeader->Value(); - } - } - - return $aResult; - } - - /** - * @param string $sHeaderName - * - * @return \MailSo\Mime\HeaderCollection - */ - public function RemoveByName($sHeaderName) - { - $aResult = $this->FilterList(function ($oHeader) use ($sHeaderName) { - return $oHeader && \strtolower($oHeader->Name()) !== \strtolower($sHeaderName); - }); - - return $this->SetAsArray($aResult); - } - - /** - * @param string $sHeaderName - * @param bool $bCharsetAutoDetect = false - * - * @return \MailSo\Mime\EmailCollection|null - */ - public function GetAsEmailCollection($sHeaderName, $bCharsetAutoDetect = false) - { - $oResult = null; - $sValue = $this->ValueByName($sHeaderName, $bCharsetAutoDetect); - if (0 < \strlen($sValue)) - { - $oResult = \MailSo\Mime\EmailCollection::NewInstance($sValue); - } - - return $oResult && 0 < $oResult->Count() ? $oResult : null; - } - - /** - * @param string $sHeaderName - * @return \MailSo\Mime\ParameterCollection|null - */ - public function ParametersByName($sHeaderName) - { - $oParameters = $oHeader = null; - $oHeader =& $this->GetByName($sHeaderName); - if ($oHeader) - { - $oParameters = $oHeader->Parameters(); - } - - return $oParameters; - } - - /** - * @param string $sHeaderName - * @param string $sParamName - * @return string - */ - public function ParameterValue($sHeaderName, $sParamName) - { - $oParameters = $this->ParametersByName($sHeaderName); - return (null !== $oParameters) ? $oParameters->ParameterValueByName($sParamName) : ''; - } - - /** - * @param string $sHeaderName - * @return \MailSo\Mime\Header | false - */ - public function &GetByName($sHeaderName) - { - $oResult = $oHeader = null; - - $sHeaderNameLower = \strtolower($sHeaderName); - $aHeaders =& $this->GetAsArray(); - foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader) - { - if ($sHeaderNameLower === \strtolower($oHeader->Name())) - { - $oResult =& $oHeader; - break; - } - } - - return $oResult; - } - - /** - * @param array $aList - * @return \MailSo\Mime\HeaderCollection - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function SetAsArray($aList) - { - parent::SetAsArray($aList); - - return $this; - } - - /** - * @param string $sParentCharset - * @return \MailSo\Mime\HeaderCollection - */ - public function SetParentCharset($sParentCharset) - { - if (0 < \strlen($sParentCharset)) - { - if ($this->sParentCharset !== $sParentCharset) - { - $oHeader = null; - $aHeaders =& $this->GetAsArray(); - - foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader) - { - $oHeader->SetParentCharset($sParentCharset); - } - - $this->sParentCharset = $sParentCharset; - } - } - - return $this; - } - - /** - * @return void - */ - public function Clear() - { - parent::Clear(); - - $this->sRawHeaders = ''; - } - - /** - * @param string $sRawHeaders - * @param bool $bStoreRawHeaders = false - * @param string $sParentCharset = '' - * - * @return \MailSo\Mime\HeaderCollection - */ - public function Parse($sRawHeaders, $bStoreRawHeaders = false, $sParentCharset = '') - { - $this->Clear(); - - if ($bStoreRawHeaders) - { - $this->sRawHeaders = $sRawHeaders; - } - - if (0 === \strlen($this->sParentCharset)) - { - $this->sParentCharset = $sParentCharset; - } - - $aHeaders = \explode("\n", \str_replace("\r", '', $sRawHeaders)); - - $sName = null; - $sValue = null; - foreach ($aHeaders as $sHeadersValue) - { - if (0 === strlen($sHeadersValue)) - { - continue; - } - - $sFirstChar = \substr($sHeadersValue, 0, 1); - if ($sFirstChar !== ' ' && $sFirstChar !== "\t" && false === \strpos($sHeadersValue, ':')) - { - continue; - } - else if (null !== $sName && ($sFirstChar === ' ' || $sFirstChar === "\t")) - { - $sValue = \is_null($sValue) ? '' : $sValue; - - if ('?=' === \substr(\rtrim($sHeadersValue), -2)) - { - $sHeadersValue = \rtrim($sHeadersValue); - } - - if ('=?' === \substr(\ltrim($sHeadersValue), 0, 2)) - { - $sHeadersValue = \ltrim($sHeadersValue); - } - - if ('=?' === \substr($sHeadersValue, 0, 2)) - { - $sValue .= $sHeadersValue; - } - else - { - $sValue .= "\n".$sHeadersValue; - } - } - else - { - if (null !== $sName) - { - $oHeader = Header::NewInstanceFromEncodedString($sName.': '.$sValue, $this->sParentCharset); - if ($oHeader) - { - $this->Add($oHeader); - } - - $sName = null; - $sValue = null; - } - - $aHeaderParts = \explode(':', $sHeadersValue, 2); - $sName = $aHeaderParts[0]; - $sValue = isset($aHeaderParts[1]) ? $aHeaderParts[1] : ''; - - if ('?=' === \substr(\rtrim($sValue), -2)) - { - $sValue = \rtrim($sValue); - } - } - } - - if (null !== $sName) - { - $oHeader = Header::NewInstanceFromEncodedString($sName.': '.$sValue, $this->sParentCharset); - if ($oHeader) - { - $this->Add($oHeader); - } - } - - return $this; - } - - /** - * @return int - */ - public function DkimStatuses() - { - $aResult = array(); - - $aHeaders = $this->ValuesByName(\MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS); - if (\is_array($aHeaders) && 0 < \count($aHeaders)) - { - foreach ($aHeaders as $sHeaderValue) - { - $sStatus = ''; - $sHeader = ''; - $sDkimLine = ''; - - $aMatch = array(); - - $sHeaderValue = \preg_replace('/[\r\n\t\s]+/', ' ', $sHeaderValue); - - if (\preg_match('/dkim=.+/i', $sHeaderValue, $aMatch) && !empty($aMatch[0])) - { - $sDkimLine = $aMatch[0]; - - $aMatch = array(); - if (\preg_match('/dkim=([a-zA-Z0-9]+)/i', $sDkimLine, $aMatch) && !empty($aMatch[1])) - { - $sStatus = $aMatch[1]; - } - - $aMatch = array(); - if (\preg_match('/header\.(d|i|from)=([^\s;]+)/i', $sDkimLine, $aMatch) && !empty($aMatch[2])) - { - $sHeader = \trim($aMatch[2]); - } - - if (!empty($sStatus) && !empty($sHeader)) - { - $aResult[] = array($sStatus, $sHeader, $sDkimLine); - } - } - } - } - else - { - // X-DKIM-Authentication-Results: signer="hostinger.com" status="pass" - $aHeaders = $this->ValuesByName(\MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS); - if (\is_array($aHeaders) && 0 < \count($aHeaders)) - { - foreach ($aHeaders as $sHeaderValue) - { - $sStatus = ''; - $sHeader = ''; - - $aMatch = array(); - - $sHeaderValue = \preg_replace('/[\r\n\t\s]+/', ' ', $sHeaderValue); - - if (\preg_match('/status[\s]?=[\s]?"([a-zA-Z0-9]+)"/i', $sHeaderValue, $aMatch) && !empty($aMatch[1])) - { - $sStatus = $aMatch[1]; - } - - if (\preg_match('/signer[\s]?=[\s]?"([^";]+)"/i', $sHeaderValue, $aMatch) && !empty($aMatch[1])) - { - $sHeader = \trim($aMatch[1]); - } - - if (!empty($sStatus) && !empty($sHeader)) - { - $aResult[] = array($sStatus, $sHeader, $sHeaderValue); - } - } - } - } - - return $aResult; - } - - /** - * @return int - */ - public function PopulateEmailColectionByDkim($oEmails) - { - if ($oEmails && $oEmails instanceof \MailSo\Mime\EmailCollection) - { - $aDkimStatuses = $this->DkimStatuses(); - if (\is_array($aDkimStatuses) && 0 < \count($aDkimStatuses)) - { - $oEmails->ForeachList(function (/* @var $oItem \MailSo\Mime\Email */ $oItem) use ($aDkimStatuses) { - if ($oItem && $oItem instanceof \MailSo\Mime\Email) - { - $sEmail = $oItem->GetEmail(); - foreach ($aDkimStatuses as $aDkimData) - { - if (isset($aDkimData[0], $aDkimData[1]) && - $aDkimData[1] === \strstr($sEmail, $aDkimData[1])) - { - $oItem->SetDkimStatusAndValue($aDkimData[0], empty($aDkimData[2]) ? '' : $aDkimData[2]); - } - } - } - }); - } - } - } - - /** - * @return string - */ - public function ToEncodedString() - { - $aResult = array(); - $aHeaders =& $this->GetAsArray(); - foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader) - { - $aResult[] = $oHeader->EncodedValue(); - } - - return \implode(\MailSo\Mime\Enumerations\Constants::CRLF, $aResult); - } -} +sRawHeaders = ''; + $this->sParentCharset = ''; + + if (0 < \strlen($sRawHeaders)) + { + $this->Parse($sRawHeaders, $bStoreRawHeaders); + } + } + + /** + * @param string $sRawHeaders = '' + * @param bool $bStoreRawHeaders = true + * + * @return \MailSo\Mime\HeaderCollection + */ + public static function NewInstance($sRawHeaders = '', $bStoreRawHeaders = true) + { + return new self($sRawHeaders, $bStoreRawHeaders); + } + + /** + * @param string $sName + * @param string $sValue + * @param bool $bToTop = false + * + * @return \MailSo\Mime\HeaderCollection + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function AddByName($sName, $sValue, $bToTop = false) + { + return $this->Add(Header::NewInstance($sName, $sValue), $bToTop); + } + + /** + * @param string $sName + * @param string $sValue + * @param bool $bToTop = false + * + * @return \MailSo\Mime\HeaderCollection + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function SetByName($sName, $sValue, $bToTop = false) + { + return $this->RemoveByName($sName)->Add(Header::NewInstance($sName, $sValue), $bToTop); + } + + /** + * @return \MailSo\Mime\Header | null + */ + public function &GetByIndex($iIndex) + { + $mResult = null; + $mResult =& parent::GetByIndex($iIndex); + return $mResult; + } + + /** + * @param string $sHeaderName + * @param bool $bCharsetAutoDetect = false + * @return string + */ + public function ValueByName($sHeaderName, $bCharsetAutoDetect = false) + { + $oHeader = null; + $oHeader =& $this->GetByName($sHeaderName); + return (null !== $oHeader) ? ($bCharsetAutoDetect ? $oHeader->ValueWithCharsetAutoDetect() : $oHeader->Value()) : ''; + } + + /** + * @param string $sHeaderName + * @param bool $bCharsetAutoDetect = false + * @return array + */ + public function ValuesByName($sHeaderName, $bCharsetAutoDetect = false) + { + $aResult = array(); + $oHeader = null; + + $sHeaderNameLower = \strtolower($sHeaderName); + $aHeaders =& $this->GetAsArray(); + foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader) + { + if ($sHeaderNameLower === \strtolower($oHeader->Name())) + { + $aResult[] = $bCharsetAutoDetect ? $oHeader->ValueWithCharsetAutoDetect() : $oHeader->Value(); + } + } + + return $aResult; + } + + /** + * @param string $sHeaderName + * + * @return \MailSo\Mime\HeaderCollection + */ + public function RemoveByName($sHeaderName) + { + $aResult = $this->FilterList(function ($oHeader) use ($sHeaderName) { + return $oHeader && \strtolower($oHeader->Name()) !== \strtolower($sHeaderName); + }); + + return $this->SetAsArray($aResult); + } + + /** + * @param string $sHeaderName + * @param bool $bCharsetAutoDetect = false + * + * @return \MailSo\Mime\EmailCollection|null + */ + public function GetAsEmailCollection($sHeaderName, $bCharsetAutoDetect = false) + { + $oResult = null; + $sValue = $this->ValueByName($sHeaderName, $bCharsetAutoDetect); + if (0 < \strlen($sValue)) + { + $oResult = \MailSo\Mime\EmailCollection::NewInstance($sValue); + } + + return $oResult && 0 < $oResult->Count() ? $oResult : null; + } + + /** + * @param string $sHeaderName + * @return \MailSo\Mime\ParameterCollection|null + */ + public function ParametersByName($sHeaderName) + { + $oParameters = $oHeader = null; + $oHeader =& $this->GetByName($sHeaderName); + if ($oHeader) + { + $oParameters = $oHeader->Parameters(); + } + + return $oParameters; + } + + /** + * @param string $sHeaderName + * @param string $sParamName + * @return string + */ + public function ParameterValue($sHeaderName, $sParamName) + { + $oParameters = $this->ParametersByName($sHeaderName); + return (null !== $oParameters) ? $oParameters->ParameterValueByName($sParamName) : ''; + } + + /** + * @param string $sHeaderName + * @return \MailSo\Mime\Header | false + */ + public function &GetByName($sHeaderName) + { + $oResult = $oHeader = null; + + $sHeaderNameLower = \strtolower($sHeaderName); + $aHeaders =& $this->GetAsArray(); + foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader) + { + if ($sHeaderNameLower === \strtolower($oHeader->Name())) + { + $oResult =& $oHeader; + break; + } + } + + return $oResult; + } + + /** + * @param array $aList + * @return \MailSo\Mime\HeaderCollection + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function SetAsArray($aList) + { + parent::SetAsArray($aList); + + return $this; + } + + /** + * @param string $sParentCharset + * @return \MailSo\Mime\HeaderCollection + */ + public function SetParentCharset($sParentCharset) + { + if (0 < \strlen($sParentCharset)) + { + if ($this->sParentCharset !== $sParentCharset) + { + $oHeader = null; + $aHeaders =& $this->GetAsArray(); + + foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader) + { + $oHeader->SetParentCharset($sParentCharset); + } + + $this->sParentCharset = $sParentCharset; + } + } + + return $this; + } + + /** + * @return void + */ + public function Clear() + { + parent::Clear(); + + $this->sRawHeaders = ''; + } + + /** + * @param string $sRawHeaders + * @param bool $bStoreRawHeaders = false + * @param string $sParentCharset = '' + * + * @return \MailSo\Mime\HeaderCollection + */ + public function Parse($sRawHeaders, $bStoreRawHeaders = false, $sParentCharset = '') + { + $this->Clear(); + + if ($bStoreRawHeaders) + { + $this->sRawHeaders = $sRawHeaders; + } + + if (0 === \strlen($this->sParentCharset)) + { + $this->sParentCharset = $sParentCharset; + } + + $aHeaders = \explode("\n", \str_replace("\r", '', $sRawHeaders)); + + $sName = null; + $sValue = null; + foreach ($aHeaders as $sHeadersValue) + { + if (0 === strlen($sHeadersValue)) + { + continue; + } + + $sFirstChar = \substr($sHeadersValue, 0, 1); + if ($sFirstChar !== ' ' && $sFirstChar !== "\t" && false === \strpos($sHeadersValue, ':')) + { + continue; + } + else if (null !== $sName && ($sFirstChar === ' ' || $sFirstChar === "\t")) + { + $sValue = \is_null($sValue) ? '' : $sValue; + + if ('?=' === \substr(\rtrim($sHeadersValue), -2)) + { + $sHeadersValue = \rtrim($sHeadersValue); + } + + if ('=?' === \substr(\ltrim($sHeadersValue), 0, 2)) + { + $sHeadersValue = \ltrim($sHeadersValue); + } + + if ('=?' === \substr($sHeadersValue, 0, 2)) + { + $sValue .= $sHeadersValue; + } + else + { + $sValue .= "\n".$sHeadersValue; + } + } + else + { + if (null !== $sName) + { + $oHeader = Header::NewInstanceFromEncodedString($sName.': '.$sValue, $this->sParentCharset); + if ($oHeader) + { + $this->Add($oHeader); + } + + $sName = null; + $sValue = null; + } + + $aHeaderParts = \explode(':', $sHeadersValue, 2); + $sName = $aHeaderParts[0]; + $sValue = isset($aHeaderParts[1]) ? $aHeaderParts[1] : ''; + + if ('?=' === \substr(\rtrim($sValue), -2)) + { + $sValue = \rtrim($sValue); + } + } + } + + if (null !== $sName) + { + $oHeader = Header::NewInstanceFromEncodedString($sName.': '.$sValue, $this->sParentCharset); + if ($oHeader) + { + $this->Add($oHeader); + } + } + + return $this; + } + + /** + * @return int + */ + public function DkimStatuses() + { + $aResult = array(); + + $aHeaders = $this->ValuesByName(\MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS); + if (\is_array($aHeaders) && 0 < \count($aHeaders)) + { + foreach ($aHeaders as $sHeaderValue) + { + $sStatus = ''; + $sHeader = ''; + $sDkimLine = ''; + + $aMatch = array(); + + $sHeaderValue = \preg_replace('/[\r\n\t\s]+/', ' ', $sHeaderValue); + + if (\preg_match('/dkim=.+/i', $sHeaderValue, $aMatch) && !empty($aMatch[0])) + { + $sDkimLine = $aMatch[0]; + + $aMatch = array(); + if (\preg_match('/dkim=([a-zA-Z0-9]+)/i', $sDkimLine, $aMatch) && !empty($aMatch[1])) + { + $sStatus = $aMatch[1]; + } + + $aMatch = array(); + if (\preg_match('/header\.(d|i|from)=([^\s;]+)/i', $sDkimLine, $aMatch) && !empty($aMatch[2])) + { + $sHeader = \trim($aMatch[2]); + } + + if (!empty($sStatus) && !empty($sHeader)) + { + $aResult[] = array($sStatus, $sHeader, $sDkimLine); + } + } + } + } + else + { + // X-DKIM-Authentication-Results: signer="hostinger.com" status="pass" + $aHeaders = $this->ValuesByName(\MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS); + if (\is_array($aHeaders) && 0 < \count($aHeaders)) + { + foreach ($aHeaders as $sHeaderValue) + { + $sStatus = ''; + $sHeader = ''; + + $aMatch = array(); + + $sHeaderValue = \preg_replace('/[\r\n\t\s]+/', ' ', $sHeaderValue); + + if (\preg_match('/status[\s]?=[\s]?"([a-zA-Z0-9]+)"/i', $sHeaderValue, $aMatch) && !empty($aMatch[1])) + { + $sStatus = $aMatch[1]; + } + + if (\preg_match('/signer[\s]?=[\s]?"([^";]+)"/i', $sHeaderValue, $aMatch) && !empty($aMatch[1])) + { + $sHeader = \trim($aMatch[1]); + } + + if (!empty($sStatus) && !empty($sHeader)) + { + $aResult[] = array($sStatus, $sHeader, $sHeaderValue); + } + } + } + } + + return $aResult; + } + + /** + * @return int + */ + public function PopulateEmailColectionByDkim($oEmails) + { + if ($oEmails && $oEmails instanceof \MailSo\Mime\EmailCollection) + { + $aDkimStatuses = $this->DkimStatuses(); + if (\is_array($aDkimStatuses) && 0 < \count($aDkimStatuses)) + { + $oEmails->ForeachList(function (/* @var $oItem \MailSo\Mime\Email */ $oItem) use ($aDkimStatuses) { + if ($oItem && $oItem instanceof \MailSo\Mime\Email) + { + $sEmail = $oItem->GetEmail(); + foreach ($aDkimStatuses as $aDkimData) + { + if (isset($aDkimData[0], $aDkimData[1]) && + $aDkimData[1] === \strstr($sEmail, $aDkimData[1])) + { + $oItem->SetDkimStatusAndValue($aDkimData[0], empty($aDkimData[2]) ? '' : $aDkimData[2]); + } + } + } + }); + } + } + } + + /** + * @return string + */ + public function ToEncodedString() + { + $aResult = array(); + $aHeaders =& $this->GetAsArray(); + foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader) + { + $aResult[] = $oHeader->EncodedValue(); + } + + return \implode(\MailSo\Mime\Enumerations\Constants::CRLF, $aResult); + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Message.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Message.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Message.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Message.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parameter.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Parameter.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parameter.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Parameter.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/ParameterCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/ParameterCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/ParameterCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/ParameterCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserEmpty.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Parser/ParserEmpty.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserEmpty.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Parser/ParserEmpty.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Parser/ParserInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Parser/ParserInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserMemory.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Parser/ParserMemory.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserMemory.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Parser/ParserMemory.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Part.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Part.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Part.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/Part.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/PartCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/PartCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/PartCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Mime/PartCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/ConnectionException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/ConnectionException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/ConnectionException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/ConnectionException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/Exception.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/Exception.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/Exception.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/InvalidArgumentException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/InvalidArgumentException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/InvalidArgumentException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/InvalidArgumentException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketAlreadyConnectedException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketAlreadyConnectedException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketAlreadyConnectedException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketAlreadyConnectedException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketCanNotConnectToHostException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketCanNotConnectToHostException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketCanNotConnectToHostException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketCanNotConnectToHostException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketConnectionDoesNotAvailableException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketConnectionDoesNotAvailableException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketConnectionDoesNotAvailableException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketConnectionDoesNotAvailableException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketReadException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketReadException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketReadException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketReadException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketReadTimeoutException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketReadTimeoutException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketReadTimeoutException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketReadTimeoutException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketUnreadBufferException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketUnreadBufferException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketUnreadBufferException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketUnreadBufferException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketUnsuppoterdSecureConnectionException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketUnsuppoterdSecureConnectionException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketUnsuppoterdSecureConnectionException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketUnsuppoterdSecureConnectionException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketWriteException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketWriteException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketWriteException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/Exceptions/SocketWriteException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/NetClient.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/NetClient.php similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/NetClient.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/NetClient.php index 5fffbbf9..dfc9d273 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/NetClient.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Net/NetClient.php @@ -196,6 +196,7 @@ public function capturePhpErrorWithException($iErrNo, $sErrStr, $sErrFile, $iErr * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT * @param bool $bVerifySsl = false * @param bool $bAllowSelfSigned = true + * @param string $sClientCert = '' * * @return void * @@ -205,7 +206,8 @@ public function capturePhpErrorWithException($iErrNo, $sErrStr, $sErrFile, $iErr */ public function Connect($sServerName, $iPort, $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, - $bVerifySsl = false, $bAllowSelfSigned = true) + $bVerifySsl = false, $bAllowSelfSigned = true, + $sClientCert = '') { if (!\MailSo\Base\Validator::NotEmptyString($sServerName, true) || !\MailSo\Base\Validator::PortInt($iPort)) { @@ -254,7 +256,6 @@ public function Connect($sServerName, $iPort, $bVerifySsl = !!$bVerifySsl; $bAllowSelfSigned = $bVerifySsl ? !!$bAllowSelfSigned : true; - $aStreamContextSettings = array( 'ssl' => array( 'verify_host' => $bVerifySsl, @@ -264,6 +265,11 @@ public function Connect($sServerName, $iPort, ) ); + if (!empty($sClientCert)) + { + $aStreamContextSettings['ssl']['local_cert'] = $sClientCert; + } + \MailSo\Hooks::Run('Net.NetClient.StreamContextSettings/Filter', array(&$aStreamContextSettings)); $rStreamContext = \stream_context_create($aStreamContextSettings); @@ -317,8 +323,10 @@ public function EnableCrypto() { case defined('STREAM_CRYPTO_METHOD_ANY_CLIENT') && @\stream_socket_enable_crypto($this->rConnect, true, STREAM_CRYPTO_METHOD_ANY_CLIENT): - case @\stream_socket_enable_crypto($this->rConnect, true, STREAM_CRYPTO_METHOD_TLS_CLIENT): - case @\stream_socket_enable_crypto($this->rConnect, true, STREAM_CRYPTO_METHOD_SSLv23_CLIENT): + case defined('STREAM_CRYPTO_METHOD_TLS_CLIENT') && + @\stream_socket_enable_crypto($this->rConnect, true, STREAM_CRYPTO_METHOD_TLS_CLIENT): + case defined('STREAM_CRYPTO_METHOD_SSLv23_CLIENT') && + @\stream_socket_enable_crypto($this->rConnect, true, STREAM_CRYPTO_METHOD_SSLv23_CLIENT): $bError = false; break; } diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Exceptions/Exception.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/Exception.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Exceptions/Exception.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/LoginBadCredentialsException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Exceptions/LoginBadCredentialsException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/LoginBadCredentialsException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Exceptions/LoginBadCredentialsException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/NegativeResponseException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Exceptions/NegativeResponseException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/NegativeResponseException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Exceptions/NegativeResponseException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/ResponseException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Exceptions/ResponseException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/ResponseException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Exceptions/ResponseException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/RuntimeException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Exceptions/RuntimeException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/RuntimeException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Exceptions/RuntimeException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Pop3Client.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Pop3Client.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Pop3Client.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Pop3/Pop3Client.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/Exceptions/Exception.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/Exception.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/Exceptions/Exception.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/LoginBadCredentialsException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/Exceptions/LoginBadCredentialsException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/LoginBadCredentialsException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/Exceptions/LoginBadCredentialsException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/NegativeResponseException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/Exceptions/NegativeResponseException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/NegativeResponseException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/Exceptions/NegativeResponseException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/ResponseException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/Exceptions/ResponseException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/ResponseException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/Exceptions/ResponseException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/RuntimeException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/Exceptions/RuntimeException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/RuntimeException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/Exceptions/RuntimeException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/PoppassdClient.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/PoppassdClient.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/PoppassdClient.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Poppassd/PoppassdClient.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/Exception.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/Exception.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/Exception.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginBadCredentialsException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/LoginBadCredentialsException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginBadCredentialsException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/LoginBadCredentialsException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginBadMethodException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/LoginBadMethodException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginBadMethodException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/LoginBadMethodException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/LoginException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/LoginException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/NegativeResponseException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/NegativeResponseException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/NegativeResponseException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/NegativeResponseException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/ResponseException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/ResponseException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/ResponseException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/ResponseException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/RuntimeException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/RuntimeException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/RuntimeException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/Exceptions/RuntimeException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/ManageSieveClient.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/ManageSieveClient.php similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/ManageSieveClient.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/ManageSieveClient.php index 77dd400f..cd4e1798 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/ManageSieveClient.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Sieve/ManageSieveClient.php @@ -1,653 +1,653 @@ -bIsLoggined = false; - $this->iRequestTime = 0; - $this->aCapa = array(); - $this->aModules = array(); - - $this->__USE_INITIAL_AUTH_PLAIN_COMMAND = true; - } - - /** - * @return \MailSo\Sieve\ManageSieveClient - */ - public static function NewInstance() - { - return new self(); - } - - /** - * @param string $sCapa - * - * @return bool - */ - public function IsSupported($sCapa) - { - return isset($this->aCapa[\strtoupper($sCapa)]); - } - - /** - * @param string $sModule - * - * @return bool - */ - public function IsModuleSupported($sModule) - { - return $this->IsSupported('SIEVE') && \in_array(\strtolower(\trim($sModule)), $this->aModules); - } - - /** - * @return array - */ - public function Modules() - { - return $this->aModules; - } - - /** - * @param string $sAuth - * - * @return bool - */ - public function IsAuthSupported($sAuth) - { - return $this->IsSupported('SASL') && \in_array(\strtoupper($sAuth), $this->aAuth); - } - - /** - * @param string $sServerName - * @param int $iPort - * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT - * @param bool $bVerifySsl = false - * @param bool $bAllowSelfSigned = true - * - * @return \MailSo\Sieve\ManageSieveClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Sieve\Exceptions\ResponseException - */ - public function Connect($sServerName, $iPort, - $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, - $bVerifySsl = false, $bAllowSelfSigned = true) - { - $this->iRequestTime = \microtime(true); - - parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned); - - $mResponse = $this->parseResponse(); - $this->validateResponse($mResponse); - $this->parseStartupResponse($mResponse); - - if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS( - $this->IsSupported('STARTTLS'), $this->iSecurityType)) - { - $this->sendRequestWithCheck('STARTTLS'); - $this->EnableCrypto(); - - $mResponse = $this->parseResponse(); - $this->validateResponse($mResponse); - $this->parseStartupResponse($mResponse); - } - else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType) - { - $this->writeLogException( - new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - return $this; - } - - /** - * @param string $sLogin - * @param string $sPassword - * @param string $sLoginAuthKey = '' - * - * @return \MailSo\Sieve\ManageSieveClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Sieve\Exceptions\LoginException - */ - public function Login($sLogin, $sPassword, $sLoginAuthKey = '') - { - if (!\MailSo\Base\Validator::NotEmptyString($sLogin, true) || - !\MailSo\Base\Validator::NotEmptyString($sPassword, true)) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - if ($this->IsSupported('SASL')) - { - $bAuth = false; - try - { - if ($this->IsAuthSupported('PLAIN')) - { - $sAuth = \base64_encode($sLoginAuthKey."\0".$sLogin."\0".$sPassword); - - if ($this->__USE_INITIAL_AUTH_PLAIN_COMMAND) - { - $this->sendRequest('AUTHENTICATE "PLAIN" "'.$sAuth.'"'); - } - else - { - $this->sendRequest('AUTHENTICATE "PLAIN" {'.\strlen($sAuth).'+}'); - $this->sendRequest($sAuth); - } - - $mResponse = $this->parseResponse(); - $this->validateResponse($mResponse); - $this->parseStartupResponse($mResponse); - $bAuth = true; - } - else if ($this->IsAuthSupported('LOGIN')) - { - $sLogin = \base64_encode($sLogin); - $sPassword = \base64_encode($sPassword); - - $this->sendRequest('AUTHENTICATE "LOGIN"'); - $this->sendRequest('{'.\strlen($sLogin).'+}'); - $this->sendRequest($sLogin); - $this->sendRequest('{'.\strlen($sPassword).'+}'); - $this->sendRequest($sPassword); - - $mResponse = $this->parseResponse(); - $this->validateResponse($mResponse); - $this->parseStartupResponse($mResponse); - $bAuth = true; - } - } - catch (\MailSo\Sieve\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Sieve\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), '', 0, $oException), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - if (!$bAuth) - { - $this->writeLogException( - new \MailSo\Sieve\Exceptions\LoginBadMethodException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - } - else - { - $this->writeLogException( - new \MailSo\Sieve\Exceptions\LoginException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $this->bIsLoggined = true; - - return $this; - } - - /** - * @return \MailSo\Sieve\ManageSieveClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - public function Logout() - { - if ($this->bIsLoggined) - { - $this->sendRequestWithCheck('LOGOUT'); - $this->bIsLoggined = false; - } - - return $this; - } - - /** - * @return array - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - public function ListScripts() - { - $this->sendRequest('LISTSCRIPTS'); - $mResponse = $this->parseResponse(); - $this->validateResponse($mResponse); - - $aResult = array(); - if (\is_array($mResponse)) - { - foreach ($mResponse as $sLine) - { - $aTokens = $this->parseLine($sLine); - if (false === $aTokens) - { - continue; - } - - $aResult[$aTokens[0]] = 'ACTIVE' === substr($sLine, -6); - } - } - - return $aResult; - } - - /** - * @return array - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - public function Capability() - { - $this->sendRequest('CAPABILITY'); - $mResponse = $this->parseResponse(); - $this->validateResponse($mResponse); - $this->parseStartupResponse($mResponse); - - return $this->aCapa; - } - - /** - * @return \MailSo\Sieve\ManageSieveClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - public function Noop() - { - $this->sendRequestWithCheck('NOOP'); - - return $this; - } - - /** - * @param string $sScriptName - * - * @return string - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - public function GetScript($sScriptName) - { - $this->sendRequest('GETSCRIPT "'.$sScriptName.'"'); - $mResponse = $this->parseResponse(); - $this->validateResponse($mResponse); - - $sScript = ''; - if (\is_array($mResponse) && 0 < \count($mResponse)) - { - if ('{' === $mResponse[0]{0}) - { - \array_shift($mResponse); - } - - if (\in_array(\substr($mResponse[\count($mResponse) - 1], 0, 2), array('OK', 'NO'))) - { - \array_pop($mResponse); - } - - $sScript = \implode("\n", $mResponse); - } - - return $sScript; - } - - /** - * @param string $sScriptName - * @param string $sScriptSource - * - * @return \MailSo\Sieve\ManageSieveClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - public function PutScript($sScriptName, $sScriptSource) - { - $this->sendRequest('PUTSCRIPT "'.$sScriptName.'" {'.\strlen($sScriptSource).'+}'); - $this->sendRequestWithCheck($sScriptSource); - - return $this; - } - - /** - * @param string $sScriptSource - * - * @return \MailSo\Sieve\ManageSieveClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - public function CheckScript($sScriptSource) - { - $this->sendRequest('CHECKSCRIPT {'.\strlen($sScriptSource).'+}'); - $this->sendRequestWithCheck($sScriptSource); - - return $this; - } - - /** - * @param string $sScriptName - * - * @return \MailSo\Sieve\ManageSieveClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - public function SetActiveScript($sScriptName) - { - $this->sendRequestWithCheck('SETACTIVE "'.$sScriptName.'"'); - - return $this; - } - - /** - * @param string $sScriptName - * - * @return \MailSo\Sieve\ManageSieveClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - public function DeleteScript($sScriptName) - { - $this->sendRequestWithCheck('DELETESCRIPT "'.$sScriptName.'"'); - - return $this; - } - - /** - * @return string - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - public function GetActiveScriptName() - { - $aList = $this->ListScripts(); - if (\is_array($aList) && 0 < \count($aList)) - { - foreach ($aList as $sName => $bIsActive) - { - if ($bIsActive) - { - return $sName; - } - } - } - - return ''; - } - - /** - * @param string $sScriptName - * - * @return bool - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - public function IsActiveScript($sScriptName) - { - return $sScriptName === $this->GetActiveScriptName(); - } - - /** - * @param string $sLine - * @return array|false - */ - private function parseLine($sLine) - { - if (false === $sLine || null === $sLine || \in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) - { - return false; - } - - $iStart = -1; - $iIndex = 0; - $aResult = false; - - for ($iPos = 0; $iPos < \strlen($sLine); $iPos++) - { - if ('"' === $sLine[$iPos] && '\\' !== $sLine[$iPos]) - { - if (-1 === $iStart) - { - $iStart = $iPos; - } - else - { - $aResult = \is_array($aResult) ? $aResult : array(); - $aResult[$iIndex++] = \substr($sLine, $iStart + 1, $iPos - $iStart - 1); - $iStart = -1; - } - } - } - - return \is_array($aResult) && isset($aResult[0]) ? $aResult : false; - } - - /** - * @param string $mResponse - * - * @return void - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - */ - private function parseStartupResponse($mResponse) - { - foreach ($mResponse as $sLine) - { - $aTokens = $this->parseLine($sLine); - - if (false === $aTokens || !isset($aTokens[0]) || - \in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) - { - continue; - } - - $sToken = \strtoupper($aTokens[0]); - $this->aCapa[$sToken] = isset($aTokens[1]) ? $aTokens[1] : ''; - - if (isset($aTokens[1])) - { - switch ($sToken) { - case 'SASL': - $this->aAuth = \explode(' ', \strtoupper($aTokens[1])); - break; - case 'SIEVE': - $this->aModules = \explode(' ', \strtolower($aTokens[1])); - break; - } - } - } - } - - /** - * @param string $sRequest - * - * @return void - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - */ - private function sendRequest($sRequest) - { - if (!\MailSo\Base\Validator::NotEmptyString($sRequest, true)) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $this->IsConnected(true); - - $this->sendRaw($sRequest); - } - - /** - * @param string $sRequest - * - * @return void - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - private function sendRequestWithCheck($sRequest) - { - $this->sendRequest($sRequest); - $this->validateResponse($this->parseResponse()); - } - - /** - * @param string $sLine - * - * @return string - */ - private function convertEndOfLine($sLine) - { - $sLine = \trim($sLine); - if ('}' === \substr($sLine, -1)) - { - $iPos = \strrpos($sLine, '{'); - if (false !== $iPos) - { - $sSunLine = \substr($sLine, $iPos + 1, -1); - if (\is_numeric($sSunLine) && 0 < (int) $sSunLine) - { - $iLen = (int) $sSunLine; - - $this->getNextBuffer($iLen, true); - - if (\strlen($this->sResponseBuffer) === $iLen) - { - $sLine = \trim(\substr_replace($sLine, $this->sResponseBuffer, $iPos)); - } - } - } - } - - return $sLine; - } - - /** - * @return array|bool - */ - private function parseResponse() - { - $this->iRequestTime = \microtime(true); - - $aResult = array(); - do - { - $this->getNextBuffer(); - - $sLine = $this->sResponseBuffer; - if (false === $sLine) - { - break; - } - else if (\in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) - { - $aResult[] = $this->convertEndOfLine($sLine); - break; - } - else - { - $aResult[] = $this->convertEndOfLine($sLine); - } - } - while (true); - - $this->writeLog((\microtime(true) - $this->iRequestTime), - \MailSo\Log\Enumerations\Type::TIME); - - return $aResult; - } - - /** - * @throws \MailSo\Sieve\Exceptions\NegativeResponseException - */ - private function validateResponse($aResponse) - { - if (!\is_array($aResponse) || 0 === \count($aResponse) || - 'OK' !== \substr($aResponse[\count($aResponse) - 1], 0, 2)) - { - $this->writeLogException( - new \MailSo\Sieve\Exceptions\NegativeResponseException($aResponse), - \MailSo\Log\Enumerations\Type::WARNING, true); - } - } - - /** - * @return string - */ - protected function getLogName() - { - return 'SIEVE'; - } - - /** - * @param \MailSo\Log\Logger $oLogger - * - * @return \MailSo\Sieve\ManageSieveClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function SetLogger($oLogger) - { - parent::SetLogger($oLogger); - - return $this; - } -} +bIsLoggined = false; + $this->iRequestTime = 0; + $this->aCapa = array(); + $this->aModules = array(); + + $this->__USE_INITIAL_AUTH_PLAIN_COMMAND = true; + } + + /** + * @return \MailSo\Sieve\ManageSieveClient + */ + public static function NewInstance() + { + return new self(); + } + + /** + * @param string $sCapa + * + * @return bool + */ + public function IsSupported($sCapa) + { + return isset($this->aCapa[\strtoupper($sCapa)]); + } + + /** + * @param string $sModule + * + * @return bool + */ + public function IsModuleSupported($sModule) + { + return $this->IsSupported('SIEVE') && \in_array(\strtolower(\trim($sModule)), $this->aModules); + } + + /** + * @return array + */ + public function Modules() + { + return $this->aModules; + } + + /** + * @param string $sAuth + * + * @return bool + */ + public function IsAuthSupported($sAuth) + { + return $this->IsSupported('SASL') && \in_array(\strtoupper($sAuth), $this->aAuth); + } + + /** + * @param string $sServerName + * @param int $iPort + * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT + * @param bool $bVerifySsl = false + * @param bool $bAllowSelfSigned = true + * + * @return \MailSo\Sieve\ManageSieveClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Sieve\Exceptions\ResponseException + */ + public function Connect($sServerName, $iPort, + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, + $bVerifySsl = false, $bAllowSelfSigned = true) + { + $this->iRequestTime = \microtime(true); + + parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned); + + $mResponse = $this->parseResponse(); + $this->validateResponse($mResponse); + $this->parseStartupResponse($mResponse); + + if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS( + $this->IsSupported('STARTTLS'), $this->iSecurityType)) + { + $this->sendRequestWithCheck('STARTTLS'); + $this->EnableCrypto(); + + $mResponse = $this->parseResponse(); + $this->validateResponse($mResponse); + $this->parseStartupResponse($mResponse); + } + else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType) + { + $this->writeLogException( + new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + return $this; + } + + /** + * @param string $sLogin + * @param string $sPassword + * @param string $sLoginAuthKey = '' + * + * @return \MailSo\Sieve\ManageSieveClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Sieve\Exceptions\LoginException + */ + public function Login($sLogin, $sPassword, $sLoginAuthKey = '') + { + if (!\MailSo\Base\Validator::NotEmptyString($sLogin, true) || + !\MailSo\Base\Validator::NotEmptyString($sPassword, true)) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + if ($this->IsSupported('SASL')) + { + $bAuth = false; + try + { + if ($this->IsAuthSupported('PLAIN')) + { + $sAuth = \base64_encode($sLoginAuthKey."\0".$sLogin."\0".$sPassword); + + if ($this->__USE_INITIAL_AUTH_PLAIN_COMMAND) + { + $this->sendRequest('AUTHENTICATE "PLAIN" "'.$sAuth.'"'); + } + else + { + $this->sendRequest('AUTHENTICATE "PLAIN" {'.\strlen($sAuth).'+}'); + $this->sendRequest($sAuth); + } + + $mResponse = $this->parseResponse(); + $this->validateResponse($mResponse); + $this->parseStartupResponse($mResponse); + $bAuth = true; + } + else if ($this->IsAuthSupported('LOGIN')) + { + $sLogin = \base64_encode($sLogin); + $sPassword = \base64_encode($sPassword); + + $this->sendRequest('AUTHENTICATE "LOGIN"'); + $this->sendRequest('{'.\strlen($sLogin).'+}'); + $this->sendRequest($sLogin); + $this->sendRequest('{'.\strlen($sPassword).'+}'); + $this->sendRequest($sPassword); + + $mResponse = $this->parseResponse(); + $this->validateResponse($mResponse); + $this->parseStartupResponse($mResponse); + $bAuth = true; + } + } + catch (\MailSo\Sieve\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Sieve\Exceptions\LoginBadCredentialsException( + $oException->GetResponses(), '', 0, $oException), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + if (!$bAuth) + { + $this->writeLogException( + new \MailSo\Sieve\Exceptions\LoginBadMethodException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + } + else + { + $this->writeLogException( + new \MailSo\Sieve\Exceptions\LoginException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $this->bIsLoggined = true; + + return $this; + } + + /** + * @return \MailSo\Sieve\ManageSieveClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + public function Logout() + { + if ($this->bIsLoggined) + { + $this->sendRequestWithCheck('LOGOUT'); + $this->bIsLoggined = false; + } + + return $this; + } + + /** + * @return array + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + public function ListScripts() + { + $this->sendRequest('LISTSCRIPTS'); + $mResponse = $this->parseResponse(); + $this->validateResponse($mResponse); + + $aResult = array(); + if (\is_array($mResponse)) + { + foreach ($mResponse as $sLine) + { + $aTokens = $this->parseLine($sLine); + if (false === $aTokens) + { + continue; + } + + $aResult[$aTokens[0]] = 'ACTIVE' === substr($sLine, -6); + } + } + + return $aResult; + } + + /** + * @return array + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + public function Capability() + { + $this->sendRequest('CAPABILITY'); + $mResponse = $this->parseResponse(); + $this->validateResponse($mResponse); + $this->parseStartupResponse($mResponse); + + return $this->aCapa; + } + + /** + * @return \MailSo\Sieve\ManageSieveClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + public function Noop() + { + $this->sendRequestWithCheck('NOOP'); + + return $this; + } + + /** + * @param string $sScriptName + * + * @return string + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + public function GetScript($sScriptName) + { + $this->sendRequest('GETSCRIPT "'.$sScriptName.'"'); + $mResponse = $this->parseResponse(); + $this->validateResponse($mResponse); + + $sScript = ''; + if (\is_array($mResponse) && 0 < \count($mResponse)) + { + if ('{' === $mResponse[0]{0}) + { + \array_shift($mResponse); + } + + if (\in_array(\substr($mResponse[\count($mResponse) - 1], 0, 2), array('OK', 'NO'))) + { + \array_pop($mResponse); + } + + $sScript = \implode("\n", $mResponse); + } + + return $sScript; + } + + /** + * @param string $sScriptName + * @param string $sScriptSource + * + * @return \MailSo\Sieve\ManageSieveClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + public function PutScript($sScriptName, $sScriptSource) + { + $this->sendRequest('PUTSCRIPT "'.$sScriptName.'" {'.\strlen($sScriptSource).'+}'); + $this->sendRequestWithCheck($sScriptSource); + + return $this; + } + + /** + * @param string $sScriptSource + * + * @return \MailSo\Sieve\ManageSieveClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + public function CheckScript($sScriptSource) + { + $this->sendRequest('CHECKSCRIPT {'.\strlen($sScriptSource).'+}'); + $this->sendRequestWithCheck($sScriptSource); + + return $this; + } + + /** + * @param string $sScriptName + * + * @return \MailSo\Sieve\ManageSieveClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + public function SetActiveScript($sScriptName) + { + $this->sendRequestWithCheck('SETACTIVE "'.$sScriptName.'"'); + + return $this; + } + + /** + * @param string $sScriptName + * + * @return \MailSo\Sieve\ManageSieveClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + public function DeleteScript($sScriptName) + { + $this->sendRequestWithCheck('DELETESCRIPT "'.$sScriptName.'"'); + + return $this; + } + + /** + * @return string + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + public function GetActiveScriptName() + { + $aList = $this->ListScripts(); + if (\is_array($aList) && 0 < \count($aList)) + { + foreach ($aList as $sName => $bIsActive) + { + if ($bIsActive) + { + return $sName; + } + } + } + + return ''; + } + + /** + * @param string $sScriptName + * + * @return bool + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + public function IsActiveScript($sScriptName) + { + return $sScriptName === $this->GetActiveScriptName(); + } + + /** + * @param string $sLine + * @return array|false + */ + private function parseLine($sLine) + { + if (false === $sLine || null === $sLine || \in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) + { + return false; + } + + $iStart = -1; + $iIndex = 0; + $aResult = false; + + for ($iPos = 0; $iPos < \strlen($sLine); $iPos++) + { + if ('"' === $sLine[$iPos] && '\\' !== $sLine[$iPos]) + { + if (-1 === $iStart) + { + $iStart = $iPos; + } + else + { + $aResult = \is_array($aResult) ? $aResult : array(); + $aResult[$iIndex++] = \substr($sLine, $iStart + 1, $iPos - $iStart - 1); + $iStart = -1; + } + } + } + + return \is_array($aResult) && isset($aResult[0]) ? $aResult : false; + } + + /** + * @param string $mResponse + * + * @return void + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + */ + private function parseStartupResponse($mResponse) + { + foreach ($mResponse as $sLine) + { + $aTokens = $this->parseLine($sLine); + + if (false === $aTokens || !isset($aTokens[0]) || + \in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) + { + continue; + } + + $sToken = \strtoupper($aTokens[0]); + $this->aCapa[$sToken] = isset($aTokens[1]) ? $aTokens[1] : ''; + + if (isset($aTokens[1])) + { + switch ($sToken) { + case 'SASL': + $this->aAuth = \explode(' ', \strtoupper($aTokens[1])); + break; + case 'SIEVE': + $this->aModules = \explode(' ', \strtolower($aTokens[1])); + break; + } + } + } + } + + /** + * @param string $sRequest + * + * @return void + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + */ + private function sendRequest($sRequest) + { + if (!\MailSo\Base\Validator::NotEmptyString($sRequest, true)) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $this->IsConnected(true); + + $this->sendRaw($sRequest); + } + + /** + * @param string $sRequest + * + * @return void + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + private function sendRequestWithCheck($sRequest) + { + $this->sendRequest($sRequest); + $this->validateResponse($this->parseResponse()); + } + + /** + * @param string $sLine + * + * @return string + */ + private function convertEndOfLine($sLine) + { + $sLine = \trim($sLine); + if ('}' === \substr($sLine, -1)) + { + $iPos = \strrpos($sLine, '{'); + if (false !== $iPos) + { + $sSunLine = \substr($sLine, $iPos + 1, -1); + if (\is_numeric($sSunLine) && 0 < (int) $sSunLine) + { + $iLen = (int) $sSunLine; + + $this->getNextBuffer($iLen, true); + + if (\strlen($this->sResponseBuffer) === $iLen) + { + $sLine = \trim(\substr_replace($sLine, $this->sResponseBuffer, $iPos)); + } + } + } + } + + return $sLine; + } + + /** + * @return array|bool + */ + private function parseResponse() + { + $this->iRequestTime = \microtime(true); + + $aResult = array(); + do + { + $this->getNextBuffer(); + + $sLine = $this->sResponseBuffer; + if (false === $sLine) + { + break; + } + else if (\in_array(\substr($sLine, 0, 2), array('OK', 'NO'))) + { + $aResult[] = $this->convertEndOfLine($sLine); + break; + } + else + { + $aResult[] = $this->convertEndOfLine($sLine); + } + } + while (true); + + $this->writeLog((\microtime(true) - $this->iRequestTime), + \MailSo\Log\Enumerations\Type::TIME); + + return $aResult; + } + + /** + * @throws \MailSo\Sieve\Exceptions\NegativeResponseException + */ + private function validateResponse($aResponse) + { + if (!\is_array($aResponse) || 0 === \count($aResponse) || + 'OK' !== \substr($aResponse[\count($aResponse) - 1], 0, 2)) + { + $this->writeLogException( + new \MailSo\Sieve\Exceptions\NegativeResponseException($aResponse), + \MailSo\Log\Enumerations\Type::WARNING, true); + } + } + + /** + * @return string + */ + protected function getLogName() + { + return 'SIEVE'; + } + + /** + * @param \MailSo\Log\Logger $oLogger + * + * @return \MailSo\Sieve\ManageSieveClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function SetLogger($oLogger) + { + parent::SetLogger($oLogger); + + return $this; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/Exception.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/Exception.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/Exception.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginBadCredentialsException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/LoginBadCredentialsException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginBadCredentialsException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/LoginBadCredentialsException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginBadMethodException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/LoginBadMethodException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginBadMethodException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/LoginBadMethodException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/LoginException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/LoginException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/NegativeResponseException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/NegativeResponseException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/NegativeResponseException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/NegativeResponseException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/ResponseException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/ResponseException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/ResponseException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/ResponseException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/RuntimeException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/RuntimeException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/RuntimeException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/Exceptions/RuntimeException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/SmtpClient.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/SmtpClient.php similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/SmtpClient.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/SmtpClient.php index ce09f029..f536b72a 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/SmtpClient.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Smtp/SmtpClient.php @@ -1,838 +1,838 @@ -aAuthTypes = array(); - - $this->iRequestTime = 0; - $this->iSizeCapaValue = 0; - $this->aResults = array(); - $this->aCapa = array(); - - $this->bHelo = false; - $this->bRcpt = false; - $this->bMail = false; - $this->bData = false; - } - - /** - * @return \MailSo\Smtp\SmtpClient - */ - public static function NewInstance() - { - return new self(); - } - - /** - * @return bool - */ - public function IsSupported($sCapa) - { - return in_array(strtoupper($sCapa), $this->aCapa); - } - - /** - * @return bool - */ - public function IsAuthSupported($sAuth) - { - return in_array(strtoupper($sAuth), $this->aAuthTypes); - } - - /** - * @return bool - */ - public function HasSupportedAuth() - { - return $this->IsAuthSupported('PLAIN') || $this->IsAuthSupported('LOGIN'); - } - - /** - * @return string - */ - public static function EhloHelper() - { - $sEhloHost = empty($_SERVER['SERVER_NAME']) ? '' : \trim($_SERVER['SERVER_NAME']); - if (empty($sEhloHost)) - { - $sEhloHost = empty($_SERVER['HTTP_HOST']) ? '' : \trim($_SERVER['HTTP_HOST']); - } - - if (empty($sEhloHost)) - { - $sEhloHost = \function_exists('gethostname') ? \gethostname() : 'localhost'; - } - - $sEhloHost = \trim(\preg_replace('/:\d+$/', '', \trim($sEhloHost))); - - if (\preg_match('/^\d+\.\d+\.\d+\.\d+$/', $sEhloHost)) - { - $sEhloHost = '['.$sEhloHost.']'; - } - - return empty($sEhloHost) ? 'localhost' : $sEhloHost; - } - - /** - * @param string $sServerName - * @param int $iPort = 25 - * @param string $sEhloHost = '[127.0.0.1]' - * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT - * @param bool $bVerifySsl = false - * @param bool $bAllowSelfSigned = true - * - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\ResponseException - */ - public function Connect($sServerName, $iPort = 25, $sEhloHost = '[127.0.0.1]', - $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, - $bVerifySsl = false, $bAllowSelfSigned = true) - { - $this->iRequestTime = microtime(true); - - parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned); - - $this->validateResponse(220); - - $this->preLoginStartTLSAndEhloProcess($sEhloHost); - - return $this; - } - - /** - * @param string $sLogin - * @param string $sPassword - * @param boolean $bUseAuthPlainIfSupported = true - * @param boolean $bUseAuthCramMd5IfSupported = true - * - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - public function Login($sLogin, $sPassword, $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true) - { - $sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin)); - - if ($bUseAuthCramMd5IfSupported && $this->IsAuthSupported('CRAM-MD5')) - { - try - { - $this->sendRequestWithCheck('AUTH', 334, 'CRAM-MD5'); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadMethodException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - - $sTicket = ''; - - $sContinuationResponse = !empty($this->aResults[0]) ? \trim($this->aResults[0]) : ''; - if ($sContinuationResponse && '334 ' === \substr($sContinuationResponse, 0, 4) && 0 < \strlen(\substr($sContinuationResponse, 4))) - { - $sTicket = @\base64_decode(\substr($sContinuationResponse, 4)); - $this->writeLogWithCrlf('ticket: '.$sTicket); - } - - if (empty($sTicket)) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\NegativeResponseException(), - \MailSo\Log\Enumerations\Type::NOTICE, true - ); - } - - try - { - $this->sendRequestWithCheck(\base64_encode($sLogin.' '.\MailSo\Base\Utils::Hmac($sTicket, $sPassword)), 235, '', true); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - } - else if ($bUseAuthPlainIfSupported && $this->IsAuthSupported('PLAIN')) - { - if ($this->__USE_SINGLE_LINE_AUTH_PLAIN_COMMAND) - { - try - { - $this->sendRequestWithCheck('AUTH', 235, 'PLAIN '.\base64_encode("\0".$sLogin."\0".$sPassword), true); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - } - else - { - try - { - $this->sendRequestWithCheck('AUTH', 334, 'PLAIN'); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadMethodException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - - try - { - $this->sendRequestWithCheck(\base64_encode("\0".$sLogin."\0".$sPassword), 235, '', true); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - } - } - else if ($this->IsAuthSupported('LOGIN')) - { - try - { - $this->sendRequestWithCheck('AUTH', 334, 'LOGIN'); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadMethodException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - - try - { - $this->sendRequestWithCheck(\base64_encode($sLogin), 334, ''); - $this->sendRequestWithCheck(\base64_encode($sPassword), 235, '', true); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - } - else - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadMethodException(), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - - return $this; - } - - /** - * @param string $sXOAuth2Token - * - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - public function LoginWithXOauth2($sXOAuth2Token) - { - if ($this->IsAuthSupported('XOAUTH2')) - { - try - { - $this->sendRequestWithCheck('AUTH', 235, 'XOAUTH2 '.\trim($sXOAuth2Token)); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - } - else - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadMethodException(), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - - return $this; - } - - /** - * @param string $sFrom - * @param string $sSizeIfSupported = '' - * @param bool $bDsn = false - * - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - public function MailFrom($sFrom, $sSizeIfSupported = '', $bDsn = false) - { - $sFrom = \MailSo\Base\Utils::IdnToAscii( - \MailSo\Base\Utils::Trim($sFrom), true); - - $sCmd = 'FROM:<'.$sFrom.'>'; - - $sSizeIfSupported = (string) $sSizeIfSupported; - if (0 < \strlen($sSizeIfSupported) && \is_numeric($sSizeIfSupported) && $this->IsSupported('SIZE')) - { - $sCmd .= ' SIZE='.$sSizeIfSupported; - } - - if ($bDsn && $this->IsSupported('DSN')) - { - $sCmd .= ' RET=HDRS'; - } - - $this->sendRequestWithCheck('MAIL', 250, $sCmd); - - $this->bMail = true; - $this->bRcpt = false; - $this->bData = false; - - return $this; - } - - /** - * @param string $sTo - * @param bool $bDsn = false - * - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - public function Rcpt($sTo, $bDsn = false) - { - if (!$this->bMail) - { - $this->writeLogException( - new Exceptions\RuntimeException('No sender reverse path has been supplied'), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $sTo = \MailSo\Base\Utils::IdnToAscii( - \MailSo\Base\Utils::Trim($sTo), true); - - $sCmd = 'TO:<'.$sTo.'>'; - - if ($bDsn && $this->IsSupported('DSN')) - { - $sCmd .= ' NOTIFY=SUCCESS,FAILURE'; - } - - $this->sendRequestWithCheck( - 'RCPT', array(250, 251), $sCmd, false, - 'Failed to add recipient "'.$sTo.'"' - ); - - $this->bRcpt = true; - - return $this; - } - - /** - * @param string $sTo - * - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - public function MailTo($sTo) - { - return $this->Rcpt($sTo); - } - - /** - * @param string $sData - * - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - public function Data($sData) - { - if (!\MailSo\Base\Validator::NotEmptyString($sData, true)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $rDataStream = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($sData); - unset($sData); - $this->DataWithStream($rDataStream); - \MailSo\Base\ResourceRegistry::CloseMemoryResource($rDataStream); - - return $this; - } - - /** - * @param resource $rDataStream - * - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - public function DataWithStream($rDataStream) - { - if (!\is_resource($rDataStream)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - if (!$this->bRcpt) - { - $this->writeLogException( - new Exceptions\RuntimeException('No recipient forward path has been supplied'), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $this->sendRequestWithCheck('DATA', 354); - - $this->writeLog('Message data.', \MailSo\Log\Enumerations\Type::NOTE); - - $this->bRunningCallback = true; - - while (!\feof($rDataStream)) - { - $sBuffer = \fgets($rDataStream); - if (false !== $sBuffer) - { - if (0 === \strpos($sBuffer, '.')) - { - $sBuffer = '.'.$sBuffer; - } - - $this->sendRaw(\rtrim($sBuffer, "\r\n"), false); - - \MailSo\Base\Utils::ResetTimeLimit(); - continue; - } - else if (!\feof($rDataStream)) - { - $this->writeLogException( - new Exceptions\RuntimeException('Cannot read input resource'), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - break; - } - - $this->sendRequestWithCheck('.', 250); - - $this->bRunningCallback = false; - - $this->bData = true; - - return $this; - } - - /** - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - public function Rset() - { - $this->sendRequestWithCheck('RSET', array(250, 220)); - - $this->bMail = false; - $this->bRcpt = false; - $this->bData = false; - - return $this; - } - - /** - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - public function Vrfy($sUser) - { - $sUser = \MailSo\Base\Utils::IdnToAscii( - \MailSo\Base\Utils::Trim($sUser)); - - $this->sendRequestWithCheck('VRFY', array(250, 251, 252), $sUser); - - return $this; - } - - /** - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - public function Noop() - { - $this->sendRequestWithCheck('NOOP', 250); - - return $this; - } - - /** - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - public function Logout() - { - if ($this->IsConnected()) - { - $this->sendRequestWithCheck('QUIT', 221); - } - - $this->bHelo = false; - $this->bMail = false; - $this->bRcpt = false; - $this->bData = false; - - return $this; - } - - /** - * @param string $sEhloHost - * - * @return void - */ - private function preLoginStartTLSAndEhloProcess($sEhloHost) - { - if ($this->bHelo) - { - $this->writeLogException( - new Exceptions\RuntimeException('Cannot issue EHLO/HELO to existing session'), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $this->ehloOrHelo($sEhloHost); - - if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS( - $this->IsSupported('STARTTLS'), $this->iSecurityType, $this->HasSupportedAuth())) - { - $this->sendRequestWithCheck('STARTTLS', 220); - $this->EnableCrypto(); - - $this->ehloOrHelo($sEhloHost); - } - else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType) - { - $this->writeLogException( - new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $this->bHelo = true; - } - - /** - * @param string $sCommand - * @param string $sAddToCommand = '' - * @param bool $bSecureLog = false - * - * @return void - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - */ - private function sendRequest($sCommand, $sAddToCommand = '', $bSecureLog = false) - { - if (!\MailSo\Base\Validator::NotEmptyString($sCommand, true)) - { - $this->writeLogException( - new \MailSo\Base\Exceptions\InvalidArgumentException(), - \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $this->IsConnected(true); - - $sCommand = \trim($sCommand); - $sRealCommand = $sCommand.(0 === \strlen($sAddToCommand) ? '' : ' '.$sAddToCommand); - - $sFakeCommand = ($bSecureLog) ? '********' : ''; - - $this->iRequestTime = \microtime(true); - $this->sendRaw($sRealCommand, true, $sFakeCommand); - - return $this; - } - - /** - * @param string $sCommand - * @param int|array $mExpectCode - * @param string $sAddToCommand = '' - * @param bool $bSecureLog = false - * @param string $sErrorPrefix = '' - * - * @return void - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - private function sendRequestWithCheck($sCommand, $mExpectCode, $sAddToCommand = '', $bSecureLog = false, $sErrorPrefix = '') - { - $this->sendRequest($sCommand, $sAddToCommand, $bSecureLog); - $this->validateResponse($mExpectCode, $sErrorPrefix); - } - - /** - * @param string $sHost - * - * @return void - */ - private function ehloOrHelo($sHost) - { - try - { - $this->ehlo($sHost); - } - catch (\Exception $oException) - { - try - { - $this->helo($sHost); - } - catch (\Exception $oException) - { - throw $oException; - } - } - - return $this; - } - - /** - * @param string $sHost - * - * @return void - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - private function ehlo($sHost) - { - $this->sendRequestWithCheck('EHLO', 250, $sHost); - - foreach ($this->aResults as $sLine) - { - $aMatch = array(); - if (\preg_match('/[\d]+[ \-](.+)$/', $sLine, $aMatch) && isset($aMatch[1]) && 0 < \strlen($aMatch[1])) - { - $sLine = \trim($aMatch[1]); - $aLine = \preg_split('/[ =]/', $sLine, 2); - if (\is_array($aLine) && 0 < \count($aLine) && !empty($aLine[0])) - { - $sCapa = \strtoupper($aLine[0]); - if (('AUTH' === $sCapa || 'SIZE' === $sCapa) && !empty($aLine[1])) - { - $sSubLine = \trim(\strtoupper($aLine[1])); - if (0 < \strlen($sSubLine)) - { - if ('AUTH' === $sCapa) - { - $this->aAuthTypes = \explode(' ', $sSubLine); - } - else if ('SIZE' === $sCapa && \is_numeric($sSubLine)) - { - $this->iSizeCapaValue = (int) $sSubLine; - } - } - } - - $this->aCapa[] = $sCapa; - } - } - } - } - - /** - * @param string $sHost - * - * @return void - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Smtp\Exceptions\Exception - */ - private function helo($sHost) - { - $this->sendRequestWithCheck('HELO', 250, $sHost); - $this->aAuthTypes = array(); - $this->iSizeCapaValue = 0; - $this->aCapa = array(); - } - - /** - * @param int|array $mExpectCode - * @param string $sErrorPrefix = '' - * - * @return void - * - * @throws \MailSo\Smtp\Exceptions\ResponseException - */ - private function validateResponse($mExpectCode, $sErrorPrefix = '') - { - if (!\is_array($mExpectCode)) - { - $mExpectCode = array((int) $mExpectCode); - } - else - { - $mExpectCode = \array_map('intval', $mExpectCode); - } - - $aParts = array('', '', ''); - $this->aResults = array(); - do - { - $this->getNextBuffer(); - $aParts = \preg_split('/([\s\-]+)/', $this->sResponseBuffer, 2, PREG_SPLIT_DELIM_CAPTURE); - - if (\is_array($aParts) && 3 === \count($aParts) && \is_numeric($aParts[0])) - { - if ('-' !== \substr($aParts[1], 0, 1) && !\in_array((int) $aParts[0], $mExpectCode)) - { - $this->writeLogException( - new Exceptions\NegativeResponseException($this->aResults, - ('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim( - (0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : ''). - $this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true); - } - } - else - { - $this->writeLogException( - new Exceptions\ResponseException($this->aResults, - ('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim( - (0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : ''). - $this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true); - } - - $this->aResults[] = $this->sResponseBuffer; - } - while ('-' === \substr($aParts[1], 0, 1)); - - $this->writeLog((microtime(true) - $this->iRequestTime), - \MailSo\Log\Enumerations\Type::TIME); - } - - /** - * @return string - */ - protected function getLogName() - { - return 'SMTP'; - } - - /** - * @param \MailSo\Log\Logger $oLogger - * - * @return \MailSo\Smtp\SmtpClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function SetLogger($oLogger) - { - parent::SetLogger($oLogger); - - return $this; - } -} +aAuthTypes = array(); + + $this->iRequestTime = 0; + $this->iSizeCapaValue = 0; + $this->aResults = array(); + $this->aCapa = array(); + + $this->bHelo = false; + $this->bRcpt = false; + $this->bMail = false; + $this->bData = false; + } + + /** + * @return \MailSo\Smtp\SmtpClient + */ + public static function NewInstance() + { + return new self(); + } + + /** + * @return bool + */ + public function IsSupported($sCapa) + { + return in_array(strtoupper($sCapa), $this->aCapa); + } + + /** + * @return bool + */ + public function IsAuthSupported($sAuth) + { + return in_array(strtoupper($sAuth), $this->aAuthTypes); + } + + /** + * @return bool + */ + public function HasSupportedAuth() + { + return $this->IsAuthSupported('PLAIN') || $this->IsAuthSupported('LOGIN'); + } + + /** + * @return string + */ + public static function EhloHelper() + { + $sEhloHost = empty($_SERVER['SERVER_NAME']) ? '' : \trim($_SERVER['SERVER_NAME']); + if (empty($sEhloHost)) + { + $sEhloHost = empty($_SERVER['HTTP_HOST']) ? '' : \trim($_SERVER['HTTP_HOST']); + } + + if (empty($sEhloHost)) + { + $sEhloHost = \function_exists('gethostname') ? \gethostname() : 'localhost'; + } + + $sEhloHost = \trim(\preg_replace('/:\d+$/', '', \trim($sEhloHost))); + + if (\preg_match('/^\d+\.\d+\.\d+\.\d+$/', $sEhloHost)) + { + $sEhloHost = '['.$sEhloHost.']'; + } + + return empty($sEhloHost) ? 'localhost' : $sEhloHost; + } + + /** + * @param string $sServerName + * @param int $iPort = 25 + * @param string $sEhloHost = '[127.0.0.1]' + * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT + * @param bool $bVerifySsl = false + * @param bool $bAllowSelfSigned = true + * + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\ResponseException + */ + public function Connect($sServerName, $iPort = 25, $sEhloHost = '[127.0.0.1]', + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, + $bVerifySsl = false, $bAllowSelfSigned = true) + { + $this->iRequestTime = microtime(true); + + parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned); + + $this->validateResponse(220); + + $this->preLoginStartTLSAndEhloProcess($sEhloHost); + + return $this; + } + + /** + * @param string $sLogin + * @param string $sPassword + * @param boolean $bUseAuthPlainIfSupported = true + * @param boolean $bUseAuthCramMd5IfSupported = true + * + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + public function Login($sLogin, $sPassword, $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true) + { + $sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin)); + + if ($bUseAuthCramMd5IfSupported && $this->IsAuthSupported('CRAM-MD5')) + { + try + { + $this->sendRequestWithCheck('AUTH', 334, 'CRAM-MD5'); + } + catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadMethodException( + $oException->GetResponses(), $oException->getMessage(), 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + + $sTicket = ''; + + $sContinuationResponse = !empty($this->aResults[0]) ? \trim($this->aResults[0]) : ''; + if ($sContinuationResponse && '334 ' === \substr($sContinuationResponse, 0, 4) && 0 < \strlen(\substr($sContinuationResponse, 4))) + { + $sTicket = @\base64_decode(\substr($sContinuationResponse, 4)); + $this->writeLogWithCrlf('ticket: '.$sTicket); + } + + if (empty($sTicket)) + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\NegativeResponseException(), + \MailSo\Log\Enumerations\Type::NOTICE, true + ); + } + + try + { + $this->sendRequestWithCheck(\base64_encode($sLogin.' '.\MailSo\Base\Utils::Hmac($sTicket, $sPassword)), 235, '', true); + } + catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( + $oException->GetResponses(), $oException->getMessage(), 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + } + else if ($bUseAuthPlainIfSupported && $this->IsAuthSupported('PLAIN')) + { + if ($this->__USE_SINGLE_LINE_AUTH_PLAIN_COMMAND) + { + try + { + $this->sendRequestWithCheck('AUTH', 235, 'PLAIN '.\base64_encode("\0".$sLogin."\0".$sPassword), true); + } + catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( + $oException->GetResponses(), $oException->getMessage(), 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + } + else + { + try + { + $this->sendRequestWithCheck('AUTH', 334, 'PLAIN'); + } + catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadMethodException( + $oException->GetResponses(), $oException->getMessage(), 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + + try + { + $this->sendRequestWithCheck(\base64_encode("\0".$sLogin."\0".$sPassword), 235, '', true); + } + catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( + $oException->GetResponses(), $oException->getMessage(), 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + } + } + else if ($this->IsAuthSupported('LOGIN')) + { + try + { + $this->sendRequestWithCheck('AUTH', 334, 'LOGIN'); + } + catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadMethodException( + $oException->GetResponses(), $oException->getMessage(), 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + + try + { + $this->sendRequestWithCheck(\base64_encode($sLogin), 334, ''); + $this->sendRequestWithCheck(\base64_encode($sPassword), 235, '', true); + } + catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( + $oException->GetResponses(), $oException->getMessage(), 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + } + else + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadMethodException(), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + + return $this; + } + + /** + * @param string $sXOAuth2Token + * + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + public function LoginWithXOauth2($sXOAuth2Token) + { + if ($this->IsAuthSupported('XOAUTH2')) + { + try + { + $this->sendRequestWithCheck('AUTH', 235, 'XOAUTH2 '.\trim($sXOAuth2Token)); + } + catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( + $oException->GetResponses(), $oException->getMessage(), 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + } + else + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadMethodException(), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + + return $this; + } + + /** + * @param string $sFrom + * @param string $sSizeIfSupported = '' + * @param bool $bDsn = false + * + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + public function MailFrom($sFrom, $sSizeIfSupported = '', $bDsn = false) + { + $sFrom = \MailSo\Base\Utils::IdnToAscii( + \MailSo\Base\Utils::Trim($sFrom), true); + + $sCmd = 'FROM:<'.$sFrom.'>'; + + $sSizeIfSupported = (string) $sSizeIfSupported; + if (0 < \strlen($sSizeIfSupported) && \is_numeric($sSizeIfSupported) && $this->IsSupported('SIZE')) + { + $sCmd .= ' SIZE='.$sSizeIfSupported; + } + + if ($bDsn && $this->IsSupported('DSN')) + { + $sCmd .= ' RET=HDRS'; + } + + $this->sendRequestWithCheck('MAIL', 250, $sCmd); + + $this->bMail = true; + $this->bRcpt = false; + $this->bData = false; + + return $this; + } + + /** + * @param string $sTo + * @param bool $bDsn = false + * + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + public function Rcpt($sTo, $bDsn = false) + { + if (!$this->bMail) + { + $this->writeLogException( + new Exceptions\RuntimeException('No sender reverse path has been supplied'), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $sTo = \MailSo\Base\Utils::IdnToAscii( + \MailSo\Base\Utils::Trim($sTo), true); + + $sCmd = 'TO:<'.$sTo.'>'; + + if ($bDsn && $this->IsSupported('DSN')) + { + $sCmd .= ' NOTIFY=SUCCESS,FAILURE'; + } + + $this->sendRequestWithCheck( + 'RCPT', array(250, 251), $sCmd, false, + 'Failed to add recipient "'.$sTo.'"' + ); + + $this->bRcpt = true; + + return $this; + } + + /** + * @param string $sTo + * + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + public function MailTo($sTo) + { + return $this->Rcpt($sTo); + } + + /** + * @param string $sData + * + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + public function Data($sData) + { + if (!\MailSo\Base\Validator::NotEmptyString($sData, true)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $rDataStream = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($sData); + unset($sData); + $this->DataWithStream($rDataStream); + \MailSo\Base\ResourceRegistry::CloseMemoryResource($rDataStream); + + return $this; + } + + /** + * @param resource $rDataStream + * + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + public function DataWithStream($rDataStream) + { + if (!\is_resource($rDataStream)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + if (!$this->bRcpt) + { + $this->writeLogException( + new Exceptions\RuntimeException('No recipient forward path has been supplied'), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $this->sendRequestWithCheck('DATA', 354); + + $this->writeLog('Message data.', \MailSo\Log\Enumerations\Type::NOTE); + + $this->bRunningCallback = true; + + while (!\feof($rDataStream)) + { + $sBuffer = \fgets($rDataStream); + if (false !== $sBuffer) + { + if (0 === \strpos($sBuffer, '.')) + { + $sBuffer = '.'.$sBuffer; + } + + $this->sendRaw(\rtrim($sBuffer, "\r\n"), false); + + \MailSo\Base\Utils::ResetTimeLimit(); + continue; + } + else if (!\feof($rDataStream)) + { + $this->writeLogException( + new Exceptions\RuntimeException('Cannot read input resource'), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + break; + } + + $this->sendRequestWithCheck('.', 250); + + $this->bRunningCallback = false; + + $this->bData = true; + + return $this; + } + + /** + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + public function Rset() + { + $this->sendRequestWithCheck('RSET', array(250, 220)); + + $this->bMail = false; + $this->bRcpt = false; + $this->bData = false; + + return $this; + } + + /** + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + public function Vrfy($sUser) + { + $sUser = \MailSo\Base\Utils::IdnToAscii( + \MailSo\Base\Utils::Trim($sUser)); + + $this->sendRequestWithCheck('VRFY', array(250, 251, 252), $sUser); + + return $this; + } + + /** + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + public function Noop() + { + $this->sendRequestWithCheck('NOOP', 250); + + return $this; + } + + /** + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + public function Logout() + { + if ($this->IsConnected()) + { + $this->sendRequestWithCheck('QUIT', 221); + } + + $this->bHelo = false; + $this->bMail = false; + $this->bRcpt = false; + $this->bData = false; + + return $this; + } + + /** + * @param string $sEhloHost + * + * @return void + */ + private function preLoginStartTLSAndEhloProcess($sEhloHost) + { + if ($this->bHelo) + { + $this->writeLogException( + new Exceptions\RuntimeException('Cannot issue EHLO/HELO to existing session'), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $this->ehloOrHelo($sEhloHost); + + if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS( + $this->IsSupported('STARTTLS'), $this->iSecurityType, $this->HasSupportedAuth())) + { + $this->sendRequestWithCheck('STARTTLS', 220); + $this->EnableCrypto(); + + $this->ehloOrHelo($sEhloHost); + } + else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType) + { + $this->writeLogException( + new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $this->bHelo = true; + } + + /** + * @param string $sCommand + * @param string $sAddToCommand = '' + * @param bool $bSecureLog = false + * + * @return void + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + */ + private function sendRequest($sCommand, $sAddToCommand = '', $bSecureLog = false) + { + if (!\MailSo\Base\Validator::NotEmptyString($sCommand, true)) + { + $this->writeLogException( + new \MailSo\Base\Exceptions\InvalidArgumentException(), + \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $this->IsConnected(true); + + $sCommand = \trim($sCommand); + $sRealCommand = $sCommand.(0 === \strlen($sAddToCommand) ? '' : ' '.$sAddToCommand); + + $sFakeCommand = ($bSecureLog) ? '********' : ''; + + $this->iRequestTime = \microtime(true); + $this->sendRaw($sRealCommand, true, $sFakeCommand); + + return $this; + } + + /** + * @param string $sCommand + * @param int|array $mExpectCode + * @param string $sAddToCommand = '' + * @param bool $bSecureLog = false + * @param string $sErrorPrefix = '' + * + * @return void + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + private function sendRequestWithCheck($sCommand, $mExpectCode, $sAddToCommand = '', $bSecureLog = false, $sErrorPrefix = '') + { + $this->sendRequest($sCommand, $sAddToCommand, $bSecureLog); + $this->validateResponse($mExpectCode, $sErrorPrefix); + } + + /** + * @param string $sHost + * + * @return void + */ + private function ehloOrHelo($sHost) + { + try + { + $this->ehlo($sHost); + } + catch (\Exception $oException) + { + try + { + $this->helo($sHost); + } + catch (\Exception $oException) + { + throw $oException; + } + } + + return $this; + } + + /** + * @param string $sHost + * + * @return void + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + private function ehlo($sHost) + { + $this->sendRequestWithCheck('EHLO', 250, $sHost); + + foreach ($this->aResults as $sLine) + { + $aMatch = array(); + if (\preg_match('/[\d]+[ \-](.+)$/', $sLine, $aMatch) && isset($aMatch[1]) && 0 < \strlen($aMatch[1])) + { + $sLine = \trim($aMatch[1]); + $aLine = \preg_split('/[ =]/', $sLine, 2); + if (\is_array($aLine) && 0 < \count($aLine) && !empty($aLine[0])) + { + $sCapa = \strtoupper($aLine[0]); + if (('AUTH' === $sCapa || 'SIZE' === $sCapa) && !empty($aLine[1])) + { + $sSubLine = \trim(\strtoupper($aLine[1])); + if (0 < \strlen($sSubLine)) + { + if ('AUTH' === $sCapa) + { + $this->aAuthTypes = \explode(' ', $sSubLine); + } + else if ('SIZE' === $sCapa && \is_numeric($sSubLine)) + { + $this->iSizeCapaValue = (int) $sSubLine; + } + } + } + + $this->aCapa[] = $sCapa; + } + } + } + } + + /** + * @param string $sHost + * + * @return void + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Smtp\Exceptions\Exception + */ + private function helo($sHost) + { + $this->sendRequestWithCheck('HELO', 250, $sHost); + $this->aAuthTypes = array(); + $this->iSizeCapaValue = 0; + $this->aCapa = array(); + } + + /** + * @param int|array $mExpectCode + * @param string $sErrorPrefix = '' + * + * @return void + * + * @throws \MailSo\Smtp\Exceptions\ResponseException + */ + private function validateResponse($mExpectCode, $sErrorPrefix = '') + { + if (!\is_array($mExpectCode)) + { + $mExpectCode = array((int) $mExpectCode); + } + else + { + $mExpectCode = \array_map('intval', $mExpectCode); + } + + $aParts = array('', '', ''); + $this->aResults = array(); + do + { + $this->getNextBuffer(); + $aParts = \preg_split('/([\s\-]+)/', $this->sResponseBuffer, 2, PREG_SPLIT_DELIM_CAPTURE); + + if (\is_array($aParts) && 3 === \count($aParts) && \is_numeric($aParts[0])) + { + if ('-' !== \substr($aParts[1], 0, 1) && !\in_array((int) $aParts[0], $mExpectCode)) + { + $this->writeLogException( + new Exceptions\NegativeResponseException($this->aResults, + ('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim( + (0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : ''). + $this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true); + } + } + else + { + $this->writeLogException( + new Exceptions\ResponseException($this->aResults, + ('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim( + (0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : ''). + $this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true); + } + + $this->aResults[] = $this->sResponseBuffer; + } + while ('-' === \substr($aParts[1], 0, 1)); + + $this->writeLog((microtime(true) - $this->iRequestTime), + \MailSo\Log\Enumerations\Type::TIME); + } + + /** + * @return string + */ + protected function getLogName() + { + return 'SMTP'; + } + + /** + * @param \MailSo\Log\Logger $oLogger + * + * @return \MailSo\Smtp\SmtpClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function SetLogger($oLogger) + { + parent::SetLogger($oLogger); + + return $this; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Vendors/Net/IDNA2.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Vendors/Net/IDNA2.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Vendors/Net/IDNA2.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Vendors/Net/IDNA2.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Version.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Version.php similarity index 93% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Version.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Version.php index fd79b51d..f17b2871 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Version.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/MailSo/Version.php @@ -1,59 +1,59 @@ -getSignature(); - } - - return $sSignature; - } -} +getSignature(); + } + + return $sSignature; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/LICENSE.txt b/rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/LICENSE.txt similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/LICENSE.txt rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/LICENSE.txt diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/Mobile_Detect.json b/rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/Mobile_Detect.json similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/Mobile_Detect.json rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/Mobile_Detect.json diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/Mobile_Detect.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/Mobile_Detect.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/Mobile_Detect.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/Mobile_Detect.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/README.md b/rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/README.md similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/README.md rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/README.md diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/composer.json b/rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/composer.json similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/composer.json rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/composer.json diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/namespaced/Detection/MobileDetect.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/namespaced/Detection/MobileDetect.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/namespaced/Detection/MobileDetect.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/namespaced/Detection/MobileDetect.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/ruleset.xml b/rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/ruleset.xml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/ruleset.xml rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Mobile_Detect/ruleset.xml diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/Client.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/Client.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/Client.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/Client.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/ClientCredentials.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/GrantType/ClientCredentials.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/ClientCredentials.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/GrantType/ClientCredentials.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/IGrantType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/GrantType/IGrantType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/IGrantType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/GrantType/IGrantType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/Password.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/GrantType/Password.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/Password.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/GrantType/Password.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/RefreshToken.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/GrantType/RefreshToken.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/RefreshToken.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/GrantType/RefreshToken.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/README b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/README similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/README rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHP-OAuth2/README diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPGangsta/GoogleAuthenticator.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHPGangsta/GoogleAuthenticator.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHPGangsta/GoogleAuthenticator.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHPGangsta/GoogleAuthenticator.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/GD.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHPThumb/GD.php similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/GD.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHPThumb/GD.php index 733fe476..53469eda 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/GD.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHPThumb/GD.php @@ -1,1417 +1,1417 @@ - - * Copyright (c) 2009, Ian Selby/Gen X Design - * - * Author(s): Ian Selby - * - * Licensed under the MIT License - * Redistributions of files must retain the above copyright notice. - * - * @author Ian Selby - * @copyright Copyright (c) 2009 Gen X Design - * @link http://phpthumb.gxdlabs.com - * @license http://www.opensource.org/licenses/mit-license.php The MIT License - */ - -class GD extends PHPThumb -{ - /** - * The prior image (before manipulation) - * - * @var resource - */ - protected $oldImage; - - /** - * The working image (used during manipulation) - * - * @var resource - */ - protected $workingImage; - - /** - * The current dimensions of the image - * - * @var array - */ - protected $currentDimensions; - - /** - * The new, calculated dimensions of the image - * - * @var array - */ - protected $newDimensions; - - /** - * The options for this class - * - * This array contains various options that determine the behavior in - * various functions throughout the class. Functions note which specific - * option key / values are used in their documentation - * - * @var array - */ - protected $options; - - /** - * The maximum width an image can be after resizing (in pixels) - * - * @var int - */ - protected $maxWidth; - - /** - * The maximum height an image can be after resizing (in pixels) - * - * @var int - */ - protected $maxHeight; - - /** - * The percentage to resize the image by - * - * @var int - */ - protected $percent; - - /** - * @param string $fileName - * @param array $options - * @param array $plugins - */ - public function __construct($fileName, $options = array(), array $plugins = array()) - { - parent::__construct($fileName, $options, $plugins); - - $this->determineFormat(); - $this->verifyFormatCompatiblity(); - - switch ($this->format) { - case 'GIF': - $this->oldImage = @imagecreatefromgif($this->fileName); - break; - case 'JPG': - $this->oldImage = @imagecreatefromjpeg($this->fileName); - break; - case 'PNG': - $this->oldImage = @imagecreatefrompng($this->fileName); - break; - case 'STRING': - $this->oldImage = @imagecreatefromstring($this->fileName); - break; - } - - if (!is_resource($this->oldImage)) - { - throw new \Exception('Invalid image file'); - } - else - { - $this->currentDimensions = array ( - 'width' => imagesx($this->oldImage), - 'height' => imagesy($this->oldImage) - ); - } - } - - public function __destruct() - { - if (is_resource($this->oldImage)) { - imagedestroy($this->oldImage); - } - - if (is_resource($this->workingImage)) { - imagedestroy($this->workingImage); - } - } - - /** - * Pad an image to desired dimensions. Moves the image into the center and fills the rest with $color. - * @param $width - * @param $height - * @param array $color - * @return GD - */ - public function pad($width, $height, $color = array(255, 255, 255)) - { - // no resize - woohoo! - if ($width == $this->currentDimensions['width'] && $height == $this->currentDimensions['height']) { - return $this; - } - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($width, $height); - } else { - $this->workingImage = imagecreate($width, $height); - } - - // create the fill color - $fillColor = imagecolorallocate( - $this->workingImage, - $color[0], - $color[1], - $color[2] - ); - - // fill our working image with the fill color - imagefill( - $this->workingImage, - 0, - 0, - $fillColor - ); - - // copy the image into the center of our working image - imagecopyresampled( - $this->workingImage, - $this->oldImage, - intval(($width-$this->currentDimensions['width']) / 2), - intval(($height-$this->currentDimensions['height']) / 2), - 0, - 0, - $this->currentDimensions['width'], - $this->currentDimensions['height'], - $this->currentDimensions['width'], - $this->currentDimensions['height'] - ); - - // update all the variables and resources to be correct - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $width; - $this->currentDimensions['height'] = $height; - - return $this; - } - - /** - * Resizes an image to be no larger than $maxWidth or $maxHeight - * - * If either param is set to zero, then that dimension will not be considered as a part of the resize. - * Additionally, if $this->options['resizeUp'] is set to true (false by default), then this function will - * also scale the image up to the maximum dimensions provided. - * - * @param int $maxWidth The maximum width of the image in pixels - * @param int $maxHeight The maximum height of the image in pixels - * @return \PHPThumb\GD - */ - public function resize($maxWidth = 0, $maxHeight = 0) - { - // make sure our arguments are valid - if (!is_numeric($maxWidth)) { - throw new \InvalidArgumentException('$maxWidth must be numeric'); - } - - if (!is_numeric($maxHeight)) { - throw new \InvalidArgumentException('$maxHeight must be numeric'); - } - - // make sure we're not exceeding our image size if we're not supposed to - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($maxHeight) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $maxHeight; - $this->maxWidth = (intval($maxWidth) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $maxWidth; - } else { - $this->maxHeight = intval($maxHeight); - $this->maxWidth = intval($maxWidth); - } - - // get the new dimensions... - $this->calcImageSize($this->currentDimensions['width'], $this->currentDimensions['height']); - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - } else { - $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - } - - $this->preserveAlpha(); - - // and create the newly sized image - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - 0, - 0, - $this->newDimensions['newWidth'], - $this->newDimensions['newHeight'], - $this->currentDimensions['width'], - $this->currentDimensions['height'] - ); - - // update all the variables and resources to be correct - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $this->newDimensions['newWidth']; - $this->currentDimensions['height'] = $this->newDimensions['newHeight']; - - return $this; - } - - /** - * Adaptively Resizes the Image - * - * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the - * remaining overflow (from the center) to get the image to be the size specified - * - * @param int $maxWidth - * @param int $maxHeight - * @return \PHPThumb\GD - */ - public function adaptiveResize($width, $height) - { - // make sure our arguments are valid - if ((!is_numeric($width) || $width == 0) && (!is_numeric($height) || $height == 0)) { - throw new \InvalidArgumentException('$width and $height must be numeric and greater than zero'); - } - - if (!is_numeric($width) || $width == 0) { - $width = ($height * $this->currentDimensions['width']) / $this->currentDimensions['height']; - } - - if (!is_numeric($height) || $height == 0) { - $height = ($width * $this->currentDimensions['height']) / $this->currentDimensions['width']; - } - - // make sure we're not exceeding our image size if we're not supposed to - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); - - // resize the image to be close to our desired dimensions - $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - - // reset the max dimensions... - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); - } else { - $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); - } - - $this->preserveAlpha(); - - $cropWidth = $this->maxWidth; - $cropHeight = $this->maxHeight; - $cropX = 0; - $cropY = 0; - - // now, figure out how to crop the rest of the image... - if ($this->currentDimensions['width'] > $this->maxWidth) { - $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2); - } elseif ($this->currentDimensions['height'] > $this->maxHeight) { - $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2); - } - - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - $cropX, - $cropY, - $cropWidth, - $cropHeight, - $cropWidth, - $cropHeight - ); - - // update all the variables and resources to be correct - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $this->maxWidth; - $this->currentDimensions['height'] = $this->maxHeight; - - return $this; - } - - /** - * Adaptively Resizes the Image and Crops Using a Percentage - * - * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the - * remaining overflow using a provided percentage to get the image to be the size specified. - * - * The percentage mean different things depending on the orientation of the original image. - * - * For Landscape images: - * --------------------- - * - * A percentage of 1 would crop the image all the way to the left, which would be the same as - * using adaptiveResizeQuadrant() with $quadrant = 'L' - * - * A percentage of 50 would crop the image to the center which would be the same as using - * adaptiveResizeQuadrant() with $quadrant = 'C', or even the original adaptiveResize() - * - * A percentage of 100 would crop the image to the image all the way to the right, etc, etc. - * Note that you can use any percentage between 1 and 100. - * - * For Portrait images: - * -------------------- - * - * This works the same as for Landscape images except that a percentage of 1 means top and 100 means bottom - * - * @param int $maxWidth - * @param int $maxHeight - * @param int $percent - * @return \PHPThumb\GD - */ - public function adaptiveResizePercent($width, $height, $percent = 50) - { - // make sure our arguments are valid - if (!is_numeric($width) || $width == 0) { - throw new \InvalidArgumentException('$width must be numeric and greater than zero'); - } - - if (!is_numeric($height) || $height == 0) { - throw new \InvalidArgumentException('$height must be numeric and greater than zero'); - } - - // make sure we're not exceeding our image size if we're not supposed to - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); - - // resize the image to be close to our desired dimensions - $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - - // reset the max dimensions... - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); - } else { - $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); - } - - $this->preserveAlpha(); - - $cropWidth = $this->maxWidth; - $cropHeight = $this->maxHeight; - $cropX = 0; - $cropY = 0; - - // Crop the rest of the image using the quadrant - - if ($percent > 100) { - $percent = 100; - } elseif ($percent < 1) { - $percent = 1; - } - - if ($this->currentDimensions['width'] > $this->maxWidth) { - // Image is landscape - $maxCropX = $this->currentDimensions['width'] - $this->maxWidth; - $cropX = intval(($percent / 100) * $maxCropX); - - } elseif ($this->currentDimensions['height'] > $this->maxHeight) { - // Image is portrait - $maxCropY = $this->currentDimensions['height'] - $this->maxHeight; - $cropY = intval(($percent / 100) * $maxCropY); - } - - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - $cropX, - $cropY, - $cropWidth, - $cropHeight, - $cropWidth, - $cropHeight - ); - - // update all the variables and resources to be correct - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $this->maxWidth; - $this->currentDimensions['height'] = $this->maxHeight; - - return $this; - } - - /** - * Adaptively Resizes the Image and Crops Using a Quadrant - * - * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the - * remaining overflow using the quadrant to get the image to be the size specified. - * - * The quadrants available are Top, Bottom, Center, Left, and Right: - * - * - * +---+---+---+ - * | | T | | - * +---+---+---+ - * | L | C | R | - * +---+---+---+ - * | | B | | - * +---+---+---+ - * - * Note that if your image is Landscape and you choose either of the Top or Bottom quadrants (which won't - * make sence since only the Left and Right would be available, then the Center quadrant will be used - * to crop. This would have exactly the same result as using adaptiveResize(). - * The same goes if your image is portrait and you choose either the Left or Right quadrants. - * - * @param int $maxWidth - * @param int $maxHeight - * @param string $quadrant T, B, C, L, R - * @return \PHPThumb\GD - */ - public function adaptiveResizeQuadrant($width, $height, $quadrant = 'C') - { - // make sure our arguments are valid - if (!is_numeric($width) || $width == 0) { - throw new \InvalidArgumentException('$width must be numeric and greater than zero'); - } - - if (!is_numeric($height) || $height == 0) { - throw new \InvalidArgumentException('$height must be numeric and greater than zero'); - } - - // make sure we're not exceeding our image size if we're not supposed to - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); - - // resize the image to be close to our desired dimensions - $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - - // reset the max dimensions... - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); - } else { - $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); - } - - $this->preserveAlpha(); - - $cropWidth = $this->maxWidth; - $cropHeight = $this->maxHeight; - $cropX = 0; - $cropY = 0; - - // Crop the rest of the image using the quadrant - - if ($this->currentDimensions['width'] > $this->maxWidth) { - // Image is landscape - switch ($quadrant) { - case 'L': - $cropX = 0; - break; - case 'R': - $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth)); - break; - case 'C': - default: - $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2); - break; - } - } elseif ($this->currentDimensions['height'] > $this->maxHeight) { - // Image is portrait - switch ($quadrant) { - case 'T': - $cropY = 0; - break; - case 'B': - $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight)); - break; - case 'C': - default: - $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2); - break; - } - } - - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - $cropX, - $cropY, - $cropWidth, - $cropHeight, - $cropWidth, - $cropHeight - ); - - // update all the variables and resources to be correct - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $this->maxWidth; - $this->currentDimensions['height'] = $this->maxHeight; - - return $this; - } - - /** - * Resizes an image by a given percent uniformly, - * Percentage should be whole number representation (i.e. 1-100) - * - * @param int $percent - * @return GD - * @throws \InvalidArgumentException - */ - public function resizePercent($percent = 0) - { - if (!is_numeric($percent)) { - throw new \InvalidArgumentException ('$percent must be numeric'); - } - - $this->percent = intval($percent); - - $this->calcImageSizePercent($this->currentDimensions['width'], $this->currentDimensions['height']); - - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - } else { - $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - } - - $this->preserveAlpha(); - - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - 0, - 0, - $this->newDimensions['newWidth'], - $this->newDimensions['newHeight'], - $this->currentDimensions['width'], - $this->currentDimensions['height'] - ); - - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $this->newDimensions['newWidth']; - $this->currentDimensions['height'] = $this->newDimensions['newHeight']; - - return $this; - } - - /** - * Crops an image from the center with provided dimensions - * - * If no height is given, the width will be used as a height, thus creating a square crop - * - * @param int $cropWidth - * @param int $cropHeight - * @return \PHPThumb\GD - */ - public function cropFromCenter($cropWidth, $cropHeight = null) - { - if (!is_numeric($cropWidth)) { - throw new \InvalidArgumentException('$cropWidth must be numeric'); - } - - if ($cropHeight !== null && !is_numeric($cropHeight)) { - throw new \InvalidArgumentException('$cropHeight must be numeric'); - } - - if ($cropHeight === null) { - $cropHeight = $cropWidth; - } - - $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth; - $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight; - - $cropX = intval(($this->currentDimensions['width'] - $cropWidth) / 2); - $cropY = intval(($this->currentDimensions['height'] - $cropHeight) / 2); - - $this->crop($cropX, $cropY, $cropWidth, $cropHeight); - - return $this; - } - - /** - * Vanilla Cropping - Crops from x,y with specified width and height - * - * @param int $startX - * @param int $startY - * @param int $cropWidth - * @param int $cropHeight - * @return \PHPThumb\GD - */ - public function crop($startX, $startY, $cropWidth, $cropHeight) - { - // validate input - if (!is_numeric($startX)) { - throw new \InvalidArgumentException('$startX must be numeric'); - } - - if (!is_numeric($startY)) { - throw new \InvalidArgumentException('$startY must be numeric'); - } - - if (!is_numeric($cropWidth)) { - throw new \InvalidArgumentException('$cropWidth must be numeric'); - } - - if (!is_numeric($cropHeight)) { - throw new \InvalidArgumentException('$cropHeight must be numeric'); - } - - // do some calculations - $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth; - $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight; - - // ensure everything's in bounds - if (($startX + $cropWidth) > $this->currentDimensions['width']) { - $startX = ($this->currentDimensions['width'] - $cropWidth); - } - - if (($startY + $cropHeight) > $this->currentDimensions['height']) { - $startY = ($this->currentDimensions['height'] - $cropHeight); - } - - if ($startX < 0) { - $startX = 0; - } - - if ($startY < 0) { - $startY = 0; - } - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($cropWidth, $cropHeight); - } else { - $this->workingImage = imagecreate($cropWidth, $cropHeight); - } - - $this->preserveAlpha(); - - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - $startX, - $startY, - $cropWidth, - $cropHeight, - $cropWidth, - $cropHeight - ); - - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $cropWidth; - $this->currentDimensions['height'] = $cropHeight; - - return $this; - } - - /** - * Rotates image either 90 degrees clockwise or counter-clockwise - * - * @param string $direction - * @retunrn \PHPThumb\GD - */ - public function rotateImage($direction = 'CW') - { - if ($direction == 'CW') { - $this->rotateImageNDegrees(90); - } else { - $this->rotateImageNDegrees(-90); - } - - return $this; - } - - /** - * Rotates image specified number of degrees - * - * @param int $degrees - * @return \PHPThumb\GD - */ - public function rotateImageNDegrees($degrees) - { - if (!is_numeric($degrees)) { - throw new \InvalidArgumentException('$degrees must be numeric'); - } - - if (!function_exists('imagerotate')) { - throw new \RuntimeException('Your version of GD does not support image rotation'); - } - - $this->workingImage = imagerotate($this->oldImage, $degrees, 0); - - $newWidth = $this->currentDimensions['height']; - $newHeight = $this->currentDimensions['width']; - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $newWidth; - $this->currentDimensions['height'] = $newHeight; - - return $this; - } - - /** - * Applies a filter to the image - * - * @param int $filter - * @return \PHPThumb\GD - */ - public function imageFilter($filter, $arg1 = false, $arg2 = false, $arg3 = false, $arg4 = false) - { - if (!is_numeric($filter)) { - throw new \InvalidArgumentException('$filter must be numeric'); - } - - if (!function_exists('imagefilter')) { - throw new \RuntimeException('Your version of GD does not support image filters'); - } - - $result = false; - if ($arg1 === false) { - $result = imagefilter($this->oldImage, $filter); - } elseif ($arg2 === false) { - $result = imagefilter($this->oldImage, $filter, $arg1); - } elseif ($arg3 === false) { - $result = imagefilter($this->oldImage, $filter, $arg1, $arg2); - } elseif ($arg4 === false) { - $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3); - } else { - $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3, $arg4); - } - - if (!$result) { - throw new \RuntimeException('GD imagefilter failed'); - } - - $this->workingImage = $this->oldImage; - - return $this; - } - - /** - * Shows an image - * - * This function will show the current image by first sending the appropriate header - * for the format, and then outputting the image data. If headers have already been sent, - * a runtime exception will be thrown - * - * @param bool $rawData Whether or not the raw image stream should be output - * @return \PHPThumb\GD - */ - public function show($rawData = false) - { - //Execute any plugins - if ($this->plugins) { - foreach ($this->plugins as $plugin) { - /* @var $plugin \PHPThumb\PluginInterface */ - $plugin->execute($this); - } - } - - if (headers_sent() && php_sapi_name() != 'cli') { - throw new \RuntimeException('Cannot show image, headers have already been sent'); - } - - // When the interlace option equals true or false call imageinterlace else leave it to default - if ($this->options['interlace'] === true) { - imageinterlace($this->oldImage, 1); - } elseif ($this->options['interlace'] === false) { - imageinterlace($this->oldImage, 0); - } - - switch ($this->format) { - case 'GIF': - if ($rawData === false) { - header('Content-type: image/gif'); - } - imagegif($this->oldImage); - break; - case 'JPG': - if ($rawData === false) { - header('Content-type: image/jpeg'); - } - imagejpeg($this->oldImage, null, $this->options['jpegQuality']); - break; - case 'PNG': - case 'STRING': - if ($rawData === false) { - header('Content-type: image/png'); - } - imagepng($this->oldImage); - break; - } - - return $this; - } - - /** - * Returns the Working Image as a String - * - * This function is useful for getting the raw image data as a string for storage in - * a database, or other similar things. - * - * @return string - */ - public function getImageAsString() - { - $data = null; - ob_start(); - $this->show(true); - $data = ob_get_contents(); - ob_end_clean(); - - return $data; - } - - /** - * Saves an image - * - * This function will make sure the target directory is writeable, and then save the image. - * - * If the target directory is not writeable, the function will try to correct the permissions (if allowed, this - * is set as an option ($this->options['correctPermissions']). If the target cannot be made writeable, then a - * \RuntimeException is thrown. - * - * @param string $fileName The full path and filename of the image to save - * @param string $format The format to save the image in (optional, must be one of [GIF,JPG,PNG] - * @return \PHPThumb\GD - */ - public function save($fileName, $format = null) - { - $validFormats = array('GIF', 'JPG', 'PNG'); - $format = ($format !== null) ? strtoupper($format) : $this->format; - - if (!in_array($format, $validFormats)) { - throw new \InvalidArgumentException("Invalid format type specified in save function: {$format}"); - } - - // make sure the directory is writeable - if (!is_writeable(dirname($fileName))) { - // try to correct the permissions - if ($this->options['correctPermissions'] === true) { - @chmod(dirname($fileName), 0777); - - // throw an exception if not writeable - if (!is_writeable(dirname($fileName))) { - throw new \RuntimeException("File is not writeable, and could not correct permissions: {$fileName}"); - } - } else { // throw an exception if not writeable - throw new \RuntimeException("File not writeable: {$fileName}"); - } - } - - // When the interlace option equals true or false call imageinterlace else leave it to default - if ($this->options['interlace'] === true) { - imageinterlace($this->oldImage, 1); - } elseif ($this->options['interlace'] === false) { - imageinterlace($this->oldImage, 0); - } - - switch ($format) { - case 'GIF': - imagegif($this->oldImage, $fileName); - break; - case 'JPG': - imagejpeg($this->oldImage, $fileName, $this->options['jpegQuality']); - break; - case 'PNG': - imagepng($this->oldImage, $fileName); - break; - } - - return $this; - } - - ################################# - # ----- GETTERS / SETTERS ----- # - ################################# - - /** - * Sets options for all operations. - * @param array $options - * @return GD - */ - public function setOptions(array $options = array()) - { - // we've yet to init the default options, so create them here - if (sizeof($this->options) == 0) { - $defaultOptions = array( - 'resizeUp' => false, - 'jpegQuality' => 100, - 'correctPermissions' => false, - 'preserveAlpha' => true, - 'alphaMaskColor' => array (255, 255, 255), - 'preserveTransparency' => true, - 'transparencyMaskColor' => array (0, 0, 0), - 'interlace' => null - ); - } else { // otherwise, let's use what we've got already - $defaultOptions = $this->options; - } - - $this->options = array_merge($defaultOptions, $options); - - return $this; - } - - /** - * Returns $currentDimensions. - * - * @see \PHPThumb\GD::$currentDimensions - */ - public function getCurrentDimensions() - { - return $this->currentDimensions; - } - - /** - * @param $currentDimensions - * @return GD - */ - public function setCurrentDimensions($currentDimensions) - { - $this->currentDimensions = $currentDimensions; - - return $this; - } - - /** - * @return int - */ - public function getMaxHeight() - { - return $this->maxHeight; - } - - /** - * @param $maxHeight - * @return GD - */ - public function setMaxHeight($maxHeight) - { - $this->maxHeight = $maxHeight; - - return $this; - } - - /** - * @return int - */ - public function getMaxWidth() - { - return $this->maxWidth; - } - - /** - * @param $maxWidth - * @return GD - */ - public function setMaxWidth($maxWidth) - { - $this->maxWidth = $maxWidth; - - return $this; - } - - /** - * Returns $newDimensions. - * - * @see \PHPThumb\GD::$newDimensions - */ - public function getNewDimensions() - { - return $this->newDimensions; - } - - /** - * Sets $newDimensions. - * - * @param object $newDimensions - * @see \PHPThumb\GD::$newDimensions - */ - public function setNewDimensions($newDimensions) - { - $this->newDimensions = $newDimensions; - - return $this; - } - - /** - * Returns $options. - * - * @see \PHPThumb\GD::$options - */ - public function getOptions() - { - return $this->options; - } - - /** - * Returns $percent. - * - * @see \PHPThumb\GD::$percent - */ - public function getPercent() - { - return $this->percent; - } - - /** - * Sets $percent. - * - * @param object $percent - * @see \PHPThumb\GD::$percent - */ - public function setPercent($percent) - { - $this->percent = $percent; - - return $this; - } - - /** - * Returns $oldImage. - * - * @see \PHPThumb\GD::$oldImage - */ - public function getOldImage() - { - return $this->oldImage; - } - - /** - * Sets $oldImage. - * - * @param object $oldImage - * @see \PHPThumb\GD::$oldImage - */ - public function setOldImage($oldImage) - { - $this->oldImage = $oldImage; - - return $this; - } - - /** - * Returns $workingImage. - * - * @see \PHPThumb\GD::$workingImage - */ - public function getWorkingImage() - { - return $this->workingImage; - } - - /** - * Sets $workingImage. - * - * @param object $workingImage - * @see \PHPThumb\GD::$workingImage - */ - public function setWorkingImage($workingImage) - { - $this->workingImage = $workingImage; - - return $this; - } - - - ################################# - # ----- UTILITY FUNCTIONS ----- # - ################################# - - /** - * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions - * - * @return array - * @param int $width - * @param int $height - */ - protected function calcWidth($width, $height) - { - $newWidthPercentage = (100 * $this->maxWidth) / $width; - $newHeight = ($height * $newWidthPercentage) / 100; - - return array( - 'newWidth' => intval($this->maxWidth), - 'newHeight' => intval($newHeight) - ); - } - - /** - * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions - * - * @return array - * @param int $width - * @param int $height - */ - protected function calcHeight($width, $height) - { - $newHeightPercentage = (100 * $this->maxHeight) / $height; - $newWidth = ($width * $newHeightPercentage) / 100; - - return array( - 'newWidth' => ceil($newWidth), - 'newHeight' => ceil($this->maxHeight) - ); - } - - /** - * Calculates a new width and height for the image based on $this->percent and the provided dimensions - * - * @return array - * @param int $width - * @param int $height - */ - protected function calcPercent($width, $height) - { - $newWidth = ($width * $this->percent) / 100; - $newHeight = ($height * $this->percent) / 100; - - return array( - 'newWidth' => ceil($newWidth), - 'newHeight' => ceil($newHeight) - ); - } - - /** - * Calculates the new image dimensions - * - * These calculations are based on both the provided dimensions and $this->maxWidth and $this->maxHeight - * - * @param int $width - * @param int $height - */ - protected function calcImageSize($width, $height) - { - $newSize = array( - 'newWidth' => $width, - 'newHeight' => $height - ); - - if ($this->maxWidth > 0) { - $newSize = $this->calcWidth($width, $height); - - if ($this->maxHeight > 0 && $newSize['newHeight'] > $this->maxHeight) { - $newSize = $this->calcHeight($newSize['newWidth'], $newSize['newHeight']); - } - } - - if ($this->maxHeight > 0) { - $newSize = $this->calcHeight($width, $height); - - if ($this->maxWidth > 0 && $newSize['newWidth'] > $this->maxWidth) { - $newSize = $this->calcWidth($newSize['newWidth'], $newSize['newHeight']); - } - } - - $this->newDimensions = $newSize; - } - - /** - * Calculates new image dimensions, not allowing the width and height to be less than either the max width or height - * - * @param int $width - * @param int $height - */ - protected function calcImageSizeStrict($width, $height) - { - // first, we need to determine what the longest resize dimension is.. - if ($this->maxWidth >= $this->maxHeight) { - // and determine the longest original dimension - if ($width > $height) { - $newDimensions = $this->calcHeight($width, $height); - - if ($newDimensions['newWidth'] < $this->maxWidth) { - $newDimensions = $this->calcWidth($width, $height); - } - } elseif ($height >= $width) { - $newDimensions = $this->calcWidth($width, $height); - - if ($newDimensions['newHeight'] < $this->maxHeight) { - $newDimensions = $this->calcHeight($width, $height); - } - } - } elseif ($this->maxHeight > $this->maxWidth) { - if ($width >= $height) { - $newDimensions = $this->calcWidth($width, $height); - - if ($newDimensions['newHeight'] < $this->maxHeight) { - $newDimensions = $this->calcHeight($width, $height); - } - } elseif ($height > $width) { - $newDimensions = $this->calcHeight($width, $height); - - if ($newDimensions['newWidth'] < $this->maxWidth) { - $newDimensions = $this->calcWidth($width, $height); - } - } - } - - $this->newDimensions = $newDimensions; - } - - /** - * Calculates new dimensions based on $this->percent and the provided dimensions - * - * @param int $width - * @param int $height - */ - protected function calcImageSizePercent($width, $height) - { - if ($this->percent > 0) { - $this->newDimensions = $this->calcPercent($width, $height); - } - } - - /** - * Determines the file format by mime-type - * - * This function will throw exceptions for invalid images / mime-types - * - */ - protected function determineFormat() - { - $formatInfo = getimagesize($this->fileName); - - // non-image files will return false - if ($formatInfo === false) { - if ($this->remoteImage) { - throw new \Exception("Could not determine format of remote image: {$this->fileName}"); - } else { - throw new \Exception("File is not a valid image: {$this->fileName}"); - } - } - - $mimeType = isset($formatInfo['mime']) ? $formatInfo['mime'] : null; - - switch ($mimeType) { - case 'image/gif': - $this->format = 'GIF'; - break; - case 'image/jpeg': - $this->format = 'JPG'; - break; - case 'image/png': - $this->format = 'PNG'; - break; - default: - throw new \Exception("Image format not supported: {$mimeType}"); - } - } - - /** - * Makes sure the correct GD implementation exists for the file type - * - */ - protected function verifyFormatCompatiblity() - { - $isCompatible = true; - $gdInfo = gd_info(); - - switch ($this->format) { - case 'GIF': - $isCompatible = isset($gdInfo['GIF Create Support']); - break; - case 'JPG': - $isCompatible = (isset($gdInfo['JPG Support']) || isset($gdInfo['JPEG Support'])) ? true : false; - break; - case 'PNG': - $isCompatible = isset($gdInfo[$this->format . ' Support']); - break; - default: - $isCompatible = false; - } - - if (!$isCompatible) { - // one last check for "JPEG" instead - $isCompatible = isset($gdInfo['JPEG Support']); - - if (!$isCompatible) { - throw new \Exception("Your GD installation does not support {$this->format} image types"); - } - } - } - - /** - * Preserves the alpha or transparency for PNG and GIF files - * - * Alpha / transparency will not be preserved if the appropriate options are set to false. - * Also, the GIF transparency is pretty skunky (the results aren't awesome), but it works like a - * champ... that's the nature of GIFs tho, so no huge surprise. - * - * This functionality was originally suggested by commenter Aimi (no links / site provided) - Thanks! :) - * - */ - protected function preserveAlpha() - { - if ($this->format == 'PNG' && $this->options['preserveAlpha'] === true) { - imagealphablending($this->workingImage, false); - - $colorTransparent = imagecolorallocatealpha( - $this->workingImage, - $this->options['alphaMaskColor'][0], - $this->options['alphaMaskColor'][1], - $this->options['alphaMaskColor'][2], - 0 - ); - - imagefill($this->workingImage, 0, 0, $colorTransparent); - imagesavealpha($this->workingImage, true); - } - // preserve transparency in GIFs... this is usually pretty rough tho - if ($this->format == 'GIF' && $this->options['preserveTransparency'] === true) { - $colorTransparent = imagecolorallocate( - $this->workingImage, - $this->options['transparencyMaskColor'][0], - $this->options['transparencyMaskColor'][1], - $this->options['transparencyMaskColor'][2] - ); - - imagecolortransparent($this->workingImage, $colorTransparent); - imagetruecolortopalette($this->workingImage, true, 256); - } - } -} + + * Copyright (c) 2009, Ian Selby/Gen X Design + * + * Author(s): Ian Selby + * + * Licensed under the MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author Ian Selby + * @copyright Copyright (c) 2009 Gen X Design + * @link http://phpthumb.gxdlabs.com + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + */ + +class GD extends PHPThumb +{ + /** + * The prior image (before manipulation) + * + * @var resource + */ + protected $oldImage; + + /** + * The working image (used during manipulation) + * + * @var resource + */ + protected $workingImage; + + /** + * The current dimensions of the image + * + * @var array + */ + protected $currentDimensions; + + /** + * The new, calculated dimensions of the image + * + * @var array + */ + protected $newDimensions; + + /** + * The options for this class + * + * This array contains various options that determine the behavior in + * various functions throughout the class. Functions note which specific + * option key / values are used in their documentation + * + * @var array + */ + protected $options; + + /** + * The maximum width an image can be after resizing (in pixels) + * + * @var int + */ + protected $maxWidth; + + /** + * The maximum height an image can be after resizing (in pixels) + * + * @var int + */ + protected $maxHeight; + + /** + * The percentage to resize the image by + * + * @var int + */ + protected $percent; + + /** + * @param string $fileName + * @param array $options + * @param array $plugins + */ + public function __construct($fileName, $options = array(), array $plugins = array()) + { + parent::__construct($fileName, $options, $plugins); + + $this->determineFormat(); + $this->verifyFormatCompatiblity(); + + switch ($this->format) { + case 'GIF': + $this->oldImage = @imagecreatefromgif($this->fileName); + break; + case 'JPG': + $this->oldImage = @imagecreatefromjpeg($this->fileName); + break; + case 'PNG': + $this->oldImage = @imagecreatefrompng($this->fileName); + break; + case 'STRING': + $this->oldImage = @imagecreatefromstring($this->fileName); + break; + } + + if (!is_resource($this->oldImage)) + { + throw new \Exception('Invalid image file'); + } + else + { + $this->currentDimensions = array ( + 'width' => imagesx($this->oldImage), + 'height' => imagesy($this->oldImage) + ); + } + } + + public function __destruct() + { + if (is_resource($this->oldImage)) { + imagedestroy($this->oldImage); + } + + if (is_resource($this->workingImage)) { + imagedestroy($this->workingImage); + } + } + + /** + * Pad an image to desired dimensions. Moves the image into the center and fills the rest with $color. + * @param $width + * @param $height + * @param array $color + * @return GD + */ + public function pad($width, $height, $color = array(255, 255, 255)) + { + // no resize - woohoo! + if ($width == $this->currentDimensions['width'] && $height == $this->currentDimensions['height']) { + return $this; + } + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($width, $height); + } else { + $this->workingImage = imagecreate($width, $height); + } + + // create the fill color + $fillColor = imagecolorallocate( + $this->workingImage, + $color[0], + $color[1], + $color[2] + ); + + // fill our working image with the fill color + imagefill( + $this->workingImage, + 0, + 0, + $fillColor + ); + + // copy the image into the center of our working image + imagecopyresampled( + $this->workingImage, + $this->oldImage, + intval(($width-$this->currentDimensions['width']) / 2), + intval(($height-$this->currentDimensions['height']) / 2), + 0, + 0, + $this->currentDimensions['width'], + $this->currentDimensions['height'], + $this->currentDimensions['width'], + $this->currentDimensions['height'] + ); + + // update all the variables and resources to be correct + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $width; + $this->currentDimensions['height'] = $height; + + return $this; + } + + /** + * Resizes an image to be no larger than $maxWidth or $maxHeight + * + * If either param is set to zero, then that dimension will not be considered as a part of the resize. + * Additionally, if $this->options['resizeUp'] is set to true (false by default), then this function will + * also scale the image up to the maximum dimensions provided. + * + * @param int $maxWidth The maximum width of the image in pixels + * @param int $maxHeight The maximum height of the image in pixels + * @return \PHPThumb\GD + */ + public function resize($maxWidth = 0, $maxHeight = 0) + { + // make sure our arguments are valid + if (!is_numeric($maxWidth)) { + throw new \InvalidArgumentException('$maxWidth must be numeric'); + } + + if (!is_numeric($maxHeight)) { + throw new \InvalidArgumentException('$maxHeight must be numeric'); + } + + // make sure we're not exceeding our image size if we're not supposed to + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($maxHeight) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $maxHeight; + $this->maxWidth = (intval($maxWidth) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $maxWidth; + } else { + $this->maxHeight = intval($maxHeight); + $this->maxWidth = intval($maxWidth); + } + + // get the new dimensions... + $this->calcImageSize($this->currentDimensions['width'], $this->currentDimensions['height']); + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + } else { + $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + } + + $this->preserveAlpha(); + + // and create the newly sized image + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + 0, + 0, + $this->newDimensions['newWidth'], + $this->newDimensions['newHeight'], + $this->currentDimensions['width'], + $this->currentDimensions['height'] + ); + + // update all the variables and resources to be correct + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $this->newDimensions['newWidth']; + $this->currentDimensions['height'] = $this->newDimensions['newHeight']; + + return $this; + } + + /** + * Adaptively Resizes the Image + * + * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the + * remaining overflow (from the center) to get the image to be the size specified + * + * @param int $maxWidth + * @param int $maxHeight + * @return \PHPThumb\GD + */ + public function adaptiveResize($width, $height) + { + // make sure our arguments are valid + if ((!is_numeric($width) || $width == 0) && (!is_numeric($height) || $height == 0)) { + throw new \InvalidArgumentException('$width and $height must be numeric and greater than zero'); + } + + if (!is_numeric($width) || $width == 0) { + $width = ($height * $this->currentDimensions['width']) / $this->currentDimensions['height']; + } + + if (!is_numeric($height) || $height == 0) { + $height = ($width * $this->currentDimensions['height']) / $this->currentDimensions['width']; + } + + // make sure we're not exceeding our image size if we're not supposed to + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); + + // resize the image to be close to our desired dimensions + $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + + // reset the max dimensions... + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); + } else { + $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); + } + + $this->preserveAlpha(); + + $cropWidth = $this->maxWidth; + $cropHeight = $this->maxHeight; + $cropX = 0; + $cropY = 0; + + // now, figure out how to crop the rest of the image... + if ($this->currentDimensions['width'] > $this->maxWidth) { + $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2); + } elseif ($this->currentDimensions['height'] > $this->maxHeight) { + $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2); + } + + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + $cropX, + $cropY, + $cropWidth, + $cropHeight, + $cropWidth, + $cropHeight + ); + + // update all the variables and resources to be correct + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $this->maxWidth; + $this->currentDimensions['height'] = $this->maxHeight; + + return $this; + } + + /** + * Adaptively Resizes the Image and Crops Using a Percentage + * + * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the + * remaining overflow using a provided percentage to get the image to be the size specified. + * + * The percentage mean different things depending on the orientation of the original image. + * + * For Landscape images: + * --------------------- + * + * A percentage of 1 would crop the image all the way to the left, which would be the same as + * using adaptiveResizeQuadrant() with $quadrant = 'L' + * + * A percentage of 50 would crop the image to the center which would be the same as using + * adaptiveResizeQuadrant() with $quadrant = 'C', or even the original adaptiveResize() + * + * A percentage of 100 would crop the image to the image all the way to the right, etc, etc. + * Note that you can use any percentage between 1 and 100. + * + * For Portrait images: + * -------------------- + * + * This works the same as for Landscape images except that a percentage of 1 means top and 100 means bottom + * + * @param int $maxWidth + * @param int $maxHeight + * @param int $percent + * @return \PHPThumb\GD + */ + public function adaptiveResizePercent($width, $height, $percent = 50) + { + // make sure our arguments are valid + if (!is_numeric($width) || $width == 0) { + throw new \InvalidArgumentException('$width must be numeric and greater than zero'); + } + + if (!is_numeric($height) || $height == 0) { + throw new \InvalidArgumentException('$height must be numeric and greater than zero'); + } + + // make sure we're not exceeding our image size if we're not supposed to + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); + + // resize the image to be close to our desired dimensions + $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + + // reset the max dimensions... + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); + } else { + $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); + } + + $this->preserveAlpha(); + + $cropWidth = $this->maxWidth; + $cropHeight = $this->maxHeight; + $cropX = 0; + $cropY = 0; + + // Crop the rest of the image using the quadrant + + if ($percent > 100) { + $percent = 100; + } elseif ($percent < 1) { + $percent = 1; + } + + if ($this->currentDimensions['width'] > $this->maxWidth) { + // Image is landscape + $maxCropX = $this->currentDimensions['width'] - $this->maxWidth; + $cropX = intval(($percent / 100) * $maxCropX); + + } elseif ($this->currentDimensions['height'] > $this->maxHeight) { + // Image is portrait + $maxCropY = $this->currentDimensions['height'] - $this->maxHeight; + $cropY = intval(($percent / 100) * $maxCropY); + } + + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + $cropX, + $cropY, + $cropWidth, + $cropHeight, + $cropWidth, + $cropHeight + ); + + // update all the variables and resources to be correct + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $this->maxWidth; + $this->currentDimensions['height'] = $this->maxHeight; + + return $this; + } + + /** + * Adaptively Resizes the Image and Crops Using a Quadrant + * + * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the + * remaining overflow using the quadrant to get the image to be the size specified. + * + * The quadrants available are Top, Bottom, Center, Left, and Right: + * + * + * +---+---+---+ + * | | T | | + * +---+---+---+ + * | L | C | R | + * +---+---+---+ + * | | B | | + * +---+---+---+ + * + * Note that if your image is Landscape and you choose either of the Top or Bottom quadrants (which won't + * make sence since only the Left and Right would be available, then the Center quadrant will be used + * to crop. This would have exactly the same result as using adaptiveResize(). + * The same goes if your image is portrait and you choose either the Left or Right quadrants. + * + * @param int $maxWidth + * @param int $maxHeight + * @param string $quadrant T, B, C, L, R + * @return \PHPThumb\GD + */ + public function adaptiveResizeQuadrant($width, $height, $quadrant = 'C') + { + // make sure our arguments are valid + if (!is_numeric($width) || $width == 0) { + throw new \InvalidArgumentException('$width must be numeric and greater than zero'); + } + + if (!is_numeric($height) || $height == 0) { + throw new \InvalidArgumentException('$height must be numeric and greater than zero'); + } + + // make sure we're not exceeding our image size if we're not supposed to + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); + + // resize the image to be close to our desired dimensions + $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + + // reset the max dimensions... + if ($this->options['resizeUp'] === false) { + $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; + $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; + } else { + $this->maxHeight = intval($height); + $this->maxWidth = intval($width); + } + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); + } else { + $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); + } + + $this->preserveAlpha(); + + $cropWidth = $this->maxWidth; + $cropHeight = $this->maxHeight; + $cropX = 0; + $cropY = 0; + + // Crop the rest of the image using the quadrant + + if ($this->currentDimensions['width'] > $this->maxWidth) { + // Image is landscape + switch ($quadrant) { + case 'L': + $cropX = 0; + break; + case 'R': + $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth)); + break; + case 'C': + default: + $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2); + break; + } + } elseif ($this->currentDimensions['height'] > $this->maxHeight) { + // Image is portrait + switch ($quadrant) { + case 'T': + $cropY = 0; + break; + case 'B': + $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight)); + break; + case 'C': + default: + $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2); + break; + } + } + + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + $cropX, + $cropY, + $cropWidth, + $cropHeight, + $cropWidth, + $cropHeight + ); + + // update all the variables and resources to be correct + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $this->maxWidth; + $this->currentDimensions['height'] = $this->maxHeight; + + return $this; + } + + /** + * Resizes an image by a given percent uniformly, + * Percentage should be whole number representation (i.e. 1-100) + * + * @param int $percent + * @return GD + * @throws \InvalidArgumentException + */ + public function resizePercent($percent = 0) + { + if (!is_numeric($percent)) { + throw new \InvalidArgumentException ('$percent must be numeric'); + } + + $this->percent = intval($percent); + + $this->calcImageSizePercent($this->currentDimensions['width'], $this->currentDimensions['height']); + + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + } else { + $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); + } + + $this->preserveAlpha(); + + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + 0, + 0, + $this->newDimensions['newWidth'], + $this->newDimensions['newHeight'], + $this->currentDimensions['width'], + $this->currentDimensions['height'] + ); + + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $this->newDimensions['newWidth']; + $this->currentDimensions['height'] = $this->newDimensions['newHeight']; + + return $this; + } + + /** + * Crops an image from the center with provided dimensions + * + * If no height is given, the width will be used as a height, thus creating a square crop + * + * @param int $cropWidth + * @param int $cropHeight + * @return \PHPThumb\GD + */ + public function cropFromCenter($cropWidth, $cropHeight = null) + { + if (!is_numeric($cropWidth)) { + throw new \InvalidArgumentException('$cropWidth must be numeric'); + } + + if ($cropHeight !== null && !is_numeric($cropHeight)) { + throw new \InvalidArgumentException('$cropHeight must be numeric'); + } + + if ($cropHeight === null) { + $cropHeight = $cropWidth; + } + + $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth; + $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight; + + $cropX = intval(($this->currentDimensions['width'] - $cropWidth) / 2); + $cropY = intval(($this->currentDimensions['height'] - $cropHeight) / 2); + + $this->crop($cropX, $cropY, $cropWidth, $cropHeight); + + return $this; + } + + /** + * Vanilla Cropping - Crops from x,y with specified width and height + * + * @param int $startX + * @param int $startY + * @param int $cropWidth + * @param int $cropHeight + * @return \PHPThumb\GD + */ + public function crop($startX, $startY, $cropWidth, $cropHeight) + { + // validate input + if (!is_numeric($startX)) { + throw new \InvalidArgumentException('$startX must be numeric'); + } + + if (!is_numeric($startY)) { + throw new \InvalidArgumentException('$startY must be numeric'); + } + + if (!is_numeric($cropWidth)) { + throw new \InvalidArgumentException('$cropWidth must be numeric'); + } + + if (!is_numeric($cropHeight)) { + throw new \InvalidArgumentException('$cropHeight must be numeric'); + } + + // do some calculations + $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth; + $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight; + + // ensure everything's in bounds + if (($startX + $cropWidth) > $this->currentDimensions['width']) { + $startX = ($this->currentDimensions['width'] - $cropWidth); + } + + if (($startY + $cropHeight) > $this->currentDimensions['height']) { + $startY = ($this->currentDimensions['height'] - $cropHeight); + } + + if ($startX < 0) { + $startX = 0; + } + + if ($startY < 0) { + $startY = 0; + } + + // create the working image + if (function_exists('imagecreatetruecolor')) { + $this->workingImage = imagecreatetruecolor($cropWidth, $cropHeight); + } else { + $this->workingImage = imagecreate($cropWidth, $cropHeight); + } + + $this->preserveAlpha(); + + imagecopyresampled( + $this->workingImage, + $this->oldImage, + 0, + 0, + $startX, + $startY, + $cropWidth, + $cropHeight, + $cropWidth, + $cropHeight + ); + + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $cropWidth; + $this->currentDimensions['height'] = $cropHeight; + + return $this; + } + + /** + * Rotates image either 90 degrees clockwise or counter-clockwise + * + * @param string $direction + * @retunrn \PHPThumb\GD + */ + public function rotateImage($direction = 'CW') + { + if ($direction == 'CW') { + $this->rotateImageNDegrees(90); + } else { + $this->rotateImageNDegrees(-90); + } + + return $this; + } + + /** + * Rotates image specified number of degrees + * + * @param int $degrees + * @return \PHPThumb\GD + */ + public function rotateImageNDegrees($degrees) + { + if (!is_numeric($degrees)) { + throw new \InvalidArgumentException('$degrees must be numeric'); + } + + if (!function_exists('imagerotate')) { + throw new \RuntimeException('Your version of GD does not support image rotation'); + } + + $this->workingImage = imagerotate($this->oldImage, $degrees, 0); + + $newWidth = $this->currentDimensions['height']; + $newHeight = $this->currentDimensions['width']; + $this->oldImage = $this->workingImage; + $this->currentDimensions['width'] = $newWidth; + $this->currentDimensions['height'] = $newHeight; + + return $this; + } + + /** + * Applies a filter to the image + * + * @param int $filter + * @return \PHPThumb\GD + */ + public function imageFilter($filter, $arg1 = false, $arg2 = false, $arg3 = false, $arg4 = false) + { + if (!is_numeric($filter)) { + throw new \InvalidArgumentException('$filter must be numeric'); + } + + if (!function_exists('imagefilter')) { + throw new \RuntimeException('Your version of GD does not support image filters'); + } + + $result = false; + if ($arg1 === false) { + $result = imagefilter($this->oldImage, $filter); + } elseif ($arg2 === false) { + $result = imagefilter($this->oldImage, $filter, $arg1); + } elseif ($arg3 === false) { + $result = imagefilter($this->oldImage, $filter, $arg1, $arg2); + } elseif ($arg4 === false) { + $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3); + } else { + $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3, $arg4); + } + + if (!$result) { + throw new \RuntimeException('GD imagefilter failed'); + } + + $this->workingImage = $this->oldImage; + + return $this; + } + + /** + * Shows an image + * + * This function will show the current image by first sending the appropriate header + * for the format, and then outputting the image data. If headers have already been sent, + * a runtime exception will be thrown + * + * @param bool $rawData Whether or not the raw image stream should be output + * @return \PHPThumb\GD + */ + public function show($rawData = false) + { + //Execute any plugins + if ($this->plugins) { + foreach ($this->plugins as $plugin) { + /* @var $plugin \PHPThumb\PluginInterface */ + $plugin->execute($this); + } + } + + if (headers_sent() && php_sapi_name() != 'cli') { + throw new \RuntimeException('Cannot show image, headers have already been sent'); + } + + // When the interlace option equals true or false call imageinterlace else leave it to default + if ($this->options['interlace'] === true) { + imageinterlace($this->oldImage, 1); + } elseif ($this->options['interlace'] === false) { + imageinterlace($this->oldImage, 0); + } + + switch ($this->format) { + case 'GIF': + if ($rawData === false) { + header('Content-type: image/gif'); + } + imagegif($this->oldImage); + break; + case 'JPG': + if ($rawData === false) { + header('Content-type: image/jpeg'); + } + imagejpeg($this->oldImage, null, $this->options['jpegQuality']); + break; + case 'PNG': + case 'STRING': + if ($rawData === false) { + header('Content-type: image/png'); + } + imagepng($this->oldImage); + break; + } + + return $this; + } + + /** + * Returns the Working Image as a String + * + * This function is useful for getting the raw image data as a string for storage in + * a database, or other similar things. + * + * @return string + */ + public function getImageAsString() + { + $data = null; + ob_start(); + $this->show(true); + $data = ob_get_contents(); + ob_end_clean(); + + return $data; + } + + /** + * Saves an image + * + * This function will make sure the target directory is writeable, and then save the image. + * + * If the target directory is not writeable, the function will try to correct the permissions (if allowed, this + * is set as an option ($this->options['correctPermissions']). If the target cannot be made writeable, then a + * \RuntimeException is thrown. + * + * @param string $fileName The full path and filename of the image to save + * @param string $format The format to save the image in (optional, must be one of [GIF,JPG,PNG] + * @return \PHPThumb\GD + */ + public function save($fileName, $format = null) + { + $validFormats = array('GIF', 'JPG', 'PNG'); + $format = ($format !== null) ? strtoupper($format) : $this->format; + + if (!in_array($format, $validFormats)) { + throw new \InvalidArgumentException("Invalid format type specified in save function: {$format}"); + } + + // make sure the directory is writeable + if (!is_writeable(dirname($fileName))) { + // try to correct the permissions + if ($this->options['correctPermissions'] === true) { + @chmod(dirname($fileName), 0777); + + // throw an exception if not writeable + if (!is_writeable(dirname($fileName))) { + throw new \RuntimeException("File is not writeable, and could not correct permissions: {$fileName}"); + } + } else { // throw an exception if not writeable + throw new \RuntimeException("File not writeable: {$fileName}"); + } + } + + // When the interlace option equals true or false call imageinterlace else leave it to default + if ($this->options['interlace'] === true) { + imageinterlace($this->oldImage, 1); + } elseif ($this->options['interlace'] === false) { + imageinterlace($this->oldImage, 0); + } + + switch ($format) { + case 'GIF': + imagegif($this->oldImage, $fileName); + break; + case 'JPG': + imagejpeg($this->oldImage, $fileName, $this->options['jpegQuality']); + break; + case 'PNG': + imagepng($this->oldImage, $fileName); + break; + } + + return $this; + } + + ################################# + # ----- GETTERS / SETTERS ----- # + ################################# + + /** + * Sets options for all operations. + * @param array $options + * @return GD + */ + public function setOptions(array $options = array()) + { + // we've yet to init the default options, so create them here + if (sizeof($this->options) == 0) { + $defaultOptions = array( + 'resizeUp' => false, + 'jpegQuality' => 100, + 'correctPermissions' => false, + 'preserveAlpha' => true, + 'alphaMaskColor' => array (255, 255, 255), + 'preserveTransparency' => true, + 'transparencyMaskColor' => array (0, 0, 0), + 'interlace' => null + ); + } else { // otherwise, let's use what we've got already + $defaultOptions = $this->options; + } + + $this->options = array_merge($defaultOptions, $options); + + return $this; + } + + /** + * Returns $currentDimensions. + * + * @see \PHPThumb\GD::$currentDimensions + */ + public function getCurrentDimensions() + { + return $this->currentDimensions; + } + + /** + * @param $currentDimensions + * @return GD + */ + public function setCurrentDimensions($currentDimensions) + { + $this->currentDimensions = $currentDimensions; + + return $this; + } + + /** + * @return int + */ + public function getMaxHeight() + { + return $this->maxHeight; + } + + /** + * @param $maxHeight + * @return GD + */ + public function setMaxHeight($maxHeight) + { + $this->maxHeight = $maxHeight; + + return $this; + } + + /** + * @return int + */ + public function getMaxWidth() + { + return $this->maxWidth; + } + + /** + * @param $maxWidth + * @return GD + */ + public function setMaxWidth($maxWidth) + { + $this->maxWidth = $maxWidth; + + return $this; + } + + /** + * Returns $newDimensions. + * + * @see \PHPThumb\GD::$newDimensions + */ + public function getNewDimensions() + { + return $this->newDimensions; + } + + /** + * Sets $newDimensions. + * + * @param object $newDimensions + * @see \PHPThumb\GD::$newDimensions + */ + public function setNewDimensions($newDimensions) + { + $this->newDimensions = $newDimensions; + + return $this; + } + + /** + * Returns $options. + * + * @see \PHPThumb\GD::$options + */ + public function getOptions() + { + return $this->options; + } + + /** + * Returns $percent. + * + * @see \PHPThumb\GD::$percent + */ + public function getPercent() + { + return $this->percent; + } + + /** + * Sets $percent. + * + * @param object $percent + * @see \PHPThumb\GD::$percent + */ + public function setPercent($percent) + { + $this->percent = $percent; + + return $this; + } + + /** + * Returns $oldImage. + * + * @see \PHPThumb\GD::$oldImage + */ + public function getOldImage() + { + return $this->oldImage; + } + + /** + * Sets $oldImage. + * + * @param object $oldImage + * @see \PHPThumb\GD::$oldImage + */ + public function setOldImage($oldImage) + { + $this->oldImage = $oldImage; + + return $this; + } + + /** + * Returns $workingImage. + * + * @see \PHPThumb\GD::$workingImage + */ + public function getWorkingImage() + { + return $this->workingImage; + } + + /** + * Sets $workingImage. + * + * @param object $workingImage + * @see \PHPThumb\GD::$workingImage + */ + public function setWorkingImage($workingImage) + { + $this->workingImage = $workingImage; + + return $this; + } + + + ################################# + # ----- UTILITY FUNCTIONS ----- # + ################################# + + /** + * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions + * + * @return array + * @param int $width + * @param int $height + */ + protected function calcWidth($width, $height) + { + $newWidthPercentage = (100 * $this->maxWidth) / $width; + $newHeight = ($height * $newWidthPercentage) / 100; + + return array( + 'newWidth' => intval($this->maxWidth), + 'newHeight' => intval($newHeight) + ); + } + + /** + * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions + * + * @return array + * @param int $width + * @param int $height + */ + protected function calcHeight($width, $height) + { + $newHeightPercentage = (100 * $this->maxHeight) / $height; + $newWidth = ($width * $newHeightPercentage) / 100; + + return array( + 'newWidth' => ceil($newWidth), + 'newHeight' => ceil($this->maxHeight) + ); + } + + /** + * Calculates a new width and height for the image based on $this->percent and the provided dimensions + * + * @return array + * @param int $width + * @param int $height + */ + protected function calcPercent($width, $height) + { + $newWidth = ($width * $this->percent) / 100; + $newHeight = ($height * $this->percent) / 100; + + return array( + 'newWidth' => ceil($newWidth), + 'newHeight' => ceil($newHeight) + ); + } + + /** + * Calculates the new image dimensions + * + * These calculations are based on both the provided dimensions and $this->maxWidth and $this->maxHeight + * + * @param int $width + * @param int $height + */ + protected function calcImageSize($width, $height) + { + $newSize = array( + 'newWidth' => $width, + 'newHeight' => $height + ); + + if ($this->maxWidth > 0) { + $newSize = $this->calcWidth($width, $height); + + if ($this->maxHeight > 0 && $newSize['newHeight'] > $this->maxHeight) { + $newSize = $this->calcHeight($newSize['newWidth'], $newSize['newHeight']); + } + } + + if ($this->maxHeight > 0) { + $newSize = $this->calcHeight($width, $height); + + if ($this->maxWidth > 0 && $newSize['newWidth'] > $this->maxWidth) { + $newSize = $this->calcWidth($newSize['newWidth'], $newSize['newHeight']); + } + } + + $this->newDimensions = $newSize; + } + + /** + * Calculates new image dimensions, not allowing the width and height to be less than either the max width or height + * + * @param int $width + * @param int $height + */ + protected function calcImageSizeStrict($width, $height) + { + // first, we need to determine what the longest resize dimension is.. + if ($this->maxWidth >= $this->maxHeight) { + // and determine the longest original dimension + if ($width > $height) { + $newDimensions = $this->calcHeight($width, $height); + + if ($newDimensions['newWidth'] < $this->maxWidth) { + $newDimensions = $this->calcWidth($width, $height); + } + } elseif ($height >= $width) { + $newDimensions = $this->calcWidth($width, $height); + + if ($newDimensions['newHeight'] < $this->maxHeight) { + $newDimensions = $this->calcHeight($width, $height); + } + } + } elseif ($this->maxHeight > $this->maxWidth) { + if ($width >= $height) { + $newDimensions = $this->calcWidth($width, $height); + + if ($newDimensions['newHeight'] < $this->maxHeight) { + $newDimensions = $this->calcHeight($width, $height); + } + } elseif ($height > $width) { + $newDimensions = $this->calcHeight($width, $height); + + if ($newDimensions['newWidth'] < $this->maxWidth) { + $newDimensions = $this->calcWidth($width, $height); + } + } + } + + $this->newDimensions = $newDimensions; + } + + /** + * Calculates new dimensions based on $this->percent and the provided dimensions + * + * @param int $width + * @param int $height + */ + protected function calcImageSizePercent($width, $height) + { + if ($this->percent > 0) { + $this->newDimensions = $this->calcPercent($width, $height); + } + } + + /** + * Determines the file format by mime-type + * + * This function will throw exceptions for invalid images / mime-types + * + */ + protected function determineFormat() + { + $formatInfo = getimagesize($this->fileName); + + // non-image files will return false + if ($formatInfo === false) { + if ($this->remoteImage) { + throw new \Exception("Could not determine format of remote image: {$this->fileName}"); + } else { + throw new \Exception("File is not a valid image: {$this->fileName}"); + } + } + + $mimeType = isset($formatInfo['mime']) ? $formatInfo['mime'] : null; + + switch ($mimeType) { + case 'image/gif': + $this->format = 'GIF'; + break; + case 'image/jpeg': + $this->format = 'JPG'; + break; + case 'image/png': + $this->format = 'PNG'; + break; + default: + throw new \Exception("Image format not supported: {$mimeType}"); + } + } + + /** + * Makes sure the correct GD implementation exists for the file type + * + */ + protected function verifyFormatCompatiblity() + { + $isCompatible = true; + $gdInfo = gd_info(); + + switch ($this->format) { + case 'GIF': + $isCompatible = isset($gdInfo['GIF Create Support']); + break; + case 'JPG': + $isCompatible = (isset($gdInfo['JPG Support']) || isset($gdInfo['JPEG Support'])) ? true : false; + break; + case 'PNG': + $isCompatible = isset($gdInfo[$this->format . ' Support']); + break; + default: + $isCompatible = false; + } + + if (!$isCompatible) { + // one last check for "JPEG" instead + $isCompatible = isset($gdInfo['JPEG Support']); + + if (!$isCompatible) { + throw new \Exception("Your GD installation does not support {$this->format} image types"); + } + } + } + + /** + * Preserves the alpha or transparency for PNG and GIF files + * + * Alpha / transparency will not be preserved if the appropriate options are set to false. + * Also, the GIF transparency is pretty skunky (the results aren't awesome), but it works like a + * champ... that's the nature of GIFs tho, so no huge surprise. + * + * This functionality was originally suggested by commenter Aimi (no links / site provided) - Thanks! :) + * + */ + protected function preserveAlpha() + { + if ($this->format == 'PNG' && $this->options['preserveAlpha'] === true) { + imagealphablending($this->workingImage, false); + + $colorTransparent = imagecolorallocatealpha( + $this->workingImage, + $this->options['alphaMaskColor'][0], + $this->options['alphaMaskColor'][1], + $this->options['alphaMaskColor'][2], + 0 + ); + + imagefill($this->workingImage, 0, 0, $colorTransparent); + imagesavealpha($this->workingImage, true); + } + // preserve transparency in GIFs... this is usually pretty rough tho + if ($this->format == 'GIF' && $this->options['preserveTransparency'] === true) { + $colorTransparent = imagecolorallocate( + $this->workingImage, + $this->options['transparencyMaskColor'][0], + $this->options['transparencyMaskColor'][1], + $this->options['transparencyMaskColor'][2] + ); + + imagecolortransparent($this->workingImage, $colorTransparent); + imagetruecolortopalette($this->workingImage, true, 256); + } + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/PHPThumb.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHPThumb/PHPThumb.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/PHPThumb.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHPThumb/PHPThumb.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/PluginInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHPThumb/PluginInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/PluginInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHPThumb/PluginInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/Plugins/Reflection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/PHPThumb/Plugins/Reflection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/Plugins/Reflection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/PHPThumb/Plugins/Reflection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Autoloader.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Autoloader.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Autoloader.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Autoloader.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Client.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Client.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Client.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Client.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientContextInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/ClientContextInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientContextInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/ClientContextInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/ClientException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/ClientException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/ClientInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/ClientInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/ClusterStrategy.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/ClusterStrategy.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/ClusterStrategy.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/ClusterStrategy.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/DistributorInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Distributor/DistributorInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/DistributorInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Distributor/DistributorInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/EmptyRingException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Distributor/EmptyRingException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/EmptyRingException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Distributor/EmptyRingException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/HashRing.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Distributor/HashRing.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/HashRing.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Distributor/HashRing.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/KetamaRing.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Distributor/KetamaRing.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/KetamaRing.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Distributor/KetamaRing.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Hash/CRC16.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Hash/CRC16.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Hash/CRC16.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Hash/CRC16.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Hash/HashGeneratorInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Hash/HashGeneratorInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Hash/HashGeneratorInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/Hash/HashGeneratorInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/PredisStrategy.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/PredisStrategy.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/PredisStrategy.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/PredisStrategy.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/RedisStrategy.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/RedisStrategy.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/RedisStrategy.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/RedisStrategy.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/StrategyInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/StrategyInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/StrategyInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Cluster/StrategyInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/CursorBasedIterator.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/CursorBasedIterator.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/CursorBasedIterator.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/CursorBasedIterator.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/HashKey.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/HashKey.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/HashKey.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/HashKey.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/Keyspace.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/Keyspace.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/Keyspace.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/Keyspace.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/ListKey.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/ListKey.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/ListKey.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/ListKey.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/SetKey.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/SetKey.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/SetKey.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/SetKey.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/SortedSetKey.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/SortedSetKey.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/SortedSetKey.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Collection/Iterator/SortedSetKey.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Command.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/Command.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Command.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/Command.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/CommandInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/CommandInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/CommandInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/CommandInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionAuth.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ConnectionAuth.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionAuth.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ConnectionAuth.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionEcho.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ConnectionEcho.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionEcho.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ConnectionEcho.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionPing.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ConnectionPing.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionPing.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ConnectionPing.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionQuit.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ConnectionQuit.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionQuit.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ConnectionQuit.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionSelect.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ConnectionSelect.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionSelect.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ConnectionSelect.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashDelete.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashDelete.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashDelete.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashDelete.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashExists.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashExists.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashExists.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashExists.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGet.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashGet.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGet.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashGet.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGetAll.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashGetAll.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGetAll.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashGetAll.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGetMultiple.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashGetMultiple.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGetMultiple.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashGetMultiple.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashIncrementBy.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashIncrementBy.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashIncrementBy.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashIncrementBy.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashIncrementByFloat.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashIncrementByFloat.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashIncrementByFloat.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashIncrementByFloat.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashKeys.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashKeys.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashKeys.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashKeys.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashLength.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashLength.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashLength.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashLength.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashScan.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashScan.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashScan.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashScan.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSet.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashSet.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSet.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashSet.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSetMultiple.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashSetMultiple.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSetMultiple.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashSetMultiple.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSetPreserve.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashSetPreserve.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSetPreserve.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashSetPreserve.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashStringLength.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashStringLength.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashStringLength.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashStringLength.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashValues.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashValues.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashValues.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HashValues.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogAdd.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HyperLogLogAdd.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogAdd.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HyperLogLogAdd.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogCount.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HyperLogLogCount.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogCount.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HyperLogLogCount.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogMerge.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HyperLogLogMerge.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogMerge.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/HyperLogLogMerge.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyDelete.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyDelete.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyDelete.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyDelete.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyDump.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyDump.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyDump.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyDump.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExists.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyExists.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExists.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyExists.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExpire.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyExpire.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExpire.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyExpire.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExpireAt.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyExpireAt.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExpireAt.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyExpireAt.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyKeys.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyKeys.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyKeys.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyKeys.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyMigrate.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyMigrate.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyMigrate.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyMigrate.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyMove.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyMove.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyMove.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyMove.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPersist.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyPersist.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPersist.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyPersist.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseExpire.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyPreciseExpire.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseExpire.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyPreciseExpire.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseExpireAt.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyPreciseExpireAt.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseExpireAt.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyPreciseExpireAt.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseTimeToLive.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyPreciseTimeToLive.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseTimeToLive.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyPreciseTimeToLive.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRandom.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyRandom.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRandom.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyRandom.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRename.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyRename.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRename.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyRename.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRenamePreserve.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyRenamePreserve.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRenamePreserve.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyRenamePreserve.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRestore.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyRestore.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRestore.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyRestore.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyScan.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyScan.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyScan.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyScan.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeySort.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeySort.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeySort.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeySort.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyTimeToLive.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyTimeToLive.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyTimeToLive.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyTimeToLive.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/KeyType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListIndex.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListIndex.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListIndex.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListIndex.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListInsert.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListInsert.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListInsert.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListInsert.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListLength.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListLength.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListLength.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListLength.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopFirst.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopFirst.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopFirst.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopFirst.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopFirstBlocking.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopFirstBlocking.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopFirstBlocking.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopFirstBlocking.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLast.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopLast.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLast.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopLast.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastBlocking.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopLastBlocking.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastBlocking.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopLastBlocking.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastPushHead.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopLastPushHead.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastPushHead.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopLastPushHead.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastPushHeadBlocking.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopLastPushHeadBlocking.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastPushHeadBlocking.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPopLastPushHeadBlocking.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushHead.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPushHead.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushHead.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPushHead.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushHeadX.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPushHeadX.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushHeadX.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPushHeadX.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushTail.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPushTail.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushTail.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPushTail.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushTailX.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPushTailX.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushTailX.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListPushTailX.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListRange.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListRange.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListRange.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListRange.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListRemove.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListRemove.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListRemove.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListRemove.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListSet.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListSet.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListSet.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListSet.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListTrim.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListTrim.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListTrim.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ListTrim.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PrefixableCommandInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PrefixableCommandInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PrefixableCommandInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PrefixableCommandInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/KeyPrefixProcessor.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/Processor/KeyPrefixProcessor.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/KeyPrefixProcessor.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/Processor/KeyPrefixProcessor.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/ProcessorChain.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/Processor/ProcessorChain.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/ProcessorChain.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/Processor/ProcessorChain.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/ProcessorInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/Processor/ProcessorInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/ProcessorInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/Processor/ProcessorInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubPublish.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubPublish.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubPublish.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubPublish.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubPubsub.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubPubsub.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubPubsub.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubPubsub.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubSubscribe.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubSubscribe.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubSubscribe.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubSubscribe.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubSubscribeByPattern.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubSubscribeByPattern.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubSubscribeByPattern.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubSubscribeByPattern.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubUnsubscribe.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubUnsubscribe.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubUnsubscribe.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubUnsubscribe.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubUnsubscribeByPattern.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubUnsubscribeByPattern.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubUnsubscribeByPattern.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/PubSubUnsubscribeByPattern.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/RawCommand.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/RawCommand.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/RawCommand.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/RawCommand.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ScriptCommand.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ScriptCommand.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ScriptCommand.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ScriptCommand.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerBackgroundRewriteAOF.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerBackgroundRewriteAOF.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerBackgroundRewriteAOF.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerBackgroundRewriteAOF.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerBackgroundSave.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerBackgroundSave.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerBackgroundSave.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerBackgroundSave.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerClient.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerClient.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerClient.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerClient.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerCommand.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerCommand.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerCommand.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerCommand.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerConfig.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerConfig.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerConfig.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerConfig.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerDatabaseSize.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerDatabaseSize.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerDatabaseSize.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerDatabaseSize.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerEval.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerEval.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerEval.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerEval.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerEvalSHA.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerEvalSHA.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerEvalSHA.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerEvalSHA.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerFlushAll.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerFlushAll.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerFlushAll.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerFlushAll.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerFlushDatabase.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerFlushDatabase.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerFlushDatabase.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerFlushDatabase.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerInfo.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerInfo.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerInfo.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerInfo.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerInfoV26x.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerInfoV26x.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerInfoV26x.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerInfoV26x.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerLastSave.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerLastSave.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerLastSave.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerLastSave.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerMonitor.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerMonitor.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerMonitor.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerMonitor.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerObject.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerObject.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerObject.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerObject.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSave.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerSave.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSave.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerSave.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerScript.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerScript.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerScript.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerScript.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSentinel.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerSentinel.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSentinel.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerSentinel.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerShutdown.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerShutdown.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerShutdown.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerShutdown.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSlaveOf.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerSlaveOf.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSlaveOf.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerSlaveOf.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSlowlog.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerSlowlog.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSlowlog.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerSlowlog.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerTime.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerTime.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerTime.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ServerTime.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetAdd.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetAdd.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetAdd.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetAdd.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetCardinality.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetCardinality.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetCardinality.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetCardinality.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetDifference.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetDifference.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetDifference.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetDifference.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetDifferenceStore.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetDifferenceStore.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetDifferenceStore.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetDifferenceStore.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIntersection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetIntersection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIntersection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetIntersection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIntersectionStore.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetIntersectionStore.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIntersectionStore.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetIntersectionStore.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIsMember.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetIsMember.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIsMember.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetIsMember.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetMembers.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetMembers.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetMembers.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetMembers.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetMove.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetMove.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetMove.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetMove.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetPop.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetPop.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetPop.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetPop.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetRandomMember.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetRandomMember.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetRandomMember.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetRandomMember.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetRemove.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetRemove.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetRemove.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetRemove.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetScan.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetScan.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetScan.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetScan.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetUnion.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetUnion.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetUnion.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetUnion.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetUnionStore.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetUnionStore.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetUnionStore.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/SetUnionStore.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringAppend.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringAppend.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringAppend.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringAppend.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitCount.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringBitCount.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitCount.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringBitCount.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitOp.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringBitOp.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitOp.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringBitOp.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitPos.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringBitPos.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitPos.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringBitPos.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringDecrement.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringDecrement.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringDecrement.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringDecrement.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringDecrementBy.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringDecrementBy.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringDecrementBy.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringDecrementBy.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGet.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringGet.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGet.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringGet.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetBit.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringGetBit.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetBit.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringGetBit.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetMultiple.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringGetMultiple.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetMultiple.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringGetMultiple.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetRange.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringGetRange.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetRange.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringGetRange.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetSet.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringGetSet.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetSet.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringGetSet.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrement.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringIncrement.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrement.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringIncrement.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrementBy.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringIncrementBy.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrementBy.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringIncrementBy.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrementByFloat.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringIncrementByFloat.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrementByFloat.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringIncrementByFloat.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringPreciseSetExpire.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringPreciseSetExpire.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringPreciseSetExpire.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringPreciseSetExpire.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSet.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSet.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSet.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSet.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetBit.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetBit.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetBit.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetBit.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetExpire.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetExpire.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetExpire.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetExpire.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetMultiple.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetMultiple.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetMultiple.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetMultiple.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetMultiplePreserve.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetMultiplePreserve.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetMultiplePreserve.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetMultiplePreserve.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetPreserve.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetPreserve.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetPreserve.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetPreserve.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetRange.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetRange.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetRange.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSetRange.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringStrlen.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringStrlen.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringStrlen.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringStrlen.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSubstr.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSubstr.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSubstr.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/StringSubstr.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionDiscard.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/TransactionDiscard.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionDiscard.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/TransactionDiscard.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionExec.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/TransactionExec.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionExec.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/TransactionExec.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionMulti.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/TransactionMulti.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionMulti.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/TransactionMulti.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionUnwatch.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/TransactionUnwatch.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionUnwatch.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/TransactionUnwatch.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionWatch.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/TransactionWatch.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionWatch.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/TransactionWatch.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetAdd.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetAdd.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetAdd.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetAdd.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetCardinality.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetCardinality.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetCardinality.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetCardinality.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetCount.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetCount.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetCount.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetCount.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetIncrementBy.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetIncrementBy.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetIncrementBy.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetIncrementBy.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetIntersectionStore.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetIntersectionStore.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetIntersectionStore.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetIntersectionStore.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetLexCount.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetLexCount.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetLexCount.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetLexCount.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRange.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRange.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRange.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRange.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRangeByLex.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRangeByLex.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRangeByLex.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRangeByLex.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRangeByScore.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRangeByScore.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRangeByScore.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRangeByScore.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRank.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRank.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRank.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRank.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemove.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRemove.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemove.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRemove.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByLex.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRemoveRangeByLex.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByLex.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRemoveRangeByLex.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByRank.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRemoveRangeByRank.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByRank.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRemoveRangeByRank.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByScore.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRemoveRangeByScore.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByScore.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetRemoveRangeByScore.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRange.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetReverseRange.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRange.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetReverseRange.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRangeByLex.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetReverseRangeByLex.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRangeByLex.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetReverseRangeByLex.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRangeByScore.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetReverseRangeByScore.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRangeByScore.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetReverseRangeByScore.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRank.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetReverseRank.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRank.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetReverseRank.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetScan.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetScan.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetScan.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetScan.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetScore.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetScore.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetScore.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetScore.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetUnionStore.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetUnionStore.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetUnionStore.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Command/ZSetUnionStore.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/CommunicationException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/CommunicationException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/CommunicationException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/CommunicationException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ClusterOption.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/ClusterOption.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ClusterOption.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/ClusterOption.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ConnectionFactoryOption.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/ConnectionFactoryOption.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ConnectionFactoryOption.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/ConnectionFactoryOption.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ExceptionsOption.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/ExceptionsOption.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ExceptionsOption.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/ExceptionsOption.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/OptionInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/OptionInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/OptionInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/OptionInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/Options.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/Options.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/Options.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/Options.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/OptionsInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/OptionsInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/OptionsInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/OptionsInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/PrefixOption.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/PrefixOption.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/PrefixOption.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/PrefixOption.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ProfileOption.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/ProfileOption.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ProfileOption.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/ProfileOption.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ReplicationOption.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/ReplicationOption.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ReplicationOption.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Configuration/ReplicationOption.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/AbstractConnection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/AbstractConnection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/AbstractConnection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/AbstractConnection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/ClusterInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Aggregate/ClusterInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/ClusterInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Aggregate/ClusterInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/MasterSlaveReplication.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Aggregate/MasterSlaveReplication.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/MasterSlaveReplication.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Aggregate/MasterSlaveReplication.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/PredisCluster.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Aggregate/PredisCluster.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/PredisCluster.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Aggregate/PredisCluster.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/RedisCluster.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Aggregate/RedisCluster.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/RedisCluster.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Aggregate/RedisCluster.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/ReplicationInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Aggregate/ReplicationInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/ReplicationInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Aggregate/ReplicationInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/AggregateConnectionInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/AggregateConnectionInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/AggregateConnectionInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/AggregateConnectionInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/CompositeConnectionInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/CompositeConnectionInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/CompositeConnectionInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/CompositeConnectionInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/CompositeStreamConnection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/CompositeStreamConnection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/CompositeStreamConnection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/CompositeStreamConnection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ConnectionException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/ConnectionException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ConnectionException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/ConnectionException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ConnectionInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/ConnectionInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ConnectionInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/ConnectionInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Factory.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Factory.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Factory.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Factory.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/FactoryInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/FactoryInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/FactoryInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/FactoryInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/NodeConnectionInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/NodeConnectionInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/NodeConnectionInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/NodeConnectionInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Parameters.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Parameters.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Parameters.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/Parameters.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ParametersInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/ParametersInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ParametersInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/ParametersInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/PhpiredisSocketConnection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/PhpiredisSocketConnection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/PhpiredisSocketConnection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/PhpiredisSocketConnection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/PhpiredisStreamConnection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/PhpiredisStreamConnection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/PhpiredisStreamConnection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/PhpiredisStreamConnection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/StreamConnection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/StreamConnection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/StreamConnection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/StreamConnection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/WebdisConnection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/WebdisConnection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/WebdisConnection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Connection/WebdisConnection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Monitor/Consumer.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Monitor/Consumer.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Monitor/Consumer.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Monitor/Consumer.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/NotSupportedException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/NotSupportedException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/NotSupportedException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/NotSupportedException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/Atomic.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Pipeline/Atomic.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/Atomic.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Pipeline/Atomic.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/ConnectionErrorProof.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Pipeline/ConnectionErrorProof.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/ConnectionErrorProof.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Pipeline/ConnectionErrorProof.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/FireAndForget.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Pipeline/FireAndForget.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/FireAndForget.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Pipeline/FireAndForget.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/Pipeline.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Pipeline/Pipeline.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/Pipeline.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Pipeline/Pipeline.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PredisException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/PredisException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PredisException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/PredisException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/Factory.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/Factory.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/Factory.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/Factory.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/ProfileInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/ProfileInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/ProfileInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/ProfileInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisProfile.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisProfile.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisProfile.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisProfile.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisUnstable.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisUnstable.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisUnstable.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisUnstable.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion200.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion200.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion200.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion200.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion220.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion220.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion220.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion220.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion240.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion240.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion240.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion240.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion260.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion260.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion260.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion260.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion280.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion280.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion280.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion280.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion300.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion300.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion300.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Profile/RedisVersion300.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ProtocolException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/ProtocolException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ProtocolException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/ProtocolException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ProtocolProcessorInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/ProtocolProcessorInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ProtocolProcessorInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/ProtocolProcessorInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/RequestSerializerInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/RequestSerializerInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/RequestSerializerInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/RequestSerializerInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ResponseReaderInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/ResponseReaderInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ResponseReaderInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/ResponseReaderInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/CompositeProtocolProcessor.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/CompositeProtocolProcessor.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/CompositeProtocolProcessor.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/CompositeProtocolProcessor.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/BulkResponse.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/BulkResponse.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/BulkResponse.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/BulkResponse.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/ErrorResponse.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/ErrorResponse.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/ErrorResponse.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/ErrorResponse.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/IntegerResponse.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/IntegerResponse.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/IntegerResponse.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/IntegerResponse.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/MultiBulkResponse.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/MultiBulkResponse.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/MultiBulkResponse.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/MultiBulkResponse.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/ResponseHandlerInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/ResponseHandlerInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/ResponseHandlerInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/ResponseHandlerInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/StatusResponse.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/StatusResponse.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/StatusResponse.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/StatusResponse.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/StreamableMultiBulkResponse.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/StreamableMultiBulkResponse.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/StreamableMultiBulkResponse.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/Handler/StreamableMultiBulkResponse.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/ProtocolProcessor.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/ProtocolProcessor.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/ProtocolProcessor.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/ProtocolProcessor.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/RequestSerializer.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/RequestSerializer.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/RequestSerializer.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/RequestSerializer.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/ResponseReader.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/ResponseReader.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/ResponseReader.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Protocol/Text/ResponseReader.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/AbstractConsumer.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/PubSub/AbstractConsumer.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/AbstractConsumer.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/PubSub/AbstractConsumer.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/Consumer.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/PubSub/Consumer.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/Consumer.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/PubSub/Consumer.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/DispatcherLoop.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/PubSub/DispatcherLoop.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/DispatcherLoop.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/PubSub/DispatcherLoop.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Replication/ReplicationStrategy.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Replication/ReplicationStrategy.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Replication/ReplicationStrategy.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Replication/ReplicationStrategy.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Error.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/Error.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Error.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/Error.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ErrorInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/ErrorInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ErrorInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/ErrorInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulk.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/Iterator/MultiBulk.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulk.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/Iterator/MultiBulk.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulkIterator.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/Iterator/MultiBulkIterator.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulkIterator.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/Iterator/MultiBulkIterator.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulkTuple.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/Iterator/MultiBulkTuple.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulkTuple.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/Iterator/MultiBulkTuple.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ResponseInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/ResponseInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ResponseInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/ResponseInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ServerException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/ServerException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ServerException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/ServerException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Status.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/Status.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Status.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Response/Status.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Session/Handler.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Session/Handler.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Session/Handler.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Session/Handler.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/AbortedMultiExecException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Transaction/AbortedMultiExecException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/AbortedMultiExecException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Transaction/AbortedMultiExecException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/MultiExec.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Transaction/MultiExec.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/MultiExec.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Transaction/MultiExec.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/MultiExecState.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Transaction/MultiExecState.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/MultiExecState.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/Predis/Transaction/MultiExecState.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Actions.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Actions.php similarity index 99% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Actions.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Actions.php index 00102672..1e1263ec 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Actions.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Actions.php @@ -1257,11 +1257,12 @@ public function SetMailtoRequest($sTo) * @param string $sLogin * @param string $sPassword * @param string $sSignMeToken = '' + * @param string $sClientCert = '' * @param bool $bThrowProvideException = false * * @return \RainLoop\Model\Account|null */ - public function LoginProvide($sEmail, $sLogin, $sPassword, $sSignMeToken = '', $bThrowProvideException = false) + public function LoginProvide($sEmail, $sLogin, $sPassword, $sSignMeToken = '', $sClientCert = '', $bThrowProvideException = false) { $oAccount = null; if (0 < \strlen($sEmail) && 0 < \strlen($sLogin) && 0 < \strlen($sPassword)) @@ -1271,8 +1272,8 @@ public function LoginProvide($sEmail, $sLogin, $sPassword, $sSignMeToken = '', $ { if ($oDomain->ValidateWhiteList($sEmail, $sLogin)) { - $oAccount = \RainLoop\Model\Account::NewInstance($sEmail, $sLogin, $sPassword, $oDomain, $sSignMeToken); - $this->Plugins()->RunHook('filter.account', array(&$oAccount)); + $oAccount = \RainLoop\Model\Account::NewInstance($sEmail, $sLogin, $sPassword, $oDomain, $sSignMeToken, '', '', $sClientCert); + $this->Plugins()->RunHook('filter.acount', array(&$oAccount)); if ($bThrowProvideException && !($oAccount instanceof \RainLoop\Model\Account)) { @@ -1316,7 +1317,7 @@ public function GetAccountFromCustomToken($sToken, $bThrowExceptionOnFalse = tru ) { $oAccount = $this->LoginProvide($aAccountHash[1], $aAccountHash[2], $aAccountHash[3], - empty($aAccountHash[5]) ? '' : $aAccountHash[5], $bThrowExceptionOnFalse); + empty($aAccountHash[5]) ? '' : $aAccountHash[5], empty($aAccountHash[11]) ? '' : $aAccountHash[11], $bThrowExceptionOnFalse); if ($oAccount instanceof \RainLoop\Model\Account) { @@ -1510,7 +1511,6 @@ public function AppData($bAdmin, $bMobile = false, $bMobileDevice = false, $sAut 'LoadingDescriptionEsc' => 'RainLoop', 'FaviconUrl' => $oConfig->Get('webmail', 'favicon_url', ''), 'LoginDescription' => '', - 'LoginPowered' => true, 'LoginLogo' => '', 'LoginBackground' => '', 'LoginCss' => '', @@ -2247,10 +2247,10 @@ public function LoginProcess(&$sEmail, &$sPassword, $sSignMeToken = '', $this->Plugins()->RunHook('event.login-pre-login-provide', array()); $oAccount = null; - + $sClientCert = \trim($this->Config()->Get('ssl', 'client_cert', '')); try { - $oAccount = $this->LoginProvide($sEmail, $sLogin, $sPassword, $sSignMeToken, true); + $oAccount = $this->LoginProvide($sEmail, $sLogin, $sPassword, $sSignMeToken, $sClientCert, true); if (!($oAccount instanceof \RainLoop\Model\Account)) { @@ -4143,7 +4143,8 @@ public function DoAdminDomainTest() $iTime = \microtime(true); $oImapClient->Connect($oDomain->IncHost(), $oDomain->IncPort(), $oDomain->IncSecure(), !!$this->Config()->Get('ssl', 'verify_certificate', false), - !!$this->Config()->Get('ssl', 'allow_self_signed', true) + !!$this->Config()->Get('ssl', 'allow_self_signed', true), + $this->Config()->Get('ssl', 'client_cert', '') ); $iImapTime = \microtime(true) - $iTime; @@ -5890,6 +5891,8 @@ private function buildMessage($oAccount, $bWithDraftInfo = true) if (!$this->Config()->Get('security', 'hide_x_mailer_header', false)) { $oMessage->SetXMailer('RainLoop/'.APP_VERSION); + } else { + $oMessage->DoesNotAddDefaultXMailer(); } $oFromIdentity = $this->GetIdentityByID($oAccount, $sIdentityID); diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Api.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Api.php similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Api.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Api.php index 3c98d836..9013825d 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Api.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Api.php @@ -1,275 +1,275 @@ -Config(); - } - - /** - * @return \MailSo\Log\Logger - */ - public static function Logger() - { - return \RainLoop\Api::Actions()->Logger(); - } - - /** - * @return string - */ - public static function SetupDefaultMailSoConfig() - { - if (\class_exists('MailSo\Config')) - { - if (\RainLoop\Api::Config()->Get('labs', 'disable_iconv_if_mbstring_supported', false) && - \MailSo\Base\Utils::IsMbStringSupported() && \MailSo\Config::$MBSTRING) - { - \MailSo\Config::$ICONV = false; - } - - \MailSo\Config::$MessageListFastSimpleSearch = - !!\RainLoop\Api::Config()->Get('labs', 'imap_message_list_fast_simple_search', true); - - \MailSo\Config::$MessageListCountLimitTrigger = - (int) \RainLoop\Api::Config()->Get('labs', 'imap_message_list_count_limit_trigger', 0); - - \MailSo\Config::$MessageListDateFilter = - (int) \RainLoop\Api::Config()->Get('labs', 'imap_message_list_date_filter', 0); - - \MailSo\Config::$MessageListPermanentFilter = - \trim(\RainLoop\Api::Config()->Get('labs', 'imap_message_list_permanent_filter', '')); - - \MailSo\Config::$MessageAllHeaders = - !!\RainLoop\Api::Config()->Get('labs', 'imap_message_all_headers', false); - - \MailSo\Config::$LargeThreadLimit = - (int) \RainLoop\Api::Config()->Get('labs', 'imap_large_thread_limit', 50); - - \MailSo\Config::$ImapTimeout = - (int) \RainLoop\Api::Config()->Get('labs', 'imap_timeout', 300); - - \MailSo\Config::$BoundaryPrefix = '_RainLoop_'; - - \MailSo\Config::$SystemLogger = \RainLoop\Api::Logger(); - - $sSslCafile = \RainLoop\Api::Config()->Get('ssl', 'cafile', ''); - $sSslCapath = \RainLoop\Api::Config()->Get('ssl', 'capath', ''); - - \RainLoop\Utils::$CookieDefaultPath = \RainLoop\Api::Config()->Get('labs', 'cookie_default_path', ''); - if (\RainLoop\Api::Config()->Get('labs', 'cookie_default_secure', false)) - { - \RainLoop\Utils::$CookieDefaultSecure = true; - } - - if (!empty($sSslCafile) || !empty($sSslCapath)) - { - \MailSo\Hooks::Add('Net.NetClient.StreamContextSettings/Filter', function (&$aStreamContextSettings) use ($sSslCafile, $sSslCapath) { - if (isset($aStreamContextSettings['ssl']) && \is_array($aStreamContextSettings['ssl'])) - { - if (empty($aStreamContextSettings['ssl']['cafile']) && !empty($sSslCafile)) - { - $aStreamContextSettings['ssl']['cafile'] = $sSslCafile; - } - - if (empty($aStreamContextSettings['ssl']['capath']) && !empty($sSslCapath)) - { - $aStreamContextSettings['ssl']['capath'] = $sSslCapath; - } - } - }); - } - - \MailSo\Config::$HtmlStrictDebug = !!\RainLoop\Api::Config()->Get('debug', 'enable', false); - - \MailSo\Config::$CheckNewMessages = !!\RainLoop\Api::Config()->Get('labs', 'check_new_messages', true); - - if (\RainLoop\Api::Config()->Get('labs', 'strict_html_parser', true)) - { - \MailSo\Config::$HtmlStrictAllowedAttributes = array( - // rainloop - 'data-wrp', - // defaults - 'name', - 'dir', 'lang', 'style', 'title', - 'background', 'bgcolor', 'alt', 'height', 'width', 'src', 'href', - 'border', 'bordercolor', 'charset', 'direction', 'language', - // a - 'coords', 'download', 'hreflang', 'shape', - // body - 'alink', 'bgproperties', 'bottommargin', 'leftmargin', 'link', 'rightmargin', 'text', 'topmargin', 'vlink', - 'marginwidth', 'marginheight', 'offset', - // button, - 'disabled', 'type', 'value', - // col - 'align', 'valign', - // font - 'color', 'face', 'size', - // form - 'novalidate', - // hr - 'noshade', - // img - 'hspace', 'sizes', 'srcset', 'vspace', 'usemap', - // input, textarea - 'checked', 'max', 'min', 'maxlength', 'multiple', 'pattern', 'placeholder', 'readonly', 'required', 'step', 'wrap', - // label - 'for', - // meter - 'low', 'high', 'optimum', - // ol - 'reversed', 'start', - // option - 'selected', 'label', - // table - 'cols', 'rows', 'frame', 'rules', 'summary', 'cellpadding', 'cellspacing', - // td - 'abbr', 'axis', 'colspan', 'rowspan', 'headers', 'nowrap' - ); - } - } - } - - /** - * @return string - */ - public static function Version() - { - return APP_VERSION; - } - - /** - * @param string $sEmail - * @param string $sPassword - * @param array $aAdditionalOptions = array() - * @param bool $bUseTimeout = true - * - * @return string - */ - public static function GetUserSsoHash($sEmail, $sPassword, $aAdditionalOptions = array(), $bUseTimeout = true) - { - $sSsoHash = \MailSo\Base\Utils::Sha1Rand(\md5($sEmail).\md5($sPassword)); - - return \RainLoop\Api::Actions()->Cacher()->Set(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash), - \RainLoop\Utils::EncodeKeyValuesQ(array( - 'Email' => $sEmail, - 'Password' => $sPassword, - 'AdditionalOptions' => $aAdditionalOptions, - 'Time' => $bUseTimeout ? \time() : 0 - ))) ? $sSsoHash : ''; - } - - /** - * @param string $sSsoHash - * - * @return bool - */ - public static function ClearUserSsoHash($sSsoHash) - { - return \RainLoop\Api::Actions()->Cacher()->Delete(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash)); - } - - /** - * @param string $sEmail - * - * @return bool - */ - public static function ClearUserData($sEmail) - { - if (0 < \strlen($sEmail)) - { - $sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail); - - $oStorageProvider = \RainLoop\Api::Actions()->StorageProvider(); - if ($oStorageProvider && $oStorageProvider->IsActive()) - { - $oStorageProvider->DeleteStorage($sEmail); - } - - if (\RainLoop\Api::Actions()->AddressBookProvider() && - \RainLoop\Api::Actions()->AddressBookProvider()->IsActive()) - { - \RainLoop\Api::Actions()->AddressBookProvider()->DeleteAllContacts($sEmail); - } - - return true; - } - - return false; - } - - /** - * @return bool - */ - public static function LogoutCurrentLogginedUser() - { - \RainLoop\Utils::ClearCookie('rlsession'); - return true; - } - - /** - * @return void - */ - public static function ExitOnEnd() - { - if (!\defined('RAINLOOP_EXIT_ON_END')) - { - \define('RAINLOOP_EXIT_ON_END', true); - } - } -} +Config(); + } + + /** + * @return \MailSo\Log\Logger + */ + public static function Logger() + { + return \RainLoop\Api::Actions()->Logger(); + } + + /** + * @return string + */ + public static function SetupDefaultMailSoConfig() + { + if (\class_exists('MailSo\Config')) + { + if (\RainLoop\Api::Config()->Get('labs', 'disable_iconv_if_mbstring_supported', false) && + \MailSo\Base\Utils::IsMbStringSupported() && \MailSo\Config::$MBSTRING) + { + \MailSo\Config::$ICONV = false; + } + + \MailSo\Config::$MessageListFastSimpleSearch = + !!\RainLoop\Api::Config()->Get('labs', 'imap_message_list_fast_simple_search', true); + + \MailSo\Config::$MessageListCountLimitTrigger = + (int) \RainLoop\Api::Config()->Get('labs', 'imap_message_list_count_limit_trigger', 0); + + \MailSo\Config::$MessageListDateFilter = + (int) \RainLoop\Api::Config()->Get('labs', 'imap_message_list_date_filter', 0); + + \MailSo\Config::$MessageListPermanentFilter = + \trim(\RainLoop\Api::Config()->Get('labs', 'imap_message_list_permanent_filter', '')); + + \MailSo\Config::$MessageAllHeaders = + !!\RainLoop\Api::Config()->Get('labs', 'imap_message_all_headers', false); + + \MailSo\Config::$LargeThreadLimit = + (int) \RainLoop\Api::Config()->Get('labs', 'imap_large_thread_limit', 50); + + \MailSo\Config::$ImapTimeout = + (int) \RainLoop\Api::Config()->Get('labs', 'imap_timeout', 300); + + \MailSo\Config::$BoundaryPrefix = '_RainLoop_'; + + \MailSo\Config::$SystemLogger = \RainLoop\Api::Logger(); + + $sSslCafile = \RainLoop\Api::Config()->Get('ssl', 'cafile', ''); + $sSslCapath = \RainLoop\Api::Config()->Get('ssl', 'capath', ''); + + \RainLoop\Utils::$CookieDefaultPath = \RainLoop\Api::Config()->Get('labs', 'cookie_default_path', ''); + if (\RainLoop\Api::Config()->Get('labs', 'cookie_default_secure', false)) + { + \RainLoop\Utils::$CookieDefaultSecure = true; + } + + if (!empty($sSslCafile) || !empty($sSslCapath)) + { + \MailSo\Hooks::Add('Net.NetClient.StreamContextSettings/Filter', function (&$aStreamContextSettings) use ($sSslCafile, $sSslCapath) { + if (isset($aStreamContextSettings['ssl']) && \is_array($aStreamContextSettings['ssl'])) + { + if (empty($aStreamContextSettings['ssl']['cafile']) && !empty($sSslCafile)) + { + $aStreamContextSettings['ssl']['cafile'] = $sSslCafile; + } + + if (empty($aStreamContextSettings['ssl']['capath']) && !empty($sSslCapath)) + { + $aStreamContextSettings['ssl']['capath'] = $sSslCapath; + } + } + }); + } + + \MailSo\Config::$HtmlStrictDebug = !!\RainLoop\Api::Config()->Get('debug', 'enable', false); + + \MailSo\Config::$CheckNewMessages = !!\RainLoop\Api::Config()->Get('labs', 'check_new_messages', true); + + if (\RainLoop\Api::Config()->Get('labs', 'strict_html_parser', true)) + { + \MailSo\Config::$HtmlStrictAllowedAttributes = array( + // rainloop + 'data-wrp', + // defaults + 'name', + 'dir', 'lang', 'style', 'title', + 'background', 'bgcolor', 'alt', 'height', 'width', 'src', 'href', + 'border', 'bordercolor', 'charset', 'direction', 'language', + // a + 'coords', 'download', 'hreflang', 'shape', + // body + 'alink', 'bgproperties', 'bottommargin', 'leftmargin', 'link', 'rightmargin', 'text', 'topmargin', 'vlink', + 'marginwidth', 'marginheight', 'offset', + // button, + 'disabled', 'type', 'value', + // col + 'align', 'valign', + // font + 'color', 'face', 'size', + // form + 'novalidate', + // hr + 'noshade', + // img + 'hspace', 'sizes', 'srcset', 'vspace', 'usemap', + // input, textarea + 'checked', 'max', 'min', 'maxlength', 'multiple', 'pattern', 'placeholder', 'readonly', 'required', 'step', 'wrap', + // label + 'for', + // meter + 'low', 'high', 'optimum', + // ol + 'reversed', 'start', + // option + 'selected', 'label', + // table + 'cols', 'rows', 'frame', 'rules', 'summary', 'cellpadding', 'cellspacing', + // td + 'abbr', 'axis', 'colspan', 'rowspan', 'headers', 'nowrap' + ); + } + } + } + + /** + * @return string + */ + public static function Version() + { + return APP_VERSION; + } + + /** + * @param string $sEmail + * @param string $sPassword + * @param array $aAdditionalOptions = array() + * @param bool $bUseTimeout = true + * + * @return string + */ + public static function GetUserSsoHash($sEmail, $sPassword, $aAdditionalOptions = array(), $bUseTimeout = true) + { + $sSsoHash = \MailSo\Base\Utils::Sha1Rand(\md5($sEmail).\md5($sPassword)); + + return \RainLoop\Api::Actions()->Cacher()->Set(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash), + \RainLoop\Utils::EncodeKeyValuesQ(array( + 'Email' => $sEmail, + 'Password' => $sPassword, + 'AdditionalOptions' => $aAdditionalOptions, + 'Time' => $bUseTimeout ? \time() : 0 + ))) ? $sSsoHash : ''; + } + + /** + * @param string $sSsoHash + * + * @return bool + */ + public static function ClearUserSsoHash($sSsoHash) + { + return \RainLoop\Api::Actions()->Cacher()->Delete(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash)); + } + + /** + * @param string $sEmail + * + * @return bool + */ + public static function ClearUserData($sEmail) + { + if (0 < \strlen($sEmail)) + { + $sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail); + + $oStorageProvider = \RainLoop\Api::Actions()->StorageProvider(); + if ($oStorageProvider && $oStorageProvider->IsActive()) + { + $oStorageProvider->DeleteStorage($sEmail); + } + + if (\RainLoop\Api::Actions()->AddressBookProvider() && + \RainLoop\Api::Actions()->AddressBookProvider()->IsActive()) + { + \RainLoop\Api::Actions()->AddressBookProvider()->DeleteAllContacts($sEmail); + } + + return true; + } + + return false; + } + + /** + * @return bool + */ + public static function LogoutCurrentLogginedUser() + { + \RainLoop\Utils::ClearCookie('rlsession'); + return true; + } + + /** + * @return void + */ + public static function ExitOnEnd() + { + if (!\defined('RAINLOOP_EXIT_ON_END')) + { + \define('RAINLOOP_EXIT_ON_END', true); + } + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Common/BackwardCapability/Account.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Common/BackwardCapability/Account.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Common/BackwardCapability/Account.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Common/BackwardCapability/Account.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Common/FacebookRainLoopPersistentDataHandler.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Common/FacebookRainLoopPersistentDataHandler.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Common/FacebookRainLoopPersistentDataHandler.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Common/FacebookRainLoopPersistentDataHandler.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Common/MbStringFix.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Common/MbStringFix.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Common/MbStringFix.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Common/MbStringFix.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Common/PdoAbstract.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Common/PdoAbstract.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Common/PdoAbstract.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Common/PdoAbstract.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Common/RainLoopFacebookRedirectLoginHelper.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Common/RainLoopFacebookRedirectLoginHelper.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Common/RainLoopFacebookRedirectLoginHelper.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Common/RainLoopFacebookRedirectLoginHelper.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Config/AbstractConfig.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Config/AbstractConfig.php similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Config/AbstractConfig.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Config/AbstractConfig.php index b188ddd0..5fe2ca2f 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Config/AbstractConfig.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Config/AbstractConfig.php @@ -1,343 +1,343 @@ -sFile = \APP_PRIVATE_DATA.'configs/'.\trim($sFileName); - - $sAdditionalFileName = \trim($sAdditionalFileName); - $this->sAdditionalFile = \APP_PRIVATE_DATA.'configs/'.$sAdditionalFileName; - $this->sAdditionalFile = 0 < \strlen($sAdditionalFileName) && - \file_exists($this->sAdditionalFile) ? $this->sAdditionalFile : ''; - - $this->sFileHeader = $sFileHeader; - $this->aData = $this->defaultValues(); - - $this->bUseApcCache = APP_USE_APC_CACHE && - \MailSo\Base\Utils::FunctionExistsAndEnabled(array('apc_fetch', 'apc_store')); - } - - /** - * @return array - */ - protected abstract function defaultValues(); - - /** - * @return bool - */ - public function IsInited() - { - return \is_array($this->aData) && 0 < \count($this->aData); - } - - /** - * @param string $sSection - * @param string $sName - * @param mixed $mDefault = null - * - * @return mixed - */ - public function Get($sSection, $sName, $mDefault = null) - { - $mResult = $mDefault; - if (isset($this->aData[$sSection][$sName][0])) - { - $mResult = $this->aData[$sSection][$sName][0]; - } - return $mResult; - } - - /** - * @param string $sSectionKey - * @param string $sParamKey - * @param mixed $mParamValue - * - * @return void - */ - public function Set($sSectionKey, $sParamKey, $mParamValue) - { - if (isset($this->aData[$sSectionKey][$sParamKey][0])) - { - $sType = \gettype($this->aData[$sSectionKey][$sParamKey][0]); - switch ($sType) - { - default: - case 'float': - case 'string': - $this->aData[$sSectionKey][$sParamKey][0] = (string) $mParamValue; - break; - case 'int': - case 'integer': - $this->aData[$sSectionKey][$sParamKey][0] = (int) $mParamValue; - break; - case 'bool': - case 'boolean': - $this->aData[$sSectionKey][$sParamKey][0] = (bool) $mParamValue; - break; - } - } - else if ('custom' === $sSectionKey) - { - $this->aData[$sSectionKey][$sParamKey] = array((string) $mParamValue); - } - } - - /** - * @return string - */ - private function cacheKey() - { - return 'config:'.\sha1($this->sFile).':'.\sha1($this->sAdditionalFile).':'; - } - - /** - * @return bool - */ - private function loadDataFromCache() - { - if ($this->bUseApcCache) - { - $iMTime = @\filemtime($this->sFile); - $iMTime = \is_int($iMTime) && 0 < $iMTime ? $iMTime : 0; - - $iATime = $this->sAdditionalFile ? @\filemtime($this->sAdditionalFile) : 0; - $iATime = \is_int($iATime) && 0 < $iATime ? $iATime : 0; - - if (0 < $iMTime) - { - $sKey = $this->cacheKey(); - - $sTimeHash = \apc_fetch($sKey.'time'); - if ($sTimeHash && $sTimeHash === \md5($iMTime.'/'.$iATime)) - { - $aFetchData = \apc_fetch($sKey.'data'); - if (\is_array($aFetchData)) - { - $this->aData = $aFetchData; - return true; - } - } - } - } - - return false; - } - - /** - * @return bool - */ - private function storeDataToCache() - { - if ($this->bUseApcCache) - { - $iMTime = @\filemtime($this->sFile); - $iMTime = \is_int($iMTime) && 0 < $iMTime ? $iMTime : 0; - - $iATime = $this->sAdditionalFile ? @\filemtime($this->sAdditionalFile) : 0; - $iATime = \is_int($iATime) && 0 < $iATime ? $iATime : 0; - - if (0 < $iMTime) - { - $sKey = $this->cacheKey(); - - \apc_store($sKey.'time', \md5($iMTime.'/'.$iATime)); - \apc_store($sKey.'data', $this->aData); - - return true; - } - } - - return false; - } - - /** - * @return bool - */ - private function clearCache() - { - if ($this->bUseApcCache) - { - $sKey = $this->cacheKey(); - - \apc_delete($sKey.'time'); - \apc_delete($sKey.'data'); - - return true; - } - - return false; - } - - /** - * @return bool - */ - public function IsFileExists() - { - return \file_exists($this->sFile); - } - - /** - * @return bool - */ - public function Load() - { - if (\file_exists($this->sFile) && \is_readable($this->sFile)) - { - if ($this->loadDataFromCache()) - { - return true; - } - - $aData = \RainLoop\Utils::CustomParseIniFile($this->sFile, true); - if (\is_array($aData) && 0 < \count($aData)) - { - foreach ($aData as $sSectionKey => $aSectionValue) - { - if (\is_array($aSectionValue)) - { - foreach ($aSectionValue as $sParamKey => $mParamValue) - { - $this->Set($sSectionKey, $sParamKey, $mParamValue); - } - } - } - - unset($aData); - - if (\file_exists($this->sAdditionalFile) && \is_readable($this->sAdditionalFile)) - { - $aSubData = \RainLoop\Utils::CustomParseIniFile($this->sAdditionalFile, true); - if (\is_array($aSubData) && 0 < \count($aSubData)) - { - foreach ($aSubData as $sSectionKey => $aSectionValue) - { - if (\is_array($aSectionValue)) - { - foreach ($aSectionValue as $sParamKey => $mParamValue) - { - $this->Set($sSectionKey, $sParamKey, $mParamValue); - } - } - } - } - - unset($aSubData); - } - - $this->storeDataToCache(); - - return true; - } - } - - return false; - } - - /** - * @return bool - */ - public function Save() - { - if (\file_exists($this->sFile) && !\is_writable($this->sFile)) - { - return false; - } - - $sNewLine = "\n"; - - $aResultLines = array(); - - foreach ($this->aData as $sSectionKey => $aSectionValue) - { - if (\is_array($aSectionValue)) - { - $aResultLines[] = ''; - $aResultLines[] = '['.$sSectionKey.']'; - $bFirst = true; - - foreach ($aSectionValue as $sParamKey => $mParamValue) - { - if (\is_array($mParamValue)) - { - if (!empty($mParamValue[1])) - { - $sDesk = \str_replace("\r", '', $mParamValue[1]); - $aDesk = \explode("\n", $sDesk); - $aDesk = \array_map(function (&$sLine) { - return '; '.$sLine; - }, $aDesk); - - if (!$bFirst) - { - $aResultLines[] = ''; - } - - $aResultLines[] = \implode($sNewLine, $aDesk); - } - - $bFirst = false; - - $sValue = '""'; - switch (\gettype($mParamValue[0])) - { - default: - case 'string': - $sValue = '"'.\str_replace('"', '\"', $mParamValue[0]).'"'; - break; - case 'int': - case 'integer': - $sValue = $mParamValue[0]; - break; - case 'bool': - case 'boolean': - $sValue = $mParamValue[0] ? 'On' : 'Off'; - break; - } - - $aResultLines[] = $sParamKey.' = '.$sValue; - } - } - } - } - - $this->clearCache(); - return false !== \file_put_contents($this->sFile, - (0 < \strlen($this->sFileHeader) ? $this->sFileHeader : ''). - $sNewLine.\implode($sNewLine, $aResultLines)); - } -} +sFile = \APP_PRIVATE_DATA.'configs/'.\trim($sFileName); + + $sAdditionalFileName = \trim($sAdditionalFileName); + $this->sAdditionalFile = \APP_PRIVATE_DATA.'configs/'.$sAdditionalFileName; + $this->sAdditionalFile = 0 < \strlen($sAdditionalFileName) && + \file_exists($this->sAdditionalFile) ? $this->sAdditionalFile : ''; + + $this->sFileHeader = $sFileHeader; + $this->aData = $this->defaultValues(); + + $this->bUseApcCache = APP_USE_APC_CACHE && + \MailSo\Base\Utils::FunctionExistsAndEnabled(array('apc_fetch', 'apc_store')); + } + + /** + * @return array + */ + protected abstract function defaultValues(); + + /** + * @return bool + */ + public function IsInited() + { + return \is_array($this->aData) && 0 < \count($this->aData); + } + + /** + * @param string $sSection + * @param string $sName + * @param mixed $mDefault = null + * + * @return mixed + */ + public function Get($sSection, $sName, $mDefault = null) + { + $mResult = $mDefault; + if (isset($this->aData[$sSection][$sName][0])) + { + $mResult = $this->aData[$sSection][$sName][0]; + } + return $mResult; + } + + /** + * @param string $sSectionKey + * @param string $sParamKey + * @param mixed $mParamValue + * + * @return void + */ + public function Set($sSectionKey, $sParamKey, $mParamValue) + { + if (isset($this->aData[$sSectionKey][$sParamKey][0])) + { + $sType = \gettype($this->aData[$sSectionKey][$sParamKey][0]); + switch ($sType) + { + default: + case 'float': + case 'string': + $this->aData[$sSectionKey][$sParamKey][0] = (string) $mParamValue; + break; + case 'int': + case 'integer': + $this->aData[$sSectionKey][$sParamKey][0] = (int) $mParamValue; + break; + case 'bool': + case 'boolean': + $this->aData[$sSectionKey][$sParamKey][0] = (bool) $mParamValue; + break; + } + } + else if ('custom' === $sSectionKey) + { + $this->aData[$sSectionKey][$sParamKey] = array((string) $mParamValue); + } + } + + /** + * @return string + */ + private function cacheKey() + { + return 'config:'.\sha1($this->sFile).':'.\sha1($this->sAdditionalFile).':'; + } + + /** + * @return bool + */ + private function loadDataFromCache() + { + if ($this->bUseApcCache) + { + $iMTime = @\filemtime($this->sFile); + $iMTime = \is_int($iMTime) && 0 < $iMTime ? $iMTime : 0; + + $iATime = $this->sAdditionalFile ? @\filemtime($this->sAdditionalFile) : 0; + $iATime = \is_int($iATime) && 0 < $iATime ? $iATime : 0; + + if (0 < $iMTime) + { + $sKey = $this->cacheKey(); + + $sTimeHash = \apc_fetch($sKey.'time'); + if ($sTimeHash && $sTimeHash === \md5($iMTime.'/'.$iATime)) + { + $aFetchData = \apc_fetch($sKey.'data'); + if (\is_array($aFetchData)) + { + $this->aData = $aFetchData; + return true; + } + } + } + } + + return false; + } + + /** + * @return bool + */ + private function storeDataToCache() + { + if ($this->bUseApcCache) + { + $iMTime = @\filemtime($this->sFile); + $iMTime = \is_int($iMTime) && 0 < $iMTime ? $iMTime : 0; + + $iATime = $this->sAdditionalFile ? @\filemtime($this->sAdditionalFile) : 0; + $iATime = \is_int($iATime) && 0 < $iATime ? $iATime : 0; + + if (0 < $iMTime) + { + $sKey = $this->cacheKey(); + + \apc_store($sKey.'time', \md5($iMTime.'/'.$iATime)); + \apc_store($sKey.'data', $this->aData); + + return true; + } + } + + return false; + } + + /** + * @return bool + */ + private function clearCache() + { + if ($this->bUseApcCache) + { + $sKey = $this->cacheKey(); + + \apc_delete($sKey.'time'); + \apc_delete($sKey.'data'); + + return true; + } + + return false; + } + + /** + * @return bool + */ + public function IsFileExists() + { + return \file_exists($this->sFile); + } + + /** + * @return bool + */ + public function Load() + { + if (\file_exists($this->sFile) && \is_readable($this->sFile)) + { + if ($this->loadDataFromCache()) + { + return true; + } + + $aData = \RainLoop\Utils::CustomParseIniFile($this->sFile, true); + if (\is_array($aData) && 0 < \count($aData)) + { + foreach ($aData as $sSectionKey => $aSectionValue) + { + if (\is_array($aSectionValue)) + { + foreach ($aSectionValue as $sParamKey => $mParamValue) + { + $this->Set($sSectionKey, $sParamKey, $mParamValue); + } + } + } + + unset($aData); + + if (\file_exists($this->sAdditionalFile) && \is_readable($this->sAdditionalFile)) + { + $aSubData = \RainLoop\Utils::CustomParseIniFile($this->sAdditionalFile, true); + if (\is_array($aSubData) && 0 < \count($aSubData)) + { + foreach ($aSubData as $sSectionKey => $aSectionValue) + { + if (\is_array($aSectionValue)) + { + foreach ($aSectionValue as $sParamKey => $mParamValue) + { + $this->Set($sSectionKey, $sParamKey, $mParamValue); + } + } + } + } + + unset($aSubData); + } + + $this->storeDataToCache(); + + return true; + } + } + + return false; + } + + /** + * @return bool + */ + public function Save() + { + if (\file_exists($this->sFile) && !\is_writable($this->sFile)) + { + return false; + } + + $sNewLine = "\n"; + + $aResultLines = array(); + + foreach ($this->aData as $sSectionKey => $aSectionValue) + { + if (\is_array($aSectionValue)) + { + $aResultLines[] = ''; + $aResultLines[] = '['.$sSectionKey.']'; + $bFirst = true; + + foreach ($aSectionValue as $sParamKey => $mParamValue) + { + if (\is_array($mParamValue)) + { + if (!empty($mParamValue[1])) + { + $sDesk = \str_replace("\r", '', $mParamValue[1]); + $aDesk = \explode("\n", $sDesk); + $aDesk = \array_map(function (&$sLine) { + return '; '.$sLine; + }, $aDesk); + + if (!$bFirst) + { + $aResultLines[] = ''; + } + + $aResultLines[] = \implode($sNewLine, $aDesk); + } + + $bFirst = false; + + $sValue = '""'; + switch (\gettype($mParamValue[0])) + { + default: + case 'string': + $sValue = '"'.\str_replace('"', '\"', $mParamValue[0]).'"'; + break; + case 'int': + case 'integer': + $sValue = $mParamValue[0]; + break; + case 'bool': + case 'boolean': + $sValue = $mParamValue[0] ? 'On' : 'Off'; + break; + } + + $aResultLines[] = $sParamKey.' = '.$sValue; + } + } + } + } + + $this->clearCache(); + return false !== \file_put_contents($this->sFile, + (0 < \strlen($this->sFileHeader) ? $this->sFileHeader : ''). + $sNewLine.\implode($sNewLine, $aResultLines)); + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Config/Application.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Config/Application.php similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Config/Application.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Config/Application.php index a7db9d74..c4316703 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Config/Application.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Config/Application.php @@ -1,471 +1,474 @@ -aReplaceEnv = null; - if ((isset($_ENV) && \is_array($_ENV) && 0 < \count($_ENV)) || - (isset($_SERVER) && \is_array($_SERVER) && 0 < \count($_SERVER))) - { - $sEnvNames = $this->Get('labs', 'replace_env_in_configuration', ''); - if (0 < \strlen($sEnvNames)) - { - $this->aReplaceEnv = \explode(',', $sEnvNames); - if (\is_array($this->aReplaceEnv)) - { - $this->aReplaceEnv = \array_map('trim', $this->aReplaceEnv); - $this->aReplaceEnv = \array_map('strtolower', $this->aReplaceEnv); - } - } - } - - if (!\is_array($this->aReplaceEnv) || 0 === \count($this->aReplaceEnv)) - { - $this->aReplaceEnv = null; - } - } - - /** - * @param string $sSection - * @param string $sName - * @param mixed $mDefault = null - * - * @return mixed - */ - public function Get($sSection, $sName, $mDefault = null) - { - $mResult = parent::Get($sSection, $sName, $mDefault); - if ($this->aReplaceEnv && \is_string($mResult)) - { - $sKey = \strtolower($sSection.'.'.$sName); - if (\in_array($sKey, $this->aReplaceEnv) && false !== strpos($mResult, '$')) - { - $mResult = \preg_replace_callback('/\$([^\s]+)/', function($aMatch) { - - if (!empty($aMatch[0]) && !empty($aMatch[1])) - { - if (!empty($_ENV[$aMatch[1]])) - { - return $_SERVER[$aMatch[1]]; - } - - if (!empty($_SERVER[$aMatch[1]])) - { - return $_SERVER[$aMatch[1]]; - } - - return $aMatch[0]; - } - - return ''; - - }, $mResult); - } - } - - return $mResult; - } - - /** - * @param string $sPassword - * - * @return void - */ - public function SetPassword($sPassword) - { - return $this->Set('security', 'admin_password', \md5(APP_SALT.$sPassword.APP_SALT)); - } - - /** - * @param string $sPassword - * - * @return bool - */ - public function ValidatePassword($sPassword) - { - $sPassword = (string) $sPassword; - $sConfigPassword = (string) $this->Get('security', 'admin_password', ''); - - return 0 < \strlen($sPassword) && - (($sPassword === $sConfigPassword && '12345' === $sConfigPassword) || \md5(APP_SALT.$sPassword.APP_SALT) === $sConfigPassword); - } - - /** - * @return bool - */ - public function Save() - { - $this->Set('version', 'current', APP_VERSION); - $this->Set('version', 'saved', \gmdate('r')); - - return parent::Save(); - } - - /** - * @return array - */ - protected function defaultValues() - { - return array( - - 'webmail' => array( - - 'title' => array('RainLoop Webmail', 'Text displayed as page title'), - 'loading_description' => array('RainLoop', 'Text displayed on startup'), - 'favicon_url' => array('', ''), - - 'theme' => array('Default', 'Theme used by default'), - 'allow_themes' => array(true, 'Allow theme selection on settings screen'), - 'allow_user_background' => array(false), - - 'language' => array('en', 'Language used by default'), - 'language_admin' => array('en', 'Admin Panel interface language'), - 'allow_languages_on_settings' => array(true, 'Allow language selection on settings screen'), - - 'allow_additional_accounts' => array(true, ''), - 'allow_additional_identities' => array(true, ''), - - 'messages_per_page' => array(20, ' Number of messages displayed on page by default'), - - 'attachment_size_limit' => array(25, - 'File size limit (MB) for file upload on compose screen -0 for unlimited.') - ), - - 'interface' => array( - 'show_attachment_thumbnail' => array(true, ''), - 'use_native_scrollbars' => array(false), - 'new_move_to_folder_button' => array(true) - ), - - 'branding' => array( - 'login_logo' => array(''), - 'login_background' => array(''), - 'login_desc' => array(''), - 'login_css' => array(''), - 'login_powered' => array(true), - - 'user_css' => array(''), - 'user_logo' => array(''), - 'user_logo_title' => array(''), - 'user_logo_message' => array(''), - 'user_iframe_message' => array(''), - - 'welcome_page_url' => array(''), - 'welcome_page_display' => array('none') - ), - - 'contacts' => array( - 'enable' => array(false, 'Enable contacts'), - 'allow_sync' => array(false), - 'sync_interval' => array(20), - 'type' => array('sqlite', ''), - 'pdo_dsn' => array('mysql:host=127.0.0.1;port=3306;dbname=rainloop', ''), - 'pdo_user' => array('root', ''), - 'pdo_password' => array('', ''), - 'suggestions_limit' => array(30) - ), - - 'security' => array( - 'csrf_protection' => array(true, - 'Enable CSRF protection (http://en.wikipedia.org/wiki/Cross-site_request_forgery)'), - - 'custom_server_signature' => array('RainLoop'), - 'x_frame_options_header' => array(''), - - 'openpgp' => array(false), - - 'admin_login' => array('admin', 'Login and password for web admin panel'), - 'admin_password' => array('12345'), - 'allow_admin_panel' => array(true, 'Access settings'), - 'allow_two_factor_auth' => array(false), - 'force_two_factor_auth' => array(false), - 'hide_x_mailer_header' => array(false), - 'admin_panel_host' => array(''), - 'admin_panel_key' => array('admin'), - 'content_security_policy' => array(''), - 'core_install_access_domain' => array('') - ), - - 'ssl' => array( - 'verify_certificate' => array(false, 'Require verification of SSL certificate used.'), - 'allow_self_signed' => array(true, 'Allow self-signed certificates. Requires verify_certificate.'), - 'cafile' => array('', 'Location of Certificate Authority file on local filesystem (/etc/ssl/certs/ca-certificates.crt)'), - 'capath' => array('', 'capath must be a correctly hashed certificate directory. (/etc/ssl/certs/)'), - ), - - 'capa' => array( - 'folders' => array(true), - 'composer' => array(true), - 'contacts' => array(true), - 'settings' => array(true), - 'quota' => array(true), - 'help' => array(true), - 'reload' => array(true), - 'search' => array(true), - 'search_adv' => array(true), - 'filters' => array(true), - 'x-templates' => array(false), - 'dangerous_actions' => array(true), - 'message_actions' => array(true), - 'messagelist_actions' => array(true), - 'attachments_actions' => array(true) - ), - - 'login' => array( - - 'default_domain' => array('', ''), - - 'allow_languages_on_login' => array(true, - 'Allow language selection on webmail login screen'), - - 'determine_user_language' => array(true, ''), - 'determine_user_domain' => array(false, ''), - - 'welcome_page' => array(false, ''), - - 'hide_submit_button' => array(true), - - 'forgot_password_link_url' => array('', ''), - 'registration_link_url' => array('', ''), - - 'login_lowercase' => array(true, ''), - - 'sign_me_auto' => array(\RainLoop\Enumerations\SignMeType::DEFAILT_OFF, - 'This option allows webmail to remember the logged in user -once they closed the browser window. - -Values: - "DefaultOff" - can be used, disabled by default; - "DefaultOn" - can be used, enabled by default; - "Unused" - cannot be used') - ), - - 'plugins' => array( - 'enable' => array(false, 'Enable plugin support'), - 'enabled_list' => array('', 'List of enabled plugins'), - ), - - 'defaults' => array( - 'view_editor_type' => array('Html', 'Editor mode used by default (Plain, Html, HtmlForced or PlainForced)'), - 'view_layout' => array(1, 'layout: 0 - no preview, 1 - side preview, 2 - bottom preview'), - 'view_use_checkboxes' => array(true), - 'autologout' => array(30), - 'show_images' => array(false), - 'contacts_autosave' => array(true), - 'mail_use_threads' => array(false), - 'allow_draft_autosave' => array(true), - 'mail_reply_same_folder' => array(false) - ), - - 'logs' => array( - - 'enable' => array(false, 'Enable logging'), - - 'write_on_error_only' => array(false, 'Logs entire request only if error occured (php requred)'), - 'write_on_php_error_only' => array(false, 'Logs entire request only if php error occured'), - 'write_on_timeout_only' => array(0, 'Logs entire request only if request timeout (in seconds) occured.'), - - 'hide_passwords' => array(true, 'Required for development purposes only. -Disabling this option is not recommended.'), - - 'time_offset' => array('0'), - 'session_filter' => array(''), - - 'filename' => array('log-{date:Y-m-d}.txt', - 'Log filename. -For security reasons, some characters are removed from filename. -Allows for pattern-based folder creation (see examples below). - -Patterns: - {date:Y-m-d} - Replaced by pattern-based date - Detailed info: http://www.php.net/manual/en/function.date.php - {user:email} - Replaced by user\'s email address - If user is not logged in, value is set to "unknown" - {user:login} - Replaced by user\'s login (the user part of an email) - If user is not logged in, value is set to "unknown" - {user:domain} - Replaced by user\'s domain name (the domain part of an email) - If user is not logged in, value is set to "unknown" - {user:uid} - Replaced by user\'s UID regardless of account currently used - - {user:ip} - {request:ip} - Replaced by user\'s IP address - -Others: - {imap:login} {imap:host} {imap:port} - {smtp:login} {smtp:host} {smtp:port} - -Examples: - filename = "log-{date:Y-m-d}.txt" - filename = "{date:Y-m-d}/{user:domain}/{user:email}_{user:uid}.log" - filename = "{user:email}-{date:Y-m-d}.txt"'), - - 'auth_logging' => array(false, 'Enable auth logging in a separate file (for fail2ban)'), - 'auth_logging_filename' => array('fail2ban/auth-{date:Y-m-d}.txt'), - 'auth_logging_format' => array('[{date:Y-m-d H:i:s}] Auth failed: ip={request:ip} user={imap:login} host={imap:host} port={imap:port}') - ), - - 'debug' => array( - 'enable' => array(false, 'Special option required for development purposes') - ), - - 'social' => array( - 'google_enable' => array(false, 'Google'), - 'google_enable_auth' => array(false), - 'google_enable_auth_fast' => array(false), - 'google_enable_drive' => array(false), - 'google_enable_preview' => array(false), - 'google_client_id' => array(''), - 'google_client_secret' => array(''), - 'google_api_key' => array(''), - - 'fb_enable' => array(false, 'Facebook'), - 'fb_app_id' => array(''), - 'fb_app_secret' => array(''), - - 'twitter_enable' => array(false, 'Twitter'), - 'twitter_consumer_key' => array(''), - 'twitter_consumer_secret' => array(''), - - 'dropbox_enable' => array(false, 'Dropbox'), - 'dropbox_api_key' => array('') - ), - - 'cache' => array( - 'enable' => array(true, - 'The section controls caching of the entire application. - -Enables caching in the system'), - - 'index' => array('v1', 'Additional caching key. If changed, cache is purged'), - - 'fast_cache_driver' => array('files', 'Can be: files, APC, memcache, redis (beta)'), - 'fast_cache_index' => array('v1', 'Additional caching key. If changed, fast cache is purged'), - - 'http' => array(true, 'Browser-level cache. If enabled, caching is maintainted without using files'), - 'http_expires' => array(3600, 'Browser-level cache time (seconds, Expires header)'), - - 'server_uids' => array(true, 'Caching message UIDs when searching and sorting (threading)') - ), - - 'labs' => array( - 'allow_mobile_version' => array(true, - 'Experimental settings. Handle with care. -'), - 'ignore_folders_subscription' => array(false), - 'check_new_password_strength' => array(true), - 'update_channel' => array('stable'), - 'allow_gravatar' => array(true), - 'allow_prefetch' => array(true), - 'allow_smart_html_links' => array(true), - 'cache_system_data' => array(true), - 'date_from_headers' => array(true), - 'autocreate_system_folders' => array(true), - 'allow_message_append' => array(false), - 'disable_iconv_if_mbstring_supported' => array(false), - 'login_fault_delay' => array(1), - 'log_ajax_response_write_limit' => array(300), - 'allow_html_editor_source_button' => array(false), - 'allow_html_editor_biti_buttons' => array(false), - 'allow_ctrl_enter_on_compose' => array(true), - 'try_to_detect_hidden_images' => array(false), - 'hide_dangerous_actions' => array(false), - 'use_app_debug_js' => array(false), - 'use_mobile_version_for_tablets' => array(false), - 'use_app_debug_css' => array(false), - 'use_imap_sort' => array(true), - 'use_imap_force_selection' => array(false), - 'use_imap_list_subscribe' => array(true), - 'use_imap_thread' => array(true), - 'use_imap_move' => array(false), - 'use_imap_expunge_all_on_delete' => array(false), - 'imap_forwarded_flag' => array('$Forwarded'), - 'imap_read_receipt_flag' => array('$ReadReceipt'), - 'imap_body_text_limit' => array(555000), - 'imap_message_list_fast_simple_search' => array(true), - 'imap_message_list_count_limit_trigger' => array(0), - 'imap_message_list_date_filter' => array(0), - 'imap_message_list_permanent_filter' => array(''), - 'imap_message_all_headers' => array(false), - 'imap_large_thread_limit' => array(50), - 'imap_folder_list_limit' => array(200), - 'imap_show_login_alert' => array(true), - 'imap_use_auth_plain' => array(true), - 'imap_use_auth_cram_md5' => array(false), - 'smtp_show_server_errors' => array(false), - 'smtp_use_auth_plain' => array(true), - 'smtp_use_auth_cram_md5' => array(false), - 'sieve_allow_raw_script' => array(false), - 'sieve_utf8_folder_name' => array(true), - 'sieve_auth_plain_initial' => array(true), - 'sieve_allow_fileinto_inbox' => array(false), - 'imap_timeout' => array(300), - 'smtp_timeout' => array(60), - 'sieve_timeout' => array(10), - 'domain_list_limit' => array(99), - 'mail_func_clear_headers' => array(true), - 'mail_func_additional_parameters' => array(false), - 'favicon_status' => array(true), - 'folders_spec_limit' => array(50), - 'owncloud_save_folder' => array('Attachments'), - 'owncloud_suggestions' => array(true), - 'curl_proxy' => array(''), - 'curl_proxy_auth' => array(''), - 'in_iframe' => array(false), - 'force_https' => array(false), - 'custom_login_link' => array(''), - 'custom_logout_link' => array(''), - 'allow_external_login' => array(false), - 'allow_external_sso' => array(false), - 'external_sso_key' => array(''), - 'http_client_ip_check_proxy' => array(false), - 'fast_cache_memcache_host' => array('127.0.0.1'), - 'fast_cache_memcache_port' => array(11211), - 'fast_cache_redis_host' => array('127.0.0.1'), - 'fast_cache_redis_port' => array(6379), - 'use_local_proxy_for_external_images' => array(false), - 'detect_image_exif_orientation' => array(true), - 'cookie_default_path' => array(''), - 'cookie_default_secure' => array(false), - 'check_new_messages' => array(true), - 'replace_env_in_configuration' => array(''), - 'startup_url' => array(''), - 'strict_html_parser' => array(false), - 'allow_cmd' => array(false), - 'dev_email' => array(''), - 'dev_password' => array('') - ), - - 'version' => array( - 'current' => array(''), - 'saved' => array('') - ) - ); - } -} +aReplaceEnv = null; + if ((isset($_ENV) && \is_array($_ENV) && 0 < \count($_ENV)) || + (isset($_SERVER) && \is_array($_SERVER) && 0 < \count($_SERVER))) + { + $sEnvNames = $this->Get('labs', 'replace_env_in_configuration', ''); + if (0 < \strlen($sEnvNames)) + { + $this->aReplaceEnv = \explode(',', $sEnvNames); + if (\is_array($this->aReplaceEnv)) + { + $this->aReplaceEnv = \array_map('trim', $this->aReplaceEnv); + $this->aReplaceEnv = \array_map('strtolower', $this->aReplaceEnv); + } + } + } + + if (!\is_array($this->aReplaceEnv) || 0 === \count($this->aReplaceEnv)) + { + $this->aReplaceEnv = null; + } + } + + /** + * @param string $sSection + * @param string $sName + * @param mixed $mDefault = null + * + * @return mixed + */ + public function Get($sSection, $sName, $mDefault = null) + { + $mResult = parent::Get($sSection, $sName, $mDefault); + if ($this->aReplaceEnv && \is_string($mResult)) + { + $sKey = \strtolower($sSection.'.'.$sName); + if (\in_array($sKey, $this->aReplaceEnv) && false !== strpos($mResult, '$')) + { + $mResult = \preg_replace_callback('/\$([^\s]+)/', function($aMatch) { + + if (!empty($aMatch[0]) && !empty($aMatch[1])) + { + if (!empty($_ENV[$aMatch[1]])) + { + return $_SERVER[$aMatch[1]]; + } + + if (!empty($_SERVER[$aMatch[1]])) + { + return $_SERVER[$aMatch[1]]; + } + + return $aMatch[0]; + } + + return ''; + + }, $mResult); + } + } + + return $mResult; + } + + /** + * @param string $sPassword + * + * @return void + */ + public function SetPassword($sPassword) + { + return $this->Set('security', 'admin_password', \md5(APP_SALT.$sPassword.APP_SALT)); + } + + /** + * @param string $sPassword + * + * @return bool + */ + public function ValidatePassword($sPassword) + { + $sPassword = (string) $sPassword; + $sConfigPassword = (string) $this->Get('security', 'admin_password', ''); + + return 0 < \strlen($sPassword) && + (($sPassword === $sConfigPassword && '12345' === $sConfigPassword) || \md5(APP_SALT.$sPassword.APP_SALT) === $sConfigPassword); + } + + /** + * @return bool + */ + public function Save() + { + $this->Set('version', 'current', APP_VERSION); + $this->Set('version', 'saved', \gmdate('r')); + + return parent::Save(); + } + + /** + * @return array + */ + protected function defaultValues() + { + return array( + + 'webmail' => array( + + 'title' => array('RainLoop Webmail', 'Text displayed as page title'), + 'loading_description' => array('RainLoop', 'Text displayed on startup'), + 'favicon_url' => array('', ''), + + 'theme' => array('Default', 'Theme used by default'), + 'allow_themes' => array(true, 'Allow theme selection on settings screen'), + 'allow_user_background' => array(false), + + 'language' => array('en', 'Language used by default'), + 'language_admin' => array('en', 'Admin Panel interface language'), + 'allow_languages_on_settings' => array(true, 'Allow language selection on settings screen'), + + 'allow_additional_accounts' => array(true, ''), + 'allow_additional_identities' => array(true, ''), + + 'messages_per_page' => array(20, ' Number of messages displayed on page by default'), + + 'attachment_size_limit' => array(25, + 'File size limit (MB) for file upload on compose screen +0 for unlimited.') + ), + + 'interface' => array( + 'show_attachment_thumbnail' => array(true, ''), + 'use_native_scrollbars' => array(false), + 'new_move_to_folder_button' => array(true) + ), + + 'branding' => array( + 'login_logo' => array(''), + 'login_background' => array(''), + 'login_desc' => array(''), + 'login_css' => array(''), + + 'user_css' => array(''), + 'user_logo' => array(''), + 'user_logo_title' => array(''), + 'user_logo_message' => array(''), + 'user_iframe_message' => array(''), + + 'welcome_page_url' => array(''), + 'welcome_page_display' => array('none') + ), + + 'contacts' => array( + 'enable' => array(false, 'Enable contacts'), + 'allow_sync' => array(false), + 'sync_interval' => array(20), + 'type' => array('sqlite', ''), + 'pdo_dsn' => array('mysql:host=127.0.0.1;port=3306;dbname=rainloop', ''), + 'pdo_user' => array('root', ''), + 'pdo_password' => array('', ''), + 'suggestions_limit' => array(30) + ), + + 'security' => array( + 'csrf_protection' => array(true, + 'Enable CSRF protection (http://en.wikipedia.org/wiki/Cross-site_request_forgery)'), + + 'custom_server_signature' => array('RainLoop'), + 'x_frame_options_header' => array(''), + 'x_xss_protection_header' => array('1; mode=block'), + + 'openpgp' => array(false), + + 'admin_login' => array('admin', 'Login and password for web admin panel'), + 'admin_password' => array('12345'), + 'allow_admin_panel' => array(true, 'Access settings'), + 'allow_two_factor_auth' => array(false), + 'force_two_factor_auth' => array(false), + 'hide_x_mailer_header' => array(false), + 'admin_panel_host' => array(''), + 'admin_panel_key' => array('admin'), + 'content_security_policy' => array(''), + 'core_install_access_domain' => array('') + ), + + 'ssl' => array( + 'verify_certificate' => array(false, 'Require verification of SSL certificate used.'), + 'allow_self_signed' => array(true, 'Allow self-signed certificates. Requires verify_certificate.'), + 'cafile' => array('', 'Location of Certificate Authority file on local filesystem (/etc/ssl/certs/ca-certificates.crt)'), + 'capath' => array('', 'capath must be a correctly hashed certificate directory. (/etc/ssl/certs/)'), + 'client_cert' => array('', 'Location of client certificate file (pem format with private key) on local filesystem'), + ), + + 'capa' => array( + 'folders' => array(true), + 'composer' => array(true), + 'contacts' => array(true), + 'settings' => array(true), + 'quota' => array(true), + 'help' => array(true), + 'reload' => array(true), + 'search' => array(true), + 'search_adv' => array(true), + 'filters' => array(true), + 'x-templates' => array(false), + 'dangerous_actions' => array(true), + 'message_actions' => array(true), + 'messagelist_actions' => array(true), + 'attachments_actions' => array(true) + ), + + 'login' => array( + + 'default_domain' => array('', ''), + + 'allow_languages_on_login' => array(true, + 'Allow language selection on webmail login screen'), + + 'determine_user_language' => array(true, ''), + 'determine_user_domain' => array(false, ''), + + 'welcome_page' => array(false, ''), + + 'hide_submit_button' => array(true), + + 'forgot_password_link_url' => array('', ''), + 'registration_link_url' => array('', ''), + + 'login_lowercase' => array(true, ''), + + 'sign_me_auto' => array(\RainLoop\Enumerations\SignMeType::DEFAILT_OFF, + 'This option allows webmail to remember the logged in user +once they closed the browser window. + +Values: + "DefaultOff" - can be used, disabled by default; + "DefaultOn" - can be used, enabled by default; + "Unused" - cannot be used') + ), + + 'plugins' => array( + 'enable' => array(false, 'Enable plugin support'), + 'enabled_list' => array('', 'List of enabled plugins'), + ), + + 'defaults' => array( + 'view_editor_type' => array('Html', 'Editor mode used by default (Plain, Html, HtmlForced or PlainForced)'), + 'view_layout' => array(1, 'layout: 0 - no preview, 1 - side preview, 2 - bottom preview'), + 'view_use_checkboxes' => array(true), + 'autologout' => array(30), + 'show_images' => array(false), + 'contacts_autosave' => array(true), + 'mail_use_threads' => array(false), + 'allow_draft_autosave' => array(true), + 'mail_reply_same_folder' => array(false) + ), + + 'logs' => array( + + 'enable' => array(false, 'Enable logging'), + + 'write_on_error_only' => array(false, 'Logs entire request only if error occured (php requred)'), + 'write_on_php_error_only' => array(false, 'Logs entire request only if php error occured'), + 'write_on_timeout_only' => array(0, 'Logs entire request only if request timeout (in seconds) occured.'), + + 'hide_passwords' => array(true, 'Required for development purposes only. +Disabling this option is not recommended.'), + + 'time_offset' => array('0'), + 'session_filter' => array(''), + + 'sentry_dsn' => array(''), + + 'filename' => array('log-{date:Y-m-d}.txt', + 'Log filename. +For security reasons, some characters are removed from filename. +Allows for pattern-based folder creation (see examples below). + +Patterns: + {date:Y-m-d} - Replaced by pattern-based date + Detailed info: http://www.php.net/manual/en/function.date.php + {user:email} - Replaced by user\'s email address + If user is not logged in, value is set to "unknown" + {user:login} - Replaced by user\'s login (the user part of an email) + If user is not logged in, value is set to "unknown" + {user:domain} - Replaced by user\'s domain name (the domain part of an email) + If user is not logged in, value is set to "unknown" + {user:uid} - Replaced by user\'s UID regardless of account currently used + + {user:ip} + {request:ip} - Replaced by user\'s IP address + +Others: + {imap:login} {imap:host} {imap:port} + {smtp:login} {smtp:host} {smtp:port} + +Examples: + filename = "log-{date:Y-m-d}.txt" + filename = "{date:Y-m-d}/{user:domain}/{user:email}_{user:uid}.log" + filename = "{user:email}-{date:Y-m-d}.txt"'), + + 'auth_logging' => array(false, 'Enable auth logging in a separate file (for fail2ban)'), + 'auth_logging_filename' => array('fail2ban/auth-{date:Y-m-d}.txt'), + 'auth_logging_format' => array('[{date:Y-m-d H:i:s}] Auth failed: ip={request:ip} user={imap:login} host={imap:host} port={imap:port}') + ), + + 'debug' => array( + 'enable' => array(false, 'Special option required for development purposes') + ), + + 'social' => array( + 'google_enable' => array(false, 'Google'), + 'google_enable_auth' => array(false), + 'google_enable_auth_fast' => array(false), + 'google_enable_drive' => array(false), + 'google_enable_preview' => array(false), + 'google_client_id' => array(''), + 'google_client_secret' => array(''), + 'google_api_key' => array(''), + + 'fb_enable' => array(false, 'Facebook'), + 'fb_app_id' => array(''), + 'fb_app_secret' => array(''), + + 'twitter_enable' => array(false, 'Twitter'), + 'twitter_consumer_key' => array(''), + 'twitter_consumer_secret' => array(''), + + 'dropbox_enable' => array(false, 'Dropbox'), + 'dropbox_api_key' => array('') + ), + + 'cache' => array( + 'enable' => array(true, + 'The section controls caching of the entire application. + +Enables caching in the system'), + + 'index' => array('v1', 'Additional caching key. If changed, cache is purged'), + + 'fast_cache_driver' => array('files', 'Can be: files, APC, memcache, redis (beta)'), + 'fast_cache_index' => array('v1', 'Additional caching key. If changed, fast cache is purged'), + + 'http' => array(true, 'Browser-level cache. If enabled, caching is maintainted without using files'), + 'http_expires' => array(3600, 'Browser-level cache time (seconds, Expires header)'), + + 'server_uids' => array(true, 'Caching message UIDs when searching and sorting (threading)') + ), + + 'labs' => array( + 'allow_mobile_version' => array(true, + 'Experimental settings. Handle with care. +'), + 'ignore_folders_subscription' => array(false), + 'check_new_password_strength' => array(true), + 'update_channel' => array('stable'), + 'allow_gravatar' => array(true), + 'allow_prefetch' => array(true), + 'allow_smart_html_links' => array(true), + 'cache_system_data' => array(true), + 'date_from_headers' => array(true), + 'autocreate_system_folders' => array(true), + 'allow_message_append' => array(false), + 'disable_iconv_if_mbstring_supported' => array(false), + 'login_fault_delay' => array(1), + 'log_ajax_response_write_limit' => array(300), + 'allow_html_editor_source_button' => array(false), + 'allow_html_editor_biti_buttons' => array(false), + 'allow_ctrl_enter_on_compose' => array(true), + 'try_to_detect_hidden_images' => array(false), + 'hide_dangerous_actions' => array(false), + 'use_app_debug_js' => array(false), + 'use_mobile_version_for_tablets' => array(false), + 'use_app_debug_css' => array(false), + 'use_imap_sort' => array(true), + 'use_imap_force_selection' => array(false), + 'use_imap_list_subscribe' => array(true), + 'use_imap_thread' => array(true), + 'use_imap_move' => array(false), + 'use_imap_expunge_all_on_delete' => array(false), + 'imap_forwarded_flag' => array('$Forwarded'), + 'imap_read_receipt_flag' => array('$ReadReceipt'), + 'imap_body_text_limit' => array(555000), + 'imap_message_list_fast_simple_search' => array(true), + 'imap_message_list_count_limit_trigger' => array(0), + 'imap_message_list_date_filter' => array(0), + 'imap_message_list_permanent_filter' => array(''), + 'imap_message_all_headers' => array(false), + 'imap_large_thread_limit' => array(50), + 'imap_folder_list_limit' => array(200), + 'imap_show_login_alert' => array(true), + 'imap_use_auth_plain' => array(true), + 'imap_use_auth_cram_md5' => array(false), + 'smtp_show_server_errors' => array(false), + 'smtp_use_auth_plain' => array(true), + 'smtp_use_auth_cram_md5' => array(false), + 'sieve_allow_raw_script' => array(false), + 'sieve_utf8_folder_name' => array(true), + 'sieve_auth_plain_initial' => array(true), + 'sieve_allow_fileinto_inbox' => array(false), + 'imap_timeout' => array(300), + 'smtp_timeout' => array(60), + 'sieve_timeout' => array(10), + 'domain_list_limit' => array(99), + 'mail_func_clear_headers' => array(true), + 'mail_func_additional_parameters' => array(false), + 'favicon_status' => array(true), + 'folders_spec_limit' => array(50), + 'owncloud_save_folder' => array('Attachments'), + 'owncloud_suggestions' => array(true), + 'curl_proxy' => array(''), + 'curl_proxy_auth' => array(''), + 'in_iframe' => array(false), + 'force_https' => array(false), + 'custom_login_link' => array(''), + 'custom_logout_link' => array(''), + 'allow_external_login' => array(false), + 'allow_external_sso' => array(false), + 'external_sso_key' => array(''), + 'http_client_ip_check_proxy' => array(false), + 'fast_cache_memcache_host' => array('127.0.0.1'), + 'fast_cache_memcache_port' => array(11211), + 'fast_cache_redis_host' => array('127.0.0.1'), + 'fast_cache_redis_port' => array(6379), + 'use_local_proxy_for_external_images' => array(false), + 'detect_image_exif_orientation' => array(true), + 'cookie_default_path' => array(''), + 'cookie_default_secure' => array(false), + 'check_new_messages' => array(true), + 'replace_env_in_configuration' => array(''), + 'startup_url' => array(''), + 'strict_html_parser' => array(false), + 'allow_cmd' => array(false), + 'dev_email' => array(''), + 'dev_password' => array('') + ), + + 'version' => array( + 'current' => array(''), + 'saved' => array('') + ) + ); + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Config/Plugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Config/Plugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Config/Plugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Config/Plugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/Capa.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/Capa.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/Capa.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/Capa.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/Layout.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/Layout.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/Layout.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/Layout.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/PluginPropertyType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/PluginPropertyType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/PluginPropertyType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/PluginPropertyType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/SignMeType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/SignMeType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/SignMeType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/SignMeType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/TimeFormat.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/TimeFormat.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/TimeFormat.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/TimeFormat.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/UploadClientError.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/UploadClientError.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/UploadClientError.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/UploadClientError.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/UploadError.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/UploadError.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Enumerations/UploadError.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Enumerations/UploadError.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Exceptions/ClientException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Exceptions/ClientException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Exceptions/ClientException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Exceptions/ClientException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Exceptions/Exception.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Exceptions/Exception.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Exceptions/Exception.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Exceptions/InvalidArgumentException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Exceptions/InvalidArgumentException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Exceptions/InvalidArgumentException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Exceptions/InvalidArgumentException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Exceptions/RuntimeException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Exceptions/RuntimeException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Exceptions/RuntimeException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Exceptions/RuntimeException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/KeyPathHelper.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/KeyPathHelper.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/KeyPathHelper.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/KeyPathHelper.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Model/Account.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Model/Account.php similarity index 92% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Model/Account.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Model/Account.php index 4539b5c4..c8575d78 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Model/Account.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Model/Account.php @@ -1,585 +1,603 @@ -sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true); - $this->sLogin = \MailSo\Base\Utils::IdnToAscii($sLogin); - $this->sPassword = $sPassword; - $this->oDomain = $oDomain; - $this->sSignMeToken = $sSignMeToken; - $this->sProxyAuthUser = $sProxyAuthUser; - $this->sProxyAuthPassword = $sProxyAuthPassword; - $this->sParentEmail = ''; - } - - /** - * @param string $sEmail - * @param string $sLogin - * @param string $sPassword - * @param \RainLoop\Model\Domain $oDomain - * @param string $sSignMeToken = '' - * @param string $sProxyAuthUser = '' - * @param string $sProxyAuthPassword = '' - * - * @return \RainLoop\Model\Account - */ - public static function NewInstance($sEmail, $sLogin, $sPassword, \RainLoop\Model\Domain $oDomain, - $sSignMeToken = '', $sProxyAuthUser = '', $sProxyAuthPassword = '') - { - return new self($sEmail, $sLogin, $sPassword, $oDomain, $sSignMeToken, $sProxyAuthUser, $sProxyAuthPassword); - } - - /** - * @return string - */ - public function Email() - { - return $this->sEmail; - } - - /** - * @return string - */ - public function ParentEmail() - { - return $this->sParentEmail; - } - - /** - * @return string - */ - public function ProxyAuthUser() - { - return $this->sProxyAuthUser; - } - - /** - * @return string - */ - public function ProxyAuthPassword() - { - return $this->sProxyAuthPassword; - } - - /** - * @return string - */ - public function ParentEmailHelper() - { - return 0 < \strlen($this->sParentEmail) ? $this->sParentEmail : $this->sEmail; - } - - /** - * @return string - */ - public function IsAdditionalAccount() - { - return 0 < \strlen($this->sParentEmail); - } - - /** - * @return string - */ - public function IncLogin() - { - $sLogin = $this->sLogin; - if ($this->oDomain->IncShortLogin()) - { - $sLogin = \MailSo\Base\Utils::GetAccountNameFromEmail($this->sLogin); - } - - return $sLogin; - } - - /** - * @return string - */ - public function IncPassword() - { - return $this->sPassword; - } - - /** - * @return string - */ - public function OutLogin() - { - $sLogin = $this->sLogin; - if ($this->oDomain->OutShortLogin()) - { - $sLogin = \MailSo\Base\Utils::GetAccountNameFromEmail($this->sLogin); - } - - return $sLogin; - } - - /** - * @return string - */ - public function Login() - { - return $this->IncLogin(); - } - - /** - * @return string - */ - public function Password() - { - return $this->IncPassword(); - } - - /** - * @return bool - */ - public function SignMe() - { - return 0 < \strlen($this->sSignMeToken); - } - - /** - * @return string - */ - public function SignMeToken() - { - return $this->sSignMeToken; - } - - /** - * @return \RainLoop\Model\Domain - */ - public function Domain() - { - return $this->oDomain; - } - - /** - * @return string - */ - public function Hash() - { - return md5(APP_SALT.$this->Email().APP_SALT.$this->DomainIncHost(). - APP_SALT.$this->DomainIncPort().APP_SALT.$this->Password().APP_SALT.'0'.APP_SALT.$this->ParentEmail().APP_SALT); - } - - /** - * @param string $sPassword - * - * @return void - */ - public function SetPassword($sPassword) - { - $this->sPassword = $sPassword; - } - - /** - * @param string $sParentEmail - * - * @return void - */ - public function SetParentEmail($sParentEmail) - { - $this->sParentEmail = \trim(\MailSo\Base\Utils::IdnToAscii($sParentEmail, true)); - } - - /** - * @param string $sProxyAuthUser - * - * @return void - */ - public function SetProxyAuthUser($sProxyAuthUser) - { - return $this->sProxyAuthUser = $sProxyAuthUser; - } - - /** - * @param string $sProxyAuthPassword - * - * @return void - */ - public function SetProxyAuthPassword($sProxyAuthPassword) - { - return $this->sProxyAuthPassword = $sProxyAuthPassword; - } - - /** - * @return string - */ - public function DomainIncHost() - { - return $this->Domain()->IncHost(); - } - - /** - * @return int - */ - public function DomainIncPort() - { - return $this->Domain()->IncPort(); - } - - /** - * @return int - */ - public function DomainIncSecure() - { - return $this->Domain()->IncSecure(); - } - - /** - * @return string - */ - public function DomainOutHost() - { - return $this->Domain()->OutHost(); - } - - /** - * @return int - */ - public function DomainOutPort() - { - return $this->Domain()->OutPort(); - } - - /** - * @return int - */ - public function DomainOutSecure() - { - return $this->Domain()->OutSecure(); - } - - /** - * @return bool - */ - public function DomainOutAuth() - { - return $this->Domain()->OutAuth(); - } - - /** - * @return string - */ - public function DomainSieveHost() - { - return $this->Domain()->SieveHost(); - } - - /** - * @return int - */ - public function DomainSievePort() - { - return $this->Domain()->SievePort(); - } - - /** - * @return int - */ - public function DomainSieveSecure() - { - return $this->Domain()->SieveSecure(); - } - - /** - * @return bool - */ - public function DomainSieveAllowRaw() - { - return $this->Domain()->SieveAllowRaw(); - } - - /** - * @return string - */ - public function GetAuthToken() - { - return \RainLoop\Utils::EncodeKeyValues(array( - 'token', // 0 - $this->sEmail, // 1 - $this->sLogin, // 2 - $this->sPassword, // 3 - \RainLoop\Utils::Fingerprint(), // 4 - $this->sSignMeToken, // 5 - $this->sParentEmail, // 6 - \RainLoop\Utils::GetShortToken(), // 7 - $this->sProxyAuthUser, // 8 - $this->sProxyAuthPassword, // 9 - 0 // 10 // timelife - )); - } - - /** - * @return string - */ - public function GetAuthTokenQ() - { - return \RainLoop\Utils::EncodeKeyValuesQ(array( - 'token', // 0 - $this->sEmail, // 1 - $this->sLogin, // 2 - $this->sPassword, // 3 - \RainLoop\Utils::Fingerprint(), // 4 - $this->sSignMeToken, // 5 - $this->sParentEmail, // 6 - \RainLoop\Utils::GetShortToken(), // 7 - $this->sProxyAuthUser, // 8 - $this->sProxyAuthPassword, // 9 - 0 // 10 // timelife - )); - } - - /** - * @param \RainLoop\Plugins\Manager $oPlugins - * @param \MailSo\Mail\MailClient $oMailClient - * @param \RainLoop\Application $oConfig - * - * @return bool - */ - public function IncConnectAndLoginHelper($oPlugins, $oMailClient, $oConfig) - { - $bLogin = false; - - $aImapCredentials = array( - 'UseConnect' => true, - 'UseAuth' => true, - 'Host' => $this->DomainIncHost(), - 'Port' => $this->DomainIncPort(), - 'Secure' => $this->DomainIncSecure(), - 'Login' => $this->IncLogin(), - 'Password' => $this->Password(), - 'ProxyAuthUser' => $this->ProxyAuthUser(), - 'ProxyAuthPassword' => $this->ProxyAuthPassword(), - 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), - 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true), - 'UseAuthPlainIfSupported' => !!$oConfig->Get('labs', 'imap_use_auth_plain', true), - 'UseAuthCramMd5IfSupported' => !!$oConfig->Get('labs', 'imap_use_auth_cram_md5', true) - ); - - $oPlugins->RunHook('filter.imap-credentials', array($this, &$aImapCredentials)); - - $oPlugins->RunHook('event.imap-pre-connect', array($this, $aImapCredentials['UseConnect'], $aImapCredentials)); - - if ($aImapCredentials['UseConnect']) - { - $oMailClient - ->Connect($aImapCredentials['Host'], $aImapCredentials['Port'], - $aImapCredentials['Secure'], $aImapCredentials['VerifySsl'], $aImapCredentials['AllowSelfSigned']); - - } - - $oPlugins->RunHook('event.imap-pre-login', array($this, $aImapCredentials['UseAuth'], $aImapCredentials)); - - if ($aImapCredentials['UseAuth']) - { - if (0 < \strlen($aImapCredentials['ProxyAuthUser']) && - 0 < \strlen($aImapCredentials['ProxyAuthPassword'])) - { - $oMailClient - ->Login($aImapCredentials['ProxyAuthUser'], $aImapCredentials['ProxyAuthPassword'], - $aImapCredentials['Login'], $aImapCredentials['UseAuthPlainIfSupported'], $aImapCredentials['UseAuthCramMd5IfSupported']); - } - else - { - $iGatLen = \strlen(APP_GOOGLE_ACCESS_TOKEN_PREFIX); - $sPassword = $aImapCredentials['Password']; - if (APP_GOOGLE_ACCESS_TOKEN_PREFIX === \substr($sPassword, 0, $iGatLen)) - { - $oMailClient->LoginWithXOauth2( - \base64_encode('user='.$aImapCredentials['Login']."\1".'auth=Bearer '.\substr($sPassword, $iGatLen)."\1\1")); - } - else - { - $oMailClient->Login($aImapCredentials['Login'], $aImapCredentials['Password'], '', - $aImapCredentials['UseAuthPlainIfSupported'], $aImapCredentials['UseAuthCramMd5IfSupported']); - } - } - - $bLogin = true; - } - - $oPlugins->RunHook('event.imap-post-login', array($this, $aImapCredentials['UseAuth'], $bLogin, $aImapCredentials)); - - return $bLogin; - } - - /** - * @param \RainLoop\Plugins\Manager $oPlugins - * @param \MailSo\Smtp\SmtpClient|null $oSmtpClient - * @param \RainLoop\Application $oConfig - * @param bool $bUsePhpMail = false - * - * @return bool - */ - public function OutConnectAndLoginHelper($oPlugins, $oSmtpClient, $oConfig, &$bUsePhpMail = false) - { - $bLogin = false; - - $aSmtpCredentials = array( - 'UseConnect' => true, - 'UseAuth' => $this->DomainOutAuth(), - 'UsePhpMail' => $bUsePhpMail, - 'Ehlo' => \MailSo\Smtp\SmtpClient::EhloHelper(), - 'Host' => $this->DomainOutHost(), - 'Port' => $this->DomainOutPort(), - 'Secure' => $this->DomainOutSecure(), - 'Login' => $this->OutLogin(), - 'Password' => $this->Password(), - 'ProxyAuthUser' => $this->ProxyAuthUser(), - 'ProxyAuthPassword' => $this->ProxyAuthPassword(), - 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), - 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true), - 'UseAuthPlainIfSupported' => !!$oConfig->Get('labs', 'smtp_use_auth_plain', true), - 'UseAuthCramMd5IfSupported' => !!$oConfig->Get('labs', 'smtp_use_auth_cram_md5', true) - ); - - $oPlugins->RunHook('filter.smtp-credentials', array($this, &$aSmtpCredentials)); - - $bUsePhpMail = $aSmtpCredentials['UsePhpMail']; - - $oPlugins->RunHook('event.smtp-pre-connect', array($this, $aSmtpCredentials['UseConnect'], $aSmtpCredentials)); - - if ($aSmtpCredentials['UseConnect'] && !$aSmtpCredentials['UsePhpMail'] && $oSmtpClient) - { - $oSmtpClient->Connect($aSmtpCredentials['Host'], $aSmtpCredentials['Port'], $aSmtpCredentials['Ehlo'], - $aSmtpCredentials['Secure'], $aSmtpCredentials['VerifySsl'], $aSmtpCredentials['AllowSelfSigned'] - ); - } - - $oPlugins->RunHook('event.smtp-post-connect', array($this, $aSmtpCredentials['UseConnect'], $aSmtpCredentials)); - $oPlugins->RunHook('event.smtp-pre-login', array($this, $aSmtpCredentials['UseAuth'], $aSmtpCredentials)); - - if ($aSmtpCredentials['UseAuth'] && !$aSmtpCredentials['UsePhpMail'] && $oSmtpClient) - { - $iGatLen = \strlen(APP_GOOGLE_ACCESS_TOKEN_PREFIX); - $sPassword = $aSmtpCredentials['Password']; - if (APP_GOOGLE_ACCESS_TOKEN_PREFIX === \substr($sPassword, 0, $iGatLen)) - { - $oSmtpClient->LoginWithXOauth2( - \base64_encode('user='.$aSmtpCredentials['Login']."\1".'auth=Bearer '.\substr($sPassword, $iGatLen)."\1\1")); - } - else - { - $oSmtpClient->Login($aSmtpCredentials['Login'], $aSmtpCredentials['Password'], - $aSmtpCredentials['UseAuthPlainIfSupported'], $aSmtpCredentials['UseAuthCramMd5IfSupported']); - } - - $bLogin = true; - } - - $oPlugins->RunHook('event.smtp-post-login', array($this, $aSmtpCredentials['UseAuth'], $bLogin, $aSmtpCredentials)); - - return $bLogin; - } - - /** - * @param \RainLoop\Plugins\Manager $oPlugins - * @param \MailSo\Sieve\ManageSieveClient $oSieveClient - * @param \RainLoop\Application $oConfig - */ - public function SieveConnectAndLoginHelper($oPlugins, $oSieveClient, $oConfig) - { - $bLogin = false; - - $aSieveCredentials = array( - 'UseConnect' => true, - 'UseAuth' => true, - 'Host' => $this->DomainSieveHost(), - 'Port' => $this->DomainSievePort(), - 'Secure' => $this->DomainSieveSecure(), - 'Login' => $this->IncLogin(), - 'Password' => $this->Password(), - 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), - 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true), - 'InitialAuthPlain' => !!$oConfig->Get('ssl', 'sieve_auth_plain_initial', true) - ); - - $oPlugins->RunHook('filter.sieve-credentials', array($this, &$aSieveCredentials)); - - $oPlugins->RunHook('event.sieve-pre-connect', array($this, $aSieveCredentials['UseConnect'], $aSieveCredentials)); - - if ($oSieveClient) - { - $oSieveClient->__USE_INITIAL_AUTH_PLAIN_COMMAND = $aSieveCredentials['InitialAuthPlain']; - - if ($aSieveCredentials['UseConnect']) - { - $oSieveClient->Connect($aSieveCredentials['Host'], $aSieveCredentials['Port'], - $aSieveCredentials['Secure'], $aSieveCredentials['VerifySsl'], $aSieveCredentials['AllowSelfSigned'] - ); - } - } - - $oPlugins->RunHook('event.sieve-post-connect', array($this, $aSieveCredentials['UseConnect'], $aSieveCredentials)); - - $oPlugins->RunHook('event.sieve-pre-login', array($this, $aSieveCredentials['UseAuth'], $aSieveCredentials)); - - if ($aSieveCredentials['UseAuth']) - { - $oSieveClient->Login($aSieveCredentials['Login'], $aSieveCredentials['Password']); - - $bLogin = true; - } - - $oPlugins->RunHook('event.sieve-post-login', array($this, $aSieveCredentials['UseAuth'], $bLogin, $aSieveCredentials)); - - return $bLogin; - } -} +sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true); + $this->sLogin = \MailSo\Base\Utils::IdnToAscii($sLogin); + $this->sPassword = $sPassword; + $this->oDomain = $oDomain; + $this->sSignMeToken = $sSignMeToken; + $this->sProxyAuthUser = $sProxyAuthUser; + $this->sProxyAuthPassword = $sProxyAuthPassword; + $this->sClientCert = $sClientCert; + $this->sParentEmail = ''; + } + + /** + * @param string $sEmail + * @param string $sLogin + * @param string $sPassword + * @param \RainLoop\Model\Domain $oDomain + * @param string $sSignMeToken = '' + * @param string $sProxyAuthUser = '' + * @param string $sProxyAuthPassword = '' + * + * @return \RainLoop\Model\Account + */ + public static function NewInstance($sEmail, $sLogin, $sPassword, \RainLoop\Model\Domain $oDomain, + $sSignMeToken = '', $sProxyAuthUser = '', $sProxyAuthPassword = '', $sClientCert = '') + { + return new self($sEmail, $sLogin, $sPassword, $oDomain, $sSignMeToken, $sProxyAuthUser, $sProxyAuthPassword, $sClientCert); + } + + /** + * @return string + */ + public function Email() + { + return $this->sEmail; + } + + /** + * @return string + */ + public function ParentEmail() + { + return $this->sParentEmail; + } + + /** + * @return string + */ + public function ProxyAuthUser() + { + return $this->sProxyAuthUser; + } + + /** + * @return string + */ + public function ProxyAuthPassword() + { + return $this->sProxyAuthPassword; + } + + /** + * @return string + */ + public function ParentEmailHelper() + { + return 0 < \strlen($this->sParentEmail) ? $this->sParentEmail : $this->sEmail; + } + + /** + * @return string + */ + public function IsAdditionalAccount() + { + return 0 < \strlen($this->sParentEmail); + } + + /** + * @return string + */ + public function IncLogin() + { + $sLogin = $this->sLogin; + if ($this->oDomain->IncShortLogin()) + { + $sLogin = \MailSo\Base\Utils::GetAccountNameFromEmail($this->sLogin); + } + + return $sLogin; + } + + /** + * @return string + */ + public function IncPassword() + { + return $this->sPassword; + } + + /** + * @return string + */ + public function OutLogin() + { + $sLogin = $this->sLogin; + if ($this->oDomain->OutShortLogin()) + { + $sLogin = \MailSo\Base\Utils::GetAccountNameFromEmail($this->sLogin); + } + + return $sLogin; + } + + /** + * @return string + */ + public function Login() + { + return $this->IncLogin(); + } + + /** + * @return string + */ + public function Password() + { + return $this->IncPassword(); + } + + /** + * @return string + */ + public function ClientCert() + { + return $this->sClientCert; + } + + /** + * @return bool + */ + public function SignMe() + { + return 0 < \strlen($this->sSignMeToken); + } + + /** + * @return string + */ + public function SignMeToken() + { + return $this->sSignMeToken; + } + + /** + * @return \RainLoop\Model\Domain + */ + public function Domain() + { + return $this->oDomain; + } + + /** + * @return string + */ + public function Hash() + { + return md5(APP_SALT.$this->Email().APP_SALT.$this->DomainIncHost(). + APP_SALT.$this->DomainIncPort().APP_SALT.$this->Password().APP_SALT.'0'.APP_SALT.$this->ParentEmail().APP_SALT); + } + + /** + * @param string $sPassword + * + * @return void + */ + public function SetPassword($sPassword) + { + $this->sPassword = $sPassword; + } + + /** + * @param string $sParentEmail + * + * @return void + */ + public function SetParentEmail($sParentEmail) + { + $this->sParentEmail = \trim(\MailSo\Base\Utils::IdnToAscii($sParentEmail, true)); + } + + /** + * @param string $sProxyAuthUser + * + * @return void + */ + public function SetProxyAuthUser($sProxyAuthUser) + { + return $this->sProxyAuthUser = $sProxyAuthUser; + } + + /** + * @param string $sProxyAuthPassword + * + * @return void + */ + public function SetProxyAuthPassword($sProxyAuthPassword) + { + return $this->sProxyAuthPassword = $sProxyAuthPassword; + } + + /** + * @return string + */ + public function DomainIncHost() + { + return $this->Domain()->IncHost(); + } + + /** + * @return int + */ + public function DomainIncPort() + { + return $this->Domain()->IncPort(); + } + + /** + * @return int + */ + public function DomainIncSecure() + { + return $this->Domain()->IncSecure(); + } + + /** + * @return string + */ + public function DomainOutHost() + { + return $this->Domain()->OutHost(); + } + + /** + * @return int + */ + public function DomainOutPort() + { + return $this->Domain()->OutPort(); + } + + /** + * @return int + */ + public function DomainOutSecure() + { + return $this->Domain()->OutSecure(); + } + + /** + * @return bool + */ + public function DomainOutAuth() + { + return $this->Domain()->OutAuth(); + } + + /** + * @return string + */ + public function DomainSieveHost() + { + return $this->Domain()->SieveHost(); + } + + /** + * @return int + */ + public function DomainSievePort() + { + return $this->Domain()->SievePort(); + } + + /** + * @return int + */ + public function DomainSieveSecure() + { + return $this->Domain()->SieveSecure(); + } + + /** + * @return bool + */ + public function DomainSieveAllowRaw() + { + return $this->Domain()->SieveAllowRaw(); + } + + /** + * @return string + */ + public function GetAuthToken() + { + return \RainLoop\Utils::EncodeKeyValues(array( + 'token', // 0 + $this->sEmail, // 1 + $this->sLogin, // 2 + $this->sPassword, // 3 + \RainLoop\Utils::Fingerprint(), // 4 + $this->sSignMeToken, // 5 + $this->sParentEmail, // 6 + \RainLoop\Utils::GetShortToken(), // 7 + $this->sProxyAuthUser, // 8 + $this->sProxyAuthPassword, // 9 + 0, // 10 // timelife + $this->sClientCert // 11 + )); + } + + /** + * @return string + */ + public function GetAuthTokenQ() + { + return \RainLoop\Utils::EncodeKeyValuesQ(array( + 'token', // 0 + $this->sEmail, // 1 + $this->sLogin, // 2 + $this->sPassword, // 3 + \RainLoop\Utils::Fingerprint(), // 4 + $this->sSignMeToken, // 5 + $this->sParentEmail, // 6 + \RainLoop\Utils::GetShortToken(), // 7 + $this->sProxyAuthUser, // 8 + $this->sProxyAuthPassword, // 9 + 0, // 10 // timelife + $this->sClientCert // 11 + )); + } + + /** + * @param \RainLoop\Plugins\Manager $oPlugins + * @param \MailSo\Mail\MailClient $oMailClient + * @param \RainLoop\Application $oConfig + * + * @return bool + */ + public function IncConnectAndLoginHelper($oPlugins, $oMailClient, $oConfig) + { + $bLogin = false; + + $aImapCredentials = array( + 'UseConnect' => true, + 'UseAuth' => true, + 'Host' => $this->DomainIncHost(), + 'Port' => $this->DomainIncPort(), + 'Secure' => $this->DomainIncSecure(), + 'Login' => $this->IncLogin(), + 'Password' => $this->Password(), + 'ProxyAuthUser' => $this->ProxyAuthUser(), + 'ProxyAuthPassword' => $this->ProxyAuthPassword(), + 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), + 'ClientCert' => $this->ClientCert(), + 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true), + 'UseAuthPlainIfSupported' => !!$oConfig->Get('labs', 'imap_use_auth_plain', true), + 'UseAuthCramMd5IfSupported' => !!$oConfig->Get('labs', 'imap_use_auth_cram_md5', true) + ); + + $oPlugins->RunHook('filter.imap-credentials', array($this, &$aImapCredentials)); + + $oPlugins->RunHook('event.imap-pre-connect', array($this, $aImapCredentials['UseConnect'], $aImapCredentials)); + + if ($aImapCredentials['UseConnect']) + { + $oMailClient + ->Connect($aImapCredentials['Host'], $aImapCredentials['Port'], + $aImapCredentials['Secure'], $aImapCredentials['VerifySsl'], + $aImapCredentials['AllowSelfSigned'], $aImapCredentials['ClientCert']); + + } + + $oPlugins->RunHook('event.imap-pre-login', array($this, $aImapCredentials['UseAuth'], $aImapCredentials)); + + if ($aImapCredentials['UseAuth']) + { + if (0 < \strlen($aImapCredentials['ProxyAuthUser']) && + 0 < \strlen($aImapCredentials['ProxyAuthPassword'])) + { + $oMailClient + ->Login($aImapCredentials['ProxyAuthUser'], $aImapCredentials['ProxyAuthPassword'], + $aImapCredentials['Login'], $aImapCredentials['UseAuthPlainIfSupported'], $aImapCredentials['UseAuthCramMd5IfSupported']); + } + else + { + $iGatLen = \strlen(APP_GOOGLE_ACCESS_TOKEN_PREFIX); + $sPassword = $aImapCredentials['Password']; + if (APP_GOOGLE_ACCESS_TOKEN_PREFIX === \substr($sPassword, 0, $iGatLen)) + { + $oMailClient->LoginWithXOauth2( + \base64_encode('user='.$aImapCredentials['Login']."\1".'auth=Bearer '.\substr($sPassword, $iGatLen)."\1\1")); + } + else + { + $oMailClient->Login($aImapCredentials['Login'], $aImapCredentials['Password'], '', + $aImapCredentials['UseAuthPlainIfSupported'], $aImapCredentials['UseAuthCramMd5IfSupported']); + } + } + + $bLogin = true; + } + + $oPlugins->RunHook('event.imap-post-login', array($this, $aImapCredentials['UseAuth'], $bLogin, $aImapCredentials)); + + return $bLogin; + } + + /** + * @param \RainLoop\Plugins\Manager $oPlugins + * @param \MailSo\Smtp\SmtpClient|null $oSmtpClient + * @param \RainLoop\Application $oConfig + * @param bool $bUsePhpMail = false + * + * @return bool + */ + public function OutConnectAndLoginHelper($oPlugins, $oSmtpClient, $oConfig, &$bUsePhpMail = false) + { + $bLogin = false; + + $aSmtpCredentials = array( + 'UseConnect' => true, + 'UseAuth' => $this->DomainOutAuth(), + 'UsePhpMail' => $bUsePhpMail, + 'Ehlo' => \MailSo\Smtp\SmtpClient::EhloHelper(), + 'Host' => $this->DomainOutHost(), + 'Port' => $this->DomainOutPort(), + 'Secure' => $this->DomainOutSecure(), + 'Login' => $this->OutLogin(), + 'Password' => $this->Password(), + 'ProxyAuthUser' => $this->ProxyAuthUser(), + 'ProxyAuthPassword' => $this->ProxyAuthPassword(), + 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), + 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true), + 'UseAuthPlainIfSupported' => !!$oConfig->Get('labs', 'smtp_use_auth_plain', true), + 'UseAuthCramMd5IfSupported' => !!$oConfig->Get('labs', 'smtp_use_auth_cram_md5', true) + ); + + $oPlugins->RunHook('filter.smtp-credentials', array($this, &$aSmtpCredentials)); + + $bUsePhpMail = $aSmtpCredentials['UsePhpMail']; + + $oPlugins->RunHook('event.smtp-pre-connect', array($this, $aSmtpCredentials['UseConnect'], $aSmtpCredentials)); + + if ($aSmtpCredentials['UseConnect'] && !$aSmtpCredentials['UsePhpMail'] && $oSmtpClient) + { + $oSmtpClient->Connect($aSmtpCredentials['Host'], $aSmtpCredentials['Port'], $aSmtpCredentials['Ehlo'], + $aSmtpCredentials['Secure'], $aSmtpCredentials['VerifySsl'], $aSmtpCredentials['AllowSelfSigned'] + ); + } + + $oPlugins->RunHook('event.smtp-post-connect', array($this, $aSmtpCredentials['UseConnect'], $aSmtpCredentials)); + $oPlugins->RunHook('event.smtp-pre-login', array($this, $aSmtpCredentials['UseAuth'], $aSmtpCredentials)); + + if ($aSmtpCredentials['UseAuth'] && !$aSmtpCredentials['UsePhpMail'] && $oSmtpClient) + { + $iGatLen = \strlen(APP_GOOGLE_ACCESS_TOKEN_PREFIX); + $sPassword = $aSmtpCredentials['Password']; + if (APP_GOOGLE_ACCESS_TOKEN_PREFIX === \substr($sPassword, 0, $iGatLen)) + { + $oSmtpClient->LoginWithXOauth2( + \base64_encode('user='.$aSmtpCredentials['Login']."\1".'auth=Bearer '.\substr($sPassword, $iGatLen)."\1\1")); + } + else + { + $oSmtpClient->Login($aSmtpCredentials['Login'], $aSmtpCredentials['Password'], + $aSmtpCredentials['UseAuthPlainIfSupported'], $aSmtpCredentials['UseAuthCramMd5IfSupported']); + } + + $bLogin = true; + } + + $oPlugins->RunHook('event.smtp-post-login', array($this, $aSmtpCredentials['UseAuth'], $bLogin, $aSmtpCredentials)); + + return $bLogin; + } + + /** + * @param \RainLoop\Plugins\Manager $oPlugins + * @param \MailSo\Sieve\ManageSieveClient $oSieveClient + * @param \RainLoop\Application $oConfig + */ + public function SieveConnectAndLoginHelper($oPlugins, $oSieveClient, $oConfig) + { + $bLogin = false; + + $aSieveCredentials = array( + 'UseConnect' => true, + 'UseAuth' => true, + 'Host' => $this->DomainSieveHost(), + 'Port' => $this->DomainSievePort(), + 'Secure' => $this->DomainSieveSecure(), + 'Login' => $this->IncLogin(), + 'Password' => $this->Password(), + 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), + 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true), + 'InitialAuthPlain' => !!$oConfig->Get('ssl', 'sieve_auth_plain_initial', true) + ); + + $oPlugins->RunHook('filter.sieve-credentials', array($this, &$aSieveCredentials)); + + $oPlugins->RunHook('event.sieve-pre-connect', array($this, $aSieveCredentials['UseConnect'], $aSieveCredentials)); + + if ($oSieveClient) + { + $oSieveClient->__USE_INITIAL_AUTH_PLAIN_COMMAND = $aSieveCredentials['InitialAuthPlain']; + + if ($aSieveCredentials['UseConnect']) + { + $oSieveClient->Connect($aSieveCredentials['Host'], $aSieveCredentials['Port'], + $aSieveCredentials['Secure'], $aSieveCredentials['VerifySsl'], $aSieveCredentials['AllowSelfSigned'] + ); + } + } + + $oPlugins->RunHook('event.sieve-post-connect', array($this, $aSieveCredentials['UseConnect'], $aSieveCredentials)); + + $oPlugins->RunHook('event.sieve-pre-login', array($this, $aSieveCredentials['UseAuth'], $aSieveCredentials)); + + if ($aSieveCredentials['UseAuth']) + { + $oSieveClient->Login($aSieveCredentials['Login'], $aSieveCredentials['Password']); + + $bLogin = true; + } + + $oPlugins->RunHook('event.sieve-post-login', array($this, $aSieveCredentials['UseAuth'], $bLogin, $aSieveCredentials)); + + return $bLogin; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Model/Domain.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Model/Domain.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Model/Domain.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Model/Domain.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Model/Identity.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Model/Identity.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Model/Identity.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Model/Identity.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Model/Template.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Model/Template.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Model/Template.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Model/Template.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Notifications.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Notifications.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Notifications.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Notifications.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Plugins/AbstractPlugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Plugins/AbstractPlugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Plugins/AbstractPlugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Plugins/AbstractPlugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Plugins/Helper.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Plugins/Helper.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Plugins/Helper.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Plugins/Helper.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Plugins/Manager.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Plugins/Manager.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Plugins/Manager.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Plugins/Manager.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Plugins/Property.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Plugins/Property.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Plugins/Property.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Plugins/Property.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AbstractProvider.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AbstractProvider.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AbstractProvider.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AbstractProvider.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/AddressBookInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/AddressBookInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/AddressBookInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/AddressBookInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/Classes/Contact.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Contact.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/Classes/Contact.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Contact.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/Classes/Property.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Property.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/Classes/Property.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Property.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/Classes/Tag.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Tag.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/Classes/Tag.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Tag.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/Enumerations/PropertyType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/Enumerations/PropertyType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/Enumerations/PropertyType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/Enumerations/PropertyType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/ChangePassword.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/ChangePassword.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/ChangePassword.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/ChangePassword.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/ChangePassword/ChangePasswordInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/ChangePassword/ChangePasswordInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/ChangePassword/ChangePasswordInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/ChangePassword/ChangePasswordInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Domain.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Domain.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Domain.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Domain.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Domain/DefaultDomain.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Domain/DefaultDomain.php similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Domain/DefaultDomain.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Domain/DefaultDomain.php index 0b9bb572..cce57262 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Domain/DefaultDomain.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Domain/DefaultDomain.php @@ -1,410 +1,410 @@ -sDomainPath = \rtrim(\trim($sDomainPath), '\\/'); - $this->oCacher = $oCacher; - } - - /** - * @param string $sName - * @param bool $bBack = false - * - * @return string - */ - public function codeFileName($sName, $bBack = false) - { - if ($bBack && 'default' === $sName) - { - return '*'; - } - else if (!$bBack && '*' === $sName) - { - return 'default'; - } - - if ($bBack) - { - $sName = \MailSo\Base\Utils::IdnToUtf8($sName, true); - } - else - { - $sName = \MailSo\Base\Utils::IdnToAscii($sName, true); - } - - return $bBack ? \str_replace('_wildcard_', '*', $sName) : \str_replace('*', '_wildcard_', $sName); - } - - /** - * @return string - */ - private function wildcardDomainsCacheKey() - { - return '/WildCard/DomainCache/'.\md5(APP_VERSION.APP_PRIVATE_DATA_NAME).'/'; - } - - /** - * @return string - */ - private function getWildcardDomainsLine() - { - if ($this->oCacher) - { - $sResult = $this->oCacher->Get($this->wildcardDomainsCacheKey()); - if (0 < \strlen($sResult)) - { - return $sResult; - } - } - - $sResult = ''; - $aNames = array(); - - $aList = \glob($this->sDomainPath.'/*.ini'); - foreach ($aList as $sFile) - { - $sName = \substr(\basename($sFile), 0, -4); - if ('default' === $sName || false !== \strpos($sName, '_wildcard_')) - { - $aNames[] = $this->codeFileName($sName, true); - } - } - - if (0 < \count($aNames)) - { - \rsort($aNames, SORT_STRING); - $sResult = \implode(' ', $aNames); - } - - if ($this->oCacher) - { - $this->oCacher->Set($this->wildcardDomainsCacheKey(), $sResult); - } - - return $sResult; - } - - /** - * @param string $sName - * @param bool $bFindWithWildCard = false - * @param bool $bCheckDisabled = true - * @param bool $bCheckAliases = true - * - * @return \RainLoop\Model\Domain|null - */ - public function Load($sName, $bFindWithWildCard = false, $bCheckDisabled = true, $bCheckAliases = true) - { - $mResult = null; - - $sDisabled = ''; - $sFoundedValue = ''; - - $sRealFileName = $this->codeFileName($sName); - - if (\file_exists($this->sDomainPath.'/disabled')) - { - $sDisabled = @\file_get_contents($this->sDomainPath.'/disabled'); - } - - if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.ini') && - (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.\MailSo\Base\Utils::IdnToAscii($sName, true).','))) - { - $aDomain = \RainLoop\Utils::CustomParseIniFile($this->sDomainPath.'/'.$sRealFileName.'.ini'); -// if ($bCheckAliases && !empty($aDomain['alias'])) -// { -// $oDomain = $this->Load($aDomain['alias'], false, false, false); -// if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain) -// { -// $oDomain->SetAliasName($sName); -// } -// -// return $oDomain; -// } - - // fix misspellings (#119) - if (\is_array($aDomain)) - { - if (isset($aDomain['smpt_host'])) - { - $aDomain['smtp_host'] = $aDomain['smpt_host']; - } - - if (isset($aDomain['smpt_port'])) - { - $aDomain['smtp_port'] = $aDomain['smpt_port']; - } - - if (isset($aDomain['smpt_secure'])) - { - $aDomain['smtp_secure'] = $aDomain['smpt_secure']; - } - - if (isset($aDomain['smpt_auth'])) - { - $aDomain['smtp_auth'] = $aDomain['smpt_auth']; - } - } - //--- - - $mResult = \RainLoop\Model\Domain::NewInstanceFromDomainConfigArray($sName, $aDomain); - } - else if ($bCheckAliases && \file_exists($this->sDomainPath.'/'.$sRealFileName.'.alias') && - (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.\MailSo\Base\Utils::IdnToAscii($sName, true).','))) - { - $sAlias = \trim(\file_get_contents($this->sDomainPath.'/'.$sRealFileName.'.alias')); - if (!empty($sAlias)) - { - $oDomain = $this->Load($sAlias, false, false, false); - if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain) - { - $oDomain->SetAliasName($sName); - } - - return $oDomain; - } - } - else if ($bFindWithWildCard) - { - $sNames = $this->getWildcardDomainsLine(); - if (0 < \strlen($sNames)) - { - if (\RainLoop\Plugins\Helper::ValidateWildcardValues( - \MailSo\Base\Utils::IdnToUtf8($sName, true), $sNames, $sFoundedValue) && 0 < \strlen($sFoundedValue)) - { - if (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.$sFoundedValue.',')) - { - $mResult = $this->Load($sFoundedValue, false); - } - } - } - } - - return $mResult; - } - - /** - * @param \RainLoop\Model\Domain $oDomain - * - * @return bool - */ - public function Save(\RainLoop\Model\Domain $oDomain) - { - $sRealFileName = $this->codeFileName($oDomain->Name()); - - if ($this->oCacher) - { - $this->oCacher->Delete($this->wildcardDomainsCacheKey()); - } - - $mResult = \file_put_contents($this->sDomainPath.'/'.$sRealFileName.'.ini', $oDomain->ToIniString()); - return \is_int($mResult) && 0 < $mResult; - } - - /** - * @param string $sName - * @param string $sAlias - * - * @return bool - */ - public function SaveAlias($sName, $sAlias) - { - $sRealFileName = $this->codeFileName($sName); - - if ($this->oCacher) - { - $this->oCacher->Delete($this->wildcardDomainsCacheKey()); - } - - $mResult = \file_put_contents($this->sDomainPath.'/'.$sRealFileName.'.alias', $sAlias); - return \is_int($mResult) && 0 < $mResult; - } - - /** - * @param string $sName - * @param bool $bDisable - * - * @return bool - */ - public function Disable($sName, $bDisable) - { - $sName = \MailSo\Base\Utils::IdnToAscii($sName, true); - - $sFile = ''; - if (\file_exists($this->sDomainPath.'/disabled')) - { - $sFile = @\file_get_contents($this->sDomainPath.'/disabled'); - } - - $aResult = array(); - $aNames = \explode(',', $sFile); - if ($bDisable) - { - \array_push($aNames, $sName); - $aResult = $aNames; - } - else - { - foreach ($aNames as $sItem) - { - if ($sName !== $sItem) - { - $aResult[] = $sItem; - } - } - } - - $aResult = \array_unique($aResult); - return false !== \file_put_contents($this->sDomainPath.'/disabled', \trim(\implode(',', $aResult), ', ')); - } - - /** - * @param string $sName - * - * @return bool - */ - public function Delete($sName) - { - $bResult = true; - $sRealFileName = $this->codeFileName($sName); - - if (0 < \strlen($sName)) - { - if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.ini')) - { - $bResult = \unlink($this->sDomainPath.'/'.$sRealFileName.'.ini'); - } - else if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.alias')) - { - $bResult = \unlink($this->sDomainPath.'/'.$sRealFileName.'.alias'); - } - } - - if ($bResult) - { - $this->Disable($sName, false); - } - - if ($this->oCacher) - { - $this->oCacher->Delete($this->wildcardDomainsCacheKey()); - } - - return $bResult; - } - - /** - * @param int $iOffset = 0 - * @param int $iLimit = 20 - * @param int $sSearch = '' - * @param bool $bIncludeAliases = true - * - * @return array - */ - public function GetList($iOffset = 0, $iLimit = 20, $sSearch = '', $bIncludeAliases = true) - { - $aResult = array(); - $aWildCards = array(); - $aAliases = array(); - -// $aList = \glob($this->sDomainPath.'/*.{ini,alias}', GLOB_BRACE); - $aList = @\array_diff(\scandir($this->sDomainPath), array('.', '..')); - if (\is_array($aList)) - { - foreach ($aList as $sFile) - { - $sName = $sFile; - if ('.ini' === \substr($sName, -4) || '.alias' === \substr($sName, -6)) - { - $bAlias = '.alias' === \substr($sName, -6); - - $sName = \preg_replace('/\.(ini|alias)$/', '', $sName); - $sName = $this->codeFileName($sName, true); - - if ($bAlias) - { - if ($bIncludeAliases) - { - $aAliases[] = $sName; - } - } - else if (false !== \strpos($sName, '*')) - { - $aWildCards[] = $sName; - } - else - { - $aResult[] = $sName; - } - } - } - } - - \sort($aResult, SORT_STRING); - \sort($aAliases, SORT_STRING); - \rsort($aWildCards, SORT_STRING); - - $aResult = \array_merge($aResult, $aAliases, $aWildCards); - - $iOffset = (0 > $iOffset) ? 0 : $iOffset; - $iLimit = (0 > $iLimit) ? 0 : ((999 < $iLimit) ? 999 : $iLimit); - - $aResult = \array_slice($aResult, $iOffset, $iLimit); - - $aDisabledNames = array(); - if (0 < \count($aResult) && \file_exists($this->sDomainPath.'/disabled')) - { - $sDisabled = @\file_get_contents($this->sDomainPath.'/disabled'); - if (false !== $sDisabled && 0 < strlen($sDisabled)) - { - $aDisabledNames = \explode(',', $sDisabled); - $aDisabledNames = \array_unique($aDisabledNames); - foreach ($aDisabledNames as $iIndex => $sValue) - { - $aDisabledNames[$iIndex] = \MailSo\Base\Utils::IdnToUtf8($sValue, true); - } - } - } - - $aReturn = array(); - foreach ($aResult as $sName) - { - $aReturn[$sName] = array( - !\in_array($sName, $aDisabledNames), - \in_array($sName, $aAliases) - ); - } - - return $aReturn; - } - - /** - * @param string $sSearch = '' - * @param bool $bIncludeAliases = true - * - * @return int - */ - public function Count($sSearch = '', $bIncludeAliases = true) - { - return \count($this->GetList(0, 999, $sSearch, $bIncludeAliases)); - } +sDomainPath = \rtrim(\trim($sDomainPath), '\\/'); + $this->oCacher = $oCacher; + } + + /** + * @param string $sName + * @param bool $bBack = false + * + * @return string + */ + public function codeFileName($sName, $bBack = false) + { + if ($bBack && 'default' === $sName) + { + return '*'; + } + else if (!$bBack && '*' === $sName) + { + return 'default'; + } + + if ($bBack) + { + $sName = \MailSo\Base\Utils::IdnToUtf8($sName, true); + } + else + { + $sName = \MailSo\Base\Utils::IdnToAscii($sName, true); + } + + return $bBack ? \str_replace('_wildcard_', '*', $sName) : \str_replace('*', '_wildcard_', $sName); + } + + /** + * @return string + */ + private function wildcardDomainsCacheKey() + { + return '/WildCard/DomainCache/'.\md5(APP_VERSION.APP_PRIVATE_DATA_NAME).'/'; + } + + /** + * @return string + */ + private function getWildcardDomainsLine() + { + if ($this->oCacher) + { + $sResult = $this->oCacher->Get($this->wildcardDomainsCacheKey()); + if (0 < \strlen($sResult)) + { + return $sResult; + } + } + + $sResult = ''; + $aNames = array(); + + $aList = \glob($this->sDomainPath.'/*.ini'); + foreach ($aList as $sFile) + { + $sName = \substr(\basename($sFile), 0, -4); + if ('default' === $sName || false !== \strpos($sName, '_wildcard_')) + { + $aNames[] = $this->codeFileName($sName, true); + } + } + + if (0 < \count($aNames)) + { + \rsort($aNames, SORT_STRING); + $sResult = \implode(' ', $aNames); + } + + if ($this->oCacher) + { + $this->oCacher->Set($this->wildcardDomainsCacheKey(), $sResult); + } + + return $sResult; + } + + /** + * @param string $sName + * @param bool $bFindWithWildCard = false + * @param bool $bCheckDisabled = true + * @param bool $bCheckAliases = true + * + * @return \RainLoop\Model\Domain|null + */ + public function Load($sName, $bFindWithWildCard = false, $bCheckDisabled = true, $bCheckAliases = true) + { + $mResult = null; + + $sDisabled = ''; + $sFoundedValue = ''; + + $sRealFileName = $this->codeFileName($sName); + + if (\file_exists($this->sDomainPath.'/disabled')) + { + $sDisabled = @\file_get_contents($this->sDomainPath.'/disabled'); + } + + if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.ini') && + (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.\MailSo\Base\Utils::IdnToAscii($sName, true).','))) + { + $aDomain = \RainLoop\Utils::CustomParseIniFile($this->sDomainPath.'/'.$sRealFileName.'.ini'); +// if ($bCheckAliases && !empty($aDomain['alias'])) +// { +// $oDomain = $this->Load($aDomain['alias'], false, false, false); +// if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain) +// { +// $oDomain->SetAliasName($sName); +// } +// +// return $oDomain; +// } + + // fix misspellings (#119) + if (\is_array($aDomain)) + { + if (isset($aDomain['smpt_host'])) + { + $aDomain['smtp_host'] = $aDomain['smpt_host']; + } + + if (isset($aDomain['smpt_port'])) + { + $aDomain['smtp_port'] = $aDomain['smpt_port']; + } + + if (isset($aDomain['smpt_secure'])) + { + $aDomain['smtp_secure'] = $aDomain['smpt_secure']; + } + + if (isset($aDomain['smpt_auth'])) + { + $aDomain['smtp_auth'] = $aDomain['smpt_auth']; + } + } + //--- + + $mResult = \RainLoop\Model\Domain::NewInstanceFromDomainConfigArray($sName, $aDomain); + } + else if ($bCheckAliases && \file_exists($this->sDomainPath.'/'.$sRealFileName.'.alias') && + (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.\MailSo\Base\Utils::IdnToAscii($sName, true).','))) + { + $sAlias = \trim(\file_get_contents($this->sDomainPath.'/'.$sRealFileName.'.alias')); + if (!empty($sAlias)) + { + $oDomain = $this->Load($sAlias, false, false, false); + if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain) + { + $oDomain->SetAliasName($sName); + } + + return $oDomain; + } + } + else if ($bFindWithWildCard) + { + $sNames = $this->getWildcardDomainsLine(); + if (0 < \strlen($sNames)) + { + if (\RainLoop\Plugins\Helper::ValidateWildcardValues( + \MailSo\Base\Utils::IdnToUtf8($sName, true), $sNames, $sFoundedValue) && 0 < \strlen($sFoundedValue)) + { + if (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.$sFoundedValue.',')) + { + $mResult = $this->Load($sFoundedValue, false); + } + } + } + } + + return $mResult; + } + + /** + * @param \RainLoop\Model\Domain $oDomain + * + * @return bool + */ + public function Save(\RainLoop\Model\Domain $oDomain) + { + $sRealFileName = $this->codeFileName($oDomain->Name()); + + if ($this->oCacher) + { + $this->oCacher->Delete($this->wildcardDomainsCacheKey()); + } + + $mResult = \file_put_contents($this->sDomainPath.'/'.$sRealFileName.'.ini', $oDomain->ToIniString()); + return \is_int($mResult) && 0 < $mResult; + } + + /** + * @param string $sName + * @param string $sAlias + * + * @return bool + */ + public function SaveAlias($sName, $sAlias) + { + $sRealFileName = $this->codeFileName($sName); + + if ($this->oCacher) + { + $this->oCacher->Delete($this->wildcardDomainsCacheKey()); + } + + $mResult = \file_put_contents($this->sDomainPath.'/'.$sRealFileName.'.alias', $sAlias); + return \is_int($mResult) && 0 < $mResult; + } + + /** + * @param string $sName + * @param bool $bDisable + * + * @return bool + */ + public function Disable($sName, $bDisable) + { + $sName = \MailSo\Base\Utils::IdnToAscii($sName, true); + + $sFile = ''; + if (\file_exists($this->sDomainPath.'/disabled')) + { + $sFile = @\file_get_contents($this->sDomainPath.'/disabled'); + } + + $aResult = array(); + $aNames = \explode(',', $sFile); + if ($bDisable) + { + \array_push($aNames, $sName); + $aResult = $aNames; + } + else + { + foreach ($aNames as $sItem) + { + if ($sName !== $sItem) + { + $aResult[] = $sItem; + } + } + } + + $aResult = \array_unique($aResult); + return false !== \file_put_contents($this->sDomainPath.'/disabled', \trim(\implode(',', $aResult), ', ')); + } + + /** + * @param string $sName + * + * @return bool + */ + public function Delete($sName) + { + $bResult = true; + $sRealFileName = $this->codeFileName($sName); + + if (0 < \strlen($sName)) + { + if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.ini')) + { + $bResult = \unlink($this->sDomainPath.'/'.$sRealFileName.'.ini'); + } + else if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.alias')) + { + $bResult = \unlink($this->sDomainPath.'/'.$sRealFileName.'.alias'); + } + } + + if ($bResult) + { + $this->Disable($sName, false); + } + + if ($this->oCacher) + { + $this->oCacher->Delete($this->wildcardDomainsCacheKey()); + } + + return $bResult; + } + + /** + * @param int $iOffset = 0 + * @param int $iLimit = 20 + * @param int $sSearch = '' + * @param bool $bIncludeAliases = true + * + * @return array + */ + public function GetList($iOffset = 0, $iLimit = 20, $sSearch = '', $bIncludeAliases = true) + { + $aResult = array(); + $aWildCards = array(); + $aAliases = array(); + +// $aList = \glob($this->sDomainPath.'/*.{ini,alias}', GLOB_BRACE); + $aList = @\array_diff(\scandir($this->sDomainPath), array('.', '..')); + if (\is_array($aList)) + { + foreach ($aList as $sFile) + { + $sName = $sFile; + if ('.ini' === \substr($sName, -4) || '.alias' === \substr($sName, -6)) + { + $bAlias = '.alias' === \substr($sName, -6); + + $sName = \preg_replace('/\.(ini|alias)$/', '', $sName); + $sName = $this->codeFileName($sName, true); + + if ($bAlias) + { + if ($bIncludeAliases) + { + $aAliases[] = $sName; + } + } + else if (false !== \strpos($sName, '*')) + { + $aWildCards[] = $sName; + } + else + { + $aResult[] = $sName; + } + } + } + } + + \sort($aResult, SORT_STRING); + \sort($aAliases, SORT_STRING); + \rsort($aWildCards, SORT_STRING); + + $aResult = \array_merge($aResult, $aAliases, $aWildCards); + + $iOffset = (0 > $iOffset) ? 0 : $iOffset; + $iLimit = (0 > $iLimit) ? 0 : ((999 < $iLimit) ? 999 : $iLimit); + + $aResult = \array_slice($aResult, $iOffset, $iLimit); + + $aDisabledNames = array(); + if (0 < \count($aResult) && \file_exists($this->sDomainPath.'/disabled')) + { + $sDisabled = @\file_get_contents($this->sDomainPath.'/disabled'); + if (false !== $sDisabled && 0 < strlen($sDisabled)) + { + $aDisabledNames = \explode(',', $sDisabled); + $aDisabledNames = \array_unique($aDisabledNames); + foreach ($aDisabledNames as $iIndex => $sValue) + { + $aDisabledNames[$iIndex] = \MailSo\Base\Utils::IdnToUtf8($sValue, true); + } + } + } + + $aReturn = array(); + foreach ($aResult as $sName) + { + $aReturn[$sName] = array( + !\in_array($sName, $aDisabledNames), + \in_array($sName, $aAliases) + ); + } + + return $aReturn; + } + + /** + * @param string $sSearch = '' + * @param bool $bIncludeAliases = true + * + * @return int + */ + public function Count($sSearch = '', $bIncludeAliases = true) + { + return \count($this->GetList(0, 999, $sSearch, $bIncludeAliases)); + } } \ No newline at end of file diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Domain/DomainAdminInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Domain/DomainAdminInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Domain/DomainAdminInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Domain/DomainAdminInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Domain/DomainInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Domain/DomainInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Domain/DomainInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Domain/DomainInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Files.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Files.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Files.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Files.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Files/FileStorage.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Files/FileStorage.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Files/FileStorage.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Files/FileStorage.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Files/IFiles.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Files/IFiles.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Files/IFiles.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Files/IFiles.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Classes/Filter.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Classes/Filter.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Classes/Filter.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Classes/Filter.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Classes/FilterCondition.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Classes/FilterCondition.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Classes/FilterCondition.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Classes/FilterCondition.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Enumerations/ActionType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Enumerations/ActionType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Enumerations/ActionType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Enumerations/ActionType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionField.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionField.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionField.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionField.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionsType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionsType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionsType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/Enumerations/ConditionsType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/FiltersInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/FiltersInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/FiltersInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/FiltersInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/SieveStorage.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/SieveStorage.php similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/SieveStorage.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/SieveStorage.php index 953ca350..04b15f8e 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Filters/SieveStorage.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Filters/SieveStorage.php @@ -1,564 +1,564 @@ -oLogger = null; - - $this->oPlugins = $oPlugins; - $this->oConfig = $oConfig; - - $this->bUtf8FolderName = !!$this->oConfig->Get('labs', 'sieve_utf8_folder_name', true); - } - - /** - * @param \RainLoop\Model\Account $oAccount - * @param bool $bAllowRaw = false - * - * @return array - */ - public function Load($oAccount, $bAllowRaw = false) - { - $sRaw = ''; - - $bBasicIsActive = false; - $bRawIsActive = false; - - $aModules = array(); - $aFilters = array(); - - $oSieveClient = \MailSo\Sieve\ManageSieveClient::NewInstance()->SetLogger($this->oLogger); - $oSieveClient->SetTimeOuts(10, (int) $this->oConfig->Get('labs', 'sieve_timeout', 10)); - - if ($oAccount->SieveConnectAndLoginHelper($this->oPlugins, $oSieveClient, $this->oConfig)) - { - $aModules = $oSieveClient->Modules(); - $aList = $oSieveClient->ListScripts(); - - if (\is_array($aList) && 0 < \count($aList)) - { - if (isset($aList[self::SIEVE_FILE_NAME])) - { - $bBasicIsActive = !!$aList[self::SIEVE_FILE_NAME]; - $sS = $oSieveClient->GetScript(self::SIEVE_FILE_NAME); - if ($sS) - { - $aFilters = $this->fileStringToCollection($sS); - } - } - - if ($bAllowRaw && isset($aList[self::SIEVE_FILE_NAME_RAW])) - { - $bRawIsActive = !!$aList[self::SIEVE_FILE_NAME_RAW]; - $sRaw = \trim($oSieveClient->GetScript(self::SIEVE_FILE_NAME_RAW)); - } - } - - $oSieveClient->LogoutAndDisconnect(); - } - - return array( - 'RawIsAllow' => $bAllowRaw, - 'RawIsActive' => $bRawIsActive, - 'Raw' => $bAllowRaw ? $sRaw : '', - 'Filters' => !$bBasicIsActive && !$bRawIsActive ? array() : $aFilters, - 'Capa' => $bAllowRaw ? $aModules : array(), - 'Modules' => array( - 'redirect' => \in_array('fileinto', $aModules), - 'regex' => \in_array('regex', $aModules), - 'relational' => \in_array('relational', $aModules), - 'date' => \in_array('date', $aModules), - 'moveto' => \in_array('fileinto', $aModules), - 'reject' => \in_array('reject', $aModules), - 'vacation' => \in_array('vacation', $aModules), - 'markasread' => \in_array('imap4flags', $aModules) - ) - ); - } - - /** - * @param \RainLoop\Model\Account $oAccount - * @param array $aFilters - * @param string $sRaw = '' - * @param bool $bRawIsActive = false - * - * @return bool - */ - public function Save($oAccount, $aFilters, $sRaw = '', $bRawIsActive = false) - { - $oSieveClient = \MailSo\Sieve\ManageSieveClient::NewInstance()->SetLogger($this->oLogger); - $oSieveClient->SetTimeOuts(10, (int) \RainLoop\Api::Config()->Get('labs', 'sieve_timeout', 10)); - - if ($oAccount->SieveConnectAndLoginHelper($this->oPlugins, $oSieveClient, $this->oConfig)) - { - $aList = $oSieveClient->ListScripts(); - - if ($bRawIsActive) - { - if (!empty($sRaw)) - { - $oSieveClient->PutScript(self::SIEVE_FILE_NAME_RAW, $sRaw); - $oSieveClient->SetActiveScript(self::SIEVE_FILE_NAME_RAW); - } - else if (isset($aList[self::SIEVE_FILE_NAME_RAW])) - { - $oSieveClient->DeleteScript(self::SIEVE_FILE_NAME_RAW); - } - } - else - { - $sUserFilter = $this->collectionToFileString($aFilters); - - if (!empty($sUserFilter)) - { - $oSieveClient->PutScript(self::SIEVE_FILE_NAME, $sUserFilter); - $oSieveClient->SetActiveScript(self::SIEVE_FILE_NAME); - } - else if (isset($aList[self::SIEVE_FILE_NAME])) - { - $oSieveClient->DeleteScript(self::SIEVE_FILE_NAME); - } - } - - $oSieveClient->LogoutAndDisconnect(); - - return true; - } - - return false; - } - - /** - * @param \RainLoop\Providers\Filters\Classes\FilterCondition $oCondition - * - * @return string - */ - private function conditionToSieveScript($oCondition, &$aCapa) - { - $sResult = ''; - $sTypeWord = ''; - $bTrue = true; - - $sValue = \trim($oCondition->Value()); - $sValueSecond = \trim($oCondition->ValueSecond()); - - if (0 < \strlen($sValue) || - (0 < \strlen($sValue) && 0 < \strlen($sValueSecond) && - \RainLoop\Providers\Filters\Enumerations\ConditionField::HEADER === $oCondition->Field())) - { - switch ($oCondition->Type()) - { - case \RainLoop\Providers\Filters\Enumerations\ConditionType::OVER: - $sTypeWord = ':over'; - break; - case \RainLoop\Providers\Filters\Enumerations\ConditionType::UNDER: - $sTypeWord = ':under'; - break; - case \RainLoop\Providers\Filters\Enumerations\ConditionType::NOT_EQUAL_TO: - $sResult .= 'not '; - case \RainLoop\Providers\Filters\Enumerations\ConditionType::EQUAL_TO: - $sTypeWord = ':is'; - break; - case \RainLoop\Providers\Filters\Enumerations\ConditionType::NOT_CONTAINS: - $sResult .= 'not '; - case \RainLoop\Providers\Filters\Enumerations\ConditionType::CONTAINS: - $sTypeWord = ':contains'; - break; - case \RainLoop\Providers\Filters\Enumerations\ConditionType::REGEX: - $sTypeWord = ':regex'; - $aCapa['regex'] = true; - break; - default: - $bTrue = false; - $sResult = '/* @Error: unknown type value */ false'; - break; - } - - switch ($oCondition->Field()) - { - case \RainLoop\Providers\Filters\Enumerations\ConditionField::FROM: - $sResult .= 'header '.$sTypeWord.' ["From"]'; - break; - case \RainLoop\Providers\Filters\Enumerations\ConditionField::RECIPIENT: - $sResult .= 'header '.$sTypeWord.' ["To", "CC"]'; - break; - case \RainLoop\Providers\Filters\Enumerations\ConditionField::SUBJECT: - $sResult .= 'header '.$sTypeWord.' ["Subject"]'; - break; - case \RainLoop\Providers\Filters\Enumerations\ConditionField::HEADER: - $sResult .= 'header '.$sTypeWord.' ["'.$this->quote($sValueSecond).'"]'; - break; - case \RainLoop\Providers\Filters\Enumerations\ConditionField::SIZE: - $sResult .= 'size '.$sTypeWord; - break; - default: - $bTrue = false; - $sResult = '/* @Error: unknown field value */ false'; - break; - } - - if ($bTrue) - { - if (\in_array($oCondition->Field(), array( - \RainLoop\Providers\Filters\Enumerations\ConditionField::FROM, - \RainLoop\Providers\Filters\Enumerations\ConditionField::RECIPIENT - )) && false !== \strpos($sValue, ',')) - { - $self = $this; - $aValue = \array_map(function ($sValue) use ($self) { - return '"'.$self->quote(\trim($sValue)).'"'; - }, \explode(',', $sValue)); - - $sResult .= ' ['.\trim(\implode(', ', $aValue)).']'; - } - else if (\RainLoop\Providers\Filters\Enumerations\ConditionField::SIZE === $oCondition->Field()) - { - $sResult .= ' '.$this->quote($sValue); - } - else - { - $sResult .= ' "'.$this->quote($sValue).'"'; - } - - $sResult = \MailSo\Base\Utils::StripSpaces($sResult); - } - } - else - { - $sResult = '/* @Error: empty condition value */ false'; - } - - return $sResult; - } - - /** - * @param \RainLoop\Providers\Filters\Classes\Filter $oFilter - * @param array $aCapa - * - * @return string - */ - private function filterToSieveScript($oFilter, &$aCapa) - { - $sNL = \RainLoop\Providers\Filters\SieveStorage::NEW_LINE; - $sTab = ' '; - - $bAll = false; - $aResult = array(); - - // Conditions - $aConditions = $oFilter->Conditions(); - if (\is_array($aConditions)) - { - if (1 < \count($aConditions)) - { - if (\RainLoop\Providers\Filters\Enumerations\ConditionsType::ANY === - $oFilter->ConditionsType()) - { - $aResult[] = 'if anyof('; - - $bTrim = false; - foreach ($aConditions as $oCond) - { - $bTrim = true; - $sCons = $this->conditionToSieveScript($oCond, $aCapa); - if (!empty($sCons)) - { - $aResult[] = $sTab.$sCons.','; - } - } - if ($bTrim) - { - $aResult[\count($aResult) - 1] = \rtrim($aResult[\count($aResult) - 1], ','); - } - - $aResult[] = ')'; - } - else - { - $aResult[] = 'if allof('; - foreach ($aConditions as $oCond) - { - $aResult[] = $sTab.$this->conditionToSieveScript($oCond, $aCapa).','; - } - - $aResult[\count($aResult) - 1] = \rtrim($aResult[\count($aResult) - 1], ','); - $aResult[] = ')'; - } - } - else if (1 === \count($aConditions)) - { - $aResult[] = 'if '.$this->conditionToSieveScript($aConditions[0], $aCapa).''; - } - else - { - $bAll = true; - } - } - - // actions - if (!$bAll) - { - $aResult[] = '{'; - } - else - { - $sTab = ''; - } - - if ($oFilter->MarkAsRead() && \in_array($oFilter->ActionType(), array( - \RainLoop\Providers\Filters\Enumerations\ActionType::NONE, - \RainLoop\Providers\Filters\Enumerations\ActionType::MOVE_TO, - \RainLoop\Providers\Filters\Enumerations\ActionType::FORWARD - ))) - { - $aCapa['imap4flags'] = true; - $aResult[] = $sTab.'addflag "\\\\Seen";'; - } - - switch ($oFilter->ActionType()) - { - case \RainLoop\Providers\Filters\Enumerations\ActionType::NONE: - $aResult[] = $sTab.'stop;'; - break; - case \RainLoop\Providers\Filters\Enumerations\ActionType::DISCARD: - $aResult[] = $sTab.'discard;'; - $aResult[] = $sTab.'stop;'; - break; - case \RainLoop\Providers\Filters\Enumerations\ActionType::VACATION: - $sValue = \trim($oFilter->ActionValue()); - $sValueSecond = \trim($oFilter->ActionValueSecond()); - $sValueThird = \trim($oFilter->ActionValueThird()); - $sValueFourth = \trim($oFilter->ActionValueFourth()); - if (0 < \strlen($sValue)) - { - $aCapa['vacation'] = true; - - $iDays = 1; - $sSubject = ''; - if (0 < \strlen($sValueSecond)) - { - $sSubject = ':subject "'. - $this->quote(\MailSo\Base\Utils::StripSpaces($sValueSecond)).'" '; - } - - if (0 < \strlen($sValueThird) && \is_numeric($sValueThird) && 1 < (int) $sValueThird) - { - $iDays = (int) $sValueThird; - } - - $sAddresses = ''; - if (0 < \strlen($sValueFourth)) - { - $self = $this; - - $aAddresses = \explode(',', $sValueFourth); - $aAddresses = \array_filter(\array_map(function ($sEmail) use ($self) { - $sEmail = \trim($sEmail); - return 0 < \strlen($sEmail) ? '"'.$self->quote($sEmail).'"' : ''; - }, $aAddresses), 'strlen'); - - if (0 < \count($aAddresses)) - { - $sAddresses = ':addresses ['.\implode(', ', $aAddresses).'] '; - } - } - - $aResult[] = $sTab.'vacation :days '.$iDays.' '.$sAddresses.$sSubject.'"'.$this->quote($sValue).'";'; - if ($oFilter->Stop()) - { - $aResult[] = $sTab.'stop;'; - } - } - else - { - $aResult[] = $sTab.'# @Error (vacation): empty action value'; - } - break; - case \RainLoop\Providers\Filters\Enumerations\ActionType::REJECT: - $sValue = \trim($oFilter->ActionValue()); - if (0 < \strlen($sValue)) - { - $aCapa['reject'] = true; - - $aResult[] = $sTab.'reject "'.$this->quote($sValue).'";'; - $aResult[] = $sTab.'stop;'; - } - else - { - $aResult[] = $sTab.'# @Error (reject): empty action value'; - } - break; - case \RainLoop\Providers\Filters\Enumerations\ActionType::FORWARD: - $sValue = $oFilter->ActionValue(); - if (0 < \strlen($sValue)) - { - if ($oFilter->Keep()) - { - $aCapa['fileinto'] = true; - $aResult[] = $sTab.'fileinto "INBOX";'; - } - - $aResult[] = $sTab.'redirect "'.$this->quote($sValue).'";'; - $aResult[] = $sTab.'stop;'; - } - else - { - $aResult[] = $sTab.'# @Error (redirect): empty action value'; - } - break; - case \RainLoop\Providers\Filters\Enumerations\ActionType::MOVE_TO: - $sValue = $oFilter->ActionValue(); - if (0 < \strlen($sValue)) - { - $sFolderName = $sValue; // utf7-imap - if ($this->bUtf8FolderName) // to utf-8 - { - $sFolderName = \MailSo\Base\Utils::ConvertEncoding($sFolderName, - \MailSo\Base\Enumerations\Charset::UTF_7_IMAP, - \MailSo\Base\Enumerations\Charset::UTF_8); - } - - $aCapa['fileinto'] = true; - $aResult[] = $sTab.'fileinto "'.$this->quote($sFolderName).'";'; - $aResult[] = $sTab.'stop;'; - } - else - { - $aResult[] = $sTab.'# @Error (fileinto): empty action value'; - } - break; - } - - if (!$bAll) - { - $aResult[] = '}'; - } - - return \implode($sNL, $aResult); - } - - /** - * @param array $aFilters - * - * @return string - */ - private function collectionToFileString($aFilters) - { - $sNL = \RainLoop\Providers\Filters\SieveStorage::NEW_LINE; - - $aCapa = array(); - $aParts = array(); - - $aParts[] = '# This is RainLoop Webmail sieve script.'; - $aParts[] = '# Please don\'t change anything here.'; - $aParts[] = '# RAINLOOP:SIEVE'; - $aParts[] = ''; - - foreach ($aFilters as /* @var $oItem \RainLoop\Providers\Filters\Classes\Filter */ $oItem) - { - $aData = array(); - $aData[] = '/*'; - $aData[] = 'BEGIN:FILTER:'.$oItem->ID(); - $aData[] = 'BEGIN:HEADER'; - $aData[] = \chunk_split(\base64_encode($oItem->serializeToJson()), 74, $sNL).'END:HEADER'; - $aData[] = '*/'; - $aData[] = $oItem->Enabled() ? '' : '/* @Filter is disabled '; - $aData[] = $this->filterToSieveScript($oItem, $aCapa); - $aData[] = $oItem->Enabled() ? '' : '*/'; - $aData[] = '/* END:FILTER */'; - $aData[] = ''; - - $aParts[] = \implode($sNL, $aData); - } - - $aCapa = \array_keys($aCapa); - $sCapa = 0 < \count($aCapa) ? $sNL.'require '. - \str_replace('","', '", "', \json_encode($aCapa)).';'.$sNL : ''; - - return $sCapa.$sNL.\implode($sNL, $aParts).$sNL; - } - - /** - * @param string $sFileString - * - * @return array - */ - private function fileStringToCollection($sFileString) - { - $aResult = array(); - if (!empty($sFileString) && false !== \strpos($sFileString, 'RAINLOOP:SIEVE')) - { - $aMatch = array(); - if (\preg_match_all('/BEGIN:FILTER(.+?)BEGIN:HEADER(.+?)END:HEADER/s', $sFileString, $aMatch) && - isset($aMatch[2]) && \is_array($aMatch[2])) - { - foreach ($aMatch[2] as $sEncodedLine) - { - if (!empty($sEncodedLine)) - { - $sDecodedLine = \base64_decode(\preg_replace('/[\s]+/', '', $sEncodedLine)); - if (!empty($sDecodedLine)) - { - $oItem = new \RainLoop\Providers\Filters\Classes\Filter(); - if ($oItem && $oItem->unserializeFromJson($sDecodedLine)) - { - $aResult[] = $oItem; - } - } - } - } - } - } - - return $aResult; - } - - /** - * @param string $sValue - * - * @return string - */ - public function quote($sValue) - { - return \str_replace(array('\\', '"'), array('\\\\', '\\"'), \trim($sValue)); - } - - /** - * @param \MailSo\Log\Logger $oLogger - */ - public function SetLogger($oLogger) - { - $this->oLogger = $oLogger instanceof \MailSo\Log\Logger ? $oLogger : null; - } -} +oLogger = null; + + $this->oPlugins = $oPlugins; + $this->oConfig = $oConfig; + + $this->bUtf8FolderName = !!$this->oConfig->Get('labs', 'sieve_utf8_folder_name', true); + } + + /** + * @param \RainLoop\Model\Account $oAccount + * @param bool $bAllowRaw = false + * + * @return array + */ + public function Load($oAccount, $bAllowRaw = false) + { + $sRaw = ''; + + $bBasicIsActive = false; + $bRawIsActive = false; + + $aModules = array(); + $aFilters = array(); + + $oSieveClient = \MailSo\Sieve\ManageSieveClient::NewInstance()->SetLogger($this->oLogger); + $oSieveClient->SetTimeOuts(10, (int) $this->oConfig->Get('labs', 'sieve_timeout', 10)); + + if ($oAccount->SieveConnectAndLoginHelper($this->oPlugins, $oSieveClient, $this->oConfig)) + { + $aModules = $oSieveClient->Modules(); + $aList = $oSieveClient->ListScripts(); + + if (\is_array($aList) && 0 < \count($aList)) + { + if (isset($aList[self::SIEVE_FILE_NAME])) + { + $bBasicIsActive = !!$aList[self::SIEVE_FILE_NAME]; + $sS = $oSieveClient->GetScript(self::SIEVE_FILE_NAME); + if ($sS) + { + $aFilters = $this->fileStringToCollection($sS); + } + } + + if ($bAllowRaw && isset($aList[self::SIEVE_FILE_NAME_RAW])) + { + $bRawIsActive = !!$aList[self::SIEVE_FILE_NAME_RAW]; + $sRaw = \trim($oSieveClient->GetScript(self::SIEVE_FILE_NAME_RAW)); + } + } + + $oSieveClient->LogoutAndDisconnect(); + } + + return array( + 'RawIsAllow' => $bAllowRaw, + 'RawIsActive' => $bRawIsActive, + 'Raw' => $bAllowRaw ? $sRaw : '', + 'Filters' => !$bBasicIsActive && !$bRawIsActive ? array() : $aFilters, + 'Capa' => $bAllowRaw ? $aModules : array(), + 'Modules' => array( + 'redirect' => \in_array('fileinto', $aModules), + 'regex' => \in_array('regex', $aModules), + 'relational' => \in_array('relational', $aModules), + 'date' => \in_array('date', $aModules), + 'moveto' => \in_array('fileinto', $aModules), + 'reject' => \in_array('reject', $aModules), + 'vacation' => \in_array('vacation', $aModules), + 'markasread' => \in_array('imap4flags', $aModules) + ) + ); + } + + /** + * @param \RainLoop\Model\Account $oAccount + * @param array $aFilters + * @param string $sRaw = '' + * @param bool $bRawIsActive = false + * + * @return bool + */ + public function Save($oAccount, $aFilters, $sRaw = '', $bRawIsActive = false) + { + $oSieveClient = \MailSo\Sieve\ManageSieveClient::NewInstance()->SetLogger($this->oLogger); + $oSieveClient->SetTimeOuts(10, (int) \RainLoop\Api::Config()->Get('labs', 'sieve_timeout', 10)); + + if ($oAccount->SieveConnectAndLoginHelper($this->oPlugins, $oSieveClient, $this->oConfig)) + { + $aList = $oSieveClient->ListScripts(); + + if ($bRawIsActive) + { + if (!empty($sRaw)) + { + $oSieveClient->PutScript(self::SIEVE_FILE_NAME_RAW, $sRaw); + $oSieveClient->SetActiveScript(self::SIEVE_FILE_NAME_RAW); + } + else if (isset($aList[self::SIEVE_FILE_NAME_RAW])) + { + $oSieveClient->DeleteScript(self::SIEVE_FILE_NAME_RAW); + } + } + else + { + $sUserFilter = $this->collectionToFileString($aFilters); + + if (!empty($sUserFilter)) + { + $oSieveClient->PutScript(self::SIEVE_FILE_NAME, $sUserFilter); + $oSieveClient->SetActiveScript(self::SIEVE_FILE_NAME); + } + else if (isset($aList[self::SIEVE_FILE_NAME])) + { + $oSieveClient->DeleteScript(self::SIEVE_FILE_NAME); + } + } + + $oSieveClient->LogoutAndDisconnect(); + + return true; + } + + return false; + } + + /** + * @param \RainLoop\Providers\Filters\Classes\FilterCondition $oCondition + * + * @return string + */ + private function conditionToSieveScript($oCondition, &$aCapa) + { + $sResult = ''; + $sTypeWord = ''; + $bTrue = true; + + $sValue = \trim($oCondition->Value()); + $sValueSecond = \trim($oCondition->ValueSecond()); + + if (0 < \strlen($sValue) || + (0 < \strlen($sValue) && 0 < \strlen($sValueSecond) && + \RainLoop\Providers\Filters\Enumerations\ConditionField::HEADER === $oCondition->Field())) + { + switch ($oCondition->Type()) + { + case \RainLoop\Providers\Filters\Enumerations\ConditionType::OVER: + $sTypeWord = ':over'; + break; + case \RainLoop\Providers\Filters\Enumerations\ConditionType::UNDER: + $sTypeWord = ':under'; + break; + case \RainLoop\Providers\Filters\Enumerations\ConditionType::NOT_EQUAL_TO: + $sResult .= 'not '; + case \RainLoop\Providers\Filters\Enumerations\ConditionType::EQUAL_TO: + $sTypeWord = ':is'; + break; + case \RainLoop\Providers\Filters\Enumerations\ConditionType::NOT_CONTAINS: + $sResult .= 'not '; + case \RainLoop\Providers\Filters\Enumerations\ConditionType::CONTAINS: + $sTypeWord = ':contains'; + break; + case \RainLoop\Providers\Filters\Enumerations\ConditionType::REGEX: + $sTypeWord = ':regex'; + $aCapa['regex'] = true; + break; + default: + $bTrue = false; + $sResult = '/* @Error: unknown type value */ false'; + break; + } + + switch ($oCondition->Field()) + { + case \RainLoop\Providers\Filters\Enumerations\ConditionField::FROM: + $sResult .= 'header '.$sTypeWord.' ["From"]'; + break; + case \RainLoop\Providers\Filters\Enumerations\ConditionField::RECIPIENT: + $sResult .= 'header '.$sTypeWord.' ["To", "CC"]'; + break; + case \RainLoop\Providers\Filters\Enumerations\ConditionField::SUBJECT: + $sResult .= 'header '.$sTypeWord.' ["Subject"]'; + break; + case \RainLoop\Providers\Filters\Enumerations\ConditionField::HEADER: + $sResult .= 'header '.$sTypeWord.' ["'.$this->quote($sValueSecond).'"]'; + break; + case \RainLoop\Providers\Filters\Enumerations\ConditionField::SIZE: + $sResult .= 'size '.$sTypeWord; + break; + default: + $bTrue = false; + $sResult = '/* @Error: unknown field value */ false'; + break; + } + + if ($bTrue) + { + if (\in_array($oCondition->Field(), array( + \RainLoop\Providers\Filters\Enumerations\ConditionField::FROM, + \RainLoop\Providers\Filters\Enumerations\ConditionField::RECIPIENT + )) && false !== \strpos($sValue, ',')) + { + $self = $this; + $aValue = \array_map(function ($sValue) use ($self) { + return '"'.$self->quote(\trim($sValue)).'"'; + }, \explode(',', $sValue)); + + $sResult .= ' ['.\trim(\implode(', ', $aValue)).']'; + } + else if (\RainLoop\Providers\Filters\Enumerations\ConditionField::SIZE === $oCondition->Field()) + { + $sResult .= ' '.$this->quote($sValue); + } + else + { + $sResult .= ' "'.$this->quote($sValue).'"'; + } + + $sResult = \MailSo\Base\Utils::StripSpaces($sResult); + } + } + else + { + $sResult = '/* @Error: empty condition value */ false'; + } + + return $sResult; + } + + /** + * @param \RainLoop\Providers\Filters\Classes\Filter $oFilter + * @param array $aCapa + * + * @return string + */ + private function filterToSieveScript($oFilter, &$aCapa) + { + $sNL = \RainLoop\Providers\Filters\SieveStorage::NEW_LINE; + $sTab = ' '; + + $bAll = false; + $aResult = array(); + + // Conditions + $aConditions = $oFilter->Conditions(); + if (\is_array($aConditions)) + { + if (1 < \count($aConditions)) + { + if (\RainLoop\Providers\Filters\Enumerations\ConditionsType::ANY === + $oFilter->ConditionsType()) + { + $aResult[] = 'if anyof('; + + $bTrim = false; + foreach ($aConditions as $oCond) + { + $bTrim = true; + $sCons = $this->conditionToSieveScript($oCond, $aCapa); + if (!empty($sCons)) + { + $aResult[] = $sTab.$sCons.','; + } + } + if ($bTrim) + { + $aResult[\count($aResult) - 1] = \rtrim($aResult[\count($aResult) - 1], ','); + } + + $aResult[] = ')'; + } + else + { + $aResult[] = 'if allof('; + foreach ($aConditions as $oCond) + { + $aResult[] = $sTab.$this->conditionToSieveScript($oCond, $aCapa).','; + } + + $aResult[\count($aResult) - 1] = \rtrim($aResult[\count($aResult) - 1], ','); + $aResult[] = ')'; + } + } + else if (1 === \count($aConditions)) + { + $aResult[] = 'if '.$this->conditionToSieveScript($aConditions[0], $aCapa).''; + } + else + { + $bAll = true; + } + } + + // actions + if (!$bAll) + { + $aResult[] = '{'; + } + else + { + $sTab = ''; + } + + if ($oFilter->MarkAsRead() && \in_array($oFilter->ActionType(), array( + \RainLoop\Providers\Filters\Enumerations\ActionType::NONE, + \RainLoop\Providers\Filters\Enumerations\ActionType::MOVE_TO, + \RainLoop\Providers\Filters\Enumerations\ActionType::FORWARD + ))) + { + $aCapa['imap4flags'] = true; + $aResult[] = $sTab.'addflag "\\\\Seen";'; + } + + switch ($oFilter->ActionType()) + { + case \RainLoop\Providers\Filters\Enumerations\ActionType::NONE: + $aResult[] = $sTab.'stop;'; + break; + case \RainLoop\Providers\Filters\Enumerations\ActionType::DISCARD: + $aResult[] = $sTab.'discard;'; + $aResult[] = $sTab.'stop;'; + break; + case \RainLoop\Providers\Filters\Enumerations\ActionType::VACATION: + $sValue = \trim($oFilter->ActionValue()); + $sValueSecond = \trim($oFilter->ActionValueSecond()); + $sValueThird = \trim($oFilter->ActionValueThird()); + $sValueFourth = \trim($oFilter->ActionValueFourth()); + if (0 < \strlen($sValue)) + { + $aCapa['vacation'] = true; + + $iDays = 1; + $sSubject = ''; + if (0 < \strlen($sValueSecond)) + { + $sSubject = ':subject "'. + $this->quote(\MailSo\Base\Utils::StripSpaces($sValueSecond)).'" '; + } + + if (0 < \strlen($sValueThird) && \is_numeric($sValueThird) && 1 < (int) $sValueThird) + { + $iDays = (int) $sValueThird; + } + + $sAddresses = ''; + if (0 < \strlen($sValueFourth)) + { + $self = $this; + + $aAddresses = \explode(',', $sValueFourth); + $aAddresses = \array_filter(\array_map(function ($sEmail) use ($self) { + $sEmail = \trim($sEmail); + return 0 < \strlen($sEmail) ? '"'.$self->quote($sEmail).'"' : ''; + }, $aAddresses), 'strlen'); + + if (0 < \count($aAddresses)) + { + $sAddresses = ':addresses ['.\implode(', ', $aAddresses).'] '; + } + } + + $aResult[] = $sTab.'vacation :days '.$iDays.' '.$sAddresses.$sSubject.'"'.$this->quote($sValue).'";'; + if ($oFilter->Stop()) + { + $aResult[] = $sTab.'stop;'; + } + } + else + { + $aResult[] = $sTab.'# @Error (vacation): empty action value'; + } + break; + case \RainLoop\Providers\Filters\Enumerations\ActionType::REJECT: + $sValue = \trim($oFilter->ActionValue()); + if (0 < \strlen($sValue)) + { + $aCapa['reject'] = true; + + $aResult[] = $sTab.'reject "'.$this->quote($sValue).'";'; + $aResult[] = $sTab.'stop;'; + } + else + { + $aResult[] = $sTab.'# @Error (reject): empty action value'; + } + break; + case \RainLoop\Providers\Filters\Enumerations\ActionType::FORWARD: + $sValue = $oFilter->ActionValue(); + if (0 < \strlen($sValue)) + { + if ($oFilter->Keep()) + { + $aCapa['fileinto'] = true; + $aResult[] = $sTab.'fileinto "INBOX";'; + } + + $aResult[] = $sTab.'redirect "'.$this->quote($sValue).'";'; + $aResult[] = $sTab.'stop;'; + } + else + { + $aResult[] = $sTab.'# @Error (redirect): empty action value'; + } + break; + case \RainLoop\Providers\Filters\Enumerations\ActionType::MOVE_TO: + $sValue = $oFilter->ActionValue(); + if (0 < \strlen($sValue)) + { + $sFolderName = $sValue; // utf7-imap + if ($this->bUtf8FolderName) // to utf-8 + { + $sFolderName = \MailSo\Base\Utils::ConvertEncoding($sFolderName, + \MailSo\Base\Enumerations\Charset::UTF_7_IMAP, + \MailSo\Base\Enumerations\Charset::UTF_8); + } + + $aCapa['fileinto'] = true; + $aResult[] = $sTab.'fileinto "'.$this->quote($sFolderName).'";'; + $aResult[] = $sTab.'stop;'; + } + else + { + $aResult[] = $sTab.'# @Error (fileinto): empty action value'; + } + break; + } + + if (!$bAll) + { + $aResult[] = '}'; + } + + return \implode($sNL, $aResult); + } + + /** + * @param array $aFilters + * + * @return string + */ + private function collectionToFileString($aFilters) + { + $sNL = \RainLoop\Providers\Filters\SieveStorage::NEW_LINE; + + $aCapa = array(); + $aParts = array(); + + $aParts[] = '# This is RainLoop Webmail sieve script.'; + $aParts[] = '# Please don\'t change anything here.'; + $aParts[] = '# RAINLOOP:SIEVE'; + $aParts[] = ''; + + foreach ($aFilters as /* @var $oItem \RainLoop\Providers\Filters\Classes\Filter */ $oItem) + { + $aData = array(); + $aData[] = '/*'; + $aData[] = 'BEGIN:FILTER:'.$oItem->ID(); + $aData[] = 'BEGIN:HEADER'; + $aData[] = \chunk_split(\base64_encode($oItem->serializeToJson()), 74, $sNL).'END:HEADER'; + $aData[] = '*/'; + $aData[] = $oItem->Enabled() ? '' : '/* @Filter is disabled '; + $aData[] = $this->filterToSieveScript($oItem, $aCapa); + $aData[] = $oItem->Enabled() ? '' : '*/'; + $aData[] = '/* END:FILTER */'; + $aData[] = ''; + + $aParts[] = \implode($sNL, $aData); + } + + $aCapa = \array_keys($aCapa); + $sCapa = 0 < \count($aCapa) ? $sNL.'require '. + \str_replace('","', '", "', \json_encode($aCapa)).';'.$sNL : ''; + + return $sCapa.$sNL.\implode($sNL, $aParts).$sNL; + } + + /** + * @param string $sFileString + * + * @return array + */ + private function fileStringToCollection($sFileString) + { + $aResult = array(); + if (!empty($sFileString) && false !== \strpos($sFileString, 'RAINLOOP:SIEVE')) + { + $aMatch = array(); + if (\preg_match_all('/BEGIN:FILTER(.+?)BEGIN:HEADER(.+?)END:HEADER/s', $sFileString, $aMatch) && + isset($aMatch[2]) && \is_array($aMatch[2])) + { + foreach ($aMatch[2] as $sEncodedLine) + { + if (!empty($sEncodedLine)) + { + $sDecodedLine = \base64_decode(\preg_replace('/[\s]+/', '', $sEncodedLine)); + if (!empty($sDecodedLine)) + { + $oItem = new \RainLoop\Providers\Filters\Classes\Filter(); + if ($oItem && $oItem->unserializeFromJson($sDecodedLine)) + { + $aResult[] = $oItem; + } + } + } + } + } + } + + return $aResult; + } + + /** + * @param string $sValue + * + * @return string + */ + public function quote($sValue) + { + return \str_replace(array('\\', '"'), array('\\\\', '\\"'), \trim($sValue)); + } + + /** + * @param \MailSo\Log\Logger $oLogger + */ + public function SetLogger($oLogger) + { + $this->oLogger = $oLogger instanceof \MailSo\Log\Logger ? $oLogger : null; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Settings.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Settings.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Settings.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Settings.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Settings/DefaultSettings.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Settings/DefaultSettings.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Settings/DefaultSettings.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Settings/DefaultSettings.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Settings/ISettings.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Settings/ISettings.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Settings/ISettings.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Settings/ISettings.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Storage.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Storage.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Storage.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Storage.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Storage/Enumerations/StorageType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Storage/Enumerations/StorageType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Storage/Enumerations/StorageType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Storage/Enumerations/StorageType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Storage/FileStorage.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Storage/FileStorage.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Storage/FileStorage.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Storage/FileStorage.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Storage/IStorage.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Storage/IStorage.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Storage/IStorage.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Storage/IStorage.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Storage/TemproryApcStorage.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Storage/TemproryApcStorage.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Storage/TemproryApcStorage.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Storage/TemproryApcStorage.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Suggestions.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Suggestions.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Suggestions.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Suggestions.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Suggestions/ISuggestions.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Suggestions/ISuggestions.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Suggestions/ISuggestions.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Suggestions/ISuggestions.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Suggestions/OwnCloudSuggestions.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Suggestions/OwnCloudSuggestions.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Suggestions/OwnCloudSuggestions.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Suggestions/OwnCloudSuggestions.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Suggestions/TestSuggestions.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Suggestions/TestSuggestions.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/Suggestions/TestSuggestions.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/Suggestions/TestSuggestions.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/TwoFactorAuth.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/TwoFactorAuth.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/TwoFactorAuth.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/TwoFactorAuth.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/TwoFactorAuth/AbstractTwoFactorAuth.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/TwoFactorAuth/AbstractTwoFactorAuth.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/TwoFactorAuth/AbstractTwoFactorAuth.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/TwoFactorAuth/AbstractTwoFactorAuth.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/TwoFactorAuth/GoogleTwoFactorAuth.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/TwoFactorAuth/GoogleTwoFactorAuth.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/TwoFactorAuth/GoogleTwoFactorAuth.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/TwoFactorAuth/GoogleTwoFactorAuth.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/TwoFactorAuth/TwoFactorAuthInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/TwoFactorAuth/TwoFactorAuthInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Providers/TwoFactorAuth/TwoFactorAuthInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Providers/TwoFactorAuth/TwoFactorAuthInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Service.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Service.php similarity index 87% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Service.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Service.php index fee85d11..a167e3ab 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Service.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Service.php @@ -1,328 +1,344 @@ -oHttp = \MailSo\Base\Http::SingletonInstance(); - $this->oActions = \RainLoop\Api::Actions(); - - $this->oServiceActions = new \RainLoop\ServiceActions($this->oHttp, $this->oActions); - - if ($this->oActions->Config()->Get('debug', 'enable', false)) - { - \error_reporting(E_ALL); - \ini_set('display_errors', 1); - } - - $sServer = \trim($this->oActions->Config()->Get('security', 'custom_server_signature', '')); - if (0 < \strlen($sServer)) - { - @\header('Server: '.$sServer, true); - } - - $sXFrameOptionsHeader = \trim($this->oActions->Config()->Get('security', 'x_frame_options_header', '')); - if (0 < \strlen($sXFrameOptionsHeader)) - { - @\header('X-Frame-Options: '.$sXFrameOptionsHeader, true); - } - - if ($this->oActions->Config()->Get('labs', 'force_https', false) && !$this->oHttp->IsSecure()) - { - @\header('Location: https://'.$this->oHttp->GetHost(false, false).$this->oHttp->GetUrl(), true); - exit(0); - } - - $this->localHandle(); - } - - /** - * @return bool - */ - public function RunResult() - { - return true; - } - - /** - * @staticvar bool $bOne - * @return bool - */ - public static function Handle() - { - static $bOne = null; - if (null === $bOne) - { - $oService = null; - if (\class_exists('MailSo\Version')) - { - $oService = new self(); - } - - $bOne = $oService->RunResult(); - } - - return $bOne; - } - - /** - * @return \RainLoop\Service - */ - private function localHandle() - { - if (!\class_exists('MailSo\Version')) - { - return $this; - } - - $this->oActions->BootStart(); - - $sResult = ''; - $bCached = false; - - $sQuery = $this->oActions->ParseQueryAuthString(); - - $this->oActions->Plugins()->RunHook('filter.http-query', array(&$sQuery)); - $aPaths = \explode('/', $sQuery); - $this->oActions->Plugins()->RunHook('filter.http-paths', array(&$aPaths)); - - $bAdmin = false; - $sAdminPanelHost = $this->oActions->Config()->Get('security', 'admin_panel_host', ''); - if (empty($sAdminPanelHost)) - { - $sAdminPanelKey = \strtolower($this->oActions->Config()->Get('security', 'admin_panel_key', 'admin')); - $bAdmin = !empty($aPaths[0]) && \strtolower($aPaths[0]) === $sAdminPanelKey; - } - else if (empty($aPaths[0]) && - \MailSo\Base\Utils::StrToLowerIfAscii($sAdminPanelHost) === \MailSo\Base\Utils::StrToLowerIfAscii($this->oHttp->GetHost())) - { - $bAdmin = true; - } - - if ($this->oHttp->IsPost()) - { - $this->oHttp->ServerNoCache(); - } - - if ($bAdmin && !$this->oActions->Config()->Get('security', 'allow_admin_panel', true)) - { - echo $this->oServiceActions->ErrorTemplates('Access Denied.', - 'Access to the RainLoop Webmail Admin Panel is not allowed!', true); - - return $this; - } - - $bIndex = true; - if (0 < \count($aPaths) && !empty($aPaths[0]) && !$bAdmin && 'index' !== \strtolower($aPaths[0])) - { - $bIndex = false; - $sMethodName = 'Service'.\preg_replace('/@.+$/', '', $aPaths[0]); - $sMethodExtra = 0 < \strpos($aPaths[0], '@') ? \preg_replace('/^[^@]+@/', '', $aPaths[0]) : ''; - - if (\method_exists($this->oServiceActions, $sMethodName) && - \is_callable(array($this->oServiceActions, $sMethodName))) - { - $this->oServiceActions->SetQuery($sQuery)->SetPaths($aPaths); - $sResult = \call_user_func(array($this->oServiceActions, $sMethodName), $sMethodExtra); - } - else if (!$this->oActions->Plugins()->RunAdditionalPart($aPaths[0], $aPaths)) - { - $bIndex = true; - } - } - - $bMobile = false; - $bMobileDevice = false; - - if ($this->oActions->Config()->Get('labs', 'allow_mobile_version', false)) - { - $bUseMobileVersionForTablets = $this->oActions->Config()->Get('labs', 'use_mobile_version_for_tablets', false); - - $oMobileDetect = new \Detection\MobileDetect(); - $bMobileDevice = $oMobileDetect->isMobile() && - ($bUseMobileVersionForTablets ? true : !$oMobileDetect->isTablet()); - - if ($bIndex) - { - $sMobileType = (string) \RainLoop\Utils::GetCookie(\RainLoop\Actions::RL_MOBILE_TYPE, ''); - switch ($sMobileType) { - default: - $sMobileType = ''; - $bMobile = $bMobileDevice; - break; - case 'mobile': - $bMobile = true; - break; - case 'desktop': - $bMobile = false; - break; - } - } - } - - if ($bIndex) - { - @\header('Content-Security-Policy:'); - @\header_remove('Content-Security-Policy'); - - @header('Content-Type: text/html; charset=utf-8'); - $this->oHttp->ServerNoCache(); - - if (!@\is_dir(APP_DATA_FOLDER_PATH) || !@\is_writable(APP_DATA_FOLDER_PATH)) - { - echo $this->oServiceActions->ErrorTemplates( - 'Permission denied!', - 'RainLoop Webmail cannot access to the data folder "'.APP_DATA_FOLDER_PATH.'"' - ); - - return $this; - } - - $aTemplateParameters = $this->indexTemplateParameters($bAdmin, $bMobile, $bMobileDevice); - - $sCacheFileName = ''; - if ($this->oActions->Config()->Get('labs', 'cache_system_data', true) && !empty($aTemplateParameters['{{BaseHash}}'])) - { - $sCacheFileName = 'TMPL:'.$aTemplateParameters['{{BaseHash}}']; - $sResult = $this->oActions->Cacher()->Get($sCacheFileName); - } - - if (0 === \strlen($sResult)) - { -// $aTemplateParameters['{{BaseTemplates}}'] = $this->oServiceActions->compileTemplates($bAdmin, false); - $sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Index.html'), $aTemplateParameters); - - $sResult = \RainLoop\Utils::ClearHtmlOutput($sResult); - if (0 < \strlen($sCacheFileName)) - { - $this->oActions->Cacher()->Set($sCacheFileName, $sResult); - } - } - else - { - $bCached = true; - } - - $sResult .= ''; - } - - // Output result - echo $sResult; - unset($sResult); - - $this->oActions->BootEnd(); - return $this; - } - - /** - * @param string $sPath - * - * @return string - */ - private function staticPath($sPath) - { - return $this->oActions->StaticPath($sPath); - } - - /** - * @param bool $bAdmin = false - * @param bool $bMobile = false - * @param bool $bMobileDevice = false - * - * @return array - */ - private function indexTemplateParameters($bAdmin = false, $bMobile = false, $bMobileDevice = false) - { - $sLanguage = 'en'; - $sTheme = 'Default'; - - list($sLanguage, $sTheme) = $this->oActions->GetLanguageAndTheme($bAdmin, $bMobile); - - $bAppJsDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_js', false); - $bAppCssDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_css', false); - - $sFaviconUrl = (string) $this->oActions->Config()->Get('webmail', 'favicon_url', ''); - - $sFaviconPngLink = $sFaviconUrl ? $sFaviconUrl : $this->staticPath('apple-touch-icon.png'); - $sAppleTouchLink = $sFaviconUrl ? '' : $this->staticPath('apple-touch-icon.png'); - - $sContentSecurityPolicy = $this->oActions->Config()->Get('security', 'content_security_policy', ''); - - $aTemplateParameters = array( - '{{BaseAppFaviconPngLinkTag}}' => $sFaviconPngLink ? '' : '', - '{{BaseAppFaviconTouchLinkTag}}' => $sAppleTouchLink ? '' : '', - '{{BaseAppMainCssLink}}' => $this->staticPath('css/app'.($bAppCssDebug ? '' : '.min').'.css'), - '{{BaseAppThemeCssLink}}' => $this->oActions->ThemeLink($sTheme, $bAdmin), - '{{BaseAppBootScriptLink}}' => $this->staticPath('js/'.($bAppJsDebug ? '' : 'min/').'boot'.($bAppJsDebug ? '' : '.min').'.js'), - '{{BaseViewport}}' => $bMobile ? 'width=device-width,initial-scale=1,user-scalable=no' : 'width=950,maximum-scale=2', - '{{BaseContentSecurityPolicy}}' => $sContentSecurityPolicy ? - '' : '', - '{{BaseDir}}' => false && \in_array($sLanguage, array('ar', 'he', 'ur')) ? 'rtl' : 'ltr', - '{{BaseAppManifestLink}}' => $this->staticPath('manifest.json') - ); - - $aTemplateParameters['{{RainloopBootData}}'] = \json_encode(array( - 'admin' => $bAdmin, - 'language' => $sLanguage, - 'theme' => $sTheme, - 'mobile' => $bMobile, - 'mobileDevice' => $bMobileDevice - )); - - $aTemplateParameters['{{BaseHash}}'] = \md5( - \implode('~', array( - $bAdmin ? '1' : '0', - \md5($this->oActions->Config()->Get('cache', 'index', '')), - $this->oActions->Plugins()->Hash(), - \RainLoop\Utils::WebVersionPath(), - APP_VERSION, - )). - \implode('~', $aTemplateParameters) - ); - - return $aTemplateParameters; - } -} +oHttp = \MailSo\Base\Http::SingletonInstance(); + $this->oActions = \RainLoop\Api::Actions(); + + $this->oServiceActions = new \RainLoop\ServiceActions($this->oHttp, $this->oActions); + + if ($this->oActions->Config()->Get('debug', 'enable', false)) + { + \error_reporting(E_ALL); + \ini_set('display_errors', 1); + } + + $sServer = \trim($this->oActions->Config()->Get('security', 'custom_server_signature', '')); + if (0 < \strlen($sServer)) + { + @\header('Server: '.$sServer, true); + } + + $sXFrameOptionsHeader = \trim($this->oActions->Config()->Get('security', 'x_frame_options_header', '')); + if (0 < \strlen($sXFrameOptionsHeader)) + { + @\header('X-Frame-Options: '.$sXFrameOptionsHeader, true); + } + + $sXssProtectionOptionsHeader = \trim($this->oActions->Config()->Get('security', 'x_xss_protection_header', '')); + if (0 < \strlen($sXssProtectionOptionsHeader)) + { + @\header('X-XSS-Protection: '.$sXssProtectionOptionsHeader, true); + } + + if ($this->oActions->Config()->Get('labs', 'force_https', false) && !$this->oHttp->IsSecure()) + { + @\header('Location: https://'.$this->oHttp->GetHost(false, false).$this->oHttp->GetUrl(), true); + exit(0); + } + + $this->localHandle(); + } + + /** + * @return bool + */ + public function RunResult() + { + return true; + } + + /** + * @staticvar bool $bOne + * @return bool + */ + public static function Handle() + { + static $bOne = null; + if (null === $bOne) + { + $oService = null; + if (\class_exists('MailSo\Version')) + { + $oService = new self(); + } + + $bOne = $oService->RunResult(); + } + + return $bOne; + } + + /** + * @return \RainLoop\Service + */ + private function localHandle() + { + if (!\class_exists('MailSo\Version')) + { + return $this; + } + + $this->oActions->BootStart(); + + $sResult = ''; + $bCached = false; + + $sQuery = $this->oActions->ParseQueryAuthString(); + + $this->oActions->Plugins()->RunHook('filter.http-query', array(&$sQuery)); + $aPaths = \explode('/', $sQuery); + $this->oActions->Plugins()->RunHook('filter.http-paths', array(&$aPaths)); + + $bAdmin = false; + $sAdminPanelHost = $this->oActions->Config()->Get('security', 'admin_panel_host', ''); + if (empty($sAdminPanelHost)) + { + $sAdminPanelKey = \strtolower($this->oActions->Config()->Get('security', 'admin_panel_key', 'admin')); + $bAdmin = !empty($aPaths[0]) && \strtolower($aPaths[0]) === $sAdminPanelKey; + } + else if (empty($aPaths[0]) && + \MailSo\Base\Utils::StrToLowerIfAscii($sAdminPanelHost) === \MailSo\Base\Utils::StrToLowerIfAscii($this->oHttp->GetHost())) + { + $bAdmin = true; + } + + if ($this->oHttp->IsPost()) + { + $this->oHttp->ServerNoCache(); + } + + if ($bAdmin && !$this->oActions->Config()->Get('security', 'allow_admin_panel', true)) + { + echo $this->oServiceActions->ErrorTemplates('Access Denied.', + 'Access to the RainLoop Webmail Admin Panel is not allowed!', true); + + return $this; + } + + $bIndex = true; + if (0 < \count($aPaths) && !empty($aPaths[0]) && !$bAdmin && 'index' !== \strtolower($aPaths[0])) + { + $bIndex = false; + $sMethodName = 'Service'.\preg_replace('/@.+$/', '', $aPaths[0]); + $sMethodExtra = 0 < \strpos($aPaths[0], '@') ? \preg_replace('/^[^@]+@/', '', $aPaths[0]) : ''; + + if (\method_exists($this->oServiceActions, $sMethodName) && + \is_callable(array($this->oServiceActions, $sMethodName))) + { + $this->oServiceActions->SetQuery($sQuery)->SetPaths($aPaths); + $sResult = \call_user_func(array($this->oServiceActions, $sMethodName), $sMethodExtra); + } + else if (!$this->oActions->Plugins()->RunAdditionalPart($aPaths[0], $aPaths)) + { + $bIndex = true; + } + } + + $bMobile = false; + $bMobileDevice = false; + + if ($this->oActions->Config()->Get('labs', 'allow_mobile_version', false)) + { + $bUseMobileVersionForTablets = $this->oActions->Config()->Get('labs', 'use_mobile_version_for_tablets', false); + + $oMobileDetect = new \Detection\MobileDetect(); + $bMobileDevice = $oMobileDetect->isMobile() && + ($bUseMobileVersionForTablets ? true : !$oMobileDetect->isTablet()); + + if ($bIndex) + { + $sMobileType = (string) \RainLoop\Utils::GetCookie(\RainLoop\Actions::RL_MOBILE_TYPE, ''); + switch ($sMobileType) { + default: + $sMobileType = ''; + $bMobile = $bMobileDevice; + break; + case 'mobile': + $bMobile = true; + break; + case 'desktop': + $bMobile = false; + break; + } + } + } + + if ($bIndex) + { + @\header('Content-Security-Policy:'); + @\header_remove('Content-Security-Policy'); + + @header('Content-Type: text/html; charset=utf-8'); + $this->oHttp->ServerNoCache(); + + if (!@\is_dir(APP_DATA_FOLDER_PATH) || !@\is_writable(APP_DATA_FOLDER_PATH)) + { + echo $this->oServiceActions->ErrorTemplates( + 'Permission denied!', + 'RainLoop Webmail cannot access to the data folder "'.APP_DATA_FOLDER_PATH.'"' + ); + + return $this; + } + + $aTemplateParameters = $this->indexTemplateParameters($bAdmin, $bMobile, $bMobileDevice); + + $sCacheFileName = ''; + if ($this->oActions->Config()->Get('labs', 'cache_system_data', true) && !empty($aTemplateParameters['{{BaseHash}}'])) + { + $sCacheFileName = 'TMPL:'.$aTemplateParameters['{{BaseHash}}']; + $sResult = $this->oActions->Cacher()->Get($sCacheFileName); + } + + if (0 === \strlen($sResult)) + { +// $aTemplateParameters['{{BaseTemplates}}'] = $this->oServiceActions->compileTemplates($bAdmin, false); + $sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Index.html'), $aTemplateParameters); + + $sResult = \RainLoop\Utils::ClearHtmlOutput($sResult); + if (0 < \strlen($sCacheFileName)) + { + $this->oActions->Cacher()->Set($sCacheFileName, $sResult); + } + } + else + { + $bCached = true; + } + + $sResult .= ''; + } + else + { + @\header('X-XSS-Protection: 1; mode=block'); + } + + // Output result + echo $sResult; + unset($sResult); + + $this->oActions->BootEnd(); + return $this; + } + + /** + * @param string $sPath + * + * @return string + */ + private function staticPath($sPath) + { + return $this->oActions->StaticPath($sPath); + } + + /** + * @param bool $bAdmin = false + * @param bool $bMobile = false + * @param bool $bMobileDevice = false + * + * @return array + */ + private function indexTemplateParameters($bAdmin = false, $bMobile = false, $bMobileDevice = false) + { + $sLanguage = 'en'; + $sTheme = 'Default'; + + list($sLanguage, $sTheme) = $this->oActions->GetLanguageAndTheme($bAdmin, $bMobile); + + $bAppJsDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_js', false); + $bAppCssDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_css', false); + + $sFaviconUrl = (string) $this->oActions->Config()->Get('webmail', 'favicon_url', ''); + + $sFaviconPngLink = $sFaviconUrl ? $sFaviconUrl : $this->staticPath('apple-touch-icon.png'); + $sAppleTouchLink = $sFaviconUrl ? '' : $this->staticPath('apple-touch-icon.png'); + + $sContentSecurityPolicy = $this->oActions->Config()->Get('security', 'content_security_policy', ''); + $sSentryDsn = $this->oActions->Config()->Get('logs', 'sentry_dsn', ''); + + $aTemplateParameters = array( + '{{BaseAppHeadScriptLink}}' => $sSentryDsn ? + '' : '', + '{{BaseAppBodyScript}}' => $sSentryDsn ? + '' : '', + '{{BaseAppFaviconPngLinkTag}}' => $sFaviconPngLink ? '' : '', + '{{BaseAppFaviconTouchLinkTag}}' => $sAppleTouchLink ? '' : '', + '{{BaseAppMainCssLink}}' => $this->staticPath('css/app'.($bAppCssDebug ? '' : '.min').'.css'), + '{{BaseAppThemeCssLink}}' => $this->oActions->ThemeLink($sTheme, $bAdmin), + '{{BaseAppPolyfillsScriptLink}}' => $this->staticPath('js/'.($bAppJsDebug ? '' : 'min/').'polyfills'.($bAppJsDebug ? '' : '.min').'.js'), + '{{BaseAppBootScriptLink}}' => $this->staticPath('js/'.($bAppJsDebug ? '' : 'min/').'boot'.($bAppJsDebug ? '' : '.min').'.js'), + '{{BaseViewport}}' => $bMobile ? 'width=device-width,initial-scale=1,user-scalable=no' : 'width=950,maximum-scale=2', + '{{BaseContentSecurityPolicy}}' => $sContentSecurityPolicy ? + '' : '', + '{{BaseDir}}' => false && \in_array($sLanguage, array('ar', 'he', 'ur')) ? 'rtl' : 'ltr', + '{{BaseAppManifestLink}}' => $this->staticPath('manifest.json') + ); + + $aTemplateParameters['{{RainloopBootData}}'] = \json_encode(array( + 'admin' => $bAdmin, + 'language' => $sLanguage, + 'theme' => $sTheme, + 'mobile' => $bMobile, + 'mobileDevice' => $bMobileDevice + )); + + $aTemplateParameters['{{BaseHash}}'] = \md5( + \implode('~', array( + $bAdmin ? '1' : '0', + \md5($this->oActions->Config()->Get('cache', 'index', '')), + $this->oActions->Plugins()->Hash(), + \RainLoop\Utils::WebVersionPath(), + APP_VERSION, + )). + \implode('~', $aTemplateParameters) + ); + + return $aTemplateParameters; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/ServiceActions.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/ServiceActions.php similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/ServiceActions.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/ServiceActions.php index 3dcdcd61..711b95dc 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/ServiceActions.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/ServiceActions.php @@ -1,1389 +1,1390 @@ -oHttp = $oHttp; - $this->oActions = $oActions; - $this->aPaths = array(); - $this->sQuery = ''; - } - - /** - * @return \MailSo\Log\Logger - */ - public function Logger() - { - return $this->oActions->Logger(); - } - - /** - * @return \RainLoop\Plugins\Manager - */ - public function Plugins() - { - return $this->oActions->Plugins(); - } - - /** - * @return \RainLoop\Application - */ - public function Config() - { - return $this->oActions->Config(); - } - - /** - * @return \MailSo\Cache\CacheClient - */ - public function Cacher() - { - return $this->oActions->Cacher(); - } - - /** - * @return \RainLoop\Providers\Storage - */ - public function StorageProvider() - { - return $this->oActions->StorageProvider(); - } - - /** - * @return \RainLoop\Providers\Settings - */ - public function SettingsProvider() - { - return $this->oActions->SettingsProvider(); - } - - /** - * @param array $aPaths - * - * @return \RainLoop\ServiceActions - */ - public function SetPaths($aPaths) - { - $this->aPaths = \is_array($aPaths) ? $aPaths : array(); - return $this; - } - - /** - * @param string $sQuery - * - * @return \RainLoop\ServiceActions - */ - public function SetQuery($sQuery) - { - $this->sQuery = $sQuery; - return $this; - } - - /** - * @return string - */ - public function ServiceAjax() - { - @\ob_start(); - - $aResponseItem = null; - $oException = null; - - $sAction = $this->oHttp->GetPost('Action', null); - if (empty($sAction) && $this->oHttp->IsGet() && !empty($this->aPaths[2])) - { - $sAction = $this->aPaths[2]; - } - - try - { - if ($this->oHttp->IsPost() && !in_array($sAction, array('JsInfo', 'JsError')) && - $this->Config()->Get('security', 'csrf_protection', false) && - $this->oHttp->GetPost('XToken', '') !== \RainLoop\Utils::GetCsrfToken()) - { - throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidToken); - } - else if (!empty($sAction)) - { - $sMethodName = 'Do'.$sAction; - - $this->Logger()->Write('Action: '.$sMethodName, \MailSo\Log\Enumerations\Type::NOTE, 'AJAX'); - - $aPost = $this->oHttp->GetPostAsArray(); - if (\is_array($aPost) && 0 < \count($aPost)) - { - $this->oActions->SetActionParams($aPost, $sMethodName); - switch ($sMethodName) - { - case 'DoLogin': - case 'DoAdminLogin': - case 'DoAccountAdd': - $this->Logger()->AddSecret($this->oActions->GetActionParam('Password', '')); - break; - case 'DoChangePassword': - $this->Logger()->AddSecret($this->oActions->GetActionParam('PrevPassword', '')); - $this->Logger()->AddSecret($this->oActions->GetActionParam('NewPassword', '')); - break; - } - - $this->Logger()->Write(\MailSo\Base\Utils::Php2js($aPost, $this->Logger()), - \MailSo\Log\Enumerations\Type::INFO, 'POST', true); - } - else if (3 < \count($this->aPaths) && $this->oHttp->IsGet()) - { - $this->oActions->SetActionParams(array( - 'RawKey' => empty($this->aPaths[3]) ? '' : $this->aPaths[3] - ), $sMethodName); - } - - if (\method_exists($this->oActions, $sMethodName) && - \is_callable(array($this->oActions, $sMethodName))) - { - $this->Plugins()->RunHook('ajax.action-pre-call', array($sAction)); - $aResponseItem = \call_user_func(array($this->oActions, $sMethodName)); - $this->Plugins()->RunHook('ajax.action-post-call', array($sAction, &$aResponseItem)); - } - else if ($this->Plugins()->HasAdditionalAjax($sMethodName)) - { - $this->Plugins()->RunHook('ajax.action-pre-call', array($sAction)); - $aResponseItem = $this->Plugins()->RunAdditionalAjax($sMethodName); - $this->Plugins()->RunHook('ajax.action-post-call', array($sAction, &$aResponseItem)); - } - } - - if (!\is_array($aResponseItem)) - { - throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError); - } - } - catch (\Exception $oException) - { - $aResponseItem = $this->oActions->ExceptionResponse( - empty($sAction) ? 'Unknown' : $sAction, $oException); - - if (\is_array($aResponseItem) && $oException instanceof \RainLoop\Exceptions\ClientException) - { - if ('Folders' === $sAction) - { - $aResponseItem['ClearAuth'] = true; - } - - if ($oException->getLogoutOnException()) - { - $aResponseItem['Logout'] = true; - if ($oException->getAdditionalMessage()) - { - $this->oActions->SetSpecLogoutCustomMgsWithDeletion($oException->getAdditionalMessage()); - } - } - } - } - - if (\is_array($aResponseItem)) - { - $aResponseItem['Time'] = (int) ((\microtime(true) - APP_START) * 1000); - } - - $this->Plugins()->RunHook('filter.ajax-response', array($sAction, &$aResponseItem)); - - @\header('Content-Type: application/json; charset=utf-8'); - - $sResult = \MailSo\Base\Utils::Php2js($aResponseItem, $this->Logger()); - - $sObResult = @\ob_get_clean(); - - if ($this->Logger()->IsEnabled()) - { - if (0 < \strlen($sObResult)) - { - $this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA'); - } - - if ($oException) - { - $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); - } - - $iLimit = (int) $this->Config()->Get('labs', 'log_ajax_response_write_limit', 0); - $this->Logger()->Write(0 < $iLimit && $iLimit < \strlen($sResult) - ? \substr($sResult, 0, $iLimit).'...' : $sResult, \MailSo\Log\Enumerations\Type::INFO, 'AJAX'); - } - - return $sResult; - } - - /** - * @return string - */ - public function ServiceOwnCloudAuth() - { - $this->oHttp->ServerNoCache(); - - if (!\RainLoop\Utils::IsOwnCloud() || - !isset($_ENV['___rainloop_owncloud_email']) || - !isset($_ENV['___rainloop_owncloud_password']) || - empty($_ENV['___rainloop_owncloud_email']) - ) - { - $this->oActions->SetAuthLogoutToken(); - $this->oActions->Location('./'); - return ''; - } - - $bLogout = true; - - $sEmail = $_ENV['___rainloop_owncloud_email']; - $sPassword = $_ENV['___rainloop_owncloud_password']; - - try - { - $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); - $this->oActions->AuthToken($oAccount); - - $bLogout = !($oAccount instanceof \RainLoop\Model\Account); - } - catch (\Exception $oException) - { - $this->oActions->Logger()->WriteException($oException); - } - - if ($bLogout) - { - $this->oActions->SetAuthLogoutToken(); - } - - $this->oActions->Location('./'); - return ''; - } - - /** - * @return string - */ - public function ServiceAppend() - { - @\ob_start(); - $bResponse = false; - $oException = null; - try - { - if (\method_exists($this->oActions, 'Append') && - \is_callable(array($this->oActions, 'Append'))) - { - $this->oActions->SetActionParams($this->oHttp->GetPostAsArray(), 'Append'); - $bResponse = \call_user_func(array($this->oActions, 'Append')); - } - } - catch (\Exception $oException) - { - $bResponse = false; - } - - @\header('Content-Type: text/plain; charset=utf-8'); - $sResult = true === $bResponse ? '1' : '0'; - - $sObResult = @\ob_get_clean(); - if (0 < \strlen($sObResult)) - { - $this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA'); - } - - if ($oException) - { - $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); - } - - $this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'APPEND'); - - return $sResult; - } - - /** - * @param string $sAction - * @param int $iSizeLimit = 0 - * - * @return string - */ - private function privateUpload($sAction, $iSizeLimit = 0) - { - $oConfig = $this->Config(); - - @\ob_start(); - $aResponseItem = null; - try - { - $aFile = null; - $sInputName = 'uploader'; - $iError = \RainLoop\Enumerations\UploadError::UNKNOWN; - $iSizeLimit = (0 < $iSizeLimit ? $iSizeLimit : ((int) $oConfig->Get('webmail', 'attachment_size_limit', 0))) * 1024 * 1024; - - $iError = UPLOAD_ERR_OK; - $_FILES = isset($_FILES) ? $_FILES : null; - if (isset($_FILES, $_FILES[$sInputName], $_FILES[$sInputName]['name'], $_FILES[$sInputName]['tmp_name'], $_FILES[$sInputName]['size'])) - { - $iError = (isset($_FILES[$sInputName]['error'])) ? (int) $_FILES[$sInputName]['error'] : UPLOAD_ERR_OK; - - if (UPLOAD_ERR_OK === $iError && 0 < $iSizeLimit && $iSizeLimit < (int) $_FILES[$sInputName]['size']) - { - $iError = \RainLoop\Enumerations\UploadError::CONFIG_SIZE; - } - - if (UPLOAD_ERR_OK === $iError) - { - $aFile = $_FILES[$sInputName]; - } - } - else if (!isset($_FILES) || !is_array($_FILES) || 0 === count($_FILES)) - { - $iError = UPLOAD_ERR_INI_SIZE; - } - else - { - $iError = \RainLoop\Enumerations\UploadError::EMPTY_FILES_DATA; - } - - if (\method_exists($this->oActions, $sAction) && - \is_callable(array($this->oActions, $sAction))) - { - $aActionParams = $this->oHttp->GetQueryAsArray(); - - $aActionParams['File'] = $aFile; - $aActionParams['Error'] = $iError; - - $this->oActions->SetActionParams($aActionParams, $sAction); - - $aResponseItem = \call_user_func(array($this->oActions, $sAction)); - } - - if (!is_array($aResponseItem)) - { - throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError); - } - } - catch (\Exception $oException) - { - $aResponseItem = $this->oActions->ExceptionResponse($sAction, $oException); - } - - if ('iframe' === $this->oHttp->GetPost('jua-post-type', '')) - { - @\header('Content-Type: text/html; charset=utf-8'); - } - else - { - @\header('Content-Type: application/json; charset=utf-8'); - } - - $this->Plugins()->RunHook('filter.upload-response', array(&$aResponseItem)); - $sResult = \MailSo\Base\Utils::Php2js($aResponseItem, $this->Logger()); - - $sObResult = @\ob_get_clean(); - if (0 < \strlen($sObResult)) - { - $this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA'); - } - - $this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'UPLOAD'); - - return $sResult; - } - - /** - * @return string - */ - public function ServiceUpload() - { - return $this->privateUpload('Upload'); - } - - /** - * @return string - */ - public function ServiceUploadContacts() - { - return $this->privateUpload('UploadContacts', 5); - } - - /** - * @return string - */ - public function ServiceUploadBackground() - { - return $this->privateUpload('UploadBackground', 1); - } - - /** - * @return string - */ - public function ServiceProxyExternal() - { - $bResult = false; - $sData = empty($this->aPaths[1]) ? '' : $this->aPaths[1]; - if (!empty($sData) && $this->oActions->Config()->Get('labs', 'use_local_proxy_for_external_images', false)) - { - $this->oActions->verifyCacheByKey($sData); - - $aData = \RainLoop\Utils::DecodeKeyValuesQ($sData); - if (\is_array($aData) && !empty($aData['Token']) && !empty($aData['Url']) && $aData['Token'] === \RainLoop\Utils::GetConnectionToken()) - { - $iCode = 404; - $sContentType = ''; - $mResult = $this->oHttp->GetUrlAsString($aData['Url'], 'RainLoop External Proxy', $sContentType, $iCode); - - if (false !== $mResult && 200 === $iCode && - \in_array($sContentType, array('image/png', 'image/jpeg', 'image/jpg', 'image/bmp', 'image/gif'))) - { - $bResult = true; - - $this->oActions->cacheByKey($sData); - - \header('Content-Type: '.$sContentType); - echo $mResult; - } - } - } - - if (!$bResult) - { - $this->oHttp->StatusHeader(404); - } - - return ''; - } - - /** - * @return string - */ - public function ServiceRaw() - { - $sResult = ''; - $sRawError = ''; - $sAction = empty($this->aPaths[2]) ? '' : $this->aPaths[2]; - $oException = null; - - try - { - $sRawError = 'Invalid action'; - if (0 !== \strlen($sAction)) - { - $sMethodName = 'Raw'.$sAction; - if (\method_exists($this->oActions, $sMethodName)) - { - @\header('X-Raw-Action: '.$sMethodName, true); - - $sRawError = ''; - $this->oActions->SetActionParams(array( - 'RawKey' => empty($this->aPaths[3]) ? '' : $this->aPaths[3], - 'Params' => $this->aPaths - ), $sMethodName); - - if (!\call_user_func(array($this->oActions, $sMethodName))) - { - $sRawError = 'False result'; - } - else - { - $sRawError = ''; - } - } - else - { - $sRawError = 'Unknown action "'.$sAction.'"'; - } - } - else - { - $sRawError = 'Empty action'; - } - } - catch (\RainLoop\Exceptions\ClientException $oException) - { - $sRawError = 'Exception as result'; - switch ($oException->getCode()) - { - case \RainLoop\Notifications::AuthError: - $sRawError = 'Authentication failed'; - break; - } - } - catch (\Exception $oException) - { - $sRawError = 'Exception as result'; - } - - if (0 < \strlen($sRawError)) - { - $this->oActions->Logger()->Write($sRawError, \MailSo\Log\Enumerations\Type::ERROR); - $this->oActions->Logger()->WriteDump($this->aPaths, \MailSo\Log\Enumerations\Type::ERROR, 'PATHS'); - } - - if ($oException) - { - $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR, 'RAW'); - } - - return $sResult; - } - - /** - * @return string - */ - public function ServiceLang() - { -// sleep(2); - $sResult = ''; - @\header('Content-Type: application/javascript; charset=utf-8'); - - if (!empty($this->aPaths[3])) - { - $bAdmim = 'Admin' === (isset($this->aPaths[2]) ? (string) $this->aPaths[2] : 'App'); - $sLanguage = $this->oActions->ValidateLanguage($this->aPaths[3], '', $bAdmim); - - $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true); - if (!empty($sLanguage) && $bCacheEnabled) - { - $this->oActions->verifyCacheByKey($this->sQuery); - } - - $sCacheFileName = ''; - if ($bCacheEnabled) - { - $sCacheFileName = \RainLoop\KeyPathHelper::LangCache( - $sLanguage, $bAdmim, $this->oActions->Plugins()->Hash()); - - $sResult = $this->Cacher()->Get($sCacheFileName); - } - - if (0 === \strlen($sResult)) - { - $sResult = $this->compileLanguage($sLanguage, $bAdmim, false); - if ($bCacheEnabled && 0 < \strlen($sCacheFileName)) - { - $this->Cacher()->Set($sCacheFileName, $sResult); - } - } - - if ($bCacheEnabled) - { - $this->oActions->cacheByKey($this->sQuery); - } - } - - return $sResult; - } - - /** - * @return string - */ - public function ServiceTemplates() - { - $sResult = ''; - @\header('Content-Type: application/javascript; charset=utf-8'); - - $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true); - if ($bCacheEnabled) - { - $this->oActions->verifyCacheByKey($this->sQuery); - } - - $bAdmin = false !== \strpos($this->sQuery, 'Admin'); - - $sCacheFileName = ''; - if ($bCacheEnabled) - { - $sCacheFileName = \RainLoop\KeyPathHelper::TemplatesCache($bAdmin, $this->oActions->Plugins()->Hash()); - $sResult = $this->Cacher()->Get($sCacheFileName); - } - - if (0 === \strlen($sResult)) - { - $sResult = $this->compileTemplates($bAdmin); - if ($bCacheEnabled && 0 < \strlen($sCacheFileName)) - { - $this->Cacher()->Set($sCacheFileName, $sResult); - } - } - - if ($bCacheEnabled) - { - $this->oActions->cacheByKey($this->sQuery); - } - - return $sResult; - } - - /** - * @return string - */ - public function ServicePlugins() - { - $sResult = ''; - $bAdmin = !empty($this->aPaths[2]) && 'Admin' === $this->aPaths[2]; - - @\header('Content-Type: application/javascript; charset=utf-8'); - - $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true); - if ($bCacheEnabled) - { - $this->oActions->verifyCacheByKey($this->sQuery); - } - - $sCacheFileName = ''; - if ($bCacheEnabled) - { - $sCacheFileName = \RainLoop\KeyPathHelper::PluginsJsCache($this->oActions->Plugins()->Hash()); - $sResult = $this->Cacher()->Get($sCacheFileName); - } - - if (0 === strlen($sResult)) - { - $sResult = $this->Plugins()->CompileJs($bAdmin); - if ($bCacheEnabled && 0 < \strlen($sCacheFileName)) - { - $this->Cacher()->Set($sCacheFileName, $sResult); - } - } - - if ($bCacheEnabled) - { - $this->oActions->cacheByKey($this->sQuery); - } - - return $sResult; - } - - /** - * @return string - */ - public function ServiceCss() - { - $sResult = ''; - - $bAdmin = !empty($this->aPaths[2]) && 'Admin' === $this->aPaths[2]; - $bJson = !empty($this->aPaths[9]) && 'Json' === $this->aPaths[9]; - - if ($bJson) - { - @\header('Content-Type: application/json; charset=utf-8'); - } - else - { - @\header('Content-Type: text/css; charset=utf-8'); - } - - $sTheme = ''; - if (!empty($this->aPaths[4])) - { - $sTheme = $this->oActions->ValidateTheme($this->aPaths[4]); - $sRealTheme = $sTheme; - - $bCustomTheme = '@custom' === \substr($sTheme, -7); - if ($bCustomTheme) - { - $sRealTheme = \substr($sTheme, 0, -7); - } - - $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true); - if ($bCacheEnabled) - { - $this->oActions->verifyCacheByKey($this->sQuery); - } - - $sCacheFileName = ''; - if ($bCacheEnabled) - { - $sCacheFileName = \RainLoop\KeyPathHelper::CssCache($sTheme, $this->oActions->Plugins()->Hash()); - $sResult = $this->Cacher()->Get($sCacheFileName); - } - - if (0 === \strlen($sResult)) - { - try - { - include_once APP_VERSION_ROOT_PATH.'app/libraries/lessphp/ctype.php'; - include_once APP_VERSION_ROOT_PATH.'app/libraries/lessphp/lessc.inc.php'; - - $oLess = new \RainLoopVendor\lessc(); - $oLess->setFormatter('compressed'); - - $aResult = array(); - - $sThemeFile = ($bCustomTheme ? APP_INDEX_ROOT_PATH : APP_VERSION_ROOT_PATH).'themes/'.$sRealTheme.'/styles.less'; - $sThemeExtFile = ($bCustomTheme ? APP_INDEX_ROOT_PATH : APP_VERSION_ROOT_PATH).'themes/'.$sRealTheme.'/ext.less'; - - $sThemeValuesFile = APP_VERSION_ROOT_PATH.'app/templates/Themes/values.less'; - $sThemeTemplateFile = APP_VERSION_ROOT_PATH.'app/templates/Themes/template.less'; - - if (\file_exists($sThemeFile) && \file_exists($sThemeTemplateFile) && \file_exists($sThemeValuesFile)) - { - $aResult[] = '@base: "'. - ($bCustomTheme ? \RainLoop\Utils::WebPath() : \RainLoop\Utils::WebVersionPath()). - 'themes/'.$sRealTheme.'/";'; - - $aResult[] = \file_get_contents($sThemeValuesFile); - $aResult[] = \file_get_contents($sThemeFile); - $aResult[] = \file_get_contents($sThemeTemplateFile); - - if (\file_exists($sThemeExtFile)) - { - $aResult[] = \file_get_contents($sThemeExtFile); - } - } - - $aResult[] = $this->Plugins()->CompileCss($bAdmin); - - $sResult = $oLess->compile(\implode("\n", $aResult)); - - if ($bCacheEnabled) - { - if (0 < \strlen($sCacheFileName)) - { - $this->Cacher()->Set($sCacheFileName, $sResult); - } - } - } - catch (\Exception $oException) - { - $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR, 'LESS'); - } - } - - if ($bCacheEnabled) - { - $this->oActions->cacheByKey($this->sQuery); - } - } - - return $bJson ? \MailSo\Base\Utils::Php2js(array($sTheme, $sResult), $this->Logger()) : $sResult; - } - - /** - * @return string - */ - public function ServiceSocialGoogle() - { - $bXAuth = '1' === (string) $this->oHttp->GetQuery('xauth', '0'); - return $this->oActions->Social()->GooglePopupService($bXAuth); - } - - /** - * @return string - */ - public function ServiceSocialFacebook() - { - return $this->oActions->Social()->FacebookPopupService(); - } - - /** - * @return string - */ - public function ServiceSocialTwitter() - { - return $this->oActions->Social()->TwitterPopupService(); - } - - /** - * @return string - */ - public function ServiceAppData($sAdd = '') - { - return $this->localAppData(false, $sAdd); - } - - /** - * @return string - */ - public function ServiceAdminAppData($sAdd = '') - { - return $this->localAppData(true, $sAdd); - } - - /** - * @return string - */ - public function ServiceMobileVersion() - { - \RainLoop\Utils::SetCookie(\RainLoop\Actions::RL_MOBILE_TYPE, 'mobile'); - $this->oActions->Location('./'); - return ''; - } - - /** - * @return string - */ - public function ServiceDesktopVersion() - { - \RainLoop\Utils::SetCookie(\RainLoop\Actions::RL_MOBILE_TYPE, 'desktop'); - $this->oActions->Location('./'); - return ''; - } - - /** - * @return string - */ - public function ServiceNoScript() - { - return $this->localError($this->oActions->StaticI18N('STATIC/NO_SCRIPT_TITLE'), $this->oActions->StaticI18N('STATIC/NO_SCRIPT_DESC')); - } - - /** - * @return string - */ - public function ServiceNoCookie() - { - return $this->localError($this->oActions->StaticI18N('STATIC/NO_COOKIE_TITLE'), $this->oActions->StaticI18N('STATIC/NO_COOKIE_DESC')); - } - - /** - * @return string - */ - public function ServiceBadBrowser() - { - $sTitle = $this->oActions->StaticI18N('STATIC/BAD_BROWSER_TITLE'); - $sDesc = \nl2br($this->oActions->StaticI18N('STATIC/BAD_BROWSER_DESC')); - - @\header('Content-Type: text/html; charset=utf-8'); - return \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/BadBrowser.html'), array( - '{{BaseWebStaticPath}}' => \RainLoop\Utils::WebStaticPath(), - '{{ErrorTitle}}' => $sTitle, - '{{ErrorHeader}}' => $sTitle, - '{{ErrorDesc}}' => $sDesc - )); - } - - /** - * @return string - */ - public function ServiceMailto() - { - $this->oHttp->ServerNoCache(); - - $sTo = \trim($this->oHttp->GetQuery('to', '')); - if (!empty($sTo) && \preg_match('/^mailto:/i', $sTo)) - { - $oAccount = $this->oActions->GetAccountFromSignMeToken(); - if ($oAccount) - { - $this->oActions->SetMailtoRequest($sTo); - } - } - - $this->oActions->Location('./'); - return ''; - } - - /** - * @return string - */ - public function ServicePing() - { - $this->oHttp->ServerNoCache(); - - @\header('Content-Type: text/plain; charset=utf-8'); - $this->oActions->Logger()->Write('Pong', \MailSo\Log\Enumerations\Type::INFO, 'PING'); - return 'Pong'; - } - - /** - * @return string - */ - public function ServiceInfo() - { - $this->oHttp->ServerNoCache(); - - if ($this->oActions->IsAdminLoggined(false)) - { - @\header('Content-Type: text/html; charset=utf-8'); - \phpinfo(); - } - } - - /** - * @return string - */ - public function ServiceSso() - { - $this->oHttp->ServerNoCache(); - - $oException = null; - $oAccount = null; - $bLogout = true; - - $sSsoHash = $this->oHttp->GetRequest('hash', ''); - if (!empty($sSsoHash)) - { - $mData = null; - - $sSsoSubData = $this->Cacher()->Get(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash)); - if (!empty($sSsoSubData)) - { - $mData = \RainLoop\Utils::DecodeKeyValuesQ($sSsoSubData); - $this->Cacher()->Delete(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash)); - - if (\is_array($mData) && !empty($mData['Email']) && isset($mData['Password'], $mData['Time']) && - (0 === $mData['Time'] || \time() - 10 < $mData['Time'])) - { - $sEmail = \trim($mData['Email']); - $sPassword = $mData['Password']; - - $aAdditionalOptions = isset($mData['AdditionalOptions']) && \is_array($mData['AdditionalOptions']) && - 0 < \count($mData['AdditionalOptions']) ? $mData['AdditionalOptions'] : null; - - try - { - $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); - - if ($oAccount instanceof \RainLoop\Model\Account && $aAdditionalOptions) - { - $bNeedToSettings = false; - - $oSettings = $this->SettingsProvider()->Load($oAccount); - if ($oSettings) - { - $sLanguage = isset($aAdditionalOptions['Language']) ? - $aAdditionalOptions['Language'] : ''; - - if ($sLanguage) - { - $sLanguage = $this->oActions->ValidateLanguage($sLanguage); - if ($sLanguage !== $oSettings->GetConf('Language', '')) - { - $bNeedToSettings = true; - $oSettings->SetConf('Language', $sLanguage); - } - } - } - - if ($bNeedToSettings) - { - $this->SettingsProvider()->Save($oAccount, $oSettings); - } - } - - $this->oActions->AuthToken($oAccount); - - $bLogout = !($oAccount instanceof \RainLoop\Model\Account); - } - catch (\Exception $oException) - { - $this->oActions->Logger()->WriteException($oException); - } - } - } - } - - if ($bLogout) - { - $this->oActions->SetAuthLogoutToken(); - } - - $this->oActions->Location('./'); - return ''; - } - - /** - * @return string - */ - public function ServiceRemoteAutoLogin() - { - $oException = null; - $oAccount = null; - $bLogout = true; - - $sEmail = $this->oHttp->GetEnv('REMOTE_USER', ''); - $sPassword = $this->oHttp->GetEnv('REMOTE_PASSWORD', ''); - - if (0 < \strlen($sEmail) && 0 < \strlen(\trim($sPassword))) - { - try - { - $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); - $this->oActions->AuthToken($oAccount); - $bLogout = !($oAccount instanceof \RainLoop\Model\Account); - } - catch (\Exception $oException) - { - $this->oActions->Logger()->WriteException($oException); - } - } - - if ($bLogout) - { - $this->oActions->SetAuthLogoutToken(); - } - - $this->oActions->Location('./'); - return ''; - } - - /** - * @return string - */ - public function ServiceExternalLogin() - { - $this->oHttp->ServerNoCache(); - - $oException = null; - $oAccount = null; - $bLogout = true; - - if ($this->oActions->Config()->Get('labs', 'allow_external_login', false)) - { - $sEmail = \trim($this->oHttp->GetRequest('Email', '')); - $sPassword = $this->oHttp->GetRequest('Password', ''); - - try - { - $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); - $this->oActions->AuthToken($oAccount); - $bLogout = !($oAccount instanceof \RainLoop\Model\Account); - } - catch (\Exception $oException) - { - $this->oActions->Logger()->WriteException($oException); - } - - if ($bLogout) - { - $this->oActions->SetAuthLogoutToken(); - } - } - - switch (\strtolower($this->oHttp->GetRequest('Output', 'Redirect'))) - { - case 'json': - - @\header('Content-Type: application/json; charset=utf-8'); - - $aResult = array( - 'Action' => 'ExternalLogin', - 'Result' => $oAccount instanceof \RainLoop\Model\Account ? true : false, - 'ErrorCode' => 0 - ); - - if (!$aResult['Result']) - { - if ($oException instanceof \RainLoop\Exceptions\ClientException) - { - $aResult['ErrorCode'] = $oException->getCode(); - } - else - { - $aResult['ErrorCode'] = \RainLoop\Notifications::AuthError; - } - } - - return \MailSo\Base\Utils::Php2js($aResult, $this->Logger()); - - case 'redirect': - default: - $this->oActions->Location('./'); - break; - } - - return ''; - } - - /** - * @return string - */ - public function ServiceExternalSso() - { - $this->oHttp->ServerNoCache(); - - $sResult = ''; - $bLogout = true; - $sKey = $this->oActions->Config()->Get('labs', 'external_sso_key', ''); - if ($this->oActions->Config()->Get('labs', 'allow_external_sso', false) && - !empty($sKey) && $sKey === \trim($this->oHttp->GetRequest('SsoKey', ''))) - { - $sEmail = \trim($this->oHttp->GetRequest('Email', '')); - $sPassword = $this->oHttp->GetRequest('Password', ''); - - $sResult = \RainLoop\Api::GetUserSsoHash($sEmail, $sPassword); - $bLogout = 0 === \strlen($sResult); - - switch (\strtolower($this->oHttp->GetRequest('Output', 'Plain'))) - { - case 'plain': - @\header('Content-Type: text/plain'); - break; - - case 'json': - @\header('Content-Type: application/json; charset=utf-8'); - $sResult = \MailSo\Base\Utils::Php2js(array( - 'Action' => 'ExternalSso', - 'Result' => $sResult - ), $this->Logger()); - break; - } - } - - if ($bLogout) - { - $this->oActions->SetAuthLogoutToken(); - } - - return $sResult; - } - - private function changeAction() - { - $this->oHttp->ServerNoCache(); - - $oAccount = $this->oActions->GetAccount(); - - if ($oAccount && $this->oActions->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount)) - { - $oAccountToLogin = null; - $sEmail = empty($this->aPaths[2]) ? '' : \urldecode(\trim($this->aPaths[2])); - if (!empty($sEmail)) - { - $sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail); - - $aAccounts = $this->oActions->GetAccounts($oAccount); - if (isset($aAccounts[$sEmail])) - { - $oAccountToLogin = $this->oActions->GetAccountFromCustomToken($aAccounts[$sEmail], false, false); - } - } - - if ($oAccountToLogin) - { - $this->oActions->AuthToken($oAccountToLogin); - } - } - } - - /** - * @return string - */ - public function ServiceChange() - { - $this->changeAction(); - $this->oActions->Location('./'); - return ''; - } - - /** - * @param string $sTitle - * @param string $sDesc - * - * @return mixed - */ - public function ErrorTemplates($sTitle, $sDesc, $bShowBackLink = true) - { - return strtr(file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Error.html'), array( - '{{BaseWebStaticPath}}' => \RainLoop\Utils::WebStaticPath(), - '{{ErrorTitle}}' => $sTitle, - '{{ErrorHeader}}' => $sTitle, - '{{ErrorDesc}}' => $sDesc, - '{{BackLinkVisibilityStyle}}' => $bShowBackLink ? 'display:inline-block' : 'display:none', - '{{BackLink}}' => $this->oActions->StaticI18N('STATIC/BACK_LINK'), - '{{BackHref}}' => './' - )); - } - - /** - * @param string $sTitle - * @param string $sDesc - * - * @return string - */ - private function localError($sTitle, $sDesc) - { - @header('Content-Type: text/html; charset=utf-8'); - return $this->ErrorTemplates($sTitle, \nl2br($sDesc)); - } - - /** - * @param bool $bAdmin = true - * @param string $sAdd = '' - * - * @return string - */ - private function localAppData($bAdmin = false, $sAdd = '') - { - @\header('Content-Type: application/javascript; charset=utf-8'); - $this->oHttp->ServerNoCache(); - - $sAuthAccountHash = ''; - if (!$bAdmin && 0 === \strlen($this->oActions->GetSpecAuthLogoutTokenWithDeletion())) - { - $sAuthAccountHash = $this->oActions->GetSpecAuthTokenWithDeletion(); - if (empty($sAuthAccountHash)) - { - $sAuthAccountHash = $this->oActions->GetSpecAuthToken(); - } - - if (empty($sAuthAccountHash)) - { - $oAccount = $this->oActions->GetAccountFromSignMeToken(); - if ($oAccount) - { - try - { - $this->oActions->CheckMailConnection($oAccount); - - $this->oActions->AuthToken($oAccount); - - $sAuthAccountHash = $this->oActions->GetSpecAuthToken(); - } - catch (\Exception $oException) - { - $oException = null; - $this->oActions->ClearSignMeData($oAccount); - } - } - } - - $this->oActions->SetSpecAuthToken($sAuthAccountHash); - } - - $sResult = $this->compileAppData($this->oActions->AppData($bAdmin, - 0 === \strpos($sAdd, 'mobile'), '1' === \substr($sAdd, -1), - $sAuthAccountHash), false); - - $this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'APPDATA'); - - return $sResult; - } - - /** - * @param bool $bAdmin = false - * @param bool $bJsOutput = true - * - * @return string - */ - public function compileTemplates($bAdmin = false, $bJsOutput = true) - { - $aTemplates = array(); - - \RainLoop\Utils::CompileTemplates($aTemplates, APP_VERSION_ROOT_PATH.'app/templates/Views/Components', 'Component'); - \RainLoop\Utils::CompileTemplates($aTemplates, APP_VERSION_ROOT_PATH.'app/templates/Views/'.($bAdmin ? 'Admin' : 'User')); - \RainLoop\Utils::CompileTemplates($aTemplates, APP_VERSION_ROOT_PATH.'app/templates/Views/Common'); - - $this->oActions->Plugins()->CompileTemplate($aTemplates, $bAdmin); - - $sHtml = ''; - foreach ($aTemplates as $sName => $sFile) - { - $sName = \preg_replace('/[^a-zA-Z0-9]/', '', $sName); - $sHtml .= ''; - } - - unset($aTemplates); - - return $bJsOutput ? 'window.rainloopTEMPLATES='.\MailSo\Base\Utils::Php2js(array($sHtml), $this->Logger()).';' : $sHtml; - } - - /** - * @param string $sLanguage - * - * @return string - */ - private function convertLanguageNameToMomentLanguageName($sLanguage) - { - $aHelper = array('en_gb' => 'en-gb', 'fr_ca' => 'fr-ca', 'pt_br' => 'pt-br', - 'uk_ua' => 'ua', 'zh_cn' => 'zh-cn', 'zh_tw' => 'zh-tw', 'fa_ir' => 'fa'); - - return isset($aHelper[$sLanguage]) ? $aHelper[$sLanguage] : \substr($sLanguage, 0, 2); - } - - /** - * @param string $sLanguage - * @param bool $bAdmin = false - * @param bool $bWrapByScriptTag = true - * - * @return string - */ - private function compileLanguage($sLanguage, $bAdmin = false, $bWrapByScriptTag = true) - { - $aResultLang = array(); - - $sMoment = 'window.moment && window.moment.locale && window.moment.locale(\'en\');'; - $sMomentFileName = APP_VERSION_ROOT_PATH.'app/localization/moment/'. - $this->convertLanguageNameToMomentLanguageName($sLanguage).'.js'; - - if (\file_exists($sMomentFileName)) - { - $sMoment = \file_get_contents($sMomentFileName); - $sMoment = \preg_replace('/\/\/[^\n]+\n/', '', $sMoment); - } - - \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/langs.yml', $aResultLang); - \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/'. - ($bAdmin ? 'admin' : 'webmail').'/_source.en.yml', $aResultLang); - \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/'. - ($bAdmin ? 'admin' : 'webmail').'/'.$sLanguage.'.yml', $aResultLang); - - $this->Plugins()->ReadLang($sLanguage, $aResultLang); - - $sLangJs = ''; - $aLangKeys = \array_keys($aResultLang); - foreach ($aLangKeys as $sKey) - { - $sString = isset($aResultLang[$sKey]) ? $aResultLang[$sKey] : $sKey; - if (\is_array($sString)) - { - $sString = \implode("\n", $sString); - } - - $sLangJs .= '"'.\str_replace('"', '\\"', \str_replace('\\', '\\\\', $sKey)).'":' - .'"'.\str_replace(array("\r", "\n", "\t"), array('\r', '\n', '\t'), - \str_replace('"', '\\"', \str_replace('\\', '\\\\', $sString))).'",'; - } - - $sResult = empty($sLangJs) ? 'null' : '{'.\substr($sLangJs, 0, -1).'}'; - - return - ($bWrapByScriptTag ? '' : '') - ; - } - - /** - * @param array $aAppData - * @param bool $bWrapByScriptTag = true - * - * @return string - */ - private function compileAppData($aAppData, $bWrapByScriptTag = true) - { - return - ($bWrapByScriptTag ? '' : '') - ; - } -} +oHttp = $oHttp; + $this->oActions = $oActions; + $this->aPaths = array(); + $this->sQuery = ''; + } + + /** + * @return \MailSo\Log\Logger + */ + public function Logger() + { + return $this->oActions->Logger(); + } + + /** + * @return \RainLoop\Plugins\Manager + */ + public function Plugins() + { + return $this->oActions->Plugins(); + } + + /** + * @return \RainLoop\Application + */ + public function Config() + { + return $this->oActions->Config(); + } + + /** + * @return \MailSo\Cache\CacheClient + */ + public function Cacher() + { + return $this->oActions->Cacher(); + } + + /** + * @return \RainLoop\Providers\Storage + */ + public function StorageProvider() + { + return $this->oActions->StorageProvider(); + } + + /** + * @return \RainLoop\Providers\Settings + */ + public function SettingsProvider() + { + return $this->oActions->SettingsProvider(); + } + + /** + * @param array $aPaths + * + * @return \RainLoop\ServiceActions + */ + public function SetPaths($aPaths) + { + $this->aPaths = \is_array($aPaths) ? $aPaths : array(); + return $this; + } + + /** + * @param string $sQuery + * + * @return \RainLoop\ServiceActions + */ + public function SetQuery($sQuery) + { + $this->sQuery = $sQuery; + return $this; + } + + /** + * @return string + */ + public function ServiceAjax() + { + @\ob_start(); + + $aResponseItem = null; + $oException = null; + + $sAction = $this->oHttp->GetPost('Action', null); + if (empty($sAction) && $this->oHttp->IsGet() && !empty($this->aPaths[2])) + { + $sAction = $this->aPaths[2]; + } + + try + { + if ($this->oHttp->IsPost() && !in_array($sAction, array('JsInfo', 'JsError')) && + $this->Config()->Get('security', 'csrf_protection', false) && + $this->oHttp->GetPost('XToken', '') !== \RainLoop\Utils::GetCsrfToken()) + { + throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidToken); + } + else if (!empty($sAction)) + { + $sMethodName = 'Do'.$sAction; + + $this->Logger()->Write('Action: '.$sMethodName, \MailSo\Log\Enumerations\Type::NOTE, 'AJAX'); + + $aPost = $this->oHttp->GetPostAsArray(); + if (\is_array($aPost) && 0 < \count($aPost)) + { + $this->oActions->SetActionParams($aPost, $sMethodName); + switch ($sMethodName) + { + case 'DoLogin': + case 'DoAdminLogin': + case 'DoAccountAdd': + $this->Logger()->AddSecret($this->oActions->GetActionParam('Password', '')); + break; + case 'DoChangePassword': + $this->Logger()->AddSecret($this->oActions->GetActionParam('PrevPassword', '')); + $this->Logger()->AddSecret($this->oActions->GetActionParam('NewPassword', '')); + break; + } + + $this->Logger()->Write(\MailSo\Base\Utils::Php2js($aPost, $this->Logger()), + \MailSo\Log\Enumerations\Type::INFO, 'POST', true); + } + else if (3 < \count($this->aPaths) && $this->oHttp->IsGet()) + { + $this->oActions->SetActionParams(array( + 'RawKey' => empty($this->aPaths[3]) ? '' : $this->aPaths[3] + ), $sMethodName); + } + + if (\method_exists($this->oActions, $sMethodName) && + \is_callable(array($this->oActions, $sMethodName))) + { + $this->Plugins()->RunHook('ajax.action-pre-call', array($sAction)); + $aResponseItem = \call_user_func(array($this->oActions, $sMethodName)); + $this->Plugins()->RunHook('ajax.action-post-call', array($sAction, &$aResponseItem)); + } + else if ($this->Plugins()->HasAdditionalAjax($sMethodName)) + { + $this->Plugins()->RunHook('ajax.action-pre-call', array($sAction)); + $aResponseItem = $this->Plugins()->RunAdditionalAjax($sMethodName); + $this->Plugins()->RunHook('ajax.action-post-call', array($sAction, &$aResponseItem)); + } + } + + if (!\is_array($aResponseItem)) + { + throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError); + } + } + catch (\Exception $oException) + { + $aResponseItem = $this->oActions->ExceptionResponse( + empty($sAction) ? 'Unknown' : $sAction, $oException); + + if (\is_array($aResponseItem) && $oException instanceof \RainLoop\Exceptions\ClientException) + { + if ('Folders' === $sAction) + { + $aResponseItem['ClearAuth'] = true; + } + + if ($oException->getLogoutOnException()) + { + $aResponseItem['Logout'] = true; + if ($oException->getAdditionalMessage()) + { + $this->oActions->SetSpecLogoutCustomMgsWithDeletion($oException->getAdditionalMessage()); + } + } + } + } + + if (\is_array($aResponseItem)) + { + $aResponseItem['Time'] = (int) ((\microtime(true) - APP_START) * 1000); + } + + $this->Plugins()->RunHook('filter.ajax-response', array($sAction, &$aResponseItem)); + + @\header('Content-Type: application/json; charset=utf-8'); + + $sResult = \MailSo\Base\Utils::Php2js($aResponseItem, $this->Logger()); + + $sObResult = @\ob_get_clean(); + + if ($this->Logger()->IsEnabled()) + { + if (0 < \strlen($sObResult)) + { + $this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA'); + } + + if ($oException) + { + $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); + } + + $iLimit = (int) $this->Config()->Get('labs', 'log_ajax_response_write_limit', 0); + $this->Logger()->Write(0 < $iLimit && $iLimit < \strlen($sResult) + ? \substr($sResult, 0, $iLimit).'...' : $sResult, \MailSo\Log\Enumerations\Type::INFO, 'AJAX'); + } + + return $sResult; + } + + /** + * @return string + */ + public function ServiceOwnCloudAuth() + { + $this->oHttp->ServerNoCache(); + + if (!\RainLoop\Utils::IsOwnCloud() || + !isset($_ENV['___rainloop_owncloud_email']) || + !isset($_ENV['___rainloop_owncloud_password']) || + empty($_ENV['___rainloop_owncloud_email']) + ) + { + $this->oActions->SetAuthLogoutToken(); + $this->oActions->Location('./'); + return ''; + } + + $bLogout = true; + + $sEmail = $_ENV['___rainloop_owncloud_email']; + $sPassword = $_ENV['___rainloop_owncloud_password']; + + try + { + $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); + $this->oActions->AuthToken($oAccount); + + $bLogout = !($oAccount instanceof \RainLoop\Model\Account); + } + catch (\Exception $oException) + { + $this->oActions->Logger()->WriteException($oException); + } + + if ($bLogout) + { + $this->oActions->SetAuthLogoutToken(); + } + + $this->oActions->Location('./'); + return ''; + } + + /** + * @return string + */ + public function ServiceAppend() + { + @\ob_start(); + $bResponse = false; + $oException = null; + try + { + if (\method_exists($this->oActions, 'Append') && + \is_callable(array($this->oActions, 'Append'))) + { + $this->oActions->SetActionParams($this->oHttp->GetPostAsArray(), 'Append'); + $bResponse = \call_user_func(array($this->oActions, 'Append')); + } + } + catch (\Exception $oException) + { + $bResponse = false; + } + + @\header('Content-Type: text/plain; charset=utf-8'); + $sResult = true === $bResponse ? '1' : '0'; + + $sObResult = @\ob_get_clean(); + if (0 < \strlen($sObResult)) + { + $this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA'); + } + + if ($oException) + { + $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); + } + + $this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'APPEND'); + + return $sResult; + } + + /** + * @param string $sAction + * @param int $iSizeLimit = 0 + * + * @return string + */ + private function privateUpload($sAction, $iSizeLimit = 0) + { + $oConfig = $this->Config(); + + @\ob_start(); + $aResponseItem = null; + try + { + $aFile = null; + $sInputName = 'uploader'; + $iError = \RainLoop\Enumerations\UploadError::UNKNOWN; + $iSizeLimit = (0 < $iSizeLimit ? $iSizeLimit : ((int) $oConfig->Get('webmail', 'attachment_size_limit', 0))) * 1024 * 1024; + + $iError = UPLOAD_ERR_OK; + $_FILES = isset($_FILES) ? $_FILES : null; + if (isset($_FILES, $_FILES[$sInputName], $_FILES[$sInputName]['name'], $_FILES[$sInputName]['tmp_name'], $_FILES[$sInputName]['size'])) + { + $iError = (isset($_FILES[$sInputName]['error'])) ? (int) $_FILES[$sInputName]['error'] : UPLOAD_ERR_OK; + + if (UPLOAD_ERR_OK === $iError && 0 < $iSizeLimit && $iSizeLimit < (int) $_FILES[$sInputName]['size']) + { + $iError = \RainLoop\Enumerations\UploadError::CONFIG_SIZE; + } + + if (UPLOAD_ERR_OK === $iError) + { + $aFile = $_FILES[$sInputName]; + } + } + else if (!isset($_FILES) || !is_array($_FILES) || 0 === count($_FILES)) + { + $iError = UPLOAD_ERR_INI_SIZE; + } + else + { + $iError = \RainLoop\Enumerations\UploadError::EMPTY_FILES_DATA; + } + + if (\method_exists($this->oActions, $sAction) && + \is_callable(array($this->oActions, $sAction))) + { + $aActionParams = $this->oHttp->GetQueryAsArray(); + + $aActionParams['File'] = $aFile; + $aActionParams['Error'] = $iError; + + $this->oActions->SetActionParams($aActionParams, $sAction); + + $aResponseItem = \call_user_func(array($this->oActions, $sAction)); + } + + if (!is_array($aResponseItem)) + { + throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError); + } + } + catch (\Exception $oException) + { + $aResponseItem = $this->oActions->ExceptionResponse($sAction, $oException); + } + + if ('iframe' === $this->oHttp->GetPost('jua-post-type', '')) + { + @\header('Content-Type: text/html; charset=utf-8'); + } + else + { + @\header('Content-Type: application/json; charset=utf-8'); + } + + $this->Plugins()->RunHook('filter.upload-response', array(&$aResponseItem)); + $sResult = \MailSo\Base\Utils::Php2js($aResponseItem, $this->Logger()); + + $sObResult = @\ob_get_clean(); + if (0 < \strlen($sObResult)) + { + $this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA'); + } + + $this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'UPLOAD'); + + return $sResult; + } + + /** + * @return string + */ + public function ServiceUpload() + { + return $this->privateUpload('Upload'); + } + + /** + * @return string + */ + public function ServiceUploadContacts() + { + return $this->privateUpload('UploadContacts', 5); + } + + /** + * @return string + */ + public function ServiceUploadBackground() + { + return $this->privateUpload('UploadBackground', 1); + } + + /** + * @return string + */ + public function ServiceProxyExternal() + { + $bResult = false; + $sData = empty($this->aPaths[1]) ? '' : $this->aPaths[1]; + if (!empty($sData) && $this->oActions->Config()->Get('labs', 'use_local_proxy_for_external_images', false)) + { + $this->oActions->verifyCacheByKey($sData); + + $aData = \RainLoop\Utils::DecodeKeyValuesQ($sData); + if (\is_array($aData) && !empty($aData['Token']) && !empty($aData['Url']) && $aData['Token'] === \RainLoop\Utils::GetConnectionToken()) + { + $iCode = 404; + $sContentType = ''; + $mResult = $this->oHttp->GetUrlAsString($aData['Url'], 'RainLoop External Proxy', $sContentType, $iCode); + + if (false !== $mResult && 200 === $iCode && + \in_array($sContentType, array('image/png', 'image/jpeg', 'image/jpg', 'image/bmp', 'image/gif'))) + { + $bResult = true; + + $this->oActions->cacheByKey($sData); + + \header('Content-Type: '.$sContentType); + echo $mResult; + } + } + } + + if (!$bResult) + { + $this->oHttp->StatusHeader(404); + } + + return ''; + } + + /** + * @return string + */ + public function ServiceRaw() + { + $sResult = ''; + $sRawError = ''; + $sAction = empty($this->aPaths[2]) ? '' : $this->aPaths[2]; + $oException = null; + + try + { + $sRawError = 'Invalid action'; + if (0 !== \strlen($sAction)) + { + $sMethodName = 'Raw'.$sAction; + if (\method_exists($this->oActions, $sMethodName)) + { + @\header('X-Raw-Action: '.$sMethodName, true); + @\header('Content-Security-Policy: default-src \'self\'; script-src \'none\'; style-src \'none\'; frame-src \'none\'; child-src \'none\'', true); + + $sRawError = ''; + $this->oActions->SetActionParams(array( + 'RawKey' => empty($this->aPaths[3]) ? '' : $this->aPaths[3], + 'Params' => $this->aPaths + ), $sMethodName); + + if (!\call_user_func(array($this->oActions, $sMethodName))) + { + $sRawError = 'False result'; + } + else + { + $sRawError = ''; + } + } + else + { + $sRawError = 'Unknown action "'.$sAction.'"'; + } + } + else + { + $sRawError = 'Empty action'; + } + } + catch (\RainLoop\Exceptions\ClientException $oException) + { + $sRawError = 'Exception as result'; + switch ($oException->getCode()) + { + case \RainLoop\Notifications::AuthError: + $sRawError = 'Authentication failed'; + break; + } + } + catch (\Exception $oException) + { + $sRawError = 'Exception as result'; + } + + if (0 < \strlen($sRawError)) + { + $this->oActions->Logger()->Write($sRawError, \MailSo\Log\Enumerations\Type::ERROR); + $this->oActions->Logger()->WriteDump($this->aPaths, \MailSo\Log\Enumerations\Type::ERROR, 'PATHS'); + } + + if ($oException) + { + $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR, 'RAW'); + } + + return $sResult; + } + + /** + * @return string + */ + public function ServiceLang() + { +// sleep(2); + $sResult = ''; + @\header('Content-Type: application/javascript; charset=utf-8'); + + if (!empty($this->aPaths[3])) + { + $bAdmim = 'Admin' === (isset($this->aPaths[2]) ? (string) $this->aPaths[2] : 'App'); + $sLanguage = $this->oActions->ValidateLanguage($this->aPaths[3], '', $bAdmim); + + $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true); + if (!empty($sLanguage) && $bCacheEnabled) + { + $this->oActions->verifyCacheByKey($this->sQuery); + } + + $sCacheFileName = ''; + if ($bCacheEnabled) + { + $sCacheFileName = \RainLoop\KeyPathHelper::LangCache( + $sLanguage, $bAdmim, $this->oActions->Plugins()->Hash()); + + $sResult = $this->Cacher()->Get($sCacheFileName); + } + + if (0 === \strlen($sResult)) + { + $sResult = $this->compileLanguage($sLanguage, $bAdmim, false); + if ($bCacheEnabled && 0 < \strlen($sCacheFileName)) + { + $this->Cacher()->Set($sCacheFileName, $sResult); + } + } + + if ($bCacheEnabled) + { + $this->oActions->cacheByKey($this->sQuery); + } + } + + return $sResult; + } + + /** + * @return string + */ + public function ServiceTemplates() + { + $sResult = ''; + @\header('Content-Type: application/javascript; charset=utf-8'); + + $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true); + if ($bCacheEnabled) + { + $this->oActions->verifyCacheByKey($this->sQuery); + } + + $bAdmin = false !== \strpos($this->sQuery, 'Admin'); + + $sCacheFileName = ''; + if ($bCacheEnabled) + { + $sCacheFileName = \RainLoop\KeyPathHelper::TemplatesCache($bAdmin, $this->oActions->Plugins()->Hash()); + $sResult = $this->Cacher()->Get($sCacheFileName); + } + + if (0 === \strlen($sResult)) + { + $sResult = $this->compileTemplates($bAdmin); + if ($bCacheEnabled && 0 < \strlen($sCacheFileName)) + { + $this->Cacher()->Set($sCacheFileName, $sResult); + } + } + + if ($bCacheEnabled) + { + $this->oActions->cacheByKey($this->sQuery); + } + + return $sResult; + } + + /** + * @return string + */ + public function ServicePlugins() + { + $sResult = ''; + $bAdmin = !empty($this->aPaths[2]) && 'Admin' === $this->aPaths[2]; + + @\header('Content-Type: application/javascript; charset=utf-8'); + + $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true); + if ($bCacheEnabled) + { + $this->oActions->verifyCacheByKey($this->sQuery); + } + + $sCacheFileName = ''; + if ($bCacheEnabled) + { + $sCacheFileName = \RainLoop\KeyPathHelper::PluginsJsCache($this->oActions->Plugins()->Hash()); + $sResult = $this->Cacher()->Get($sCacheFileName); + } + + if (0 === strlen($sResult)) + { + $sResult = $this->Plugins()->CompileJs($bAdmin); + if ($bCacheEnabled && 0 < \strlen($sCacheFileName)) + { + $this->Cacher()->Set($sCacheFileName, $sResult); + } + } + + if ($bCacheEnabled) + { + $this->oActions->cacheByKey($this->sQuery); + } + + return $sResult; + } + + /** + * @return string + */ + public function ServiceCss() + { + $sResult = ''; + + $bAdmin = !empty($this->aPaths[2]) && 'Admin' === $this->aPaths[2]; + $bJson = !empty($this->aPaths[9]) && 'Json' === $this->aPaths[9]; + + if ($bJson) + { + @\header('Content-Type: application/json; charset=utf-8'); + } + else + { + @\header('Content-Type: text/css; charset=utf-8'); + } + + $sTheme = ''; + if (!empty($this->aPaths[4])) + { + $sTheme = $this->oActions->ValidateTheme($this->aPaths[4]); + $sRealTheme = $sTheme; + + $bCustomTheme = '@custom' === \substr($sTheme, -7); + if ($bCustomTheme) + { + $sRealTheme = \substr($sTheme, 0, -7); + } + + $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true); + if ($bCacheEnabled) + { + $this->oActions->verifyCacheByKey($this->sQuery); + } + + $sCacheFileName = ''; + if ($bCacheEnabled) + { + $sCacheFileName = \RainLoop\KeyPathHelper::CssCache($sTheme, $this->oActions->Plugins()->Hash()); + $sResult = $this->Cacher()->Get($sCacheFileName); + } + + if (0 === \strlen($sResult)) + { + try + { + include_once APP_VERSION_ROOT_PATH.'app/libraries/lessphp/ctype.php'; + include_once APP_VERSION_ROOT_PATH.'app/libraries/lessphp/lessc.inc.php'; + + $oLess = new \RainLoopVendor\lessc(); + $oLess->setFormatter('compressed'); + + $aResult = array(); + + $sThemeFile = ($bCustomTheme ? APP_INDEX_ROOT_PATH : APP_VERSION_ROOT_PATH).'themes/'.$sRealTheme.'/styles.less'; + $sThemeExtFile = ($bCustomTheme ? APP_INDEX_ROOT_PATH : APP_VERSION_ROOT_PATH).'themes/'.$sRealTheme.'/ext.less'; + + $sThemeValuesFile = APP_VERSION_ROOT_PATH.'app/templates/Themes/values.less'; + $sThemeTemplateFile = APP_VERSION_ROOT_PATH.'app/templates/Themes/template.less'; + + if (\file_exists($sThemeFile) && \file_exists($sThemeTemplateFile) && \file_exists($sThemeValuesFile)) + { + $aResult[] = '@base: "'. + ($bCustomTheme ? \RainLoop\Utils::WebPath() : \RainLoop\Utils::WebVersionPath()). + 'themes/'.$sRealTheme.'/";'; + + $aResult[] = \file_get_contents($sThemeValuesFile); + $aResult[] = \file_get_contents($sThemeFile); + $aResult[] = \file_get_contents($sThemeTemplateFile); + + if (\file_exists($sThemeExtFile)) + { + $aResult[] = \file_get_contents($sThemeExtFile); + } + } + + $aResult[] = $this->Plugins()->CompileCss($bAdmin); + + $sResult = $oLess->compile(\implode("\n", $aResult)); + + if ($bCacheEnabled) + { + if (0 < \strlen($sCacheFileName)) + { + $this->Cacher()->Set($sCacheFileName, $sResult); + } + } + } + catch (\Exception $oException) + { + $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR, 'LESS'); + } + } + + if ($bCacheEnabled) + { + $this->oActions->cacheByKey($this->sQuery); + } + } + + return $bJson ? \MailSo\Base\Utils::Php2js(array($sTheme, $sResult), $this->Logger()) : $sResult; + } + + /** + * @return string + */ + public function ServiceSocialGoogle() + { + $bXAuth = '1' === (string) $this->oHttp->GetQuery('xauth', '0'); + return $this->oActions->Social()->GooglePopupService($bXAuth); + } + + /** + * @return string + */ + public function ServiceSocialFacebook() + { + return $this->oActions->Social()->FacebookPopupService(); + } + + /** + * @return string + */ + public function ServiceSocialTwitter() + { + return $this->oActions->Social()->TwitterPopupService(); + } + + /** + * @return string + */ + public function ServiceAppData($sAdd = '') + { + return $this->localAppData(false, $sAdd); + } + + /** + * @return string + */ + public function ServiceAdminAppData($sAdd = '') + { + return $this->localAppData(true, $sAdd); + } + + /** + * @return string + */ + public function ServiceMobileVersion() + { + \RainLoop\Utils::SetCookie(\RainLoop\Actions::RL_MOBILE_TYPE, 'mobile'); + $this->oActions->Location('./'); + return ''; + } + + /** + * @return string + */ + public function ServiceDesktopVersion() + { + \RainLoop\Utils::SetCookie(\RainLoop\Actions::RL_MOBILE_TYPE, 'desktop'); + $this->oActions->Location('./'); + return ''; + } + + /** + * @return string + */ + public function ServiceNoScript() + { + return $this->localError($this->oActions->StaticI18N('STATIC/NO_SCRIPT_TITLE'), $this->oActions->StaticI18N('STATIC/NO_SCRIPT_DESC')); + } + + /** + * @return string + */ + public function ServiceNoCookie() + { + return $this->localError($this->oActions->StaticI18N('STATIC/NO_COOKIE_TITLE'), $this->oActions->StaticI18N('STATIC/NO_COOKIE_DESC')); + } + + /** + * @return string + */ + public function ServiceBadBrowser() + { + $sTitle = $this->oActions->StaticI18N('STATIC/BAD_BROWSER_TITLE'); + $sDesc = \nl2br($this->oActions->StaticI18N('STATIC/BAD_BROWSER_DESC')); + + @\header('Content-Type: text/html; charset=utf-8'); + return \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/BadBrowser.html'), array( + '{{BaseWebStaticPath}}' => \RainLoop\Utils::WebStaticPath(), + '{{ErrorTitle}}' => $sTitle, + '{{ErrorHeader}}' => $sTitle, + '{{ErrorDesc}}' => $sDesc + )); + } + + /** + * @return string + */ + public function ServiceMailto() + { + $this->oHttp->ServerNoCache(); + + $sTo = \trim($this->oHttp->GetQuery('to', '')); + if (!empty($sTo) && \preg_match('/^mailto:/i', $sTo)) + { + $oAccount = $this->oActions->GetAccountFromSignMeToken(); + if ($oAccount) + { + $this->oActions->SetMailtoRequest($sTo); + } + } + + $this->oActions->Location('./'); + return ''; + } + + /** + * @return string + */ + public function ServicePing() + { + $this->oHttp->ServerNoCache(); + + @\header('Content-Type: text/plain; charset=utf-8'); + $this->oActions->Logger()->Write('Pong', \MailSo\Log\Enumerations\Type::INFO, 'PING'); + return 'Pong'; + } + + /** + * @return string + */ + public function ServiceInfo() + { + $this->oHttp->ServerNoCache(); + + if ($this->oActions->IsAdminLoggined(false)) + { + @\header('Content-Type: text/html; charset=utf-8'); + \phpinfo(); + } + } + + /** + * @return string + */ + public function ServiceSso() + { + $this->oHttp->ServerNoCache(); + + $oException = null; + $oAccount = null; + $bLogout = true; + + $sSsoHash = $this->oHttp->GetRequest('hash', ''); + if (!empty($sSsoHash)) + { + $mData = null; + + $sSsoSubData = $this->Cacher()->Get(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash)); + if (!empty($sSsoSubData)) + { + $mData = \RainLoop\Utils::DecodeKeyValuesQ($sSsoSubData); + $this->Cacher()->Delete(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash)); + + if (\is_array($mData) && !empty($mData['Email']) && isset($mData['Password'], $mData['Time']) && + (0 === $mData['Time'] || \time() - 10 < $mData['Time'])) + { + $sEmail = \trim($mData['Email']); + $sPassword = $mData['Password']; + + $aAdditionalOptions = isset($mData['AdditionalOptions']) && \is_array($mData['AdditionalOptions']) && + 0 < \count($mData['AdditionalOptions']) ? $mData['AdditionalOptions'] : null; + + try + { + $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); + + if ($oAccount instanceof \RainLoop\Model\Account && $aAdditionalOptions) + { + $bNeedToSettings = false; + + $oSettings = $this->SettingsProvider()->Load($oAccount); + if ($oSettings) + { + $sLanguage = isset($aAdditionalOptions['Language']) ? + $aAdditionalOptions['Language'] : ''; + + if ($sLanguage) + { + $sLanguage = $this->oActions->ValidateLanguage($sLanguage); + if ($sLanguage !== $oSettings->GetConf('Language', '')) + { + $bNeedToSettings = true; + $oSettings->SetConf('Language', $sLanguage); + } + } + } + + if ($bNeedToSettings) + { + $this->SettingsProvider()->Save($oAccount, $oSettings); + } + } + + $this->oActions->AuthToken($oAccount); + + $bLogout = !($oAccount instanceof \RainLoop\Model\Account); + } + catch (\Exception $oException) + { + $this->oActions->Logger()->WriteException($oException); + } + } + } + } + + if ($bLogout) + { + $this->oActions->SetAuthLogoutToken(); + } + + $this->oActions->Location('./'); + return ''; + } + + /** + * @return string + */ + public function ServiceRemoteAutoLogin() + { + $oException = null; + $oAccount = null; + $bLogout = true; + + $sEmail = $this->oHttp->GetEnv('REMOTE_USER', ''); + $sPassword = $this->oHttp->GetEnv('REMOTE_PASSWORD', ''); + + if (0 < \strlen($sEmail) && 0 < \strlen(\trim($sPassword))) + { + try + { + $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); + $this->oActions->AuthToken($oAccount); + $bLogout = !($oAccount instanceof \RainLoop\Model\Account); + } + catch (\Exception $oException) + { + $this->oActions->Logger()->WriteException($oException); + } + } + + if ($bLogout) + { + $this->oActions->SetAuthLogoutToken(); + } + + $this->oActions->Location('./'); + return ''; + } + + /** + * @return string + */ + public function ServiceExternalLogin() + { + $this->oHttp->ServerNoCache(); + + $oException = null; + $oAccount = null; + $bLogout = true; + + if ($this->oActions->Config()->Get('labs', 'allow_external_login', false)) + { + $sEmail = \trim($this->oHttp->GetRequest('Email', '')); + $sPassword = $this->oHttp->GetRequest('Password', ''); + + try + { + $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); + $this->oActions->AuthToken($oAccount); + $bLogout = !($oAccount instanceof \RainLoop\Model\Account); + } + catch (\Exception $oException) + { + $this->oActions->Logger()->WriteException($oException); + } + + if ($bLogout) + { + $this->oActions->SetAuthLogoutToken(); + } + } + + switch (\strtolower($this->oHttp->GetRequest('Output', 'Redirect'))) + { + case 'json': + + @\header('Content-Type: application/json; charset=utf-8'); + + $aResult = array( + 'Action' => 'ExternalLogin', + 'Result' => $oAccount instanceof \RainLoop\Model\Account ? true : false, + 'ErrorCode' => 0 + ); + + if (!$aResult['Result']) + { + if ($oException instanceof \RainLoop\Exceptions\ClientException) + { + $aResult['ErrorCode'] = $oException->getCode(); + } + else + { + $aResult['ErrorCode'] = \RainLoop\Notifications::AuthError; + } + } + + return \MailSo\Base\Utils::Php2js($aResult, $this->Logger()); + + case 'redirect': + default: + $this->oActions->Location('./'); + break; + } + + return ''; + } + + /** + * @return string + */ + public function ServiceExternalSso() + { + $this->oHttp->ServerNoCache(); + + $sResult = ''; + $bLogout = true; + $sKey = $this->oActions->Config()->Get('labs', 'external_sso_key', ''); + if ($this->oActions->Config()->Get('labs', 'allow_external_sso', false) && + !empty($sKey) && $sKey === \trim($this->oHttp->GetRequest('SsoKey', ''))) + { + $sEmail = \trim($this->oHttp->GetRequest('Email', '')); + $sPassword = $this->oHttp->GetRequest('Password', ''); + + $sResult = \RainLoop\Api::GetUserSsoHash($sEmail, $sPassword); + $bLogout = 0 === \strlen($sResult); + + switch (\strtolower($this->oHttp->GetRequest('Output', 'Plain'))) + { + case 'plain': + @\header('Content-Type: text/plain'); + break; + + case 'json': + @\header('Content-Type: application/json; charset=utf-8'); + $sResult = \MailSo\Base\Utils::Php2js(array( + 'Action' => 'ExternalSso', + 'Result' => $sResult + ), $this->Logger()); + break; + } + } + + if ($bLogout) + { + $this->oActions->SetAuthLogoutToken(); + } + + return $sResult; + } + + private function changeAction() + { + $this->oHttp->ServerNoCache(); + + $oAccount = $this->oActions->GetAccount(); + + if ($oAccount && $this->oActions->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount)) + { + $oAccountToLogin = null; + $sEmail = empty($this->aPaths[2]) ? '' : \urldecode(\trim($this->aPaths[2])); + if (!empty($sEmail)) + { + $sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail); + + $aAccounts = $this->oActions->GetAccounts($oAccount); + if (isset($aAccounts[$sEmail])) + { + $oAccountToLogin = $this->oActions->GetAccountFromCustomToken($aAccounts[$sEmail], false, false); + } + } + + if ($oAccountToLogin) + { + $this->oActions->AuthToken($oAccountToLogin); + } + } + } + + /** + * @return string + */ + public function ServiceChange() + { + $this->changeAction(); + $this->oActions->Location('./'); + return ''; + } + + /** + * @param string $sTitle + * @param string $sDesc + * + * @return mixed + */ + public function ErrorTemplates($sTitle, $sDesc, $bShowBackLink = true) + { + return strtr(file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Error.html'), array( + '{{BaseWebStaticPath}}' => \RainLoop\Utils::WebStaticPath(), + '{{ErrorTitle}}' => $sTitle, + '{{ErrorHeader}}' => $sTitle, + '{{ErrorDesc}}' => $sDesc, + '{{BackLinkVisibilityStyle}}' => $bShowBackLink ? 'display:inline-block' : 'display:none', + '{{BackLink}}' => $this->oActions->StaticI18N('STATIC/BACK_LINK'), + '{{BackHref}}' => './' + )); + } + + /** + * @param string $sTitle + * @param string $sDesc + * + * @return string + */ + private function localError($sTitle, $sDesc) + { + @header('Content-Type: text/html; charset=utf-8'); + return $this->ErrorTemplates($sTitle, \nl2br($sDesc)); + } + + /** + * @param bool $bAdmin = true + * @param string $sAdd = '' + * + * @return string + */ + private function localAppData($bAdmin = false, $sAdd = '') + { + @\header('Content-Type: application/javascript; charset=utf-8'); + $this->oHttp->ServerNoCache(); + + $sAuthAccountHash = ''; + if (!$bAdmin && 0 === \strlen($this->oActions->GetSpecAuthLogoutTokenWithDeletion())) + { + $sAuthAccountHash = $this->oActions->GetSpecAuthTokenWithDeletion(); + if (empty($sAuthAccountHash)) + { + $sAuthAccountHash = $this->oActions->GetSpecAuthToken(); + } + + if (empty($sAuthAccountHash)) + { + $oAccount = $this->oActions->GetAccountFromSignMeToken(); + if ($oAccount) + { + try + { + $this->oActions->CheckMailConnection($oAccount); + + $this->oActions->AuthToken($oAccount); + + $sAuthAccountHash = $this->oActions->GetSpecAuthToken(); + } + catch (\Exception $oException) + { + $oException = null; + $this->oActions->ClearSignMeData($oAccount); + } + } + } + + $this->oActions->SetSpecAuthToken($sAuthAccountHash); + } + + $sResult = $this->compileAppData($this->oActions->AppData($bAdmin, + 0 === \strpos($sAdd, 'mobile'), '1' === \substr($sAdd, -1), + $sAuthAccountHash), false); + + $this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'APPDATA'); + + return $sResult; + } + + /** + * @param bool $bAdmin = false + * @param bool $bJsOutput = true + * + * @return string + */ + public function compileTemplates($bAdmin = false, $bJsOutput = true) + { + $aTemplates = array(); + + \RainLoop\Utils::CompileTemplates($aTemplates, APP_VERSION_ROOT_PATH.'app/templates/Views/Components', 'Component'); + \RainLoop\Utils::CompileTemplates($aTemplates, APP_VERSION_ROOT_PATH.'app/templates/Views/'.($bAdmin ? 'Admin' : 'User')); + \RainLoop\Utils::CompileTemplates($aTemplates, APP_VERSION_ROOT_PATH.'app/templates/Views/Common'); + + $this->oActions->Plugins()->CompileTemplate($aTemplates, $bAdmin); + + $sHtml = ''; + foreach ($aTemplates as $sName => $sFile) + { + $sName = \preg_replace('/[^a-zA-Z0-9]/', '', $sName); + $sHtml .= ''; + } + + unset($aTemplates); + + return $bJsOutput ? 'window.rainloopTEMPLATES='.\MailSo\Base\Utils::Php2js(array($sHtml), $this->Logger()).';' : $sHtml; + } + + /** + * @param string $sLanguage + * + * @return string + */ + private function convertLanguageNameToMomentLanguageName($sLanguage) + { + $aHelper = array('en_gb' => 'en-gb', 'fr_ca' => 'fr-ca', 'pt_br' => 'pt-br', + 'uk_ua' => 'ua', 'zh_cn' => 'zh-cn', 'zh_tw' => 'zh-tw', 'fa_ir' => 'fa'); + + return isset($aHelper[$sLanguage]) ? $aHelper[$sLanguage] : \substr($sLanguage, 0, 2); + } + + /** + * @param string $sLanguage + * @param bool $bAdmin = false + * @param bool $bWrapByScriptTag = true + * + * @return string + */ + private function compileLanguage($sLanguage, $bAdmin = false, $bWrapByScriptTag = true) + { + $aResultLang = array(); + + $sMoment = 'window.moment && window.moment.locale && window.moment.locale(\'en\');'; + $sMomentFileName = APP_VERSION_ROOT_PATH.'app/localization/moment/'. + $this->convertLanguageNameToMomentLanguageName($sLanguage).'.js'; + + if (\file_exists($sMomentFileName)) + { + $sMoment = \file_get_contents($sMomentFileName); + $sMoment = \preg_replace('/\/\/[^\n]+\n/', '', $sMoment); + } + + \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/langs.yml', $aResultLang); + \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/'. + ($bAdmin ? 'admin' : 'webmail').'/_source.en.yml', $aResultLang); + \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/'. + ($bAdmin ? 'admin' : 'webmail').'/'.$sLanguage.'.yml', $aResultLang); + + $this->Plugins()->ReadLang($sLanguage, $aResultLang); + + $sLangJs = ''; + $aLangKeys = \array_keys($aResultLang); + foreach ($aLangKeys as $sKey) + { + $sString = isset($aResultLang[$sKey]) ? $aResultLang[$sKey] : $sKey; + if (\is_array($sString)) + { + $sString = \implode("\n", $sString); + } + + $sLangJs .= '"'.\str_replace('"', '\\"', \str_replace('\\', '\\\\', $sKey)).'":' + .'"'.\str_replace(array("\r", "\n", "\t"), array('\r', '\n', '\t'), + \str_replace('"', '\\"', \str_replace('\\', '\\\\', $sString))).'",'; + } + + $sResult = empty($sLangJs) ? 'null' : '{'.\substr($sLangJs, 0, -1).'}'; + + return + ($bWrapByScriptTag ? '' : '') + ; + } + + /** + * @param array $aAppData + * @param bool $bWrapByScriptTag = true + * + * @return string + */ + private function compileAppData($aAppData, $bWrapByScriptTag = true) + { + return + ($bWrapByScriptTag ? '' : '') + ; + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Settings.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Settings.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Settings.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Settings.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Social.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Social.php similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Social.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Social.php index d19164f8..a1363756 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Social.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Social.php @@ -1,792 +1,792 @@ -oHttp = $oHttp; - $this->oActions = $oActions; - } - - /** - * @return bool - */ - public function GoogleDisconnect($oAccount) - { - $oGoogle = $this->GoogleConnector(); - if ($oAccount && $oGoogle) - { - $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); - $sEncodedeData = $oSettings->GetConf('GoogleAccessToken', ''); - - if (!empty($sEncodedeData)) - { - $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData); - if (\is_array($aData) && !empty($aData['id'])) - { - $this->oActions->StorageProvider()->Clear(null, - \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, - $this->GoogleUserLoginStorageKey($oGoogle, $aData['id']) - ); - } - } - - $oSettings->SetConf('GoogleAccessToken', ''); - $oSettings->SetConf('GoogleSocialName', ''); - - return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); - } - - return false; - } - - /** - * @return bool - */ - public function FacebookDisconnect($oAccount) - { - $oFacebook = $this->FacebookConnector($oAccount ? $oAccount : null); - if ($oAccount && $oFacebook) - { - $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); - - $sEncodedeData = $oSettings->GetConf('FacebookAccessToken', ''); - - if (!empty($sEncodedeData)) - { - $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData); - if (is_array($aData) && isset($aData['id'])) - { - $this->oActions->StorageProvider()->Clear(null, - \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, - $this->FacebookUserLoginStorageKey($oFacebook, $aData['id']) - ); - } - } - - $oSettings->SetConf('FacebookAccessToken', ''); - $oSettings->SetConf('FacebookSocialName', ''); - - return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); - } - - return false; - } - - /** - * @return bool - */ - public function TwitterDisconnect($oAccount) - { - $oTwitter = $this->TwitterConnector(); - if ($oAccount && $oTwitter) - { - $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); - $sEncodedData = $oSettings->GetConf('TwitterAccessToken', ''); - - if (!empty($sEncodedData)) - { - $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedData); - if (is_array($aData) && isset($aData['id'])) - { - $this->oActions->StorageProvider()->Clear(null, - \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, - $this->TwitterUserLoginStorageKey($oTwitter, $aData['id']) - ); - } - } - - $oSettings->SetConf('TwitterAccessToken', ''); - $oSettings->SetConf('TwitterSocialName', ''); - - return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); - } - - return false; - } - - /** - * @return string - */ - public function popupServiceResult($sTypeStr, $sLoginUrl, $bLogin, $iErrorCode) - { - $sResult = ''; - $bAppCssDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_css', false); - - $sIcon = $sTypeStr; - if ('facebook' === $sIcon) - { - $sIcon = $sIcon.'-alt'; - } - - if ($sLoginUrl) - { - $this->oHttp->ServerNoCache(); - @\header('Content-Type: text/html; charset=utf-8'); - - $sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Social.html'), array( - '{{RefreshMeta}}' => '', - '{{Stylesheet}}' => $this->oActions->StaticPath('css/social'.($bAppCssDebug ? '' : '.min').'.css'), - '{{Icon}}' => $sIcon, - '{{Script}}' => '' - )); - } - else - { - $this->oHttp->ServerNoCache(); - @\header('Content-Type: text/html; charset=utf-8'); - - $sCallBackType = $bLogin ? '_login' : ''; - $sConnectionFunc = 'rl_'.\md5(\RainLoop\Utils::GetConnectionToken()).'_'.$sTypeStr.$sCallBackType.'_service'; - - $sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Social.html'), array( - '{{RefreshMeta}}' => '', - '{{Stylesheet}}' => $this->oActions->StaticPath('css/social'.($bAppCssDebug ? '' : '.min').'.css'), - '{{Icon}}' => $sIcon, - '{{Script}}' => '' - )); - } - - return $sResult; - } - - /** - * @return string - */ - public function GooglePopupService($bGmail = false) - { - $sLoginUrl = ''; - $oAccount = null; - - $bLogin = false; - $iErrorCode = \RainLoop\Notifications::UnknownError; - - try - { - $oGoogle = $this->GoogleConnector(); - if ($this->oHttp->HasQuery('error')) - { - $iErrorCode = ('access_denied' === $this->oHttp->GetQuery('error')) ? - \RainLoop\Notifications::SocialGoogleLoginAccessDisable : \RainLoop\Notifications::UnknownError; - } - else if ($oGoogle) - { - $oAccount = $this->oActions->GetAccount(); - $bLogin = !$oAccount; - - $sCheckToken = ''; - $sCheckAuth = ''; - $sState = $this->oHttp->GetQuery('state'); - if (!empty($sState)) - { - $aParts = explode('|', $sState, 3); - - if (!$bGmail) - { - $bGmail = !empty($aParts[0]) ? '1' === (string) $aParts[0] : false; - } - - $sCheckToken = !empty($aParts[1]) ? $aParts[1] : ''; - $sCheckAuth = !empty($aParts[2]) ? $aParts[2] : ''; - } - - $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialGoogle'; - if (!$this->oHttp->HasQuery('code')) - { - $aParams = array( - 'scope' => \trim(\implode(' ', array( - 'https://www.googleapis.com/auth/userinfo.email', - 'https://www.googleapis.com/auth/userinfo.profile', - $bGmail ? 'https://mail.google.com/' : '' - ))), - 'state' => ($bGmail ? '1' : '0').'|'.\RainLoop\Utils::GetConnectionToken().'|'.$this->oActions->GetSpecAuthToken(), - 'response_type' => 'code' - ); - -// if ($bGmail) -// { -// $aParams['access_type'] = 'offline'; -// $aParams['approval_prompt'] = 'force'; -// } - - $sLoginUrl = $oGoogle->getAuthenticationUrl('https://accounts.google.com/o/oauth2/auth', $sRedirectUrl, $aParams); - } - else if (!empty($sState) && $sCheckToken === \RainLoop\Utils::GetConnectionToken()) - { - if (!empty($sCheckAuth)) - { - $this->oActions->SetSpecAuthToken($sCheckAuth); - $oAccount = $this->oActions->GetAccount(); - $bLogin = !$oAccount; - } - - $aParams = array('code' => $this->oHttp->GetQuery('code'), 'redirect_uri' => $sRedirectUrl); - $aAuthorizationResponse = $oGoogle->getAccessToken('https://accounts.google.com/o/oauth2/token', 'authorization_code', $aParams); - - if (!empty($aAuthorizationResponse['result']['access_token'])) - { - $oGoogle->setAccessToken($aAuthorizationResponse['result']['access_token']); - $aUserInfoResponse = $oGoogle->fetch('https://www.googleapis.com/oauth2/v2/userinfo'); - - if (!empty($aUserInfoResponse['result']['id'])) - { - if ($bLogin) - { - $aUserData = null; - if ($bGmail) - { - if (!empty($aUserInfoResponse['result']['email'])) - { - $aUserData = array( - 'Email' => $aUserInfoResponse['result']['email'], - 'Password' => APP_GOOGLE_ACCESS_TOKEN_PREFIX.$aAuthorizationResponse['result']['access_token'] - ); - } - } - else - { - $sUserData = $this->oActions->StorageProvider()->Get(null, - \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, - $this->GoogleUserLoginStorageKey($oGoogle, $aUserInfoResponse['result']['id']) - ); - - $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData); - } - - if ($aUserData && \is_array($aUserData) && - !empty($aUserData['Email']) && isset($aUserData['Password'])) - { - $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']); - } - else - { - $iErrorCode = \RainLoop\Notifications::SocialGoogleLoginAccessDisable; - } - } - - if ($oAccount && !$bGmail) - { - $aUserData = array( - 'ID' => $aUserInfoResponse['result']['id'], - 'Email' => $oAccount->Email(), - 'Password' => $oAccount->Password() - ); - - $sSocialName = !empty($aUserInfoResponse['result']['name']) ? $aUserInfoResponse['result']['name'] : ''; - $sSocialName .= !empty($aUserInfoResponse['result']['email']) ? ' ('.$aUserInfoResponse['result']['email'].')' : ''; - $sSocialName = \trim($sSocialName); - - $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); - - $oSettings->SetConf('GoogleAccessToken', \RainLoop\Utils::EncodeKeyValues(array( - 'id' => $aUserInfoResponse['result']['id'] - ))); - - $oSettings->SetConf('GoogleSocialName', $sSocialName); - - $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); - - $this->oActions->StorageProvider()->Put(null, - \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, - $this->GoogleUserLoginStorageKey($oGoogle, $aUserInfoResponse['result']['id']), - \RainLoop\Utils::EncodeKeyValues($aUserData)); - - $iErrorCode = 0; - } - } - } - } - } - } - catch (\Exception $oException) - { - $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); - } - - return $this->popupServiceResult('google', $sLoginUrl, $bLogin, $iErrorCode); - } - - /** - * @return string - */ - public function FacebookPopupService() - { - $sLoginUrl = ''; - $sSocialName = ''; - - $mData = false; - $sUserData = ''; - $aUserData = false; - $oAccount = null; - - $bLogin = false; - $iErrorCode = \RainLoop\Notifications::UnknownError; - - if (0 === \strlen($this->oActions->GetSpecAuthToken()) && $this->oHttp->HasQuery('rlah')) - { - $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', '')); - } - - $oAccount = $this->oActions->GetAccount(); - - $sRedirectUrl = ''; - $oFacebook = $this->FacebookConnector($oAccount, $sRedirectUrl); - if ($oFacebook) - { - try - { - $oRedirectLoginHelper = $oFacebook->getRedirectLoginHelper(); - $oAccessToken = $oRedirectLoginHelper->getAccessToken(); - - if (!$oAccessToken && !$this->oHttp->HasQuery('state')) - { - $sLoginUrl = $oFacebook->getRedirectLoginHelper()->getLoginUrl($sRedirectUrl.'&display=popup'); - } - else if ($oAccessToken) - { - $oResponse = $oFacebook->get('/me?fields=id,name', (string) $oAccessToken); - $oGraphUser = $oResponse->getGraphUser(); - - $mData = $oGraphUser->getId(); - $sSocialName = $oGraphUser->getName(); - - if ($oAccount) - { - if ($mData && 0 < \strlen($mData)) - { - $aUserData = array( - 'id' => $mData, - 'Email' => $oAccount->Email(), - 'Password' => $oAccount->Password() - ); - - $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); - $oSettings->SetConf('FacebookSocialName', $sSocialName); - $oSettings->SetConf('FacebookAccessToken', \RainLoop\Utils::EncodeKeyValues(array('id' => $mData))); - - $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); - - $this->oActions->StorageProvider()->Put(null, - \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, - $this->FacebookUserLoginStorageKey($oFacebook, $mData), - \RainLoop\Utils::EncodeKeyValues($aUserData)); - - $iErrorCode = 0; - } - } - else - { - $bLogin = true; - - if ($mData && 0 < \strlen($mData)) - { - $sUserData = $this->oActions->StorageProvider()->Get(null, - \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, - $this->FacebookUserLoginStorageKey($oFacebook, $mData)); - - if ($sUserData) - { - $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData); - } - } - - if ($aUserData && \is_array($aUserData) && - !empty($aUserData['Email']) && isset($aUserData['Password'])) - { - $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']); - } - else - { - $iErrorCode = \RainLoop\Notifications::SocialFacebookLoginAccessDisable; - } - } - } - } - catch (\Exception $oException) - { - $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); - } - } - - return $this->popupServiceResult('facebook', $sLoginUrl, $bLogin, $iErrorCode); - } - - /** - * @return string - */ - public function TwitterPopupService() - { - $sLoginUrl = ''; - - $sSocialName = ''; - $oAccount = null; - - $bLogin = false; - $iErrorCode = \RainLoop\Notifications::UnknownError; - - $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialTwitter'; - if (0 < strlen($this->oActions->GetSpecAuthToken())) - { - $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken(); - } - else if ($this->oHttp->HasQuery('rlah')) - { - $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', '')); - $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken(); - } - - try - { - $oTwitter = $this->TwitterConnector(); - if ($oTwitter) - { - $sSessionKey = \implode('_', array('twitter', - \md5($oTwitter->config['consumer_secret']), \md5(\RainLoop\Utils::GetConnectionToken()), 'AuthSessionData')); - - $oAccount = $this->oActions->GetAccount(); - if ($oAccount) - { - if (isset($_REQUEST['oauth_verifier'])) - { - $sAuth = $this->oActions->Cacher()->Get($sSessionKey); - $oAuth = $sAuth ? \json_decode($sAuth, true) : null; - - if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret'])) - { - $oTwitter->config['user_token'] = $oAuth['oauth_token']; - $oTwitter->config['user_secret'] = $oAuth['oauth_token_secret']; - - $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array( - 'oauth_callback' => $sRedirectUrl, - 'oauth_verifier' => $_REQUEST['oauth_verifier'] - )); - - if (200 === $iCode && isset($oTwitter->response['response'])) - { - $aAccessToken = $oTwitter->extract_params($oTwitter->response['response']); - if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id'])) - { - $aAccessToken['id'] = $aAccessToken['user_id']; - - $oTwitter->config['user_token'] = $aAccessToken['oauth_token']; - $oTwitter->config['user_secret'] = $aAccessToken['oauth_token_secret']; - - $sSocialName = !empty($aAccessToken['screen_name']) ? '@'.$aAccessToken['screen_name'] : $aAccessToken['user_id']; - $sSocialName = \trim($sSocialName); - - $aUserData = array( - 'id' => $aAccessToken['id'], - 'Email' => $oAccount->Email(), - 'Password' => $oAccount->Password() - ); - - $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); - $oSettings->SetConf('TwitterAccessToken', \RainLoop\Utils::EncodeKeyValues($aAccessToken)); - $oSettings->SetConf('TwitterSocialName', $sSocialName); - $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); - - $this->oActions->StorageProvider()->Put(null, - \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, - $this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['id']), - \RainLoop\Utils::EncodeKeyValues($aUserData)); - - $iErrorCode = 0; - } - } - } - } - else - { - $aParams = array( - 'oauth_callback' => $sRedirectUrl, - 'x_auth_access_type' => 'read' - ); - - $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams); - if (200 === $iCode && isset($oTwitter->response['response'])) - { - $oAuth = $oTwitter->extract_params($oTwitter->response['response']); - if (!empty($oAuth['oauth_token'])) - { - $this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth)); - $sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token']; - } - } - } - } - else - { - $bLogin = true; - - if (isset($_REQUEST['oauth_verifier'])) - { - $sAuth = $this->oActions->Cacher()->Get($sSessionKey); - $oAuth = $sAuth ? \json_decode($sAuth, true) : null; - if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret'])) - { - $oTwitter->config['user_token'] = $oAuth['oauth_token']; - $oTwitter->config['user_secret'] = $oAuth['oauth_token_secret']; - - $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array( - 'oauth_callback' => $sRedirectUrl, - 'oauth_verifier' => $_REQUEST['oauth_verifier'] - )); - - if (200 === $iCode && isset($oTwitter->response['response'])) - { - $aAccessToken = $oTwitter->extract_params($oTwitter->response['response']); - if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id'])) - { - $sUserData = $this->oActions->StorageProvider()->Get(null, - \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, - $this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['user_id']) - ); - - $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData); - - if ($aUserData && \is_array($aUserData) && - !empty($aUserData['Email']) && isset($aUserData['Password'])) - { - $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']); - } - else - { - $iErrorCode = \RainLoop\Notifications::SocialTwitterLoginAccessDisable; - } - - $this->oActions->Cacher()->Delete($sSessionKey); - } - } - } - } - else - { - $aParams = array( - 'oauth_callback' => $sRedirectUrl, - 'x_auth_access_type' => 'read' - ); - - $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams); - if (200 === $iCode && isset($oTwitter->response['response'])) - { - $oAuth = $oTwitter->extract_params($oTwitter->response['response']); - if (!empty($oAuth['oauth_token'])) - { - $this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth)); - $sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token']; - } - } - } - } - } - } - catch (\Exception $oException) - { - $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); - } - - return $this->popupServiceResult('twitter', $sLoginUrl, $bLogin, $iErrorCode); - } - - /** - * @return \OAuth2\Client|null - */ - public function GoogleConnector() - { - $oGoogle = false; - $oConfig = $this->oActions->Config(); - if ($oConfig->Get('social', 'google_enable', false) && - '' !== \trim($oConfig->Get('social', 'google_client_id', '')) && - '' !== \trim($oConfig->Get('social', 'google_client_secret', ''))) - { - include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/Client.php'; - include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/IGrantType.php'; - include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php'; - include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/RefreshToken.php'; - - try - { - $oGoogle = new \OAuth2\Client( - \trim($oConfig->Get('social', 'google_client_id', '')), - \trim($oConfig->Get('social', 'google_client_secret', ''))); - - $sProxy = $this->oActions->Config()->Get('labs', 'curl_proxy', ''); - if (0 < \strlen($sProxy)) - { - $oGoogle->setCurlOption(CURLOPT_PROXY, $sProxy); - - $sProxyAuth = $this->oActions->Config()->Get('labs', 'curl_proxy_auth', ''); - if (0 < \strlen($sProxyAuth)) - { - $oGoogle->setCurlOption(CURLOPT_PROXYUSERPWD, $sProxyAuth); - } - } - } - catch (\Exception $oException) - { - $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); - } - } - - return false === $oGoogle ? null : $oGoogle; - } - - /** - * @return \tmhOAuth|null - */ - public function TwitterConnector() - { - $oTwitter = false; - $oConfig = $this->oActions->Config(); - if ($oConfig->Get('social', 'twitter_enable', false) && - '' !== \trim($oConfig->Get('social', 'twitter_consumer_key', '')) && - '' !== \trim($oConfig->Get('social', 'twitter_consumer_secret', ''))) - { - include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhOAuth.php'; - include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhUtilities.php'; - - $sProxy = $this->oActions->Config()->Get('labs', 'curl_proxy', ''); - $sProxyAuth = $this->oActions->Config()->Get('labs', 'curl_proxy_auth', ''); - - $oTwitter = new \tmhOAuth(array( - 'consumer_key' => \trim($oConfig->Get('social', 'twitter_consumer_key', '')), - 'consumer_secret' => \trim($oConfig->Get('social', 'twitter_consumer_secret', '')), - 'curl_proxy' => 0 < \strlen($sProxy) ? $sProxy : false, - 'curl_proxyuserpwd' => 0 < \strlen($sProxyAuth) ? $sProxyAuth : false - )); - } - - return false === $oTwitter ? null : $oTwitter; - } - - /** - * @param \RainLoop\Model\Account|null $oAccount = null - * @param string $sRedirectUrl = '' - * - * @return \RainLoop\Common\RainLoopFacebookRedirectLoginHelper|null - */ - public function FacebookConnector($oAccount = null, &$sRedirectUrl = '') - { - $oFacebook = false; - $oConfig = $this->oActions->Config(); - $sAppID = \trim($oConfig->Get('social', 'fb_app_id', '')); - $sAppSecret = \trim($oConfig->Get('social', 'fb_app_secret', '')); - - if (\version_compare(PHP_VERSION, '5.4.0', '>=') && - $oConfig->Get('social', 'fb_enable', false) && '' !== $sAppID && - '' !== \trim($oConfig->Get('social', 'fb_app_secret', '')) && - \class_exists('Facebook\Facebook') - ) - { - $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialFacebook'; - if (0 < \strlen($this->oActions->GetSpecAuthToken())) - { - $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken(); - } - else if ($this->oHttp->HasQuery('rlah')) - { - $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', '')); - $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken(); - } - - try - { - $oAccount = $this->oActions->GetAccount(); - - $oFacebook = new \Facebook\Facebook(array( - 'app_id' => $sAppID, // Replace {app-id} with your app id - 'app_secret' => $sAppSecret, - 'persistent_data_handler' => new \RainLoop\Common\FacebookRainLoopPersistentDataHandler( - $oAccount, \RainLoop\Utils::GetConnectionToken(), $this->oActions->StorageProvider() - ) - )); - } - catch (\Exception $oException) - { - $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); - } - } - - return false === $oFacebook ? null : $oFacebook; - } - - /** - * @return string - */ - public function GoogleUserLoginStorageKey($oGoogle, $sGoogleUserId) - { - return \implode('_', array('google', \md5($oGoogle->getClientId()), $sGoogleUserId, APP_SALT)); - } - - /** - * @return string - */ - public function FacebookUserLoginStorageKey($oFacebook, $sFacebookUserId) - { - return \implode('_', array('facebookNew', \md5($oFacebook->getApp()->getId()), $sFacebookUserId, APP_SALT)); - } - - /** - * @return string - */ - public function TwitterUserLoginStorageKey($oTwitter, $sTwitterUserId) - { - return \implode('_', array('twitter_2', \md5($oTwitter->config['consumer_secret']), $sTwitterUserId, APP_SALT)); - } - - /** - * @param \RainLoop\Model\Account|null $oAccount - * @param string $sEmail - * @param string $sPassword - * - * @return int - */ - private function loginProcess(&$oAccount, $sEmail, $sPassword) - { - $iErrorCode = \RainLoop\Notifications::UnknownError; - - try - { - $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword, '', '', false, true); - if ($oAccount instanceof \RainLoop\Model\Account) - { - $this->oActions->AuthToken($oAccount); - $iErrorCode = 0; - } - else - { - $oAccount = null; - $iErrorCode = \RainLoop\Notifications::AuthError; - } - } - catch (\RainLoop\Exceptions\ClientException $oException) - { - $iErrorCode = $oException->getCode(); - } - catch (\Exception $oException) - { - unset($oException); - $iErrorCode = \RainLoop\Notifications::UnknownError; - } - - return $iErrorCode; - } +oHttp = $oHttp; + $this->oActions = $oActions; + } + + /** + * @return bool + */ + public function GoogleDisconnect($oAccount) + { + $oGoogle = $this->GoogleConnector(); + if ($oAccount && $oGoogle) + { + $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); + $sEncodedeData = $oSettings->GetConf('GoogleAccessToken', ''); + + if (!empty($sEncodedeData)) + { + $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData); + if (\is_array($aData) && !empty($aData['id'])) + { + $this->oActions->StorageProvider()->Clear(null, + \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, + $this->GoogleUserLoginStorageKey($oGoogle, $aData['id']) + ); + } + } + + $oSettings->SetConf('GoogleAccessToken', ''); + $oSettings->SetConf('GoogleSocialName', ''); + + return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); + } + + return false; + } + + /** + * @return bool + */ + public function FacebookDisconnect($oAccount) + { + $oFacebook = $this->FacebookConnector($oAccount ? $oAccount : null); + if ($oAccount && $oFacebook) + { + $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); + + $sEncodedeData = $oSettings->GetConf('FacebookAccessToken', ''); + + if (!empty($sEncodedeData)) + { + $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData); + if (is_array($aData) && isset($aData['id'])) + { + $this->oActions->StorageProvider()->Clear(null, + \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, + $this->FacebookUserLoginStorageKey($oFacebook, $aData['id']) + ); + } + } + + $oSettings->SetConf('FacebookAccessToken', ''); + $oSettings->SetConf('FacebookSocialName', ''); + + return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); + } + + return false; + } + + /** + * @return bool + */ + public function TwitterDisconnect($oAccount) + { + $oTwitter = $this->TwitterConnector(); + if ($oAccount && $oTwitter) + { + $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); + $sEncodedData = $oSettings->GetConf('TwitterAccessToken', ''); + + if (!empty($sEncodedData)) + { + $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedData); + if (is_array($aData) && isset($aData['id'])) + { + $this->oActions->StorageProvider()->Clear(null, + \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, + $this->TwitterUserLoginStorageKey($oTwitter, $aData['id']) + ); + } + } + + $oSettings->SetConf('TwitterAccessToken', ''); + $oSettings->SetConf('TwitterSocialName', ''); + + return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); + } + + return false; + } + + /** + * @return string + */ + public function popupServiceResult($sTypeStr, $sLoginUrl, $bLogin, $iErrorCode) + { + $sResult = ''; + $bAppCssDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_css', false); + + $sIcon = $sTypeStr; + if ('facebook' === $sIcon) + { + $sIcon = $sIcon.'-alt'; + } + + if ($sLoginUrl) + { + $this->oHttp->ServerNoCache(); + @\header('Content-Type: text/html; charset=utf-8'); + + $sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Social.html'), array( + '{{RefreshMeta}}' => '', + '{{Stylesheet}}' => $this->oActions->StaticPath('css/social'.($bAppCssDebug ? '' : '.min').'.css'), + '{{Icon}}' => $sIcon, + '{{Script}}' => '' + )); + } + else + { + $this->oHttp->ServerNoCache(); + @\header('Content-Type: text/html; charset=utf-8'); + + $sCallBackType = $bLogin ? '_login' : ''; + $sConnectionFunc = 'rl_'.\md5(\RainLoop\Utils::GetConnectionToken()).'_'.$sTypeStr.$sCallBackType.'_service'; + + $sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Social.html'), array( + '{{RefreshMeta}}' => '', + '{{Stylesheet}}' => $this->oActions->StaticPath('css/social'.($bAppCssDebug ? '' : '.min').'.css'), + '{{Icon}}' => $sIcon, + '{{Script}}' => '' + )); + } + + return $sResult; + } + + /** + * @return string + */ + public function GooglePopupService($bGmail = false) + { + $sLoginUrl = ''; + $oAccount = null; + + $bLogin = false; + $iErrorCode = \RainLoop\Notifications::UnknownError; + + try + { + $oGoogle = $this->GoogleConnector(); + if ($this->oHttp->HasQuery('error')) + { + $iErrorCode = ('access_denied' === $this->oHttp->GetQuery('error')) ? + \RainLoop\Notifications::SocialGoogleLoginAccessDisable : \RainLoop\Notifications::UnknownError; + } + else if ($oGoogle) + { + $oAccount = $this->oActions->GetAccount(); + $bLogin = !$oAccount; + + $sCheckToken = ''; + $sCheckAuth = ''; + $sState = $this->oHttp->GetQuery('state'); + if (!empty($sState)) + { + $aParts = explode('|', $sState, 3); + + if (!$bGmail) + { + $bGmail = !empty($aParts[0]) ? '1' === (string) $aParts[0] : false; + } + + $sCheckToken = !empty($aParts[1]) ? $aParts[1] : ''; + $sCheckAuth = !empty($aParts[2]) ? $aParts[2] : ''; + } + + $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialGoogle'; + if (!$this->oHttp->HasQuery('code')) + { + $aParams = array( + 'scope' => \trim(\implode(' ', array( + 'https://www.googleapis.com/auth/userinfo.email', + 'https://www.googleapis.com/auth/userinfo.profile', + $bGmail ? 'https://mail.google.com/' : '' + ))), + 'state' => ($bGmail ? '1' : '0').'|'.\RainLoop\Utils::GetConnectionToken().'|'.$this->oActions->GetSpecAuthToken(), + 'response_type' => 'code' + ); + +// if ($bGmail) +// { +// $aParams['access_type'] = 'offline'; +// $aParams['approval_prompt'] = 'force'; +// } + + $sLoginUrl = $oGoogle->getAuthenticationUrl('https://accounts.google.com/o/oauth2/auth', $sRedirectUrl, $aParams); + } + else if (!empty($sState) && $sCheckToken === \RainLoop\Utils::GetConnectionToken()) + { + if (!empty($sCheckAuth)) + { + $this->oActions->SetSpecAuthToken($sCheckAuth); + $oAccount = $this->oActions->GetAccount(); + $bLogin = !$oAccount; + } + + $aParams = array('code' => $this->oHttp->GetQuery('code'), 'redirect_uri' => $sRedirectUrl); + $aAuthorizationResponse = $oGoogle->getAccessToken('https://accounts.google.com/o/oauth2/token', 'authorization_code', $aParams); + + if (!empty($aAuthorizationResponse['result']['access_token'])) + { + $oGoogle->setAccessToken($aAuthorizationResponse['result']['access_token']); + $aUserInfoResponse = $oGoogle->fetch('https://www.googleapis.com/oauth2/v2/userinfo'); + + if (!empty($aUserInfoResponse['result']['id'])) + { + if ($bLogin) + { + $aUserData = null; + if ($bGmail) + { + if (!empty($aUserInfoResponse['result']['email'])) + { + $aUserData = array( + 'Email' => $aUserInfoResponse['result']['email'], + 'Password' => APP_GOOGLE_ACCESS_TOKEN_PREFIX.$aAuthorizationResponse['result']['access_token'] + ); + } + } + else + { + $sUserData = $this->oActions->StorageProvider()->Get(null, + \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, + $this->GoogleUserLoginStorageKey($oGoogle, $aUserInfoResponse['result']['id']) + ); + + $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData); + } + + if ($aUserData && \is_array($aUserData) && + !empty($aUserData['Email']) && isset($aUserData['Password'])) + { + $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']); + } + else + { + $iErrorCode = \RainLoop\Notifications::SocialGoogleLoginAccessDisable; + } + } + + if ($oAccount && !$bGmail) + { + $aUserData = array( + 'ID' => $aUserInfoResponse['result']['id'], + 'Email' => $oAccount->Email(), + 'Password' => $oAccount->Password() + ); + + $sSocialName = !empty($aUserInfoResponse['result']['name']) ? $aUserInfoResponse['result']['name'] : ''; + $sSocialName .= !empty($aUserInfoResponse['result']['email']) ? ' ('.$aUserInfoResponse['result']['email'].')' : ''; + $sSocialName = \trim($sSocialName); + + $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); + + $oSettings->SetConf('GoogleAccessToken', \RainLoop\Utils::EncodeKeyValues(array( + 'id' => $aUserInfoResponse['result']['id'] + ))); + + $oSettings->SetConf('GoogleSocialName', $sSocialName); + + $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); + + $this->oActions->StorageProvider()->Put(null, + \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, + $this->GoogleUserLoginStorageKey($oGoogle, $aUserInfoResponse['result']['id']), + \RainLoop\Utils::EncodeKeyValues($aUserData)); + + $iErrorCode = 0; + } + } + } + } + } + } + catch (\Exception $oException) + { + $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); + } + + return $this->popupServiceResult('google', $sLoginUrl, $bLogin, $iErrorCode); + } + + /** + * @return string + */ + public function FacebookPopupService() + { + $sLoginUrl = ''; + $sSocialName = ''; + + $mData = false; + $sUserData = ''; + $aUserData = false; + $oAccount = null; + + $bLogin = false; + $iErrorCode = \RainLoop\Notifications::UnknownError; + + if (0 === \strlen($this->oActions->GetSpecAuthToken()) && $this->oHttp->HasQuery('rlah')) + { + $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', '')); + } + + $oAccount = $this->oActions->GetAccount(); + + $sRedirectUrl = ''; + $oFacebook = $this->FacebookConnector($oAccount, $sRedirectUrl); + if ($oFacebook) + { + try + { + $oRedirectLoginHelper = $oFacebook->getRedirectLoginHelper(); + $oAccessToken = $oRedirectLoginHelper->getAccessToken(); + + if (!$oAccessToken && !$this->oHttp->HasQuery('state')) + { + $sLoginUrl = $oFacebook->getRedirectLoginHelper()->getLoginUrl($sRedirectUrl.'&display=popup'); + } + else if ($oAccessToken) + { + $oResponse = $oFacebook->get('/me?fields=id,name', (string) $oAccessToken); + $oGraphUser = $oResponse->getGraphUser(); + + $mData = $oGraphUser->getId(); + $sSocialName = $oGraphUser->getName(); + + if ($oAccount) + { + if ($mData && 0 < \strlen($mData)) + { + $aUserData = array( + 'id' => $mData, + 'Email' => $oAccount->Email(), + 'Password' => $oAccount->Password() + ); + + $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); + $oSettings->SetConf('FacebookSocialName', $sSocialName); + $oSettings->SetConf('FacebookAccessToken', \RainLoop\Utils::EncodeKeyValues(array('id' => $mData))); + + $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); + + $this->oActions->StorageProvider()->Put(null, + \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, + $this->FacebookUserLoginStorageKey($oFacebook, $mData), + \RainLoop\Utils::EncodeKeyValues($aUserData)); + + $iErrorCode = 0; + } + } + else + { + $bLogin = true; + + if ($mData && 0 < \strlen($mData)) + { + $sUserData = $this->oActions->StorageProvider()->Get(null, + \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, + $this->FacebookUserLoginStorageKey($oFacebook, $mData)); + + if ($sUserData) + { + $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData); + } + } + + if ($aUserData && \is_array($aUserData) && + !empty($aUserData['Email']) && isset($aUserData['Password'])) + { + $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']); + } + else + { + $iErrorCode = \RainLoop\Notifications::SocialFacebookLoginAccessDisable; + } + } + } + } + catch (\Exception $oException) + { + $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); + } + } + + return $this->popupServiceResult('facebook', $sLoginUrl, $bLogin, $iErrorCode); + } + + /** + * @return string + */ + public function TwitterPopupService() + { + $sLoginUrl = ''; + + $sSocialName = ''; + $oAccount = null; + + $bLogin = false; + $iErrorCode = \RainLoop\Notifications::UnknownError; + + $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialTwitter'; + if (0 < strlen($this->oActions->GetSpecAuthToken())) + { + $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken(); + } + else if ($this->oHttp->HasQuery('rlah')) + { + $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', '')); + $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken(); + } + + try + { + $oTwitter = $this->TwitterConnector(); + if ($oTwitter) + { + $sSessionKey = \implode('_', array('twitter', + \md5($oTwitter->config['consumer_secret']), \md5(\RainLoop\Utils::GetConnectionToken()), 'AuthSessionData')); + + $oAccount = $this->oActions->GetAccount(); + if ($oAccount) + { + if (isset($_REQUEST['oauth_verifier'])) + { + $sAuth = $this->oActions->Cacher()->Get($sSessionKey); + $oAuth = $sAuth ? \json_decode($sAuth, true) : null; + + if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret'])) + { + $oTwitter->config['user_token'] = $oAuth['oauth_token']; + $oTwitter->config['user_secret'] = $oAuth['oauth_token_secret']; + + $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array( + 'oauth_callback' => $sRedirectUrl, + 'oauth_verifier' => $_REQUEST['oauth_verifier'] + )); + + if (200 === $iCode && isset($oTwitter->response['response'])) + { + $aAccessToken = $oTwitter->extract_params($oTwitter->response['response']); + if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id'])) + { + $aAccessToken['id'] = $aAccessToken['user_id']; + + $oTwitter->config['user_token'] = $aAccessToken['oauth_token']; + $oTwitter->config['user_secret'] = $aAccessToken['oauth_token_secret']; + + $sSocialName = !empty($aAccessToken['screen_name']) ? '@'.$aAccessToken['screen_name'] : $aAccessToken['user_id']; + $sSocialName = \trim($sSocialName); + + $aUserData = array( + 'id' => $aAccessToken['id'], + 'Email' => $oAccount->Email(), + 'Password' => $oAccount->Password() + ); + + $oSettings = $this->oActions->SettingsProvider()->Load($oAccount); + $oSettings->SetConf('TwitterAccessToken', \RainLoop\Utils::EncodeKeyValues($aAccessToken)); + $oSettings->SetConf('TwitterSocialName', $sSocialName); + $this->oActions->SettingsProvider()->Save($oAccount, $oSettings); + + $this->oActions->StorageProvider()->Put(null, + \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, + $this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['id']), + \RainLoop\Utils::EncodeKeyValues($aUserData)); + + $iErrorCode = 0; + } + } + } + } + else + { + $aParams = array( + 'oauth_callback' => $sRedirectUrl, + 'x_auth_access_type' => 'read' + ); + + $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams); + if (200 === $iCode && isset($oTwitter->response['response'])) + { + $oAuth = $oTwitter->extract_params($oTwitter->response['response']); + if (!empty($oAuth['oauth_token'])) + { + $this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth)); + $sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token']; + } + } + } + } + else + { + $bLogin = true; + + if (isset($_REQUEST['oauth_verifier'])) + { + $sAuth = $this->oActions->Cacher()->Get($sSessionKey); + $oAuth = $sAuth ? \json_decode($sAuth, true) : null; + if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret'])) + { + $oTwitter->config['user_token'] = $oAuth['oauth_token']; + $oTwitter->config['user_secret'] = $oAuth['oauth_token_secret']; + + $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array( + 'oauth_callback' => $sRedirectUrl, + 'oauth_verifier' => $_REQUEST['oauth_verifier'] + )); + + if (200 === $iCode && isset($oTwitter->response['response'])) + { + $aAccessToken = $oTwitter->extract_params($oTwitter->response['response']); + if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id'])) + { + $sUserData = $this->oActions->StorageProvider()->Get(null, + \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, + $this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['user_id']) + ); + + $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData); + + if ($aUserData && \is_array($aUserData) && + !empty($aUserData['Email']) && isset($aUserData['Password'])) + { + $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']); + } + else + { + $iErrorCode = \RainLoop\Notifications::SocialTwitterLoginAccessDisable; + } + + $this->oActions->Cacher()->Delete($sSessionKey); + } + } + } + } + else + { + $aParams = array( + 'oauth_callback' => $sRedirectUrl, + 'x_auth_access_type' => 'read' + ); + + $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams); + if (200 === $iCode && isset($oTwitter->response['response'])) + { + $oAuth = $oTwitter->extract_params($oTwitter->response['response']); + if (!empty($oAuth['oauth_token'])) + { + $this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth)); + $sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token']; + } + } + } + } + } + } + catch (\Exception $oException) + { + $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); + } + + return $this->popupServiceResult('twitter', $sLoginUrl, $bLogin, $iErrorCode); + } + + /** + * @return \OAuth2\Client|null + */ + public function GoogleConnector() + { + $oGoogle = false; + $oConfig = $this->oActions->Config(); + if ($oConfig->Get('social', 'google_enable', false) && + '' !== \trim($oConfig->Get('social', 'google_client_id', '')) && + '' !== \trim($oConfig->Get('social', 'google_client_secret', ''))) + { + include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/Client.php'; + include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/IGrantType.php'; + include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php'; + include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/RefreshToken.php'; + + try + { + $oGoogle = new \OAuth2\Client( + \trim($oConfig->Get('social', 'google_client_id', '')), + \trim($oConfig->Get('social', 'google_client_secret', ''))); + + $sProxy = $this->oActions->Config()->Get('labs', 'curl_proxy', ''); + if (0 < \strlen($sProxy)) + { + $oGoogle->setCurlOption(CURLOPT_PROXY, $sProxy); + + $sProxyAuth = $this->oActions->Config()->Get('labs', 'curl_proxy_auth', ''); + if (0 < \strlen($sProxyAuth)) + { + $oGoogle->setCurlOption(CURLOPT_PROXYUSERPWD, $sProxyAuth); + } + } + } + catch (\Exception $oException) + { + $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); + } + } + + return false === $oGoogle ? null : $oGoogle; + } + + /** + * @return \tmhOAuth|null + */ + public function TwitterConnector() + { + $oTwitter = false; + $oConfig = $this->oActions->Config(); + if ($oConfig->Get('social', 'twitter_enable', false) && + '' !== \trim($oConfig->Get('social', 'twitter_consumer_key', '')) && + '' !== \trim($oConfig->Get('social', 'twitter_consumer_secret', ''))) + { + include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhOAuth.php'; + include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhUtilities.php'; + + $sProxy = $this->oActions->Config()->Get('labs', 'curl_proxy', ''); + $sProxyAuth = $this->oActions->Config()->Get('labs', 'curl_proxy_auth', ''); + + $oTwitter = new \tmhOAuth(array( + 'consumer_key' => \trim($oConfig->Get('social', 'twitter_consumer_key', '')), + 'consumer_secret' => \trim($oConfig->Get('social', 'twitter_consumer_secret', '')), + 'curl_proxy' => 0 < \strlen($sProxy) ? $sProxy : false, + 'curl_proxyuserpwd' => 0 < \strlen($sProxyAuth) ? $sProxyAuth : false + )); + } + + return false === $oTwitter ? null : $oTwitter; + } + + /** + * @param \RainLoop\Model\Account|null $oAccount = null + * @param string $sRedirectUrl = '' + * + * @return \RainLoop\Common\RainLoopFacebookRedirectLoginHelper|null + */ + public function FacebookConnector($oAccount = null, &$sRedirectUrl = '') + { + $oFacebook = false; + $oConfig = $this->oActions->Config(); + $sAppID = \trim($oConfig->Get('social', 'fb_app_id', '')); + $sAppSecret = \trim($oConfig->Get('social', 'fb_app_secret', '')); + + if (\version_compare(PHP_VERSION, '5.4.0', '>=') && + $oConfig->Get('social', 'fb_enable', false) && '' !== $sAppID && + '' !== \trim($oConfig->Get('social', 'fb_app_secret', '')) && + \class_exists('Facebook\Facebook') + ) + { + $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialFacebook'; + if (0 < \strlen($this->oActions->GetSpecAuthToken())) + { + $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken(); + } + else if ($this->oHttp->HasQuery('rlah')) + { + $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', '')); + $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken(); + } + + try + { + $oAccount = $this->oActions->GetAccount(); + + $oFacebook = new \Facebook\Facebook(array( + 'app_id' => $sAppID, // Replace {app-id} with your app id + 'app_secret' => $sAppSecret, + 'persistent_data_handler' => new \RainLoop\Common\FacebookRainLoopPersistentDataHandler( + $oAccount, \RainLoop\Utils::GetConnectionToken(), $this->oActions->StorageProvider() + ) + )); + } + catch (\Exception $oException) + { + $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR); + } + } + + return false === $oFacebook ? null : $oFacebook; + } + + /** + * @return string + */ + public function GoogleUserLoginStorageKey($oGoogle, $sGoogleUserId) + { + return \implode('_', array('google', \md5($oGoogle->getClientId()), $sGoogleUserId, APP_SALT)); + } + + /** + * @return string + */ + public function FacebookUserLoginStorageKey($oFacebook, $sFacebookUserId) + { + return \implode('_', array('facebookNew', \md5($oFacebook->getApp()->getId()), $sFacebookUserId, APP_SALT)); + } + + /** + * @return string + */ + public function TwitterUserLoginStorageKey($oTwitter, $sTwitterUserId) + { + return \implode('_', array('twitter_2', \md5($oTwitter->config['consumer_secret']), $sTwitterUserId, APP_SALT)); + } + + /** + * @param \RainLoop\Model\Account|null $oAccount + * @param string $sEmail + * @param string $sPassword + * + * @return int + */ + private function loginProcess(&$oAccount, $sEmail, $sPassword) + { + $iErrorCode = \RainLoop\Notifications::UnknownError; + + try + { + $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword, '', '', false, true); + if ($oAccount instanceof \RainLoop\Model\Account) + { + $this->oActions->AuthToken($oAccount); + $iErrorCode = 0; + } + else + { + $oAccount = null; + $iErrorCode = \RainLoop\Notifications::AuthError; + } + } + catch (\RainLoop\Exceptions\ClientException $oException) + { + $iErrorCode = $oException->getCode(); + } + catch (\Exception $oException) + { + unset($oException); + $iErrorCode = \RainLoop\Notifications::UnknownError; + } + + return $iErrorCode; + } } \ No newline at end of file diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Utils.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Utils.php similarity index 92% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Utils.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Utils.php index 83b20418..ceb7f687 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Utils.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/RainLoop/Utils.php @@ -16,8 +16,6 @@ class Utils static $Cookies = null; - static $RSA = null; - static $RsaKey = null; /** @@ -45,49 +43,6 @@ static public function PgpVerifyFile($sFileName, $sSignature) return false; } - /** - * @return \Crypt_RSA|null - */ - static public function CryptRSA() - { - if (null === \RainLoop\Utils::$RSA) - { - if (!\defined('_phpseclib_')) - { - \set_include_path(\get_include_path().PATH_SEPARATOR.APP_VERSION_ROOT_PATH.'app/libraries/phpseclib'); - define('_phpseclib_', true); - } - - if (!\class_exists('Crypt_RSA', false)) - { - include_once 'Crypt/RSA.php'; - \defined('CRYPT_RSA_MODE') || \define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); - } - - if (\class_exists('Crypt_RSA')) - { - $oRsa = new \Crypt_RSA(); - - $oRsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); - $oRsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1); - $oRsa->setPrivateKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1); - - $sPrivateKey = \file_exists(APP_PRIVATE_DATA.'rsa/private') ? - \file_get_contents(APP_PRIVATE_DATA.'rsa/private') : ''; - - if (!empty($sPrivateKey)) - { - $oRsa->loadKey($sPrivateKey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1); - $oRsa->loadKey($oRsa->getPublicKey(), CRYPT_RSA_PUBLIC_FORMAT_PKCS1); - - \RainLoop\Utils::$RSA = $oRsa; - } - } - } - - return \RainLoop\Utils::$RSA; - } - /** * @return string */ diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/AbstractBackend.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Backend/AbstractBackend.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/AbstractBackend.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Backend/AbstractBackend.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/BackendInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Backend/BackendInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/BackendInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Backend/BackendInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/NotificationSupport.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Backend/NotificationSupport.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/NotificationSupport.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Backend/NotificationSupport.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/PDO.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Backend/PDO.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/PDO.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Backend/PDO.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/SharingSupport.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Backend/SharingSupport.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/SharingSupport.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Backend/SharingSupport.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Calendar.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Calendar.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Calendar.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Calendar.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarObject.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/CalendarObject.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarObject.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/CalendarObject.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryParser.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryParser.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryParser.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryParser.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryValidator.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryValidator.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryValidator.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryValidator.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarRootNode.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/CalendarRootNode.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarRootNode.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/CalendarRootNode.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Exception/InvalidComponentType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Exception/InvalidComponentType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Exception/InvalidComponentType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Exception/InvalidComponentType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICSExportPlugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/ICSExportPlugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICSExportPlugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/ICSExportPlugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICalendar.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/ICalendar.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICalendar.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/ICalendar.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICalendarObject.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/ICalendarObject.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICalendarObject.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/ICalendarObject.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/IShareableCalendar.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/IShareableCalendar.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/IShareableCalendar.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/IShareableCalendar.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ISharedCalendar.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/ISharedCalendar.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ISharedCalendar.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/ISharedCalendar.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Collection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Collection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Collection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Collection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/ICollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/ICollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/ICollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/ICollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/INode.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/INode.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/INode.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/INode.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/INotificationType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/INotificationType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/INotificationType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/INotificationType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Node.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Node.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Node.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Node.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/Invite.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/Invite.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/Invite.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/Invite.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/InviteReply.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/InviteReply.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/InviteReply.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/InviteReply.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/SystemStatus.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/SystemStatus.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/SystemStatus.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/SystemStatus.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Plugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Plugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Plugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Plugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/Collection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/Collection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/Collection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/Collection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyRead.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyRead.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyRead.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyRead.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyWrite.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyWrite.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyWrite.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyWrite.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyRead.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyRead.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyRead.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyRead.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyWrite.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyWrite.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyWrite.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyWrite.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/User.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/User.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/User.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Principal/User.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/AllowedSharingModes.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/AllowedSharingModes.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/AllowedSharingModes.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/AllowedSharingModes.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/Invite.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/Invite.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/Invite.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/Invite.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/ScheduleCalendarTransp.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/ScheduleCalendarTransp.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/ScheduleCalendarTransp.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/ScheduleCalendarTransp.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarComponentSet.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarComponentSet.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarComponentSet.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarComponentSet.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarData.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarData.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarData.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarData.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCollationSet.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCollationSet.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCollationSet.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCollationSet.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/IMip.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/IMip.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/IMip.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/IMip.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/IOutbox.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/IOutbox.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/IOutbox.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/IOutbox.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/Outbox.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/Outbox.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/Outbox.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/Outbox.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ShareableCalendar.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/ShareableCalendar.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ShareableCalendar.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/ShareableCalendar.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/SharedCalendar.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/SharedCalendar.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/SharedCalendar.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/SharedCalendar.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/SharingPlugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/SharingPlugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/SharingPlugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/SharingPlugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/UserCalendars.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/UserCalendars.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/UserCalendars.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/UserCalendars.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Version.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Version.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Version.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CalDAV/Version.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBook.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/AddressBook.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBook.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/AddressBook.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBookQueryParser.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/AddressBookQueryParser.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBookQueryParser.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/AddressBookQueryParser.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBookRoot.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/AddressBookRoot.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBookRoot.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/AddressBookRoot.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/AbstractBackend.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Backend/AbstractBackend.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/AbstractBackend.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Backend/AbstractBackend.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/BackendInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Backend/BackendInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/BackendInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Backend/BackendInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/PDO.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Backend/PDO.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/PDO.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Backend/PDO.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Card.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Card.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Card.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Card.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/IAddressBook.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/IAddressBook.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/IAddressBook.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/IAddressBook.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/ICard.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/ICard.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/ICard.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/ICard.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/IDirectory.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/IDirectory.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/IDirectory.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/IDirectory.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Plugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Plugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Plugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Plugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Property/SupportedAddressData.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Property/SupportedAddressData.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Property/SupportedAddressData.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Property/SupportedAddressData.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/UserAddressBooks.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/UserAddressBooks.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/UserAddressBooks.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/UserAddressBooks.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/VCFExportPlugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/VCFExportPlugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/VCFExportPlugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/VCFExportPlugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Version.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Version.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Version.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/CardDAV/Version.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractBasic.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractBasic.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractBasic.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractBasic.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractDigest.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractDigest.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractDigest.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractDigest.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/Apache.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/Apache.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/Apache.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/Apache.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/BackendInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/BackendInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/BackendInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/BackendInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/File.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/File.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/File.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/File.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/PDO.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/PDO.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/PDO.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/PDO.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Plugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Plugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Plugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Auth/Plugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/GuessContentType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/GuessContentType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/GuessContentType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/GuessContentType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/MapGetToPropFind.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/MapGetToPropFind.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/MapGetToPropFind.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/MapGetToPropFind.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/Plugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/Plugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/Plugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/Plugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/favicon.ico b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/favicon.ico similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/favicon.ico rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/favicon.ico diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/addressbook.png b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/addressbook.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/addressbook.png rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/addressbook.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/calendar.png b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/calendar.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/calendar.png rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/calendar.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/card.png b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/card.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/card.png rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/card.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/collection.png b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/collection.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/collection.png rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/collection.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/file.png b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/file.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/file.png rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/file.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/parent.png b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/parent.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/parent.png rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/parent.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/principal.png b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/principal.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/principal.png rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/principal.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Client.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Client.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Client.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Client.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Collection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Collection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Collection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Collection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/BadRequest.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/BadRequest.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/BadRequest.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/BadRequest.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Conflict.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/Conflict.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Conflict.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/Conflict.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ConflictingLock.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/ConflictingLock.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ConflictingLock.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/ConflictingLock.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/FileNotFound.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/FileNotFound.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/FileNotFound.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/FileNotFound.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Forbidden.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/Forbidden.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Forbidden.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/Forbidden.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/InsufficientStorage.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/InsufficientStorage.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/InsufficientStorage.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/InsufficientStorage.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/InvalidResourceType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/InvalidResourceType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/InvalidResourceType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/InvalidResourceType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/LockTokenMatchesRequestUri.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/LockTokenMatchesRequestUri.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/LockTokenMatchesRequestUri.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/LockTokenMatchesRequestUri.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Locked.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/Locked.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Locked.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/Locked.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/MethodNotAllowed.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/MethodNotAllowed.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/MethodNotAllowed.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/MethodNotAllowed.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotAuthenticated.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/NotAuthenticated.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotAuthenticated.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/NotAuthenticated.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotFound.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/NotFound.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotFound.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/NotFound.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotImplemented.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/NotImplemented.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotImplemented.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/NotImplemented.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/PaymentRequired.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/PaymentRequired.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/PaymentRequired.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/PaymentRequired.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/PreconditionFailed.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/PreconditionFailed.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/PreconditionFailed.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/PreconditionFailed.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ReportNotSupported.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/ReportNotSupported.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ReportNotSupported.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/ReportNotSupported.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/RequestedRangeNotSatisfiable.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/RequestedRangeNotSatisfiable.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/RequestedRangeNotSatisfiable.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/RequestedRangeNotSatisfiable.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ServiceUnavailable.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/ServiceUnavailable.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ServiceUnavailable.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/ServiceUnavailable.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/UnsupportedMediaType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/UnsupportedMediaType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/UnsupportedMediaType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Exception/UnsupportedMediaType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/Directory.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FS/Directory.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/Directory.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FS/Directory.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/File.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FS/File.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/File.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FS/File.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/Node.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FS/Node.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/Node.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FS/Node.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/Directory.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FSExt/Directory.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/Directory.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FSExt/Directory.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/File.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FSExt/File.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/File.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FSExt/File.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/Node.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FSExt/Node.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/Node.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/FSExt/Node.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/File.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/File.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/File.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/File.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ICollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/ICollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ICollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/ICollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IExtendedCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/IExtendedCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IExtendedCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/IExtendedCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IFile.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/IFile.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IFile.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/IFile.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/INode.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/INode.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/INode.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/INode.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IProperties.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/IProperties.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IProperties.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/IProperties.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IQuota.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/IQuota.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IQuota.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/IQuota.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/AbstractBackend.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/AbstractBackend.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/AbstractBackend.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/AbstractBackend.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/BackendInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/BackendInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/BackendInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/BackendInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/FS.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/FS.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/FS.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/FS.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/File.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/File.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/File.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/File.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/PDO.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/PDO.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/PDO.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/PDO.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/LockInfo.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/LockInfo.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/LockInfo.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/LockInfo.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Plugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Plugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Plugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Locks/Plugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Mount/Plugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Mount/Plugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Mount/Plugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Mount/Plugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Node.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Node.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Node.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Node.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ObjectTree.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/ObjectTree.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ObjectTree.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/ObjectTree.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PartialUpdate/IFile.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/PartialUpdate/IFile.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PartialUpdate/IFile.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/PartialUpdate/IFile.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PartialUpdate/Plugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/PartialUpdate/Plugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PartialUpdate/Plugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/PartialUpdate/Plugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/GetLastModified.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/GetLastModified.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/GetLastModified.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/GetLastModified.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/Href.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/Href.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/Href.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/Href.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/HrefList.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/HrefList.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/HrefList.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/HrefList.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/IHref.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/IHref.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/IHref.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/IHref.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/LockDiscovery.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/LockDiscovery.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/LockDiscovery.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/LockDiscovery.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/ResourceType.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/ResourceType.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/ResourceType.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/ResourceType.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/Response.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/Response.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/Response.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/Response.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/ResponseList.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/ResponseList.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/ResponseList.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/ResponseList.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/SupportedLock.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/SupportedLock.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/SupportedLock.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/SupportedLock.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/SupportedReportSet.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/SupportedReportSet.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/SupportedReportSet.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Property/SupportedReportSet.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PropertyInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/PropertyInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PropertyInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/PropertyInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Server.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Server.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Server.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Server.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ServerPlugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/ServerPlugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ServerPlugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/ServerPlugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/SimpleCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/SimpleCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/SimpleCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/SimpleCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/SimpleFile.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/SimpleFile.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/SimpleFile.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/SimpleFile.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/StringUtil.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/StringUtil.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/StringUtil.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/StringUtil.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/TemporaryFileFilterPlugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/TemporaryFileFilterPlugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/TemporaryFileFilterPlugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/TemporaryFileFilterPlugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Tree.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Tree.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Tree.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Tree.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Tree/Filesystem.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Tree/Filesystem.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Tree/Filesystem.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Tree/Filesystem.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/URLUtil.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/URLUtil.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/URLUtil.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/URLUtil.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/UUIDUtil.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/UUIDUtil.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/UUIDUtil.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/UUIDUtil.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Version.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Version.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Version.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/Version.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/XMLUtil.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/XMLUtil.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/XMLUtil.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAV/XMLUtil.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/AbstractPrincipalCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/AbstractPrincipalCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/AbstractPrincipalCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/AbstractPrincipalCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/AceConflict.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Exception/AceConflict.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/AceConflict.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Exception/AceConflict.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NeedPrivileges.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NeedPrivileges.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NeedPrivileges.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NeedPrivileges.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NoAbstract.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NoAbstract.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NoAbstract.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NoAbstract.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NotRecognizedPrincipal.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NotRecognizedPrincipal.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NotRecognizedPrincipal.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NotRecognizedPrincipal.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NotSupportedPrivilege.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NotSupportedPrivilege.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NotSupportedPrivilege.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NotSupportedPrivilege.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IACL.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/IACL.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IACL.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/IACL.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IPrincipal.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/IPrincipal.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IPrincipal.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/IPrincipal.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IPrincipalCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/IPrincipalCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IPrincipalCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/IPrincipalCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Plugin.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Plugin.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Plugin.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Plugin.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Principal.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Principal.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Principal.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Principal.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/AbstractBackend.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/AbstractBackend.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/AbstractBackend.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/AbstractBackend.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/BackendInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/BackendInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/BackendInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/BackendInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/PDO.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/PDO.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/PDO.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/PDO.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalCollection.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalCollection.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalCollection.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalCollection.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/Acl.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Property/Acl.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/Acl.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Property/Acl.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/AclRestrictions.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Property/AclRestrictions.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/AclRestrictions.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Property/AclRestrictions.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/CurrentUserPrivilegeSet.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Property/CurrentUserPrivilegeSet.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/CurrentUserPrivilegeSet.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Property/CurrentUserPrivilegeSet.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/Principal.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Property/Principal.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/Principal.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Property/Principal.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/SupportedPrivilegeSet.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Property/SupportedPrivilegeSet.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/SupportedPrivilegeSet.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Property/SupportedPrivilegeSet.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Version.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Version.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Version.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/DAVACL/Version.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/AWSAuth.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/AWSAuth.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/AWSAuth.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/AWSAuth.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/AbstractAuth.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/AbstractAuth.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/AbstractAuth.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/AbstractAuth.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/BasicAuth.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/BasicAuth.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/BasicAuth.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/BasicAuth.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/DigestAuth.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/DigestAuth.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/DigestAuth.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/DigestAuth.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Request.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/Request.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Request.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/Request.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Response.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/Response.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Response.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/Response.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Util.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/Util.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Util.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/Util.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Version.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/Version.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Version.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/HTTP/Version.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Cli.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Cli.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Cli.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Cli.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VAlarm.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VAlarm.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VAlarm.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VAlarm.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VCalendar.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VCalendar.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VCalendar.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VCalendar.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VCard.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VCard.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VCard.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VCard.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VEvent.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VEvent.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VEvent.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VEvent.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VFreeBusy.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VFreeBusy.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VFreeBusy.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VFreeBusy.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VJournal.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VJournal.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VJournal.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VJournal.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VTodo.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VTodo.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VTodo.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Component/VTodo.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/DateTimeParser.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/DateTimeParser.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/DateTimeParser.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/DateTimeParser.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Document.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Document.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Document.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Document.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/ElementList.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/ElementList.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/ElementList.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/ElementList.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/EofException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/EofException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/EofException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/EofException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/FreeBusyGenerator.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/FreeBusyGenerator.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/FreeBusyGenerator.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/FreeBusyGenerator.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Node.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Node.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Node.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Node.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parameter.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Parameter.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parameter.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Parameter.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/ParseException.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/ParseException.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/ParseException.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/ParseException.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/Json.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Parser/Json.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/Json.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Parser/Json.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/MimeDir.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Parser/MimeDir.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/MimeDir.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Parser/MimeDir.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/Parser.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Parser/Parser.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/Parser.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Parser/Parser.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Binary.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Binary.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Binary.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Binary.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Boolean.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Boolean.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Boolean.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Boolean.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/FlatText.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/FlatText.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/FlatText.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/FlatText.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Float.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Float.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Float.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Float.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/CalAddress.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/CalAddress.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/CalAddress.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/CalAddress.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Date.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Date.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Date.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Date.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/DateTime.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/DateTime.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/DateTime.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/DateTime.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Duration.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Duration.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Duration.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Duration.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Period.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Period.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Period.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Period.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Recur.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Recur.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Recur.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Recur.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Integer.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Integer.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Integer.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Integer.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Text.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Text.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Text.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Text.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Time.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Time.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Time.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Time.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Unknown.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Unknown.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Unknown.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Unknown.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Uri.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Uri.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Uri.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/Uri.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/UtcOffset.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/UtcOffset.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/UtcOffset.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/UtcOffset.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/Date.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/Date.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/Date.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/Date.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateAndOrTime.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateAndOrTime.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateAndOrTime.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateAndOrTime.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateTime.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateTime.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateTime.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateTime.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/LanguageTag.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/LanguageTag.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/LanguageTag.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/LanguageTag.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/TimeStamp.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/TimeStamp.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/TimeStamp.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/TimeStamp.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Reader.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Reader.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Reader.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Reader.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/RecurrenceIterator.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/RecurrenceIterator.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/RecurrenceIterator.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/RecurrenceIterator.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/ICalendar.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Splitter/ICalendar.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/ICalendar.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Splitter/ICalendar.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/SplitterInterface.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Splitter/SplitterInterface.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/SplitterInterface.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Splitter/SplitterInterface.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/VCard.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Splitter/VCard.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/VCard.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Splitter/VCard.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/StringUtil.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/StringUtil.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/StringUtil.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/StringUtil.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/TimeZoneUtil.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/TimeZoneUtil.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/TimeZoneUtil.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/TimeZoneUtil.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/VCardConverter.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/VCardConverter.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/VCardConverter.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/VCardConverter.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Version.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Version.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Version.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/Version.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/includes.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/includes.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/includes.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/SabreForRainLoop/VObject/includes.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/LICENSE b/rainloop/app/rainloop/v/1.13.0/app/libraries/lessphp/LICENSE similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/LICENSE rename to rainloop/app/rainloop/v/1.13.0/app/libraries/lessphp/LICENSE diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/README.md b/rainloop/app/rainloop/v/1.13.0/app/libraries/lessphp/README.md similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/README.md rename to rainloop/app/rainloop/v/1.13.0/app/libraries/lessphp/README.md diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/ctype.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/lessphp/ctype.php similarity index 93% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/ctype.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/lessphp/ctype.php index d2bc9a0a..74a12d14 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/ctype.php +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/lessphp/ctype.php @@ -1,40 +1,40 @@ - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/pclzip/pclzip.lib.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/pclzip/pclzip.lib.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/pclzip/pclzip.lib.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/pclzip/pclzip.lib.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/pclzip/readme.txt b/rainloop/app/rainloop/v/1.13.0/app/libraries/pclzip/readme.txt similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/pclzip/readme.txt rename to rainloop/app/rainloop/v/1.13.0/app/libraries/pclzip/readme.txt index d1b11e25..6ed88394 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/libraries/pclzip/readme.txt +++ b/rainloop/app/rainloop/v/1.13.0/app/libraries/pclzip/readme.txt @@ -1,421 +1,421 @@ -// -------------------------------------------------------------------------------- -// PclZip 2.8.2 - readme.txt -// -------------------------------------------------------------------------------- -// License GNU/LGPL - August 2009 -// Vincent Blavet - vincent@phpconcept.net -// http://www.phpconcept.net -// -------------------------------------------------------------------------------- -// $Id: readme.txt,v 1.60 2009/09/30 20:35:21 vblavet Exp $ -// -------------------------------------------------------------------------------- - - - -0 - Sommaire -============ - 1 - Introduction - 2 - What's new - 3 - Corrected bugs - 4 - Known bugs or limitations - 5 - License - 6 - Warning - 7 - Documentation - 8 - Author - 9 - Contribute - -1 - Introduction -================ - - PclZip is a library that allow you to manage a Zip archive. - - Full documentation about PclZip can be found here : http://www.phpconcept.net/pclzip - -2 - What's new -============== - - Version 2.8.2 : - - PCLZIP_CB_PRE_EXTRACT and PCLZIP_CB_POST_EXTRACT are now supported with - extraction as a string (PCLZIP_OPT_EXTRACT_AS_STRING). The string - can also be modified in the post-extract call back. - **Bugs correction : - - PCLZIP_OPT_REMOVE_ALL_PATH was not working correctly - - Remove use of eval() and do direct call to callback functions - - Correct support of 64bits systems (Thanks to WordPress team) - - Version 2.8.1 : - - Move option PCLZIP_OPT_BY_EREG to PCLZIP_OPT_BY_PREG because ereg() is - deprecated in PHP 5.3. When using option PCLZIP_OPT_BY_EREG, PclZip will - automatically replace it by PCLZIP_OPT_BY_PREG. - - Version 2.8 : - - Improve extraction of zip archive for large files by using temporary files - This feature is working like the one defined in r2.7. - Options are renamed : PCLZIP_OPT_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_OFF, - PCLZIP_OPT_TEMP_FILE_THRESHOLD - - Add a ratio constant PCLZIP_TEMPORARY_FILE_RATIO to configure the auto - sense of temporary file use. - - Bug correction : Reduce filepath in returned file list to remove ennoying - './/' preambule in file path. - - Version 2.7 : - - Improve creation of zip archive for large files : - PclZip will now autosense the configured memory and use temporary files - when large file is suspected. - This feature can also ne triggered by manual options in create() and add() - methods. 'PCLZIP_OPT_ADD_TEMP_FILE_ON' force the use of temporary files, - 'PCLZIP_OPT_ADD_TEMP_FILE_OFF' disable the autosense technic, - 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD' allow for configuration of a size - threshold to use temporary files. - Using "temporary files" rather than "memory" might take more time, but - might give the ability to zip very large files : - Tested on my win laptop with a 88Mo file : - Zip "in-memory" : 18sec (max_execution_time=30, memory_limit=180Mo) - Zip "tmporary-files" : 23sec (max_execution_time=30, memory_limit=30Mo) - - Replace use of mktime() by time() to limit the E_STRICT error messages. - - Bug correction : When adding files with full windows path (drive letter) - PclZip is now working. Before, if the drive letter is not the default - path, PclZip was not able to add the file. - - Version 2.6 : - - Code optimisation - - New attributes PCLZIP_ATT_FILE_COMMENT gives the ability to - add a comment for a specific file. (Don't really know if this is usefull) - - New attribute PCLZIP_ATT_FILE_CONTENT gives the ability to add a string - as a file. - - New attribute PCLZIP_ATT_FILE_MTIME modify the timestamp associated with - a file. - - Correct a bug. Files archived with a timestamp with 0h0m0s were extracted - with current time - - Add CRC value in the informations returned back for each file after an - action. - - Add missing closedir() statement. - - When adding a folder, and removing the path of this folder, files were - incorrectly added with a '/' at the beginning. Which means files are - related to root in unix systems. Corrected. - - Add conditional if before constant definition. This will allow users - to redefine constants without changing the file, and then improve - upgrade of pclzip code for new versions. - - Version 2.5 : - - Introduce the ability to add file/folder with individual properties (file descriptor). - This gives for example the ability to change the filename of a zipped file. - . Able to add files individually - . Able to change full name - . Able to change short name - . Compatible with global options - - New attributes : PCLZIP_ATT_FILE_NAME, PCLZIP_ATT_FILE_NEW_SHORT_NAME, PCLZIP_ATT_FILE_NEW_FULL_NAME - - New error code : PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE - - Add a security control feature. PclZip can extract any file in any folder - of a system. People may use this to upload a zip file and try to override - a system file. The PCLZIP_OPT_EXTRACT_DIR_RESTRICTION will give the - ability to forgive any directory transversal behavior. - - New PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : check extraction path - - New error code : PCLZIP_ERR_DIRECTORY_RESTRICTION - - Modification in PclZipUtilPathInclusion() : dir and path beginning with ./ will be prepend - by current path (getcwd()) - - Version 2.4 : - - Code improvment : try to speed up the code by removing unusefull call to pack() - - Correct bug in delete() : delete() should be called with no argument. This was not - the case in 2.3. This is corrected in 2.4. - - Correct a bug in path_inclusion function. When the path has several '../../', the - result was bad. - - Add a check for magic_quotes_runtime configuration. If enabled, PclZip will - disable it while working and det it back to its original value. - This resolve a lots of bad formated archive errors. - - Bug correction : PclZip now correctly unzip file in some specific situation, - when compressed content has same size as uncompressed content. - - Bug correction : When selecting option 'PCLZIP_OPT_REMOVE_ALL_PATH', - directories are not any more created. - - Code improvment : correct unclosed opendir(), better handling of . and .. in - loops. - - - Version 2.3 : - - Correct a bug with PHP5 : affecting the value 0xFE49FFE0 to a variable does not - give the same result in PHP4 and PHP5 .... - - Version 2.2 : - - Try development of PCLZIP_OPT_CRYPT ..... - However this becomes to a stop. To crypt/decrypt I need to multiply 2 long integers, - the result (greater than a long) is not supported by PHP. Even the use of bcmath - functions does not help. I did not find yet a solution ...; - - Add missing '/' at end of directory entries - - Check is a file is encrypted or not. Returns status 'unsupported_encryption' and/or - error code PCLZIP_ERR_UNSUPPORTED_ENCRYPTION. - - Corrected : Bad "version need to extract" field in local file header - - Add private method privCheckFileHeaders() in order to check local and central - file headers. PclZip is now supporting purpose bit flag bit 3. Purpose bit flag bit 3 gives - the ability to have a local file header without size, compressed size and crc filled. - - Add a generic status 'error' for file status - - Add control of compression type. PclZip only support deflate compression method. - Before v2.2, PclZip does not check the compression method used in an archive while - extracting. With v2.2 PclZip returns a new error status for a file using an unsupported - compression method. New status is "unsupported_compression". New error code is - PCLZIP_ERR_UNSUPPORTED_COMPRESSION. - - Add optional attribute PCLZIP_OPT_STOP_ON_ERROR. This will stop the extract of files - when errors like 'a folder with same name exists' or 'a newer file exists' or - 'a write protected file' exists, rather than set a status for the concerning file - and resume the extract of the zip. - - Add optional attribute PCLZIP_OPT_REPLACE_NEWER. This will force, during an extract' the - replacement of the file, even if a newer version of the file exists. - Note that today if a file with the same name already exists but is older it will be - replaced by the extracted one. - - Improve PclZipUtilOption() - - Support of zip archive with trailing bytes. Before 2.2, PclZip checks that the central - directory structure is the last data in the archive. Crypt encryption/decryption of - zip archive put trailing 0 bytes after decryption. PclZip is now supporting this. - - Version 2.1 : - - Add the ability to abort the extraction by using a user callback function. - The user can now return the value '2' in its callback which indicates to stop the - extraction. For a pre call-back extract is stopped before the extration of the current - file. For a post call back, the extraction is stopped after. - - Add the ability to extract a file (or several files) directly in the standard output. - This is done by the new parameter PCLZIP_OPT_EXTRACT_IN_OUTPUT with method extract(). - - Add support for parameters PCLZIP_OPT_COMMENT, PCLZIP_OPT_ADD_COMMENT, - PCLZIP_OPT_PREPEND_COMMENT. This will create, replace, add, or prepend comments - in the zip archive. - - When merging two archives, the comments are not any more lost, but merged, with a - blank space separator. - - Corrected bug : Files are not deleted when all files are asked to be deleted. - - Corrected bug : Folders with name '0' made PclZip to abort the create or add feature. - - - Version 2.0 : - ***** Warning : Some new features may break the backward compatibility for your scripts. - Please carefully read the readme file. - - Add the ability to delete by Index, name and regular expression. This feature is - performed by the method delete(), which uses the optional parameters - PCLZIP_OPT_BY_INDEX, PCLZIP_OPT_BY_NAME, PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG. - - Add the ability to extract by regular expression. To extract by regexp you must use the method - extract(), with the option PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG - (depending if you want to use ereg() or preg_match() syntax) followed by the - regular expression pattern. - - Add the ability to extract by index, directly with the extract() method. This is a - code improvment of the extractByIndex() method. - - Add the ability to extract by name. To extract by name you must use the method - extract(), with the option PCLZIP_OPT_BY_NAME followed by the filename to - extract or an array of filenames to extract. To extract all a folder, use the folder - name rather than the filename with a '/' at the end. - - Add the ability to add files without compression. This is done with a new attribute - which is PCLZIP_OPT_NO_COMPRESSION. - - Add the attribute PCLZIP_OPT_EXTRACT_AS_STRING, which allow to extract a file directly - in a string without using any file (or temporary file). - - Add constant PCLZIP_SEPARATOR for static configuration of filename separators in a single string. - The default separator is now a comma (,) and not any more a blank space. - THIS BREAK THE BACKWARD COMPATIBILITY : Please check if this may have an impact with - your script. - - Improve algorythm performance by removing the use of temporary files when adding or - extracting files in an archive. - - Add (correct) detection of empty filename zipping. This can occurs when the removed - path is the same - as a zipped dir. The dir is not zipped (['status'] = filtered), only its content. - - Add better support for windows paths (thanks for help from manus@manusfreedom.com). - - Corrected bug : When the archive file already exists with size=0, the add() method - fails. Corrected in 2.0. - - Remove the use of OS_WINDOWS constant. Use php_uname() function rather. - - Control the order of index ranges in extract by index feature. - - Change the internal management of folders (better handling of internal flag). - - - Version 1.3 : - - Removing the double include check. This is now done by include_once() and require_once() - PHP directives. - - Changing the error handling mecanism : Remove the use of an external error library. - The former PclError...() functions are replaced by internal equivalent methods. - By changing the environment variable PCLZIP_ERROR_EXTERNAL you can still use the former library. - Introducing the use of constants for error codes rather than integer values. This will help - in futur improvment. - Introduction of error handling functions like errorCode(), errorName() and errorInfo(). - - Remove the deprecated use of calling function with arguments passed by reference. - - Add the calling of extract(), extractByIndex(), create() and add() functions - with variable options rather than fixed arguments. - - Add the ability to remove all the file path while extracting or adding, - without any need to specify the path to remove. - This is available for extract(), extractByIndex(), create() and add() functionS by using - the new variable options parameters : - - PCLZIP_OPT_REMOVE_ALL_PATH : by indicating this option while calling the fct. - - Ability to change the mode of a file after the extraction (chmod()). - This is available for extract() and extractByIndex() functionS by using - the new variable options parameters. - - PCLZIP_OPT_SET_CHMOD : by setting the value of this option. - - Ability to definition call-back options. These call-back will be called during the adding, - or the extracting of file (extract(), extractByIndex(), create() and add() functions) : - - PCLZIP_CB_PRE_EXTRACT : will be called before each extraction of a file. The user - can trigerred the change the filename of the extracted file. The user can triggered the - skip of the extraction. This is adding a 'skipped' status in the file list result value. - - PCLZIP_CB_POST_EXTRACT : will be called after each extraction of a file. - Nothing can be triggered from that point. - - PCLZIP_CB_PRE_ADD : will be called before each add of a file. The user - can trigerred the change the stored filename of the added file. The user can triggered the - skip of the add. This is adding a 'skipped' status in the file list result value. - - PCLZIP_CB_POST_ADD : will be called after each add of a file. - Nothing can be triggered from that point. - - Two status are added in the file list returned as function result : skipped & filename_too_long - 'skipped' is used when a call-back function ask for skipping the file. - 'filename_too_long' is used while adding a file with a too long filename to archive (the file is - not added) - - Adding the function PclZipUtilPathInclusion(), that check the inclusion of a path into - a directory. - - Add a check of the presence of the archive file before some actions (like list, ...) - - Add the initialisation of field "index" in header array. This means that by - default index will be -1 when not explicitly set by the methods. - - Version 1.2 : - - Adding a duplicate function. - - Adding a merge function. The merge function is a "quick merge" function, - it just append the content of an archive at the end of the first one. There - is no check for duplicate files or more recent files. - - Improve the search of the central directory end. - - Version 1.1.2 : - - - Changing the license of PclZip. PclZip is now released under the GNU / LGPL license - (see License section). - - Adding the optional support of a static temporary directory. You will need to configure - the constant PCLZIP_TEMPORARY_DIR if you want to use this feature. - - Improving the rename() function. In some cases rename() does not work (different - Filesystems), so it will be replaced by a copy() + unlink() functions. - - Version 1.1.1 : - - - Maintenance release, no new feature. - - Version 1.1 : - - - New method Add() : adding files in the archive - - New method ExtractByIndex() : partial extract of the archive, files are identified by - their index in the archive - - New method DeleteByIndex() : delete some files/folder entries from the archive, - files are identified by their index in the archive. - - Adding a test of the zlib extension presence. If not present abort the script. - - Version 1.0.1 : - - - No new feature - - -3 - Corrected bugs -================== - - Corrected in Version 2.0 : - - Corrected : During an extraction, if a call-back fucntion is used and try to skip - a file, all the extraction process is stopped. - - Corrected in Version 1.3 : - - Corrected : Support of static synopsis for method extract() is broken. - - Corrected : invalid size of archive content field (0xFF) should be (0xFFFF). - - Corrected : When an extract is done with a remove_path parameter, the entry for - the directory with exactly the same path is not skipped/filtered. - - Corrected : extractByIndex() and deleteByIndex() were not managing index in the - right way. For example indexes '1,3-5,11' will only extract files 1 and 11. This - is due to a sort of the index resulting table that puts 11 before 3-5 (sort on - string and not interger). The sort is temporarilly removed, this means that - you must provide a sorted list of index ranges. - - Corrected in Version 1.2 : - - - Nothing. - - Corrected in Version 1.1.2 : - - - Corrected : Winzip is unable to delete or add new files in a PclZip created archives. - - Corrected in Version 1.1.1 : - - - Corrected : When archived file is not compressed (0% compression), the - extract method fails. - - Corrected in Version 1.1 : - - - Corrected : Adding a complete tree of folder may result in a bad archive - creation. - - Corrected in Version 1.0.1 : - - - Corrected : Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024). - - -4 - Known bugs or limitations -============================= - - Please publish bugs reports in SourceForge : - http://sourceforge.net/tracker/?group_id=40254&atid=427564 - - In Version 2.x : - - PclZip does only support file uncompressed or compressed with deflate (compression method 8) - - PclZip does not support password protected zip archive - - Some concern were seen when changing mtime of a file while archiving. - Seems to be linked to Daylight Saving Time (PclTest_changing_mtime). - - In Version 1.2 : - - - merge() methods does not check for duplicate files or last date of modifications. - - In Version 1.1 : - - - Limitation : Using 'extract' fields in the file header in the zip archive is not supported. - - WinZip is unable to delete a single file in a PclZip created archive. It is also unable to - add a file in a PclZip created archive. (Corrected in v.1.2) - - In Version 1.0.1 : - - - Adding a complete tree of folder may result in a bad archive - creation. (Corrected in V.1.1). - - Path given to methods must be in the unix format (/) and not the Windows format (\). - Workaround : Use only / directory separators. - - PclZip is using temporary files that are sometime the name of the file with a .tmp or .gz - added suffix. Files with these names may already exist and may be overwritten. - Workaround : none. - - PclZip does not check if the zlib extension is present. If it is absent, the zip - file is not created and the lib abort without warning. - Workaround : enable the zlib extension on the php install - - In Version 1.0 : - - - Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024). - (Corrected in v.1.0.1) - - Limitation : Multi-disk zip archive are not supported. - - -5 - License -=========== - - Since version 1.1.2, PclZip Library is released under GNU/LGPL license. - This library is free, so you can use it at no cost. - - HOWEVER, if you release a script, an application, a library or any kind of - code using PclZip library (or a part of it), YOU MUST : - - Indicate in the documentation (or a readme file), that your work - uses PclZip Library, and make a reference to the author and the web site - http://www.phpconcept.net - - Gives the ability to the final user to update the PclZip libary. - - I will also appreciate that you send me a mail (vincent@phpconcept.net), just to - be aware that someone is using PclZip. - - For more information about GNU/LGPL license : http://www.gnu.org - -6 - Warning -================= - - This library and the associated files are non commercial, non professional work. - It should not have unexpected results. However if any damage is caused by this software - the author can not be responsible. - The use of this software is at the risk of the user. - -7 - Documentation -================= - PclZip User Manuel is available in English on PhpConcept : http://www.phpconcept.net/pclzip/man/en/index.php - A Russian translation was done by Feskov Kuzma : http://php.russofile.ru/ru/authors/unsort/zip/ - -8 - Author -========== - - This software was written by Vincent Blavet (vincent@phpconcept.net) on its leasure time. - -9 - Contribute -============== - If you want to contribute to the development of PclZip, please contact vincent@phpconcept.net. - If you can help in financing PhpConcept hosting service, please go to - http://www.phpconcept.net/soutien.php +// -------------------------------------------------------------------------------- +// PclZip 2.8.2 - readme.txt +// -------------------------------------------------------------------------------- +// License GNU/LGPL - August 2009 +// Vincent Blavet - vincent@phpconcept.net +// http://www.phpconcept.net +// -------------------------------------------------------------------------------- +// $Id: readme.txt,v 1.60 2009/09/30 20:35:21 vblavet Exp $ +// -------------------------------------------------------------------------------- + + + +0 - Sommaire +============ + 1 - Introduction + 2 - What's new + 3 - Corrected bugs + 4 - Known bugs or limitations + 5 - License + 6 - Warning + 7 - Documentation + 8 - Author + 9 - Contribute + +1 - Introduction +================ + + PclZip is a library that allow you to manage a Zip archive. + + Full documentation about PclZip can be found here : http://www.phpconcept.net/pclzip + +2 - What's new +============== + + Version 2.8.2 : + - PCLZIP_CB_PRE_EXTRACT and PCLZIP_CB_POST_EXTRACT are now supported with + extraction as a string (PCLZIP_OPT_EXTRACT_AS_STRING). The string + can also be modified in the post-extract call back. + **Bugs correction : + - PCLZIP_OPT_REMOVE_ALL_PATH was not working correctly + - Remove use of eval() and do direct call to callback functions + - Correct support of 64bits systems (Thanks to WordPress team) + + Version 2.8.1 : + - Move option PCLZIP_OPT_BY_EREG to PCLZIP_OPT_BY_PREG because ereg() is + deprecated in PHP 5.3. When using option PCLZIP_OPT_BY_EREG, PclZip will + automatically replace it by PCLZIP_OPT_BY_PREG. + + Version 2.8 : + - Improve extraction of zip archive for large files by using temporary files + This feature is working like the one defined in r2.7. + Options are renamed : PCLZIP_OPT_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_OFF, + PCLZIP_OPT_TEMP_FILE_THRESHOLD + - Add a ratio constant PCLZIP_TEMPORARY_FILE_RATIO to configure the auto + sense of temporary file use. + - Bug correction : Reduce filepath in returned file list to remove ennoying + './/' preambule in file path. + + Version 2.7 : + - Improve creation of zip archive for large files : + PclZip will now autosense the configured memory and use temporary files + when large file is suspected. + This feature can also ne triggered by manual options in create() and add() + methods. 'PCLZIP_OPT_ADD_TEMP_FILE_ON' force the use of temporary files, + 'PCLZIP_OPT_ADD_TEMP_FILE_OFF' disable the autosense technic, + 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD' allow for configuration of a size + threshold to use temporary files. + Using "temporary files" rather than "memory" might take more time, but + might give the ability to zip very large files : + Tested on my win laptop with a 88Mo file : + Zip "in-memory" : 18sec (max_execution_time=30, memory_limit=180Mo) + Zip "tmporary-files" : 23sec (max_execution_time=30, memory_limit=30Mo) + - Replace use of mktime() by time() to limit the E_STRICT error messages. + - Bug correction : When adding files with full windows path (drive letter) + PclZip is now working. Before, if the drive letter is not the default + path, PclZip was not able to add the file. + + Version 2.6 : + - Code optimisation + - New attributes PCLZIP_ATT_FILE_COMMENT gives the ability to + add a comment for a specific file. (Don't really know if this is usefull) + - New attribute PCLZIP_ATT_FILE_CONTENT gives the ability to add a string + as a file. + - New attribute PCLZIP_ATT_FILE_MTIME modify the timestamp associated with + a file. + - Correct a bug. Files archived with a timestamp with 0h0m0s were extracted + with current time + - Add CRC value in the informations returned back for each file after an + action. + - Add missing closedir() statement. + - When adding a folder, and removing the path of this folder, files were + incorrectly added with a '/' at the beginning. Which means files are + related to root in unix systems. Corrected. + - Add conditional if before constant definition. This will allow users + to redefine constants without changing the file, and then improve + upgrade of pclzip code for new versions. + + Version 2.5 : + - Introduce the ability to add file/folder with individual properties (file descriptor). + This gives for example the ability to change the filename of a zipped file. + . Able to add files individually + . Able to change full name + . Able to change short name + . Compatible with global options + - New attributes : PCLZIP_ATT_FILE_NAME, PCLZIP_ATT_FILE_NEW_SHORT_NAME, PCLZIP_ATT_FILE_NEW_FULL_NAME + - New error code : PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE + - Add a security control feature. PclZip can extract any file in any folder + of a system. People may use this to upload a zip file and try to override + a system file. The PCLZIP_OPT_EXTRACT_DIR_RESTRICTION will give the + ability to forgive any directory transversal behavior. + - New PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : check extraction path + - New error code : PCLZIP_ERR_DIRECTORY_RESTRICTION + - Modification in PclZipUtilPathInclusion() : dir and path beginning with ./ will be prepend + by current path (getcwd()) + + Version 2.4 : + - Code improvment : try to speed up the code by removing unusefull call to pack() + - Correct bug in delete() : delete() should be called with no argument. This was not + the case in 2.3. This is corrected in 2.4. + - Correct a bug in path_inclusion function. When the path has several '../../', the + result was bad. + - Add a check for magic_quotes_runtime configuration. If enabled, PclZip will + disable it while working and det it back to its original value. + This resolve a lots of bad formated archive errors. + - Bug correction : PclZip now correctly unzip file in some specific situation, + when compressed content has same size as uncompressed content. + - Bug correction : When selecting option 'PCLZIP_OPT_REMOVE_ALL_PATH', + directories are not any more created. + - Code improvment : correct unclosed opendir(), better handling of . and .. in + loops. + + + Version 2.3 : + - Correct a bug with PHP5 : affecting the value 0xFE49FFE0 to a variable does not + give the same result in PHP4 and PHP5 .... + + Version 2.2 : + - Try development of PCLZIP_OPT_CRYPT ..... + However this becomes to a stop. To crypt/decrypt I need to multiply 2 long integers, + the result (greater than a long) is not supported by PHP. Even the use of bcmath + functions does not help. I did not find yet a solution ...; + - Add missing '/' at end of directory entries + - Check is a file is encrypted or not. Returns status 'unsupported_encryption' and/or + error code PCLZIP_ERR_UNSUPPORTED_ENCRYPTION. + - Corrected : Bad "version need to extract" field in local file header + - Add private method privCheckFileHeaders() in order to check local and central + file headers. PclZip is now supporting purpose bit flag bit 3. Purpose bit flag bit 3 gives + the ability to have a local file header without size, compressed size and crc filled. + - Add a generic status 'error' for file status + - Add control of compression type. PclZip only support deflate compression method. + Before v2.2, PclZip does not check the compression method used in an archive while + extracting. With v2.2 PclZip returns a new error status for a file using an unsupported + compression method. New status is "unsupported_compression". New error code is + PCLZIP_ERR_UNSUPPORTED_COMPRESSION. + - Add optional attribute PCLZIP_OPT_STOP_ON_ERROR. This will stop the extract of files + when errors like 'a folder with same name exists' or 'a newer file exists' or + 'a write protected file' exists, rather than set a status for the concerning file + and resume the extract of the zip. + - Add optional attribute PCLZIP_OPT_REPLACE_NEWER. This will force, during an extract' the + replacement of the file, even if a newer version of the file exists. + Note that today if a file with the same name already exists but is older it will be + replaced by the extracted one. + - Improve PclZipUtilOption() + - Support of zip archive with trailing bytes. Before 2.2, PclZip checks that the central + directory structure is the last data in the archive. Crypt encryption/decryption of + zip archive put trailing 0 bytes after decryption. PclZip is now supporting this. + + Version 2.1 : + - Add the ability to abort the extraction by using a user callback function. + The user can now return the value '2' in its callback which indicates to stop the + extraction. For a pre call-back extract is stopped before the extration of the current + file. For a post call back, the extraction is stopped after. + - Add the ability to extract a file (or several files) directly in the standard output. + This is done by the new parameter PCLZIP_OPT_EXTRACT_IN_OUTPUT with method extract(). + - Add support for parameters PCLZIP_OPT_COMMENT, PCLZIP_OPT_ADD_COMMENT, + PCLZIP_OPT_PREPEND_COMMENT. This will create, replace, add, or prepend comments + in the zip archive. + - When merging two archives, the comments are not any more lost, but merged, with a + blank space separator. + - Corrected bug : Files are not deleted when all files are asked to be deleted. + - Corrected bug : Folders with name '0' made PclZip to abort the create or add feature. + + + Version 2.0 : + ***** Warning : Some new features may break the backward compatibility for your scripts. + Please carefully read the readme file. + - Add the ability to delete by Index, name and regular expression. This feature is + performed by the method delete(), which uses the optional parameters + PCLZIP_OPT_BY_INDEX, PCLZIP_OPT_BY_NAME, PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG. + - Add the ability to extract by regular expression. To extract by regexp you must use the method + extract(), with the option PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG + (depending if you want to use ereg() or preg_match() syntax) followed by the + regular expression pattern. + - Add the ability to extract by index, directly with the extract() method. This is a + code improvment of the extractByIndex() method. + - Add the ability to extract by name. To extract by name you must use the method + extract(), with the option PCLZIP_OPT_BY_NAME followed by the filename to + extract or an array of filenames to extract. To extract all a folder, use the folder + name rather than the filename with a '/' at the end. + - Add the ability to add files without compression. This is done with a new attribute + which is PCLZIP_OPT_NO_COMPRESSION. + - Add the attribute PCLZIP_OPT_EXTRACT_AS_STRING, which allow to extract a file directly + in a string without using any file (or temporary file). + - Add constant PCLZIP_SEPARATOR for static configuration of filename separators in a single string. + The default separator is now a comma (,) and not any more a blank space. + THIS BREAK THE BACKWARD COMPATIBILITY : Please check if this may have an impact with + your script. + - Improve algorythm performance by removing the use of temporary files when adding or + extracting files in an archive. + - Add (correct) detection of empty filename zipping. This can occurs when the removed + path is the same + as a zipped dir. The dir is not zipped (['status'] = filtered), only its content. + - Add better support for windows paths (thanks for help from manus@manusfreedom.com). + - Corrected bug : When the archive file already exists with size=0, the add() method + fails. Corrected in 2.0. + - Remove the use of OS_WINDOWS constant. Use php_uname() function rather. + - Control the order of index ranges in extract by index feature. + - Change the internal management of folders (better handling of internal flag). + + + Version 1.3 : + - Removing the double include check. This is now done by include_once() and require_once() + PHP directives. + - Changing the error handling mecanism : Remove the use of an external error library. + The former PclError...() functions are replaced by internal equivalent methods. + By changing the environment variable PCLZIP_ERROR_EXTERNAL you can still use the former library. + Introducing the use of constants for error codes rather than integer values. This will help + in futur improvment. + Introduction of error handling functions like errorCode(), errorName() and errorInfo(). + - Remove the deprecated use of calling function with arguments passed by reference. + - Add the calling of extract(), extractByIndex(), create() and add() functions + with variable options rather than fixed arguments. + - Add the ability to remove all the file path while extracting or adding, + without any need to specify the path to remove. + This is available for extract(), extractByIndex(), create() and add() functionS by using + the new variable options parameters : + - PCLZIP_OPT_REMOVE_ALL_PATH : by indicating this option while calling the fct. + - Ability to change the mode of a file after the extraction (chmod()). + This is available for extract() and extractByIndex() functionS by using + the new variable options parameters. + - PCLZIP_OPT_SET_CHMOD : by setting the value of this option. + - Ability to definition call-back options. These call-back will be called during the adding, + or the extracting of file (extract(), extractByIndex(), create() and add() functions) : + - PCLZIP_CB_PRE_EXTRACT : will be called before each extraction of a file. The user + can trigerred the change the filename of the extracted file. The user can triggered the + skip of the extraction. This is adding a 'skipped' status in the file list result value. + - PCLZIP_CB_POST_EXTRACT : will be called after each extraction of a file. + Nothing can be triggered from that point. + - PCLZIP_CB_PRE_ADD : will be called before each add of a file. The user + can trigerred the change the stored filename of the added file. The user can triggered the + skip of the add. This is adding a 'skipped' status in the file list result value. + - PCLZIP_CB_POST_ADD : will be called after each add of a file. + Nothing can be triggered from that point. + - Two status are added in the file list returned as function result : skipped & filename_too_long + 'skipped' is used when a call-back function ask for skipping the file. + 'filename_too_long' is used while adding a file with a too long filename to archive (the file is + not added) + - Adding the function PclZipUtilPathInclusion(), that check the inclusion of a path into + a directory. + - Add a check of the presence of the archive file before some actions (like list, ...) + - Add the initialisation of field "index" in header array. This means that by + default index will be -1 when not explicitly set by the methods. + + Version 1.2 : + - Adding a duplicate function. + - Adding a merge function. The merge function is a "quick merge" function, + it just append the content of an archive at the end of the first one. There + is no check for duplicate files or more recent files. + - Improve the search of the central directory end. + + Version 1.1.2 : + + - Changing the license of PclZip. PclZip is now released under the GNU / LGPL license + (see License section). + - Adding the optional support of a static temporary directory. You will need to configure + the constant PCLZIP_TEMPORARY_DIR if you want to use this feature. + - Improving the rename() function. In some cases rename() does not work (different + Filesystems), so it will be replaced by a copy() + unlink() functions. + + Version 1.1.1 : + + - Maintenance release, no new feature. + + Version 1.1 : + + - New method Add() : adding files in the archive + - New method ExtractByIndex() : partial extract of the archive, files are identified by + their index in the archive + - New method DeleteByIndex() : delete some files/folder entries from the archive, + files are identified by their index in the archive. + - Adding a test of the zlib extension presence. If not present abort the script. + + Version 1.0.1 : + + - No new feature + + +3 - Corrected bugs +================== + + Corrected in Version 2.0 : + - Corrected : During an extraction, if a call-back fucntion is used and try to skip + a file, all the extraction process is stopped. + + Corrected in Version 1.3 : + - Corrected : Support of static synopsis for method extract() is broken. + - Corrected : invalid size of archive content field (0xFF) should be (0xFFFF). + - Corrected : When an extract is done with a remove_path parameter, the entry for + the directory with exactly the same path is not skipped/filtered. + - Corrected : extractByIndex() and deleteByIndex() were not managing index in the + right way. For example indexes '1,3-5,11' will only extract files 1 and 11. This + is due to a sort of the index resulting table that puts 11 before 3-5 (sort on + string and not interger). The sort is temporarilly removed, this means that + you must provide a sorted list of index ranges. + + Corrected in Version 1.2 : + + - Nothing. + + Corrected in Version 1.1.2 : + + - Corrected : Winzip is unable to delete or add new files in a PclZip created archives. + + Corrected in Version 1.1.1 : + + - Corrected : When archived file is not compressed (0% compression), the + extract method fails. + + Corrected in Version 1.1 : + + - Corrected : Adding a complete tree of folder may result in a bad archive + creation. + + Corrected in Version 1.0.1 : + + - Corrected : Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024). + + +4 - Known bugs or limitations +============================= + + Please publish bugs reports in SourceForge : + http://sourceforge.net/tracker/?group_id=40254&atid=427564 + + In Version 2.x : + - PclZip does only support file uncompressed or compressed with deflate (compression method 8) + - PclZip does not support password protected zip archive + - Some concern were seen when changing mtime of a file while archiving. + Seems to be linked to Daylight Saving Time (PclTest_changing_mtime). + + In Version 1.2 : + + - merge() methods does not check for duplicate files or last date of modifications. + + In Version 1.1 : + + - Limitation : Using 'extract' fields in the file header in the zip archive is not supported. + - WinZip is unable to delete a single file in a PclZip created archive. It is also unable to + add a file in a PclZip created archive. (Corrected in v.1.2) + + In Version 1.0.1 : + + - Adding a complete tree of folder may result in a bad archive + creation. (Corrected in V.1.1). + - Path given to methods must be in the unix format (/) and not the Windows format (\). + Workaround : Use only / directory separators. + - PclZip is using temporary files that are sometime the name of the file with a .tmp or .gz + added suffix. Files with these names may already exist and may be overwritten. + Workaround : none. + - PclZip does not check if the zlib extension is present. If it is absent, the zip + file is not created and the lib abort without warning. + Workaround : enable the zlib extension on the php install + + In Version 1.0 : + + - Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024). + (Corrected in v.1.0.1) + - Limitation : Multi-disk zip archive are not supported. + + +5 - License +=========== + + Since version 1.1.2, PclZip Library is released under GNU/LGPL license. + This library is free, so you can use it at no cost. + + HOWEVER, if you release a script, an application, a library or any kind of + code using PclZip library (or a part of it), YOU MUST : + - Indicate in the documentation (or a readme file), that your work + uses PclZip Library, and make a reference to the author and the web site + http://www.phpconcept.net + - Gives the ability to the final user to update the PclZip libary. + + I will also appreciate that you send me a mail (vincent@phpconcept.net), just to + be aware that someone is using PclZip. + + For more information about GNU/LGPL license : http://www.gnu.org + +6 - Warning +================= + + This library and the associated files are non commercial, non professional work. + It should not have unexpected results. However if any damage is caused by this software + the author can not be responsible. + The use of this software is at the risk of the user. + +7 - Documentation +================= + PclZip User Manuel is available in English on PhpConcept : http://www.phpconcept.net/pclzip/man/en/index.php + A Russian translation was done by Feskov Kuzma : http://php.russofile.ru/ru/authors/unsort/zip/ + +8 - Author +========== + + This software was written by Vincent Blavet (vincent@phpconcept.net) on its leasure time. + +9 - Contribute +============== + If you want to contribute to the development of PclZip, please contact vincent@phpconcept.net. + If you can help in financing PhpConcept hosting service, please go to + http://www.phpconcept.net/soutien.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/COPYING b/rainloop/app/rainloop/v/1.13.0/app/libraries/spyc/COPYING similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/COPYING rename to rainloop/app/rainloop/v/1.13.0/app/libraries/spyc/COPYING diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/README.md b/rainloop/app/rainloop/v/1.13.0/app/libraries/spyc/README.md similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/README.md rename to rainloop/app/rainloop/v/1.13.0/app/libraries/spyc/README.md diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/Spyc.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/spyc/Spyc.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/Spyc.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/spyc/Spyc.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/composer.json b/rainloop/app/rainloop/v/1.13.0/app/libraries/spyc/composer.json similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/composer.json rename to rainloop/app/rainloop/v/1.13.0/app/libraries/spyc/composer.json diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/LICENSE b/rainloop/app/rainloop/v/1.13.0/app/libraries/tmhOAuth/LICENSE similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/LICENSE rename to rainloop/app/rainloop/v/1.13.0/app/libraries/tmhOAuth/LICENSE diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/README.md b/rainloop/app/rainloop/v/1.13.0/app/libraries/tmhOAuth/README.md similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/README.md rename to rainloop/app/rainloop/v/1.13.0/app/libraries/tmhOAuth/README.md diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/cacert.pem b/rainloop/app/rainloop/v/1.13.0/app/libraries/tmhOAuth/cacert.pem similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/cacert.pem rename to rainloop/app/rainloop/v/1.13.0/app/libraries/tmhOAuth/cacert.pem diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/tmhOAuth.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/tmhOAuth/tmhOAuth.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/tmhOAuth.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/tmhOAuth/tmhOAuth.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/tmhUtilities.php b/rainloop/app/rainloop/v/1.13.0/app/libraries/tmhOAuth/tmhUtilities.php similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/tmhUtilities.php rename to rainloop/app/rainloop/v/1.13.0/app/libraries/tmhOAuth/tmhUtilities.php diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/README b/rainloop/app/rainloop/v/1.13.0/app/localization/README similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/README rename to rainloop/app/rainloop/v/1.13.0/app/localization/README diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/README b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/README similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/README rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/README diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/_source.en.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/_source.en.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/_source.en.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/_source.en.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/cs_CZ.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/cs_CZ.yml similarity index 90% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/cs_CZ.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/cs_CZ.yml index ab8d3ccf..3bf2aaaa 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/cs_CZ.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/cs_CZ.yml @@ -26,18 +26,20 @@ cs_CZ: LABEL_ALLOW_LANGUAGES_ON_SETTINGS: "Povolit výběr jazyka na přihlašovací obrazovce" LABEL_ALLOW_THEMES_ON_SETTINGS: "Povolit výběr motivu na přihlašovací obrazovce" LABEL_ALLOW_BACKGROUND_ON_SETTINGS: "Povolit výběr pozadí na přihlašovací obrazovce" + LABEL_NEW_FOLDER_MOVE: "Nové tlačítko \"přesunout do adresáře\"" LABEL_SHOW_THUMBNAILS: "Zobrazovat miniatury (přílohy)" - LABEL_ALLOW_GRAVATAR: "Povolit nastavení avatara" + LABEL_ALLOW_GRAVATAR: "Povolit Gravatar" LEGEND_MAIN: "Hlavní" LABEL_ATTACHMENT_SIZE_LIMIT: "Limit velikosti přílohy" LABEL_ALLOW_ADDITIONAL_ACCOUNTS: "Povolit přidávat další účty" LABEL_ALLOW_IDENTITIES: "Povolit další identity" LABEL_ALLOW_TEMPLATES: "Povolit šablony" + ALERT_DATA_ACCESS: "Adresář s RainLoop daty je veřejně přístupný. Nakonfigurujte prosím webový server tak, aby skryl adresář data z externího přístupu. Více zde:" ALERT_WARNING: "Upozornění!" HTML_ALERT_WEAK_PASSWORD: | Používáte výchozí administrátorské heslo.
- Z bezpečnostních důvodů jeji prosím + Z bezpečnostních důvodů jej prosím změnte. TAB_LOGIN: LEGEND_LOGIN_SCREEN: "Přihlašovací obrazovka" @@ -89,6 +91,7 @@ cs_CZ: TAB_DOMAINS: LEGEND_DOMAINS: "Domény" BUTTON_ADD_DOMAIN: "Přidat Doménu" + BUTTON_ADD_ALIAS: "Přidat alias" DELETE_ARE_YOU_SURE: "Jste si jistí?" HTML_DOMAINS_HELPER: | Seznam domén, ke kterým je možné přistupovat přes webmail. @@ -113,24 +116,24 @@ cs_CZ: TAB_INTEGRATIONS: LEGEND_GOOGLE: "Google" LABEL_ENABLE_GOOGLE: "Povolit Google integraci" - LABEL_GOOGLE_AUTH: "Authorizace" - LABEL_GOOGLE_DRIVE: "Google Drive integrace (Compose view)" + LABEL_GOOGLE_AUTH: "Autorizace" + LABEL_GOOGLE_DRIVE: "Google Drive integrace (Psaní zpráv)" LABEL_GOOGLE_PREVIEW: "Google Viewer integrace (náhled pro Microsoft Word, Excel a PowerPoint soubory)" LABEL_GOOGLE_CLIENT_ID: "Klient ID" LABEL_GOOGLE_CLIENT_SECRET: "Klient Secret" LABEL_GOOGLE_API_KEY: "Api klíč" HINT_GOOGLE_API_KEY: "Vyžadováno pro Google Drive File Picker" LEGEND_FACEBOOK: "Facebook" - LABEL_ENABLE_FACEBOOK: "Povolit Facebook integraci (Authorizaci)" + LABEL_ENABLE_FACEBOOK: "Povolit Facebook integraci (Autorizaci)" LABEL_FACEBOOK_APP_ID: "App ID" LABEL_FACEBOOK_APP_SECRET: "App Secret" LEGEND_TWITTER: "Twitter" - LABEL_ENABLE_TWITTER: "Povolit Twitter integraci (Authorizaci)" + LABEL_ENABLE_TWITTER: "Povolit Twitter integraci (Autorizaci)" LABEL_TWITTER_CONSUMER_KEY: "Consumer Key" LABEL_TWITTER_CONSUMER_SECRET: "Consumer Secret" LEGEND_DROPBOX: "Dropbox" LABEL_ENABLE_DROPBOX: "Povolit Dropbox integraci" - LABEL_DROPBOX_API_KEY: "Api key" + LABEL_DROPBOX_API_KEY: "Api klíč" TOP_ALERT: "Detailní informace o integraci sociálních sítí jsou dostupné na adrese" TAB_PLUGINS: LEGEND_PLUGINS: "Pluginy" @@ -167,9 +170,9 @@ cs_CZ: HINT_READ_CHANGE_LOG: "Přečtěte si prosím change log předtím, než budete chtít provést aktualizaci." HINT_IS_UP_TO_DATE: "RainLoop je v aktuální verzi." HTML_NEW_VERSION: "Nová verze %VERSION% je k dispozici." - LABEL_UPDATING: "Aktualizace" - LABEL_CHECKING: "Zjistit nové aktualizace" - BUTTON_UPDATE: "Aktualizace" + LABEL_UPDATING: "Aktualizuji" + LABEL_CHECKING: "Kontroluji nové aktualizace" + BUTTON_UPDATE: "Aktualizovat" BUTTON_DOWNLOAD: "Stáhnout" BUTTON_CHANGELOG: "Seznam změn" POPUPS_ACTIVATE: @@ -179,14 +182,20 @@ cs_CZ: LABEL_SUB_KEY: "Licenční klíč" BUTTON_ACTIVATE: "Aktivovat" LABEL_ACTIVATED: "Aktivováno" - ERROR_INVALID_SUBS_KEY: "Nevalidní licenční klíč" + ERROR_INVALID_SUBS_KEY: "Neplatný licenční klíč" SUBS_KEY_ACTIVATED: "Licenční klíč byl úspěšně aktivován" HTML_DESC: | - Po aktivaci bude prémiové licence pro doménu %DOMAIN% prodloužena. + Po aktivaci bude prémiová licence pro doménu %DOMAIN% prodloužena.
Aktivační klíč lze použít pouze pro jednu doménu.

Jakmile začnete proces aktivace, nelze ho přerušit nebo ukončit. + POPUPS_DOMAIN_ALIAS: + TITLE_ADD_DOMAIN_ALIAS: "Přidat alias" + LABEL_ALIAS: "Alias" + LABEL_DOMAIN: "Doména" + BUTTON_CLOSE: "Zavřít" + BUTTON_ADD: "Přidat" POPUPS_DOMAIN: TITLE_ADD_DOMAIN: "Přidat Doménu" TITLE_ADD_DOMAIN_WITH_NAME: "Přidat Doménu \"%NAME%\"" @@ -240,7 +249,7 @@ cs_CZ: DOMAIN_ALREADY_EXISTS: "Doména již existuje" UNKNOWN_ERROR: "Neznámá chyba" NOTIFICATIONS: - INVALID_TOKEN: "Nevalidní token" + INVALID_TOKEN: "Neplatný token" AUTH_ERROR: "Chyba authentikace" ACCESS_ERROR: "Chyba v přístupu" CONNECTION_ERROR: "Nelze se spojit se serverem" @@ -278,11 +287,11 @@ cs_CZ: CANT_RENAME_FOLDER: "Složku se nepodařilo přejmenovat" CANT_DELETE_FOLDER: "Složku se nepodařilo odstranit" CANT_DELETE_NON_EMPTY_FOLDER: "Nelze odstranit neprázdnou složku" - CANT_SUBSCRIBE_FOLDER: "Can't subscribe folder" - CANT_UNSUBSCRIBE_FOLDER: "Can't unsubscribe folder" + CANT_SUBSCRIBE_FOLDER: "Nelze přihlásit složku" + CANT_UNSUBSCRIBE_FOLDER: "Nelze odhlásit složku" CANT_SAVE_SETTINGS: "Nastavení se nepodařilo uložit" CANT_SAVE_PLUGIN_SETTINGS: "Nastavení se nepodařilo uložit" - DOMAIN_ALREADY_EXISTS: "Táto doména již existuje" + DOMAIN_ALREADY_EXISTS: "Tato doména již existuje" CANT_INSTALL_PACKAGE: "Instalace balíčku se nezdařila" CANT_DELETE_PACKAGE: "Odstranění balíčku se nezdařilo" INVALID_PLUGIN_PACKAGE: "Nevalidní balíček" @@ -291,11 +300,11 @@ cs_CZ: LICENSING_DOMAIN_EXPIRED: "Licence pro tuto doménu vypršela." LICENSING_DOMAIN_BANNED: "Licence pro tuto doménu byla zablokována." DEMO_SEND_MESSAGE_ERROR: "Z důvodu bezpečnosti tento demo účet není oprávněn posílat zprávy na externí emaily!" - DEMO_ACCOUNT_ERROR: "Z důvodu bezpečnosti tento účet nemá oprávnění toto provést!" - ACCOUNT_ALREADY_EXISTS: "Účet už existuje" + DEMO_ACCOUNT_ERROR: "Z důvodu bezpečnosti tento účet nemá oprávnění k této akci!" + ACCOUNT_ALREADY_EXISTS: "Účet již existuje" ACCOUNT_DOES_NOT_EXIST: "Účet neexistuje" MAIL_SERVER_ERROR: "Nastala chyba během přístupu na poštovní server" - INVALID_INPUT_ARGUMENT: "Nevalidní vstupní argument" + INVALID_INPUT_ARGUMENT: "Neplatný vstupní argument" UNKNOWN_ERROR: "Neznámá chyba" STATIC: BACK_LINK: "Obnovit" diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/da_DK.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/da_DK.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/da_DK.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/da_DK.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/de_DE.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/de_DE.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/de_DE.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/de_DE.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/en_US.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/en_US.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/en_US.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/en_US.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/es_ES.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/es_ES.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/es_ES.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/es_ES.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/fa_IR.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/fa_IR.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/fa_IR.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/fa_IR.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/fi_FI.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/fi_FI.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/fi_FI.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/fi_FI.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/fr_FR.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/fr_FR.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/fr_FR.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/fr_FR.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/hu_HU.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/hu_HU.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/hu_HU.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/hu_HU.yml diff --git a/rainloop/app/rainloop/v/1.13.0/app/localization/admin/id_ID.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/id_ID.yml new file mode 100644 index 00000000..f929b07a --- /dev/null +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/id_ID.yml @@ -0,0 +1,324 @@ +id_ID: + LOGIN: + LABEL_LOGIN: "Login" + LABEL_PASSWORD: "Password" + BUTTON_LOGIN: "Login ke panel admin" + TOP_PANEL: + LABEL_PREMIUM: "Premium" + LABEL_ADMIN_PANEL: "Panel Admin" + TABS_LABELS: + LABEL_GENERAL_NAME: "Umum" + LABEL_LOGIN_NAME: "Login" + LABEL_BRANDING_NAME: "Branding" + LABEL_CONTACTS_NAME: "Kontak" + LABEL_DOMAINS_NAME: "Domain" + LABEL_SECURITY_NAME: "Keamanan" + LABEL_INTEGRATION_NAME: "Integrasi" + LABEL_PLUGINS_NAME: "Plugin" + LABEL_PACKAGES_NAME: "Paket" + LABEL_LICENSING_NAME: "Lisensi" + LABEL_ABOUT_NAME: "Tentang" + TAB_GENERAL: + LEGEND_INTERFACE: "Antarmuka" + LABEL_LANGUAGE: "Bahasa" + LABEL_LANGUAGE_ADMIN: "Bahasa (admin)" + LABEL_THEME: "Tema" + LABEL_ALLOW_LANGUAGES_ON_SETTINGS: "Izinkan pemilihan bahasa pada laman pengaturan" + LABEL_ALLOW_THEMES_ON_SETTINGS: "Izinkan pemilihan tema di laman pengaturan" + LABEL_ALLOW_BACKGROUND_ON_SETTINGS: "Izinkan pemilihan gambar latar di laman pengaturan" + LABEL_NEW_FOLDER_MOVE: "Tombol \"pindahkan ke folder\" baru" + LABEL_SHOW_THUMBNAILS: "Tampikankan gambar kecil (lampiran)" + LABEL_ALLOW_GRAVATAR: "Izinkan Gravatar" + LEGEND_MAIN: "Utama" + LABEL_ATTACHMENT_SIZE_LIMIT: "Batas ukuran lampiran" + LABEL_ALLOW_ADDITIONAL_ACCOUNTS: "Izinkan akun tambahan" + LABEL_ALLOW_IDENTITIES: "Izinkan identitas jamak" + LABEL_ALLOW_TEMPLATES: "Izinkan penggunaan template" + ALERT_DATA_ACCESS: "Data foldel RainLoop bisa diakses. Silahkan atur web server anda untuk menyembunyikan folder data dari akses eksternal. Baca selengkapnya di sini:" + ALERT_WARNING: "Peringatan!" + HTML_ALERT_WEAK_PASSWORD: | + Anda menggunakan password admin bawaan. +
+ Atas alasan keamanan, mohon + mengganti + password dengan frasa yang lainnya segera. + TAB_LOGIN: + LEGEND_LOGIN_SCREEN: "Laman login" + LABEL_DEFAULT_DOMAIN: "Domain bawaan" + LABEL_DETERMINE_USER_DOMAIN: "Coba untuk memeriksa user domain" + LABEL_ALLOW_LANGUAGES_ON_LOGIN: "Izinkan pemilihan bahasa di laman login" + LABEL_DETERMINE_USER_LANGUAGE: "Coba untuk memeriksa bahasa user" + TAB_BRANDING: + LEGEND_BRANDING: "Branding" + LABEL_PAGE_TITLE: "Judul laman" + LABEL_LOADING_DESCRIPTION: "Deskripsi loading" + LABEL_FAVICON_URL: "Favicon" + LEGEND_LOGIN: "Login" + LABEL_LOGIN_LOGO: "Logo" + LABEL_LOGIN_DESCRIPTION: "Deskripsi" + LABEL_LOGIN_BACKGROUND: "Gambar latar" + LABEL_LOGIN_CUSTOM_CSS: "Custom CSS" + LABEL_LOGIN_SHOW_POWERED_LINK: "Tampilkan link \"Powered by RainLoop\"" + LEGEND_USER: "User" + LABEL_USER_LOGO: "Logo" + LABEL_USER_LOGO_TITLE: "Judul Logo" + LABEL_USER_LOGO_MESSAGE: "Logo (Tampilan Pesan)" + LABEL_USER_CUSTOM_CSS: "Custom CSS" + LEGEND_WELCOME_PAGE: "Laman selamat datang" + LABEL_WELCOME_PAGE_TITLE: "Judul" + LABEL_WELCOME_PAGE_URL: "URL" + LABEL_WELCOME_PAGE_DISPLAY: "Tampilan" + OPTION_WELCOME_PAGE_DISPLAY_NONE: "Tidak ada" + OPTION_WELCOME_PAGE_DISPLAY_ONCE: "Sekali" + OPTION_WELCOME_PAGE_DISPLAY_ALWAYS: "Selalu" + HTML_ALERT_PREMIUM: "Fungsi ini tersedia hanya untuk pengguna Premium." + TAB_CONTACTS: + LEGEND_CONTACTS: "Kontak" + LEGEND_STORAGE: "Media simpan (PDO)" + LABEL_ENABLE_CONTACTS: "Izinkan kontak" + LABEL_ALLOW_SYNC: "Izinkan sinkronisasi kontak (dengan server CardDAV eksternal)" + LABEL_STORAGE_TYPE: "Tipe" + LABEL_STORAGE_DSN: "Dsn" + LABEL_STORAGE_USER: "User" + LABEL_STORAGE_PASSWORD: "Password" + BUTTON_TEST: "Ujicoba" + ALERT_NOTICE: "Perhatian!" + HTML_ALERT_DO_NOT_USE_THIS_DATABASE: "Jangan gunakan tipe database ini untuk jumlah user aktif yang besar." + HTML_ALERT_DOES_NOT_SUPPORTED: | + Sistem anda tidak mendukung kontak +
+ Anda harus memasang atau mengaktifkan PDO (SQLite / MySQL / PostgreSQL) extension pada server anda. + TAB_DOMAINS: + LEGEND_DOMAINS: "Domain" + BUTTON_ADD_DOMAIN: "Tambah domain" + BUTTON_ADD_ALIAS: "Tambah alias" + DELETE_ARE_YOU_SURE: "Anda yakin?" + HTML_DOMAINS_HELPER: | + Daftar domain webmail yang diizinkan mengakses. +
+ Klik pada nama domain untuk mengatur domain. + TAB_SECURITY: + LEGEND_SECURITY: "Keamanan" + LABEL_ALLOW_TWO_STEP: "Izinkan Verifikasi 2-Langkah" + LABEL_FORCE_TWO_STEP: "Pasakan Verifikasi 2-Langkah" + LABEL_USE_IMAGE_PROXY: "Gunakan proxy lokal untuk gambar dari luar" + LABEL_ALLOW_OPEN_PGP: "Izinkan OpenPGP" + LABEL_SHOW_PHP_INFO: "Tampilkan informasi PHP" + LEGEND_ADMIN_PANEL_ACCESS_CREDENTIALS: "Hak Akses Panel Admin" + LABEL_CURRENT_PASSWORD: "Password saat ini" + LABEL_NEW_LOGIN: "Login baru" + LABEL_NEW_PASSWORD: "Password baru" + LABEL_REPEAT_PASSWORD: "Ulangi" + BUTTON_UPDATE_PASSWORD: "Perbarui Password" + LEGEND_SSL: "SSL" + LABEL_REQUIRE_VERIFICATION: "Diperlukan verifikasi sertifikat SSL dengan (IMAP/SMTP) " + LABEL_ALLOW_SELF_SIGNED: "Izinkan sertifikat yang dibuat sendiri" + TAB_INTEGRATIONS: + LEGEND_GOOGLE: "Google" + LABEL_ENABLE_GOOGLE: "Aktifkan Integrasi Google" + LABEL_GOOGLE_AUTH: "Otorisasi" + LABEL_GOOGLE_DRIVE: "Integrasi Google Drive (Tampilan compose)" + LABEL_GOOGLE_PREVIEW: "Intergrasi Google Viewer (Pratinjau untuk Microsoft Word, Excel dan file PowerPoint)" + LABEL_GOOGLE_CLIENT_ID: "ID Klien" + LABEL_GOOGLE_CLIENT_SECRET: "Kode Rahasia Klien" + LABEL_GOOGLE_API_KEY: "Kunci API" + HINT_GOOGLE_API_KEY: "Diperlukan untuk Google Drive File Picker" + LEGEND_FACEBOOK: "Facebook" + LABEL_ENABLE_FACEBOOK: "Aktifkan Integrasi Facebook (Otorisasi)" + LABEL_FACEBOOK_APP_ID: "ID App" + LABEL_FACEBOOK_APP_SECRET: "Kode rahasia App" + LEGEND_TWITTER: "Twitter" + LABEL_ENABLE_TWITTER: "Aktifkan Integrasi Twitter (Otorisasi)" + LABEL_TWITTER_CONSUMER_KEY: "Kunci Consumer" + LABEL_TWITTER_CONSUMER_SECRET: "Kode Rahasia Consumer" + LEGEND_DROPBOX: "Dropbox" + LABEL_ENABLE_DROPBOX: "Aktifkan Integrasi Dropbox" + LABEL_DROPBOX_API_KEY: "Kunci API" + TOP_ALERT: "Informasi lengkap di Integrasi medsos ditemukan pada" + TAB_PLUGINS: + LEGEND_PLUGINS: "Plugins" + LABEL_ENABLE_PLUGINS: "Aktifkan plugins" + ALERT_NO_PLUGINS: "Belum ada plugins yang terinstal" + LINK_INSTALL_NEW: "Klik di sini untuk menginstall yang baru" + HINT_CLICK_NAME: "Klik pada nama untuk mengatur plugins" + TAB_PACKAGES: + LEGEND_AVAILABLE_FOR_UPDATE: "Tersedia untuk Pembaruan" + LEGEND_AVAILABLE_FOR_INSTALLATION: "Tersedia untuk Instalasi" + LEGEND_INSTALLED_PACKAGES: "Paket Terinstal" + ALERT_CANNOT_ACCESS_REPOSITORY: "Tidak bisa menjangkau repositori saat ini" + TAB_LICENSING: + LABEL_YOUR_DOMAIN: "Domain anda" + LABEL_VERSION: "Versi" + LABEL_CHECKING: "Memeriksa" + TYPE_BASIC_HINT: "Domain ini belum dilisensikan untuk penggunaan komersil (dengan fitur tambahan)." + TYPE_BASIC_HINT_2: "Domain ini tidak bisa dilinsensikan" + HTML_ALERT_TOP_1: "RainLoop Webmail dilisensi di bawah" + HTML_ALERT_TOP_2: "Anda gratis jika ditujukan proyek pribadi." + HTML_ALERT_TOP_3: | + Tujuan penggunaan komersil (dengan fitur tambahan) RainLoop Webmail harus + langganan. + TYPE_PREMIUM_LIFETIME: "Seumur hidup" + LABEL_SUB_EXPIRES: "Langganan berakhir" + BUTTON_ACTIVATE: "Aktifkan Kunci Langganan untuk domain ini" + BUTTON_PURCHASE: "Beli" + BUTTON_TRIAL: "Percobaan" + TAB_ABOUT: + LEGEND_ABOUT: "Tentang" + LABEL_TAG_HINT: "Klien web-based email yang simpel, modern & cepat" + LABEL_ALL_RIGHTS_RESERVED: "Hak Cipta" + HINT_READ_CHANGE_LOG: "Mohon baca log perubahan sebelum melakukan pembaruan" + HINT_IS_UP_TO_DATE: "RainLoop sudah terbaru" + HTML_NEW_VERSION: "Versi %VERSION% baru tersedia" + LABEL_UPDATING: "Memperbarui" + LABEL_CHECKING: "Memeriksa pembaruan" + BUTTON_UPDATE: "Pembaruan" + BUTTON_DOWNLOAD: "Mengunduh" + BUTTON_CHANGELOG: "Log Perubahan" + POPUPS_ACTIVATE: + TITLE_ACTIVATE: "Akifkan kunci berlangganan?" + TITLE_ACTIVATION: "Mengaktivasi..." + LABEL_DOMAIN: "Domain" + LABEL_SUB_KEY: "Kunci Berlangganan" + BUTTON_ACTIVATE: "Aktivasi" + LABEL_ACTIVATED: "Sudah Diaktivasi" + ERROR_INVALID_SUBS_KEY: "Kunci Berlangganan tidak sah" + SUBS_KEY_ACTIVATED: "Kunci berlangganan berhasil diaktifkan" + HTML_DESC: | + Setelah aktivasi, langganan premium untuk %DOMAIN% akan diperpanjang. +
+ Ingat bahwa kunci berlangganan hanya berlaku untuk domain tunggal. +

+ Setelah Dimulai, proses aktivasi tidak bisa dicegah dan dibatalkan. + POPUPS_DOMAIN_ALIAS: + TITLE_ADD_DOMAIN_ALIAS: "Tambah Alias" + LABEL_ALIAS: "Alias" + LABEL_DOMAIN: "Domain" + BUTTON_CLOSE: "Tutup" + BUTTON_ADD: "Tambah" + POPUPS_DOMAIN: + TITLE_ADD_DOMAIN: "Tambah Domain" + TITLE_ADD_DOMAIN_WITH_NAME: "Tambah \"%NAME%\" Domain" + TITLE_EDIT_DOMAIN: "Ubah Domain \"%NAME%\"" + LABEL_NAME: "Nama" + NAME_HELPER: "Mendukung Wildcard" + LABEL_IMAP: "IMAP" + LABEL_SMTP: "SMTP" + LABEL_SIEVE: "SIEVE" + LABEL_SERVER: "Server" + LABEL_PORT: "Port" + LABEL_SECURE: "Aman" + LABEL_WHITE_LIST: "Daftar Putih" + SECURE_OPTION_NONE: "Tidak satupun" + SECURE_OPTION_SSL: "SSL/TLS" + SECURE_OPTION_STARTTLS: "STARTTLS" + LABEL_ALLOW_SIEVE_SCRIPTS: "Izinkan script sieve" + LABEL_ALLOW_USER_SCRIPT: "Izinkan script user yang dikustomisasi" + LABEL_USE_SHORT_LOGIN: "Gunakan login singkat" + LABEL_USE_AUTH: "Gunakan otentikasi" + LABEL_USE_PHP_MAIL: "Gunakan fungsi mail() PHP" + BUTTON_TEST: "Ujicoba" + BUTTON_WHITE_LIST: "Daftar Putih" + BUTTON_SIEVE_CONFIGURATION: "Konfigurasi Sieve" + BUTTON_BACK_TO_IMAP: "Kembali ke pengaturan IMAP" + BUTTON_BACK: "Kembali" + BUTTON_CLOSE: "Tutup" + BUTTON_ADD: "Tambah" + BUTTON_UPDATE: "Perbarui" + NEW_DOMAIN_DESC: "Domain ini mengizinkan anda bekerja dengan alamat email
juga%NAME% " + WHITE_LIST_ALERT: | + Daftar domain webmail user yang diizinkan diakses. + Gunakan spasi untuk pemisahnya + POPUPS_PLUGIN: + TITLE_PLUGIN: "Plugin" + DESC_NOTHING_TO_CONFIGURE: "Tidak ada yang dikonfigurasi" + BUTTON_CLOSE: "Tutup" + BUTTON_SAVE: "Simpan" + TOOLTIP_ABOUT_TITLE: "Tentang" + POPUPS_ASK: + DESC_WANT_CLOSE_THIS_WINDOW: "Anda yakin menutup jendela ini?" + POPUPS_LANGUAGES: + TITLE_LANGUAGES: "Pilih bahasa anda" + HINTS: + BETA: "beta" + UNSTABLE: "Tidak stabil" + WARNING: "Peringatan!" + NOT_SUPPORTED: "tidak didukung" + REQUIRES_PHP_54: "Membutuhkan PHP 5.4 atau terbaru" + ERRORS: + DOMAIN_ALREADY_EXISTS: "Domain sudah ada" + UNKNOWN_ERROR: "Kesalahan tidak diketahui" + NOTIFICATIONS: + INVALID_TOKEN: "Token invalid" + AUTH_ERROR: "Otentikasi gagal" + ACCESS_ERROR: "Akses error" + CONNECTION_ERROR: "Tidak bisa terhubung ke server" + CAPTCHA_ERROR: "CAPTCHA salah" + SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE: > + Social ID ini tidak dipasangkan untuk akun email manapun. Login dengan kredensial + email dan aktifkan fitur ini pada seting akun. + SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE: > + Social ID ini tidak dipasangkan untuk akun email manapun. Login dengan kredensial + email dan aktifkan fitur ini pada seting akun. + SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE: > + Social ID ini tidak dipasangkan untuk akun email manapun. Login dengan kredensial + email dan aktifkan fitur ini pada seting akun. + DOMAIN_NOT_ALLOWED: "Domain tidak diizinkan" + ACCOUNT_NOT_ALLOWED: "Akun tidak diizinkan" + ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Dibutuhkan verifikasi dua langkah" + ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Kesalahan verifikasi dua langkah" + COULD_NOT_SAVE_NEW_PASSWORD: "Tidak bisa menyimpan password baru" + CURRENT_PASSWORD_INCORRECT: "Password saat ini salah" + NEW_PASSWORD_SHORT: "Password terlalu pendek" + NEW_PASSWORD_WEAK: "Password terlalu mudah" + NEW_PASSWORD_FORBIDDENT: "Password mengandung karakter terlarang" + CONTACTS_SYNC_ERROR: "Singkronisasi kontak error" + CANT_GET_MESSAGE_LIST: "Tidak bisa mengambil daftar pesan" + CANT_GET_MESSAGE: "Tidak bisa mengambil pesan" + CANT_DELETE_MESSAGE: "Tidak bisa menghapus pesan" + CANT_MOVE_MESSAGE: "Tidak bisa memindahkan pesan" + CANT_SAVE_MESSAGE: "Tidak bisa menyimpan pesan" + CANT_SEND_MESSAGE: "Tidak bisa mengirim pesan" + INVALID_RECIPIENTS: "Penerima tidak sah" + CANT_SAVE_FILTERS: "Tidak bisa menyimpan filter" + CANT_GET_FILTERS: "Tidak bisa mengambil filter" + FILTERS_ARE_NOT_CORRECT: "Filter tidak benar" + CANT_CREATE_FOLDER: "Tidak bisa membuat folder" + CANT_RENAME_FOLDER: "Tidak bisa mengubah nama folder" + CANT_DELETE_FOLDER: "Tidak bisa menghapus folder" + CANT_DELETE_NON_EMPTY_FOLDER: "Tidak bisa menghapus direktori yang berisi" + CANT_SUBSCRIBE_FOLDER: "Tidak bisa mengaitkan folder" + CANT_UNSUBSCRIBE_FOLDER: "Tidak bisa memutuskan folder" + CANT_SAVE_SETTINGS: "Tidak bisa menyimpan pengaturan" + CANT_SAVE_PLUGIN_SETTINGS: "Tidak bisa menyimpan pengaturan" + DOMAIN_ALREADY_EXISTS: "Domain sudah ada" + CANT_INSTALL_PACKAGE: "Gagal memasang paket" + CANT_DELETE_PACKAGE: "Gagal menghapus paket" + INVALID_PLUGIN_PACKAGE: "Paket plugin tidak sah" + UNSUPPORTED_PLUGIN_PACKAGE: "Paket plugin tidak didukung" + LICENSING_SERVER_IS_UNAVAILABLE: "Server berlangganan tidak tersedia" + LICENSING_DOMAIN_EXPIRED: "Berlangganan untuk domain ini telah habis." + LICENSING_DOMAIN_BANNED: "Berlangganan untuk domain ini ditolak." + DEMO_SEND_MESSAGE_ERROR: "Untuk alasan keamanan, akun ini tidak diizinkan untuk mengirim pesan ke alamat e-mail eksternal!" + DEMO_ACCOUNT_ERROR: "Untuk alasan keamanan, akun ini tidak diizinkan melakukan aksi ini!" + ACCOUNT_ALREADY_EXISTS: "Akun telah ada" + ACCOUNT_DOES_NOT_EXIST: "Akun tidak ada" + MAIL_SERVER_ERROR: "Terjadi kesalahan saat mengakses mail server" + INVALID_INPUT_ARGUMENT: "Argumen input tidak sah" + UNKNOWN_ERROR: "Kesalahan tidak diketahui" + STATIC: + BACK_LINK: "Muat ulang" + DOMAIN_LIST_DESC: "Daftar domain yang diizinkan untuk diakses." + PHP_EXSTENSIONS_ERROR_DESC: "Ekstensi PHP yang diperlukan tidak tersedia dalam konfigurasi PHP anda!" + PHP_VERSION_ERROR_DESC: "Versi PHP anda (%VERSION%) lebih rendah dari syarat minimal 5.3.0!" + NO_SCRIPT_TITLE: "Javascript diperlukan oleh aplikasi ini." + NO_SCRIPT_DESC: | + Dukungan Javascript tidak tersedia pada browser anda + Aktifkan Javascript pada pengaturan browser kemudian coba lagi. + NO_COOKIE_TITLE: "Dukungan Cookie diperlukan oleh aplikasi ini." + NO_COOKIE_DESC: | + Dukungan Cookie tidak tersedia pada browser anda + Aktifkan Cookie pada pengaturan browser kemudian coba lagi + BAD_BROWSER_TITLE: "Browser anda kadaluarsa." + BAD_BROWSER_DESC: | + Untuk bisa menggunakan seluruh fitur aplikasi, + download dan install salah satu browser berikut. diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/it_IT.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/it_IT.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/it_IT.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/it_IT.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/ja_JP.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/ja_JP.yml similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/ja_JP.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/ja_JP.yml index 640e9285..113c93ca 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/ja_JP.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/ja_JP.yml @@ -34,6 +34,7 @@ ja_JP: LABEL_ALLOW_ADDITIONAL_ACCOUNTS: "追加のアカウントを使用する" LABEL_ALLOW_IDENTITIES: "複数の表示名を使用する" LABEL_ALLOW_TEMPLATES: "テンプレートを許可する" + ALERT_DATA_ACCESS: "RainLoop のデータフォルダがアクセス可能になっています。外部から RainLoop のデータフォルダにアクセスできないよう、Web サーバーを設定してください。詳しくは以下をご覧ください:" ALERT_WARNING: "警告!" HTML_ALERT_WEAK_PASSWORD: | デフォルトの管理者パスワードを使用しています。 diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/lt_LT.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/lt_LT.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/lt_LT.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/lt_LT.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/nb_NO.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/nb_NO.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/nb_NO.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/nb_NO.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/nl_NL.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/nl_NL.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/nl_NL.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/nl_NL.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/pl_PL.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/pl_PL.yml similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/pl_PL.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/pl_PL.yml index fb263596..db55fcfc 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/pl_PL.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/pl_PL.yml @@ -13,9 +13,9 @@ pl_PL: LABEL_CONTACTS_NAME: "Kontakty" LABEL_DOMAINS_NAME: "Domeny" LABEL_SECURITY_NAME: "Bezpieczeństwo" - LABEL_INTEGRATION_NAME: "Integracja" + LABEL_INTEGRATION_NAME: "Integracje" LABEL_PLUGINS_NAME: "Wtyczki" - LABEL_PACKAGES_NAME: "Zarządzanie wtyczkami" + LABEL_PACKAGES_NAME: "Pakiety" LABEL_LICENSING_NAME: "Licencjonowanie" LABEL_ABOUT_NAME: "O programie" TAB_GENERAL: @@ -26,7 +26,7 @@ pl_PL: LABEL_ALLOW_LANGUAGES_ON_SETTINGS: "Zezwól użytkownikowi na wybór języka" LABEL_ALLOW_THEMES_ON_SETTINGS: "Zezwól użytkownikowi na zmianę motywu" LABEL_ALLOW_BACKGROUND_ON_SETTINGS: "Zezwól użytkownikowi na użycie własnego tła" - LABEL_NEW_FOLDER_MOVE: "Nowy przycisk \"przenieś do folderu\"" + LABEL_NEW_FOLDER_MOVE: "Nowy przycisk „przenieś do folderu”" LABEL_SHOW_THUMBNAILS: "Pokaż miniatury (załączniki)" LABEL_ALLOW_GRAVATAR: "Zezwól na używanie gravatarów" LEGEND_MAIN: "Główne" @@ -52,13 +52,13 @@ pl_PL: LEGEND_BRANDING: "Personalizacja" LABEL_PAGE_TITLE: "Tytuł strony" LABEL_LOADING_DESCRIPTION: "Komunikat ładowania strony" - LABEL_FAVICON_URL: "Favicon" + LABEL_FAVICON_URL: "Favikona" LEGEND_LOGIN: "Login" LABEL_LOGIN_LOGO: "Logo" LABEL_LOGIN_DESCRIPTION: "Opis" LABEL_LOGIN_BACKGROUND: "Tło" LABEL_LOGIN_CUSTOM_CSS: "Własny arkusz styli CSS" - LABEL_LOGIN_SHOW_POWERED_LINK: "Pokaż link \"Powered by RainLoop\"" + LABEL_LOGIN_SHOW_POWERED_LINK: "Pokaż link „Powered by RainLoop”" LEGEND_USER: "Użytkownik" LABEL_USER_LOGO: "Logo" LABEL_USER_LOGO_TITLE: "Tytuł logo" @@ -122,7 +122,7 @@ pl_PL: LABEL_GOOGLE_CLIENT_ID: "Identyfikator klienta" LABEL_GOOGLE_CLIENT_SECRET: "Hasło" LABEL_GOOGLE_API_KEY: "Klucz API" - HINT_GOOGLE_API_KEY: "Wymagane dla obsługi interfejsu usługi 'Dysk Google'" + HINT_GOOGLE_API_KEY: "Wymagane dla obsługi interfejsu usługi „Dysk Google”" LEGEND_FACEBOOK: "Facebook" LABEL_ENABLE_FACEBOOK: "Włącz integrację z Facebook (autoryzacja)" LABEL_FACEBOOK_APP_ID: "Identyfikator aplikacji" @@ -142,8 +142,8 @@ pl_PL: LINK_INSTALL_NEW: "Kliknij tutaj, aby zainstalować nowe wtyczki!" HINT_CLICK_NAME: "Kliknij na nazwę, aby skonfigurować wtyczkę." TAB_PACKAGES: - LEGEND_AVAILABLE_FOR_UPDATE: "Dostępna do aktualizacji" - LEGEND_AVAILABLE_FOR_INSTALLATION: "Dostępna do zainstalowania" + LEGEND_AVAILABLE_FOR_UPDATE: "Dostępne do aktualizacji" + LEGEND_AVAILABLE_FOR_INSTALLATION: "Dostępne do zainstalowania" LEGEND_INSTALLED_PACKAGES: "Zainstalowane pakiety" ALERT_CANNOT_ACCESS_REPOSITORY: "Nie można uzyskać dostępu do repozytorium." TAB_LICENSING: @@ -197,8 +197,8 @@ pl_PL: BUTTON_ADD: "Dodaj" POPUPS_DOMAIN: TITLE_ADD_DOMAIN: "Dodawanie domeny" - TITLE_ADD_DOMAIN_WITH_NAME: "Dodawanie domeny \"%NAME%\"" - TITLE_EDIT_DOMAIN: "Edycja domeny \"%NAME%\"" + TITLE_ADD_DOMAIN_WITH_NAME: "Dodawanie domeny „%NAME%”" + TITLE_EDIT_DOMAIN: "Edycja domeny „%NAME%”" LABEL_NAME: "Nazwa" NAME_HELPER: "obsługiwany znak wieloznaczności - *" LABEL_IMAP: "IMAP" @@ -216,7 +216,7 @@ pl_PL: LABEL_USE_SHORT_LOGIN: "Użyj krótkiego loginu" LABEL_USE_AUTH: "Użyj autoryzacji" LABEL_USE_PHP_MAIL: "Użyj funkcji php 'mail()'" - BUTTON_TEST: "Test" + BUTTON_TEST: "Testuj" BUTTON_WHITE_LIST: "Biała lista" BUTTON_SIEVE_CONFIGURATION: "Konfiguracja sieve" BUTTON_BACK_TO_IMAP: "Powrót do ustawień serwera IMAP" diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/pt_BR.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/pt_BR.yml similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/pt_BR.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/pt_BR.yml index 0179fb8f..a5b4db79 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/pt_BR.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/pt_BR.yml @@ -34,6 +34,7 @@ pt_BR: LABEL_ALLOW_ADDITIONAL_ACCOUNTS: "Permitir contas adicionais" LABEL_ALLOW_IDENTITIES: "Permitir identidades multiplas" LABEL_ALLOW_TEMPLATES: "Permitir templates" + ALERT_DATA_ACCESS: "A pasta de dados RainLoop está acessível. Por favor configure o seu servidor web para esconder a pasta de dados do acesso externo. Leia mais aqui:" ALERT_WARNING: "Aviso!" HTML_ALERT_WEAK_PASSWORD: | Você está usando a senha administrativa padrão. diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/ru_RU.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/ru_RU.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/ru_RU.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/ru_RU.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/sk_SK.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/sk_SK.yml similarity index 76% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/sk_SK.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/sk_SK.yml index dfe63b1a..abff0178 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/sk_SK.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/sk_SK.yml @@ -1,9 +1,10 @@ sk_SK: LOGIN: - LABEL_LOGIN: "Používateľské meno" + LABEL_LOGIN: "Prihlasovanie" LABEL_PASSWORD: "Heslo" BUTTON_LOGIN: "Prihlásiť sa do admin panelu" TOP_PANEL: + LABEL_PREMIUM: "Premium" LABEL_ADMIN_PANEL: "Admin Panel" TABS_LABELS: LABEL_GENERAL_NAME: "Všeobecné" @@ -13,6 +14,7 @@ sk_SK: LABEL_DOMAINS_NAME: "Domény" LABEL_SECURITY_NAME: "Zabezpečenie" LABEL_INTEGRATION_NAME: "Integrácie" + LABEL_PLUGINS_NAME: "Doplnky" LABEL_PACKAGES_NAME: "Balíčky" LABEL_LICENSING_NAME: "Licencovanie" LABEL_ABOUT_NAME: "O programe" @@ -21,13 +23,33 @@ sk_SK: LABEL_LANGUAGE: "Jazyk" LABEL_LANGUAGE_ADMIN: "Jazyk (admin)" LABEL_THEME: "Téma" + LABEL_ALLOW_LANGUAGES_ON_SETTINGS: "Povoliť výber jazyka v nastaveniach" + LABEL_ALLOW_THEMES_ON_SETTINGS: "Povoliť výber témy v nastaveniach" + LABEL_ALLOW_BACKGROUND_ON_SETTINGS: "Povoliť výber pozadia v nastaveniach" + LABEL_SHOW_THUMBNAILS: "Zobraziť náhľady (prílohy)" + LABEL_ALLOW_GRAVATAR: "Povoliť Gravatar" LEGEND_MAIN: "Všeobecné" + LABEL_ATTACHMENT_SIZE_LIMIT: "Maximálna veľkosť prílohy" + LABEL_ALLOW_ADDITIONAL_ACCOUNTS: "Povoliť ďalšie účty" + LABEL_ALLOW_IDENTITIES: "Povoliť viaceré identity" LABEL_ALLOW_TEMPLATES: "Povoliť šablóny" + ALERT_DATA_ACCESS: "Adresár data je dostupný. Prosím skonfigurujte svoj webserver tak, aby bol adresár data nedostupný. Viac informácií:" ALERT_WARNING: "Upozornenie!" + HTML_ALERT_WEAK_PASSWORD: | + Používate predvolené administrátorské heslo. +
+ Kvôli bezpečnosti prosím + zmeňte + heslo na iné. TAB_LOGIN: LEGEND_LOGIN_SCREEN: "Prihlasovacia obrazovka" LABEL_DEFAULT_DOMAIN: "Predvolená doména" + LABEL_DETERMINE_USER_DOMAIN: "Pokúsiť sa určiť doménu používateľa" + LABEL_ALLOW_LANGUAGES_ON_LOGIN: "Povoliť výber jazyka na prihlasovacej obrazovke" + LABEL_DETERMINE_USER_LANGUAGE: "Pokúsiť sa určiť používateľov jazyk" TAB_BRANDING: + LEGEND_BRANDING: "Vlastné označenie" + LABEL_PAGE_TITLE: "Názov stránky" LABEL_FAVICON_URL: "Favicon" LEGEND_LOGIN: "Používateľské meno" LABEL_LOGIN_LOGO: "Logo" @@ -37,6 +59,8 @@ sk_SK: LABEL_LOGIN_SHOW_POWERED_LINK: "Zobraziť link \"Powered by RainLoop\"" LEGEND_USER: "Užívateľ" LABEL_USER_LOGO: "Logo" + LABEL_USER_LOGO_TITLE: "Nadpis loga" + LABEL_USER_LOGO_MESSAGE: "Logo (zobrazenie správy)" LABEL_USER_CUSTOM_CSS: "Vlastné CSS" LEGEND_WELCOME_PAGE: "Uvítacia stránka" LABEL_WELCOME_PAGE_TITLE: "Nadpis" @@ -47,12 +71,15 @@ sk_SK: OPTION_WELCOME_PAGE_DISPLAY_ALWAYS: "Vždy" TAB_CONTACTS: LEGEND_CONTACTS: "Kontakty" + LEGEND_STORAGE: "Úložisko (PDO)" LABEL_ENABLE_CONTACTS: "Zapnúť kontakty" + LABEL_ALLOW_SYNC: "Povoliť synchronizáciu kontaktov (s externým CardDAV serverom)" LABEL_STORAGE_TYPE: "Typ" LABEL_STORAGE_DSN: "Dsn" LABEL_STORAGE_USER: "Užívateľ" LABEL_STORAGE_PASSWORD: "Heslo" BUTTON_TEST: "Test" + HTML_ALERT_DO_NOT_USE_THIS_DATABASE: "Nepoužívajte tento typ databázy, ak máte veľký počet aktívnych používateľov." TAB_DOMAINS: LEGEND_DOMAINS: "Domény" BUTTON_ADD_DOMAIN: "Pridať doménu" @@ -60,20 +87,32 @@ sk_SK: DELETE_ARE_YOU_SURE: "Ste si istí?" TAB_SECURITY: LEGEND_SECURITY: "Bezpečnosť" + LABEL_ALLOW_TWO_STEP: "Povoliť 2-krokovú verifikáciu" + LABEL_FORCE_TWO_STEP: "Vyžadovať 2-krokovú verifikáciu" + LABEL_ALLOW_OPEN_PGP: "Povoliť OpenPGP" + LABEL_SHOW_PHP_INFO: "Zobraziť informácie o PHP" LABEL_CURRENT_PASSWORD: "Súčasné heslo" + LABEL_NEW_LOGIN: "Nový login" LABEL_NEW_PASSWORD: "Nové heslo" LABEL_REPEAT_PASSWORD: "Opakovať" + BUTTON_UPDATE_PASSWORD: "Zmeniť heslo" LEGEND_SSL: "SSL" TAB_INTEGRATIONS: LEGEND_GOOGLE: "Google" + LABEL_ENABLE_GOOGLE: "Povoliť integráciu s Google" LABEL_GOOGLE_AUTH: "Overenie" LABEL_GOOGLE_CLIENT_ID: "ID klienta" LABEL_GOOGLE_API_KEY: "Api kľúč" LEGEND_FACEBOOK: "Facebook" + LABEL_ENABLE_FACEBOOK: "Povoliť integráciu s Facebook (autorizácia)" LEGEND_TWITTER: "Twitter" LABEL_ENABLE_TWITTER: "Povoliť Twitter intergáciu (overenie)" LEGEND_DROPBOX: "Dropbox" + LABEL_ENABLE_DROPBOX: "Povoliť integráciu s Dropbox" LABEL_DROPBOX_API_KEY: "Api kľúč" + TAB_PLUGINS: + LEGEND_PLUGINS: "Doplnky" + LABEL_ENABLE_PLUGINS: "Povoliť doplnky" TAB_PACKAGES: LEGEND_AVAILABLE_FOR_UPDATE: "Dostupné na aktualizáciu" LEGEND_AVAILABLE_FOR_INSTALLATION: "Dostupné na inštaláciu" @@ -88,6 +127,7 @@ sk_SK: BUTTON_PURCHASE: "Kúpiť" BUTTON_TRIAL: "Skúšobná verzia" TAB_ABOUT: + LEGEND_ABOUT: "O programe" LABEL_TAG_HINT: "Jednoduchý, moderný a rýchly webmail klient" LABEL_ALL_RIGHTS_RESERVED: "Všetky práva vyhradené." HINT_READ_CHANGE_LOG: "Prosím prečítajte si zoznam zmien pred aktualizáciou." @@ -120,22 +160,27 @@ sk_SK: LABEL_SERVER: "Server" LABEL_PORT: "Port" LABEL_SECURE: "Bezpečné" + LABEL_WHITE_LIST: "Zoznam povolených" SECURE_OPTION_NONE: "Žiadne" SECURE_OPTION_SSL: "SSL/TLS" SECURE_OPTION_STARTTLS: "STARTTLS" + LABEL_ALLOW_SIEVE_SCRIPTS: "Povoliť Sieve skripty" LABEL_USE_SHORT_LOGIN: "Použiť skrátené prihlásenie" LABEL_USE_AUTH: "Použiť overenie" LABEL_USE_PHP_MAIL: "Použiť php mail() funkciu" BUTTON_TEST: "Test" - BUTTON_SIEVE_CONFIGURATION: "Uložiť nastavenia" + BUTTON_WHITE_LIST: "Zoznam povolených" + BUTTON_SIEVE_CONFIGURATION: "Nastavenia Sieve" BUTTON_BACK_TO_IMAP: "Späť do IMAP nastavení" BUTTON_BACK: "Späť" BUTTON_CLOSE: "Zatvoriť" BUTTON_ADD: "Pridať" BUTTON_UPDATE: "Aktualizovať" POPUPS_PLUGIN: + TITLE_PLUGIN: "Doplnok" BUTTON_CLOSE: "Zatvoriť" BUTTON_SAVE: "Uložiť" + TOOLTIP_ABOUT_TITLE: "O programe" POPUPS_LANGUAGES: TITLE_LANGUAGES: "Zvoľte jazyk" HINTS: diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/sl_SI.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/sl_SI.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/sl_SI.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/sl_SI.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/sv_SE.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/sv_SE.yml similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/sv_SE.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/sv_SE.yml index fd9912cb..a73b5b38 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/sv_SE.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/sv_SE.yml @@ -34,7 +34,8 @@ sv_SE: LABEL_ALLOW_ADDITIONAL_ACCOUNTS: "Tillåt ytterligare konton" LABEL_ALLOW_IDENTITIES: "Tillåt multiidentiteter" LABEL_ALLOW_TEMPLATES: "Tillåt mallar" - ALERT_WARNING: "Advarsel!" + ALERT_DATA_ACCESS: "RainLoops datamapp är åtkomstbar. Var vänlig konfigurera din webb-server för att förhindra extern åtkomst och synlighet. Läs mer här: " + ALERT_WARNING: "Varning!" HTML_ALERT_WEAK_PASSWORD: | Du använder standardlösenord.
diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/admin/zh_CN.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/admin/zh_CN.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/admin/zh_CN.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/admin/zh_CN.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/langs.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/langs.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/langs.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/langs.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/af.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/af.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/af.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/af.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-dz.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-dz.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-dz.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-dz.js index 26a7ccb2..e6efd0a2 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-dz.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-dz.js @@ -49,7 +49,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 4 // The week that contains Jan 1st is the first week of the year. + doy : 4 // The week that contains Jan 4th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-kw.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-kw.js similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-kw.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-kw.js index 10092ba3..6a72e9ba 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-kw.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-kw.js @@ -49,7 +49,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. + doy : 12 // The week that contains Jan 12th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-ly.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-ly.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-ly.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-ly.js index 2e3cb1a7..0df68c8b 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-ly.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-ly.js @@ -112,7 +112,7 @@ }, week : { dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. + doy : 12 // The week that contains Jan 12th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-ma.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-ma.js similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-ma.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-ma.js index 3d8503d1..42db49a7 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-ma.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-ma.js @@ -49,7 +49,7 @@ }, week : { dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. + doy : 12 // The week that contains Jan 12th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-sa.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-sa.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-sa.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-sa.js index a62f8da4..1c6d46d5 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-sa.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-sa.js @@ -94,7 +94,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. + doy : 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-tn.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-tn.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-tn.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar-tn.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar.js index 3c6506b3..1549cc15 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ar.js @@ -125,7 +125,7 @@ }, week : { dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. + doy : 12 // The week that contains Jan 12th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/az.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/az.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/az.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/az.js index 578b70c5..348ddffe 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/az.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/az.js @@ -95,7 +95,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/be.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/be.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/be.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/be.js index db7a3c76..10db1c19 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/be.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/be.js @@ -122,7 +122,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bg.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/bg.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/bg.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/bg.js index f8528a2a..c70ba304 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bg.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/bg.js @@ -80,7 +80,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bm.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/bm.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/bm.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/bm.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bn.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/bn.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/bn.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/bn.js index d7d33f53..8fe71586 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bn.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/bn.js @@ -109,7 +109,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. + doy : 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bo.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/bo.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/bo.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/bo.js index ff0dcbec..6a980163 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bo.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/bo.js @@ -109,7 +109,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. + doy : 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/br.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/br.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/br.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/br.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bs.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/bs.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/bs.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/bs.js index 0aaf0e14..5e3e4286 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bs.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/bs.js @@ -141,7 +141,7 @@ ordinal : '%d.', week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ca.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ca.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ca.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ca.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/cs.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/cs.js similarity index 82% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/cs.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/cs.js index 5ae9b627..bb9e3572 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/cs.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/cs.js @@ -10,6 +10,12 @@ var months = 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split('_'), monthsShort = 'led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro'.split('_'); + + var monthsParse = [/^led/i, /^úno/i, /^bře/i, /^dub/i, /^kvě/i, /^(čvn|červen$|června)/i, /^(čvc|červenec|července)/i, /^srp/i, /^zář/i, /^říj/i, /^lis/i, /^pro/i]; + // NOTE: 'červen' is substring of 'červenec'; therefore 'červenec' must precede 'červen' in the regex to be fully matched. + // Otherwise parser matches '1. červenec' as '1. červen' + 'ec'. + var monthsRegex = /^(leden|únor|březen|duben|květen|červenec|července|červen|června|srpen|září|říjen|listopad|prosinec|led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i; + function plural(n) { return (n > 1) && (n < 5) && (~~(n / 10) !== 1); } @@ -76,28 +82,15 @@ var cs = moment.defineLocale('cs', { months : months, monthsShort : monthsShort, - monthsParse : (function (months, monthsShort) { - var i, _monthsParse = []; - for (i = 0; i < 12; i++) { - // use custom parser to solve problem with July (červenec) - _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i'); - } - return _monthsParse; - }(months, monthsShort)), - shortMonthsParse : (function (monthsShort) { - var i, _shortMonthsParse = []; - for (i = 0; i < 12; i++) { - _shortMonthsParse[i] = new RegExp('^' + monthsShort[i] + '$', 'i'); - } - return _shortMonthsParse; - }(monthsShort)), - longMonthsParse : (function (months) { - var i, _longMonthsParse = []; - for (i = 0; i < 12; i++) { - _longMonthsParse[i] = new RegExp('^' + months[i] + '$', 'i'); - } - return _longMonthsParse; - }(months)), + monthsRegex : monthsRegex, + monthsShortRegex : monthsRegex, + // NOTE: 'červen' is substring of 'červenec'; therefore 'červenec' must precede 'červen' in the regex to be fully matched. + // Otherwise parser matches '1. červenec' as '1. červen' + 'ec'. + monthsStrictRegex : /^(leden|ledna|února|únor|březen|března|duben|dubna|květen|května|červenec|července|červen|června|srpen|srpna|září|říjen|října|listopadu|listopad|prosinec|prosince)/i, + monthsShortStrictRegex : /^(led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i, + monthsParse : monthsParse, + longMonthsParse : monthsParse, + shortMonthsParse : monthsParse, weekdays : 'neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota'.split('_'), weekdaysShort : 'ne_po_út_st_čt_pá_so'.split('_'), weekdaysMin : 'ne_po_út_st_čt_pá_so'.split('_'), diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/cv.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/cv.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/cv.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/cv.js index 9b99c3c4..1db1488c 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/cv.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/cv.js @@ -53,7 +53,7 @@ ordinal : '%d-мӗш', week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/cy.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/cy.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/cy.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/cy.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/da.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/da.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/da.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/da.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/de-at.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/de-at.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/de-at.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/de-at.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/de-ch.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/de-ch.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/de-ch.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/de-ch.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/de.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/de.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/de.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/de.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/dv.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/dv.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/dv.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/dv.js index 6f057ca1..8729b02c 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/dv.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/dv.js @@ -89,7 +89,7 @@ }, week : { dow : 7, // Sunday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. + doy : 12 // The week that contains Jan 12th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/el.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/el.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/el.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/el.js diff --git a/rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-SG.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-SG.js new file mode 100644 index 00000000..4c69f117 --- /dev/null +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-SG.js @@ -0,0 +1,66 @@ +//! moment.js locale configuration + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + && typeof require === 'function' ? factory(require('../moment')) : + typeof define === 'function' && define.amd ? define(['../moment'], factory) : + factory(global.moment) +}(this, (function (moment) { 'use strict'; + + + var enSG = moment.defineLocale('en-SG', { + months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), + monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), + weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD/MM/YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY HH:mm', + LLLL : 'dddd, D MMMM YYYY HH:mm' + }, + calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }, + relativeTime : { + future : 'in %s', + past : '%s ago', + s : 'a few seconds', + ss : '%d seconds', + m : 'a minute', + mm : '%d minutes', + h : 'an hour', + hh : '%d hours', + d : 'a day', + dd : '%d days', + M : 'a month', + MM : '%d months', + y : 'a year', + yy : '%d years' + }, + dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/, + ordinal : function (number) { + var b = number % 10, + output = (~~(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + }, + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } + }); + + return enSG; + +}))); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-au.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-au.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-au.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-au.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-ca.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-ca.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-ca.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-ca.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-gb.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-gb.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-gb.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-gb.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-ie.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-ie.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-ie.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-ie.js index ede6c671..de0984cf 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-ie.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-ie.js @@ -17,7 +17,7 @@ longDateFormat : { LT : 'HH:mm', LTS : 'HH:mm:ss', - L : 'DD-MM-YYYY', + L : 'DD/MM/YYYY', LL : 'D MMMM YYYY', LLL : 'D MMMM YYYY HH:mm', LLLL : 'dddd D MMMM YYYY HH:mm' diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-il.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-il.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-il.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-il.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-nz.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-nz.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-nz.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/en-nz.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/eo.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/eo.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/eo.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/eo.js index 40eaee2f..283ebed8 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/eo.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/eo.js @@ -61,7 +61,7 @@ ordinal : '%da', week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/es-do.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/es-do.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/es-do.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/es-do.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/es-us.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/es-us.js similarity index 74% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/es-us.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/es-us.js index c12b5326..8e07d077 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/es-us.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/es-us.js @@ -11,6 +11,9 @@ var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_'), monthsShort = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_'); + var monthsParse = [/^ene/i, /^feb/i, /^mar/i, /^abr/i, /^may/i, /^jun/i, /^jul/i, /^ago/i, /^sep/i, /^oct/i, /^nov/i, /^dic/i]; + var monthsRegex = /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i; + var esUs = moment.defineLocale('es-us', { months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'), monthsShort : function (m, format) { @@ -22,7 +25,13 @@ return monthsShortDot[m.month()]; } }, - monthsParseExact : true, + monthsRegex: monthsRegex, + monthsShortRegex: monthsRegex, + monthsStrictRegex: /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i, + monthsShortStrictRegex: /^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i, + monthsParse: monthsParse, + longMonthsParse: monthsParse, + shortMonthsParse: monthsParse, weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'), weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'), weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'), @@ -31,9 +40,9 @@ LT : 'h:mm A', LTS : 'h:mm:ss A', L : 'MM/DD/YYYY', - LL : 'MMMM [de] D [de] YYYY', - LLL : 'MMMM [de] D [de] YYYY h:mm A', - LLLL : 'dddd, MMMM [de] D [de] YYYY h:mm A' + LL : 'D [de] MMMM [de] YYYY', + LLL : 'D [de] MMMM [de] YYYY h:mm A', + LLLL : 'dddd, D [de] MMMM [de] YYYY h:mm A' }, calendar : { sameDay : function () { @@ -73,7 +82,7 @@ ordinal : '%dº', week : { dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. + doy : 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/es.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/es.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/es.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/es.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/et.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/et.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/et.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/et.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/eu.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/eu.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/eu.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/eu.js index afe919fd..2c7781b9 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/eu.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/eu.js @@ -56,7 +56,7 @@ ordinal : '%d.', week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fa.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/fa.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/fa.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/fa.js index c042e315..e84f7ca1 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fa.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/fa.js @@ -96,7 +96,7 @@ ordinal : '%dم', week : { dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. + doy : 12 // The week that contains Jan 12th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fi.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/fi.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/fi.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/fi.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fo.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/fo.js similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/fo.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/fo.js index eac46d2b..8e81cfe6 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fo.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/fo.js @@ -35,13 +35,13 @@ past : '%s síðani', s : 'fá sekund', ss : '%d sekundir', - m : 'ein minutt', + m : 'ein minuttur', mm : '%d minuttir', h : 'ein tími', hh : '%d tímar', d : 'ein dagur', dd : '%d dagar', - M : 'ein mánaði', + M : 'ein mánaður', MM : '%d mánaðir', y : 'eitt ár', yy : '%d ár' diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr-ca.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/fr-ca.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr-ca.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/fr-ca.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr-ch.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/fr-ch.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr-ch.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/fr-ch.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/fr.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/fr.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fy.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/fy.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/fy.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/fy.js diff --git a/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ga.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ga.js new file mode 100644 index 00000000..a5b92de4 --- /dev/null +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ga.js @@ -0,0 +1,76 @@ +//! moment.js locale configuration + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + && typeof require === 'function' ? factory(require('../moment')) : + typeof define === 'function' && define.amd ? define(['../moment'], factory) : + factory(global.moment) +}(this, (function (moment) { 'use strict'; + + + + var months = [ + 'Eanáir', 'Feabhra', 'Márta', 'Aibreán', 'Bealtaine', 'Méitheamh', 'Iúil', 'Lúnasa', 'Meán Fómhair', 'Deaireadh Fómhair', 'Samhain', 'Nollaig' + ]; + + var monthsShort = ['Eaná', 'Feab', 'Márt', 'Aibr', 'Beal', 'Méit', 'Iúil', 'Lúna', 'Meán', 'Deai', 'Samh', 'Noll']; + + var weekdays = ['Dé Domhnaigh', 'Dé Luain', 'Dé Máirt', 'Dé Céadaoin', 'Déardaoin', 'Dé hAoine', 'Dé Satharn']; + + var weekdaysShort = ['Dom', 'Lua', 'Mái', 'Céa', 'Déa', 'hAo', 'Sat']; + + var weekdaysMin = ['Do', 'Lu', 'Má', 'Ce', 'Dé', 'hA', 'Sa']; + + var ga = moment.defineLocale('ga', { + months: months, + monthsShort: monthsShort, + monthsParseExact: true, + weekdays: weekdays, + weekdaysShort: weekdaysShort, + weekdaysMin: weekdaysMin, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm' + }, + calendar: { + sameDay: '[Inniu ag] LT', + nextDay: '[Amárach ag] LT', + nextWeek: 'dddd [ag] LT', + lastDay: '[Inné aig] LT', + lastWeek: 'dddd [seo caite] [ag] LT', + sameElse: 'L' + }, + relativeTime: { + future: 'i %s', + past: '%s ó shin', + s: 'cúpla soicind', + ss: '%d soicind', + m: 'nóiméad', + mm: '%d nóiméad', + h: 'uair an chloig', + hh: '%d uair an chloig', + d: 'lá', + dd: '%d lá', + M: 'mí', + MM: '%d mí', + y: 'bliain', + yy: '%d bliain' + }, + dayOfMonthOrdinalParse: /\d{1,2}(d|na|mh)/, + ordinal: function (number) { + var output = number === 1 ? 'd' : number % 10 === 2 ? 'na' : 'mh'; + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4 // The week that contains Jan 4th is the first week of the year. + } + }); + + return ga; + +}))); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/gd.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/gd.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/gd.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/gd.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/gl.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/gl.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/gl.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/gl.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/gom-latn.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/gom-latn.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/gom-latn.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/gom-latn.js index f26f8f9c..bfad12e7 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/gom-latn.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/gom-latn.js @@ -14,8 +14,8 @@ 'ss': [number + ' secondanim', number + ' second'], 'm': ['eka mintan', 'ek minute'], 'mm': [number + ' mintanim', number + ' mintam'], - 'h': ['eka horan', 'ek hor'], - 'hh': [number + ' horanim', number + ' horam'], + 'h': ['eka voran', 'ek vor'], + 'hh': [number + ' voranim', number + ' voram'], 'd': ['eka disan', 'ek dis'], 'dd': [number + ' disanim', number + ' dis'], 'M': ['eka mhoinean', 'ek mhoino'], diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/gu.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/gu.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/gu.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/gu.js index c025aacd..9f80dbd7 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/gu.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/gu.js @@ -114,7 +114,7 @@ }, week: { dow: 0, // Sunday is the first day of the week. - doy: 6 // The week that contains Jan 1st is the first week of the year. + doy: 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/he.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/he.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/he.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/he.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/hi.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/hi.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/hi.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/hi.js index 5145c31e..a07860a0 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/hi.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/hi.js @@ -114,7 +114,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. + doy : 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/hr.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/hr.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/hr.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/hr.js index 07ce5279..bf1597b6 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/hr.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/hr.js @@ -144,7 +144,7 @@ ordinal : '%d.', week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/hu.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/hu.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/hu.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/hu.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/hy-am.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/hy-am.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/hy-am.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/hy-am.js index d709d3bd..1be1d85f 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/hy-am.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/hy-am.js @@ -85,7 +85,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/id.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/id.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/id.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/id.js index 63eb080d..c3e8b9e3 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/id.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/id.js @@ -72,7 +72,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/is.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/is.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/is.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/is.js diff --git a/rainloop/app/rainloop/v/1.13.0/app/localization/moment/it-ch.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/it-ch.js new file mode 100644 index 00000000..fcf2d4b0 --- /dev/null +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/it-ch.js @@ -0,0 +1,68 @@ +//! moment.js locale configuration + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + && typeof require === 'function' ? factory(require('../moment')) : + typeof define === 'function' && define.amd ? define(['../moment'], factory) : + factory(global.moment) +}(this, (function (moment) { 'use strict'; + + + var itCh = moment.defineLocale('it-ch', { + months : 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split('_'), + monthsShort : 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'), + weekdays : 'domenica_lunedì_martedì_mercoledì_giovedì_venerdì_sabato'.split('_'), + weekdaysShort : 'dom_lun_mar_mer_gio_ven_sab'.split('_'), + weekdaysMin : 'do_lu_ma_me_gi_ve_sa'.split('_'), + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD.MM.YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY HH:mm', + LLLL : 'dddd D MMMM YYYY HH:mm' + }, + calendar : { + sameDay: '[Oggi alle] LT', + nextDay: '[Domani alle] LT', + nextWeek: 'dddd [alle] LT', + lastDay: '[Ieri alle] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + return '[la scorsa] dddd [alle] LT'; + default: + return '[lo scorso] dddd [alle] LT'; + } + }, + sameElse: 'L' + }, + relativeTime : { + future : function (s) { + return ((/^[0-9].+$/).test(s) ? 'tra' : 'in') + ' ' + s; + }, + past : '%s fa', + s : 'alcuni secondi', + ss : '%d secondi', + m : 'un minuto', + mm : '%d minuti', + h : 'un\'ora', + hh : '%d ore', + d : 'un giorno', + dd : '%d giorni', + M : 'un mese', + MM : '%d mesi', + y : 'un anno', + yy : '%d anni' + }, + dayOfMonthOrdinalParse : /\d{1,2}º/, + ordinal: '%dº', + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } + }); + + return itCh; + +}))); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/it.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/it.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/it.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/it.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ja.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ja.js similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ja.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ja.js index 5ec1be53..4e4efd6a 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ja.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ja.js @@ -9,7 +9,7 @@ var ja = moment.defineLocale('ja', { - months : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), + months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'), monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), weekdays : '日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日'.split('_'), weekdaysShort : '日_月_火_水_木_金_土'.split('_'), diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/jv.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/jv.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/jv.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/jv.js index f4544a25..b2bb4f41 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/jv.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/jv.js @@ -72,7 +72,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ka.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ka.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ka.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ka.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/kk.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/kk.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/kk.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/kk.js index db9d7519..c468f670 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/kk.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/kk.js @@ -77,7 +77,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/km.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/km.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/km.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/km.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/kn.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/kn.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/kn.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/kn.js index 85b35cf7..8d0ae9d8 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/kn.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/kn.js @@ -116,7 +116,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. + doy : 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ko.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ko.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ko.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ko.js diff --git a/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ku.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ku.js new file mode 100644 index 00000000..05b9dbe2 --- /dev/null +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ku.js @@ -0,0 +1,118 @@ +//! moment.js locale configuration + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + && typeof require === 'function' ? factory(require('../moment')) : + typeof define === 'function' && define.amd ? define(['../moment'], factory) : + factory(global.moment) +}(this, (function (moment) { 'use strict'; + + + var symbolMap = { + '1': '١', + '2': '٢', + '3': '٣', + '4': '٤', + '5': '٥', + '6': '٦', + '7': '٧', + '8': '٨', + '9': '٩', + '0': '٠' + }, numberMap = { + '١': '1', + '٢': '2', + '٣': '3', + '٤': '4', + '٥': '5', + '٦': '6', + '٧': '7', + '٨': '8', + '٩': '9', + '٠': '0' + }, + months = [ + 'کانونی دووەم', + 'شوبات', + 'ئازار', + 'نیسان', + 'ئایار', + 'حوزەیران', + 'تەمموز', + 'ئاب', + 'ئەیلوول', + 'تشرینی یەكەم', + 'تشرینی دووەم', + 'كانونی یەکەم' + ]; + + + var ku = moment.defineLocale('ku', { + months : months, + monthsShort : months, + weekdays : 'یه‌كشه‌ممه‌_دووشه‌ممه‌_سێشه‌ممه‌_چوارشه‌ممه‌_پێنجشه‌ممه‌_هه‌ینی_شه‌ممه‌'.split('_'), + weekdaysShort : 'یه‌كشه‌م_دووشه‌م_سێشه‌م_چوارشه‌م_پێنجشه‌م_هه‌ینی_شه‌ممه‌'.split('_'), + weekdaysMin : 'ی_د_س_چ_پ_ه_ش'.split('_'), + weekdaysParseExact : true, + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD/MM/YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY HH:mm', + LLLL : 'dddd, D MMMM YYYY HH:mm' + }, + meridiemParse: /ئێواره‌|به‌یانی/, + isPM: function (input) { + return /ئێواره‌/.test(input); + }, + meridiem : function (hour, minute, isLower) { + if (hour < 12) { + return 'به‌یانی'; + } else { + return 'ئێواره‌'; + } + }, + calendar : { + sameDay : '[ئه‌مرۆ كاتژمێر] LT', + nextDay : '[به‌یانی كاتژمێر] LT', + nextWeek : 'dddd [كاتژمێر] LT', + lastDay : '[دوێنێ كاتژمێر] LT', + lastWeek : 'dddd [كاتژمێر] LT', + sameElse : 'L' + }, + relativeTime : { + future : 'له‌ %s', + past : '%s', + s : 'چه‌ند چركه‌یه‌ك', + ss : 'چركه‌ %d', + m : 'یه‌ك خوله‌ك', + mm : '%d خوله‌ك', + h : 'یه‌ك كاتژمێر', + hh : '%d كاتژمێر', + d : 'یه‌ك ڕۆژ', + dd : '%d ڕۆژ', + M : 'یه‌ك مانگ', + MM : '%d مانگ', + y : 'یه‌ك ساڵ', + yy : '%d ساڵ' + }, + preparse: function (string) { + return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) { + return numberMap[match]; + }).replace(/،/g, ','); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap[match]; + }).replace(/,/g, '،'); + }, + week : { + dow : 6, // Saturday is the first day of the week. + doy : 12 // The week that contains Jan 12th is the first week of the year. + } + }); + + return ku; + +}))); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ky.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ky.js similarity index 94% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ky.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ky.js index 7b0c9f39..8bd29a36 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ky.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ky.js @@ -49,8 +49,8 @@ sameDay : '[Бүгүн саат] LT', nextDay : '[Эртең саат] LT', nextWeek : 'dddd [саат] LT', - lastDay : '[Кече саат] LT', - lastWeek : '[Өткен аптанын] dddd [күнү] [саат] LT', + lastDay : '[Кечээ саат] LT', + lastWeek : '[Өткөн аптанын] dddd [күнү] [саат] LT', sameElse : 'L' }, relativeTime : { @@ -77,7 +77,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/lb.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/lb.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/lb.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/lb.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/lo.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/lo.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/lo.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/lo.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/lt.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/lt.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/lt.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/lt.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/lv.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/lv.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/lv.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/lv.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/me.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/me.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/me.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/me.js index ee7bd396..6608d095 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/me.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/me.js @@ -102,7 +102,7 @@ ordinal : '%d.', week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mi.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/mi.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/mi.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/mi.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mk.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/mk.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/mk.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/mk.js index e2d44989..051f683f 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mk.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/mk.js @@ -80,7 +80,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ml.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ml.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ml.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ml.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mn.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/mn.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/mn.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/mn.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mr.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/mr.js similarity index 99% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/mr.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/mr.js index fdeaa3d9..984559fd 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mr.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/mr.js @@ -150,7 +150,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. + doy : 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ms-my.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ms-my.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ms-my.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ms-my.js index 72188205..92014be2 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ms-my.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ms-my.js @@ -72,7 +72,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ms.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ms.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ms.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ms.js index 1fe21443..b499b5c5 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ms.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ms.js @@ -72,7 +72,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mt.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/mt.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/mt.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/mt.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/my.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/my.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/my.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/my.js index bc87c7f7..ca3102a4 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/my.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/my.js @@ -83,7 +83,7 @@ }, week: { dow: 1, // Monday is the first day of the week. - doy: 4 // The week that contains Jan 1st is the first week of the year. + doy: 4 // The week that contains Jan 4th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/nb.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/nb.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/nb.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/nb.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ne.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ne.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ne.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ne.js index 2ec063ee..21c03a85 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ne.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ne.js @@ -113,7 +113,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. + doy : 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/nl-be.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/nl-be.js similarity index 90% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/nl-be.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/nl-be.js index 0e5bdc96..479e2913 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/nl-be.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/nl-be.js @@ -12,7 +12,7 @@ monthsShortWithoutDots = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_'); var monthsParse = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i]; - var monthsRegex = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i; + var monthsRegex = /^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i; var nlBe = moment.defineLocale('nl-be', { months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'), @@ -28,7 +28,7 @@ monthsRegex: monthsRegex, monthsShortRegex: monthsRegex, - monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i, + monthsStrictRegex: /^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i, monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i, monthsParse : monthsParse, diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/nl.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/nl.js similarity index 90% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/nl.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/nl.js index 842f4fe1..11e78b9a 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/nl.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/nl.js @@ -12,7 +12,7 @@ monthsShortWithoutDots = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_'); var monthsParse = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i]; - var monthsRegex = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i; + var monthsRegex = /^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i; var nl = moment.defineLocale('nl', { months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'), @@ -28,7 +28,7 @@ monthsRegex: monthsRegex, monthsShortRegex: monthsRegex, - monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i, + monthsStrictRegex: /^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i, monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i, monthsParse : monthsParse, diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/nn.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/nn.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/nn.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/nn.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pa-in.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/pa-in.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/pa-in.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/pa-in.js index 63f4f44e..58ae1283 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pa-in.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/pa-in.js @@ -34,7 +34,7 @@ }; var paIn = moment.defineLocale('pa-in', { - // There are months name as per Nanakshahi Calender but they are not used as rigidly in modern Punjabi. + // There are months name as per Nanakshahi Calendar but they are not used as rigidly in modern Punjabi. months : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'), monthsShort : 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split('_'), weekdays : 'ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ'.split('_'), @@ -114,7 +114,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. + doy : 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pl.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/pl.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/pl.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/pl.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pt-br.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/pt-br.js similarity index 90% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/pt-br.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/pt-br.js index 64e0d01e..6cad5911 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pt-br.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/pt-br.js @@ -9,8 +9,8 @@ var ptBr = moment.defineLocale('pt-br', { - months : 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split('_'), - monthsShort : 'jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez'.split('_'), + months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'), + monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'), weekdays : 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split('_'), weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'), weekdaysMin : 'Do_2ª_3ª_4ª_5ª_6ª_Sá'.split('_'), diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pt.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/pt.js similarity index 91% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/pt.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/pt.js index b21ac45b..534f1c86 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pt.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/pt.js @@ -9,8 +9,8 @@ var pt = moment.defineLocale('pt', { - months : 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split('_'), - monthsShort : 'jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez'.split('_'), + months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'), + monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'), weekdays : 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split('_'), weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'), weekdaysMin : 'Do_2ª_3ª_4ª_5ª_6ª_Sá'.split('_'), diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ro.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ro.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ro.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ro.js index 47ec3d60..15bea092 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ro.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ro.js @@ -65,7 +65,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ru.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ru.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ru.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ru.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sd.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sd.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/sd.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/sd.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/se.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/se.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/se.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/se.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/si.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/si.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/si.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/si.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sk.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sk.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/sk.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/sk.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sl.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sl.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/sl.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/sl.js index 8dec7813..ecdd0cb4 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sl.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sl.js @@ -21,7 +21,7 @@ } else if (number < 5) { result += withoutSuffix || isFuture ? 'sekunde' : 'sekundah'; } else { - result += withoutSuffix || isFuture ? 'sekund' : 'sekund'; + result += 'sekund'; } return result; case 'm': @@ -163,7 +163,7 @@ ordinal : '%d.', week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sq.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sq.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/sq.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/sq.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sr-cyrl.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sr-cyrl.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/sr-cyrl.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/sr-cyrl.js index ccd92b95..e22a22fc 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sr-cyrl.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sr-cyrl.js @@ -101,7 +101,7 @@ ordinal : '%d.', week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sr.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sr.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/sr.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/sr.js index 9e1f4a3a..cb0b7ec9 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sr.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sr.js @@ -101,7 +101,7 @@ ordinal : '%d.', week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ss.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ss.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ss.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ss.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sv.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sv.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/sv.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/sv.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sw.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sw.js similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/sw.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/sw.js index 1f564e09..2c066b64 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sw.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/sw.js @@ -49,7 +49,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ta.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ta.js similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ta.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ta.js index 92142c92..f7a87d7b 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ta.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ta.js @@ -119,7 +119,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. + doy : 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/te.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/te.js similarity index 89% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/te.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/te.js index fe9ec2b3..abb40bf1 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/te.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/te.js @@ -9,8 +9,8 @@ var te = moment.defineLocale('te', { - months : 'జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జూలై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్'.split('_'), - monthsShort : 'జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జూలై_ఆగ._సెప్._అక్టో._నవ._డిసె.'.split('_'), + months : 'జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జులై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్'.split('_'), + monthsShort : 'జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జులై_ఆగ._సెప్._అక్టో._నవ._డిసె.'.split('_'), monthsParseExact : true, weekdays : 'ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం'.split('_'), weekdaysShort : 'ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని'.split('_'), @@ -79,7 +79,7 @@ }, week : { dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. + doy : 6 // The week that contains Jan 6th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tet.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/tet.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/tet.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/tet.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tg.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/tg.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/tg.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/tg.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/th.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/th.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/th.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/th.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tl-ph.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/tl-ph.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/tl-ph.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/tl-ph.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tlh.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/tlh.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/tlh.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/tlh.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tr.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/tr.js similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/tr.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/tr.js index 2e1dd730..e3fa275a 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tr.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/tr.js @@ -84,7 +84,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzl.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/tzl.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzl.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/tzl.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzm-latn.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/tzm-latn.js similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzm-latn.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/tzm-latn.js index 2f6a6f19..b7a2aed1 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzm-latn.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/tzm-latn.js @@ -48,7 +48,7 @@ }, week : { dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. + doy : 12 // The week that contains Jan 12th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzm.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/tzm.js similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzm.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/tzm.js index 1badf81b..48d71237 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzm.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/tzm.js @@ -48,7 +48,7 @@ }, week : { dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. + doy : 12 // The week that contains Jan 12th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ug-cn.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ug-cn.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ug-cn.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ug-cn.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/uk.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/uk.js similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/uk.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/uk.js index a8e7eddd..70761a18 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/uk.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/uk.js @@ -38,6 +38,9 @@ 'genitive': 'неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи'.split('_') }; + if (m === true) { + return weekdays['nominative'].slice(1, 7).concat(weekdays['nominative'].slice(0, 1)); + } if (!m) { return weekdays['nominative']; } @@ -141,7 +144,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ur.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/ur.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/ur.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/ur.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/uz-latn.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/uz-latn.js similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/uz-latn.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/uz-latn.js index cb32115b..41a348cb 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/uz-latn.js +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/uz-latn.js @@ -48,7 +48,7 @@ }, week : { dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. + doy : 7 // The week that contains Jan 7th is the first week of the year. } }); diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/uz.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/uz.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/uz.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/uz.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/vi.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/vi.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/vi.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/vi.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/x-pseudo.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/x-pseudo.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/x-pseudo.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/x-pseudo.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/yo.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/yo.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/yo.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/yo.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-cn.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/zh-cn.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-cn.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/zh-cn.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-hk.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/zh-hk.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-hk.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/zh-hk.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-tw.js b/rainloop/app/rainloop/v/1.13.0/app/localization/moment/zh-tw.js similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-tw.js rename to rainloop/app/rainloop/v/1.13.0/app/localization/moment/zh-tw.js diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/README b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/README similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/README rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/README diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/_source.en.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/_source.en.yml similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/_source.en.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/_source.en.yml index 6cb01cb9..f4f17c60 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/_source.en.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/_source.en.yml @@ -1,400 +1,400 @@ -en: - LOGIN: - LABEL_EMAIL: "Email" - LABEL_LOGIN: "Login" - LABEL_PASSWORD: "Password" - LABEL_SIGN_ME: "Remember Me" - LABEL_VERIFICATION_CODE: "Verification Code" - LABEL_DONT_ASK_VERIFICATION_CODE: "Don't ask for the code for 2 weeks" - BUTTON_SIGN_IN: "Sign In" - TITLE_SIGN_IN_GOOGLE: "Sign In using Google" - TITLE_SIGN_IN_FACEBOOK: "Sign In using Facebook" - TITLE_SIGN_IN_TWITTER: "Sign In using Twitter" - LABEL_FORGOT_PASSWORD: "Forgot password" - LABEL_REGISTRATION: "Registration" - TOP_TOOLBAR: - BUTTON_ADD_ACCOUNT: "Add Account" - BUTTON_SETTINGS: "Settings" - BUTTON_HELP: "Help" - BUTTON_LOGOUT: "Logout" - MOBILE: - BUTTON_MOBILE_VERSION: "Mobile version" - BUTTON_DESKTOP_VERSION: "Desktop version" - SEARCH: - MAIN_INPUT_PLACEHOLDER: "Search" - TITLE_ADV: "Advanced Search" - LABEL_ADV_FROM: "From" - LABEL_ADV_TO: "To" - LABEL_ADV_SUBJECT: "Subject" - LABEL_ADV_TEXT: "Text" - LABEL_ADV_HAS_ATTACHMENT: "Has attachment" - LABEL_ADV_HAS_ATTACHMENTS: "Has attachments" - LABEL_ADV_FLAGGED: "Flagged" - LABEL_ADV_UNSEEN: "Unseen" - LABEL_ADV_DATE: "Date" - LABEL_ADV_DATE_ALL: "All" - LABEL_ADV_DATE_3_DAYS: "Up to 3 days old" - LABEL_ADV_DATE_7_DAYS: "Up to 1 week old" - LABEL_ADV_DATE_MONTH: "Up to 1 month old" - LABEL_ADV_DATE_3_MONTHS: "Up to 3 months old" - LABEL_ADV_DATE_6_MONTHS: "Up to 6 months old" - LABEL_ADV_DATE_YEAR: "Up to 1 year old" - BUTTON_ADV_SEARCH: "Search" - PREVIEW_POPUP: - FULLSCREEN: "Toggle fullscreen" - ZOOM: "Zoom in/out" - CLOSE: "Close (Esc)" - LOADING: "Loading..." - GALLERY_PREV: "Previous (arrow left)" - GALLERY_NEXT: "Next (arrow right)" - GALLERY_COUNTER: "%curr% of %total%" - IMAGE_ERROR: "The image could not be loaded." - AJAX_ERROR: "The content could not be loaded." - FOLDER_LIST: - BUTTON_COMPOSE: "Compose" - BUTTON_CONTACTS: "Contacts" - BUTTON_NEW_MESSAGE: "New message" - INBOX_NAME: "Inbox" - SENT_NAME: "Sent" - DRAFTS_NAME: "Drafts" - SPAM_NAME: "Spam" - TRASH_NAME: "Trash" - ARCHIVE_NAME: "Archive" - QUOTA: - TITLE: "Quota usage" - MESSAGE_LIST: - BUTTON_RELOAD: "Reload Message List" - BUTTON_MOVE_TO: "Move To" - BUTTON_DELETE: "Delete" - BUTTON_ARCHIVE: "Archive" - BUTTON_SPAM: "Spam" - BUTTON_NOT_SPAM: "Not Spam" - BUTTON_EMPTY_FOLDER: "Clear Folder" - BUTTON_MULTY_FORWARD: "Forward as attachment(s)" - BUTTON_DELETE_WITHOUT_MOVE: "Delete permanently" - BUTTON_MORE: "More" - MENU_SET_SEEN: "Mark as read" - MENU_SET_ALL_SEEN: "Mark all as read" - MENU_UNSET_SEEN: "Mark as unread" - MENU_SET_FLAG: "Flag" - MENU_UNSET_FLAG: "Unflag" - MENU_SELECT_ALL: "All" - MENU_SELECT_NONE: "None" - MENU_SELECT_INVERT: "Invert" - MENU_SELECT_UNSEEN: "Unread" - MENU_SELECT_SEEN: "Read" - MENU_SELECT_FLAGGED: "Flagged" - MENU_SELECT_UNFLAGGED: "Unflagged" - EMPTY_LIST: "Empty list." - EMPTY_SEARCH_LIST: "No messages matched your search." - SEARCH_RESULT_FOR: "Search results for \"%SEARCH%\"" - BACK_TO_MESSAGE_LIST: "back to message list" - LIST_LOADING: "Loading" - EMPTY_SUBJECT_TEXT: "(No subject)" - PUT_MESSAGE_HERE: "Drop message here to view it in the list" - TODAY_AT: "today at %TIME%" - YESTERDAY_AT: "yesterday at %TIME%" - SEARCH_PLACEHOLDER: "Search" - NEW_MESSAGE_NOTIFICATION: "You have %COUNT% new messages!" - QUOTA_SIZE: "Using %SIZE% (%PROC%%) of your %LIMIT%" - MESSAGE: - BUTTON_EDIT: "Edit" - BUTTON_BACK: "Back" - BUTTON_CLOSE: "Close" - BUTTON_DELETE: "Delete" - BUTTON_UNSUBSCRIBE: "Unsubscribe from this list" - BUTTON_ARCHIVE: "Archive" - BUTTON_SPAM: "Spam" - BUTTON_NOT_SPAM: "Not Spam" - BUTTON_MOVE_TO: "Move To" - BUTTON_MORE: "More" - BUTTON_REPLY: "Reply" - BUTTON_REPLY_ALL: "Reply All" - BUTTON_FORWARD: "Forward" - BUTTON_FORWARD_AS_ATTACHMENT: "Forward as attachment" - BUTTON_EDIT_AS_NEW: "Edit as New" - BUTTON_SHOW_IMAGES: "Display external images" - BUTTON_NOTIFY_READ_RECEIPT: "The sender has asked to be notified when you read this message." - BUTTON_IN_NEW_WINDOW: "View in separate window" - BUTTON_THREAD_LIST: "Thread list" - BUTTON_THREAD_PREV: "Previous" - BUTTON_THREAD_NEXT: "Next" - BUTTON_THREAD_MORE: "More messages" - MENU_HEADERS: "Show message headers" - MENU_VIEW_ORIGINAL: "Show Source" - MENU_DOWNLOAD_ORIGINAL: "Download as .eml file" - MENU_FILTER_SIMILAR: "Filter messages like this" - MENU_PRINT: "Print" - EMPTY_SUBJECT_TEXT: "(No subject)" - LABEL_SUBJECT: "Subject" - LABEL_DATE: "Date" - LABEL_FROM: "From" - LABEL_FROM_SHORT: "from" - LABEL_TO: "To" - LABEL_TO_SHORT: "to" - LABEL_CC: "CC" - LABEL_BCC: "BCC" - LABEL_REPLY_TO: "Reply-To" - PRINT_LABEL_FROM: "From" - PRINT_LABEL_TO: "To" - PRINT_LABEL_CC: "CC" - PRINT_LABEL_BCC: "BCC" - PRINT_LABEL_REPLY_TO: "Reply-To" - PRINT_LABEL_DATE: "Date" - PRINT_LABEL_SUBJECT: "Subject" - PRINT_LABEL_ATTACHMENTS: "Attachments" - MESSAGE_LOADING: "Loading" - MESSAGE_VIEW_DESC: "Select any message in the list to view it here." - MESSAGE_VIEW_MOVE_DESC: "Click folder name in the left panel to select the destination." - PGP_PASSWORD_INPUT_PLACEHOLDER: "Password" - PGP_SIGNED_MESSAGE_DESC: "OpenPGP signed message (click to verify)" - PGP_ENCRYPTED_MESSAGE_DESC: "OpenPGP encrypted message (click to decrypt)" - LINK_DOWNLOAD_AS_ZIP: "Download as zip" - LINK_SAVE_TO_OWNCLOUD: "Save to ownCloud" - LINK_SAVE_TO_CLOUD: "Save to Cloud" - LINK_SAVE_TO_DROPBOX: "Save to Dropbox" - READ_RECEIPT: - SUBJECT: "Return Receipt (displayed) - %SUBJECT%" +en: + LOGIN: + LABEL_EMAIL: "Email" + LABEL_LOGIN: "Login" + LABEL_PASSWORD: "Password" + LABEL_SIGN_ME: "Remember Me" + LABEL_VERIFICATION_CODE: "Verification Code" + LABEL_DONT_ASK_VERIFICATION_CODE: "Don't ask for the code for 2 weeks" + BUTTON_SIGN_IN: "Sign In" + TITLE_SIGN_IN_GOOGLE: "Sign In using Google" + TITLE_SIGN_IN_FACEBOOK: "Sign In using Facebook" + TITLE_SIGN_IN_TWITTER: "Sign In using Twitter" + LABEL_FORGOT_PASSWORD: "Forgot password" + LABEL_REGISTRATION: "Registration" + TOP_TOOLBAR: + BUTTON_ADD_ACCOUNT: "Add Account" + BUTTON_SETTINGS: "Settings" + BUTTON_HELP: "Help" + BUTTON_LOGOUT: "Logout" + MOBILE: + BUTTON_MOBILE_VERSION: "Mobile version" + BUTTON_DESKTOP_VERSION: "Desktop version" + SEARCH: + MAIN_INPUT_PLACEHOLDER: "Search" + TITLE_ADV: "Advanced Search" + LABEL_ADV_FROM: "From" + LABEL_ADV_TO: "To" + LABEL_ADV_SUBJECT: "Subject" + LABEL_ADV_TEXT: "Text" + LABEL_ADV_HAS_ATTACHMENT: "Has attachment" + LABEL_ADV_HAS_ATTACHMENTS: "Has attachments" + LABEL_ADV_FLAGGED: "Flagged" + LABEL_ADV_UNSEEN: "Unseen" + LABEL_ADV_DATE: "Date" + LABEL_ADV_DATE_ALL: "All" + LABEL_ADV_DATE_3_DAYS: "Up to 3 days old" + LABEL_ADV_DATE_7_DAYS: "Up to 1 week old" + LABEL_ADV_DATE_MONTH: "Up to 1 month old" + LABEL_ADV_DATE_3_MONTHS: "Up to 3 months old" + LABEL_ADV_DATE_6_MONTHS: "Up to 6 months old" + LABEL_ADV_DATE_YEAR: "Up to 1 year old" + BUTTON_ADV_SEARCH: "Search" + PREVIEW_POPUP: + FULLSCREEN: "Toggle fullscreen" + ZOOM: "Zoom in/out" + CLOSE: "Close (Esc)" + LOADING: "Loading..." + GALLERY_PREV: "Previous (arrow left)" + GALLERY_NEXT: "Next (arrow right)" + GALLERY_COUNTER: "%curr% of %total%" + IMAGE_ERROR: "The image could not be loaded." + AJAX_ERROR: "The content could not be loaded." + FOLDER_LIST: + BUTTON_COMPOSE: "Compose" + BUTTON_CONTACTS: "Contacts" + BUTTON_NEW_MESSAGE: "New message" + INBOX_NAME: "Inbox" + SENT_NAME: "Sent" + DRAFTS_NAME: "Drafts" + SPAM_NAME: "Spam" + TRASH_NAME: "Trash" + ARCHIVE_NAME: "Archive" + QUOTA: + TITLE: "Quota usage" + MESSAGE_LIST: + BUTTON_RELOAD: "Reload Message List" + BUTTON_MOVE_TO: "Move To" + BUTTON_DELETE: "Delete" + BUTTON_ARCHIVE: "Archive" + BUTTON_SPAM: "Spam" + BUTTON_NOT_SPAM: "Not Spam" + BUTTON_EMPTY_FOLDER: "Clear Folder" + BUTTON_MULTY_FORWARD: "Forward as attachment(s)" + BUTTON_DELETE_WITHOUT_MOVE: "Delete permanently" + BUTTON_MORE: "More" + MENU_SET_SEEN: "Mark as read" + MENU_SET_ALL_SEEN: "Mark all as read" + MENU_UNSET_SEEN: "Mark as unread" + MENU_SET_FLAG: "Flag" + MENU_UNSET_FLAG: "Unflag" + MENU_SELECT_ALL: "All" + MENU_SELECT_NONE: "None" + MENU_SELECT_INVERT: "Invert" + MENU_SELECT_UNSEEN: "Unread" + MENU_SELECT_SEEN: "Read" + MENU_SELECT_FLAGGED: "Flagged" + MENU_SELECT_UNFLAGGED: "Unflagged" + EMPTY_LIST: "Empty list." + EMPTY_SEARCH_LIST: "No messages matched your search." + SEARCH_RESULT_FOR: "Search results for \"%SEARCH%\"" + BACK_TO_MESSAGE_LIST: "back to message list" + LIST_LOADING: "Loading" + EMPTY_SUBJECT_TEXT: "(No subject)" + PUT_MESSAGE_HERE: "Drop message here to view it in the list" + TODAY_AT: "today at %TIME%" + YESTERDAY_AT: "yesterday at %TIME%" + SEARCH_PLACEHOLDER: "Search" + NEW_MESSAGE_NOTIFICATION: "You have %COUNT% new messages!" + QUOTA_SIZE: "Using %SIZE% (%PROC%%) of your %LIMIT%" + MESSAGE: + BUTTON_EDIT: "Edit" + BUTTON_BACK: "Back" + BUTTON_CLOSE: "Close" + BUTTON_DELETE: "Delete" + BUTTON_UNSUBSCRIBE: "Unsubscribe from this list" + BUTTON_ARCHIVE: "Archive" + BUTTON_SPAM: "Spam" + BUTTON_NOT_SPAM: "Not Spam" + BUTTON_MOVE_TO: "Move To" + BUTTON_MORE: "More" + BUTTON_REPLY: "Reply" + BUTTON_REPLY_ALL: "Reply All" + BUTTON_FORWARD: "Forward" + BUTTON_FORWARD_AS_ATTACHMENT: "Forward as attachment" + BUTTON_EDIT_AS_NEW: "Edit as New" + BUTTON_SHOW_IMAGES: "Display external images" + BUTTON_NOTIFY_READ_RECEIPT: "The sender has asked to be notified when you read this message." + BUTTON_IN_NEW_WINDOW: "View in separate window" + BUTTON_THREAD_LIST: "Thread list" + BUTTON_THREAD_PREV: "Previous" + BUTTON_THREAD_NEXT: "Next" + BUTTON_THREAD_MORE: "More messages" + MENU_HEADERS: "Show message headers" + MENU_VIEW_ORIGINAL: "Show Source" + MENU_DOWNLOAD_ORIGINAL: "Download as .eml file" + MENU_FILTER_SIMILAR: "Filter messages like this" + MENU_PRINT: "Print" + EMPTY_SUBJECT_TEXT: "(No subject)" + LABEL_SUBJECT: "Subject" + LABEL_DATE: "Date" + LABEL_FROM: "From" + LABEL_FROM_SHORT: "from" + LABEL_TO: "To" + LABEL_TO_SHORT: "to" + LABEL_CC: "CC" + LABEL_BCC: "BCC" + LABEL_REPLY_TO: "Reply-To" + PRINT_LABEL_FROM: "From" + PRINT_LABEL_TO: "To" + PRINT_LABEL_CC: "CC" + PRINT_LABEL_BCC: "BCC" + PRINT_LABEL_REPLY_TO: "Reply-To" + PRINT_LABEL_DATE: "Date" + PRINT_LABEL_SUBJECT: "Subject" + PRINT_LABEL_ATTACHMENTS: "Attachments" + MESSAGE_LOADING: "Loading" + MESSAGE_VIEW_DESC: "Select any message in the list to view it here." + MESSAGE_VIEW_MOVE_DESC: "Click folder name in the left panel to select the destination." + PGP_PASSWORD_INPUT_PLACEHOLDER: "Password" + PGP_SIGNED_MESSAGE_DESC: "OpenPGP signed message (click to verify)" + PGP_ENCRYPTED_MESSAGE_DESC: "OpenPGP encrypted message (click to decrypt)" + LINK_DOWNLOAD_AS_ZIP: "Download as zip" + LINK_SAVE_TO_OWNCLOUD: "Save to ownCloud" + LINK_SAVE_TO_CLOUD: "Save to Cloud" + LINK_SAVE_TO_DROPBOX: "Save to Dropbox" + READ_RECEIPT: + SUBJECT: "Return Receipt (displayed) - %SUBJECT%" BODY: | This is a Return Receipt for the mail that you sent to %READ-RECEIPT%. Note: "This Return Receipt only acknowledges that the message was displayed on the recipient's computer." There is no guarantee that the recipient has read or understood the message contents. - SUGGESTIONS: - SEARCHING_DESC: "Searching..." - CONTACTS: - LEGEND_CONTACTS: "Contacts" - SEARCH_INPUT_PLACEHOLDER: "Search" - BUTTON_ADD_CONTACT: "Add Contact" - BUTTON_CREATE_CONTACT: "Create" - BUTTON_UPDATE_CONTACT: "Update" - BUTTON_IMPORT: "Import (csv, vcf, vCard)" - BUTTON_EXPORT_VCARD: "Export (vcf, vCard)" - BUTTON_EXPORT_CSV: "Export (csv)" - ERROR_IMPORT_FILE: "Import error (invalid file format)" - LIST_LOADING: "Loading" - EMPTY_LIST: "No contacts here" - EMPTY_SEARCH: "No contacts found" - CLEAR_SEARCH: "Clear search" - CONTACT_VIEW_DESC: "Select contact in the list to view it here." - LABEL_DISPLAY_NAME: "Display name" - LABEL_EMAIL: "Email" - LABEL_PHONE: "Phone" - LABEL_WEB: "Web" - LABEL_BIRTHDAY: "Birthday" - LINK_ADD_EMAIL: "Add an email address" - LINK_ADD_PHONE: "Add a phone" - LINK_BIRTHDAY: "Birthday" - PLACEHOLDER_ENTER_DISPLAY_NAME: "Enter display name" - PLACEHOLDER_ENTER_LAST_NAME: "Enter last name" - PLACEHOLDER_ENTER_FIRST_NAME: "Enter first name" - PLACEHOLDER_ENTER_NICK_NAME: "Enter nickname" - LABEL_READ_ONLY: "Read only" - LABEL_SHARE: "Share" - ADD_MENU_LABEL: "Add" - ADD_MENU_NICKNAME: "Nickname" - ADD_MENU_NOTES: "Notes" - ADD_MENU_EMAIL: "Email" - ADD_MENU_PHONE: "Phone" - ADD_MENU_URL: "URL" - ADD_MENU_ADDRESS: "Address" - ADD_MENU_BIRTHDAY: "Birthday" - ADD_MENU_TAGS: "Tags" - BUTTON_SHARE_NONE: "None" - BUTTON_SHARE_ALL: "Everyone" - BUTTON_SYNC: "Synchronization (CardDAV)" - COMPOSE: - TITLE_FROM: "From" - TITLE_TO: "To" - TITLE_CC: "CC" - TITLE_BCC: "BCC" - TITLE_REPLY_TO: "Reply-To" - TITLE_SUBJECT: "Subject" - LINK_SHOW_INPUTS: "show all fields" - BUTTON_SEND: "Send" - BUTTON_SAVE: "Save" - BUTTON_DELETE: "Delete" - BUTTON_CANCEL: "Cancel" - BUTTON_MINIMIZE: "Minimize" - SAVED_TIME: "Saved at %TIME%" - SAVED_ERROR_ON_SEND: "Message was sent but not saved to sent items folder" - DISCARD_UNSAVED_DATA: "Discard unsaved data?" - ATTACH_FILES: "Attach files" - ATTACH_DROP_FILES_DESC: "Drop files here" - ATTACH_ITEM_CANCEL: "Cancel" - DROPBOX: "Dropbox" - GOOGLE_DRIVE: "Google Drive" - REPLY_MESSAGE_TITLE: "%DATETIME%, %EMAIL% wrote" - FORWARD_MESSAGE_TOP_TITLE: "-------- Forwarded message -------" - FORWARD_MESSAGE_TOP_FROM: "From" - FORWARD_MESSAGE_TOP_TO: "To" - FORWARD_MESSAGE_TOP_CC: "CC" - FORWARD_MESSAGE_TOP_SENT: "Sent" - FORWARD_MESSAGE_TOP_SUBJECT: "Subject" - EMPTY_TO_ERROR_DESC: "Please specify at least one recipient" - NO_ATTACHMENTS_HERE_DESC: "No attachments here." - ATTACHMENTS_ERROR_DESC: "Warning! Not all attachments have been uploaded." - ATTACHMENTS_UPLOAD_ERROR_DESC: "Not all attachments have been uploaded yet." - BUTTON_REQUEST_READ_RECEIPT: "Request a read receipt" - BUTTON_MARK_AS_IMPORTANT: "Mark as important" - BUTTON_OPEN_PGP: "OpenPGP (Plain Text Only)" - BUTTON_REQUEST_DSN: "Request a delivery receipt" - POPUPS_WELCOME_PAGE: - BUTTON_CLOSE: "Close" - POPUPS_ASK: - BUTTON_YES: "Yes" - BUTTON_NO: "No" - DESC_WANT_CLOSE_THIS_WINDOW: "Are you sure you want to close this window?" - DESC_WANT_DELETE_MESSAGES: "Are you sure you want to delete the message(s)?" - POPUPS_LANGUAGES: - TITLE_LANGUAGES: "Choose your language" - POPUPS_ADD_ACCOUNT: - TITLE_ADD_ACCOUNT: "Add Account?" - BUTTON_ADD_ACCOUNT: "Add" - TITLE_UPDATE_ACCOUNT: "Update Account?" - BUTTON_UPDATE_ACCOUNT: "Update" - POPUPS_IDENTITY: - TITLE_ADD_IDENTITY: "Add Identity?" - TITLE_UPDATE_IDENTITY: "Update Identity?" - BUTTON_ADD_IDENTITY: "Add" - BUTTON_UPDATE_IDENTITY: "Update" - LABEL_EMAIL: "Email" - LABEL_NAME: "Name" - LABEL_REPLY_TO: "Reply-To" - LABEL_SIGNATURE: "Signature" - LABEL_CC: "Cc" - LABEL_BCC: "Bcc" - LABEL_SIGNATURE_INSERT_BEFORE: "Insert this signature before quoted text in replies" - POPUPS_CREATE_FOLDER: - TITLE_CREATE_FOLDER: "Create a folder?" - LABEL_NAME: "Folder name" - LABEL_PARENT: "Parent folder" - BUTTON_CREATE: "Create" - BUTTON_CANCEL: "Cancel" - BUTTON_CLOSE: "Close" - TITLE_CREATING_PROCESS: "Creating a folder" - POPUPS_CLEAR_FOLDER: - TITLE_CLEAR_FOLDER: "Purge all messages from the folder?" - BUTTON_CLEAR: "Clear" - BUTTON_CANCEL: "Cancel" - BUTTON_CLOSE: "Close" - DANGER_DESC_WARNING: "Warning!" - DANGER_DESC_HTML_1: "This action will result in removing all mails from %FOLDER% folder completely." - DANGER_DESC_HTML_2: "Once started, the process cannot be aborted or cancelled." - TITLE_CLEARING_PROCESS: "Purging the folder..." - POPUPS_IMPORT_OPEN_PGP_KEY: - TITLE_IMPORT_OPEN_PGP_KEY: "Import OpenPGP key" - BUTTON_IMPORT_OPEN_PGP_KEY: "Import" - POPUPS_VIEW_OPEN_PGP_KEY: - TITLE_VIEW_OPEN_PGP_KEY: "View OpenPGP key" - BUTTON_SELECT: "Select" - BUTTON_CLOSE: "Close" - POPUPS_GENERATE_OPEN_PGP_KEYS: - TITLE_GENERATE_OPEN_PGP_KEYS: "Generate OpenPGP keys" - LABEL_EMAIL: "Email" - LABEL_NAME: "Name" - LABEL_PASSWORD: "Password" - LABEL_KEY_BIT_LENGTH: "Key length" - BUTTON_GENERATE_OPEN_PGP_KEYS: "Generate" - POPUPS_COMPOSE_OPEN_PGP: - TITLE_COMPOSE_OPEN_PGP: "OpenPGP Sign/Encrypt" - LABEL_SIGN: "Sign" - LABEL_ENCRYPT: "Encrypt" - LABEL_PASSWORD: "Password" - BUTTON_SIGN: "Sign" - BUTTON_ENCRYPT: "Encrypt" - BUTTON_SIGN_AND_ENCRYPT: "Sign and encrypt" - POPUPS_MESSAGE_OPEN_PGP: - TITLE_MESSAGE_OPEN_PGP: "OpenPGP Decrypt" - LABEL_KEY: "Private Key" - LABEL_PASSWORD: "Password" - BUTTON_DECRYPT: "Decrypt" - POPUPS_TWO_FACTOR_TEST: - TITLE_TEST_CODE: "2-Step verification test" - LABEL_CODE: "Code" - BUTTON_TEST: "Test" - POPUPS_FILTER: - TITLE_CREATE_FILTER: "Create a filter?" - TITLE_EDIT_FILTER: "Update filter?" - FILTER_NAME: "Name" - LEGEND_CONDITIONS: "Conditions" - LEGEND_ACTIONS: "Actions" - BUTTON_DONE: "Done" - BUTTON_ADD_CONDITION: "Add a Condition" - SELECT_ACTION_NONE: "None" - SELECT_ACTION_MOVE_TO: "Move to" - SELECT_ACTION_FORWARD_TO: "Forward to" - SELECT_ACTION_REJECT: "Reject" - SELECT_ACTION_VACATION_MESSAGE: "Vacation message" - SELECT_ACTION_DISCARD: "Discard" - SELECT_FIELD_FROM: "From" - SELECT_FIELD_RECIPIENTS: "Recipients (To or CC)" - SELECT_FIELD_SUBJECT: "Subject" - SELECT_FIELD_HEADER: "Header" - SELECT_FIELD_SIZE: "Size" - SELECT_TYPE_CONTAINS: "Contains" - SELECT_TYPE_NOT_CONTAINS: "Not Contains" - SELECT_TYPE_MATCHES: "Matches (* and ? supported)" - SELECT_TYPE_NOT_MATCHES: "Not Matches (* and ? supported)" - SELECT_TYPE_REGEXP: "Regexp" - SELECT_TYPE_NOT_REGEXP: "Not Regexp" - SELECT_TYPE_EQUAL_TO: "Equal To" - SELECT_TYPE_NOT_EQUAL_TO: "Not Equal To" - SELECT_TYPE_OVER: "Over" - SELECT_TYPE_UNDER: "Under" - SELECT_MATCH_ANY: "Matching ANY of the following rules" - SELECT_MATCH_ALL: "Matching ALL of the following rules" - MARK_AS_READ_LABEL: "Mark as read" - REPLY_INTERVAL_LABEL: "Reply interval (days)" - KEEP_LABEL: "Keep" - STOP_LABEL: "Don't stop processing rules" - EMAIL_LABEL: "Email" - VACATION_SUBJECT_LABEL: "Subject (optional)" - VACATION_MESSAGE_LABEL: "Message" - VACATION_RECIPIENTS_LABEL: "Recipients (comma separated)" - REJECT_MESSAGE_LABEL: "Reject message" - ALL_INCOMING_MESSAGES_DESC: "All incoming messages" - POPUPS_SYSTEM_FOLDERS: - TITLE_SYSTEM_FOLDERS: "Select system folders" - SELECT_CHOOSE_ONE: "Choose one" - SELECT_UNUSE_NAME: "Do not use" - LABEL_SENT: "Sent" - LABEL_DRAFTS: "Drafts" - LABEL_SPAM: "Spam" - LABEL_TRASH: "Trash" - LABEL_ARCHIVE: "Archive" - BUTTON_CANCEL: "Cancel" - BUTTON_CLOSE: "Close" + SUGGESTIONS: + SEARCHING_DESC: "Searching..." + CONTACTS: + LEGEND_CONTACTS: "Contacts" + SEARCH_INPUT_PLACEHOLDER: "Search" + BUTTON_ADD_CONTACT: "Add Contact" + BUTTON_CREATE_CONTACT: "Create" + BUTTON_UPDATE_CONTACT: "Update" + BUTTON_IMPORT: "Import (csv, vcf, vCard)" + BUTTON_EXPORT_VCARD: "Export (vcf, vCard)" + BUTTON_EXPORT_CSV: "Export (csv)" + ERROR_IMPORT_FILE: "Import error (invalid file format)" + LIST_LOADING: "Loading" + EMPTY_LIST: "No contacts here" + EMPTY_SEARCH: "No contacts found" + CLEAR_SEARCH: "Clear search" + CONTACT_VIEW_DESC: "Select contact in the list to view it here." + LABEL_DISPLAY_NAME: "Display name" + LABEL_EMAIL: "Email" + LABEL_PHONE: "Phone" + LABEL_WEB: "Web" + LABEL_BIRTHDAY: "Birthday" + LINK_ADD_EMAIL: "Add an email address" + LINK_ADD_PHONE: "Add a phone" + LINK_BIRTHDAY: "Birthday" + PLACEHOLDER_ENTER_DISPLAY_NAME: "Enter display name" + PLACEHOLDER_ENTER_LAST_NAME: "Enter last name" + PLACEHOLDER_ENTER_FIRST_NAME: "Enter first name" + PLACEHOLDER_ENTER_NICK_NAME: "Enter nickname" + LABEL_READ_ONLY: "Read only" + LABEL_SHARE: "Share" + ADD_MENU_LABEL: "Add" + ADD_MENU_NICKNAME: "Nickname" + ADD_MENU_NOTES: "Notes" + ADD_MENU_EMAIL: "Email" + ADD_MENU_PHONE: "Phone" + ADD_MENU_URL: "URL" + ADD_MENU_ADDRESS: "Address" + ADD_MENU_BIRTHDAY: "Birthday" + ADD_MENU_TAGS: "Tags" + BUTTON_SHARE_NONE: "None" + BUTTON_SHARE_ALL: "Everyone" + BUTTON_SYNC: "Synchronization (CardDAV)" + COMPOSE: + TITLE_FROM: "From" + TITLE_TO: "To" + TITLE_CC: "CC" + TITLE_BCC: "BCC" + TITLE_REPLY_TO: "Reply-To" + TITLE_SUBJECT: "Subject" + LINK_SHOW_INPUTS: "show all fields" + BUTTON_SEND: "Send" + BUTTON_SAVE: "Save" + BUTTON_DELETE: "Delete" + BUTTON_CANCEL: "Cancel" + BUTTON_MINIMIZE: "Minimize" + SAVED_TIME: "Saved at %TIME%" + SAVED_ERROR_ON_SEND: "Message was sent but not saved to sent items folder" + DISCARD_UNSAVED_DATA: "Discard unsaved data?" + ATTACH_FILES: "Attach files" + ATTACH_DROP_FILES_DESC: "Drop files here" + ATTACH_ITEM_CANCEL: "Cancel" + DROPBOX: "Dropbox" + GOOGLE_DRIVE: "Google Drive" + REPLY_MESSAGE_TITLE: "%DATETIME%, %EMAIL% wrote" + FORWARD_MESSAGE_TOP_TITLE: "-------- Forwarded message -------" + FORWARD_MESSAGE_TOP_FROM: "From" + FORWARD_MESSAGE_TOP_TO: "To" + FORWARD_MESSAGE_TOP_CC: "CC" + FORWARD_MESSAGE_TOP_SENT: "Sent" + FORWARD_MESSAGE_TOP_SUBJECT: "Subject" + EMPTY_TO_ERROR_DESC: "Please specify at least one recipient" + NO_ATTACHMENTS_HERE_DESC: "No attachments here." + ATTACHMENTS_ERROR_DESC: "Warning! Not all attachments have been uploaded." + ATTACHMENTS_UPLOAD_ERROR_DESC: "Not all attachments have been uploaded yet." + BUTTON_REQUEST_READ_RECEIPT: "Request a read receipt" + BUTTON_MARK_AS_IMPORTANT: "Mark as important" + BUTTON_OPEN_PGP: "OpenPGP (Plain Text Only)" + BUTTON_REQUEST_DSN: "Request a delivery receipt" + POPUPS_WELCOME_PAGE: + BUTTON_CLOSE: "Close" + POPUPS_ASK: + BUTTON_YES: "Yes" + BUTTON_NO: "No" + DESC_WANT_CLOSE_THIS_WINDOW: "Are you sure you want to close this window?" + DESC_WANT_DELETE_MESSAGES: "Are you sure you want to delete the message(s)?" + POPUPS_LANGUAGES: + TITLE_LANGUAGES: "Choose your language" + POPUPS_ADD_ACCOUNT: + TITLE_ADD_ACCOUNT: "Add Account?" + BUTTON_ADD_ACCOUNT: "Add" + TITLE_UPDATE_ACCOUNT: "Update Account?" + BUTTON_UPDATE_ACCOUNT: "Update" + POPUPS_IDENTITY: + TITLE_ADD_IDENTITY: "Add Identity?" + TITLE_UPDATE_IDENTITY: "Update Identity?" + BUTTON_ADD_IDENTITY: "Add" + BUTTON_UPDATE_IDENTITY: "Update" + LABEL_EMAIL: "Email" + LABEL_NAME: "Name" + LABEL_REPLY_TO: "Reply-To" + LABEL_SIGNATURE: "Signature" + LABEL_CC: "Cc" + LABEL_BCC: "Bcc" + LABEL_SIGNATURE_INSERT_BEFORE: "Insert this signature before quoted text in replies" + POPUPS_CREATE_FOLDER: + TITLE_CREATE_FOLDER: "Create a folder?" + LABEL_NAME: "Folder name" + LABEL_PARENT: "Parent folder" + BUTTON_CREATE: "Create" + BUTTON_CANCEL: "Cancel" + BUTTON_CLOSE: "Close" + TITLE_CREATING_PROCESS: "Creating a folder" + POPUPS_CLEAR_FOLDER: + TITLE_CLEAR_FOLDER: "Purge all messages from the folder?" + BUTTON_CLEAR: "Clear" + BUTTON_CANCEL: "Cancel" + BUTTON_CLOSE: "Close" + DANGER_DESC_WARNING: "Warning!" + DANGER_DESC_HTML_1: "This action will result in removing all mails from %FOLDER% folder completely." + DANGER_DESC_HTML_2: "Once started, the process cannot be aborted or cancelled." + TITLE_CLEARING_PROCESS: "Purging the folder..." + POPUPS_IMPORT_OPEN_PGP_KEY: + TITLE_IMPORT_OPEN_PGP_KEY: "Import OpenPGP key" + BUTTON_IMPORT_OPEN_PGP_KEY: "Import" + POPUPS_VIEW_OPEN_PGP_KEY: + TITLE_VIEW_OPEN_PGP_KEY: "View OpenPGP key" + BUTTON_SELECT: "Select" + BUTTON_CLOSE: "Close" + POPUPS_GENERATE_OPEN_PGP_KEYS: + TITLE_GENERATE_OPEN_PGP_KEYS: "Generate OpenPGP keys" + LABEL_EMAIL: "Email" + LABEL_NAME: "Name" + LABEL_PASSWORD: "Password" + LABEL_KEY_BIT_LENGTH: "Key length" + BUTTON_GENERATE_OPEN_PGP_KEYS: "Generate" + POPUPS_COMPOSE_OPEN_PGP: + TITLE_COMPOSE_OPEN_PGP: "OpenPGP Sign/Encrypt" + LABEL_SIGN: "Sign" + LABEL_ENCRYPT: "Encrypt" + LABEL_PASSWORD: "Password" + BUTTON_SIGN: "Sign" + BUTTON_ENCRYPT: "Encrypt" + BUTTON_SIGN_AND_ENCRYPT: "Sign and encrypt" + POPUPS_MESSAGE_OPEN_PGP: + TITLE_MESSAGE_OPEN_PGP: "OpenPGP Decrypt" + LABEL_KEY: "Private Key" + LABEL_PASSWORD: "Password" + BUTTON_DECRYPT: "Decrypt" + POPUPS_TWO_FACTOR_TEST: + TITLE_TEST_CODE: "2-Step verification test" + LABEL_CODE: "Code" + BUTTON_TEST: "Test" + POPUPS_FILTER: + TITLE_CREATE_FILTER: "Create a filter?" + TITLE_EDIT_FILTER: "Update filter?" + FILTER_NAME: "Name" + LEGEND_CONDITIONS: "Conditions" + LEGEND_ACTIONS: "Actions" + BUTTON_DONE: "Done" + BUTTON_ADD_CONDITION: "Add a Condition" + SELECT_ACTION_NONE: "None" + SELECT_ACTION_MOVE_TO: "Move to" + SELECT_ACTION_FORWARD_TO: "Forward to" + SELECT_ACTION_REJECT: "Reject" + SELECT_ACTION_VACATION_MESSAGE: "Vacation message" + SELECT_ACTION_DISCARD: "Discard" + SELECT_FIELD_FROM: "From" + SELECT_FIELD_RECIPIENTS: "Recipients (To or CC)" + SELECT_FIELD_SUBJECT: "Subject" + SELECT_FIELD_HEADER: "Header" + SELECT_FIELD_SIZE: "Size" + SELECT_TYPE_CONTAINS: "Contains" + SELECT_TYPE_NOT_CONTAINS: "Not Contains" + SELECT_TYPE_MATCHES: "Matches (* and ? supported)" + SELECT_TYPE_NOT_MATCHES: "Not Matches (* and ? supported)" + SELECT_TYPE_REGEXP: "Regexp" + SELECT_TYPE_NOT_REGEXP: "Not Regexp" + SELECT_TYPE_EQUAL_TO: "Equal To" + SELECT_TYPE_NOT_EQUAL_TO: "Not Equal To" + SELECT_TYPE_OVER: "Over" + SELECT_TYPE_UNDER: "Under" + SELECT_MATCH_ANY: "Matching ANY of the following rules" + SELECT_MATCH_ALL: "Matching ALL of the following rules" + MARK_AS_READ_LABEL: "Mark as read" + REPLY_INTERVAL_LABEL: "Reply interval (days)" + KEEP_LABEL: "Keep" + STOP_LABEL: "Don't stop processing rules" + EMAIL_LABEL: "Email" + VACATION_SUBJECT_LABEL: "Subject (optional)" + VACATION_MESSAGE_LABEL: "Message" + VACATION_RECIPIENTS_LABEL: "Recipients (comma separated)" + REJECT_MESSAGE_LABEL: "Reject message" + ALL_INCOMING_MESSAGES_DESC: "All incoming messages" + POPUPS_SYSTEM_FOLDERS: + TITLE_SYSTEM_FOLDERS: "Select system folders" + SELECT_CHOOSE_ONE: "Choose one" + SELECT_UNUSE_NAME: "Do not use" + LABEL_SENT: "Sent" + LABEL_DRAFTS: "Drafts" + LABEL_SPAM: "Spam" + LABEL_TRASH: "Trash" + LABEL_ARCHIVE: "Archive" + BUTTON_CANCEL: "Cancel" + BUTTON_CLOSE: "Close" NOTIFICATION_SENT: | You haven't selected "Sent" system folder messages are put to after sending. If you don't want to save sent message, please select "Do not use" option. - NOTIFICATION_DRAFTS: "You haven't selected \"Drafts\" system folder messages are saved to while composing." + NOTIFICATION_DRAFTS: "You haven't selected \"Drafts\" system folder messages are saved to while composing." NOTIFICATION_SPAM: | You haven't selected "Spam" system folder spamed messages are placed to. If you wish to remove messages permanently, please select "Do not use" option. NOTIFICATION_TRASH: | You haven't selected "Trash" system folder deleted messages are placed to. If you wish to remove messages permanently, please select "Do not use" option. - NOTIFICATION_ARCHIVE: "You haven't selected \"Archive\" system folder achived messages are placed to." - POPUPS_TWO_FACTOR_CFG: - LEGEND_TWO_FACTOR_AUTH: "2-Step Verification (TOTP)" - LABEL_ENABLE_TWO_FACTOR: "Enable 2-Step verification" - LABEL_TWO_FACTOR_USER: "User" - LABEL_TWO_FACTOR_STATUS: "Status" - LABEL_TWO_FACTOR_SECRET: "Secret" - LABEL_TWO_FACTOR_BACKUP_CODES: "Backup codes" - BUTTON_CREATE: "Create a secret" - BUTTON_ACTIVATE: "Activate" - BUTTON_CLEAR: "Clear" - BUTTON_LOGOUT: "Logout" - BUTTON_DONE: "Done" - BUTTON_TEST: "Test" - LINK_TEST: "test" - BUTTON_SHOW_SECRET: "Show Secret" - BUTTON_HIDE_SECRET: "Hide Secret" - TWO_FACTOR_REQUIRE_DESC: "Your account requires 2-Step verification configuration." - TWO_FACTOR_SECRET_CONFIGURED_DESC: "Configured" - TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Not configured" + NOTIFICATION_ARCHIVE: "You haven't selected \"Archive\" system folder achived messages are placed to." + POPUPS_TWO_FACTOR_CFG: + LEGEND_TWO_FACTOR_AUTH: "2-Step Verification (TOTP)" + LABEL_ENABLE_TWO_FACTOR: "Enable 2-Step verification" + LABEL_TWO_FACTOR_USER: "User" + LABEL_TWO_FACTOR_STATUS: "Status" + LABEL_TWO_FACTOR_SECRET: "Secret" + LABEL_TWO_FACTOR_BACKUP_CODES: "Backup codes" + BUTTON_CREATE: "Create a secret" + BUTTON_ACTIVATE: "Activate" + BUTTON_CLEAR: "Clear" + BUTTON_LOGOUT: "Logout" + BUTTON_DONE: "Done" + BUTTON_TEST: "Test" + LINK_TEST: "test" + BUTTON_SHOW_SECRET: "Show Secret" + BUTTON_HIDE_SECRET: "Hide Secret" + TWO_FACTOR_REQUIRE_DESC: "Your account requires 2-Step verification configuration." + TWO_FACTOR_SECRET_CONFIGURED_DESC: "Configured" + TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Not configured" TWO_FACTOR_SECRET_DESC: > Import this info into your Google Authenticator client (or other TOTP client) using the provided QR code below or by entering the code manually. @@ -402,246 +402,246 @@ en: If you can't receive codes via Google Authenticator (or other TOTP client), you can use backup codes to sign in. After you’ve used a backup code to sign in, it will become inactive. - TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "You can't change this setting before test." - TITLES: - LOADING: "Loading" - LOGIN: "Login" - MAILBOX: "MailBox" - SETTINGS: "Settings" - COMPOSE: "Compose" - UPLOAD: - ERROR_FILE_IS_TOO_BIG: "File is too big" - ERROR_FILE_PARTIALLY_UPLOADED: "File was partially uploaded due to unknown error" - ERROR_NO_FILE_UPLOADED: "No file uploaded" - ERROR_MISSING_TEMP_FOLDER: "The temporary file is missing" - ERROR_ON_SAVING_FILE: "An unknown file upload error occurred" - ERROR_FILE_TYPE: "Invalid file type" - ERROR_UNKNOWN: "An unknown file upload error occurred" - EDITOR: - TEXT_SWITCHER_PLAINT_TEXT: "HTML <-> TEXT" - TEXT_SWITCHER_RICH_FORMATTING: "Rich formatting" - TEXT_SWITCHER_CONFIRM: "Text formatting and images will be lost. Are you sure you want to continue?" - SETTINGS_LABELS: - LABEL_PERSONAL_NAME: "Personal" - LABEL_GENERAL_NAME: "General" - LABEL_CONTACTS_NAME: "Contacts" - LABEL_FOLDERS_NAME: "Folders" - LABEL_ACCOUNTS_NAME: "Accounts" - LABEL_IDENTITY_NAME: "Identity" - LABEL_IDENTITIES_NAME: "Identities" - LABEL_FILTERS_NAME: "Filters" - LABEL_TEMPLATES_NAME: "Templates" - LABEL_SECURITY_NAME: "Security" - LABEL_SOCIAL_NAME: "Social" - LABEL_THEMES_NAME: "Themes" - LABEL_CHANGE_PASSWORD_NAME: "Password" - LABEL_OPEN_PGP_NAME: "OpenPGP" - BUTTON_BACK: "Back" - SETTINGS_FILTERS: - LEGEND_FILTERS: "Filters" - BUTTON_SAVE: "Save" - BUTTON_ADD_FILTER: "Add a Filter" - BUTTON_DELETE: "Delete" - BUTTON_RAW_SCRIPT: "Use Custom User Script" - SUBNAME_NONE: "None" - SUBNAME_MOVE_TO: "Move to \"%FOLDER%\"" - SUBNAME_FORWARD_TO: "Forward to \"%EMAIL%\"" - SUBNAME_REJECT: "Reject" - SUBNAME_VACATION_MESSAGE: "Vacation message" - SUBNAME_DISCARD: "Discard" - CAPABILITY_LABEL: "Capability" - LOADING_PROCESS: "Updating filter list" - DELETING_ASK: "Are you sure?" - CHACHES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server." - SETTINGS_IDENTITY: - LEGEND_IDENTITY: "Identity" - LABEL_DISPLAY_NAME: "Name" - LABEL_REPLY_TO: "Reply-To" - LABEL_SIGNATURE: "Signature" - LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages" - SETTINGS_SECURITY: - LEGEND_SECURITY: "Security" - LABEL_CONFIGURE_TWO_FACTOR: "Configure 2-Step verification" - LABEL_AUTOLOGOUT: "Auto Logout" - AUTOLOGIN_NEVER_OPTION_NAME: "Never" - AUTOLOGIN_MINUTES_OPTION_NAME: "%MINUTES% minute(s)" - AUTOLOGIN_HOURS_OPTION_NAME: "%HOURS% hour(s)" - SETTINGS_GENERAL: - LEGEND_GENERAL: "General" - LABEL_LANGUAGE: "Language" - LABEL_IDENTITY: "Identity" - LABEL_LAYOUT: "Layout" - LABEL_LAYOUT_NO_SPLIT: "No Split" - LABEL_LAYOUT_VERTICAL_SPLIT: "Vertical Split" - LABEL_LAYOUT_HORIZONTAL_SPLIT: "Horizontal Split" - LABEL_EDITOR: "Default text editor" - LABEL_EDITOR_HTML: "Html" - LABEL_EDITOR_PLAIN: "Plain" - LABEL_EDITOR_HTML_FORCED: "Html (forced)" - LABEL_EDITOR_PLAIN_FORCED: "Plain (forced)" - LABEL_ANIMATION: "Interface animation" - LABEL_ANIMATION_FULL: "Full" - LABEL_ANIMATION_NORMAL: "Normal" - LABEL_ANIMATION_NONE: "None" - LABEL_VIEW_OPTIONS: "View options" - LABEL_USE_PREVIEW_PANE: "Use preview pane" - LABEL_USE_CHECKBOXES_IN_LIST: "Display checkboxes in list" - LABEL_USE_THREADS: "Use threads" - LABEL_REPLY_SAME_FOLDER: "Place replies in the folder of the message being replied to" - LABEL_SHOW_IMAGES: "Always display external images in message body" - LABEL_SHOW_ANIMATION: "Show animation" - LABEL_MESSAGE_PER_PAGE: "Messages on page" - LABEL_NOTIFICATIONS: "Notifications" - LABEL_SOUND_NOTIFICATION: "Sound notification" - LABEL_CHROME_NOTIFICATION_DESC: "Show new messages notification popups" - LABEL_CHROME_NOTIFICATION_DESC_DENIED: "(Blocked by the browser)" - SETTINGS_CONTACTS: - LEGEND_CONTACTS: "Contacts" - LABEL_CONTACTS_AUTOSAVE: "Automatically add recipients to your address book" - LEGEND_CONTACTS_SYNC: "Remote Synchronization (CardDAV)" - LABEL_CONTACTS_SYNC_ENABLE: "Enable remote synchronization" - LABEL_CONTACTS_SYNC_SERVER: "Server" - LABEL_CONTACTS_SYNC_AB_URL: "Addressbook URL" - LABEL_CONTACTS_SYNC_USER: "User" - LABEL_CONTACTS_SYNC_PASSWORD: "Password" - SETTINGS_THEMES: - LEGEND_THEMES: "Themes" - LEGEND_THEMES_CUSTOM: "Custom Theme Configuration" - LABEL_CUSTOM_TYPE: "Type" - LABEL_CUSTOM_TYPE_LIGHT: "Light" - LABEL_CUSTOM_TYPE_DARK: "Dark" - LABEL_CUSTOM_BACKGROUND_IMAGE: "Background" - BUTTON_UPLOAD_BACKGROUND_IMAGE: "Upload background image (JPG, PNG)" - ERROR_FILE_IS_TOO_BIG: "File is too big" - ERROR_FILE_TYPE_ERROR: "Invalid file type (JPG and PNG only)" - ERROR_UNKNOWN: "An unknown file upload error occurred" - SETTINGS_SOCIAL: - LEGEND_GOOGLE: "Google" - BUTTON_GOOGLE_CONNECT: "Connect Google" - BUTTON_GOOGLE_DISCONNECT: "Disconnect Google" - MAIN_GOOGLE_DESC: "After enabling login via Google, you can log into this account using Google button on the login screen." - LEGEND_FACEBOOK: "Facebook" - BUTTON_FACEBOOK_CONNECT: "Connect Facebook" - BUTTON_FACEBOOK_DISCONNECT: "Disconnect Facebook" - MAIN_FACEBOOK_DESC: "After enabling login via Facebook, you can log into this account using Facebook button on the login screen." - LEGEND_TWITTER: "Twitter" - BUTTON_TWITTER_CONNECT: "Connect Twitter" - BUTTON_TWITTER_DISCONNECT: "Disconnect Twitter" - MAIN_TWITTER_DESC: "After enabling login via Twitter, you can log into this account using Twitter button on the login screen." - SETTINGS_FOLDERS: - LEGEND_FOLDERS: "Folder List" - BUTTON_CREATE: "Create Folder" - BUTTON_SYSTEM: "System Folders" - BUTTON_DELETE: "Delete" - BUTTON_SUBSCRIBE: "Subscribe" - BUTTON_UNSUBSCRIBE: "Unsubscribe" - LOADING_PROCESS: "Updating folder list" - CREATING_PROCESS: "Creating a folder" - DELETING_PROCESS: "Deleting a folder" - RENAMING_PROCESS: "Renaming a folder" - DELETING_ASK: "Are you sure?" - TO_MANY_FOLDERS_DESC_1: "You have too many folders!" - TO_MANY_FOLDERS_DESC_2: "We have shown only a part of them, to avoid performance problems." - HELP_DELETE_FOLDER: "Delete folder" - HELP_SHOW_HIDE_FOLDER: "Show/hide folder" - HELP_CHECK_FOR_NEW_MESSAGES: "Check/don't check for new messages" - SETTINGS_ACCOUNTS: - LEGEND_ACCOUNTS: "Accounts" - LEGEND_IDENTITIES: "Identities" - LEGEND_ACCOUNTS_AND_IDENTITIES: "Accounts and Identities" - BUTTON_ADD_ACCOUNT: "Add an Account" - BUTTON_ADD_IDENTITY: "Add an Identity" - BUTTON_DELETE: "Delete" - LOADING_PROCESS: "Updating..." - DELETING_ASK: "Are you sure?" - DEFAULT_IDENTITY_LABEL: "default" - SETTINGS_IDENTITIES: - LEGEND_IDENTITY: "Identity" - LEGEND_IDENTITIES: "Additional Identities" - LABEL_DEFAULT: "Default" - LABEL_DISPLAY_NAME: "Name" - LABEL_REPLY_TO: "Reply-To" - LABEL_SIGNATURE: "Signature" - LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages" - BUTTON_ADD_IDENTITY: "Add Identity" - BUTTON_DELETE: "Delete" - LOADING_PROCESS: "Updating identity list" - DELETING_ASK: "Are you sure?" - SETTINGS_CHANGE_PASSWORD: - LEGEND_CHANGE_PASSWORD: "Change Password" - LABEL_CURRENT_PASSWORD: "Current password" - LABEL_NEW_PASSWORD: "New password" - LABEL_REPEAT_PASSWORD: "Confirm New Password" - BUTTON_UPDATE_PASSWORD: "Set New Password" - ERROR_PASSWORD_MISMATCH: "Passwords do not match, please try again" - SETTINGS_OPEN_PGP: - LEGEND_OPEN_PGP: "OpenPGP" - BUTTON_ADD_OPEN_PGP_KEY: "Import OpenPGP Key" - BUTTON_GENERATE_OPEN_PGP_KEYS: "Generate OpenPGP Keys" - TITLE_PRIVATE: "Private" - TITLE_PUBLIC: "Public" - DELETING_ASK: "Are you sure?" - GENERATE_ONLY_HTTPS: "HTTPS only" - LABEL_ALLOW_DRAFT_AUTOSAVE: "Automatically save draft" - SHORTCUTS_HELP: - LEGEND_SHORTCUTS_HELP: "Keyboard shortcuts help" - TAB_MAILBOX: "Mailbox" - TAB_MESSAGE_LIST: "Message list" - TAB_MESSAGE_VIEW: "Message view" - TAB_COMPOSE: "Compose" - LABEL_OPEN_USER_DROPDOWN: "Open user dropdown" - LABEL_REPLY: "Reply" - LABEL_REPLY_ALL: "Reply All" - LABEL_FORWARD: "Forward" - LABEL_FORWARD_MULTIPLY: "Forward as attachment(s)" - LABEL_HELP: "Help" - LABEL_CHECK_ALL: "Select all messages" - LABEL_ARCHIVE: "Archive" - LABEL_DELETE: "Delete" - LABEL_OPEN_THREAD: "Open selected thread" - LABEL_MOVE: "Move" - LABEL_READ: "Read selected messages" - LABEL_UNREAD: "Unread selected messages" - LABEL_IMPORTANT: "Important, flag selected messages" - LABEL_SEARCH: "Search" - LABEL_CANCEL_SEARCH: "Cancel search" - LABEL_FULLSCREEN_ENTER: "Fullscreen (Preview pane layout)" - LABEL_VIEW_MESSAGE_ENTER: "View message (No preview pane layout)" - LABEL_SWITCH_TO_MESSAGE: "Switch focus to selected message" - LABEL_SWITCH_TO_FOLDER_LIST: "Switch focus to folder list" - LABEL_FULLSCREEN_TOGGLE: "Toggle fullscreen mode" - LABEL_BLOCKQUOTES_TOGGLE: "Toggle message blockquotes" - LABEL_THREAD_NEXT: "Next message in thread" - LABEL_THREAD_PREV: "Previous message in thread" - LABEL_PRINT: "Print" - LABEL_EXIT_FULLSCREEN: "Exit fullscreen mode" - LABEL_CLOSE_MESSAGE: "Close message (No preview pane layout)" - LABEL_SWITCH_TO_LIST: "Switch focus back to message list" - LABEL_OPEN_COMPOSE_POPUP: "Open compose popup" - LABEL_MINIMIZE_COMPOSE_POPUP: "Minimize compose popup" - LABEL_OPEN_IDENTITIES_DROPDOWN: "Open identities dropdown" - LABEL_SAVE_MESSAGE: "Save message" - LABEL_SEND_MESSAGE: "Send message" - LABEL_CLOSE_COMPOSE: "Close compose" - PGP_NOTIFICATIONS: - NO_PUBLIC_KEYS_FOUND: "No public keys found" - NO_PUBLIC_KEYS_FOUND_FOR: "No public keys found for \"%EMAIL%\" email" - NO_PRIVATE_KEY_FOUND: "No private key found" - NO_PRIVATE_KEY_FOUND_FOR: "No private key found for \"%EMAIL%\" email" - ADD_A_PUBLICK_KEY: "Add a public key" - SELECT_A_PRIVATE_KEY: "Select a private key" - UNVERIFIRED_SIGNATURE: "Unverified signature" - DECRYPTION_ERROR: "OpenPGP decryption error" - GOOD_SIGNATURE: "Good signature from %USER%" - PGP_ERROR: "OpenPGP error: %ERROR%" - SPECIFY_FROM_EMAIL: "Please specify FROM email address" - SPECIFY_AT_LEAST_ONE_RECIPIENT: "Please specify at least one recipient" - NOTIFICATIONS: - INVALID_TOKEN: "Invalid token" - AUTH_ERROR: "Authentication failed" - ACCESS_ERROR: "Access error" - CONNECTION_ERROR: "Can't connect to server" - CAPTCHA_ERROR: "Incorrect CAPTCHA." + TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "You can't change this setting before test." + TITLES: + LOADING: "Loading" + LOGIN: "Login" + MAILBOX: "MailBox" + SETTINGS: "Settings" + COMPOSE: "Compose" + UPLOAD: + ERROR_FILE_IS_TOO_BIG: "File is too big" + ERROR_FILE_PARTIALLY_UPLOADED: "File was partially uploaded due to unknown error" + ERROR_NO_FILE_UPLOADED: "No file uploaded" + ERROR_MISSING_TEMP_FOLDER: "The temporary file is missing" + ERROR_ON_SAVING_FILE: "An unknown file upload error occurred" + ERROR_FILE_TYPE: "Invalid file type" + ERROR_UNKNOWN: "An unknown file upload error occurred" + EDITOR: + TEXT_SWITCHER_PLAINT_TEXT: "HTML <-> TEXT" + TEXT_SWITCHER_RICH_FORMATTING: "Rich formatting" + TEXT_SWITCHER_CONFIRM: "Text formatting and images will be lost. Are you sure you want to continue?" + SETTINGS_LABELS: + LABEL_PERSONAL_NAME: "Personal" + LABEL_GENERAL_NAME: "General" + LABEL_CONTACTS_NAME: "Contacts" + LABEL_FOLDERS_NAME: "Folders" + LABEL_ACCOUNTS_NAME: "Accounts" + LABEL_IDENTITY_NAME: "Identity" + LABEL_IDENTITIES_NAME: "Identities" + LABEL_FILTERS_NAME: "Filters" + LABEL_TEMPLATES_NAME: "Templates" + LABEL_SECURITY_NAME: "Security" + LABEL_SOCIAL_NAME: "Social" + LABEL_THEMES_NAME: "Themes" + LABEL_CHANGE_PASSWORD_NAME: "Password" + LABEL_OPEN_PGP_NAME: "OpenPGP" + BUTTON_BACK: "Back" + SETTINGS_FILTERS: + LEGEND_FILTERS: "Filters" + BUTTON_SAVE: "Save" + BUTTON_ADD_FILTER: "Add a Filter" + BUTTON_DELETE: "Delete" + BUTTON_RAW_SCRIPT: "Use Custom User Script" + SUBNAME_NONE: "None" + SUBNAME_MOVE_TO: "Move to \"%FOLDER%\"" + SUBNAME_FORWARD_TO: "Forward to \"%EMAIL%\"" + SUBNAME_REJECT: "Reject" + SUBNAME_VACATION_MESSAGE: "Vacation message" + SUBNAME_DISCARD: "Discard" + CAPABILITY_LABEL: "Capability" + LOADING_PROCESS: "Updating filter list" + DELETING_ASK: "Are you sure?" + CHACHES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server." + SETTINGS_IDENTITY: + LEGEND_IDENTITY: "Identity" + LABEL_DISPLAY_NAME: "Name" + LABEL_REPLY_TO: "Reply-To" + LABEL_SIGNATURE: "Signature" + LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages" + SETTINGS_SECURITY: + LEGEND_SECURITY: "Security" + LABEL_CONFIGURE_TWO_FACTOR: "Configure 2-Step verification" + LABEL_AUTOLOGOUT: "Auto Logout" + AUTOLOGIN_NEVER_OPTION_NAME: "Never" + AUTOLOGIN_MINUTES_OPTION_NAME: "%MINUTES% minute(s)" + AUTOLOGIN_HOURS_OPTION_NAME: "%HOURS% hour(s)" + SETTINGS_GENERAL: + LEGEND_GENERAL: "General" + LABEL_LANGUAGE: "Language" + LABEL_IDENTITY: "Identity" + LABEL_LAYOUT: "Layout" + LABEL_LAYOUT_NO_SPLIT: "No Split" + LABEL_LAYOUT_VERTICAL_SPLIT: "Vertical Split" + LABEL_LAYOUT_HORIZONTAL_SPLIT: "Horizontal Split" + LABEL_EDITOR: "Default text editor" + LABEL_EDITOR_HTML: "Html" + LABEL_EDITOR_PLAIN: "Plain" + LABEL_EDITOR_HTML_FORCED: "Html (forced)" + LABEL_EDITOR_PLAIN_FORCED: "Plain (forced)" + LABEL_ANIMATION: "Interface animation" + LABEL_ANIMATION_FULL: "Full" + LABEL_ANIMATION_NORMAL: "Normal" + LABEL_ANIMATION_NONE: "None" + LABEL_VIEW_OPTIONS: "View options" + LABEL_USE_PREVIEW_PANE: "Use preview pane" + LABEL_USE_CHECKBOXES_IN_LIST: "Display checkboxes in list" + LABEL_USE_THREADS: "Use threads" + LABEL_REPLY_SAME_FOLDER: "Place replies in the folder of the message being replied to" + LABEL_SHOW_IMAGES: "Always display external images in message body" + LABEL_SHOW_ANIMATION: "Show animation" + LABEL_MESSAGE_PER_PAGE: "Messages on page" + LABEL_NOTIFICATIONS: "Notifications" + LABEL_SOUND_NOTIFICATION: "Sound notification" + LABEL_CHROME_NOTIFICATION_DESC: "Show new messages notification popups" + LABEL_CHROME_NOTIFICATION_DESC_DENIED: "(Blocked by the browser)" + SETTINGS_CONTACTS: + LEGEND_CONTACTS: "Contacts" + LABEL_CONTACTS_AUTOSAVE: "Automatically add recipients to your address book" + LEGEND_CONTACTS_SYNC: "Remote Synchronization (CardDAV)" + LABEL_CONTACTS_SYNC_ENABLE: "Enable remote synchronization" + LABEL_CONTACTS_SYNC_SERVER: "Server" + LABEL_CONTACTS_SYNC_AB_URL: "Addressbook URL" + LABEL_CONTACTS_SYNC_USER: "User" + LABEL_CONTACTS_SYNC_PASSWORD: "Password" + SETTINGS_THEMES: + LEGEND_THEMES: "Themes" + LEGEND_THEMES_CUSTOM: "Custom Theme Configuration" + LABEL_CUSTOM_TYPE: "Type" + LABEL_CUSTOM_TYPE_LIGHT: "Light" + LABEL_CUSTOM_TYPE_DARK: "Dark" + LABEL_CUSTOM_BACKGROUND_IMAGE: "Background" + BUTTON_UPLOAD_BACKGROUND_IMAGE: "Upload background image (JPG, PNG)" + ERROR_FILE_IS_TOO_BIG: "File is too big" + ERROR_FILE_TYPE_ERROR: "Invalid file type (JPG and PNG only)" + ERROR_UNKNOWN: "An unknown file upload error occurred" + SETTINGS_SOCIAL: + LEGEND_GOOGLE: "Google" + BUTTON_GOOGLE_CONNECT: "Connect Google" + BUTTON_GOOGLE_DISCONNECT: "Disconnect Google" + MAIN_GOOGLE_DESC: "After enabling login via Google, you can log into this account using Google button on the login screen." + LEGEND_FACEBOOK: "Facebook" + BUTTON_FACEBOOK_CONNECT: "Connect Facebook" + BUTTON_FACEBOOK_DISCONNECT: "Disconnect Facebook" + MAIN_FACEBOOK_DESC: "After enabling login via Facebook, you can log into this account using Facebook button on the login screen." + LEGEND_TWITTER: "Twitter" + BUTTON_TWITTER_CONNECT: "Connect Twitter" + BUTTON_TWITTER_DISCONNECT: "Disconnect Twitter" + MAIN_TWITTER_DESC: "After enabling login via Twitter, you can log into this account using Twitter button on the login screen." + SETTINGS_FOLDERS: + LEGEND_FOLDERS: "Folder List" + BUTTON_CREATE: "Create Folder" + BUTTON_SYSTEM: "System Folders" + BUTTON_DELETE: "Delete" + BUTTON_SUBSCRIBE: "Subscribe" + BUTTON_UNSUBSCRIBE: "Unsubscribe" + LOADING_PROCESS: "Updating folder list" + CREATING_PROCESS: "Creating a folder" + DELETING_PROCESS: "Deleting a folder" + RENAMING_PROCESS: "Renaming a folder" + DELETING_ASK: "Are you sure?" + TO_MANY_FOLDERS_DESC_1: "You have too many folders!" + TO_MANY_FOLDERS_DESC_2: "We have shown only a part of them, to avoid performance problems." + HELP_DELETE_FOLDER: "Delete folder" + HELP_SHOW_HIDE_FOLDER: "Show/hide folder" + HELP_CHECK_FOR_NEW_MESSAGES: "Check/don't check for new messages" + SETTINGS_ACCOUNTS: + LEGEND_ACCOUNTS: "Accounts" + LEGEND_IDENTITIES: "Identities" + LEGEND_ACCOUNTS_AND_IDENTITIES: "Accounts and Identities" + BUTTON_ADD_ACCOUNT: "Add an Account" + BUTTON_ADD_IDENTITY: "Add an Identity" + BUTTON_DELETE: "Delete" + LOADING_PROCESS: "Updating..." + DELETING_ASK: "Are you sure?" + DEFAULT_IDENTITY_LABEL: "default" + SETTINGS_IDENTITIES: + LEGEND_IDENTITY: "Identity" + LEGEND_IDENTITIES: "Additional Identities" + LABEL_DEFAULT: "Default" + LABEL_DISPLAY_NAME: "Name" + LABEL_REPLY_TO: "Reply-To" + LABEL_SIGNATURE: "Signature" + LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages" + BUTTON_ADD_IDENTITY: "Add Identity" + BUTTON_DELETE: "Delete" + LOADING_PROCESS: "Updating identity list" + DELETING_ASK: "Are you sure?" + SETTINGS_CHANGE_PASSWORD: + LEGEND_CHANGE_PASSWORD: "Change Password" + LABEL_CURRENT_PASSWORD: "Current password" + LABEL_NEW_PASSWORD: "New password" + LABEL_REPEAT_PASSWORD: "Confirm New Password" + BUTTON_UPDATE_PASSWORD: "Set New Password" + ERROR_PASSWORD_MISMATCH: "Passwords do not match, please try again" + SETTINGS_OPEN_PGP: + LEGEND_OPEN_PGP: "OpenPGP" + BUTTON_ADD_OPEN_PGP_KEY: "Import OpenPGP Key" + BUTTON_GENERATE_OPEN_PGP_KEYS: "Generate OpenPGP Keys" + TITLE_PRIVATE: "Private" + TITLE_PUBLIC: "Public" + DELETING_ASK: "Are you sure?" + GENERATE_ONLY_HTTPS: "HTTPS only" + LABEL_ALLOW_DRAFT_AUTOSAVE: "Automatically save draft" + SHORTCUTS_HELP: + LEGEND_SHORTCUTS_HELP: "Keyboard shortcuts help" + TAB_MAILBOX: "Mailbox" + TAB_MESSAGE_LIST: "Message list" + TAB_MESSAGE_VIEW: "Message view" + TAB_COMPOSE: "Compose" + LABEL_OPEN_USER_DROPDOWN: "Open user dropdown" + LABEL_REPLY: "Reply" + LABEL_REPLY_ALL: "Reply All" + LABEL_FORWARD: "Forward" + LABEL_FORWARD_MULTIPLY: "Forward as attachment(s)" + LABEL_HELP: "Help" + LABEL_CHECK_ALL: "Select all messages" + LABEL_ARCHIVE: "Archive" + LABEL_DELETE: "Delete" + LABEL_OPEN_THREAD: "Open selected thread" + LABEL_MOVE: "Move" + LABEL_READ: "Read selected messages" + LABEL_UNREAD: "Unread selected messages" + LABEL_IMPORTANT: "Important, flag selected messages" + LABEL_SEARCH: "Search" + LABEL_CANCEL_SEARCH: "Cancel search" + LABEL_FULLSCREEN_ENTER: "Fullscreen (Preview pane layout)" + LABEL_VIEW_MESSAGE_ENTER: "View message (No preview pane layout)" + LABEL_SWITCH_TO_MESSAGE: "Switch focus to selected message" + LABEL_SWITCH_TO_FOLDER_LIST: "Switch focus to folder list" + LABEL_FULLSCREEN_TOGGLE: "Toggle fullscreen mode" + LABEL_BLOCKQUOTES_TOGGLE: "Toggle message blockquotes" + LABEL_THREAD_NEXT: "Next message in thread" + LABEL_THREAD_PREV: "Previous message in thread" + LABEL_PRINT: "Print" + LABEL_EXIT_FULLSCREEN: "Exit fullscreen mode" + LABEL_CLOSE_MESSAGE: "Close message (No preview pane layout)" + LABEL_SWITCH_TO_LIST: "Switch focus back to message list" + LABEL_OPEN_COMPOSE_POPUP: "Open compose popup" + LABEL_MINIMIZE_COMPOSE_POPUP: "Minimize compose popup" + LABEL_OPEN_IDENTITIES_DROPDOWN: "Open identities dropdown" + LABEL_SAVE_MESSAGE: "Save message" + LABEL_SEND_MESSAGE: "Send message" + LABEL_CLOSE_COMPOSE: "Close compose" + PGP_NOTIFICATIONS: + NO_PUBLIC_KEYS_FOUND: "No public keys found" + NO_PUBLIC_KEYS_FOUND_FOR: "No public keys found for \"%EMAIL%\" email" + NO_PRIVATE_KEY_FOUND: "No private key found" + NO_PRIVATE_KEY_FOUND_FOR: "No private key found for \"%EMAIL%\" email" + ADD_A_PUBLICK_KEY: "Add a public key" + SELECT_A_PRIVATE_KEY: "Select a private key" + UNVERIFIRED_SIGNATURE: "Unverified signature" + DECRYPTION_ERROR: "OpenPGP decryption error" + GOOD_SIGNATURE: "Good signature from %USER%" + PGP_ERROR: "OpenPGP error: %ERROR%" + SPECIFY_FROM_EMAIL: "Please specify FROM email address" + SPECIFY_AT_LEAST_ONE_RECIPIENT: "Please specify at least one recipient" + NOTIFICATIONS: + INVALID_TOKEN: "Invalid token" + AUTH_ERROR: "Authentication failed" + ACCESS_ERROR: "Access error" + CONNECTION_ERROR: "Can't connect to server" + CAPTCHA_ERROR: "Incorrect CAPTCHA." SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE: > This social ID is not assigned for any email account yet. Log in using email credentials and enable this feature in account settings. @@ -651,63 +651,63 @@ en: SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE: > This social ID is not assigned for any email account yet. Log in using email credentials and enable this feature in account settings. - DOMAIN_NOT_ALLOWED: "Domain is not allowed" - ACCOUNT_NOT_ALLOWED: "Account is not allowed" - ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Two factor verification required" - ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Two factor verification error" - COULD_NOT_SAVE_NEW_PASSWORD: "Could not save new password" - CURRENT_PASSWORD_INCORRECT: "Current password incorrect" - NEW_PASSWORD_SHORT: "Password is too short" - NEW_PASSWORD_WEAK: "Password is too easy" - NEW_PASSWORD_FORBIDDENT: "Password contains forbidden characters" - CONTACTS_SYNC_ERROR: "Contacts synchronization error" - CANT_GET_MESSAGE_LIST: "Can't get message list" - CANT_GET_MESSAGE: "Can't get message" - CANT_DELETE_MESSAGE: "Can't delete message" - CANT_MOVE_MESSAGE: "Can't move message" - CANT_SAVE_MESSAGE: "Can't save message" - CANT_SEND_MESSAGE: "Can't send message" - INVALID_RECIPIENTS: "Invalid recipients" - CANT_SAVE_FILTERS: "Can't save filters" - CANT_GET_FILTERS: "Can't get filters" - FILTERS_ARE_NOT_CORRECT: "Filters are not correct" - CANT_CREATE_FOLDER: "Can't create folder" - CANT_RENAME_FOLDER: "Can't rename folder" - CANT_DELETE_FOLDER: "Can't delete folder" - CANT_DELETE_NON_EMPTY_FOLDER: "Can't delete non-empty directory" - CANT_SUBSCRIBE_FOLDER: "Can't subscribe folder" - CANT_UNSUBSCRIBE_FOLDER: "Can't unsubscribe folder" - CANT_SAVE_SETTINGS: "Can't save settings" - CANT_SAVE_PLUGIN_SETTINGS: "Can't save settings" - DOMAIN_ALREADY_EXISTS: "Domain already exists" - CANT_INSTALL_PACKAGE: "Failed to install package" - CANT_DELETE_PACKAGE: "Failed to remove package" - INVALID_PLUGIN_PACKAGE: "Invalid plugin package" - UNSUPPORTED_PLUGIN_PACKAGE: "Unsupported plugin package" - LICENSING_SERVER_IS_UNAVAILABLE: "Subscription server is unvailable" - LICENSING_DOMAIN_EXPIRED: "Subscription for this domain has expired." - LICENSING_DOMAIN_BANNED: "Subscription for this domain is banned." - DEMO_SEND_MESSAGE_ERROR: "For security purposes, this account is not allowed to send messages to external e-mail addresses!" - DEMO_ACCOUNT_ERROR: "For security purposes, this account is not allowed for this action!" - ACCOUNT_ALREADY_EXISTS: "Account already exists" - ACCOUNT_DOES_NOT_EXIST: "Account doesn't exist" - MAIL_SERVER_ERROR: "An error has occured while accessing mail server" - INVALID_INPUT_ARGUMENT: "Invalid input argument" - UNKNOWN_ERROR: "Unknown error" - STATIC: - BACK_LINK: "Reload" - DOMAIN_LIST_DESC: "List of domains webmail is allowed to access." - PHP_EXSTENSIONS_ERROR_DESC: "Required PHP extension are not available in your PHP configuration!" - PHP_VERSION_ERROR_DESC: "Your PHP version (%VERSION%) is lower than the minimal required 5.3.0!" - NO_SCRIPT_TITLE: "JavaScript is required for this application." + DOMAIN_NOT_ALLOWED: "Domain is not allowed" + ACCOUNT_NOT_ALLOWED: "Account is not allowed" + ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Two factor verification required" + ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Two factor verification error" + COULD_NOT_SAVE_NEW_PASSWORD: "Could not save new password" + CURRENT_PASSWORD_INCORRECT: "Current password incorrect" + NEW_PASSWORD_SHORT: "Password is too short" + NEW_PASSWORD_WEAK: "Password is too easy" + NEW_PASSWORD_FORBIDDENT: "Password contains forbidden characters" + CONTACTS_SYNC_ERROR: "Contacts synchronization error" + CANT_GET_MESSAGE_LIST: "Can't get message list" + CANT_GET_MESSAGE: "Can't get message" + CANT_DELETE_MESSAGE: "Can't delete message" + CANT_MOVE_MESSAGE: "Can't move message" + CANT_SAVE_MESSAGE: "Can't save message" + CANT_SEND_MESSAGE: "Can't send message" + INVALID_RECIPIENTS: "Invalid recipients" + CANT_SAVE_FILTERS: "Can't save filters" + CANT_GET_FILTERS: "Can't get filters" + FILTERS_ARE_NOT_CORRECT: "Filters are not correct" + CANT_CREATE_FOLDER: "Can't create folder" + CANT_RENAME_FOLDER: "Can't rename folder" + CANT_DELETE_FOLDER: "Can't delete folder" + CANT_DELETE_NON_EMPTY_FOLDER: "Can't delete non-empty directory" + CANT_SUBSCRIBE_FOLDER: "Can't subscribe folder" + CANT_UNSUBSCRIBE_FOLDER: "Can't unsubscribe folder" + CANT_SAVE_SETTINGS: "Can't save settings" + CANT_SAVE_PLUGIN_SETTINGS: "Can't save settings" + DOMAIN_ALREADY_EXISTS: "Domain already exists" + CANT_INSTALL_PACKAGE: "Failed to install package" + CANT_DELETE_PACKAGE: "Failed to remove package" + INVALID_PLUGIN_PACKAGE: "Invalid plugin package" + UNSUPPORTED_PLUGIN_PACKAGE: "Unsupported plugin package" + LICENSING_SERVER_IS_UNAVAILABLE: "Subscription server is unvailable" + LICENSING_DOMAIN_EXPIRED: "Subscription for this domain has expired." + LICENSING_DOMAIN_BANNED: "Subscription for this domain is banned." + DEMO_SEND_MESSAGE_ERROR: "For security purposes, this account is not allowed to send messages to external e-mail addresses!" + DEMO_ACCOUNT_ERROR: "For security purposes, this account is not allowed for this action!" + ACCOUNT_ALREADY_EXISTS: "Account already exists" + ACCOUNT_DOES_NOT_EXIST: "Account doesn't exist" + MAIL_SERVER_ERROR: "An error has occured while accessing mail server" + INVALID_INPUT_ARGUMENT: "Invalid input argument" + UNKNOWN_ERROR: "Unknown error" + STATIC: + BACK_LINK: "Reload" + DOMAIN_LIST_DESC: "List of domains webmail is allowed to access." + PHP_EXSTENSIONS_ERROR_DESC: "Required PHP extension are not available in your PHP configuration!" + PHP_VERSION_ERROR_DESC: "Your PHP version (%VERSION%) is lower than the minimal required 5.3.0!" + NO_SCRIPT_TITLE: "JavaScript is required for this application." NO_SCRIPT_DESC: | JavaScript support is not available in your browser. Please enable JavaScript support in your browser settings and retry. - NO_COOKIE_TITLE: "Cookies support is required for this application." + NO_COOKIE_TITLE: "Cookies support is required for this application." NO_COOKIE_DESC: | Cookies support is not available in your browser. Please enable Cookie support in your browser settings and retry. - BAD_BROWSER_TITLE: "Your browser is outdated." + BAD_BROWSER_TITLE: "Your browser is outdated." BAD_BROWSER_DESC: | To use all the features of the application, download and install one of these browsers: diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ar_SA.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/ar_SA.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ar_SA.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/ar_SA.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/bg_BG.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/bg_BG.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/bg_BG.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/bg_BG.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/cs_CZ.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/cs_CZ.yml similarity index 87% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/cs_CZ.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/cs_CZ.yml index 970aa02e..68e86348 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/cs_CZ.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/cs_CZ.yml @@ -27,7 +27,7 @@ cs_CZ: LABEL_ADV_TO: "Příjemce" LABEL_ADV_SUBJECT: "Předmět" LABEL_ADV_TEXT: "Text" - LABEL_ADV_HAS_ATTACHMENT: "S přílohu" + LABEL_ADV_HAS_ATTACHMENT: "S přílohou" LABEL_ADV_HAS_ATTACHMENTS: "S přílohami" LABEL_ADV_FLAGGED: "Označené hvězdičkou" LABEL_ADV_UNSEEN: "Nepřečtené" @@ -102,13 +102,14 @@ cs_CZ: BUTTON_BACK: "Zpět" BUTTON_CLOSE: "Zavřít" BUTTON_DELETE: "Odstranit" + BUTTON_UNSUBSCRIBE: "Odhlásit se z odběru" BUTTON_ARCHIVE: "Archivovat" BUTTON_SPAM: "Je to SPAM" BUTTON_NOT_SPAM: "Není to SPAM" BUTTON_MOVE_TO: "Přesunout do" BUTTON_MORE: "Více" BUTTON_REPLY: "Odpovědět" - BUTTON_REPLY_ALL: "Odpovědaě všem" + BUTTON_REPLY_ALL: "Odpovědět všem" BUTTON_FORWARD: "Přeposlat" BUTTON_FORWARD_AS_ATTACHMENT: "Přeposlat jako přílohu" BUTTON_EDIT_AS_NEW: "Použit jako šablonu" @@ -144,18 +145,20 @@ cs_CZ: PRINT_LABEL_ATTACHMENTS: "Přílohy" MESSAGE_LOADING: "Načítám" MESSAGE_VIEW_DESC: "Vyberte zprávu ze seznamu pro její zobrazení zde." + MESSAGE_VIEW_MOVE_DESC: "Vyberte cílovou složku v levém panelu." PGP_PASSWORD_INPUT_PLACEHOLDER: "Heslo" PGP_SIGNED_MESSAGE_DESC: "Zpráva podepsaná OpenPGP (klikněte pro ověření)" PGP_ENCRYPTED_MESSAGE_DESC: "Zpráva šifrovaná OpenPGP (klikněte pro dešifraci)" LINK_DOWNLOAD_AS_ZIP: "Stáhnout jako zip" LINK_SAVE_TO_OWNCLOUD: "Uložit do ownCloud" + LINK_SAVE_TO_CLOUD: "Uložit do Cloudu" LINK_SAVE_TO_DROPBOX: "Uložit do Dropbox" READ_RECEIPT: SUBJECT: "Potvrzení o zobrazení zprávy - %SUBJECT%" BODY: | Toto je potrvzení o zaslání emailu na adresu %READ-RECEIPT%. - Poznámka: Toto potvrzení zajištujě, že zpráva byla zobrazena v poštovní schrnánce příjemce. Nezajišťuje, že ji příjemce čelt a rozuměl jí. + Poznámka: Toto potvrzení zajišťuje, že zpráva byla zobrazena v poštovní schránce příjemce. Nezajišťuje, že ji příjemce četl a rozuměl jí. SUGGESTIONS: SEARCHING_DESC: "Hledám..." CONTACTS: @@ -231,10 +234,10 @@ cs_CZ: NO_ATTACHMENTS_HERE_DESC: "Žádné přílohy." ATTACHMENTS_ERROR_DESC: "Upozornění! Některé přílohy nebyly nahrány." ATTACHMENTS_UPLOAD_ERROR_DESC: "Některé přílohy ještě nebyly nahrány" - BUTTON_REQUEST_READ_RECEIPT: "Vyžádat si potvrzení o příjetí" + BUTTON_REQUEST_READ_RECEIPT: "Vyžádat si potvrzení o přečtení" BUTTON_MARK_AS_IMPORTANT: "Označit jako důležité" BUTTON_OPEN_PGP: "OpenPGP (jen Plain Text)" - BUTTON_REQUEST_DSN: "Request a delivery receipt" + BUTTON_REQUEST_DSN: "Vyžádat si potvrzení o přijetí" POPUPS_WELCOME_PAGE: BUTTON_CLOSE: "Zavřít" POPUPS_ASK: @@ -376,28 +379,29 @@ cs_CZ: LEGEND_TWO_FACTOR_AUTH: "Dvoufázové ověření" LABEL_ENABLE_TWO_FACTOR: "Povlit dvoufázové ověření" LABEL_TWO_FACTOR_USER: "Uživatel" - LABEL_TWO_FACTOR_STATUS: "Status" - LABEL_TWO_FACTOR_SECRET: "Secret" - LABEL_TWO_FACTOR_BACKUP_CODES: "Backup codes" - BUTTON_CREATE: "Create New Secret" + LABEL_TWO_FACTOR_STATUS: "Stav" + LABEL_TWO_FACTOR_SECRET: "Tajný klíč" + LABEL_TWO_FACTOR_BACKUP_CODES: "Záložní kódy" + BUTTON_CREATE: "Aktivovat dvoustupňové přihlašování" BUTTON_ACTIVATE: "Aktivovat" - BUTTON_CLEAR: "Clear" + BUTTON_CLEAR: "Zrušit dvoustupňové přihlašování" BUTTON_LOGOUT: "Odhlásit" BUTTON_DONE: "Hotovo" BUTTON_TEST: "Test" - LINK_TEST: "test" - BUTTON_SHOW_SECRET: "Show Secret" - BUTTON_HIDE_SECRET: "Hide Secret" + LINK_TEST: "Otestovat" + BUTTON_SHOW_SECRET: "Zobrazit tajné klíče" + BUTTON_HIDE_SECRET: "Skrýt tajné klíče" TWO_FACTOR_REQUIRE_DESC: "Váš účet vyžaduje nastavení dvoufázového ověření" TWO_FACTOR_SECRET_CONFIGURED_DESC: "Nastaveno" TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Nenastaveno" - TWO_FACTOR_SECRET_DESC: >- - Import this info into your Google Authenticator client (or other TOTP client) - using the provided QR code below or by entering the code manually. - TWO_FACTOR_BACKUP_CODES_DESC: >- - If you can't receive codes via Google Authenticator, you can use backup codes - to sign in. After you’ve used a backup code to sign in, it will become inactive. - TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "You can't change this setting before test." + TWO_FACTOR_SECRET_DESC: > + Importujte klíč do Vašeho Google Authenticatoru (nebo jiného TOTP klienta) + pomocí níže uvedeného QR kódu nebo zadáním kódu ručně. + TWO_FACTOR_BACKUP_CODES_DESC: > + Pokud nemůžete získat kódy skrze Google Authenticator (nebo jiného TOTP klienta), + můžete použít záložní kódy k přihlášení. Poté, co použijete záložní klíč, + stane se nadále neaktivním. + TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "Toto nastavení nelze změnit před otestováním." TITLES: LOADING: "Načítám" LOGIN: "Uživatelské jméno" @@ -410,9 +414,10 @@ cs_CZ: ERROR_NO_FILE_UPLOADED: "Soubor nebyl nahrán" ERROR_MISSING_TEMP_FOLDER: "Chybí dočasný soubor" ERROR_ON_SAVING_FILE: "Nastala neznámá chyba při ukládání" - ERROR_FILE_TYPE: "Nesprávny typ souboru" + ERROR_FILE_TYPE: "Neplatný typ souboru" ERROR_UNKNOWN: "Nastala neznámá chyba při nahrávaní" EDITOR: + TEXT_SWITCHER_PLAINT_TEXT: "HTML <-> TEXT" TEXT_SWITCHER_RICH_FORMATTING: "Formátovaný text" TEXT_SWITCHER_CONFIRM: "Formátování textu a obrázky budou odstraněné. Chcete pokračovat?" SETTINGS_LABELS: @@ -421,8 +426,8 @@ cs_CZ: LABEL_CONTACTS_NAME: "Kontakty" LABEL_FOLDERS_NAME: "Složky" LABEL_ACCOUNTS_NAME: "Účty" - LABEL_IDENTITY_NAME: "Identita" - LABEL_IDENTITIES_NAME: "Identity" + LABEL_IDENTITY_NAME: "Alias" + LABEL_IDENTITIES_NAME: "Aliasy" LABEL_FILTERS_NAME: "Filtry" LABEL_TEMPLATES_NAME: "Šablony" LABEL_SECURITY_NAME: "Zabezpečení" @@ -445,10 +450,10 @@ cs_CZ: SUBNAME_DISCARD: "Zahodit" CAPABILITY_LABEL: "Capability" LOADING_PROCESS: "Aktualizovat seznam filtrů" - DELETING_ASK: "Opravdu to chcete?" + DELETING_ASK: "Jste si jisti?" CHACHES_NEED_TO_BE_SAVED_DESC: "Změny musí být uloženy na serveru." SETTINGS_IDENTITY: - LEGEND_IDENTITY: "Identita" + LEGEND_IDENTITY: "Aliasy" LABEL_DISPLAY_NAME: "Jméno" LABEL_REPLY_TO: "Adresa pro odpovědi" LABEL_SIGNATURE: "Podpis" @@ -459,11 +464,12 @@ cs_CZ: LABEL_AUTOLOGOUT: "Automatické odhlášení" AUTOLOGIN_NEVER_OPTION_NAME: "Nikdy" AUTOLOGIN_MINUTES_OPTION_NAME: "%MINUTES% minut" + AUTOLOGIN_HOURS_OPTION_NAME: "%HOURS% hodin" SETTINGS_GENERAL: LEGEND_GENERAL: "Všeobecné" LABEL_LANGUAGE: "Jazyk" - LABEL_IDENTITY: "Identity" - LABEL_LAYOUT: "Layout" + LABEL_IDENTITY: "Uživatel" + LABEL_LAYOUT: "Rozložení" LABEL_LAYOUT_NO_SPLIT: "Nerozdělovat" LABEL_LAYOUT_VERTICAL_SPLIT: "Vertikální rozdělení" LABEL_LAYOUT_HORIZONTAL_SPLIT: "Horizontální rozdělění" @@ -471,7 +477,7 @@ cs_CZ: LABEL_EDITOR_HTML: "Html" LABEL_EDITOR_PLAIN: "Text" LABEL_EDITOR_HTML_FORCED: "Html (vynucený)" - LABEL_EDITOR_PLAIN_FORCED: "Plain (vynucený)" + LABEL_EDITOR_PLAIN_FORCED: "Text (vynucený)" LABEL_ANIMATION: "Animace prostředí" LABEL_ANIMATION_FULL: "Všechny" LABEL_ANIMATION_NORMAL: "Normální" @@ -494,7 +500,7 @@ cs_CZ: LEGEND_CONTACTS_SYNC: "Vzdálená synchronizace (CardDAV)" LABEL_CONTACTS_SYNC_ENABLE: "Povolit vzdálenou synchronizaci" LABEL_CONTACTS_SYNC_SERVER: "Server" - LABEL_CONTACTS_SYNC_AB_URL: "Addressbook URL" + LABEL_CONTACTS_SYNC_AB_URL: "URL adresáře" LABEL_CONTACTS_SYNC_USER: "Uživatel" LABEL_CONTACTS_SYNC_PASSWORD: "Heslo" SETTINGS_THEMES: @@ -524,6 +530,7 @@ cs_CZ: SETTINGS_FOLDERS: LEGEND_FOLDERS: "Seznam složek" BUTTON_CREATE: "Vytvořit složku" + BUTTON_SYSTEM: "Systémové složky" BUTTON_DELETE: "Odstranit" BUTTON_SUBSCRIBE: "Přihlásit se" BUTTON_UNSUBSCRIBE: "Odhlásit se" @@ -531,7 +538,7 @@ cs_CZ: CREATING_PROCESS: "Vytvářím složku" DELETING_PROCESS: "Odstraňuji složku" RENAMING_PROCESS: "Přejmenovávám složku" - DELETING_ASK: "Opravdu to chcete?" + DELETING_ASK: "Jste si jisti?" TO_MANY_FOLDERS_DESC_1: "Máte moc složek!" TO_MANY_FOLDERS_DESC_2: "Můžeme zobrazit jen část z nich, abychom zabránili problémům s výkonem." HELP_DELETE_FOLDER: "Smazat složku" @@ -539,25 +546,25 @@ cs_CZ: HELP_CHECK_FOR_NEW_MESSAGES: "Kontrovat/nekontrolovat nové příchozí zprávy" SETTINGS_ACCOUNTS: LEGEND_ACCOUNTS: "Seznam účtů" - LEGEND_IDENTITIES: "Identity" - LEGEND_ACCOUNTS_AND_IDENTITIES: "Účty a identity" + LEGEND_IDENTITIES: "Aliasy" + LEGEND_ACCOUNTS_AND_IDENTITIES: "Účty a aliasy" BUTTON_ADD_ACCOUNT: "Přidat účet" - BUTTON_ADD_IDENTITY: "Přidat identitu" + BUTTON_ADD_IDENTITY: "Přidat alias" BUTTON_DELETE: "Odstranit" LOADING_PROCESS: "Aktualizace seznamu účtů" DELETING_ASK: "Opravdu to chcete?" DEFAULT_IDENTITY_LABEL: "výchozí" SETTINGS_IDENTITIES: - LEGEND_IDENTITY: "Identita" - LEGEND_IDENTITIES: "Další identity" + LEGEND_IDENTITY: "Alias" + LEGEND_IDENTITIES: "Další aliasy" LABEL_DEFAULT: "Výchozí" LABEL_DISPLAY_NAME: "Jméno" LABEL_REPLY_TO: "Adresa pro odpověď" LABEL_SIGNATURE: "Podpis" LABEL_ADD_SIGNATURE_TO_ALL: "Připojit ke všem odeslaným zprávám" - BUTTON_ADD_IDENTITY: "Přidat Identitu" + BUTTON_ADD_IDENTITY: "Přidat alias" BUTTON_DELETE: "Odstranit" - LOADING_PROCESS: "Aktualizace seznamu identit" + LOADING_PROCESS: "Aktualizace seznamu aliasů" DELETING_ASK: "Opravdu to chcete?" SETTINGS_CHANGE_PASSWORD: LEGEND_CHANGE_PASSWORD: "Změnit heslo" @@ -574,6 +581,7 @@ cs_CZ: TITLE_PUBLIC: "Veřejný" DELETING_ASK: "Opravdu to chcete?" GENERATE_ONLY_HTTPS: "Pouze HTTPS" + LABEL_ALLOW_DRAFT_AUTOSAVE: "Automaticky uložit koncept" SHORTCUTS_HELP: LEGEND_SHORTCUTS_HELP: "Klávesové zkratky" TAB_MAILBOX: "Schránka" @@ -596,37 +604,37 @@ cs_CZ: LABEL_IMPORTANT: "Označit vybrané zprávy jako důležité" LABEL_SEARCH: "Hledat" LABEL_CANCEL_SEARCH: "Zrušit hledání" - LABEL_FULLSCREEN_ENTER: "Fullscreen (Preview pane layout)" - LABEL_VIEW_MESSAGE_ENTER: "View message (No preview pane layout)" - LABEL_SWITCH_TO_MESSAGE: "Switch focus to selected message" - LABEL_SWITCH_TO_FOLDER_LIST: "Switch focus to folder list" - LABEL_FULLSCREEN_TOGGLE: "Toggle fullscreen mode" - LABEL_BLOCKQUOTES_TOGGLE: "Toggle message blockquotes" - LABEL_THREAD_NEXT: "Next message in thread" - LABEL_THREAD_PREV: "Previous message in thread" + LABEL_FULLSCREEN_ENTER: "Celoobrazovkové rozložení (náhled)" + LABEL_VIEW_MESSAGE_ENTER: "Zobrazit zprávu (bez náhledu)" + LABEL_SWITCH_TO_MESSAGE: "Zobrazit vybranou zprávu" + LABEL_SWITCH_TO_FOLDER_LIST: "Skočit do panelu adresářů" + LABEL_FULLSCREEN_TOGGLE: "Přepnout režim celé obrazovky" + LABEL_BLOCKQUOTES_TOGGLE: "Přepnout zobrazení přiložených zpráv" + LABEL_THREAD_NEXT: "Následující zpráva ve vlákně" + LABEL_THREAD_PREV: "Předchozí zpráva ve vlákně" LABEL_PRINT: "Tisk" - LABEL_EXIT_FULLSCREEN: "Exit fullscreen mode" - LABEL_CLOSE_MESSAGE: "Close message (No preview pane layout)" - LABEL_SWITCH_TO_LIST: "Switch focus back to message list" - LABEL_OPEN_COMPOSE_POPUP: "Open compose popup" - LABEL_MINIMIZE_COMPOSE_POPUP: "Minimize compose popup" - LABEL_OPEN_IDENTITIES_DROPDOWN: "Open identities dropdown" - LABEL_SAVE_MESSAGE: "Save message" - LABEL_SEND_MESSAGE: "Send message" - LABEL_CLOSE_COMPOSE: "Close compose" + LABEL_EXIT_FULLSCREEN: "Ukončit režim celé obrazovky" + LABEL_CLOSE_MESSAGE: "Zavřít zprávu (bez náhledu)" + LABEL_SWITCH_TO_LIST: "Vrátit se zpět do seznamu zpráv" + LABEL_OPEN_COMPOSE_POPUP: "Nová zpráva v okně" + LABEL_MINIMIZE_COMPOSE_POPUP: "Minimalizovat otevřené okno" + LABEL_OPEN_IDENTITIES_DROPDOWN: "Otevřít seznam aliasů" + LABEL_SAVE_MESSAGE: "Uložit zprávu" + LABEL_SEND_MESSAGE: "Odeslat zprávu" + LABEL_CLOSE_COMPOSE: "Zavřít okno se zprávou" PGP_NOTIFICATIONS: - NO_PUBLIC_KEYS_FOUND: "No public keys found" - NO_PUBLIC_KEYS_FOUND_FOR: "No public keys found for \"%EMAIL%\" email" - NO_PRIVATE_KEY_FOUND: "No private key found" - NO_PRIVATE_KEY_FOUND_FOR: "No private key found for \"%EMAIL%\" email" - ADD_A_PUBLICK_KEY: "Add a public key" + NO_PUBLIC_KEYS_FOUND: "Nenalezen žádný veřejný klíč" + NO_PUBLIC_KEYS_FOUND_FOR: "Žádný veřejný klíč pro \"%EMAIL%\" nenalezen" + NO_PRIVATE_KEY_FOUND: "Nenalezen žádný soukromý klíč" + NO_PRIVATE_KEY_FOUND_FOR: "Žádný soukromý klíč pro \"%EMAIL%\" nenalezen" + ADD_A_PUBLICK_KEY: "Přidat veřejný klíč" SELECT_A_PRIVATE_KEY: "Vyberte soukromý klíč" - UNVERIFIRED_SIGNATURE: "Unverified signature" - DECRYPTION_ERROR: "OpenPGP decryption error" - GOOD_SIGNATURE: "Good signature from %USER%" - PGP_ERROR: "OpenPGP error: %ERROR%" - SPECIFY_FROM_EMAIL: "Please specify FROM email address" - SPECIFY_AT_LEAST_ONE_RECIPIENT: "Please specify at least one recipient" + UNVERIFIRED_SIGNATURE: "Neověřený podpis" + DECRYPTION_ERROR: "OpenPGP chyba dešifrování" + GOOD_SIGNATURE: "Ověřený podpis od %USER%" + PGP_ERROR: "OpenPGP chyba: %ERROR%" + SPECIFY_FROM_EMAIL: "Zadejte emailovou adresu odesílatele" + SPECIFY_AT_LEAST_ONE_RECIPIENT: "Zadejte prosím alespoň jednoho příjemce" NOTIFICATIONS: INVALID_TOKEN: "Neplatný token" AUTH_ERROR: "Ověření selhalo" @@ -666,8 +674,8 @@ cs_CZ: CANT_RENAME_FOLDER: "Složku se nepodařilo přejmenovat" CANT_DELETE_FOLDER: "Složku se nepodařilo odstranit" CANT_DELETE_NON_EMPTY_FOLDER: "Nelze odstranit neprázdnou složku" - CANT_SUBSCRIBE_FOLDER: "Can't subscribe folder" - CANT_UNSUBSCRIBE_FOLDER: "Can't unsubscribe folder" + CANT_SUBSCRIBE_FOLDER: "Nelze přihlásit adresář" + CANT_UNSUBSCRIBE_FOLDER: "Nelze odhlásit adresář" CANT_SAVE_SETTINGS: "Nastavení se nepodařilo uložit" CANT_SAVE_PLUGIN_SETTINGS: "Nastavení se nepodařilo uložit" DOMAIN_ALREADY_EXISTS: "Táto doména již existuje" diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/da_DK.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/da_DK.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/da_DK.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/da_DK.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/de_DE.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/de_DE.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/de_DE.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/de_DE.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/el_GR.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/el_GR.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/el_GR.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/el_GR.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/en_GB.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/en_GB.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/en_GB.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/en_GB.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/en_US.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/en_US.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/en_US.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/en_US.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/es_ES.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/es_ES.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/es_ES.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/es_ES.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/et_EE.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/et_EE.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/et_EE.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/et_EE.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fa_IR.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/fa_IR.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fa_IR.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/fa_IR.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fi_FI.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/fi_FI.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fi_FI.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/fi_FI.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fr_FR.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/fr_FR.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fr_FR.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/fr_FR.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/hu_HU.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/hu_HU.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/hu_HU.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/hu_HU.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/id_ID.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/id_ID.yml similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/id_ID.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/id_ID.yml index 2b4c3188..c8e99fed 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/id_ID.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/id_ID.yml @@ -10,7 +10,7 @@ id_ID: TITLE_SIGN_IN_GOOGLE: "Masuk dengan akun Google" TITLE_SIGN_IN_FACEBOOK: "Masuk dengan akun Facebook" TITLE_SIGN_IN_TWITTER: "Masuk dengan akun Twitter" - LABEL_FORGOT_PASSWORD: "Lupa Sandi" + LABEL_FORGOT_PASSWORD: "Lupa sandi" LABEL_REGISTRATION: "Registrasi" TOP_TOOLBAR: BUTTON_ADD_ACCOUNT: "Tambah Akun" @@ -22,7 +22,7 @@ id_ID: BUTTON_DESKTOP_VERSION: "Versi Desktop" SEARCH: MAIN_INPUT_PLACEHOLDER: "Cari" - TITLE_ADV: "Pencarian lanjutan" + TITLE_ADV: "Pencarian Rinci" LABEL_ADV_FROM: "Dari" LABEL_ADV_TO: "Kepada" LABEL_ADV_SUBJECT: "Judul" @@ -69,7 +69,7 @@ id_ID: BUTTON_ARCHIVE: "Arsipkan" BUTTON_SPAM: "Spam" BUTTON_NOT_SPAM: "Bukan Spam" - BUTTON_EMPTY_FOLDER: "Buat Folder" + BUTTON_EMPTY_FOLDER: "Bersihkan Folder" BUTTON_MULTY_FORWARD: "Teruskan sebagai lampiran" BUTTON_DELETE_WITHOUT_MOVE: "Hapus permanen" BUTTON_MORE: "Lagi" @@ -181,10 +181,10 @@ id_ID: LABEL_EMAIL: "Email" LABEL_PHONE: "Telepon" LABEL_WEB: "Web" - LABEL_BIRTHDAY: "Ultah" + LABEL_BIRTHDAY: "Tanggal lahir" LINK_ADD_EMAIL: "Tambah alamat email" LINK_ADD_PHONE: "Tambah telepon" - LINK_BIRTHDAY: "Ultah" + LINK_BIRTHDAY: "Tanggal lahir" PLACEHOLDER_ENTER_DISPLAY_NAME: "Isi nama tampilan" PLACEHOLDER_ENTER_LAST_NAME: "Isi nama belakang " PLACEHOLDER_ENTER_FIRST_NAME: "Isi nama depan" @@ -198,9 +198,9 @@ id_ID: ADD_MENU_PHONE: "Telepon" ADD_MENU_URL: "URL" ADD_MENU_ADDRESS: "Alamat" - ADD_MENU_BIRTHDAY: "Ultah" + ADD_MENU_BIRTHDAY: "Tanggal lahir" ADD_MENU_TAGS: "Penanda" - BUTTON_SHARE_NONE: "Kosongkan" + BUTTON_SHARE_NONE: "Tak satupun" BUTTON_SHARE_ALL: "Semuanya" BUTTON_SYNC: "Sinkronisasi (CardDAV)" COMPOSE: @@ -236,7 +236,7 @@ id_ID: ATTACHMENTS_ERROR_DESC: "Peringatan! belum semua lampiran terunggah." ATTACHMENTS_UPLOAD_ERROR_DESC: "Belum semua lampiran terunggah." BUTTON_REQUEST_READ_RECEIPT: "Minta pemberitahuan telah dibaca" - BUTTON_MARK_AS_IMPORTANT: "Tandai sebagai penting" + BUTTON_MARK_AS_IMPORTANT: "Tandai sebagai pesan penting" BUTTON_OPEN_PGP: "OpenPGP (Teks Biasa)" BUTTON_REQUEST_DSN: "Minta pemberitahuan berhasil kirim" POPUPS_WELCOME_PAGE: @@ -245,7 +245,7 @@ id_ID: BUTTON_YES: "Ya" BUTTON_NO: "Tidak" DESC_WANT_CLOSE_THIS_WINDOW: "Anda yakin untuk menutup jendela ini?" - DESC_WANT_DELETE_MESSAGES: "Anda yakin untuk menutup semua jendela ini?" + DESC_WANT_DELETE_MESSAGES: "Anda yakin menghapus permanen pesan ini?" POPUPS_LANGUAGES: TITLE_LANGUAGES: "Pilih bahasa" POPUPS_ADD_ACCOUNT: @@ -279,7 +279,7 @@ id_ID: BUTTON_CANCEL: "Batal" BUTTON_CLOSE: "Tutup" DANGER_DESC_WARNING: "Peringatan!" - DANGER_DESC_HTML_1: "Aksi ini akan menyebabkan dibuangnya surat dari folder%FOLDER% secara menyeluruh." + DANGER_DESC_HTML_1: "Aksi ini akan menyebabkan dibuangnya surat dari folder %FOLDER% secara menyeluruh." DANGER_DESC_HTML_2: "Begitu dimulai, proses tidak dapat dibatalkan atau ditunda." TITLE_CLEARING_PROCESS: "Membersihkan folder..." POPUPS_IMPORT_OPEN_PGP_KEY: @@ -701,13 +701,13 @@ id_ID: PHP_VERSION_ERROR_DESC: "Versi PHP anda (%VERSION%) lebih rendah dari syarat minimal yaitu 5.3.0!" NO_SCRIPT_TITLE: "JavaScript diperlukan oleh aplikasi ini." NO_SCRIPT_DESC: | - Dukungan Javascript tidak tersedia di peramban anda - Silahkan aktifkan dukungan Javascript di pengaturan peramban anda dan coba lagi. + Dukungan Javascript tidak tersedia di browser anda + Silahkan aktifkan dukungan Javascript di pengaturan browser anda dan coba lagi. NO_COOKIE_TITLE: "Dukurangan Cookies diperlukan oleh aplikasi ini." NO_COOKIE_DESC: | - Dukungan cookies tidak tersedia di peramban anda. - Silahkan aktifkan dukungan Cookies di pengaturan peramban dan coba lagi. - BAD_BROWSER_TITLE: "Peramban anda kadaluarsa." + Dukungan cookies tidak tersedia di browser anda. + Silahkan aktifkan dukungan Cookies di pengaturan browser dan coba lagi. + BAD_BROWSER_TITLE: "Browser anda kadaluarsa." BAD_BROWSER_DESC: | Untuk bisa menggunakan semua fitur aplikasi, - unduh dan pasang salah satu peramban berikut: + unduh dan pasang salah satu browser berikut: diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/is_IS.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/is_IS.yml similarity index 59% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/is_IS.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/is_IS.yml index ce8e24f5..0ded9715 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/is_IS.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/is_IS.yml @@ -1,12 +1,12 @@ is_IS: LOGIN: - LABEL_EMAIL: "Netfang" - LABEL_LOGIN: "Innskrá" + LABEL_EMAIL: "Tölvupóstfang" + LABEL_LOGIN: "Innskráning" LABEL_PASSWORD: "Lykilorð" LABEL_SIGN_ME: "Muna" LABEL_VERIFICATION_CODE: "Sannvottunarkóði" LABEL_DONT_ASK_VERIFICATION_CODE: "Ekki spyrja um kóðann næstu 2 vikur" - BUTTON_SIGN_IN: "Innskrá" + BUTTON_SIGN_IN: "Skrá inn" TITLE_SIGN_IN_GOOGLE: "Innskráning með Google" TITLE_SIGN_IN_FACEBOOK: "Innskráning með Facebook" TITLE_SIGN_IN_TWITTER: "Innskráning með Twitter" @@ -19,7 +19,7 @@ is_IS: BUTTON_LOGOUT: "Útskrá" MOBILE: BUTTON_MOBILE_VERSION: "Farsímaútgáfa" - BUTTON_DESKTOP_VERSION: "Skjáborðsútgáfa" + BUTTON_DESKTOP_VERSION: "Vinnutölvuútgáfa" SEARCH: MAIN_INPUT_PLACEHOLDER: "Leita" TITLE_ADV: "Ítarleg leit" @@ -42,7 +42,7 @@ is_IS: BUTTON_ADV_SEARCH: "Leita" PREVIEW_POPUP: FULLSCREEN: "Víxla heilskjá af/á" - ZOOM: "Aðdráttir að/frá" + ZOOM: "Aðdráttur að/frá" CLOSE: "Loka (Esc)" LOADING: "Hleð..." GALLERY_PREV: "Fyrra (vinstri örvarhnappur)" @@ -70,7 +70,7 @@ is_IS: BUTTON_SPAM: "Ruslpóstur" BUTTON_NOT_SPAM: "Ekki ruslpóstur" BUTTON_EMPTY_FOLDER: "Hreinsa möppu" - BUTTON_MULTY_FORWARD: "Áframsenda skilaboð" + BUTTON_MULTY_FORWARD: "Áframsenda sem viðhengi" BUTTON_DELETE_WITHOUT_MOVE: "Eyða endanlega" BUTTON_MORE: "Meira" MENU_SET_SEEN: "Merkja lesið" @@ -95,7 +95,7 @@ is_IS: TODAY_AT: "í dag kl. %TIME%" YESTERDAY_AT: "í gær kl. %TIME%" SEARCH_PLACEHOLDER: "Leita" - NEW_MESSAGE_NOTIFICATION: "Þú átt %COUNT% ný bréf!" + NEW_MESSAGE_NOTIFICATION: "Þú átt %COUNT% ný skilaboð!" QUOTA_SIZE: "Notar %SIZE% (%PROC%%) af %LIMIT%" MESSAGE: BUTTON_EDIT: "Breyta" @@ -120,13 +120,13 @@ is_IS: BUTTON_THREAD_PREV: "Fyrra" BUTTON_THREAD_NEXT: "Næsta" BUTTON_THREAD_MORE: "Fleiri skilaboð" - MENU_HEADERS: "Sýna bréfahausa" + MENU_HEADERS: "Sýna skilaboðahausa" MENU_VIEW_ORIGINAL: "Sýna upprunalegt" - MENU_DOWNLOAD_ORIGINAL: "Niðurhala sem .eml skrá" - MENU_FILTER_SIMILAR: "Sía skilaboð eins og þetta" + MENU_DOWNLOAD_ORIGINAL: "Sækja sem .eml skrá" + MENU_FILTER_SIMILAR: "Sía skilaboð eins og þessi" MENU_PRINT: "Prenta" - EMPTY_SUBJECT_TEXT: "(Ekkert viðhengi)" - LABEL_SUBJECT: "Viðhengi" + EMPTY_SUBJECT_TEXT: "(Ekkert viðfangsefni)" + LABEL_SUBJECT: "Viðfangsefni" LABEL_DATE: "Dagsetning" LABEL_FROM: "Frá" LABEL_FROM_SHORT: "frá" @@ -134,22 +134,24 @@ is_IS: LABEL_TO_SHORT: "til" LABEL_CC: "CC" LABEL_BCC: "BCC" - LABEL_REPLY_TO: "Svara á" + LABEL_REPLY_TO: "Svara-til" PRINT_LABEL_FROM: "Frá" PRINT_LABEL_TO: "Til" PRINT_LABEL_CC: "CC" PRINT_LABEL_BCC: "BCC" - PRINT_LABEL_REPLY_TO: "Svara á" + PRINT_LABEL_REPLY_TO: "Svara-til" PRINT_LABEL_DATE: "Dagsetning" - PRINT_LABEL_SUBJECT: "Viðhengi" + PRINT_LABEL_SUBJECT: "Viðfangsefni" PRINT_LABEL_ATTACHMENTS: "Viðhengi" MESSAGE_LOADING: "Hleð" - MESSAGE_VIEW_DESC: "Veldu bréf úr listanum til að skoða hér." + MESSAGE_VIEW_DESC: "Veldu skilaboð úr listanum til að skoða hér." + MESSAGE_VIEW_MOVE_DESC: "Smelltu á heiti möppu á spjaldinu til vinstri til að velja áfangastaðinn." PGP_PASSWORD_INPUT_PLACEHOLDER: "Lykilorð" PGP_SIGNED_MESSAGE_DESC: "Skeyti undirritað með OpenPGP (smelltu til að sannvotta)" PGP_ENCRYPTED_MESSAGE_DESC: "Skeyti dulritað með OpenPGP (smelltu til að afkóða)" LINK_DOWNLOAD_AS_ZIP: "Sækja sem .zip skrá" LINK_SAVE_TO_OWNCLOUD: "Vista í ownCloud" + LINK_SAVE_TO_CLOUD: "Vista í tölvuský" LINK_SAVE_TO_DROPBOX: "Vista í Dropbox" READ_RECEIPT: SUBJECT: "Móttökukvittun (birt) - %SUBJECT%" @@ -206,8 +208,8 @@ is_IS: TITLE_TO: "Til" TITLE_CC: "CC" TITLE_BCC: "BCC" - TITLE_REPLY_TO: "Svara á" - TITLE_SUBJECT: "Viðhengi" + TITLE_REPLY_TO: "Svara-til" + TITLE_SUBJECT: "Viðfangsefni" LINK_SHOW_INPUTS: "sýna alla reiti" BUTTON_SEND: "Senda" BUTTON_SAVE: "Vista" @@ -258,10 +260,11 @@ is_IS: BUTTON_UPDATE_IDENTITY: "Uppfæra" LABEL_EMAIL: "Tölvupóstfang" LABEL_NAME: "Nafn" - LABEL_REPLY_TO: "Svara á" + LABEL_REPLY_TO: "Svara-til" LABEL_SIGNATURE: "Undirskrift" LABEL_CC: "Cc" LABEL_BCC: "Bcc" + LABEL_SIGNATURE_INSERT_BEFORE: "Setja þessa undirskrift inn á undan tilvitnuðum texta þegar verið er að svara" POPUPS_CREATE_FOLDER: TITLE_CREATE_FOLDER: "Búa til möppu?" LABEL_NAME: "Nafn á möppu" @@ -271,12 +274,12 @@ is_IS: BUTTON_CLOSE: "Loka" TITLE_CREATING_PROCESS: "Bý til möppu" POPUPS_CLEAR_FOLDER: - TITLE_CLEAR_FOLDER: "Fjarlægja öll bréf úr þessari möppu?" + TITLE_CLEAR_FOLDER: "Fjarlægja öll skilaboð úr þessari möppu?" BUTTON_CLEAR: "Hreinsa" BUTTON_CANCEL: "Hætta við" BUTTON_CLOSE: "Loka" DANGER_DESC_WARNING: "Aðvörun!" - DANGER_DESC_HTML_1: "Þessi aðgerð veldur því að öll bréf úr %FOLDER% möppunni." + DANGER_DESC_HTML_1: "Þessi aðgerð veldur því að öll skilaboð úr %FOLDER% möppunni verða fjarlægð." DANGER_DESC_HTML_2: "Það er ekki hægt að hætta við aðgerðina eftir að búið er að keyra hana." TITLE_CLEARING_PROCESS: "Tæmi möppu..." POPUPS_IMPORT_OPEN_PGP_KEY: @@ -322,7 +325,7 @@ is_IS: SELECT_ACTION_MOVE_TO: "Færa í" SELECT_ACTION_FORWARD_TO: "Áframsenda til" SELECT_ACTION_REJECT: "Hafna" - SELECT_ACTION_VACATION_MESSAGE: "Skilaboð vegna frís" + SELECT_ACTION_VACATION_MESSAGE: "Skilaboð vegna fría" SELECT_ACTION_DISCARD: "Henda" SELECT_FIELD_FROM: "Frá" SELECT_FIELD_RECIPIENTS: "Viðtakendur (Til eða CC)" @@ -342,6 +345,7 @@ is_IS: SELECT_MATCH_ANY: "Samsvarar EINHVERRI af eftirfarandi reglum" SELECT_MATCH_ALL: "Samsvarar ÖLLUM eftirfarandi reglum" MARK_AS_READ_LABEL: "Merkja sem lesið" + REPLY_INTERVAL_LABEL: "Bil milli svara (dagar)" KEEP_LABEL: "Halda" STOP_LABEL: "Ekki hætta að vinna með reglur" EMAIL_LABEL: "Tölvupóstfang" @@ -358,48 +362,50 @@ is_IS: LABEL_DRAFTS: "Drög" LABEL_SPAM: "Ruslpóstur" LABEL_TRASH: "Ruslafata" - LABEL_ARCHIVE: "Safnskrá" + LABEL_ARCHIVE: "Safn" BUTTON_CANCEL: "Hætta við" BUTTON_CLOSE: "Loka" NOTIFICATION_SENT: | - Þú hefur ekki valið kerfismöppuna "Sent" fyrir bréf eftir sendingu. - Ef þú vilt fjarlægja bréfið endanlega, veldu þá valkostinn "Ekki nota". - NOTIFICATION_DRAFTS: "Þú hefur ekki valið kerfismöppuna \"Drög\" þar sem bréf sem eru vistuð í á meðan þú skrifar." + Þú hefur ekki valið kerfismöppuna "Sent" fyrir skilaboð eftir sendingu. + Ef þú vilt ekki vista send skilaboð, veldu þá valkostinn "Ekki nota". + NOTIFICATION_DRAFTS: "Þú hefur ekki valið kerfismöppuna \"Drög\" þar sem skilaboð sem eru vistuð í á meðan þú skrifar." NOTIFICATION_SPAM: | Þú hefur ekki valið kerfismöppuna "Ruslpóstur" sem ruslsendingar eru settar í. - Ef þú vilt fjarlægja bréfið endanlega, veldu þá valkostinn "Ekki nota". + Ef þú vilt fjarlægja skilaboðin endanlega, veldu þá valkostinn "Ekki nota". NOTIFICATION_TRASH: | - Þú hefur ekki valið kerfismöppuna "Ruslafata" sem eydd bréf eru sett í. - Ef þú vilt fjarlægja bréfið endanlega, veldu þá valkostinn "Ekki nota". - NOTIFICATION_ARCHIVE: "Þú hefur ekki valið kerfismöppuna \"Safnskrá\" undir bréf sem á að geyma til langs tíma." + Þú hefur ekki valið kerfismöppuna "Ruslafata" sem eydd skilaboð eru sett í. + Ef þú vilt fjarlægja skilaboðin endanlega, veldu þá valkostinn "Ekki nota". + NOTIFICATION_ARCHIVE: "Þú hefur ekki valið kerfismöppuna \"Safnskrá\" undir skilaboð sem á að geyma til langs tíma." POPUPS_TWO_FACTOR_CFG: LEGEND_TWO_FACTOR_AUTH: "2-þrepa sannvottun (TOTP)" LABEL_ENABLE_TWO_FACTOR: "Virkja 2-þrepa sannvottun" LABEL_TWO_FACTOR_USER: "Notandi" LABEL_TWO_FACTOR_STATUS: "Staða" - LABEL_TWO_FACTOR_BACKUP_CODES: "Backup codes" - BUTTON_CREATE: "Create New Secret" - BUTTON_ACTIVATE: "Activate" - BUTTON_CLEAR: "Clear" - BUTTON_LOGOUT: "Logout" - BUTTON_DONE: "Done" - BUTTON_TEST: "Test" - LINK_TEST: "test" - BUTTON_SHOW_SECRET: "Show Secret" - BUTTON_HIDE_SECRET: "Hide Secret" - TWO_FACTOR_REQUIRE_DESC: "Your account requires 2-Step verification configuration." - TWO_FACTOR_SECRET_CONFIGURED_DESC: "Configured" - TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Not configured" - TWO_FACTOR_SECRET_DESC: >- - Import this info into your Google Authenticator client (or other TOTP client) - using the provided QR code below or by entering the code manually. - TWO_FACTOR_BACKUP_CODES_DESC: >- - If you can't receive codes via Google Authenticator, you can use backup codes - to sign in. After you’ve used a backup code to sign in, it will become inactive. - TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "You can't change this setting before test." + LABEL_TWO_FACTOR_SECRET: "Leynikóði" + LABEL_TWO_FACTOR_BACKUP_CODES: "Öryggiskóðar" + BUTTON_CREATE: "Búa til leynikóða" + BUTTON_ACTIVATE: "Virkja" + BUTTON_CLEAR: "Hreinsa" + BUTTON_LOGOUT: "Útskráning" + BUTTON_DONE: "Lokið" + BUTTON_TEST: "Prófa" + LINK_TEST: "prófa" + BUTTON_SHOW_SECRET: "Sýna leynikóða" + BUTTON_HIDE_SECRET: "Fela leynikóða" + TWO_FACTOR_REQUIRE_DESC: "Aðgangurinn þinn krefst uppsetningar á 2-þrepa auðkenningu." + TWO_FACTOR_SECRET_CONFIGURED_DESC: "Stillt" + TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Ekki stillt" + TWO_FACTOR_SECRET_DESC: > + Flyttu þessar upplýsingar inn í Google Authenticator forritið (eða annað TOTP-forrit) + með því að nota QR-kóðann hér fyrir neðan eða með því að skrifa kóðann inn. + TWO_FACTOR_BACKUP_CODES_DESC: > + Ef þú getur ekki tekið við kóðum með Google Authenticator forritinu (eða öðru + TOTP-forriti), geturðu notað öryggiskóða til að skrá þig inn. Eftir að þú + hefur notað öryggiskóða til að skrá þig inn, verður hann óvirkur. + TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "Þú getur ekki breytt þessari stillingu fyrir prófun." TITLES: - LOADING: "Hleð" - LOGIN: "Innskrá" + LOADING: "Hleð inn" + LOGIN: "Innskráning" MAILBOX: "Pósthólf" SETTINGS: "Stillingar" COMPOSE: "Semja" @@ -407,103 +413,103 @@ is_IS: ERROR_FILE_IS_TOO_BIG: "Skráin er of stór" ERROR_FILE_PARTIALLY_UPLOADED: "Innsending á skrá heppnaðist ekki vegna óþekktrar villu" ERROR_NO_FILE_UPLOADED: "Engin skrá send inn" - ERROR_MISSING_TEMP_FOLDER: "Tímabundna skráin er ekki til staðar" - ERROR_ON_SAVING_FILE: "Óþekkt innsendingar villa kom upp" - ERROR_FILE_TYPE: "Röng skráar tegund" - ERROR_UNKNOWN: "Óþekkt innsendingar villa kom upp" + ERROR_MISSING_TEMP_FOLDER: "Bráðabirgðaskráin er ekki til staðar" + ERROR_ON_SAVING_FILE: "Óþekkt innsendingarvilla kom upp" + ERROR_FILE_TYPE: "Röng skráartegund" + ERROR_UNKNOWN: "Óþekkt innsendingarvilla kom upp" EDITOR: TEXT_SWITCHER_PLAINT_TEXT: "HTML <-> TEXTI" - TEXT_SWITCHER_RICH_FORMATTING: "Rich forsnið" - TEXT_SWITCHER_CONFIRM: "Texta forsnið og myndir munu týnast. Ertu viss um að þú viljir halda áfram?" + TEXT_SWITCHER_RICH_FORMATTING: "Ríkuleg textasnið" + TEXT_SWITCHER_CONFIRM: "Snið á texta og myndir munu tapast. Ertu viss um að þú viljir halda áfram?" SETTINGS_LABELS: LABEL_PERSONAL_NAME: "Persónulegt" LABEL_GENERAL_NAME: "Almennt" - LABEL_CONTACTS_NAME: "Contacts" + LABEL_CONTACTS_NAME: "Tengiliðir" LABEL_FOLDERS_NAME: "Möppur" LABEL_ACCOUNTS_NAME: "Aðgangar" - LABEL_IDENTITY_NAME: "Identity" - LABEL_IDENTITIES_NAME: "Identities" - LABEL_FILTERS_NAME: "Filters" - LABEL_TEMPLATES_NAME: "Templates" - LABEL_SECURITY_NAME: "Security" - LABEL_SOCIAL_NAME: "Social" - LABEL_THEMES_NAME: "Þemur" + LABEL_IDENTITY_NAME: "Auðkenni" + LABEL_IDENTITIES_NAME: "Auðkenni" + LABEL_FILTERS_NAME: "Síur" + LABEL_TEMPLATES_NAME: "Sniðmát" + LABEL_SECURITY_NAME: "Öryggi" + LABEL_SOCIAL_NAME: "Samfélagsmiðlar" + LABEL_THEMES_NAME: "Þemu" LABEL_CHANGE_PASSWORD_NAME: "Lykilorð" LABEL_OPEN_PGP_NAME: "OpenPGP" BUTTON_BACK: "Til baka" SETTINGS_FILTERS: - LEGEND_FILTERS: "Filters" - BUTTON_SAVE: "Save" - BUTTON_ADD_FILTER: "Add a Filter" - BUTTON_DELETE: "Delete" - BUTTON_RAW_SCRIPT: "Use Custom User Script" - SUBNAME_NONE: "None" - SUBNAME_MOVE_TO: "Move to \"%FOLDER%\"" - SUBNAME_FORWARD_TO: "Forward to \"%EMAIL%\"" - SUBNAME_REJECT: "Reject" - SUBNAME_VACATION_MESSAGE: "Vacation message" - SUBNAME_DISCARD: "Discard" - CAPABILITY_LABEL: "Capability" - LOADING_PROCESS: "Updating filter list" - DELETING_ASK: "Are you sure?" - CHACHES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server." + LEGEND_FILTERS: "Síur" + BUTTON_SAVE: "Vista" + BUTTON_ADD_FILTER: "Bæta við síu" + BUTTON_DELETE: "Eyða" + BUTTON_RAW_SCRIPT: "Nota sérsniðna notandaskriftu" + SUBNAME_NONE: "Ekkert" + SUBNAME_MOVE_TO: "Færa í \"%FOLDER%\"" + SUBNAME_FORWARD_TO: "Áframsenda til \"%EMAIL%\"" + SUBNAME_REJECT: "Hafna" + SUBNAME_VACATION_MESSAGE: "Skilaboð vegna fría" + SUBNAME_DISCARD: "Henda" + CAPABILITY_LABEL: "Geta" + LOADING_PROCESS: "Uppfæri síulista" + DELETING_ASK: "Ertu viss?" + CHACHES_NEED_TO_BE_SAVED_DESC: "Það þarf að vista þessar breytingar á þjóninum." SETTINGS_IDENTITY: - LEGEND_IDENTITY: "Identity" + LEGEND_IDENTITY: "Auðkenni" LABEL_DISPLAY_NAME: "Nafn" - LABEL_REPLY_TO: "Svara" + LABEL_REPLY_TO: "Svara-til" LABEL_SIGNATURE: "Undirskrift" - LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages" + LABEL_ADD_SIGNATURE_TO_ALL: "Bættu undirskrift við öll útsend skilaboð" SETTINGS_SECURITY: - LEGEND_SECURITY: "Security" + LEGEND_SECURITY: "Öryggi" LABEL_CONFIGURE_TWO_FACTOR: "Stilla 2-þrepa sannvottun" - LABEL_AUTOLOGOUT: "Auto Logout" - AUTOLOGIN_NEVER_OPTION_NAME: "Never" - AUTOLOGIN_MINUTES_OPTION_NAME: "%MINUTES% minute(s)" + LABEL_AUTOLOGOUT: "Sjálfvirk útskráning" + AUTOLOGIN_NEVER_OPTION_NAME: "Aldrei" + AUTOLOGIN_MINUTES_OPTION_NAME: "%MINUTES% mínútu(r)" AUTOLOGIN_HOURS_OPTION_NAME: "%HOURS% klukkustund(ir)" SETTINGS_GENERAL: LEGEND_GENERAL: "Almennt" LABEL_LANGUAGE: "Tungumál" - LABEL_IDENTITY: "Identity" - LABEL_LAYOUT: "Layout" - LABEL_LAYOUT_NO_SPLIT: "No Split" - LABEL_LAYOUT_VERTICAL_SPLIT: "Vertical Split" - LABEL_LAYOUT_HORIZONTAL_SPLIT: "Horizontal Split" + LABEL_IDENTITY: "Auðkenni" + LABEL_LAYOUT: "Framsetning" + LABEL_LAYOUT_NO_SPLIT: "Ekki klofið" + LABEL_LAYOUT_VERTICAL_SPLIT: "Klofið lóðrétt" + LABEL_LAYOUT_HORIZONTAL_SPLIT: "Klofið lárétt" LABEL_EDITOR: "Sjálfgefinn textaritill" - LABEL_EDITOR_HTML: "Html" - LABEL_EDITOR_PLAIN: "Venjulegur" - LABEL_EDITOR_HTML_FORCED: "Html (forced)" - LABEL_EDITOR_PLAIN_FORCED: "Plain (forced)" - LABEL_ANIMATION: "Interface animation" + LABEL_EDITOR_HTML: "HTML" + LABEL_EDITOR_PLAIN: "Venjulegt" + LABEL_EDITOR_HTML_FORCED: "HTML (þvingað)" + LABEL_EDITOR_PLAIN_FORCED: "Einfalt (þvingað)" + LABEL_ANIMATION: "Hreyfingar í viðmóti" LABEL_ANIMATION_FULL: "Full" - LABEL_ANIMATION_NORMAL: "Normal" - LABEL_ANIMATION_NONE: "None" - LABEL_VIEW_OPTIONS: "Sýni valmöguleikar" + LABEL_ANIMATION_NORMAL: "Venjulegt" + LABEL_ANIMATION_NONE: "Ekkert" + LABEL_VIEW_OPTIONS: "Valkostir skoðunar" LABEL_USE_PREVIEW_PANE: "Nota forskoðunarham" LABEL_USE_CHECKBOXES_IN_LIST: "Sýna valkassa í listanum" LABEL_USE_THREADS: "Nota þræði" - LABEL_REPLY_SAME_FOLDER: "Setja svör í möppu þar sem bréfið sem er verið að svara" - LABEL_SHOW_IMAGES: "Sýna ávallt myndir í bréfum" + LABEL_REPLY_SAME_FOLDER: "Setja svör í möppu skilaboðanna sem er verið að svara" + LABEL_SHOW_IMAGES: "Sýna ávallt myndir í skilaboðum" LABEL_SHOW_ANIMATION: "Sýna hreyfingar" - LABEL_MESSAGE_PER_PAGE: "Bréf á síðu" + LABEL_MESSAGE_PER_PAGE: "Skilaboð á síðu" LABEL_NOTIFICATIONS: "Tilkynningar" - LABEL_SOUND_NOTIFICATION: "Sound notification" - LABEL_CHROME_NOTIFICATION_DESC: "Sýna tilkynningarglugga fyrir ný bréf" + LABEL_SOUND_NOTIFICATION: "Tilkynningarhljóð" + LABEL_CHROME_NOTIFICATION_DESC: "Sýna tilkynningarglugga fyrir ný skilaboð" LABEL_CHROME_NOTIFICATION_DESC_DENIED: "(Lokað af vafra)" SETTINGS_CONTACTS: - LEGEND_CONTACTS: "Contacts" - LABEL_CONTACTS_AUTOSAVE: "Automatically add recipients to your address book" - LEGEND_CONTACTS_SYNC: "Remote Synchronization (CardDAV)" - LABEL_CONTACTS_SYNC_ENABLE: "Enable remote synchronization" - LABEL_CONTACTS_SYNC_SERVER: "Server" - LABEL_CONTACTS_SYNC_AB_URL: "Addressbook URL" - LABEL_CONTACTS_SYNC_USER: "User" - LABEL_CONTACTS_SYNC_PASSWORD: "Password" + LEGEND_CONTACTS: "Tengiliðir" + LABEL_CONTACTS_AUTOSAVE: "Bæta viðtakendum sjálfkrafa í nafnaskrá" + LEGEND_CONTACTS_SYNC: "Fjartengd samstilling (CardDAV)" + LABEL_CONTACTS_SYNC_ENABLE: "Virkja fjartengda samstillingu" + LABEL_CONTACTS_SYNC_SERVER: "Þjónn" + LABEL_CONTACTS_SYNC_AB_URL: "Slóð á nafnaskrá" + LABEL_CONTACTS_SYNC_USER: "Notandi" + LABEL_CONTACTS_SYNC_PASSWORD: "Lykilorð" SETTINGS_THEMES: - LEGEND_THEMES: "Þemur" - LEGEND_THEMES_CUSTOM: "Sérsniðin þemu stilling" + LEGEND_THEMES: "Þemu" + LEGEND_THEMES_CUSTOM: "Sérsniðin þemastilling" LABEL_CUSTOM_TYPE: "Tegund" - LABEL_CUSTOM_TYPE_LIGHT: "Ljós" - LABEL_CUSTOM_TYPE_DARK: "Dökk" + LABEL_CUSTOM_TYPE_LIGHT: "Ljóst" + LABEL_CUSTOM_TYPE_DARK: "Dökkt" LABEL_CUSTOM_BACKGROUND_IMAGE: "Bakgrunnur" BUTTON_UPLOAD_BACKGROUND_IMAGE: "Senda inn bakgrunnsmynd (JPG, PNG)" ERROR_FILE_IS_TOO_BIG: "Skrá er of stór" @@ -529,141 +535,145 @@ is_IS: BUTTON_DELETE: "Eyða" BUTTON_SUBSCRIBE: "Áskrift" BUTTON_UNSUBSCRIBE: "Afskrá" - LOADING_PROCESS: "Uppfæri möppu lista" + LOADING_PROCESS: "Uppfæri möppulista" CREATING_PROCESS: "Bý til möppu" DELETING_PROCESS: "Eyði möppu" RENAMING_PROCESS: "Endurnefna möppu" DELETING_ASK: "Ertu viss?" - TO_MANY_FOLDERS_DESC_1: "You have too many folders!" - TO_MANY_FOLDERS_DESC_2: "We have shown only a part of them, to avoid performance problems." - HELP_DELETE_FOLDER: "Delete folder" - HELP_SHOW_HIDE_FOLDER: "Show/hide folder" - HELP_CHECK_FOR_NEW_MESSAGES: "Check/don't check for new messages" + TO_MANY_FOLDERS_DESC_1: "Þú ert með allt of margar möppur!" + TO_MANY_FOLDERS_DESC_2: "Við höfum birt aðeins hluta þeirra, til að koma í veg fyrir vandamál með afköst." + HELP_DELETE_FOLDER: "Eyða möppu" + HELP_SHOW_HIDE_FOLDER: "Birta/fela möppu" + HELP_CHECK_FOR_NEW_MESSAGES: "Athuga/ekki athuga með ný skilaboð" SETTINGS_ACCOUNTS: LEGEND_ACCOUNTS: "Aðgangslisti" - LEGEND_IDENTITIES: "Identities" - LEGEND_ACCOUNTS_AND_IDENTITIES: "Accounts and Identities" + LEGEND_IDENTITIES: "Auðkenni" + LEGEND_ACCOUNTS_AND_IDENTITIES: "Aðgangar og auðkenni" BUTTON_ADD_ACCOUNT: "Bæta við aðgangi" - BUTTON_ADD_IDENTITY: "Add an Identity" + BUTTON_ADD_IDENTITY: "Bæta við auðkenni" BUTTON_DELETE: "Eyða" LOADING_PROCESS: "Uppfæri aðgangslista" DELETING_ASK: "Ertu viss?" - DEFAULT_IDENTITY_LABEL: "default" + DEFAULT_IDENTITY_LABEL: "sjálfgefið" SETTINGS_IDENTITIES: - LEGEND_IDENTITY: "Identity" - LEGEND_IDENTITIES: "Additional Identities" - LABEL_DEFAULT: "Default" + LEGEND_IDENTITY: "Auðkenni" + LEGEND_IDENTITIES: "Viðbótarauðkenni" + LABEL_DEFAULT: "Sjálfgefið" LABEL_DISPLAY_NAME: "Nafn" - LABEL_REPLY_TO: "Svara" + LABEL_REPLY_TO: "Svara-til" LABEL_SIGNATURE: "Undirskrift" - LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages" - BUTTON_ADD_IDENTITY: "Add Identity" - BUTTON_DELETE: "Delete" - LOADING_PROCESS: "Updating identity list" - DELETING_ASK: "Are you sure?" + LABEL_ADD_SIGNATURE_TO_ALL: "Bættu undirskrift við öll útsend skilaboð" + BUTTON_ADD_IDENTITY: "Bæta við auðkenni" + BUTTON_DELETE: "Eyða" + LOADING_PROCESS: "Uppfæri auðkennalista" + DELETING_ASK: "Ertu viss?" SETTINGS_CHANGE_PASSWORD: LEGEND_CHANGE_PASSWORD: "Breyta lykilorði" LABEL_CURRENT_PASSWORD: "Núverandi lykilorð" LABEL_NEW_PASSWORD: "Nýtt lykilorð" LABEL_REPEAT_PASSWORD: "Nýtt lykilorð aftur" BUTTON_UPDATE_PASSWORD: "Setja nýtt lykilorð" - ERROR_PASSWORD_MISMATCH: "Passwords do not match, please try again" + ERROR_PASSWORD_MISMATCH: "Lykilorðin stemma ekki, reyndu aftur" SETTINGS_OPEN_PGP: LEGEND_OPEN_PGP: "OpenPGP" - BUTTON_ADD_OPEN_PGP_KEY: "Import OpenPGP Key" - BUTTON_GENERATE_OPEN_PGP_KEYS: "Generate OpenPGP Keys" - TITLE_PRIVATE: "Private" - TITLE_PUBLIC: "Public" - DELETING_ASK: "Are you sure?" - GENERATE_ONLY_HTTPS: "HTTPS only" + BUTTON_ADD_OPEN_PGP_KEY: "Flytja inn OpenPGP-lykil" + BUTTON_GENERATE_OPEN_PGP_KEYS: "Búa til OpenPGP-lykla" + TITLE_PRIVATE: "Einkalykill" + TITLE_PUBLIC: "Dreifilykill" + DELETING_ASK: "Ertu viss?" + GENERATE_ONLY_HTTPS: "Einungis HTTPS" + LABEL_ALLOW_DRAFT_AUTOSAVE: "Vista drög sjálfkrafa" SHORTCUTS_HELP: - LEGEND_SHORTCUTS_HELP: "Keyboard shortcuts help" - TAB_MAILBOX: "Mailbox" - TAB_MESSAGE_LIST: "Message list" - TAB_MESSAGE_VIEW: "Message view" - TAB_COMPOSE: "Compose" - LABEL_OPEN_USER_DROPDOWN: "Open user dropdown" - LABEL_REPLY: "Reply" - LABEL_REPLY_ALL: "Reply All" - LABEL_FORWARD: "Forward" - LABEL_FORWARD_MULTIPLY: "Forward (multiply)" - LABEL_HELP: "Help" - LABEL_CHECK_ALL: "Select all messages" - LABEL_ARCHIVE: "Archive" - LABEL_DELETE: "Delete" - LABEL_OPEN_THREAD: "Open selected thread" - LABEL_MOVE: "Move" - LABEL_READ: "Read selected messages" - LABEL_UNREAD: "Unread selected messages" + LEGEND_SHORTCUTS_HELP: "Hjálp fyrir flýtilykla" + TAB_MAILBOX: "Pósthólf" + TAB_MESSAGE_LIST: "Skilaboðalisti" + TAB_MESSAGE_VIEW: "Skilaboðasýn" + TAB_COMPOSE: "Semja" + LABEL_OPEN_USER_DROPDOWN: "Opna fellilista notenda" + LABEL_REPLY: "Svara" + LABEL_REPLY_ALL: "Svara öllum" + LABEL_FORWARD: "Áframsenda" + LABEL_FORWARD_MULTIPLY: "Áframsenda sem viðhengi" + LABEL_HELP: "Hjálp" + LABEL_CHECK_ALL: "Velja öll skilaboð" + LABEL_ARCHIVE: "Setja í safn" + LABEL_DELETE: "Eyða" + LABEL_OPEN_THREAD: "Opna valinn þráð" + LABEL_MOVE: "Færa" + LABEL_READ: "Lesa valin skilaboð" + LABEL_UNREAD: "Gera valin skilaboð ólesin" LABEL_IMPORTANT: "Mikilvægt, flagga valin skeyti" - LABEL_SEARCH: "Search" - LABEL_CANCEL_SEARCH: "Cancel search" - LABEL_FULLSCREEN_ENTER: "Fullscreen (Preview pane layout)" - LABEL_VIEW_MESSAGE_ENTER: "View message (No preview pane layout)" - LABEL_SWITCH_TO_MESSAGE: "Switch focus to selected message" - LABEL_SWITCH_TO_FOLDER_LIST: "Switch focus to folder list" - LABEL_FULLSCREEN_TOGGLE: "Toggle fullscreen mode" - LABEL_BLOCKQUOTES_TOGGLE: "Toggle message blockquotes" - LABEL_THREAD_NEXT: "Next message in thread" - LABEL_THREAD_PREV: "Previous message in thread" - LABEL_PRINT: "Print" - LABEL_EXIT_FULLSCREEN: "Exit fullscreen mode" - LABEL_CLOSE_MESSAGE: "Close message (No preview pane layout)" - LABEL_SWITCH_TO_LIST: "Switch focus back to message list" - LABEL_OPEN_COMPOSE_POPUP: "Open compose popup" - LABEL_MINIMIZE_COMPOSE_POPUP: "Minimize compose popup" - LABEL_OPEN_IDENTITIES_DROPDOWN: "Open identities dropdown" - LABEL_SAVE_MESSAGE: "Save message" - LABEL_SEND_MESSAGE: "Send message" - LABEL_CLOSE_COMPOSE: "Close compose" + LABEL_SEARCH: "Leita" + LABEL_CANCEL_SEARCH: "Hætta við leit" + LABEL_FULLSCREEN_ENTER: "Á öllum skjánum (með forskoðunarspjaldi)" + LABEL_VIEW_MESSAGE_ENTER: "Skoða skilaboð (ekkert forskoðunarspjald)" + LABEL_SWITCH_TO_MESSAGE: "Skipta virkni á valin skilaboð" + LABEL_SWITCH_TO_FOLDER_LIST: "Skipta virkni á möppulista" + LABEL_FULLSCREEN_TOGGLE: "Víxla heilskjá af/á" + LABEL_BLOCKQUOTES_TOGGLE: "Víxla inndregnum tilvitnunum skilaboða af/á" + LABEL_THREAD_NEXT: "Næstu skilaboð í þræði" + LABEL_THREAD_PREV: "Fyrri skilaboð í þræði" + LABEL_PRINT: "Prenta" + LABEL_EXIT_FULLSCREEN: "Fara úr fullum skjá" + LABEL_CLOSE_MESSAGE: "Loka skilaboðum (ekkert forskoðunarspjald)" + LABEL_SWITCH_TO_LIST: "Skipta virkni til baka í skilaboðalista" + LABEL_OPEN_COMPOSE_POPUP: "Opna riltilglugga" + LABEL_MINIMIZE_COMPOSE_POPUP: "Lágmarka riltilglugga" + LABEL_OPEN_IDENTITIES_DROPDOWN: "Opna fellilista með persónuauðkennum" + LABEL_SAVE_MESSAGE: "Vista skilaboð" + LABEL_SEND_MESSAGE: "Senda skilaboð" + LABEL_CLOSE_COMPOSE: "Loka ritli" PGP_NOTIFICATIONS: - NO_PUBLIC_KEYS_FOUND: "No public keys found" - NO_PUBLIC_KEYS_FOUND_FOR: "No public keys found for \"%EMAIL%\" email" - NO_PRIVATE_KEY_FOUND: "No private key found" - NO_PRIVATE_KEY_FOUND_FOR: "No private key found for \"%EMAIL%\" email" - ADD_A_PUBLICK_KEY: "Add a public key" + NO_PUBLIC_KEYS_FOUND: "Engir dreifilyklar fundust" + NO_PUBLIC_KEYS_FOUND_FOR: "Engir dreifilyklar fundust fyrir \"%EMAIL%\" póstfangið" + NO_PRIVATE_KEY_FOUND: "Enginn einkalykill fannst" + NO_PRIVATE_KEY_FOUND_FOR: "Engir einkalyklar fundust fyrir \"%EMAIL%\" póstfangið" + ADD_A_PUBLICK_KEY: "Bættu við dreifilykli" SELECT_A_PRIVATE_KEY: "Veldu einkalykil" - UNVERIFIRED_SIGNATURE: "Unverified signature" - DECRYPTION_ERROR: "OpenPGP decryption error" - GOOD_SIGNATURE: "Good signature from %USER%" - PGP_ERROR: "OpenPGP error: %ERROR%" - SPECIFY_FROM_EMAIL: "Please specify FROM email address" - SPECIFY_AT_LEAST_ONE_RECIPIENT: "Please specify at least one recipient" + UNVERIFIRED_SIGNATURE: "Óstaðfest undirritun" + DECRYPTION_ERROR: "OpenPGP afkóðunarvilla" + GOOD_SIGNATURE: "Gild undirritun frá %USER%" + PGP_ERROR: "OpenPGP villa: %ERROR%" + SPECIFY_FROM_EMAIL: "Tilgreindu FRÁ tölvupóstfang" + SPECIFY_AT_LEAST_ONE_RECIPIENT: "Tiltaktu að minnsta kosti einn viðtakanda" NOTIFICATIONS: INVALID_TOKEN: "Rangt tákn" AUTH_ERROR: "Auðkenning mistókst" ACCESS_ERROR: "Aðgangsvilla" CONNECTION_ERROR: "Get ekki tengst á netþjón" CAPTCHA_ERROR: "Rangt CAPTCHA." - SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE: >- - Þetta samfélags ID er ekki úthlutað á neitt netfang ennþá. Skráðu þig inn - með netfangs upplýsingum og bættu þessum valmöguleika við í aðgangsstillingum. - SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE: >- - Þetta samfélags ID er ekki úthlutað á neitt netfang ennþá. Skráðu þig inn - með netfangs upplýsingum og bættu þessum valmöguleika við í aðgangsstillingum. - SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE: >- - Þetta samfélags ID er ekki úthlutað á neitt netfang ennþá. Skráðu þig inn - með netfangs upplýsingum og bættu þessum valmöguleika við í aðgangsstillingum. + SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE: > + Þessu samfélagsauðkenni er ekki úthlutað á neitt tölvupóstfang ennþá. Skráðu + þig inn með notandaupplýsingum tölvupóstfangsins og bættu þessum valmöguleika + við í aðgangsstillingum. + SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE: > + Þessu samfélagsauðkenni er ekki úthlutað á neitt tölvupóstfang ennþá. Skráðu + þig inn með notandaupplýsingum tölvupóstfangsins og bættu þessum valmöguleika + við í aðgangsstillingum. + SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE: > + Þessu samfélagsauðkenni er ekki úthlutað á neitt tölvupóstfang ennþá. Skráðu + þig inn með notandaupplýsingum tölvupóstfangsins og bættu þessum valmöguleika + við í aðgangsstillingum. DOMAIN_NOT_ALLOWED: "Lén ekki leyft" - ACCOUNT_NOT_ALLOWED: "Account is not allowed" - ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Two factor verification required" - ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Two factor verification error" - COULD_NOT_SAVE_NEW_PASSWORD: "Could not save new password" - CURRENT_PASSWORD_INCORRECT: "Current password incorrect" - NEW_PASSWORD_SHORT: "Password is too short" - NEW_PASSWORD_WEAK: "Password is too easy" - NEW_PASSWORD_FORBIDDENT: "Password contains forbidden characters" - CONTACTS_SYNC_ERROR: "Contacts synchronization error" - CANT_GET_MESSAGE_LIST: "Get ekki sótt bréfa lista" - CANT_GET_MESSAGE: "Get ekki sótt bréf" - CANT_DELETE_MESSAGE: "Get ekki eytt bréfi" - CANT_MOVE_MESSAGE: "Get ekki fært bréf" - CANT_SAVE_MESSAGE: "Get ekki vistað bréf" - CANT_SEND_MESSAGE: "Get ekki sent bréf" + ACCOUNT_NOT_ALLOWED: "Aðgangur er ekki leyfður" + ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Krafist er 2-þrepa sannvottunar" + ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Villa í 2-þrepa sannvottun" + COULD_NOT_SAVE_NEW_PASSWORD: "Gat ekki vistað nýtt lykilorð" + CURRENT_PASSWORD_INCORRECT: "Núverandi lykilorð er rangt" + NEW_PASSWORD_SHORT: "Lykilorð er of stutt" + NEW_PASSWORD_WEAK: "Lykilorð er of auðvelt" + NEW_PASSWORD_FORBIDDENT: "Lykilorð inniheldur óleyfilega stafi" + CONTACTS_SYNC_ERROR: "Villa í samstillingu tengiliða" + CANT_GET_MESSAGE_LIST: "Get ekki sótt skilaboðlista" + CANT_GET_MESSAGE: "Get ekki sótt skilaboð" + CANT_DELETE_MESSAGE: "Get ekki eytt skilaboðum" + CANT_MOVE_MESSAGE: "Get ekki fært skilaboð" + CANT_SAVE_MESSAGE: "Get ekki vistað skilaboð" + CANT_SEND_MESSAGE: "Get ekki sent skilaboð" INVALID_RECIPIENTS: "Rangir viðtakendur" - CANT_SAVE_FILTERS: "Can't save filters" - CANT_GET_FILTERS: "Can't get filters" - FILTERS_ARE_NOT_CORRECT: "Filters are not correct" + CANT_SAVE_FILTERS: "Get ekki vistað síur" + CANT_GET_FILTERS: "Get ekki sótt síur" + FILTERS_ARE_NOT_CORRECT: "Síur eru ekki réttar" CANT_CREATE_FOLDER: "Get ekki búið til möppu" CANT_RENAME_FOLDER: "Get ekki endurnefnt möppu" CANT_DELETE_FOLDER: "Get ekki eytt möppu" @@ -672,35 +682,35 @@ is_IS: CANT_UNSUBSCRIBE_FOLDER: "Get ekki hætt áskrift á möppu" CANT_SAVE_SETTINGS: "Get ekki vistað stillingar" CANT_SAVE_PLUGIN_SETTINGS: "Get ekki stillingar" - DOMAIN_ALREADY_EXISTS: "Lén tilstaðar núþegar" + DOMAIN_ALREADY_EXISTS: "Lén er nú þegar til staðar" CANT_INSTALL_PACKAGE: "Mistókst að setja inn pakka" CANT_DELETE_PACKAGE: "Mistókst að fjarlægja pakka" - INVALID_PLUGIN_PACKAGE: "Rangur forrita pakki" - UNSUPPORTED_PLUGIN_PACKAGE: "Óstuddur forrita pakki" - LICENSING_SERVER_IS_UNAVAILABLE: "Áskriftar netþjónn er ekki aðgengilegur" - LICENSING_DOMAIN_EXPIRED: "Áskrift furir þetta lén hefur runnið út." + INVALID_PLUGIN_PACKAGE: "Ógildur viðbótapakki" + UNSUPPORTED_PLUGIN_PACKAGE: "Óstuddur viðbótapakki" + LICENSING_SERVER_IS_UNAVAILABLE: "Áskriftarnetþjónn er ekki aðgengilegur" + LICENSING_DOMAIN_EXPIRED: "Áskrift fyrir þetta lén hefur runnið út." LICENSING_DOMAIN_BANNED: "Áskrift fyrir þetta lén er bönnuð." - DEMO_SEND_MESSAGE_ERROR: "Vegna öryggissjónarmiða, þá hefur þessi sýni aðgangur ekki leyfi til að senda bréf á utanaðkomandi netföng!" - DEMO_ACCOUNT_ERROR: "For security purposes, this account is not allowed for this action!" - ACCOUNT_ALREADY_EXISTS: "Aðgangur er til núþegar" + DEMO_SEND_MESSAGE_ERROR: "Vegna öryggissjónarmiða, þá hefur þessi aðgangur ekki leyfi til að senda póst á utanaðkomandi netföng!" + DEMO_ACCOUNT_ERROR: "Vegna öryggissjónarmiða, þá hefur þessi aðgangur ekki heimild fyrir þessa aðgerð!" + ACCOUNT_ALREADY_EXISTS: "Aðgangur er nú þegar til staðar" ACCOUNT_DOES_NOT_EXIST: "Aðgangur er ekki til" - MAIL_SERVER_ERROR: "Villa kom upp við tilraun til að tengjast netþjóni" - INVALID_INPUT_ARGUMENT: "Invalid input argument" + MAIL_SERVER_ERROR: "Villa kom upp við tilraun til að tengjast póstþjóni" + INVALID_INPUT_ARGUMENT: "Óleyfilegt inntaksviðfang" UNKNOWN_ERROR: "Óþekkt villa" STATIC: BACK_LINK: "Endurhlaða" DOMAIN_LIST_DESC: "Listi yfir lén sem vefpóstur má tengjast." - PHP_EXSTENSIONS_ERROR_DESC: "Nauðsynlegar PHP framlenginar eru ekki til staðar í PHP uppsetningunni þinni!" - PHP_VERSION_ERROR_DESC: "PHP útgáfan þín (%VERSION%) er eldri en lágmarks útgáfa sem krafist er (5.3.0)!" + PHP_EXSTENSIONS_ERROR_DESC: "Nauðsynlegir PHP-viðaukar eru ekki til staðar í PHP uppsetningunni þinni!" + PHP_VERSION_ERROR_DESC: "PHP útgáfan þín (%VERSION%) er eldri en lágmarksútgáfan sem krafist er (5.3.0)!" NO_SCRIPT_TITLE: "JavaScript er nauðsynlegt fyrir þetta forrit." NO_SCRIPT_DESC: | - JavaScript stuðningur er ekki til staðar fyrir vafrann þinn. - Vinsamlegast gerðu JavaScript virkt í vafranum þínum og reyndu aftur. - NO_COOKIE_TITLE: "Köku stuðningur er nauðsynlegur fyrir þetta forrit." + JavaScript stuðningur er ekki virkt í vafranum þínum. + Gerðu JavaScript virkt í stillingum vafrans og reyndu aftur. + NO_COOKIE_TITLE: "Stuðningur við vefkökur er nauðsynlegur fyrir þetta forrit." NO_COOKIE_DESC: | - Köku stuðningur er ekki til staðar í vafranum þínum. - Vinsamlegast gerðu JavaScript virkt í vafranum þínum og reyndu aftur. + Stuðningur við vefkökur er ekki til staðar í vafranum þínum. + Gerðu vefkökur virkar í vafranum þínum og reyndu aftur. BAD_BROWSER_TITLE: "Vafrinn þinn er úreltur." BAD_BROWSER_DESC: | - Til að geta notað alla valmöguleika í þessu forriti, - niðurhalaðu og settu upp einn af þessum vöfrum: + Til að geta notað alla eiginleikana í þessu forriti, + náðu í og settu upp einn af þessum vöfrum: diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/it_IT.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/it_IT.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/it_IT.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/it_IT.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ja_JP.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/ja_JP.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ja_JP.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/ja_JP.yml diff --git a/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/ko_KR.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/ko_KR.yml new file mode 100644 index 00000000..1008f6ee --- /dev/null +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/ko_KR.yml @@ -0,0 +1,698 @@ +ko_KR: + LOGIN: + LABEL_EMAIL: "이메일" + LABEL_LOGIN: "아이디" + LABEL_PASSWORD: "비밀번호" + LABEL_SIGN_ME: "아이디 기억" + LABEL_VERIFICATION_CODE: "인증 코드" + LABEL_DONT_ASK_VERIFICATION_CODE: "2주 동안 코드를 물어보지 않기" + BUTTON_SIGN_IN: "로그인" + TITLE_SIGN_IN_GOOGLE: "구글 계정으로 로그인" + TITLE_SIGN_IN_FACEBOOK: "페이스북 계정으로 로그인" + TITLE_SIGN_IN_TWITTER: "트위터 계정으로 로그인" + LABEL_FORGOT_PASSWORD: "비밀번호 분실" + LABEL_REGISTRATION: "가입" + TOP_TOOLBAR: + BUTTON_ADD_ACCOUNT: "계정 추가" + BUTTON_SETTINGS: "설정" + BUTTON_HELP: "도움말" + BUTTON_LOGOUT: "로그아웃" + MOBILE: + BUTTON_MOBILE_VERSION: "모바일 버전" + BUTTON_DESKTOP_VERSION: "데스크탑 버전" + SEARCH: + MAIN_INPUT_PLACEHOLDER: "검색" + TITLE_ADV: "고급 검색" + LABEL_ADV_FROM: "보내는 사람" + LABEL_ADV_TO: "받는 사람" + LABEL_ADV_SUBJECT: "제목" + LABEL_ADV_TEXT: "본문" + LABEL_ADV_HAS_ATTACHMENT: "첨부파일이 있음" + LABEL_ADV_HAS_ATTACHMENTS: "첨부파일이 있음" + LABEL_ADV_FLAGGED: "중요" + LABEL_ADV_UNSEEN: "읽지 않음" + LABEL_ADV_DATE: "날짜" + LABEL_ADV_DATE_ALL: "모두" + LABEL_ADV_DATE_3_DAYS: "3일 이내" + LABEL_ADV_DATE_7_DAYS: "1주일 이내" + LABEL_ADV_DATE_MONTH: "1개월 이내" + LABEL_ADV_DATE_3_MONTHS: "3개월 이내" + LABEL_ADV_DATE_6_MONTHS: "6개월 이내" + LABEL_ADV_DATE_YEAR: "1년 이내" + BUTTON_ADV_SEARCH: "검색" + PREVIEW_POPUP: + FULLSCREEN: "전체화면으로 보기" + ZOOM: "확대/축소" + CLOSE: "닫기 (Esc)" + LOADING: "로딩 중..." + GALLERY_PREV: "이전 (왼쪽 방향키)" + GALLERY_NEXT: "다음 (오른쪽 방향키)" + GALLERY_COUNTER: "%total% 중 %curr%" + IMAGE_ERROR: "이미지를 불러오지 못했습니다." + AJAX_ERROR: "내용을 불러오지 못했습니다." + FOLDER_LIST: + BUTTON_COMPOSE: "메일 쓰기" + BUTTON_CONTACTS: "연락처" + BUTTON_NEW_MESSAGE: "새 메시지" + INBOX_NAME: "받은 편지함" + SENT_NAME: "보낸 편지함" + DRAFTS_NAME: "임시 보관함" + SPAM_NAME: "스팸함" + TRASH_NAME: "휴지통" + ARCHIVE_NAME: "보관함" + QUOTA: + TITLE: "사용량" + MESSAGE_LIST: + BUTTON_RELOAD: "메일 목록 새로고침" + BUTTON_MOVE_TO: "다음 위치로 이동" + BUTTON_DELETE: "삭제" + BUTTON_ARCHIVE: "보관" + BUTTON_SPAM: "스팸" + BUTTON_NOT_SPAM: "스팸 아님" + BUTTON_EMPTY_FOLDER: "폴더 비우기" + BUTTON_MULTY_FORWARD: "첨부파일 형식으로 전달" + BUTTON_DELETE_WITHOUT_MOVE: "영구 삭제" + BUTTON_MORE: "더 보기" + MENU_SET_SEEN: "읽음으로 표시" + MENU_SET_ALL_SEEN: "모두 읽음으로 표시" + MENU_UNSET_SEEN: "읽지 않음으로 표시" + MENU_SET_FLAG: "중요 표시" + MENU_UNSET_FLAG: "중요 표시 해제" + MENU_SELECT_ALL: "모두" + MENU_SELECT_NONE: "없음" + MENU_SELECT_INVERT: "반전" + MENU_SELECT_UNSEEN: "읽지 않음" + MENU_SELECT_SEEN: "읽음" + MENU_SELECT_FLAGGED: "중요" + MENU_SELECT_UNFLAGGED: "일반" + EMPTY_LIST: "목록이 비어있습니다." + EMPTY_SEARCH_LIST: "검색 조건에 맞는 결과가 없습니다.." + SEARCH_RESULT_FOR: "\"%SEARCH%\"에 대한 검색 결과" + BACK_TO_MESSAGE_LIST: "메시지 목록으로 돌아가기" + LIST_LOADING: "로딩 중" + EMPTY_SUBJECT_TEXT: "(제목 없음)" + PUT_MESSAGE_HERE: "목록에 표시할 메시지를 여기로 끌어다 놓으세요." + TODAY_AT: "오늘 %TIME%" + YESTERDAY_AT: "어제 %TIME%" + SEARCH_PLACEHOLDER: "검색" + NEW_MESSAGE_NOTIFICATION: "%COUNT% 개의 새 메시지가 있습니다!" + QUOTA_SIZE: "총 %LIMIT%%PROC%%을(를) 사용 중입니다." + MESSAGE: + BUTTON_EDIT: "편집" + BUTTON_BACK: "뒤로" + BUTTON_CLOSE: "닫기" + BUTTON_DELETE: "삭제" + BUTTON_UNSUBSCRIBE: "이 메일링 리스트를 수신거부" + BUTTON_ARCHIVE: "보관" + BUTTON_SPAM: "스팸" + BUTTON_NOT_SPAM: "스팸 아님" + BUTTON_MOVE_TO: "다음 위치로 이동" + BUTTON_MORE: "더 보기" + BUTTON_REPLY: "회신" + BUTTON_REPLY_ALL: "전체 회신" + BUTTON_FORWARD: "전달" + BUTTON_FORWARD_AS_ATTACHMENT: "첨부파일로 전달" + BUTTON_EDIT_AS_NEW: "새 메시지로 편집" + BUTTON_SHOW_IMAGES: "외부 이미지 표시" + BUTTON_NOTIFY_READ_RECEIPT: "보내는 사람이 메일 확인 알림을 요청했습니다." + BUTTON_IN_NEW_WINDOW: "개별 창에서 보기" + BUTTON_THREAD_LIST: "대화형 목록" + BUTTON_THREAD_PREV: "이전" + BUTTON_THREAD_NEXT: "다음" + BUTTON_THREAD_MORE: "다음 메시지" + MENU_HEADERS: "메시지 헤더 보기" + MENU_VIEW_ORIGINAL: "원본 보기" + MENU_DOWNLOAD_ORIGINAL: ".eml 파일로 다운로드" + MENU_FILTER_SIMILAR: "이런 유형의 메시지에 필터 적용" + MENU_PRINT: "인쇄" + EMPTY_SUBJECT_TEXT: "(제목 없음)" + LABEL_SUBJECT: "제목" + LABEL_DATE: "날짜" + LABEL_FROM: "보내는 사람" + LABEL_FROM_SHORT: "보내는 사람" + LABEL_TO: "받는 사람" + LABEL_TO_SHORT: "받는 사람" + LABEL_CC: "참조" + LABEL_BCC: "숨은 참조" + LABEL_REPLY_TO: "회신 주소" + PRINT_LABEL_FROM: "보내는 사람" + PRINT_LABEL_TO: "받는 사람" + PRINT_LABEL_CC: "참조" + PRINT_LABEL_BCC: "숨은 참조" + PRINT_LABEL_REPLY_TO: "회신 주소" + PRINT_LABEL_DATE: "날짜" + PRINT_LABEL_SUBJECT: "제목" + PRINT_LABEL_ATTACHMENTS: "첨부파일" + MESSAGE_LOADING: "불러오는 중..." + MESSAGE_VIEW_DESC: "목록에서 선택한 메시지가 여기에 표시됩니다." + MESSAGE_VIEW_MOVE_DESC: "왼쪽 패널에서 폴더명을 클릭하여 위치를 선택하세요." + PGP_PASSWORD_INPUT_PLACEHOLDER: "비밀번호" + PGP_SIGNED_MESSAGE_DESC: "OpenPGP로 서명된 메세지입니다. (인증하려면 클릭하세요)" + PGP_ENCRYPTED_MESSAGE_DESC: "OpenPGP로 암호화된 메세지입니다. (복호화하려면 클릭하세요)" + LINK_DOWNLOAD_AS_ZIP: ".zip 파일로 다운로드" + LINK_SAVE_TO_OWNCLOUD: "ownCloud에 저장" + LINK_SAVE_TO_CLOUD: "클라우드에 저장" + LINK_SAVE_TO_DROPBOX: "드롭박스에 저장" + READ_RECEIPT: + SUBJECT: "수신 확인 (표시됨) - %SUBJECT%" + SUGGESTIONS: + SEARCHING_DESC: "검색 중..." + CONTACTS: + LEGEND_CONTACTS: "연락처" + SEARCH_INPUT_PLACEHOLDER: "검색" + BUTTON_ADD_CONTACT: "연락처 추가" + BUTTON_CREATE_CONTACT: "생성" + BUTTON_UPDATE_CONTACT: "업데이트" + BUTTON_IMPORT: "가져오기 (csv, vcf, vCard)" + BUTTON_EXPORT_VCARD: "내보내기 (vcf, vCard)" + BUTTON_EXPORT_CSV: "내보내기 (csv)" + ERROR_IMPORT_FILE: "가져오기 오류 (유효하지 않은 파일 형식)" + LIST_LOADING: "불러오는 중" + EMPTY_LIST: "연락처가 없습니다." + EMPTY_SEARCH: "연락처를 찾지 못했습니다." + CLEAR_SEARCH: "검색 초기화" + CONTACT_VIEW_DESC: "목록에서 연락처를 선택하여 이 곳에 표시하세요." + LABEL_DISPLAY_NAME: "이름 표시" + LABEL_EMAIL: "이메일" + LABEL_PHONE: "전화" + LABEL_WEB: "홈페이지" + LABEL_BIRTHDAY: "생일" + LINK_ADD_EMAIL: "이메일 주소 추가" + LINK_ADD_PHONE: "전화번호 추가" + LINK_BIRTHDAY: "생일" + PLACEHOLDER_ENTER_DISPLAY_NAME: "표시명을 입력하세요" + PLACEHOLDER_ENTER_LAST_NAME: "성을 입력하세요" + PLACEHOLDER_ENTER_FIRST_NAME: "이름을 입력하세요" + PLACEHOLDER_ENTER_NICK_NAME: "별칭을 입력하세요" + LABEL_READ_ONLY: "읽기 전용" + LABEL_SHARE: "공유" + ADD_MENU_LABEL: "추가" + ADD_MENU_NICKNAME: "별칭" + ADD_MENU_NOTES: "메모" + ADD_MENU_EMAIL: "이메일" + ADD_MENU_PHONE: "전화" + ADD_MENU_URL: "URL" + ADD_MENU_ADDRESS: "주소" + ADD_MENU_BIRTHDAY: "생일" + ADD_MENU_TAGS: "태그" + BUTTON_SHARE_NONE: "없음" + BUTTON_SHARE_ALL: "전원" + BUTTON_SYNC: "동기화 (CardDAV)" + COMPOSE: + TITLE_FROM: "보내는 사람" + TITLE_TO: "받는 사람" + TITLE_CC: "참조" + TITLE_BCC: "숨은 참조" + TITLE_REPLY_TO: "회신 주소" + TITLE_SUBJECT: "제목" + LINK_SHOW_INPUTS: "모든 필드 표시" + BUTTON_SEND: "보내기" + BUTTON_SAVE: "저장" + BUTTON_DELETE: "삭제" + BUTTON_CANCEL: "취소" + BUTTON_MINIMIZE: "최소화" + SAVED_TIME: "%TIME% 에 저장됨" + SAVED_ERROR_ON_SEND: "메시지는 전송되었지만, 보낸 편지함에 저장되지 않았습니다." + DISCARD_UNSAVED_DATA: "저장되지 않은 데이터를 삭제하시겠습니까 ?" + ATTACH_FILES: "파일 첨부" + ATTACH_DROP_FILES_DESC: "파일을 끌어 놓으세요" + ATTACH_ITEM_CANCEL: "취소" + DROPBOX: "드롭박스" + GOOGLE_DRIVE: "구글 드라이브" + REPLY_MESSAGE_TITLE: "%DATETIME%에 %EMAIL%이(가) 보낸 메시지" + FORWARD_MESSAGE_TOP_TITLE: "-------- 전달된 메시지 -------" + FORWARD_MESSAGE_TOP_FROM: "보내는 사람" + FORWARD_MESSAGE_TOP_TO: "받는 사람" + FORWARD_MESSAGE_TOP_CC: "참조" + FORWARD_MESSAGE_TOP_SENT: "보냄" + FORWARD_MESSAGE_TOP_SUBJECT: "제목" + EMPTY_TO_ERROR_DESC: "수신인을 한 명 이상 선택하세요" + NO_ATTACHMENTS_HERE_DESC: "첨부된 파일이 없습니다." + ATTACHMENTS_ERROR_DESC: "경고! 모든 첨부파일이 업로드 되지 않습니다." + ATTACHMENTS_UPLOAD_ERROR_DESC: "첨부파일이 아직 업로드되지 않았습니다." + BUTTON_REQUEST_READ_RECEIPT: "수신 확인 요청" + BUTTON_MARK_AS_IMPORTANT: "중요 표시" + BUTTON_OPEN_PGP: "OpenPGP (평문만)" + BUTTON_REQUEST_DSN: "수신 확인 요청" + POPUPS_WELCOME_PAGE: + BUTTON_CLOSE: "닫기" + POPUPS_ASK: + BUTTON_YES: "예" + BUTTON_NO: "아니요" + DESC_WANT_CLOSE_THIS_WINDOW: "정말로 이 페이지를 닫으시겠습니까 ?" + DESC_WANT_DELETE_MESSAGES: "정말로 선택한 메세지를 삭제하시겠습니까 ?" + POPUPS_LANGUAGES: + TITLE_LANGUAGES: "언어 선택" + POPUPS_ADD_ACCOUNT: + TITLE_ADD_ACCOUNT: "계정을 추가할까요?" + BUTTON_ADD_ACCOUNT: "추가" + TITLE_UPDATE_ACCOUNT: "계정을 업데이트할까요?" + BUTTON_UPDATE_ACCOUNT: "업데이트" + POPUPS_IDENTITY: + TITLE_ADD_IDENTITY: "신원을 새로 추가할까요?" + TITLE_UPDATE_IDENTITY: "신원을 업데이트할까요?" + BUTTON_ADD_IDENTITY: "추가" + BUTTON_UPDATE_IDENTITY: "업데이트" + LABEL_EMAIL: "이메일" + LABEL_NAME: "이름" + LABEL_REPLY_TO: "회신 주소" + LABEL_SIGNATURE: "서명" + LABEL_CC: "참조" + LABEL_BCC: "숨은 참조" + LABEL_SIGNATURE_INSERT_BEFORE: "회신 시 이 서명을 인용문 이전에 삽입" + POPUPS_CREATE_FOLDER: + TITLE_CREATE_FOLDER: "폴더를 생성할까요?" + LABEL_NAME: "폴더명" + LABEL_PARENT: "상위 폴더" + BUTTON_CREATE: "생성" + BUTTON_CANCEL: "취소" + BUTTON_CLOSE: "닫기" + TITLE_CREATING_PROCESS: "폴더 생성 중" + POPUPS_CLEAR_FOLDER: + TITLE_CLEAR_FOLDER: "이 폴더의 모든 메시지를 완전 삭제하시겠습니까?" + BUTTON_CLEAR: "초기화" + BUTTON_CANCEL: "취소" + BUTTON_CLOSE: "닫기" + DANGER_DESC_WARNING: "경고!" + DANGER_DESC_HTML_1: "이 동작은 %FOLDER% 폴더의 메시지를 모두 삭제할 것입니다." + DANGER_DESC_HTML_2: "작업이 시작되면 중지하거나 취소할 수 없습니다." + TITLE_CLEARING_PROCESS: "폴더를 비우는 중..." + POPUPS_IMPORT_OPEN_PGP_KEY: + TITLE_IMPORT_OPEN_PGP_KEY: "OpenPGP 키 가져오기" + BUTTON_IMPORT_OPEN_PGP_KEY: "가져오기" + POPUPS_VIEW_OPEN_PGP_KEY: + TITLE_VIEW_OPEN_PGP_KEY: "OpenPGP 키 보기" + BUTTON_SELECT: "선택" + BUTTON_CLOSE: "닫기" + POPUPS_GENERATE_OPEN_PGP_KEYS: + TITLE_GENERATE_OPEN_PGP_KEYS: "OpenPGP 키 생성" + LABEL_EMAIL: "이메일" + LABEL_NAME: "이름" + LABEL_PASSWORD: "비밀번호" + LABEL_KEY_BIT_LENGTH: "키 길이" + BUTTON_GENERATE_OPEN_PGP_KEYS: "생성" + POPUPS_COMPOSE_OPEN_PGP: + TITLE_COMPOSE_OPEN_PGP: "OpenPGP 서명/암호화" + LABEL_SIGN: "로그인" + LABEL_ENCRYPT: "암호화" + LABEL_PASSWORD: "비밀번호" + BUTTON_SIGN: "로그인" + BUTTON_ENCRYPT: "암호화" + BUTTON_SIGN_AND_ENCRYPT: "서명 및 암호화" + POPUPS_MESSAGE_OPEN_PGP: + TITLE_MESSAGE_OPEN_PGP: "OpenPGP 복호화" + LABEL_KEY: "비공개 키" + LABEL_PASSWORD: "비밀번호" + BUTTON_DECRYPT: "복호화" + POPUPS_TWO_FACTOR_TEST: + TITLE_TEST_CODE: "2단계 인증 테스트" + LABEL_CODE: "코드" + BUTTON_TEST: "테스트" + POPUPS_FILTER: + TITLE_CREATE_FILTER: "필터를 생성할까요?" + TITLE_EDIT_FILTER: "필터를 업데이트할까요?" + FILTER_NAME: "이름" + LEGEND_CONDITIONS: "조건" + LEGEND_ACTIONS: "동작" + BUTTON_DONE: "완료" + BUTTON_ADD_CONDITION: "조건 추가" + SELECT_ACTION_NONE: "없음" + SELECT_ACTION_MOVE_TO: "다음 위치로 이동" + SELECT_ACTION_FORWARD_TO: "다음으로 전달" + SELECT_ACTION_REJECT: "거부" + SELECT_ACTION_VACATION_MESSAGE: "부재 중 메시지" + SELECT_ACTION_DISCARD: "Discard" + SELECT_FIELD_FROM: "보내는 사람" + SELECT_FIELD_RECIPIENTS: "수신인 (받는 사람 또는 참조)" + SELECT_FIELD_SUBJECT: "제목" + SELECT_FIELD_HEADER: "헤더" + SELECT_FIELD_SIZE: "크기" + SELECT_TYPE_CONTAINS: "다음을 포함" + SELECT_TYPE_NOT_CONTAINS: "다음을 포함하지 않음" + SELECT_TYPE_MATCHES: "다음과 일치함 (* 및 ? 지원)" + SELECT_TYPE_NOT_MATCHES: "다음과 일치하지 않음 (* 및 ? 지원)" + SELECT_TYPE_REGEXP: "정규 표현식임" + SELECT_TYPE_NOT_REGEXP: "정규 표현식이 아님" + SELECT_TYPE_EQUAL_TO: "다음과 동일함" + SELECT_TYPE_NOT_EQUAL_TO: "다음과 동일하지 않음" + SELECT_TYPE_OVER: "다음을 초과함" + SELECT_TYPE_UNDER: "다음보다 미달임" + SELECT_MATCH_ANY: "Matching any of the following rules" + SELECT_MATCH_ALL: "Matching all of the following rules" + MARK_AS_READ_LABEL: "읽음 표시" + REPLY_INTERVAL_LABEL: "회신 주기 (일)" + KEEP_LABEL: "Keep" + STOP_LABEL: "Don't stop processing rules" + EMAIL_LABEL: "이메일" + VACATION_SUBJECT_LABEL: "제목 (옵션)" + VACATION_MESSAGE_LABEL: "메시지" + VACATION_RECIPIENTS_LABEL: "수신인 (쉼표 분리)" + REJECT_MESSAGE_LABEL: "메시지 거부" + ALL_INCOMING_MESSAGES_DESC: "모든 수신 메시지" + POPUPS_SYSTEM_FOLDERS: + TITLE_SYSTEM_FOLDERS: "시스템 폴더 선택" + SELECT_CHOOSE_ONE: "하나를 선택" + SELECT_UNUSE_NAME: "사용하지 않음" + LABEL_SENT: "보낸 편지함" + LABEL_DRAFTS: "임시 보관함" + LABEL_SPAM: "스팸함" + LABEL_TRASH: "휴지통" + LABEL_ARCHIVE: "보관함" + BUTTON_CANCEL: "취소" + BUTTON_CLOSE: "닫기" + NOTIFICATION_SENT: |- + 보낸 편지함 폴더가 지정되지 않았습니다. 보낸 메시지를 보관하지 않고 삭제하려면 "사용하지 않음" 옵션을 선택해주세요. + NOTIFICATION_DRAFTS: "임시 보관함 폴더가 지정되지 않았습니다." + NOTIFICATION_SPAM: |- + 스팸함 폴더가 지정되지 않았습니다. 스팸처리한 메시지를 보관하지 않고 바로 삭제하려면 "사용하지 않음" 옵션을 선택해주세요. + NOTIFICATION_TRASH: |- + 휴지통 폴더가 지정되지 않았습니다. 삭제한 메시지를 휴지통에 보관하지 않고 바로 삭제하려면 "사용하지 않음" 옵션을 선택해주세요. + NOTIFICATION_ARCHIVE: "보관 메시지가 위치할 \"보관함\" 시스템 폴더를 선택하지 않으셨습니다." + POPUPS_TWO_FACTOR_CFG: + LEGEND_TWO_FACTOR_AUTH: "2단계 인증" + LABEL_ENABLE_TWO_FACTOR: "2단계 인증 활성화" + LABEL_TWO_FACTOR_USER: "사용자" + LABEL_TWO_FACTOR_STATUS: "상태" + LABEL_TWO_FACTOR_SECRET: "비밀번호" + LABEL_TWO_FACTOR_BACKUP_CODES: "백업 코드" + BUTTON_CREATE: "새 비밀번호 생성" + BUTTON_ACTIVATE: "활성화" + BUTTON_CLEAR: "초기화" + BUTTON_LOGOUT: "로그아웃" + BUTTON_DONE: "완료" + BUTTON_TEST: "테스트" + LINK_TEST: "테스트" + BUTTON_SHOW_SECRET: "비밀번호 표시" + BUTTON_HIDE_SECRET: "비밀번호 숨기기" + TWO_FACTOR_REQUIRE_DESC: "귀하의 계정에 2단계 인증 설정이 필요합니다." + TWO_FACTOR_SECRET_CONFIGURED_DESC: "설정됨" + TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "설정되지 않음" + TWO_FACTOR_SECRET_DESC: >- + Import this info into your Google Authenticator client (or other TOTP client) + using the provided QR code below or by entering the code manually. + TWO_FACTOR_BACKUP_CODES_DESC: >- + If you can't receive codes via Google Authenticator, you can use backup codes + to sign in. After you’ve used a backup code to sign in, it will become inactive. + TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "You can't change this setting before test." + TITLES: + LOADING: "로딩 중" + LOGIN: "로그인" + MAILBOX: "메일함" + SETTINGS: "설정" + COMPOSE: "쓰기" + UPLOAD: + ERROR_FILE_IS_TOO_BIG: "파일이 너무 큽니다." + ERROR_FILE_PARTIALLY_UPLOADED: "알 수 없는 오류로 인해 파일이 부분적으로만 업로드 되었습니다." + ERROR_NO_FILE_UPLOADED: "파일이 업로드되지 않았습니다." + ERROR_MISSING_TEMP_FOLDER: "임시 업로드 파일을 찾을 수 없습니다." + ERROR_ON_SAVING_FILE: "알 수 없는 파일 업로드 오류가 발생했습니다." + ERROR_FILE_TYPE: "유효하지 않은 파일 형식" + ERROR_UNKNOWN: "알 수 없는 업로드 오류가 발생했습니다." + EDITOR: + TEXT_SWITCHER_PLAINT_TEXT: "HTML <-> TEXT" + TEXT_SWITCHER_RICH_FORMATTING: "고급 편집" + TEXT_SWITCHER_CONFIRM: "본문 형식과 이미지가 삭제됩니다. 정말 진행하시겠습니까?" + SETTINGS_LABELS: + LABEL_PERSONAL_NAME: "개인" + LABEL_GENERAL_NAME: "일반" + LABEL_CONTACTS_NAME: "연락처" + LABEL_FOLDERS_NAME: "폴더" + LABEL_ACCOUNTS_NAME: "계정" + LABEL_IDENTITY_NAME: "신원" + LABEL_IDENTITIES_NAME: "신원" + LABEL_FILTERS_NAME: "필터" + LABEL_TEMPLATES_NAME: "템플릿" + LABEL_SECURITY_NAME: "보안" + LABEL_SOCIAL_NAME: "소셜" + LABEL_THEMES_NAME: "테마" + LABEL_CHANGE_PASSWORD_NAME: "비밀번호" + LABEL_OPEN_PGP_NAME: "OpenPGP" + BUTTON_BACK: "뒤로" + SETTINGS_FILTERS: + LEGEND_FILTERS: "필터" + BUTTON_SAVE: "저장" + BUTTON_ADD_FILTER: "필터 추가" + BUTTON_DELETE: "삭제" + BUTTON_RAW_SCRIPT: "사용자 지정 스크립트 사용" + SUBNAME_NONE: "없음" + SUBNAME_MOVE_TO: "\"%FOLDER%\"(으)로 이동" + SUBNAME_FORWARD_TO: "\"%EMAIL%\"(으)로 전달" + SUBNAME_REJECT: "거부" + SUBNAME_VACATION_MESSAGE: "부재 중 메시지" + SUBNAME_DISCARD: "Discard" + CAPABILITY_LABEL: "Capability" + LOADING_PROCESS: "필터 목록 업데이트 중" + DELETING_ASK: "정말입니까?" + CHACHES_NEED_TO_BE_SAVED_DESC: "변경사항이 서버에 저장되어야 합니다." + SETTINGS_IDENTITY: + LEGEND_IDENTITY: "신원" + LABEL_DISPLAY_NAME: "이름" + LABEL_REPLY_TO: "회신 주소" + LABEL_SIGNATURE: "서명" + LABEL_ADD_SIGNATURE_TO_ALL: "모든 발신 메시지에 서명을 추가하세요" + SETTINGS_SECURITY: + LEGEND_SECURITY: "보안" + LABEL_CONFIGURE_TWO_FACTOR: "2단계 인증 설정" + LABEL_AUTOLOGOUT: "자동 로그아웃" + AUTOLOGIN_NEVER_OPTION_NAME: "설정하지 않음" + AUTOLOGIN_MINUTES_OPTION_NAME: "%MINUTES%분" + AUTOLOGIN_HOURS_OPTION_NAME: "%HOURS%시간" + SETTINGS_GENERAL: + LEGEND_GENERAL: "일반" + LABEL_LANGUAGE: "언어" + LABEL_IDENTITY: "신원" + LABEL_LAYOUT: "레이아웃" + LABEL_LAYOUT_NO_SPLIT: "분할 해제" + LABEL_LAYOUT_VERTICAL_SPLIT: "세로 분할" + LABEL_LAYOUT_HORIZONTAL_SPLIT: "가로 분할" + LABEL_EDITOR: "기본 텍스트 편집기" + LABEL_EDITOR_HTML: "HTML" + LABEL_EDITOR_PLAIN: "평문" + LABEL_EDITOR_HTML_FORCED: "HTML (강제 적용)" + LABEL_EDITOR_PLAIN_FORCED: "평문 (강제 적용)" + LABEL_ANIMATION: "인터페이스 애니메이션" + LABEL_ANIMATION_FULL: "최대 애니메이션" + LABEL_ANIMATION_NORMAL: "보통 애니메이션" + LABEL_ANIMATION_NONE: "없음" + LABEL_VIEW_OPTIONS: "보기 옵션" + LABEL_USE_PREVIEW_PANE: "미리보기 창 사용" + LABEL_USE_CHECKBOXES_IN_LIST: "목록에서 확인상자 표시" + LABEL_USE_THREADS: "대화형 목록 사용" + LABEL_REPLY_SAME_FOLDER: "회신 메시지를 원본과 동일한 폴더 위치에 저장" + LABEL_SHOW_IMAGES: "메시지 본문에 포함된 외부 이미지를 항상 표시" + LABEL_SHOW_ANIMATION: "애니메이션 표시" + LABEL_MESSAGE_PER_PAGE: "페이지 당 메시지 개수" + LABEL_NOTIFICATIONS: "알림" + LABEL_SOUND_NOTIFICATION: "소리 알림" + LABEL_CHROME_NOTIFICATION_DESC: "새 메시지 알림 팝업 사용" + LABEL_CHROME_NOTIFICATION_DESC_DENIED: "(브라우저에 의해 차단됨)" + SETTINGS_CONTACTS: + LEGEND_CONTACTS: "Contacts" + LABEL_CONTACTS_AUTOSAVE: "수신인을 주소록에 자동으로 추가" + LEGEND_CONTACTS_SYNC: "Remote Synchronization (CardDAV)" + LABEL_CONTACTS_SYNC_ENABLE: "원격 동기화 활성화" + LABEL_CONTACTS_SYNC_SERVER: "서버" + LABEL_CONTACTS_SYNC_AB_URL: "주소록 URL" + LABEL_CONTACTS_SYNC_USER: "사용자" + LABEL_CONTACTS_SYNC_PASSWORD: "비밀번호" + SETTINGS_THEMES: + LEGEND_THEMES: "테마" + LEGEND_THEMES_CUSTOM: "사용자 지정 테마 설정" + LABEL_CUSTOM_TYPE: "유형" + LABEL_CUSTOM_TYPE_LIGHT: "밝음" + LABEL_CUSTOM_TYPE_DARK: "어두움" + LABEL_CUSTOM_BACKGROUND_IMAGE: "배경" + BUTTON_UPLOAD_BACKGROUND_IMAGE: "배경 이미지 업로드 (JPG, PNG)" + ERROR_FILE_IS_TOO_BIG: "파일이 너무 큽니다" + ERROR_FILE_TYPE_ERROR: "유효하지 않은 파일 형식 (JPG 또는 PNG만 가능)" + ERROR_UNKNOWN: "알 수 없는 파일 업로드 오류가 발생했습니다." + SETTINGS_SOCIAL: + LEGEND_GOOGLE: "구글" + BUTTON_GOOGLE_CONNECT: "구글 계정에 연결" + BUTTON_GOOGLE_DISCONNECT: "구글 계정 연결 끊기" + MAIN_GOOGLE_DESC: "구글 계정에 연결을 활성화하면, 로그인 화면에서 구글 로그인 버튼을 통해 이 메일 계정에 로그인 할 수 있습니다." + LEGEND_FACEBOOK: "페이스북" + BUTTON_FACEBOOK_CONNECT: "페이스북 계정에 연결" + BUTTON_FACEBOOK_DISCONNECT: "페이스북 계정 연결 끊기" + MAIN_FACEBOOK_DESC: "페이스북 계정에 연결을 활성화하면, 로그인 화면에서 페이스북 로그인 버튼을 통해 이 메일 계정에 로그인 할 수 있습니다." + LEGEND_TWITTER: "트위터" + BUTTON_TWITTER_CONNECT: "트위터 계정에 연결" + BUTTON_TWITTER_DISCONNECT: "트위터 계정 연결 끊기" + MAIN_TWITTER_DESC: "트위터 계정에 연결을 활성화하면, 로그인 화면에서 트위터 로그인 버튼을 통해 이 메일 계정에 로그인 할 수 있습니다." + SETTINGS_FOLDERS: + LEGEND_FOLDERS: "폴더 목록" + BUTTON_CREATE: "폴더 생성" + BUTTON_SYSTEM: "시스템 폴더" + BUTTON_DELETE: "삭제" + BUTTON_SUBSCRIBE: "구독" + BUTTON_UNSUBSCRIBE: "구독 해제" + LOADING_PROCESS: "폴더 목록 업데이트 중" + CREATING_PROCESS: "폴더 생성 중" + DELETING_PROCESS: "폴더 삭제 중" + RENAMING_PROCESS: "폴더명 변경 중" + DELETING_ASK: "정말입니까?" + TO_MANY_FOLDERS_DESC_1: "폴더가 너무 많습니다!" + TO_MANY_FOLDERS_DESC_2: "We have shown only a part of them, to avoid performance problems." + HELP_DELETE_FOLDER: "폴더 삭제" + HELP_SHOW_HIDE_FOLDER: "폴더 표시/숨기기" + HELP_CHECK_FOR_NEW_MESSAGES: "새 메시지 확인/확인 취소" + SETTINGS_ACCOUNTS: + LEGEND_ACCOUNTS: "계정" + LEGEND_IDENTITIES: "신원" + LEGEND_ACCOUNTS_AND_IDENTITIES: "계정 및 신원" + BUTTON_ADD_ACCOUNT: "계정 추가" + BUTTON_ADD_IDENTITY: "신원 추가" + BUTTON_DELETE: "삭제" + LOADING_PROCESS: "업데이트 중..." + DELETING_ASK: "정말입니까?" + DEFAULT_IDENTITY_LABEL: "default" + SETTINGS_IDENTITIES: + LEGEND_IDENTITY: "신원" + LEGEND_IDENTITIES: "새 신원 추가" + LABEL_DEFAULT: "Default" + LABEL_DISPLAY_NAME: "이름" + LABEL_REPLY_TO: "회신" + LABEL_SIGNATURE: "서명" + LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages" + BUTTON_ADD_IDENTITY: "신원 추가" + BUTTON_DELETE: "삭제" + LOADING_PROCESS: "신원 목록을 업데이트하고 있습니다." + DELETING_ASK: "정말로 삭제하시겠습니까?" + SETTINGS_CHANGE_PASSWORD: + LEGEND_CHANGE_PASSWORD: "비밀번호 변경" + LABEL_CURRENT_PASSWORD: "현재 비밀번호" + LABEL_NEW_PASSWORD: "새 비밀번호" + LABEL_REPEAT_PASSWORD: "비밀번호 재입력" + BUTTON_UPDATE_PASSWORD: "비밀번호 변경" + ERROR_PASSWORD_MISMATCH: "비밀번호가 일치하지 않습니다. 다시 시도해주세요." + SETTINGS_OPEN_PGP: + LEGEND_OPEN_PGP: "OpenPGP" + BUTTON_ADD_OPEN_PGP_KEY: "OpenPGP 키 가져오기" + BUTTON_GENERATE_OPEN_PGP_KEYS: "OpenPGP 키 생성" + TITLE_PRIVATE: "비공개" + TITLE_PUBLIC: "공개" + DELETING_ASK: "정말입니까?" + GENERATE_ONLY_HTTPS: "HTTPS만" + LABEL_ALLOW_DRAFT_AUTOSAVE: "작성 중인 메시지 자동 저장" + SHORTCUTS_HELP: + LEGEND_SHORTCUTS_HELP: "키보드 바로가기 도움말" + TAB_MAILBOX: "메일함" + TAB_MESSAGE_LIST: "메시지 목록" + TAB_MESSAGE_VIEW: "메시지 화면" + TAB_COMPOSE: "쓰기" + LABEL_OPEN_USER_DROPDOWN: "사용자 드롭다운 목록 열기" + LABEL_REPLY: "회신" + LABEL_REPLY_ALL: "전체 회신" + LABEL_FORWARD: "전달" + LABEL_FORWARD_MULTIPLY: "첨부파일로 전달" + LABEL_HELP: "도움말" + LABEL_CHECK_ALL: "전체 메시지 선택" + LABEL_ARCHIVE: "보관" + LABEL_DELETE: "삭제" + LABEL_OPEN_THREAD: "선택한 대화 열기" + LABEL_MOVE: "이동" + LABEL_READ: "선택한 메시지 읽음 표시" + LABEL_UNREAD: "선택한 메시지 읽지 않음 표시" + LABEL_IMPORTANT: "선택한 메시지 중요 표시" + LABEL_SEARCH: "검색" + LABEL_CANCEL_SEARCH: "검색 취소" + LABEL_FULLSCREEN_ENTER: "전체화면 (미리보기 화면 레이아웃)" + LABEL_VIEW_MESSAGE_ENTER: "메시지 보기 (미리보기 화면 레이아웃 없음)" + LABEL_SWITCH_TO_MESSAGE: "선택한 메시지로 촛점 전환" + LABEL_SWITCH_TO_FOLDER_LIST: "폴더 목록으로 촛점 전환" + LABEL_FULLSCREEN_TOGGLE: "전체화면 모드 전환" + LABEL_BLOCKQUOTES_TOGGLE: "메시지 인용구 전환" + LABEL_THREAD_NEXT: "대화에서 다음 메시지" + LABEL_THREAD_PREV: "대화에서 이전 메시지" + LABEL_PRINT: "인쇄" + LABEL_EXIT_FULLSCREEN: "전체화면 모드 나가기" + LABEL_CLOSE_MESSAGE: "메시지 닫기 (미리보기 화면 레이아웃 없음)" + LABEL_SWITCH_TO_LIST: "메시지 목록으로 촛점 전환" + LABEL_OPEN_COMPOSE_POPUP: "쓰기 팝업 창 열기" + LABEL_MINIMIZE_COMPOSE_POPUP: "쓰기 팝업 창 최소화" + LABEL_OPEN_IDENTITIES_DROPDOWN: "신원 드롭다운 목록 열기" + LABEL_SAVE_MESSAGE: "메시지 저장" + LABEL_SEND_MESSAGE: "메시지 보내기" + LABEL_CLOSE_COMPOSE: "쓰기 창 닫기" + PGP_NOTIFICATIONS: + NO_PUBLIC_KEYS_FOUND: "공개 키를 찾지 못했습니다" + NO_PUBLIC_KEYS_FOUND_FOR: "\"%EMAIL%\" 이메일에 대한 공개 키를 찾지 못했습니다" + NO_PRIVATE_KEY_FOUND: "비공개 키를 찾지 못했습니다" + NO_PRIVATE_KEY_FOUND_FOR: "\"%EMAIL%\" 이메일에 대한 비공개 키를 찾지 못했습니다" + ADD_A_PUBLICK_KEY: "공개 키 추가" + SELECT_A_PRIVATE_KEY: "비밀 키 선택" + UNVERIFIRED_SIGNATURE: "미인증 서명" + DECRYPTION_ERROR: "OpenPGP 복호화 오류" + GOOD_SIGNATURE: "%USER%(으)로부터 수신한 양호한 서명" + PGP_ERROR: "OpenPGP 오류: %ERROR%" + SPECIFY_FROM_EMAIL: "보내는 사람 이메일 주소를 지정해주세요" + SPECIFY_AT_LEAST_ONE_RECIPIENT: "최소 하나의 수신인을 지정해주세요" + NOTIFICATIONS: + INVALID_TOKEN: "잘못된 토큰입니다." + AUTH_ERROR: "인증에 실패했습니다" + ACCESS_ERROR: "접근 오류" + CONNECTION_ERROR: "서버에 연결할 수 없습니다." + CAPTCHA_ERROR: "보안문자를 잘못 입력하였습니다." + SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE: >- + 이 페이스북 아이디는 아직 어떠한 이메일 계정에도 연결되지 않았습니다. 이메일 계정으로 로그인 하신 후 소셜 설정에서 소셜 계정에 연결해주세요. + SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE: >- + 이 트위터 아이디는 아직 어떠한 이메일 계정에도 연결되지 않았습니다. 이메일 계정으로 로그인 하신 후 소셜 설정에서 소셜 계정에 연결해주세요. + SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE: >- + 이 구글 아이디는 아직 어떠한 이메일 계정에도 연결되지 않았습니다. 이메일 계정으로 로그인 하신 후 소셜 설정에서 소셜 계정에 연결해주세요. + DOMAIN_NOT_ALLOWED: "허용된 도메인이 아닙니다." + ACCOUNT_NOT_ALLOWED: "허용된 계정이 아닙니다." + ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "2단계 인증이 필요합니다" + ACCOUNT_TWO_FACTOR_AUTH_ERROR: "2단계 인증 오류" + COULD_NOT_SAVE_NEW_PASSWORD: "새 비밀번호를 저장하지 못했습니다" + CURRENT_PASSWORD_INCORRECT: "현재 비밀번호가 틀립니다" + NEW_PASSWORD_SHORT: "비밀번호가 너무 짧습니다" + NEW_PASSWORD_WEAK: "비밀번호가 보안에 취약합니다" + NEW_PASSWORD_FORBIDDENT: "비밀번호에 금지된 문자가 포함되어 있습니다" + CONTACTS_SYNC_ERROR: "연락처 동기화 오류" + CANT_GET_MESSAGE_LIST: "메시지 목록을 불러 올 수 없습니다." + CANT_GET_MESSAGE: "메시지를 가져올 수 없습니다." + CANT_DELETE_MESSAGE: "메시지를 삭제할 수 없습니다." + CANT_MOVE_MESSAGE: "메시지를 이동할 수 없습니다." + CANT_SAVE_MESSAGE: "메시지를 저장할 수 없습니다." + CANT_SEND_MESSAGE: "메시지를 보낼 수 없습니다." + INVALID_RECIPIENTS: "유효하지 않은 수신인" + CANT_SAVE_FILTERS: "필터를 저장할 수 없습니다" + CANT_GET_FILTERS: "필터를 가져올 수 없습니다" + FILTERS_ARE_NOT_CORRECT: "필터가 올바르지 않습니다" + CANT_CREATE_FOLDER: "폴더를 생성할 수 없습니다." + CANT_RENAME_FOLDER: "폴더명을 변경할 수 없습니다." + CANT_DELETE_FOLDER: "폴더를 삭제할 수 없습니다." + CANT_DELETE_NON_EMPTY_FOLDER: "비어있지 않은 디렉터리를 삭제할 수 없습니다." + CANT_SUBSCRIBE_FOLDER: "폴더를 볼 수 없습니다." + CANT_UNSUBSCRIBE_FOLDER: "폴더를 보이지 않게 할 수 없습니다." + CANT_SAVE_SETTINGS: "설정을 저장할 수 없습니다." + CANT_SAVE_PLUGIN_SETTINGS: "설정을 저장할 수 없습니다." + DOMAIN_ALREADY_EXISTS: "이미 존재하는 도메인입니다." + CANT_INSTALL_PACKAGE: "패키지 설치에 실패했습니다." + CANT_DELETE_PACKAGE: "패키지 제거에 실패했습니다." + INVALID_PLUGIN_PACKAGE: "정상적인 플러그인 패키지가 아닙니다." + UNSUPPORTED_PLUGIN_PACKAGE: "미지원 플러그인 패키지" + LICENSING_SERVER_IS_UNAVAILABLE: "구독 서버를 사용할 수 없습니다." + LICENSING_DOMAIN_EXPIRED: "이 도메인의 구독이 만료되었습니다." + LICENSING_DOMAIN_BANNED: "이 도메인의 구독이 금지되었습니다." + DEMO_SEND_MESSAGE_ERROR: "이 테스트 계정은 외부 메일 발송이 금지되어있습니다." + DEMO_ACCOUNT_ERROR: "보안을 사유로 이 계정에서는 해당 동작이 허용되지 않습니다." + ACCOUNT_ALREADY_EXISTS: "이미 존재하는 계정입니다." + ACCOUNT_DOES_NOT_EXIST: "존재하지 않는 계정입니다" + MAIL_SERVER_ERROR: "메일 서버에 연결하는 도중 오류가 발생했습니다." + INVALID_INPUT_ARGUMENT: "유효하지 않은 input argument" + UNKNOWN_ERROR: "알 수 없는 오류" + STATIC: + BACK_LINK: "새로고침" + DOMAIN_LIST_DESC: "접근이 허가된 도메인 목록입니다." + PHP_EXSTENSIONS_ERROR_DESC: "필요한 PHP 확장이 구성되지 않았습니다!" + PHP_VERSION_ERROR_DESC: "현재 사용 중인 PHP 버전 (%VERSION%)이 너무 낮습니다. 최소 5.3.0 이상을 설치해주세요!" + NO_SCRIPT_TITLE: "이 어플리케이션에는 자바스크립트가 필요합니다" + NO_SCRIPT_DESC: |- + 사용 중인 브라우저가 자바스크립트를 지원하지 않습니다. 브라우저 설정을 확인하여 자바스크립트 사용을 활성화하고 다시 시도해주세요. + NO_COOKIE_TITLE: "이 어플리케이션을 사용하려면 쿠키 사용이 지원되야 합니다." + NO_COOKIE_DESC: |- + 사용 중인 브라우저가 쿠키를 지원하지 않습니다. 브라우저 설정을 확인하여 쿠키 사용을 활성화하고 다시 시도해주세요. + BAD_BROWSER_TITLE: "사용 중인 브라우저가 구버전입니다." + BAD_BROWSER_DESC: |- + 이 어플리케이션을 정상적으로 사용하시려면 아래의 브라우저들 중 하나를 설치해주세요: diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/lt_LT.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/lt_LT.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/lt_LT.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/lt_LT.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/lv_LV.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/lv_LV.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/lv_LV.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/lv_LV.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/nb_NO.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/nb_NO.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/nb_NO.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/nb_NO.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/nl_NL.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/nl_NL.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/nl_NL.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/nl_NL.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pl_PL.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/pl_PL.yml similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pl_PL.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/pl_PL.yml index 0592e8ef..b82e1044 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pl_PL.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/pl_PL.yml @@ -10,7 +10,7 @@ pl_PL: TITLE_SIGN_IN_GOOGLE: "Zaloguj się przez Google" TITLE_SIGN_IN_FACEBOOK: "Zaloguj się przez Facebook" TITLE_SIGN_IN_TWITTER: "Zaloguj się przez Twitter" - LABEL_FORGOT_PASSWORD: "Zapomniałem(-am) hasło" + LABEL_FORGOT_PASSWORD: "Zapomniane hasło" LABEL_REGISTRATION: "Rejestracja" TOP_TOOLBAR: BUTTON_ADD_ACCOUNT: "Dodaj konto" @@ -89,20 +89,20 @@ pl_PL: EMPTY_SEARCH_LIST: "Brak wiadomości spełniających kryteria wyszukiwania." SEARCH_RESULT_FOR: "Wyniki wyszukiwania dla \"%SEARCH%\"" BACK_TO_MESSAGE_LIST: "powrót do listy wiadomości" - LIST_LOADING: "Ładowanie..." + LIST_LOADING: "Ładowanie" EMPTY_SUBJECT_TEXT: "(Brak tematu)" - PUT_MESSAGE_HERE: "Przeciągnij wiadomość tutaj, żeby zobaczyć ją na liście" + PUT_MESSAGE_HERE: "Upuść wiadomość tutaj, aby zobaczyć ją na liście" TODAY_AT: "dzisiaj o %TIME%" YESTERDAY_AT: "wczoraj o %TIME%" SEARCH_PLACEHOLDER: "Szukaj" - NEW_MESSAGE_NOTIFICATION: "Masz: %COUNT% now(-ą,-e,-ych) wiadomości!" + NEW_MESSAGE_NOTIFICATION: "Masz %COUNT% now(-ą,-e,-ych) wiadomość(-ci)!" QUOTA_SIZE: "Wykorzystano %SIZE% (%PROC%%) z %LIMIT%" MESSAGE: BUTTON_EDIT: "Edytuj" BUTTON_BACK: "Wstecz" BUTTON_CLOSE: "Zamknij" BUTTON_DELETE: "Usuń" - BUTTON_UNSUBSCRIBE: "Zrezygnuj z subskrypcji" + BUTTON_UNSUBSCRIBE: "Zrezygnuj z subskrypcji tej listy" BUTTON_ARCHIVE: "Archiwizuj" BUTTON_SPAM: "Oznacz jako niechcianą" BUTTON_NOT_SPAM: "Oznacz jako pożądaną" @@ -165,7 +165,7 @@ pl_PL: CONTACTS: LEGEND_CONTACTS: "Kontakty" SEARCH_INPUT_PLACEHOLDER: "Szukaj" - BUTTON_ADD_CONTACT: "Dodaj Kontakt" + BUTTON_ADD_CONTACT: "Dodaj kontakt" BUTTON_CREATE_CONTACT: "Utwórz" BUTTON_UPDATE_CONTACT: "Zaktualizuj" BUTTON_IMPORT: "Importuj (csv, vcf, vCard)" @@ -224,7 +224,7 @@ pl_PL: ATTACH_ITEM_CANCEL: "Anuluj" DROPBOX: "Dropbox" GOOGLE_DRIVE: "Dysk Google" - REPLY_MESSAGE_TITLE: "%DATETIME%, %EMAIL%" + REPLY_MESSAGE_TITLE: "%DATETIME%, %EMAIL% napisał/-a/" FORWARD_MESSAGE_TOP_TITLE: "-------- Wiadomość przekazana -------" FORWARD_MESSAGE_TOP_FROM: "Od" FORWARD_MESSAGE_TOP_TO: "Do" @@ -235,7 +235,7 @@ pl_PL: NO_ATTACHMENTS_HERE_DESC: "Brak załączników." ATTACHMENTS_ERROR_DESC: "Ostrzeżenie! Nie wszystkie załączniki zostały przesłane na serwer." ATTACHMENTS_UPLOAD_ERROR_DESC: "Jeszcze nie wszystkie załączniki zostały przesłane na serwer." - BUTTON_REQUEST_READ_RECEIPT: "Żądaj potwierdzenia wyświetlenia wiadomości" + BUTTON_REQUEST_READ_RECEIPT: "Żądaj potwierdzenia przeczytania wiadomości" BUTTON_MARK_AS_IMPORTANT: "Oznacz jako ważną" BUTTON_OPEN_PGP: "OpenPGP (tylko wiadomości tekstowe)" BUTTON_REQUEST_DSN: "Żądaj potwierdzenia dostarczenia wiadomości" @@ -244,8 +244,8 @@ pl_PL: POPUPS_ASK: BUTTON_YES: "Tak" BUTTON_NO: "Nie" - DESC_WANT_CLOSE_THIS_WINDOW: "Na pewno zamknąć to okno?" - DESC_WANT_DELETE_MESSAGES: "Na pewno usunąć wiadomość(-ci)?" + DESC_WANT_CLOSE_THIS_WINDOW: "Na pewno chcesz zamknąć to okno?" + DESC_WANT_DELETE_MESSAGES: "Na pewno chcesz usunąć wiadomość(-ci)?" POPUPS_LANGUAGES: TITLE_LANGUAGES: "Wybierz język" POPUPS_ADD_ACCOUNT: @@ -275,7 +275,7 @@ pl_PL: TITLE_CREATING_PROCESS: "Tworzenie folderu" POPUPS_CLEAR_FOLDER: TITLE_CLEAR_FOLDER: "Czy usunąć wszystkie wiadomości z folderu?" - BUTTON_CLEAR: "Usuń wszystkie" + BUTTON_CLEAR: "Wyczyść" BUTTON_CANCEL: "Anuluj" BUTTON_CLOSE: "Zamknij" DANGER_DESC_WARNING: "Ostrzeżenie!" @@ -338,8 +338,8 @@ pl_PL: SELECT_TYPE_NOT_MATCHES: "nie zawiera (*, ?)" SELECT_TYPE_REGEXP: "Wyrażenie regularne" SELECT_TYPE_NOT_REGEXP: "Niepoprawne wyrażenie regularne" - SELECT_TYPE_EQUAL_TO: "równy" - SELECT_TYPE_NOT_EQUAL_TO: "nierówny" + SELECT_TYPE_EQUAL_TO: "Równa się" + SELECT_TYPE_NOT_EQUAL_TO: "Nie równa się" SELECT_TYPE_OVER: "powyżej" SELECT_TYPE_UNDER: "poniżej" SELECT_MATCH_ANY: "Spełnia dowolny z warunków" @@ -357,7 +357,7 @@ pl_PL: POPUPS_SYSTEM_FOLDERS: TITLE_SYSTEM_FOLDERS: "Wybierz foldery systemowe" SELECT_CHOOSE_ONE: "Wybierz" - SELECT_UNUSE_NAME: "nie używaj" + SELECT_UNUSE_NAME: "Nie używaj" LABEL_SENT: "Wysłane" LABEL_DRAFTS: "Szkice" LABEL_SPAM: "Spam" @@ -383,15 +383,15 @@ pl_PL: LABEL_TWO_FACTOR_STATUS: "Status" LABEL_TWO_FACTOR_SECRET: "Tajna fraza" LABEL_TWO_FACTOR_BACKUP_CODES: "Kody zapasowe" - BUTTON_CREATE: "Utwórz nową frazę" + BUTTON_CREATE: "Utwórz sekretną frazę" BUTTON_ACTIVATE: "Aktywuj" BUTTON_CLEAR: "Wyczyść" BUTTON_LOGOUT: "Wyloguj" BUTTON_DONE: "Zamknij" BUTTON_TEST: "Testuj" LINK_TEST: "test" - BUTTON_SHOW_SECRET: "Pokaż frazę" - BUTTON_HIDE_SECRET: "Ukryj frazę" + BUTTON_SHOW_SECRET: "Pokaż sekretną frazę" + BUTTON_HIDE_SECRET: "Ukryj sekretną frazę" TWO_FACTOR_REQUIRE_DESC: "Twoje konto wymaga skonfigurowania autoryzacji 2-etapowej." TWO_FACTOR_SECRET_CONFIGURED_DESC: "Skonfigurowano" TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Nie skonfigurowano" @@ -419,7 +419,7 @@ pl_PL: EDITOR: TEXT_SWITCHER_PLAINT_TEXT: "HTML <-> zwykły tekst" TEXT_SWITCHER_RICH_FORMATTING: "Wzbogacony format tekstowy" - TEXT_SWITCHER_CONFIRM: "Formatowanie tekstu oraz wszystkie wstawione obrazy zostaną utracone. Czy na pewno chcesz kontynuować?" + TEXT_SWITCHER_CONFIRM: "Formatowanie tekstu oraz wstawione obrazy zostaną utracone. Czy na pewno chcesz kontynuować?" SETTINGS_LABELS: LABEL_PERSONAL_NAME: "Osobiste" LABEL_GENERAL_NAME: "Ogólne" @@ -450,7 +450,7 @@ pl_PL: SUBNAME_DISCARD: "Porzuć" CAPABILITY_LABEL: "Możliwości" LOADING_PROCESS: "Aktualizowanie listy filtrów" - DELETING_ASK: "Czy jesteś pewny(a)?" + DELETING_ASK: "Jesteś pewien/pewna?" CHACHES_NEED_TO_BE_SAVED_DESC: "Zmiany te muszą zostać zapisane na serwerze." SETTINGS_IDENTITY: LEGEND_IDENTITY: "Tożsamość" @@ -538,7 +538,7 @@ pl_PL: CREATING_PROCESS: "Tworzenie folderu" DELETING_PROCESS: "Usuwanie folderu" RENAMING_PROCESS: "Zmiana nazwy folderu" - DELETING_ASK: "Czy na pewno usunąć?" + DELETING_ASK: "Jesteś pewien/pewna?" TO_MANY_FOLDERS_DESC_1: "Masz za dużo folderów!" TO_MANY_FOLDERS_DESC_2: "Pokazaliśmy tylko część z nich aby uniknąć problemów z wydajnością." HELP_DELETE_FOLDER: "Usuń folder" @@ -552,7 +552,7 @@ pl_PL: BUTTON_ADD_IDENTITY: "Dodaj tożsamość" BUTTON_DELETE: "Usuń" LOADING_PROCESS: "Trwa aktualizowanie listy kont" - DELETING_ASK: "Czy na pewno usunąć?" + DELETING_ASK: "Jesteś pewien/pewna?" DEFAULT_IDENTITY_LABEL: "domyślna" SETTINGS_IDENTITIES: LEGEND_IDENTITY: "Tożsamość" @@ -565,7 +565,7 @@ pl_PL: BUTTON_ADD_IDENTITY: "Dodaj tożsamość" BUTTON_DELETE: "Usuń" LOADING_PROCESS: "Trwa aktualizowanie listy tożsamości" - DELETING_ASK: "Czy na pewno chcesz usunąć?" + DELETING_ASK: "Jesteś pewien/pewna?" SETTINGS_CHANGE_PASSWORD: LEGEND_CHANGE_PASSWORD: "Zmiana hasła" LABEL_CURRENT_PASSWORD: "Aktualne hasło" @@ -579,7 +579,7 @@ pl_PL: BUTTON_GENERATE_OPEN_PGP_KEYS: "Generuj klucz OpenPGP" TITLE_PRIVATE: "Prywatny" TITLE_PUBLIC: "Publiczny" - DELETING_ASK: "Czy na pewno chcesz usunąć?" + DELETING_ASK: "Jesteś pewien/pewna?" GENERATE_ONLY_HTTPS: "Tylko HTTPS" LABEL_ALLOW_DRAFT_AUTOSAVE: "Automatycznie zapisuj szkic" SHORTCUTS_HELP: @@ -642,22 +642,22 @@ pl_PL: CONNECTION_ERROR: "Błąd połączenia z serwerem" CAPTCHA_ERROR: "Nieprawidłowy kod CAPTCHA." SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE: > - Ten identyfikator społecznościowy (Facebook) nie jest powiązany z żadnym kontem + Ten identyfikator społecznościowy Facebook nie jest powiązany z żadnym kontem pocztowym. Zaloguj się używając danych swojego konta e-mail i skonfiguruj tę opcję w: Ustawienia > Sieci społecznościowe. SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE: > - Ten identyfikator społecznościowy (Twitter) nie jest powiązany z żadnym kontem + Ten identyfikator społecznościowy Twitter nie jest powiązany z żadnym kontem pocztowym. Zaloguj się używając danych swojego konta e-mail i skonfiguruj tę opcję w: Ustawienia > Sieci społecznościowe. SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE: > - Ten identyfikator społecznościowy (Konto Google) nie jest powiązany z żadnym + Ten identyfikator społecznościowy Konto Google nie jest powiązany z żadnym kontem pocztowym. Zaloguj się używając danych swojego konta e-mail i skonfiguruj tę opcję w: Ustawienia > Sieci społecznościowe. - DOMAIN_NOT_ALLOWED: "Domena niedozwolona" + DOMAIN_NOT_ALLOWED: "Domena jest niedozwolona" ACCOUNT_NOT_ALLOWED: "Konto nie jest dozwolone" ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Wymagana autoryzacja dwuetapowa" ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Błąd autoryzacji dwuetapowej" - COULD_NOT_SAVE_NEW_PASSWORD: "Nie można było zapisać nowego hasła" + COULD_NOT_SAVE_NEW_PASSWORD: "Nie można zapisać nowego hasła" CURRENT_PASSWORD_INCORRECT: "Obecne hasło jest niepoprawne" NEW_PASSWORD_SHORT: "Hasło jest za krótkie" NEW_PASSWORD_WEAK: "Hasło jest zbyt łatwe" diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pt_BR.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/pt_BR.yml similarity index 99% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pt_BR.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/pt_BR.yml index 0b1e144c..e1f2ebea 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pt_BR.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/pt_BR.yml @@ -151,6 +151,7 @@ pt_BR: PGP_ENCRYPTED_MESSAGE_DESC: "Mensagem criptografada com OpenPGP (clique para descriptografar)" LINK_DOWNLOAD_AS_ZIP: "Baixar como zip" LINK_SAVE_TO_OWNCLOUD: "Salvar no ownCloud" + LINK_SAVE_TO_CLOUD: "Salvar para a nuvem" LINK_SAVE_TO_DROPBOX: "Salvar no Dropbox" READ_RECEIPT: SUBJECT: "Aviso de recepção (Visualizada) - %SUBJECT%" @@ -581,6 +582,7 @@ pt_BR: TITLE_PUBLIC: "Público" DELETING_ASK: "Você tem certeza?" GENERATE_ONLY_HTTPS: "HTTPS only" + LABEL_ALLOW_DRAFT_AUTOSAVE: "Salvar automaticamente rascunho" SHORTCUTS_HELP: LEGEND_SHORTCUTS_HELP: "Ajuda com os atalhos de teclado" TAB_MAILBOX: "Caixa de correio" diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pt_PT.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/pt_PT.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pt_PT.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/pt_PT.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ro_RO.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/ro_RO.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ro_RO.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/ro_RO.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ru_RU.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/ru_RU.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ru_RU.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/ru_RU.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sk_SK.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/sk_SK.yml similarity index 81% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sk_SK.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/sk_SK.yml index d58f7f2d..0fc09a9e 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sk_SK.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/sk_SK.yml @@ -5,13 +5,13 @@ sk_SK: LABEL_PASSWORD: "Heslo" LABEL_SIGN_ME: "Zapamätať" LABEL_VERIFICATION_CODE: "Verifikačný kód" - LABEL_DONT_ASK_VERIFICATION_CODE: "Don't ask for the code for 2 weeks" - BUTTON_SIGN_IN: "Prihlásiť" - TITLE_SIGN_IN_GOOGLE: "Prihlásiť pomocu Google" - TITLE_SIGN_IN_FACEBOOK: "Prihlásiť pomocou Facebook" - TITLE_SIGN_IN_TWITTER: "Prihlásiť pomocou Twitter" - LABEL_FORGOT_PASSWORD: "Forgot password" - LABEL_REGISTRATION: "Registration" + LABEL_DONT_ASK_VERIFICATION_CODE: "Nevyžadovať kód 2 týždne" + BUTTON_SIGN_IN: "Prihlásiť sa" + TITLE_SIGN_IN_GOOGLE: "Prihlásiť sa pomocu Google" + TITLE_SIGN_IN_FACEBOOK: "Prihlásiť sa pomocou Facebook" + TITLE_SIGN_IN_TWITTER: "Prihlásiť sa pomocou Twitter" + LABEL_FORGOT_PASSWORD: "Zabudol som heslo" + LABEL_REGISTRATION: "Registrácia" TOP_TOOLBAR: BUTTON_ADD_ACCOUNT: "Pridať účet" BUTTON_SETTINGS: "Nastavenia" @@ -41,8 +41,8 @@ sk_SK: LABEL_ADV_DATE_YEAR: "Nie staršie ako 1 rok" BUTTON_ADV_SEARCH: "Hľadať" PREVIEW_POPUP: - FULLSCREEN: "Toggle fullscreen" - ZOOM: "Zoom in/out" + FULLSCREEN: "Prepnúť na celú obrazovku" + ZOOM: "Zoom" CLOSE: "Zatvoriť (Esc)" LOADING: "Načítavam..." GALLERY_PREV: "Predchádzajúci (šípka vľavo)" @@ -61,16 +61,16 @@ sk_SK: TRASH_NAME: "Kôš" ARCHIVE_NAME: "Archív" QUOTA: - TITLE: "Využitie kvóty" + TITLE: "Spotreba kvóty" MESSAGE_LIST: - BUTTON_RELOAD: "Obnoviť zoznam správ" + BUTTON_RELOAD: "Znovu načítať zoznam správ" BUTTON_MOVE_TO: "Presunúť do" BUTTON_DELETE: "Odstrániť" BUTTON_ARCHIVE: "Archív" BUTTON_SPAM: "Spam" - BUTTON_NOT_SPAM: "Not Spam" + BUTTON_NOT_SPAM: "Nie je spam" BUTTON_EMPTY_FOLDER: "Vyčistiť priečinok" - BUTTON_MULTY_FORWARD: "Preposlať správy" + BUTTON_MULTY_FORWARD: "Preposlať ako prílohu" BUTTON_DELETE_WITHOUT_MOVE: "Navždy odstrániť" BUTTON_MORE: "Viac" MENU_SET_SEEN: "Označiť ako prečítané" @@ -105,7 +105,7 @@ sk_SK: BUTTON_UNSUBSCRIBE: "Odhlásiť sa z mailing listu" BUTTON_ARCHIVE: "Archív" BUTTON_SPAM: "Spam" - BUTTON_NOT_SPAM: "Not Spam" + BUTTON_NOT_SPAM: "Nie je spam" BUTTON_MOVE_TO: "Presunúť do" BUTTON_MORE: "Viac" BUTTON_REPLY: "Odpovedať" @@ -116,10 +116,10 @@ sk_SK: BUTTON_SHOW_IMAGES: "Zobraziť externé obrázky" BUTTON_NOTIFY_READ_RECEIPT: "Odosielateľ požiadal o potvrdenie prečítania tejto správy." BUTTON_IN_NEW_WINDOW: "Zobraziť v novom okne" - BUTTON_THREAD_LIST: "Thread list" - BUTTON_THREAD_PREV: "Previous" - BUTTON_THREAD_NEXT: "Next" - BUTTON_THREAD_MORE: "More messages" + BUTTON_THREAD_LIST: "Zoznam konverzácií" + BUTTON_THREAD_PREV: "Predchádzajúci" + BUTTON_THREAD_NEXT: "Nasledujúci" + BUTTON_THREAD_MORE: "Ďalšie správy" MENU_HEADERS: "Zobraziť hlavičku správy" MENU_VIEW_ORIGINAL: "Zobraziť zdroj" MENU_DOWNLOAD_ORIGINAL: "Prevziať ako súbor .eml" @@ -144,21 +144,22 @@ sk_SK: PRINT_LABEL_SUBJECT: "Predmet" PRINT_LABEL_ATTACHMENTS: "Prílohy" MESSAGE_LOADING: "Načítavam" - MESSAGE_VIEW_DESC: "Vyberte správu zo zoznamu pre jej zobrazenie tu." + MESSAGE_VIEW_DESC: "Vyberte správu zo zoznamu pre jej zobrazenie." MESSAGE_VIEW_MOVE_DESC: "Zvoľte cieľ kliknutím na názov priečinka v ľavom stĺpci." PGP_PASSWORD_INPUT_PLACEHOLDER: "Heslo" - PGP_SIGNED_MESSAGE_DESC: "OpenPGP signed message (click to verify)" - PGP_ENCRYPTED_MESSAGE_DESC: "OpenPGP encrypted message (click to decrypt)" - LINK_DOWNLOAD_AS_ZIP: "Download as zip" - LINK_SAVE_TO_OWNCLOUD: "Save to ownCloud" - LINK_SAVE_TO_DROPBOX: "Save to Dropbox" + PGP_SIGNED_MESSAGE_DESC: "Správa podpísaná s OpenPGP (kliknite pre overenie)" + PGP_ENCRYPTED_MESSAGE_DESC: "Správa šifrovaná s OpenPGP (kliknite pre dešifrovanie)" + LINK_DOWNLOAD_AS_ZIP: "Prevziať ako zip" + LINK_SAVE_TO_OWNCLOUD: "Uložiť do ownCloud" + LINK_SAVE_TO_CLOUD: "Uložiť do Cloud" + LINK_SAVE_TO_DROPBOX: "Uložiť do Dropbox" READ_RECEIPT: - SUBJECT: "Return Receipt (displayed) - %SUBJECT%" + SUBJECT: "Potvrdenie o doručení (zobrazené) - %SUBJECT%" BODY: | - This is a Return Receipt for the mail that you sent to %READ-RECEIPT%. + Toto je potvrdenie o doručení pre mail, ktorý ste poslali %READ-RECEIPT%. - Note: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. - There is no guarantee that the recipient has read or understood the message contents. + Poznámka: Potvrdenie o doručení znamená, že správa bola zobrazená na počítači adresáta. + Potvrdenie nezaručuje, že adresát správu naozaj prečítal alebo porozumel jej obsahu. SUGGESTIONS: SEARCHING_DESC: "Hľadám..." CONTACTS: @@ -168,78 +169,78 @@ sk_SK: BUTTON_CREATE_CONTACT: "Vytvoriť" BUTTON_UPDATE_CONTACT: "Aktualizovať" BUTTON_IMPORT: "Importovať (csv, vcf, vCard)" - BUTTON_EXPORT_VCARD: "Export (vcf, vCard)" + BUTTON_EXPORT_VCARD: "Exportovať (vcf, vCard)" BUTTON_EXPORT_CSV: "Export (csv)" ERROR_IMPORT_FILE: "Chyba importu (nesprávny formát súboru)" LIST_LOADING: "Načítavam" EMPTY_LIST: "Nemáte žiadne kontakty" EMPTY_SEARCH: "Nenašli sa žiadne kontakty" - CLEAR_SEARCH: "Clear search" + CLEAR_SEARCH: "Zrušiť vyhľadávanie" CONTACT_VIEW_DESC: "Zvoľte kontakt zo zoznamu pre jeho zobrazenie tu." LABEL_DISPLAY_NAME: "Zobraziť ako" LABEL_EMAIL: "Email" LABEL_PHONE: "Telefón" LABEL_WEB: "Web" - LABEL_BIRTHDAY: "Birthday" + LABEL_BIRTHDAY: "Dátum narodenia" LINK_ADD_EMAIL: "Pridať emailovú adresu" LINK_ADD_PHONE: "Pridať telefón" - LINK_BIRTHDAY: "Birthday" + LINK_BIRTHDAY: "Dátum narodenia" PLACEHOLDER_ENTER_DISPLAY_NAME: "Zadajte Zobrazované meno" - PLACEHOLDER_ENTER_LAST_NAME: "Zadajte Priezvisko" - PLACEHOLDER_ENTER_FIRST_NAME: "Zadajte Meno" - PLACEHOLDER_ENTER_NICK_NAME: "Enter nickname" + PLACEHOLDER_ENTER_LAST_NAME: "Zadajte priezvisko" + PLACEHOLDER_ENTER_FIRST_NAME: "Zadajte meno" + PLACEHOLDER_ENTER_NICK_NAME: "Zadajte prezývku" LABEL_READ_ONLY: "Len pre čítanie" LABEL_SHARE: "Zdielať" - ADD_MENU_LABEL: "Add" - ADD_MENU_NICKNAME: "Nickname" - ADD_MENU_NOTES: "Notes" + ADD_MENU_LABEL: "Pridať" + ADD_MENU_NICKNAME: "Prezývka" + ADD_MENU_NOTES: "Poznámky" ADD_MENU_EMAIL: "Email" - ADD_MENU_PHONE: "Phone" + ADD_MENU_PHONE: "Telefón" ADD_MENU_URL: "URL" - ADD_MENU_ADDRESS: "Address" - ADD_MENU_BIRTHDAY: "Birthday" - ADD_MENU_TAGS: "Tags" + ADD_MENU_ADDRESS: "Adresa" + ADD_MENU_BIRTHDAY: "Dátum narodenia" + ADD_MENU_TAGS: "Značky" BUTTON_SHARE_NONE: "Žiadne" BUTTON_SHARE_ALL: "Všetko" - BUTTON_SYNC: "Synchronization (CardDAV)" + BUTTON_SYNC: "Synchronizácia (CardDAV)" COMPOSE: TITLE_FROM: "Odosielateľ" TITLE_TO: "Príjemca" TITLE_CC: "Kópia" TITLE_BCC: "Skrytá kópia" - TITLE_REPLY_TO: "Reply To" + TITLE_REPLY_TO: "Odpovedať na" TITLE_SUBJECT: "Predmet" LINK_SHOW_INPUTS: "zobraziť všetky polia" BUTTON_SEND: "Odoslať" BUTTON_SAVE: "Uložiť" BUTTON_DELETE: "Odstrániť" BUTTON_CANCEL: "Zrušiť" - BUTTON_MINIMIZE: "Minimize" + BUTTON_MINIMIZE: "Minimalizovať" SAVED_TIME: "Uložené o %TIME%" SAVED_ERROR_ON_SEND: "Správa bola odoslaná ale nebola uložená do priečinka odoslaných správ" - DISCARD_UNSAVED_DATA: "Discard unsaved data?" + DISCARD_UNSAVED_DATA: "Zahodiť neuložené dáta?" ATTACH_FILES: "Pripojiť súbory" ATTACH_DROP_FILES_DESC: "Súbory pusťte tu" ATTACH_ITEM_CANCEL: "Zrušiť" DROPBOX: "Dropbox" GOOGLE_DRIVE: "Google Drive" REPLY_MESSAGE_TITLE: "%DATETIME%, %EMAIL% wrote" - FORWARD_MESSAGE_TOP_TITLE: "-------- Forwarded message -------" + FORWARD_MESSAGE_TOP_TITLE: "-------- Preposlaná správa -------" FORWARD_MESSAGE_TOP_FROM: "Odosielateľ" FORWARD_MESSAGE_TOP_TO: "Príjemca" FORWARD_MESSAGE_TOP_CC: "Kópia" FORWARD_MESSAGE_TOP_SENT: "Odoslať" FORWARD_MESSAGE_TOP_SUBJECT: "Predmet" EMPTY_TO_ERROR_DESC: "Zadajte prosím aspoň jedného príjemcu" - NO_ATTACHMENTS_HERE_DESC: "No attachments here." - ATTACHMENTS_ERROR_DESC: "Warning! Not all attachments have been uploaded." - ATTACHMENTS_UPLOAD_ERROR_DESC: "Not all attachments have been uploaded yet" + NO_ATTACHMENTS_HERE_DESC: "Žiadne prílohy." + ATTACHMENTS_ERROR_DESC: "Pozor! Nie všetky prílohy boli nahraté." + ATTACHMENTS_UPLOAD_ERROR_DESC: "Nie všetky prílohy boli už nahraté na server." BUTTON_REQUEST_READ_RECEIPT: "Vyžiadať potvrdenie o prečítaní" - BUTTON_MARK_AS_IMPORTANT: "Mark as important" - BUTTON_OPEN_PGP: "OpenPGP (Plain Text Only)" - BUTTON_REQUEST_DSN: "Request a delivery receipt" + BUTTON_MARK_AS_IMPORTANT: "Označiť ako dôležité" + BUTTON_OPEN_PGP: "Open PGP (iba text)" + BUTTON_REQUEST_DSN: "Vyžiadať potvrdenie o doručení" POPUPS_WELCOME_PAGE: - BUTTON_CLOSE: "Close" + BUTTON_CLOSE: "Zatvoriť" POPUPS_ASK: BUTTON_YES: "Áno" BUTTON_NO: "Nie" @@ -250,20 +251,20 @@ sk_SK: POPUPS_ADD_ACCOUNT: TITLE_ADD_ACCOUNT: "Pridať účet?" BUTTON_ADD_ACCOUNT: "Pridať" - TITLE_UPDATE_ACCOUNT: "Update Account?" - BUTTON_UPDATE_ACCOUNT: "Update" + TITLE_UPDATE_ACCOUNT: "Upraviť účet?" + BUTTON_UPDATE_ACCOUNT: "Upraviť" POPUPS_IDENTITY: - TITLE_ADD_IDENTITY: "Pridať Identitu?" - TITLE_UPDATE_IDENTITY: "Upraviť Identitu?" + TITLE_ADD_IDENTITY: "Pridať identitu?" + TITLE_UPDATE_IDENTITY: "Upraviť identitu?" BUTTON_ADD_IDENTITY: "Pridať" BUTTON_UPDATE_IDENTITY: "Upraviť" LABEL_EMAIL: "Email" LABEL_NAME: "Meno" LABEL_REPLY_TO: "Adresa pre odpoveď" - LABEL_SIGNATURE: "Signature" - LABEL_CC: "Cc" + LABEL_SIGNATURE: "Podpis" + LABEL_CC: "Kópia" LABEL_BCC: "Skrytá kópia" - LABEL_SIGNATURE_INSERT_BEFORE: "Insert this signature before quoted text in replies" + LABEL_SIGNATURE_INSERT_BEFORE: "V odpovediach vložiť tento podpis nad citovaný text" POPUPS_CREATE_FOLDER: TITLE_CREATE_FOLDER: "Vytvoriť priečinok?" LABEL_NAME: "Názov priečinka" @@ -282,11 +283,11 @@ sk_SK: DANGER_DESC_HTML_2: "Tento proces nie je možné prerušiť." TITLE_CLEARING_PROCESS: "Odstraňujem priečinok..." POPUPS_IMPORT_OPEN_PGP_KEY: - TITLE_IMPORT_OPEN_PGP_KEY: "Import OpenPGP key" + TITLE_IMPORT_OPEN_PGP_KEY: "Importovať kľúč OpenPGP" BUTTON_IMPORT_OPEN_PGP_KEY: "Import" POPUPS_VIEW_OPEN_PGP_KEY: - TITLE_VIEW_OPEN_PGP_KEY: "View OpenPGP key" - BUTTON_SELECT: "Select" + TITLE_VIEW_OPEN_PGP_KEY: "Zobraziť kľúč OpenPGP" + BUTTON_SELECT: "Vybrať" BUTTON_CLOSE: "Close" POPUPS_GENERATE_OPEN_PGP_KEYS: TITLE_GENERATE_OPEN_PGP_KEYS: "Generate OpenPGP keys" @@ -329,30 +330,30 @@ sk_SK: SELECT_FIELD_FROM: "From" SELECT_FIELD_RECIPIENTS: "Recipients (To or CC)" SELECT_FIELD_SUBJECT: "Subject" - SELECT_FIELD_HEADER: "Header" - SELECT_FIELD_SIZE: "Size" - SELECT_TYPE_CONTAINS: "Contains" - SELECT_TYPE_NOT_CONTAINS: "Not Contains" - SELECT_TYPE_MATCHES: "Matches (* and ? supported)" - SELECT_TYPE_NOT_MATCHES: "Not Matches (* and ? supported)" + SELECT_FIELD_HEADER: "Záhlavie" + SELECT_FIELD_SIZE: "Veľkosť" + SELECT_TYPE_CONTAINS: "Obsahuje" + SELECT_TYPE_NOT_CONTAINS: "Neobsahuje" + SELECT_TYPE_MATCHES: "Zhoduje sa (* a ? je podporované)" + SELECT_TYPE_NOT_MATCHES: "Nezhoduje sa (* a ? je podporované)" SELECT_TYPE_REGEXP: "Regexp" - SELECT_TYPE_NOT_REGEXP: "Not Regexp" - SELECT_TYPE_EQUAL_TO: "Equal To" - SELECT_TYPE_NOT_EQUAL_TO: "Not Equal To" - SELECT_TYPE_OVER: "Over" - SELECT_TYPE_UNDER: "Under" - SELECT_MATCH_ANY: "Matching any of the following rules" - SELECT_MATCH_ALL: "Matching all of the following rules" - MARK_AS_READ_LABEL: "Mark as read" - REPLY_INTERVAL_LABEL: "Reply interval (days)" - KEEP_LABEL: "Keep" - STOP_LABEL: "Don't stop processing rules" + SELECT_TYPE_NOT_REGEXP: "Negatívny regexp" + SELECT_TYPE_EQUAL_TO: "Rovná sa" + SELECT_TYPE_NOT_EQUAL_TO: "Nerovná sa" + SELECT_TYPE_OVER: "Nad" + SELECT_TYPE_UNDER: "Pod" + SELECT_MATCH_ANY: "Vyhovuje akékoľvek z nasledujúcich pravidiel" + SELECT_MATCH_ALL: "Vyhovujú všetky nasledujúce pravidlá" + MARK_AS_READ_LABEL: "Označiť ako prečítané" + REPLY_INTERVAL_LABEL: "Interval odpovede (v dňoch)" + KEEP_LABEL: "Ponechať" + STOP_LABEL: "Pokračovať vo vykonávaní pravidiel" EMAIL_LABEL: "Email" - VACATION_SUBJECT_LABEL: "Subject (optional)" - VACATION_MESSAGE_LABEL: "Message" - VACATION_RECIPIENTS_LABEL: "Recipients (comma separated)" - REJECT_MESSAGE_LABEL: "Reject message" - ALL_INCOMING_MESSAGES_DESC: "All incoming messages" + VACATION_SUBJECT_LABEL: "Predmet (voliteľne)" + VACATION_MESSAGE_LABEL: "Správa" + VACATION_RECIPIENTS_LABEL: "Adresáti (oddelení čiarkou)" + REJECT_MESSAGE_LABEL: "Odmietnuť správu" + ALL_INCOMING_MESSAGES_DESC: "Všetky prichádzajúce správy" POPUPS_SYSTEM_FOLDERS: TITLE_SYSTEM_FOLDERS: "Spravovať Systémové priečinky" SELECT_CHOOSE_ONE: "Vybrať" @@ -361,7 +362,7 @@ sk_SK: LABEL_DRAFTS: "Koncepty" LABEL_SPAM: "Spam" LABEL_TRASH: "Kôš" - LABEL_ARCHIVE: "Archive" + LABEL_ARCHIVE: "Archív" BUTTON_CANCEL: "Zrušiť" BUTTON_CLOSE: "Zatvoriť" NOTIFICATION_SENT: | @@ -374,33 +375,33 @@ sk_SK: NOTIFICATION_TRASH: | Nepriradili ste systémový priečinok pre "Kôš" kam sú správy presunuté po ich odstránení. Ak si želáte takéto správy odstraňovať natrvalo, vyberte prosím možnosť "Nepoužívať". - NOTIFICATION_ARCHIVE: "You haven't selected \"Archive\" system folder achived messages are placed to.\n" + NOTIFICATION_ARCHIVE: "Nepriradili ste systémový priečinok pre \"Archív\" kam budú uložené archivované správy." POPUPS_TWO_FACTOR_CFG: LEGEND_TWO_FACTOR_AUTH: "2-Step Verification" LABEL_ENABLE_TWO_FACTOR: "Enable 2-Step verification" - LABEL_TWO_FACTOR_USER: "User" - LABEL_TWO_FACTOR_STATUS: "Status" - LABEL_TWO_FACTOR_SECRET: "Secret" - LABEL_TWO_FACTOR_BACKUP_CODES: "Backup codes" - BUTTON_CREATE: "Create New Secret" - BUTTON_ACTIVATE: "Activate" - BUTTON_CLEAR: "Clear" - BUTTON_LOGOUT: "Logout" - BUTTON_DONE: "Done" + LABEL_TWO_FACTOR_USER: "Používateľ" + LABEL_TWO_FACTOR_STATUS: "Stav" + LABEL_TWO_FACTOR_SECRET: "Tajný kľúč" + LABEL_TWO_FACTOR_BACKUP_CODES: "Záložné kódy" + BUTTON_CREATE: "Vygenerovať nový tajný kľúč" + BUTTON_ACTIVATE: "Aktivovať" + BUTTON_CLEAR: "Vyčistiť" + BUTTON_LOGOUT: "Odhlásiť" + BUTTON_DONE: "Dokončené" BUTTON_TEST: "Test" LINK_TEST: "test" - BUTTON_SHOW_SECRET: "Show Secret" - BUTTON_HIDE_SECRET: "Hide Secret" - TWO_FACTOR_REQUIRE_DESC: "Your account requires 2-Step verification configuration." - TWO_FACTOR_SECRET_CONFIGURED_DESC: "Configured" - TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Not configured" - TWO_FACTOR_SECRET_DESC: >- - Import this info into your Google Authenticator client (or other TOTP client) - using the provided QR code below or by entering the code manually. - TWO_FACTOR_BACKUP_CODES_DESC: >- - If you can't receive codes via Google Authenticator, you can use backup codes - to sign in. After you’ve used a backup code to sign in, it will become inactive. - TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "You can't change this setting before test." + BUTTON_SHOW_SECRET: "Zobraziť tajný kľúč" + BUTTON_HIDE_SECRET: "Skryť tajný kľúč" + TWO_FACTOR_REQUIRE_DESC: "Váš účet vyžaduje konfiguráciu 2-krokovej verifikácie." + TWO_FACTOR_SECRET_CONFIGURED_DESC: "Nakonfigurované" + TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Nenakonfigurované" + TWO_FACTOR_SECRET_DESC: > + Naimportujte do vášho Google Authenticator klienta (alebo iného TOTP klienta) + s použitím QR kódu alebo manuálne zadaním kódu. + TWO_FACTOR_BACKUP_CODES_DESC: > + Ak sa nemôžete prihlásiť použitím kódu z Google Authenticator (alebo iného + TOTP klienta), použite záložné kódy. Použitý záložný kód bude deaktivovaný. + TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "Toto nastavenie nemôžete zmeniť pred testom." TITLES: LOADING: "Načítavam" LOGIN: "Používateľské meno" @@ -429,19 +430,19 @@ sk_SK: LABEL_IDENTITIES_NAME: "Identity" LABEL_FILTERS_NAME: "Filters" LABEL_TEMPLATES_NAME: "Templates" - LABEL_SECURITY_NAME: "Security" + LABEL_SECURITY_NAME: "Zabezpečenie" LABEL_SOCIAL_NAME: "Social" LABEL_THEMES_NAME: "Motívy" LABEL_CHANGE_PASSWORD_NAME: "Heslo" LABEL_OPEN_PGP_NAME: "OpenPGP" BUTTON_BACK: "Späť" SETTINGS_FILTERS: - LEGEND_FILTERS: "Filters" - BUTTON_SAVE: "Save" - BUTTON_ADD_FILTER: "Add a Filter" - BUTTON_DELETE: "Delete" - BUTTON_RAW_SCRIPT: "Use Custom User Script" - SUBNAME_NONE: "None" + LEGEND_FILTERS: "Filtre" + BUTTON_SAVE: "Uložiť" + BUTTON_ADD_FILTER: "Pridať filter" + BUTTON_DELETE: "Vymazať" + BUTTON_RAW_SCRIPT: "Použiť používateľský skript" + SUBNAME_NONE: "Žiadny" SUBNAME_MOVE_TO: "Move to \"%FOLDER%\"" SUBNAME_FORWARD_TO: "Forward to \"%EMAIL%\"" SUBNAME_REJECT: "Reject" @@ -580,6 +581,7 @@ sk_SK: TITLE_PUBLIC: "Public" DELETING_ASK: "Are you sure?" GENERATE_ONLY_HTTPS: "HTTPS only" + LABEL_ALLOW_DRAFT_AUTOSAVE: "Automaticky uložiť koncept." SHORTCUTS_HELP: LEGEND_SHORTCUTS_HELP: "Keyboard shortcuts help" TAB_MAILBOX: "Mailbox" diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sl_SI.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/sl_SI.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sl_SI.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/sl_SI.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sv_SE.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/sv_SE.yml similarity index 99% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sv_SE.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/sv_SE.yml index 28ef04d1..94c21824 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sv_SE.yml +++ b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/sv_SE.yml @@ -1,6 +1,6 @@ sv_SE: LOGIN: - LABEL_EMAIL: "Epost" + LABEL_EMAIL: "E-post" LABEL_LOGIN: "Användarnamn" LABEL_PASSWORD: "Lösenord" LABEL_SIGN_ME: "Kom ihåg mig" @@ -72,7 +72,7 @@ sv_SE: BUTTON_EMPTY_FOLDER: "Rensa mapp" BUTTON_MULTY_FORWARD: "Vidarebefordra som bilaga(or)" BUTTON_DELETE_WITHOUT_MOVE: "Ta bort permanent" - BUTTON_MORE: "Mera" + BUTTON_MORE: "Mer" MENU_SET_SEEN: "Markera som läst" MENU_SET_ALL_SEEN: "Markera alla som lästa" MENU_UNSET_SEEN: "Markera som oläst" @@ -134,12 +134,12 @@ sv_SE: LABEL_TO_SHORT: "till" LABEL_CC: "CC" LABEL_BCC: "BCC" - LABEL_REPLY_TO: "Svara-till" + LABEL_REPLY_TO: "Svara till" PRINT_LABEL_FROM: "Från" PRINT_LABEL_TO: "Till" PRINT_LABEL_CC: "CC" PRINT_LABEL_BCC: "BCC" - PRINT_LABEL_REPLY_TO: "Svara-till" + PRINT_LABEL_REPLY_TO: "Svara till" PRINT_LABEL_DATE: "Datum" PRINT_LABEL_SUBJECT: "Ämne" PRINT_LABEL_ATTACHMENTS: "Bilagor" diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/tr_TR.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/tr_TR.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/tr_TR.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/tr_TR.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/uk_UA.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/uk_UA.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/uk_UA.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/uk_UA.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/zh_CN.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/zh_CN.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/zh_CN.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/zh_CN.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/zh_TW.yml b/rainloop/app/rainloop/v/1.13.0/app/localization/webmail/zh_TW.yml similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/localization/webmail/zh_TW.yml rename to rainloop/app/rainloop/v/1.13.0/app/localization/webmail/zh_TW.yml diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/RainLoop.asc b/rainloop/app/rainloop/v/1.13.0/app/resources/RainLoop.asc similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/RainLoop.asc rename to rainloop/app/rainloop/v/1.13.0/app/resources/RainLoop.asc diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/empty-contact.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/empty-contact.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/empty-contact.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/empty-contact.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/amazon.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/amazon.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/amazon.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/amazon.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/apple.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/apple.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/apple.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/apple.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/asana.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/asana.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/asana.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/asana.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/battle.net.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/battle.net.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/battle.net.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/battle.net.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/blizzard.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/blizzard.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/blizzard.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/blizzard.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/cnet.online.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/cnet.online.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/cnet.online.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/cnet.online.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/connect.asana.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/connect.asana.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/connect.asana.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/connect.asana.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/e.paypal.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/e.paypal.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/e.paypal.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/e.paypal.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ea.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/ea.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ea.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/ea.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ebay.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/ebay.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ebay.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/ebay.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/em.ea.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/em.ea.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/em.ea.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/em.ea.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.blizzard.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/email.blizzard.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.blizzard.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/email.blizzard.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.microsoft.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/email.microsoft.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.microsoft.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/email.microsoft.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.skype.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/email.skype.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.skype.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/email.skype.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/facebook.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/facebook.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/facebook.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/facebook.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/facebookmail.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/facebookmail.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/facebookmail.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/facebookmail.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/github.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/github.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/github.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/github.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/google.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/google.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/google.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/google.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/id.apple.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/id.apple.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/id.apple.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/id.apple.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/intl.paypal.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/intl.paypal.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/intl.paypal.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/intl.paypal.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/microsoft.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/microsoft.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/microsoft.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/microsoft.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/microsoftonline.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/microsoftonline.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/microsoftonline.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/microsoftonline.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/myspace.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/myspace.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/myspace.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/myspace.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/news.myspace.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/news.myspace.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/news.myspace.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/news.myspace.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/news.onlive.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/news.onlive.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/news.onlive.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/news.onlive.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/onlive.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/onlive.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/onlive.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/onlive.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/paypal.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/paypal.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/paypal.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/paypal.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/plus.google.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/plus.google.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/plus.google.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/plus.google.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/postmaster.twitter.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/postmaster.twitter.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/postmaster.twitter.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/postmaster.twitter.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply.ebay.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/reply.ebay.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply.ebay.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/reply.ebay.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply1.ebay.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/reply1.ebay.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply1.ebay.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/reply1.ebay.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply2.ebay.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/reply2.ebay.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply2.ebay.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/reply2.ebay.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply3.ebay.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/reply3.ebay.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply3.ebay.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/reply3.ebay.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/skype.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/skype.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/skype.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/skype.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/steampowered.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/steampowered.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/steampowered.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/steampowered.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ted.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/ted.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ted.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/ted.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/twitter.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/twitter.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/twitter.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/twitter.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/youtube.com.png b/rainloop/app/rainloop/v/1.13.0/app/resources/images/services/youtube.com.png similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/resources/images/services/youtube.com.png rename to rainloop/app/rainloop/v/1.13.0/app/resources/images/services/youtube.com.png diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/BadBrowser.html b/rainloop/app/rainloop/v/1.13.0/app/templates/BadBrowser.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/BadBrowser.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/BadBrowser.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Error.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Error.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Error.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Error.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Index.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Index.html similarity index 86% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Index.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Index.html index 3be1b78e..1a3d7d2b 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Index.html +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Index.html @@ -1,30 +1,33 @@ - - - - - - - - - - - - - {{BaseContentSecurityPolicy}} - - {{BaseAppFaviconPngLinkTag}} - {{BaseAppFaviconTouchLinkTag}} - - - - - -
-
- - - + + + + + + + + + + + + + + {{BaseContentSecurityPolicy}} + + {{BaseAppHeadScriptLink}} + {{BaseAppFaviconPngLinkTag}} + {{BaseAppFaviconTouchLinkTag}} + + + + + +
+
+ {{BaseAppBodyScript}} + + + diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Social.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Social.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Social.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Social.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Themes/template.less b/rainloop/app/rainloop/v/1.13.0/app/templates/Themes/template.less similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Themes/template.less rename to rainloop/app/rainloop/v/1.13.0/app/templates/Themes/template.less index 90b00d08..b4ebb2ab 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Themes/template.less +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Themes/template.less @@ -1,357 +1,357 @@ - -// mixins +++ -.thm-linear-gradient-mixin(@start, @end) when (iscolor(@start)) and (iscolor(@end)) { - background-color: mix(@start, @end, 60%) !important; - background-image: -moz-linear-gradient(top, @start, @end) !important; // FF 3.6+ - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@start), to(@end)) !important; // Safari 4+, Chrome 2+ - background-image: -webkit-linear-gradient(top, @start, @end) !important; // Safari 5.1+, Chrome 10+ - background-image: -o-linear-gradient(top, @start, @end !important); // Opera 11.10 - background-image: linear-gradient(to bottom, @start, @end) !important; // Standard, IE10 - background-repeat: repeat-x !important; - filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start),argb(@end))) !important; // IE9 and down -} - -.thm-border-radius(@radius) when (ispixel(@radius)) { - -webkit-border-radius: @radius !important; - -moz-border-radius: @radius !important; - border-radius: @radius !important; -} - -.thm-box-shadow(@shadow) { - -webkit-box-shadow: @shadow !important; - -moz-box-shadow: @shadow !important; - box-shadow: @shadow !important; -} -.thm-body-background-image(@value) when (isstring(@value)) { - background-image: url("@{base}@{value}") !important; -} -.thm-body-background-image(@value) when not (isstring(@value)) { - background-image: @value !important; -} -.thm-rgba-background-color(@simple, @rgba) when (@rgba = false) { - background-color: @simple !important; -} -.thm-rgba-background-color(@simple, @rgba) when not (@rgba = false) { - background-color: @simple !important; - background-color: @rgba !important; -} -// --- mixins - -.thm-body { - color: @main-color; - background-color: @main-background-color; - background-size: @main-background-size; - .thm-body-background-image(@main-background-image); -} - -.thm-loading { - color: @loading-color !important; - text-shadow: @loading-text-shadow !important; - - .e-spinner .e-bounce { - background-color: @loading-color !important; - } -} - -.thm-login-desc .desc { - color: @loading-color !important; - text-shadow: @loading-text-shadow !important; -} - -.thm-login { - border: @login-border !important; - .thm-rgba-background-color(@login-background-color, @login-rgba-background-color); - .thm-linear-gradient-mixin(@login-gradient-start, @login-gradient-end); - .thm-border-radius(@login-border-radius); - .thm-box-shadow(@login-box-shadow); - - &.submitting-pane.submitting { - &:before{ - background: @spinner-background; - .thm-border-radius(@login-border-radius); - } - &:after{ - border-top-color: @spinner-color; - } - } -} - -.thm-login-text { - color: @login-color !important; - - .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button { - color: @login-color !important; - } -} - -.thm-powered, .thm-mobile-switcher { - color: @powered-color; - a { - color: @powered-color; - &:hover { - color: lighten(@powered-color, 20%); - } - } -} - -.thm-languages { - color: @languages-color; - .flag-name { - color: @languages-color; - border-color: @languages-color; - } -} - -.g-ui-menu { - color: @dropdown-menu-color !important; - background-color: @dropdown-menu-background-color !important; -} - -.g-ui-menu .e-item > .e-link { - color: @dropdown-menu-color !important; - background-color: @dropdown-menu-background-color !important; - - > i { - color: @dropdown-menu-color !important; - } -} - -.g-ui-menu .e-item.selected > .e-link { - background-color: @dropdown-menu-selected-background-color !important; -} - -.g-ui-menu .e-item > .e-link:hover, .g-ui-menu .e-item > .e-link:focus { - color: @dropdown-menu-hover-color !important; - background-color: @dropdown-menu-hover-background-color !important; - - > i { - color: @dropdown-menu-hover-color !important; - } -} - -.g-ui-menu .e-item.disabled > .e-link, .g-ui-menu .e-item.disabled > .e-link:hover { - color: @dropdown-menu-disabled-color !important; - background-color: @dropdown-menu-background-color !important; - - > i { - color: @dropdown-menu-disabled-color !important; - } -} - -.thm-message-list-top-toolbar, .thm-message-list-bottom-toolbar { - .thm-rgba-background-color(@message-list-toolbar-background-color, @message-list-toolbar-rgba-background-color); - .thm-linear-gradient-mixin(@message-list-toolbar-gradient-start, @message-list-toolbar-gradient-end); -} - -.thm-folders .e-link { - - color: @folders-disabled-color !important; - - &.selectable { - color: @folders-color !important; - } - - &.selectable:hover { - color: @folders-hover-color !important; - .thm-rgba-background-color(@folders-hover-background-color, @folders-hover-rgba-background-color); - } - - &.selectable.selected { - color: @folders-selected-color !important; - .thm-rgba-background-color(@folders-selected-background-color, @folders-selected-rgba-background-color); - } - - &.focused { - color: @folders-focused-color !important; - .thm-rgba-background-color(@folders-focused-background-color, @folders-focused-rgba-background-color); - } - - &.selectable.droppableHover { - color: @folders-drop-color !important; - .thm-rgba-background-color(@folders-drop-background-color, @folders-drop-rgba-background-color); - } -} - -.thm-settings-menu .e-item { - - .e-link { - color: @settings-menu-disabled-color !important; - } - - &.selectable .e-link { - color: @settings-menu-color !important; - } - - &.selectable:hover .e-link { - .thm-rgba-background-color(@settings-menu-hover-background-color, @settings-menu-hover-rgba-background-color); - color: @settings-menu-hover-color !important; - } - - &.selectable.selected .e-link { - .thm-rgba-background-color(@settings-menu-selected-background-color, @settings-menu-selected-rgba-background-color); - color: @settings-menu-selected-color !important; - } -} - -.thm-message-view-background-color { - .thm-rgba-background-color(@message-background-color, @message-rgba-background-color); -} - -#rl-app{ - display: block; -} - -html.no-css { - - margin: 0; - padding: 0; - font-family: Arial, Verdana, Geneva, sans-serif; - - body { - margin: 0; - padding: 0; - } - - #rl-loading, #rl-loading-error { - position: absolute; - font-size: 30px; - line-height: 130%; - top: 50%; - width: 100%; - height: 65px; - margin: 0; - margin-top: -60px; - background-color: transparent; - text-align: center; - color: #333; - } - - .progressjs-container { - display: none; - } - - .thm-body { - color: #333; - background-color: #aaa; - background-image: none; - } - - .thm-loading { - color: #333 !important; - text-shadow: none !important; - - .e-spinner .e-bounce { - display: none !important; - } - } - - .thm-login-desc .desc { - color: #333 !important; - text-shadow: none !important; - } -} - -// glass style -html.glass { - - @glass-color: #fff !important; - @glass-p-color: #aaa !important; - @glass-error-color: #f76260 !important; - @glass-m-color: rgba(255, 255, 255, .8) !important; - - .thm-login { - background: none !important; - background: rgba(0, 0, 0, .5) !important; - box-shadow: none !important; - - border: none !important; - border: 1px solid rgba(255, 255, 255, .2) !important; - - .controls { - .input-append .add-on i { - color: @glass-m-color; - text-shadow: none !important; - outline: none !important; - box-shadow: none !important; - } - - input { - border: 1px solid none !important; - background: none !important; - outline: none !important; - text-shadow: none !important; - box-shadow: none !important; - - color: @glass-color; - border-color: @glass-m-color; - - &::-webkit-input-placeholder { - color: @glass-color; - text-shadow: none !important; - } - &::-moz-placeholder { - color: @glass-color; - text-shadow: none !important; - } - &:-moz-placeholder { - color: @glass-color; - text-shadow: none !important; - } - &:-ms-input-placeholder { - color: @glass-color; - text-shadow: none !important; - } - &:input-placeholder { - color: @glass-color; - text-shadow: none !important; - } - &:placeholder { - color: @glass-color; - text-shadow: none !important; - } - - &:focus, &:hover { - border-color: @glass-color; - } - } - .btn { - border: 1px solid none !important; - background: none !important; - outline: none !important; - text-shadow: none !important; - box-shadow: none !important; - - color: @glass-color; - border-color: @glass-m-color; - - text-transform: uppercase; - font-size: 13px; - - &:hover, &:active{ - border-color: @glass-color; - } - } - - &.error { - .input-append .add-on i { - color: @glass-error-color; - } - - input { - color: @glass-error-color; - border-color: @glass-error-color; - } - } - } - } - - .thm-login-text { - color: @glass-m-color; - text-shadow: none !important; - - .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button { - color: @glass-m-color; - text-shadow: none !important; - } - } -} + +// mixins +++ +.thm-linear-gradient-mixin(@start, @end) when (iscolor(@start)) and (iscolor(@end)) { + background-color: mix(@start, @end, 60%) !important; + background-image: -moz-linear-gradient(top, @start, @end) !important; // FF 3.6+ + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@start), to(@end)) !important; // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(top, @start, @end) !important; // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(top, @start, @end !important); // Opera 11.10 + background-image: linear-gradient(to bottom, @start, @end) !important; // Standard, IE10 + background-repeat: repeat-x !important; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start),argb(@end))) !important; // IE9 and down +} + +.thm-border-radius(@radius) when (ispixel(@radius)) { + -webkit-border-radius: @radius !important; + -moz-border-radius: @radius !important; + border-radius: @radius !important; +} + +.thm-box-shadow(@shadow) { + -webkit-box-shadow: @shadow !important; + -moz-box-shadow: @shadow !important; + box-shadow: @shadow !important; +} +.thm-body-background-image(@value) when (isstring(@value)) { + background-image: url("@{base}@{value}") !important; +} +.thm-body-background-image(@value) when not (isstring(@value)) { + background-image: @value !important; +} +.thm-rgba-background-color(@simple, @rgba) when (@rgba = false) { + background-color: @simple !important; +} +.thm-rgba-background-color(@simple, @rgba) when not (@rgba = false) { + background-color: @simple !important; + background-color: @rgba !important; +} +// --- mixins + +.thm-body { + color: @main-color; + background-color: @main-background-color; + background-size: @main-background-size; + .thm-body-background-image(@main-background-image); +} + +.thm-loading { + color: @loading-color !important; + text-shadow: @loading-text-shadow !important; + + .e-spinner .e-bounce { + background-color: @loading-color !important; + } +} + +.thm-login-desc .desc { + color: @loading-color !important; + text-shadow: @loading-text-shadow !important; +} + +.thm-login { + border: @login-border !important; + .thm-rgba-background-color(@login-background-color, @login-rgba-background-color); + .thm-linear-gradient-mixin(@login-gradient-start, @login-gradient-end); + .thm-border-radius(@login-border-radius); + .thm-box-shadow(@login-box-shadow); + + &.submitting-pane.submitting { + &:before{ + background: @spinner-background; + .thm-border-radius(@login-border-radius); + } + &:after{ + border-top-color: @spinner-color; + } + } +} + +.thm-login-text { + color: @login-color !important; + + .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button { + color: @login-color !important; + } +} + +.thm-powered, .thm-mobile-switcher { + color: @powered-color; + a { + color: @powered-color; + &:hover { + color: lighten(@powered-color, 20%); + } + } +} + +.thm-languages { + color: @languages-color; + .flag-name { + color: @languages-color; + border-color: @languages-color; + } +} + +.g-ui-menu { + color: @dropdown-menu-color !important; + background-color: @dropdown-menu-background-color !important; +} + +.g-ui-menu .e-item > .e-link { + color: @dropdown-menu-color !important; + background-color: @dropdown-menu-background-color !important; + + > i { + color: @dropdown-menu-color !important; + } +} + +.g-ui-menu .e-item.selected > .e-link { + background-color: @dropdown-menu-selected-background-color !important; +} + +.g-ui-menu .e-item > .e-link:hover, .g-ui-menu .e-item > .e-link:focus { + color: @dropdown-menu-hover-color !important; + background-color: @dropdown-menu-hover-background-color !important; + + > i { + color: @dropdown-menu-hover-color !important; + } +} + +.g-ui-menu .e-item.disabled > .e-link, .g-ui-menu .e-item.disabled > .e-link:hover { + color: @dropdown-menu-disabled-color !important; + background-color: @dropdown-menu-background-color !important; + + > i { + color: @dropdown-menu-disabled-color !important; + } +} + +.thm-message-list-top-toolbar, .thm-message-list-bottom-toolbar { + .thm-rgba-background-color(@message-list-toolbar-background-color, @message-list-toolbar-rgba-background-color); + .thm-linear-gradient-mixin(@message-list-toolbar-gradient-start, @message-list-toolbar-gradient-end); +} + +.thm-folders .e-link { + + color: @folders-disabled-color !important; + + &.selectable { + color: @folders-color !important; + } + + &.selectable:hover { + color: @folders-hover-color !important; + .thm-rgba-background-color(@folders-hover-background-color, @folders-hover-rgba-background-color); + } + + &.selectable.selected { + color: @folders-selected-color !important; + .thm-rgba-background-color(@folders-selected-background-color, @folders-selected-rgba-background-color); + } + + &.focused { + color: @folders-focused-color !important; + .thm-rgba-background-color(@folders-focused-background-color, @folders-focused-rgba-background-color); + } + + &.selectable.droppableHover { + color: @folders-drop-color !important; + .thm-rgba-background-color(@folders-drop-background-color, @folders-drop-rgba-background-color); + } +} + +.thm-settings-menu .e-item { + + .e-link { + color: @settings-menu-disabled-color !important; + } + + &.selectable .e-link { + color: @settings-menu-color !important; + } + + &.selectable:hover .e-link { + .thm-rgba-background-color(@settings-menu-hover-background-color, @settings-menu-hover-rgba-background-color); + color: @settings-menu-hover-color !important; + } + + &.selectable.selected .e-link { + .thm-rgba-background-color(@settings-menu-selected-background-color, @settings-menu-selected-rgba-background-color); + color: @settings-menu-selected-color !important; + } +} + +.thm-message-view-background-color { + .thm-rgba-background-color(@message-background-color, @message-rgba-background-color); +} + +#rl-app{ + display: block; +} + +html.no-css { + + margin: 0; + padding: 0; + font-family: Arial, Verdana, Geneva, sans-serif; + + body { + margin: 0; + padding: 0; + } + + #rl-loading, #rl-loading-error { + position: absolute; + font-size: 30px; + line-height: 130%; + top: 50%; + width: 100%; + height: 65px; + margin: 0; + margin-top: -60px; + background-color: transparent; + text-align: center; + color: #333; + } + + .progressjs-container { + display: none; + } + + .thm-body { + color: #333; + background-color: #aaa; + background-image: none; + } + + .thm-loading { + color: #333 !important; + text-shadow: none !important; + + .e-spinner .e-bounce { + display: none !important; + } + } + + .thm-login-desc .desc { + color: #333 !important; + text-shadow: none !important; + } +} + +// glass style +html.glass { + + @glass-color: #fff !important; + @glass-p-color: #aaa !important; + @glass-error-color: #f76260 !important; + @glass-m-color: rgba(255, 255, 255, .8) !important; + + .thm-login { + background: none !important; + background: rgba(0, 0, 0, .5) !important; + box-shadow: none !important; + + border: none !important; + border: 1px solid rgba(255, 255, 255, .2) !important; + + .controls { + .input-append .add-on i { + color: @glass-m-color; + text-shadow: none !important; + outline: none !important; + box-shadow: none !important; + } + + input { + border: 1px solid none !important; + background: none !important; + outline: none !important; + text-shadow: none !important; + box-shadow: none !important; + + color: @glass-color; + border-color: @glass-m-color; + + &::-webkit-input-placeholder { + color: @glass-color; + text-shadow: none !important; + } + &::-moz-placeholder { + color: @glass-color; + text-shadow: none !important; + } + &:-moz-placeholder { + color: @glass-color; + text-shadow: none !important; + } + &:-ms-input-placeholder { + color: @glass-color; + text-shadow: none !important; + } + &:input-placeholder { + color: @glass-color; + text-shadow: none !important; + } + &:placeholder { + color: @glass-color; + text-shadow: none !important; + } + + &:focus, &:hover { + border-color: @glass-color; + } + } + .btn { + border: 1px solid none !important; + background: none !important; + outline: none !important; + text-shadow: none !important; + box-shadow: none !important; + + color: @glass-color; + border-color: @glass-m-color; + + text-transform: uppercase; + font-size: 13px; + + &:hover, &:active{ + border-color: @glass-color; + } + } + + &.error { + .input-append .add-on i { + color: @glass-error-color; + } + + input { + color: @glass-error-color; + border-color: @glass-error-color; + } + } + } + } + + .thm-login-text { + color: @glass-m-color; + text-shadow: none !important; + + .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button { + color: @glass-m-color; + text-shadow: none !important; + } + } +} diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Themes/values.less b/rainloop/app/rainloop/v/1.13.0/app/templates/Themes/values.less similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Themes/values.less rename to rainloop/app/rainloop/v/1.13.0/app/templates/Themes/values.less diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminLogin.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminLogin.html similarity index 85% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminLogin.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminLogin.html index dc6c1176..7ca7aca5 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminLogin.html +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminLogin.html @@ -1,50 +1,47 @@ - diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsContacts.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsContacts.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsContacts.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsContacts.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsDomainListItem.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsDomainListItem.html similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsDomainListItem.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsDomainListItem.html index 6d32c436..b6f36ba9 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsDomainListItem.html +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsDomainListItem.html @@ -1,21 +1,21 @@ - - - - (alias) - - - - - - - - - - - - - - - - + + + + (alias) + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsDomains.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsDomains.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsDomains.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsDomains.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsGeneral.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsGeneral.html similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsGeneral.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsGeneral.html index 914af770..2cdbc347 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsGeneral.html +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsGeneral.html @@ -1,181 +1,181 @@ -
-
-
-

-
-
-
-
- -
-
-
- -
-
- - - - -    -
-
-
-
-
- -
-
- - - - -    -
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- -
-
-
-
- - PHP: -   - - -     - - - -
-
-
-
-
-
-
-
-
- -
+
+
+
+

+
+
+
+
+ +
+
+
+ +
+
+ + + + +    +
+
+
+
+
+ +
+
+ + + + +    +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+ + PHP: +   + + +     + + + +
+
+
+
+
+
+
+
+
+ +
\ No newline at end of file diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsLicensing.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsLicensing.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsLicensing.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsLicensing.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsLogin.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsLogin.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsLogin.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsLogin.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackages.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPackages.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackages.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPackages.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackagesListItem.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPackagesListItem.html similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackagesListItem.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPackagesListItem.html index bce55dd3..cc15c6c2 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackagesListItem.html +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPackagesListItem.html @@ -8,9 +8,11 @@ +   diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackagesTable.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPackagesTable.html similarity index 88% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackagesTable.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPackagesTable.html index 72d3cee1..5a6a1a90 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackagesTable.html +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPackagesTable.html @@ -2,7 +2,7 @@ - + diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPluginListItem.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPluginListItem.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPluginListItem.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPluginListItem.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPluginProperty.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPluginProperty.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPlugins.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPlugins.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPlugins.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsPlugins.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsSecurity.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsSecurity.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsSecurity.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsSecurity.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsSocial.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsSocial.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsSocial.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/AdminSettingsSocial.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsActivate.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/PopupsActivate.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsActivate.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/PopupsActivate.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsDomain.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/PopupsDomain.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsDomain.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/PopupsDomain.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsDomainAlias.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/PopupsDomainAlias.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsDomainAlias.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/PopupsDomainAlias.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsPlugin.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/PopupsPlugin.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsPlugin.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Admin/PopupsPlugin.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/Cmd.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/Cmd.html similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/Cmd.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/Cmd.html index f51b642b..9cd70b5f 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/Cmd.html +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/Cmd.html @@ -1,10 +1,10 @@ -
-
-
-
-
-
#
- -
-
+
+
+
+
+
+
#
+ +
+
\ No newline at end of file diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/Pagenator.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/Pagenator.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/Pagenator.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/Pagenator.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsAsk.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/PopupsAsk.html similarity index 96% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsAsk.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/PopupsAsk.html index 4054b3b6..93df1f52 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsAsk.html +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/PopupsAsk.html @@ -1,26 +1,26 @@ -
- -
+
+ +
diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsLanguages.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/PopupsLanguages.html similarity index 98% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsLanguages.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/PopupsLanguages.html index 0294673c..03e3297b 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsLanguages.html +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/PopupsLanguages.html @@ -1,22 +1,22 @@ -
- +
+
\ No newline at end of file diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsWelcomePage.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/PopupsWelcomePage.html similarity index 97% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsWelcomePage.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/PopupsWelcomePage.html index 1a4ca08c..0edb0665 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsWelcomePage.html +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Common/PopupsWelcomePage.html @@ -1,22 +1,22 @@ -
- +
+
\ No newline at end of file diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/Checkbox.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/Checkbox.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/Checkbox.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/Checkbox.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/CheckboxClassic.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/CheckboxClassic.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/CheckboxClassic.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/CheckboxClassic.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/CheckboxMaterialDesign.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/CheckboxMaterialDesign.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/CheckboxMaterialDesign.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/CheckboxMaterialDesign.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/Date.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/Date.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/Date.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/Date.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/Input.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/Input.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/Input.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/Input.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/Radio.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/Radio.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/Radio.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/Radio.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/SaveTrigger.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/SaveTrigger.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/SaveTrigger.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/SaveTrigger.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/Select.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/Select.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/Select.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/Select.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/TextArea.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/TextArea.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/Components/TextArea.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/Components/TextArea.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/User/About.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/User/About.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/User/About.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/User/About.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/User/ComposeAttachment.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/User/ComposeAttachment.html similarity index 100% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/User/ComposeAttachment.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/User/ComposeAttachment.html diff --git a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/User/Login.html b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/User/Login.html similarity index 95% rename from rainloop/app/rainloop/v/1.12.1/app/templates/Views/User/Login.html rename to rainloop/app/rainloop/v/1.13.0/app/templates/Views/User/Login.html index dc7310f7..7aa4f869 100644 --- a/rainloop/app/rainloop/v/1.12.1/app/templates/Views/User/Login.html +++ b/rainloop/app/rainloop/v/1.13.0/app/templates/Views/User/Login.html @@ -1,149 +1,148 @@ -