diff --git a/dev/App/Abstract.js b/dev/App/Abstract.js index 2e59b28aa..19a88db9a 100644 --- a/dev/App/Abstract.js +++ b/dev/App/Abstract.js @@ -244,6 +244,7 @@ } else { +// ko.components.register('Checkbox', require('Component/Classic/Checkbox')); ko.components.register('Checkbox', require('Component/Checkbox')); } diff --git a/dev/Common/Links.js b/dev/Common/Links.js index a00d84623..3040eb37c 100644 --- a/dev/Common/Links.js +++ b/dev/Common/Links.js @@ -16,7 +16,8 @@ this.sBase = '#/'; this.sServer = './?'; - this.sSubQuery = '&/s/=/'; + this.sSubQuery = '&s=/'; + this.sSubSubQuery = '&ss=/'; this.sVersion = Settings.settingsGet('Version'); this.sSpecSuffix = Settings.settingsGet('AuthAccountHash') || '0'; this.sStaticPrefix = Settings.settingsGet('StaticPrefix') || 'rainloop/v/' + this.sVersion + '/static/'; @@ -44,7 +45,7 @@ */ Links.prototype.attachmentDownload = function (sDownload) { - return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/Download/' + sDownload; + return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/Download/' + this.sSubSubQuery + sDownload; }; /** @@ -53,7 +54,7 @@ */ Links.prototype.attachmentPreview = function (sDownload) { - return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/View/' + sDownload; + return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/View/' + this.sSubSubQuery + sDownload; }; /** @@ -62,7 +63,7 @@ */ Links.prototype.attachmentPreviewAsPlain = function (sDownload) { - return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/ViewAsPlain/' + sDownload; + return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/ViewAsPlain/' + this.sSubSubQuery + sDownload; }; /** @@ -71,7 +72,7 @@ */ Links.prototype.attachmentFramed = function (sDownload) { - return this.sServer + '/Raw' + this.sSubQuery + this.sSpecSuffix + '/FramedView/' + sDownload; + return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/FramedView/' + this.sSubSubQuery + sDownload; }; /** @@ -130,7 +131,7 @@ */ Links.prototype.messageViewLink = function (sRequestHash) { - return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/ViewAsPlain/' + sRequestHash; + return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/ViewAsPlain/' + this.sSubSubQuery + sRequestHash; }; /** @@ -139,7 +140,7 @@ */ Links.prototype.messageDownloadLink = function (sRequestHash) { - return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/Download/' + sRequestHash; + return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/Download/' + this.sSubSubQuery + sRequestHash; }; /** diff --git a/dev/Component/Classic/Checkbox.js b/dev/Component/Classic/Checkbox.js new file mode 100644 index 000000000..1f9e9ce72 --- /dev/null +++ b/dev/Component/Classic/Checkbox.js @@ -0,0 +1,29 @@ + +(function () { + + 'use strict'; + + var + _ = require('_'), + + AbstracCheckbox = require('Component/AbstracCheckbox') + ; + + /** + * @constructor + * + * @param {Object} oParams + * + * @extends AbstracCheckbox + */ + function ClassicCheckboxComponent(oParams) + { + AbstracCheckbox.call(this, oParams); + } + + _.extend(ClassicCheckboxComponent.prototype, AbstracCheckbox.prototype); + + module.exports = AbstracCheckbox.componentExportHelper( + ClassicCheckboxComponent, 'CheckboxClassicComponent'); + +}()); diff --git a/dev/Screen/User/Settings.js b/dev/Screen/User/Settings.js index e56dd47a0..007b53bf2 100644 --- a/dev/Screen/User/Settings.js +++ b/dev/Screen/User/Settings.js @@ -81,7 +81,7 @@ 'SettingsSecurity', 'SETTINGS_LABELS/LABEL_SECURITY_NAME', 'security'); } - if (Settings.settingsGet('AllowGoogleSocial') || + if ((Settings.settingsGet('AllowGoogleSocial') && Settings.settingsGet('AllowGoogleSocialAuth')) || Settings.settingsGet('AllowFacebookSocial') || Settings.settingsGet('AllowTwitterSocial')) { diff --git a/dev/Styles/Main.less b/dev/Styles/Main.less index cacade686..1146ebecb 100644 --- a/dev/Styles/Main.less +++ b/dev/Styles/Main.less @@ -53,4 +53,9 @@ select:focus { html.mobile * { -webkit-tap-highlight-color: rgba(0,0,0,0); +} + +input::-ms-clear, +input::-ms-reveal { + display: none; } \ No newline at end of file diff --git a/dev/View/Admin/Login.js b/dev/View/Admin/Login.js index 57357ea55..f5aea3985 100644 --- a/dev/View/Admin/Login.js +++ b/dev/View/Admin/Login.js @@ -10,6 +10,7 @@ Enums = require('Common/Enums'), Utils = require('Common/Utils'), + Settings = require('Storage/Settings'), Remote = require('Storage/Admin/Remote'), kn = require('Knoin/Knoin'), @@ -24,6 +25,8 @@ { AbstractView.call(this, 'Center', 'AdminLogin'); + this.logoPowered = !!Settings.settingsGet('LoginPowered'); + this.login = ko.observable(''); this.password = ko.observable(''); diff --git a/package.json b/package.json index ca6d915dc..9bffb40a5 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "RainLoop", "title": "RainLoop Webmail", - "version": "1.6.10", - "release": "190", + "version": "1.6.11", + "release": "191", "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/Mail/FolderCollection.php b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php index 404439b5e..3aaffbbb6 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php @@ -63,7 +63,7 @@ class FolderCollection extends \MailSo\Base\Collection * * @return \MailSo\Mail\Folder|null */ - public function &GetByFullNameRaw($sFullNameRaw) + public function GetByFullNameRaw($sFullNameRaw) { $mResult = null; foreach ($this->aItems as /* @var $oFolder \MailSo\Mail\Folder */ $oFolder) @@ -73,6 +73,18 @@ class FolderCollection extends \MailSo\Base\Collection $mResult = $oFolder; break; } + else if ($oFolder->HasSubFolders()) + { + $mResult = $oFolder->SubFolders(true)->GetByFullNameRaw($sFullNameRaw); + if ($mResult) + { + break; + } + else + { + $mResult = null; + } + } } return $mResult; @@ -97,7 +109,7 @@ class FolderCollection extends \MailSo\Base\Collection return $this; } - + /** * @param array $aUnsortedMailFolders * diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php index 917e3a9e7..773819c14 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php @@ -2095,41 +2095,45 @@ class MailClient } /** - * @param string $sFolderNameInUtf + * @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($sFolderNameInUtf, $sFolderParentFullNameRaw = '', $bSubscribeOnCreation = true) + public function FolderCreate($sFolderNameInUtf8, $sFolderParentFullNameRaw = '', $bSubscribeOnCreation = true, $sDelimiter = '') { - if (!\MailSo\Base\Validator::NotEmptyString($sFolderNameInUtf, true) || + if (!\MailSo\Base\Validator::NotEmptyString($sFolderNameInUtf8, true) || !\is_string($sFolderParentFullNameRaw)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } - $sFolderNameInUtf = trim($sFolderNameInUtf); + $sFolderNameInUtf8 = \trim($sFolderNameInUtf8); - $aFolders = $this->oImapClient->FolderList('', 0 === \strlen(\trim($sFolderParentFullNameRaw)) ? 'INBOX' : $sFolderParentFullNameRaw); - if (!\is_array($aFolders) || !isset($aFolders[0])) + if (0 === \strlen($sDelimiter) || 0 < \strlen(\trim($sFolderParentFullNameRaw))) { - // TODO - throw new \MailSo\Mail\Exceptions\RuntimeException( - 0 === \strlen(trim($sFolderParentFullNameRaw)) - ? 'Cannot get folder delimiter' - : 'Cannot create folder in non-existen parent folder'); + $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; + } } - $sDelimiter = $aFolders[0]->Delimiter(); - if (0 < \strlen($sDelimiter) && 0 < \strlen(\trim($sFolderParentFullNameRaw))) - { - $sFolderParentFullNameRaw .= $sDelimiter; - } - - $sFullNameRawToCreate = \MailSo\Base\Utils::ConvertEncoding($sFolderNameInUtf, + $sFullNameRawToCreate = \MailSo\Base\Utils::ConvertEncoding($sFolderNameInUtf8, \MailSo\Base\Enumerations\Charset::UTF_8, \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Actions.php b/rainloop/v/0.0.0/app/src/RainLoop/Actions.php index 10c127adc..027041482 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Actions.php @@ -326,8 +326,11 @@ class Actions $sQuery = \trim(\trim($sQuery), ' /'); - $sSubQuerty = \trim(\trim($this->Http()->GetQuery('/s/', '')), ' /'); + $sSubQuerty = \trim(\trim($this->Http()->GetQuery('s', '')), ' /'); + $sSubSubQuerty = \trim(\trim($this->Http()->GetQuery('ss', '')), ' /'); + $sQuery .= 0 < \strlen($sSubQuerty) ? '/'.$sSubQuerty : ''; + $sQuery .= 0 < \strlen($sSubSubQuerty) ? '/'.$sSubSubQuerty : ''; if ('' === $this->GetSpecAuthToken()) { @@ -773,16 +776,22 @@ class Actions $oHttp = $this->Http(); $this->oLogger->Write('[DATE:'.\gmdate('d.m.y').'][RL:'.APP_VERSION.'][PHP:'.PHP_VERSION.'][IP:'. - $oHttp->GetClientIp().'][PID:'.(\MailSo\Base\Utils::FunctionExistsAndEnabled('getmypid') ? \getmypid() : 'unknown'). - '][GUID:'.\MailSo\Log\Logger::Guid().']'); - - $this->oLogger->Write( - '[APC:'.(\MailSo\Base\Utils::FunctionExistsAndEnabled('apc_fetch') ? 'on' : 'off').']'. - '[MB:'.(\MailSo\Base\Utils::FunctionExistsAndEnabled('mb_convert_encoding') ? 'on' : 'off').']'. - '[PDO:'.(\class_exists('PDO') ? \implode(',', \PDO::getAvailableDrivers()) : 'off').']'. - '['.\implode(',', \stream_get_transports()).']' + $oHttp->GetClientIp().'][PID:'.(\MailSo\Base\Utils::FunctionExistsAndEnabled('getmypid') ? \getmypid() : 'unknown').']['. + $oHttp->GetServer('SERVER_SOFTWARE', '~').']['. + (\MailSo\Base\Utils::FunctionExistsAndEnabled('php_sapi_name') ? \php_sapi_name() : '~' ).']' ); + $sPdo = (\class_exists('PDO') ? \implode(',', \PDO::getAvailableDrivers()) : 'off'); + $sPdo = empty($sPdo) ? '~' : $sPdo; + + $this->oLogger->Write('['. + 'Suhosin:'.(\extension_loaded('suhosin') || @\ini_get('suhosin.get.max_value_length') ? 'on' : 'off'). + '][APC:'.(\MailSo\Base\Utils::FunctionExistsAndEnabled('apc_fetch') ? 'on' : 'off'). + '][MB:'.(\MailSo\Base\Utils::FunctionExistsAndEnabled('mb_convert_encoding') ? 'on' : 'off'). + '][PDO:'.$sPdo. + '][Streams:'.\implode(',', \stream_get_transports()). + ']'); + $this->oLogger->Write( '['.$oHttp->GetMethod().'] '.$oHttp->GetScheme().'://'.$oHttp->GetHost(false, false).$oHttp->GetServer('REQUEST_URI', ''), \MailSo\Log\Enumerations\Type::NOTE, 'REQUEST'); @@ -977,7 +986,7 @@ class Actions static $bResult = null; if (null === $bResult) { - $bResult = $this->licenseParser($this->licenseHelper(false, true)); +// $bResult = $this->licenseParser($this->licenseHelper(false, true)); $bResult = true; } @@ -4009,7 +4018,7 @@ class Actions $aFolders =& $oFolders->GetAsArray(); if (\is_array($aFolders) && 0 < \count($aFolders)) { - if ($bListFolderTypes && false) + if ($bListFolderTypes) { foreach ($aFolders as $oFolder) { @@ -4042,7 +4051,7 @@ class Actions $sName = $oFolder->Name(); $sFullName = $oFolder->FullName(); - if (isset($aMap[$sName], $aMap[$sFullName])) + if (isset($aMap[$sName]) || isset($aMap[$sFullName])) { $iFolderType = isset($aMap[$sName]) ? $aMap[$sName] : $aMap[$sFullName]; if (!isset($aResult[$iFolderType]) && \in_array($iFolderType, array( @@ -4159,16 +4168,27 @@ class Actions } } - try + $sFullNameToCheck = \MailSo\Base\Utils::ConvertEncoding($mFolderNameToCreate, + \MailSo\Base\Enumerations\Charset::UTF_8, \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); + + if (0 < \strlen(\trim($sParent))) { - if ($this->MailClient()->FolderCreate($mFolderNameToCreate, $sParent)) - { - $bDoItAgain = true; - } + $sFullNameToCheck = $sParent.$sDelimiter.$sFullNameToCheck; } - catch (\Exception $oException) + + if (!$oFolderCollection->GetByFullNameRaw($sFullNameToCheck)) { - $this->Logger()->WriteException($oException); + try + { + if ($this->MailClient()->FolderCreate($mFolderNameToCreate, $sParent, true, $sDelimiter)) + { + $bDoItAgain = true; + } + } + catch (\Exception $oException) + { + $this->Logger()->WriteException($oException); + } } } } @@ -6492,8 +6512,9 @@ class Actions $aParams[2] = 'View'; \array_shift($aParams); + $sLast = \array_pop($aParams); - $sUrl = $this->Http()->GetFullUrl().'?/Raw/&/s/=/'.implode('/', $aParams); + $sUrl = $this->Http()->GetFullUrl().'?/Raw/&s=/'.implode('/', $aParams).'/&ss=/'.$sLast; $sFullUrl = 'http://docs.google.com/viewer?embedded=true&url='.urlencode($sUrl); @\header('Content-Type: text/html; charset=utf-8'); diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Config/Application.php b/rainloop/v/0.0.0/app/src/RainLoop/Config/Application.php index d8137583f..2f923d234 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Config/Application.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Config/Application.php @@ -55,6 +55,7 @@ class Application extends \RainLoop\Config\AbstractConfig protected function defaultValues() { return array( + 'webmail' => array( 'title' => array('RainLoop Webmail', 'Text displayed as page title'), @@ -188,9 +189,9 @@ Examples: ), 'social' => array( - 'google_enable' => array(false, 'Google'), - 'google_enable_auth' => array(true), - 'google_enable_drive' => array(true), + 'google_enable' => array(true, 'Google'), + 'google_enable_auth' => array(false), + 'google_enable_drive' => array(false), 'google_enable_preview' => array(true), 'google_client_id' => array(''), 'google_client_secret' => array(''), diff --git a/rainloop/v/0.0.0/app/src/RainLoop/ServiceActions.php b/rainloop/v/0.0.0/app/src/RainLoop/ServiceActions.php index 85d73fd34..2ca65d4dc 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/ServiceActions.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/ServiceActions.php @@ -408,6 +408,14 @@ class ServiceActions $sRawError = ''; } } + else + { + $sRawError = 'Unknown action "'.$sAction.'"'; + } + } + else + { + $sRawError = 'Empty action'; } } catch (\RainLoop\Exceptions\ClientException $oException) @@ -428,6 +436,7 @@ class ServiceActions 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) diff --git a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html index 7f5dd7637..b326a4021 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html +++ b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html @@ -33,6 +33,9 @@ +
diff --git a/rainloop/v/0.0.0/app/templates/Views/Components/CheckboxClassic.html b/rainloop/v/0.0.0/app/templates/Views/Components/CheckboxClassic.html new file mode 100644 index 000000000..d6e98a7ed --- /dev/null +++ b/rainloop/v/0.0.0/app/templates/Views/Components/CheckboxClassic.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/rainloop/v/0.0.0/app/templates/Views/User/Login.html b/rainloop/v/0.0.0/app/templates/Views/User/Login.html index 6e2369d89..1e43c6ff9 100644 --- a/rainloop/v/0.0.0/app/templates/Views/User/Login.html +++ b/rainloop/v/0.0.0/app/templates/Views/User/Login.html @@ -84,9 +84,9 @@ -