diff --git a/dev/App/User.js b/dev/App/User.js index f0eb9cb8c..46a813dee 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -1315,6 +1315,7 @@ require('Stores/User/Settings').populate(); require('Stores/User/Notification').populate(); require('Stores/User/Account').populate(); + require('Stores/User/Contact').populate(); var self = this, diff --git a/dev/Model/Attachment.js b/dev/Model/Attachment.js index c09f028dd..c66654661 100644 --- a/dev/Model/Attachment.js +++ b/dev/Model/Attachment.js @@ -122,7 +122,7 @@ */ AttachmentModel.prototype.isText = function () { - return -1 < Utils.inArray(this.mimeType, ['application/pgp-signature']) || + return -1 < Utils.inArray(this.mimeType, ['application/pgp-signature', 'message/delivery-status', 'message/rfc822']) || ('text/' === this.mimeType.substr(0, 5) && -1 === Utils.inArray(this.mimeType, ['text/html'])); }; @@ -316,6 +316,12 @@ { sClass = 'icon-file-certificate'; } + else if (-1 < Utils.inArray(sMimeType, [ + 'message/delivery-status', 'message/rfc822' + ])) + { + sClass = 'icon-file-text'; + } else if (-1 < Utils.inArray(aParts[1], [ 'rtf', 'msword', 'vnd.msword', 'vnd.openxmlformats-officedocument.wordprocessingml.document', 'vnd.openxmlformats-officedocument.wordprocessingml.template', diff --git a/package.json b/package.json index 27a86f165..bd3a765f6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "RainLoop", "title": "RainLoop Webmail", "version": "1.8.1", - "release": "271", + "release": "272", "description": "Simple, modern & fast web-based email client", "homepage": "http://rainloop.net", "main": "gulpfile.js", diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/APC.php b/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/APC.php index c09934b56..079710ae3 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/APC.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/APC.php @@ -1,85 +1,107 @@ -generateCachedKey($sKey), (string) $sValue); - } - - /** - * @param string $sKey - * - * @return string - */ - public function Get($sKey) - { - $sValue = \apc_fetch($this->generateCachedKey($sKey)); - return \is_string($sValue) ? $sValue : ''; - } - - /** - * @param string $sKey - * - * @return void - */ - public function Delete($sKey) - { - \apc_delete($this->generateCachedKey($sKey)); - } - - /** - * @param int $iTimeToClearInHours = 24 - * - * @return bool - */ - public function GC($iTimeToClearInHours = 24) - { - if (0 === $iTimeToClearInHours) - { - return \apc_clear_cache('user'); - } - - return false; - } - - /** - * @param string $sKey - * - * @return string - */ - private function generateCachedKey($sKey) - { - return \sha1($sKey); - } -} +sKeyPrefix = $sKeyPrefix; + if (!empty($this->sKeyPrefix)) + { + $this->sKeyPrefix = + \preg_replace('/[^a-zA-Z0-9_]/', '_', rtrim(trim($this->sKeyPrefix), '\\/')).'/'; + } + } + + /** + * @param string $sKeyPrefix = '' + * + * @return \MailSo\Cache\Drivers\APC + */ + public static function NewInstance($sKeyPrefix = '') + { + return new self($sKeyPrefix); + } + + /** + * @param string $sKey + * @param string $sValue + * + * @return bool + */ + public function Set($sKey, $sValue) + { + return \apc_store($this->generateCachedKey($sKey), (string) $sValue); + } + + /** + * @param string $sKey + * + * @return string + */ + public function Get($sKey) + { + $sValue = \apc_fetch($this->generateCachedKey($sKey)); + return \is_string($sValue) ? $sValue : ''; + } + + /** + * @param string $sKey + * + * @return void + */ + public function Delete($sKey) + { + \apc_delete($this->generateCachedKey($sKey)); + } + + /** + * @param int $iTimeToClearInHours = 24 + * + * @return bool + */ + public function GC($iTimeToClearInHours = 24) + { + if (0 === $iTimeToClearInHours) + { + return \apc_clear_cache('user'); + } + + return false; + } + + /** + * @param string $sKey + * + * @return string + */ + private function generateCachedKey($sKey) + { + return $this->sKeyPrefix.\sha1($sKey); + } +} diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/File.php b/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/File.php index ec12a2e00..abdb125c1 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/File.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/File.php @@ -23,29 +23,43 @@ class File implements \MailSo\Cache\DriverInterface */ private $sCacheFolder; + /** + * @var string + */ + private $sKeyPrefix; + /** * @access private * * @param string $sCacheFolder + * @param string $sKeyPrefix = '' */ - private function __construct($sCacheFolder) + private function __construct($sCacheFolder, $sKeyPrefix = '') { $this->sCacheFolder = $sCacheFolder; $this->sCacheFolder = rtrim(trim($this->sCacheFolder), '\\/').'/'; - if (!\is_dir($this->sCacheFolder)) + + $this->sKeyPrefix = $sKeyPrefix; + if (!empty($this->sKeyPrefix)) { - @\mkdir($this->sCacheFolder, 0755); + $this->sKeyPrefix = \str_pad(\preg_replace('/[^a-zA-Z0-9_]/', '_', + rtrim(trim($this->sKeyPrefix), '\\/')), 5, '_'); + + $this->sKeyPrefix = '__/'. + \substr($this->sKeyPrefix, 0, 2).'/'.\substr($this->sKeyPrefix, 2, 2).'/'. + $this->sKeyPrefix.'/'; } } /** * @param string $sCacheFolder + * @param string $sKeyPrefix = '' * * @return \MailSo\Cache\Drivers\File */ - public static function NewInstance($sCacheFolder) + public static function NewInstance($sCacheFolder, $sKeyPrefix = '') { - return new self($sCacheFolder); + return new self($sCacheFolder, $sKeyPrefix); } /** @@ -121,7 +135,7 @@ class File implements \MailSo\Cache\DriverInterface $sKeyPath = \sha1($sKey); $sKeyPath = \substr($sKeyPath, 0, 2).'/'.\substr($sKeyPath, 2, 2).'/'.$sKeyPath; - $sFilePath = $this->sCacheFolder.$sKeyPath; + $sFilePath = $this->sCacheFolder.$this->sKeyPrefix.$sKeyPath; if ($bMkDir && !\is_dir(\dirname($sFilePath))) { if (!\mkdir(\dirname($sFilePath), 0755, true)) diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/Memcache.php b/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/Memcache.php index 05f5879be..35094b488 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/Memcache.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Cache/Drivers/Memcache.php @@ -1,129 +1,144 @@ -sHost = $sHost; - $this->iPost = $iPost; - $this->iExpire = 0 < $iExpire ? $iExpire : 43200; - - $this->oMem = new \Memcache(); - if (!$this->oMem->connect($this->sHost, $this->iPost)) - { - $this->oMem = null; - } - } - - /** - * @param string $sHost = '127.0.0.1' - * @param int $iPost = 11211 - * - * @return \MailSo\Cache\Drivers\APC - */ - public static function NewInstance($sHost = '127.0.0.1', $iPost = 11211) - { - return new self($sHost, $iPost); - } - - /** - * @param string $sKey - * @param string $sValue - * - * @return bool - */ - public function Set($sKey, $sValue) - { - return $this->oMem ? $this->oMem->set($this->generateCachedKey($sKey), $sValue, 0, $this->iExpire) : false; - } - - /** - * @param string $sKey - * - * @return string - */ - public function Get($sKey) - { - $sValue = $this->oMem ? $this->oMem->get($this->generateCachedKey($sKey)) : ''; - return \is_string($sValue) ? $sValue : ''; - } - - /** - * @param string $sKey - * - * @return void - */ - public function Delete($sKey) - { - if ($this->oMem) - { - $this->oMem->delete($this->generateCachedKey($sKey)); - } - } - - /** - * @param int $iTimeToClearInHours = 24 - * - * @return bool - */ - public function GC($iTimeToClearInHours = 24) - { - if (0 === $iTimeToClearInHours && $this->oMem) - { - return $this->oMem->flush(); - } - - return false; - } - - /** - * @param string $sKey - * - * @return string - */ - private function generateCachedKey($sKey) - { - return \sha1($sKey); - } -} +sHost = $sHost; + $this->iPost = $iPost; + $this->iExpire = 0 < $iExpire ? $iExpire : 43200; + + $this->oMem = new \Memcache(); + if (!$this->oMem->connect($this->sHost, $this->iPost)) + { + $this->oMem = null; + } + + $this->sKeyPrefix = $sKeyPrefix; + if (!empty($this->sKeyPrefix)) + { + $this->sKeyPrefix = + \preg_replace('/[^a-zA-Z0-9_]/', '_', rtrim(trim($this->sKeyPrefix), '\\/')).'/'; + } + } + + /** + * @param string $sHost = '127.0.0.1' + * @param int $iPost = 11211 + * @param int $iExpire = 43200 + * @param string $sKeyPrefix = '' + * + * @return \MailSo\Cache\Drivers\APC + */ + public static function NewInstance($sHost = '127.0.0.1', $iPost = 11211, $iExpire = 43200, $sKeyPrefix = '') + { + return new self($sHost, $iPost, $iExpire, $sKeyPrefix); + } + + /** + * @param string $sKey + * @param string $sValue + * + * @return bool + */ + public function Set($sKey, $sValue) + { + return $this->oMem ? $this->oMem->set($this->generateCachedKey($sKey), $sValue, 0, $this->iExpire) : false; + } + + /** + * @param string $sKey + * + * @return string + */ + public function Get($sKey) + { + $sValue = $this->oMem ? $this->oMem->get($this->generateCachedKey($sKey)) : ''; + return \is_string($sValue) ? $sValue : ''; + } + + /** + * @param string $sKey + * + * @return void + */ + public function Delete($sKey) + { + if ($this->oMem) + { + $this->oMem->delete($this->generateCachedKey($sKey)); + } + } + + /** + * @param int $iTimeToClearInHours = 24 + * + * @return bool + */ + public function GC($iTimeToClearInHours = 24) + { + if (0 === $iTimeToClearInHours && $this->oMem) + { + return $this->oMem->flush(); + } + + return false; + } + + /** + * @param string $sKey + * + * @return string + */ + private function generateCachedKey($sKey) + { + return $this->sKeyPrefix.\sha1($sKey); + } +} diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php b/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php index c6ae86ee5..1eec18afe 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php @@ -508,8 +508,9 @@ abstract class NetClient } else { -// $this->writeLog('Stream Meta: '. -// \print_r($aSocketStatus, true), \MailSo\Log\Enumerations\Type::ERROR); + $this->writeLog('Stream Meta: '. + \print_r($aSocketStatus, true), \MailSo\Log\Enumerations\Type::ERROR); + $this->writeLogException( new Exceptions\SocketReadException(), \MailSo\Log\Enumerations\Type::ERROR, true); diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php index 39f84a0fc..fb016c164 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -51,9 +51,9 @@ class Actions private $oSocial; /** - * @var \MailSo\Cache\CacheClient + * @var array of \MailSo\Cache\CacheClient */ - private $oCacher; + private $aCachers; /** * @var \RainLoop\Providers\Storage @@ -133,7 +133,7 @@ class Actions $this->oMailClient = null; $this->oSocial = null; $this->oConfig = null; - $this->oCacher = null; + $this->aCachers = array(); $this->oStorageProvider = null; $this->oLocalStorageProvider = null; @@ -623,7 +623,7 @@ class Actions 'token' === $aAdminHash[0] && \md5(APP_SALT) === $aAdminHash[1] ) { - $this->Cacher()->Delete(\RainLoop\KeyPathHelper::SessionAdminKey($aAdminHash[2])); + $this->Cacher(null, true)->Delete(\RainLoop\KeyPathHelper::SessionAdminKey($aAdminHash[2])); } \RainLoop\Utils::ClearCookie(self::AUTH_ADMIN_TOKEN_KEY); @@ -845,24 +845,44 @@ class Actions } /** + * @param \RainLoop\Model\Account $oAccount = null + * @param bool $bForceFile = false + * * @return \MailSo\Cache\CacheClient */ - public function Cacher() + public function Cacher($oAccount = null, $bForceFile = false) { - if (null === $this->oCacher) + $sKey = ''; + if ($oAccount) { - $this->oCacher = \MailSo\Cache\CacheClient::NewInstance(); + $sKey = $oAccount->ParentEmailHelper(); + } + + $sIndexKey = empty($sKey) ? '_default_' : $sKey; + if ($bForceFile) + { + $sIndexKey .= '/_files_'; + } + + if (!isset($this->aCachers[$sIndexKey])) + { + $this->aCachers[$sIndexKey] = \MailSo\Cache\CacheClient::NewInstance(); $oDriver = null; $sDriver = \strtoupper(\trim($this->Config()->Get('cache', 'fast_cache_driver', 'files'))); switch (true) { + default: + case $bForceFile: + $oDriver = \MailSo\Cache\Drivers\File::NewInstance(APP_PRIVATE_DATA.'cache', $sKey); + break; + case ('APC' === $sDriver || 'APCU' === $sDriver) && \MailSo\Base\Utils::FunctionExistsAndEnabled(array( 'apc_store', 'apc_fetch', 'apc_delete', 'apc_clear_cache')): - $oDriver = \MailSo\Cache\Drivers\APC::NewInstance(); + $oDriver = \MailSo\Cache\Drivers\APC::NewInstance($sKey); break; case ('MEMCACHE' === $sDriver || 'MEMCACHED' === $sDriver) && @@ -870,24 +890,21 @@ class Actions $oDriver = \MailSo\Cache\Drivers\Memcache::NewInstance( $this->Config()->Get('labs', 'fast_cache_memcache_host', '127.0.0.1'), - (int) $this->Config()->Get('labs', 'fast_cache_memcache_port', 11211) + (int) $this->Config()->Get('labs', 'fast_cache_memcache_port', 11211), + 43200, $sKey ); break; - - default: - $oDriver = \MailSo\Cache\Drivers\File::NewInstance(APP_PRIVATE_DATA.'cache'); - break; } if ($oDriver) { - $this->oCacher->SetDriver($oDriver); + $this->aCachers[$sIndexKey]->SetDriver($oDriver); } - $this->oCacher->SetCacheIndex($this->Config()->Get('cache', 'fast_cache_index', '')); + $this->aCachers[$sIndexKey]->SetCacheIndex($this->Config()->Get('cache', 'fast_cache_index', '')); } - return $this->oCacher; + return $this->aCachers[$sIndexKey]; } /** @@ -1011,7 +1028,7 @@ class Actions private function getAdminToken() { $sRand = \MailSo\Base\Utils::Md5Rand(); - if (!$this->Cacher()->Set(\RainLoop\KeyPathHelper::SessionAdminKey($sRand), \time())) + if (!$this->Cacher(null, true)->Set(\RainLoop\KeyPathHelper::SessionAdminKey($sRand), \time())) { $this->oLogger->Write('Cannot store an admin token', \MailSo\Log\Enumerations\Type::WARNING); @@ -1035,7 +1052,7 @@ class Actions $aAdminHash = \RainLoop\Utils::DecodeKeyValues($this->getAdminAuthToken()); if (!empty($aAdminHash[0]) && !empty($aAdminHash[1]) && !empty($aAdminHash[2]) && 'token' === $aAdminHash[0] && \md5(APP_SALT) === $aAdminHash[1] && - '' !== $this->Cacher()->Get(\RainLoop\KeyPathHelper::SessionAdminKey($aAdminHash[2]), '') + '' !== $this->Cacher(null, true)->Get(\RainLoop\KeyPathHelper::SessionAdminKey($aAdminHash[2]), '') ) { $bResult = true; @@ -3348,7 +3365,7 @@ class Actions { $sDomain = \trim(APP_SITE); - $oCacher = $this->Cacher(); + $oCacher = $this->Cacher(null, true); $oHttp = \MailSo\Base\Http::SingletonInstance(); if (0 === \strlen($sDomain) || $oHttp->CheckLocalhost($sDomain) || !$oCacher) @@ -6115,7 +6132,7 @@ class Actions $sFolderFullName = $this->GetActionParam('MessageFolder', ''); $sUid = $this->GetActionParam('MessageUid', ''); - $this->Cacher()->Set(\RainLoop\KeyPathHelper::ReadReceiptCache($oAccount->Email(), $sFolderFullName, $sUid), '1'); + $this->Cacher($oAccount)->Set(\RainLoop\KeyPathHelper::ReadReceiptCache($oAccount->Email(), $sFolderFullName, $sUid), '1'); if (0 < \strlen($sFolderFullName) && 0 < \strlen($sUid)) { @@ -8749,7 +8766,9 @@ class Actions */ private function cacherForUids() { - return ($this->Config()->Get('cache', 'enable', true) && $this->Config()->Get('cache', 'server_uids', false)) ? $this->Cacher() : null; + $oAccount = $this->getAccountFromToken(false); + return ($this->Config()->Get('cache', 'enable', true) && + $this->Config()->Get('cache', 'server_uids', false)) ? $this->Cacher($oAccount) : null; } /** @@ -8757,7 +8776,8 @@ class Actions */ private function cacherForThreads() { - return !!$this->Config()->Get('labs', 'use_imap_thread', false) ? $this->Cacher() : null; + $oAccount = $this->getAccountFromToken(false); + return !!$this->Config()->Get('labs', 'use_imap_thread', false) ? $this->Cacher($oAccount) : null; } /** @@ -9005,7 +9025,7 @@ class Actions catch (\Exception $oException) { unset($oException); } } - if (0 < \strlen($mResult['ReadReceipt']) && '1' === $this->Cacher()->Get( + if (0 < \strlen($mResult['ReadReceipt']) && '1' === $this->Cacher($oAccount)->Get( \RainLoop\KeyPathHelper::ReadReceiptCache($oAccount->Email(), $mResult['Folder'], $mResult['Uid']), '0')) { $mResult['ReadReceipt'] = '';