diff --git a/.gitignore b/.gitignore index 7b69a62d3..a0aa7bc75 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ /rainloop.sublime-project /rainloop.sublime-workspace /rainloop/v/0.0.0/static/css/*.css -/rainloop/v/0.0.0/static/js/*.js /rainloop/v/0.0.0/static/js/**/*.js /node_modules /build/local diff --git a/.jshintrc b/.jshintrc index 25fd75f03..969b1a4ad 100644 --- a/.jshintrc +++ b/.jshintrc @@ -51,6 +51,7 @@ "jquery" : true, "globals": { + "RL_COMMUNITY" : true, "module" : true, "require" : true, "ko" : true, diff --git a/dev/Common/Globals.js b/dev/Common/Globals.js index 3a4bfb5c1..a0ce66728 100644 --- a/dev/Common/Globals.js +++ b/dev/Common/Globals.js @@ -28,6 +28,11 @@ */ Globals.startMicrotime = (new window.Date()).getTime(); + /** + * @type {boolean} + */ + Globals.community = RL_COMMUNITY; + /** * @type {?} */ diff --git a/dev/Common/HtmlEditor.js b/dev/Common/HtmlEditor.js index 5653c675d..ef72b5096 100644 --- a/dev/Common/HtmlEditor.js +++ b/dev/Common/HtmlEditor.js @@ -103,7 +103,7 @@ */ HtmlEditor.prototype.clearSignatureSigns = function (sText) { - return sText.replace(/(\u0002|\u0003|\u200C|\u200D)/g, ''); + return sText.replace(/(\u200C||<\/x-signature>)/g, ''); }; /** diff --git a/dev/Common/Utils.js b/dev/Common/Utils.js index daf84d133..958814207 100644 --- a/dev/Common/Utils.js +++ b/dev/Common/Utils.js @@ -861,10 +861,7 @@ ; sText = sHtml - // specials for signature - .replace(/\u0002\u0002/g, '\u200C\u200C') - .replace(/\u0003\u0003/g, '\u200D\u200D') - + .replace(/([\s\S]*)<\/x-signature>/gm, '\u200C$1\u200C') .replace(/]*>([\s\S\r\n]*)<\/pre>/gmi, convertPre) .replace(/[\s]+/gm, ' ') .replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gmi, fixAttibuteValue) @@ -1012,16 +1009,12 @@ sPlain = aText.join("\n"); sPlain = sPlain - - // specials for signature - .replace(/\u200C\u200C/g, '\u0002\u0002') - .replace(/\u200D\u200D/g, '\u0003\u0003') - // .replace(/~~~\/blockquote~~~\n~~~blockquote~~~/g, '\n') .replace(/&/g, '&') .replace(/>/g, '>').replace(/') .replace(/[\s]*~~~\/blockquote~~~/g, '') + .replace(/\u200C([\s\S]*)\u200C/g, '$1') .replace(/\n/g, '
') ; diff --git a/dev/Screen/Admin/Settings.js b/dev/Screen/Admin/Settings.js index 71267ca4c..1b1e6a388 100644 --- a/dev/Screen/Admin/Settings.js +++ b/dev/Screen/Admin/Settings.js @@ -38,8 +38,16 @@ kn.addSettingsViewModel(require('Settings/Admin/Login'), 'AdminSettingsLogin', 'TABS_LABELS/LABEL_LOGIN_NAME', 'login'); - kn.addSettingsViewModel(require('Settings/Admin/Branding'), - 'AdminSettingsBranding', 'TABS_LABELS/LABEL_BRANDING_NAME', 'branding'); + if (RL_COMMUNITY) + { + kn.addSettingsViewModel(require('Settings/Admin/Branding'), + 'AdminSettingsBranding', 'TABS_LABELS/LABEL_BRANDING_NAME', 'branding'); + } + else + { + kn.addSettingsViewModel(require('Settings/Admin/Prem/Branding'), + 'AdminSettingsBranding', 'TABS_LABELS/LABEL_BRANDING_NAME', 'branding'); + } kn.addSettingsViewModel(require('Settings/Admin/Contacts'), 'AdminSettingsContacts', 'TABS_LABELS/LABEL_CONTACTS_NAME', 'contacts'); @@ -56,11 +64,14 @@ kn.addSettingsViewModel(require('Settings/Admin/Plugins'), 'AdminSettingsPlugins', 'TABS_LABELS/LABEL_PLUGINS_NAME', 'plugins'); - kn.addSettingsViewModel(require('Settings/Admin/Packages'), - 'AdminSettingsPackages', 'TABS_LABELS/LABEL_PACKAGES_NAME', 'packages'); + if (!RL_COMMUNITY) + { + kn.addSettingsViewModel(require('Settings/Admin/Prem/Packages'), + 'AdminSettingsPackages', 'TABS_LABELS/LABEL_PACKAGES_NAME', 'packages'); - kn.addSettingsViewModel(require('Settings/Admin/Licensing'), - 'AdminSettingsLicensing', 'TABS_LABELS/LABEL_LICENSING_NAME', 'licensing'); + kn.addSettingsViewModel(require('Settings/Admin/Prem/Licensing'), + 'AdminSettingsLicensing', 'TABS_LABELS/LABEL_LICENSING_NAME', 'licensing'); + } kn.addSettingsViewModel(require('Settings/Admin/About'), 'AdminSettingsAbout', 'TABS_LABELS/LABEL_ABOUT_NAME', 'about'); diff --git a/dev/Settings/.gitignore b/dev/Settings/.gitignore new file mode 100644 index 000000000..d686bd062 --- /dev/null +++ b/dev/Settings/.gitignore @@ -0,0 +1,2 @@ +/Admin/Prem/** +/Admin/_Prem/** \ No newline at end of file diff --git a/dev/Settings/Admin/About.js b/dev/Settings/Admin/About.js index acba4c6b4..2f65e6280 100644 --- a/dev/Settings/Admin/About.js +++ b/dev/Settings/Admin/About.js @@ -9,7 +9,8 @@ Translator = require('Common/Translator'), Settings = require('Storage/Settings'), - CoreStore = require('Stores/Admin/Core') + CoreStore = require('Stores/Admin/Core'), + AppStore = require('Stores/Admin/App') ; /** @@ -34,6 +35,8 @@ this.coreRemoteRelease = CoreStore.coreRemoteRelease; this.coreVersionCompare = CoreStore.coreVersionCompare; + this.community = RL_COMMUNITY || AppStore.community(); + this.coreRemoteVersionHtmlDesc = ko.computed(function () { Translator.trigger(); return Translator.i18n('TAB_ABOUT/HTML_NEW_VERSION', {'VERSION': this.coreRemoteVersion()}); @@ -78,7 +81,7 @@ AboutAdminSettings.prototype.onBuild = function () { - if (this.access()) + if (this.access() && !this.community) { require('App/Admin').reloadCoreData(); } @@ -86,7 +89,7 @@ AboutAdminSettings.prototype.updateCoreData = function () { - if (!this.coreUpdating()) + if (!this.coreUpdating() && !this.community) { require('App/Admin').updateCoreData(); } diff --git a/dev/Settings/Admin/Branding.js b/dev/Settings/Admin/Branding.js index 77429cfd7..d83cd123f 100644 --- a/dev/Settings/Admin/Branding.js +++ b/dev/Settings/Admin/Branding.js @@ -67,6 +67,8 @@ }); this.loginPowered = ko.observable(!!Settings.settingsGet('LoginPowered')); + + this.community = RL_COMMUNITY || AppStore.community(); } BrandingAdminSettings.prototype.onBuild = function () @@ -76,85 +78,6 @@ Remote = require('Remote/Admin/Ajax') ; - if (this.capa()) - { - _.delay(function () { - - var - f1 = Utils.settingsSaveHelperSimpleFunction(self.loginLogo.trigger, self), - f2 = Utils.settingsSaveHelperSimpleFunction(self.loginDescription.trigger, self), - f3 = Utils.settingsSaveHelperSimpleFunction(self.loginCss.trigger, self), - f4 = Utils.settingsSaveHelperSimpleFunction(self.userLogo.trigger, self), - f5 = Utils.settingsSaveHelperSimpleFunction(self.userLogoTitle.trigger, self), - f6 = Utils.settingsSaveHelperSimpleFunction(self.loginBackground.trigger, self), - f7 = Utils.settingsSaveHelperSimpleFunction(self.userCss.trigger, self), - f8 = Utils.settingsSaveHelperSimpleFunction(self.welcomePageUrl.trigger, self), - f9 = Utils.settingsSaveHelperSimpleFunction(self.welcomePageDisplay.trigger, self) - ; - - self.loginLogo.subscribe(function (sValue) { - Remote.saveAdminConfig(f1, { - 'LoginLogo': Utils.trim(sValue) - }); - }); - - self.loginDescription.subscribe(function (sValue) { - Remote.saveAdminConfig(f2, { - 'LoginDescription': Utils.trim(sValue) - }); - }); - - self.loginCss.subscribe(function (sValue) { - Remote.saveAdminConfig(f3, { - 'LoginCss': Utils.trim(sValue) - }); - }); - - self.userLogo.subscribe(function (sValue) { - Remote.saveAdminConfig(f4, { - 'UserLogo': Utils.trim(sValue) - }); - }); - - self.userLogoTitle.subscribe(function (sValue) { - Remote.saveAdminConfig(f5, { - 'UserLogoTitle': Utils.trim(sValue) - }); - }); - - self.loginBackground.subscribe(function (sValue) { - Remote.saveAdminConfig(f6, { - 'LoginBackground': Utils.trim(sValue) - }); - }); - - self.userCss.subscribe(function (sValue) { - Remote.saveAdminConfig(f7, { - 'UserCss': Utils.trim(sValue) - }); - }); - - self.welcomePageUrl.subscribe(function (sValue) { - Remote.saveAdminConfig(f8, { - 'WelcomePageUrl': Utils.trim(sValue) - }); - }); - - self.welcomePageDisplay.subscribe(function (sValue) { - Remote.saveAdminConfig(f9, { - 'WelcomePageDisplay': Utils.trim(sValue) - }); - }); - - self.loginPowered.subscribe(function (bValue) { - Remote.saveAdminConfig(null, { - 'LoginPowered': bValue ? '1' : '0' - }); - }); - - }, 50); - } - _.delay(function () { var diff --git a/dev/Settings/Admin/Licensing.js b/dev/Settings/Admin/Licensing.js deleted file mode 100644 index 15bd709f5..000000000 --- a/dev/Settings/Admin/Licensing.js +++ /dev/null @@ -1,84 +0,0 @@ - -(function () { - - 'use strict'; - - var - ko = require('ko'), - - Settings = require('Storage/Settings'), - LicenseStore = require('Stores/Admin/License') - ; - - /** - * @constructor - */ - function LicensingAdminSettings() - { - this.licensing = LicenseStore.licensing; - this.licensingProcess = LicenseStore.licensingProcess; - this.licenseValid = LicenseStore.licenseValid; - this.licenseExpired = LicenseStore.licenseExpired; - this.licenseError = LicenseStore.licenseError; - this.licenseTrigger = LicenseStore.licenseTrigger; - - this.adminDomain = ko.observable(''); - this.subscriptionEnabled = ko.observable(!!Settings.settingsGet('SubscriptionEnabled')); - - this.licenseTrigger.subscribe(function () { - if (this.subscriptionEnabled()) - { - require('App/Admin').reloadLicensing(true); - } - }, this); - } - - LicensingAdminSettings.prototype.onBuild = function () - { - if (this.subscriptionEnabled()) - { - require('App/Admin').reloadLicensing(false); - } - }; - - LicensingAdminSettings.prototype.onShow = function () - { - this.adminDomain(Settings.settingsGet('AdminDomain')); - }; - - LicensingAdminSettings.prototype.showActivationForm = function () - { - require('Knoin/Knoin').showScreenPopup(require('View/Popup/Activate')); - }; - - LicensingAdminSettings.prototype.showTrialForm = function () - { - require('Knoin/Knoin').showScreenPopup(require('View/Popup/Activate'), [true]); - }; - - /** - * @return {boolean} - */ - LicensingAdminSettings.prototype.licenseIsUnlim = function () - { - return 1898625600 === this.licenseExpired() || 1898625700 === this.licenseExpired(); - }; - - /** - * @return {string} - */ - LicensingAdminSettings.prototype.licenseExpiredMomentValue = function () - { - var - moment = require('moment'), - iTime = this.licenseExpired(), - oM = moment.unix(iTime) - ; - - return this.licenseIsUnlim() ? 'Never' : - (iTime && (oM.format('LL') + ' (' + oM.from(moment()) + ')')); - }; - - module.exports = LicensingAdminSettings; - -}()); \ No newline at end of file diff --git a/dev/Settings/Admin/Packages.js b/dev/Settings/Admin/Packages.js deleted file mode 100644 index f901f3b01..000000000 --- a/dev/Settings/Admin/Packages.js +++ /dev/null @@ -1,113 +0,0 @@ - -(function () { - - 'use strict'; - - var - window = require('window'), - _ = require('_'), - ko = require('ko'), - - Enums = require('Common/Enums'), - Translator = require('Common/Translator'), - - PackageStore = require('Stores/Admin/Package'), - Remote = require('Remote/Admin/Ajax') - ; - - /** - * @constructor - */ - function PackagesAdminSettings() - { - this.packagesError = ko.observable(''); - - this.packages = PackageStore.packages; - this.packagesReal = PackageStore.packagesReal; - this.packagesMainUpdatable = PackageStore.packagesMainUpdatable; - - this.packagesCurrent = this.packages.filter(function (oItem) { - return oItem && '' !== oItem['installed'] && !oItem['compare']; - }); - - this.packagesAvailableForUpdate = this.packages.filter(function (oItem) { - return oItem && '' !== oItem['installed'] && !!oItem['compare']; - }); - - this.packagesAvailableForInstallation = this.packages.filter(function (oItem) { - return oItem && '' === oItem['installed']; - }); - - this.visibility = ko.computed(function () { - return PackageStore.packages.loading() ? 'visible' : 'hidden'; - }, this); - } - - PackagesAdminSettings.prototype.onShow = function () - { - this.packagesError(''); - }; - - PackagesAdminSettings.prototype.onBuild = function () - { - require('App/Admin').reloadPackagesList(); - }; - - PackagesAdminSettings.prototype.requestHelper = function (oPackage, bInstall) - { - var self = this; - return function (sResult, oData) { - - if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) - { - if (oData && oData.ErrorCode) - { - self.packagesError(Translator.getNotification(oData.ErrorCode)); - } - else - { - self.packagesError(Translator.getNotification( - bInstall ? Enums.Notification.CantInstallPackage : Enums.Notification.CantDeletePackage)); - } - } - - _.each(self.packages(), function (oItem) { - if (oItem && oPackage && oItem['loading']() && oPackage['file'] === oItem['file']) - { - oPackage['loading'](false); - oItem['loading'](false); - } - }); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result['Reload']) - { - window.location.reload(); - } - else - { - require('App/Admin').reloadPackagesList(); - } - }; - }; - - PackagesAdminSettings.prototype.deletePackage = function (oPackage) - { - if (oPackage) - { - oPackage['loading'](true); - Remote.packageDelete(this.requestHelper(oPackage, false), oPackage); - } - }; - - PackagesAdminSettings.prototype.installPackage = function (oPackage) - { - if (oPackage) - { - oPackage['loading'](true); - Remote.packageInstall(this.requestHelper(oPackage, true), oPackage); - } - }; - - module.exports = PackagesAdminSettings; - -}()); \ No newline at end of file diff --git a/dev/Settings/Admin/Plugins.js b/dev/Settings/Admin/Plugins.js index f15c7637c..c955eff04 100644 --- a/dev/Settings/Admin/Plugins.js +++ b/dev/Settings/Admin/Plugins.js @@ -12,7 +12,10 @@ Translator = require('Common/Translator'), Settings = require('Storage/Settings'), + + AppStore = require('Stores/Admin/App'), PluginStore = require('Stores/Admin/Plugin'), + Remote = require('Remote/Admin/Ajax') ; @@ -26,6 +29,8 @@ this.plugins = PluginStore.plugins; this.pluginsError = PluginStore.plugins.error; + this.community = RL_COMMUNITY || AppStore.community(); + this.visibility = ko.computed(function () { return PluginStore.plugins.loading() ? 'visible' : 'hidden'; }, this); diff --git a/dev/Stores/App.js b/dev/Stores/App.js index 45b560689..28e70b1f8 100644 --- a/dev/Stores/App.js +++ b/dev/Stores/App.js @@ -29,6 +29,7 @@ this.interfaceAnimation.valueHasMutated(); this.prem = ko.observable(false); + this.community = ko.observable(true); } AppStore.prototype.populate = function() @@ -39,6 +40,7 @@ this.interfaceAnimation(!!Settings.settingsGet('InterfaceAnimation')); this.prem(!!Settings.settingsGet('PremType')); + this.community(!!Settings.settingsGet('Community')); }; module.exports = AppStore; diff --git a/dev/View/Admin/Settings/Pane.js b/dev/View/Admin/Settings/Pane.js index fa6ff52a2..929ee0c67 100644 --- a/dev/View/Admin/Settings/Pane.js +++ b/dev/View/Admin/Settings/Pane.js @@ -26,6 +26,7 @@ this.version = ko.observable(Settings.settingsGet('Version')); this.capa = !!Settings.settingsGet('PremType'); + this.community = RL_COMMUNITY; this.adminManLoading = ko.computed(function () { return '000' !== [ diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js index c61332277..2f4955e5b 100644 --- a/dev/View/User/MailBox/MessageList.js +++ b/dev/View/User/MailBox/MessageList.js @@ -299,6 +299,11 @@ { var self = this; + if (0 < this.messageListChecked().length) + { + return false; + } + window.clearTimeout(this.iGoToUpUpOrDownDownTimeout); this.iGoToUpUpOrDownDownTimeout = window.setTimeout(function () { diff --git a/dev/bootstrap.js b/dev/bootstrap.js index d88505169..e039ce7cc 100644 --- a/dev/bootstrap.js +++ b/dev/bootstrap.js @@ -82,7 +82,7 @@ } window['__APP_BOOT'] = null; - + }, 10)); }; diff --git a/gulpfile.js b/gulpfile.js index 95fc4ab7d..8254453a8 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -6,6 +6,7 @@ var cfg = { devVersion: '0.0.0', releasesPath: 'build/dist/releases', + community: true, rainloopBuilded: false, destPath: '', @@ -220,6 +221,16 @@ gulp.task('css:main-begin', ['less:main'], function() { ; }); +gulp.task('package:community-on', function() { + cfg.community = true; + return true; +}); + +gulp.task('package:community-off', function() { + cfg.community = false; + return true; +}); + gulp.task('css:clear-less', ['css:main-begin'], function() { return gulp.src(cfg.paths.staticCSS + cfg.paths.less.main.name, {read: false}) @@ -290,6 +301,7 @@ gulp.task('js:webpack:clear', function() { }); gulp.task('js:webpack', ['js:webpack:clear'], function(callback) { + var webpack = require('webpack'), webpackCfg = require('./webpack.config.js') @@ -300,6 +312,13 @@ gulp.task('js:webpack', ['js:webpack:clear'], function(callback) { webpackCfg.output.publicPath = cfg.paths.staticJS; } + if (webpackCfg && webpackCfg.plugins) + { + webpackCfg.plugins.push(new webpack.DefinePlugin({ + 'RL_COMMUNITY': !!cfg.community + })); + } + webpack(webpackCfg, function(err, stats) { if (err) { throw new gutil.PluginError('webpack', err); @@ -466,7 +485,7 @@ gulp.task('rainloop:setup', ['rainloop:copy'], function() { cfg.destPath = cfg.releasesPath + '/webmail/' + versionFull + '/'; cfg.cleanPath = dist; cfg.zipSrcPath = dist; - cfg.zipFile = 'rainloop-' + versionFull + '.zip'; + cfg.zipFile = 'rainloop-' + (cfg.community ? 'community-' : '') + versionFull + '.zip'; cfg.md5File = cfg.zipFile; cfg.rainloopBuilded = true; @@ -538,7 +557,7 @@ gulp.task('rainloop:owncloud:setup', ['rainloop:owncloud:copy', cfg.destPath = cfg.releasesPath + '/owncloud/' + versionFull + '/'; cfg.cleanPath = dist; cfg.zipSrcPath = dist; - cfg.zipFile = 'rainloop-owncloud-app-' + versionFull + '.zip'; + cfg.zipFile = 'rainloop-owncloud-app-' + (cfg.community ? '' : 'premium-') + versionFull + '.zip'; cfg.md5File = cfg.zipFile; }); @@ -562,12 +581,16 @@ gulp.task('default', ['js:libs', 'js:boot', 'js:openpgp', 'js:min', 'css:main:mi gulp.task('fast', ['js:app', 'js:admin', 'js:chunks', 'css:main']); gulp.task('rainloop:start', ['js:lint', 'rainloop:copy', 'rainloop:setup']); -gulp.task('rainloop', ['rainloop:start', 'rainloop:zip', 'rainloop:md5', 'rainloop:clean']); -gulp.task('owncloud', ['rainloop:owncloud:copy', +gulp.task('rainloop', ['package:community-on', 'rainloop:start', 'rainloop:zip', 'rainloop:md5', 'rainloop:clean']); +gulp.task('rainloop+', ['package:community-off', 'rainloop']); + +gulp.task('owncloud', ['package:community-on', 'rainloop:owncloud:copy', 'rainloop:owncloud:copy-rainloop', 'rainloop:owncloud:copy-rainloop:clean', 'rainloop:owncloud:setup', 'rainloop:owncloud:zip', 'rainloop:owncloud:md5', 'rainloop:owncloud:clean']); +gulp.task('owncloud+', ['package:community-off', 'owncloud']); + //WATCH gulp.task('watch', ['fast'], function() { gulp.watch(cfg.paths.globjs, {interval: 1000}, ['js:app', 'js:admin']); @@ -578,10 +601,10 @@ gulp.task('watch', ['fast'], function() { gulp.task('build', ['rainloop']); gulp.task('js:hint', ['js:lint']); -gulp.task('own', ['owncloud']); -gulp.task('rl', ['rainloop']); gulp.task('w', ['watch']); gulp.task('f', ['fast']); -gulp.task('o', ['owncloud']); gulp.task('b', ['build']); +gulp.task('b+', ['build+']); +gulp.task('o', ['owncloud']); +gulp.task('o+', ['owncloud+']); gulp.task('h', ['js:lint']); \ No newline at end of file diff --git a/package.json b/package.json index dab47ba51..a25ef1b1d 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "RainLoop", "title": "RainLoop Webmail", - "version": "1.8.4", - "release": "314", + "version": "1.9.0", + "release": "315", "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/RainLoop/.gitignore b/rainloop/v/0.0.0/app/libraries/RainLoop/.gitignore new file mode 100644 index 000000000..416618dd3 --- /dev/null +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/.gitignore @@ -0,0 +1,2 @@ +/Prem/** +/_Prem/** \ No newline at end of file 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 a1a28f6ab..499bd9487 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -110,6 +110,11 @@ class Actions */ private $oTwoFactorAuthProvider; + /** + * @var \RainLoop\Providers\Prem + */ + private $oPremProvider; + /** * @var \RainLoop\Config\Application */ @@ -146,6 +151,7 @@ class Actions $this->oSuggestionsProvider = null; $this->oChangePasswordProvider = null; $this->oTwoFactorAuthProvider = null; + $this->oPremProvider = null; $this->sSpecAuthToken = ''; @@ -738,6 +744,28 @@ class Actions return $this->oTwoFactorAuthProvider; } + /** + * @return \RainLoop\Providers\Prem + */ + public function PremProvider() + { + if (null === $this->oPremProvider) + { + if (\file_exists(APP_VERSION_ROOT_PATH.'app/libraries/RainLoop/Prem/Provider.php')) + { + $this->oPremProvider = new \RainLoop\Prem\Provider( + $this->Config(), $this->Logger(), $this->Cacher(null, true) + ); + } + else + { + $this->oPremProvider = false; + } + } + + return $this->oPremProvider; + } + /** * @param bool $bLocal = false * @@ -1248,20 +1276,6 @@ class Actions return $this->GetAccountFromCustomToken($this->getAuthToken(), $bThrowExceptionOnFalse); } - /** - * @return bool - */ - private function PremType() - { - static $bResult = null; - if (null === $bResult) - { - $bResult = $this->licenseParser($this->licenseHelper(false, true)); - } - - return $bResult; - } - /** * @param bool $bAdmin * @param string $sAuthAccountHash = '' @@ -1278,6 +1292,8 @@ class Actions $oAccount = null; $oConfig = $this->Config(); + $oPremProvider = $this->PremProvider(); + $aResult = array( 'Version' => APP_VERSION, 'Auth' => false, @@ -1329,7 +1345,8 @@ class Actions 'UseImapSubscribe' => (bool) $oConfig->Get('labs', 'use_imap_list_subscribe', true), 'AllowAppendMessage' => (bool) $oConfig->Get('labs', 'allow_message_append', false), 'MaterialDesign' => (bool) $oConfig->Get('labs', 'use_material_design', true), - 'PremType' => $this->PremType(), + 'Community' => true, + 'PremType' => false, 'Admin' => array(), 'Capa' => array(), 'AttahcmentsActions' => array(), @@ -1383,21 +1400,15 @@ class Actions $aResult['Title'] = $oConfig->Get('webmail', 'title', ''); $aResult['LoadingDescription'] = $oConfig->Get('webmail', 'loading_description', ''); - if ($this->PremType()) + if ($oPremProvider) { - $aResult['LoginLogo'] = $oConfig->Get('branding', 'login_logo', ''); - $aResult['LoginBackground'] = $oConfig->Get('branding', 'login_background', ''); - $aResult['LoginCss'] = $oConfig->Get('branding', 'login_css', ''); - $aResult['LoginDescription'] = $oConfig->Get('branding', 'login_desc', ''); - $aResult['LoginPowered'] = !!$oConfig->Get('branding', 'login_powered', true); - $aResult['UserLogo'] = $oConfig->Get('branding', 'user_logo', ''); - $aResult['UserLogoTitle'] = $oConfig->Get('branding', 'user_logo_title', ''); - $aResult['UserCss'] = $oConfig->Get('branding', 'user_css', ''); - $aResult['WelcomePageUrl'] = $oConfig->Get('branding', 'welcome_page_url', ''); - $aResult['WelcomePageDisplay'] = \strtolower($oConfig->Get('branding', 'welcome_page_display', 'none')); + $oPremProvider->PopulateAppData($aResult); } - $aResult['LoadingDescriptionEsc'] = \htmlspecialchars($aResult['LoadingDescription'], ENT_QUOTES|ENT_IGNORE, 'UTF-8'); + if ('' !== $aResult['LoadingDescription'] && 'RainLoop' !== $aResult['LoadingDescription']) + { + $aResult['LoadingDescriptionEsc'] = @\htmlspecialchars($aResult['LoadingDescription'], ENT_QUOTES|ENT_IGNORE, 'UTF-8'); + } $oSettings = null; $oSettingsLocal = null; @@ -3318,7 +3329,11 @@ class Actions } else if ($bVersionsCache) { - $this->removeOldVersion(); + $oPremProvider = $this->PremProvider(); + if ($oPremProvider) + { + $oPremProvider->ClearOldVersion(); + } } $this->Plugins()->RunHook('service.app-delay-start-end'); @@ -3354,7 +3369,7 @@ class Actions * @param string $sType = 'string' * @param callable|null $mStringCallback = null */ - private function setConfigFromParams(&$oConfig, $sParamName, $sConfigSector, $sConfigName, $sType = 'string', $mStringCallback = null) + public function setConfigFromParams(&$oConfig, $sParamName, $sConfigSector, $sConfigName, $sType = 'string', $mStringCallback = null) { $sValue = $this->GetActionParam($sParamName, ''); if ($this->HasActionParam($sParamName)) @@ -3531,26 +3546,6 @@ class Actions $this->setConfigFromParams($oConfig, 'Title', 'webmail', 'title', 'string'); $this->setConfigFromParams($oConfig, 'LoadingDescription', 'webmail', 'loading_description', 'string'); - if ($this->HasOneOfActionParams(array( - 'LoginLogo', 'LoginBackground', 'LoginDescription', 'LoginCss', 'LoginPowered', - 'UserLogo', 'UserLogoTitle', 'UserCss', - 'WelcomePageUrl', 'WelcomePageDisplay' - )) && $this->PremType()) - { - $this->setConfigFromParams($oConfig, 'LoginLogo', 'branding', 'login_logo', 'string'); - $this->setConfigFromParams($oConfig, 'LoginBackground', 'branding', 'login_background', 'string'); - $this->setConfigFromParams($oConfig, 'LoginDescription', 'branding', 'login_desc', 'string'); - $this->setConfigFromParams($oConfig, 'LoginCss', 'branding', 'login_css', 'string'); - $this->setConfigFromParams($oConfig, 'LoginPowered', 'branding', 'login_powered', 'bool'); - - $this->setConfigFromParams($oConfig, 'UserLogo', 'branding', 'user_logo', 'string'); - $this->setConfigFromParams($oConfig, 'UserLogoTitle', 'branding', 'user_logo_title', 'string'); - $this->setConfigFromParams($oConfig, 'UserCss', 'branding', 'user_css', 'string'); - - $this->setConfigFromParams($oConfig, 'WelcomePageUrl', 'branding', 'welcome_page_url', 'string'); - $this->setConfigFromParams($oConfig, 'WelcomePageDisplay', 'branding', 'welcome_page_display', 'string'); - } - $this->setConfigFromParams($oConfig, 'TokenProtection', 'security', 'csrf_protection', 'bool'); $this->setConfigFromParams($oConfig, 'EnabledPlugins', 'plugins', 'enable', 'bool'); @@ -3573,6 +3568,12 @@ class Actions $this->setConfigFromParams($oConfig, 'DropboxEnable', 'social', 'dropbox_enable', 'bool'); $this->setConfigFromParams($oConfig, 'DropboxApiKey', 'social', 'dropbox_api_key', 'string'); + $oPremProvider = $this->PremProvider(); + if ($oPremProvider) + { + $oPremProvider->PremSection($this, $oConfig); + } + return $this->DefaultResponse(__FUNCTION__, $oConfig->Save()); } @@ -3647,144 +3648,6 @@ class Actions )); } - /** - * @param string $sDomain - * - * @return string - */ -// public function domainPathHelper($sDomain) -// { -// $sDomain = \strtolower(\trim($sDomain)); -// -// $sTempDomain = \preg_replace('/^(webmail|email|mail)\./', '', $sDomain); -// if (false === \strpos($sTempDomain, '.')) -// { -// $sTempDomain = $sDomain; -// } -// -// $sDomainPrefix = $sTempDomain; -// if (false === \strpos($sDomainPrefix, '.')) -// { -// $sDomainPrefix = $sTempDomain; -// } -// -// $sDomainPrefix = \substr(\preg_replace('/[^a-z0-9]+/', '', $sDomainPrefix), 0, 2); -// $sDomainPrefix = \str_pad($sDomainPrefix, 2, '_'); -// -// return 'd/'.\substr($sDomainPrefix, 0, 1).'/'.$sDomainPrefix.'/'.\urlencode($sTempDomain); -// } - - /** - * @return string - */ - public function licenseHelper($sForce = false, $bLongCache = false, $iFastCacheTimeInMin = 10, $iLongCacheTimeInDays = 3) - { - $sDomain = \trim(APP_SITE); - - $oCacher = $this->Cacher(null, true); - $oHttp = \MailSo\Base\Http::SingletonInstance(); - - if (0 === \strlen($sDomain) || $oHttp->CheckLocalhost($sDomain) || !$oCacher || !$oCacher->Verify(true)) - { - return 'NO'; - } - - $sDomainKeyValue = \RainLoop\KeyPathHelper::LicensingDomainKeyValue($sDomain); - $sDomainLongKeyValue = \RainLoop\KeyPathHelper::LicensingDomainKeyOtherValue($sDomain); - - $sValue = ''; - if (!$sForce) - { - if ($bLongCache) - { - $bLock = $oCacher->GetLock($sDomainLongKeyValue); - $iTime = $bLock ? 0 : $oCacher->GetTimer($sDomainLongKeyValue); - - if ($bLock || (0 < $iTime && \time() < $iTime + (60 * 60 * 24) * $iLongCacheTimeInDays)) - { - $sValue = $oCacher->Get($sDomainLongKeyValue); - } - } - else - { - $iTime = $oCacher->GetTimer($sDomainKeyValue); - if (0 < $iTime && \time() < $iTime + 60 * $iFastCacheTimeInMin) - { - $sValue = $oCacher->Get($sDomainKeyValue); - } - } - } - - if (0 === \strlen($sValue)) - { - if ($bLongCache) - { - if (!$oCacher->SetTimer($sDomainLongKeyValue)) - { - return 'NO'; - } - - $oCacher->SetLock($sDomainLongKeyValue); - } - - $iCode = 0; - $sContentType = ''; - -// $sValue = $oHttp->GetUrlAsString(APP_STATUS_PATH.$this->domainPathHelper($sDomain), -// 'RainLoop/'.APP_VERSION, $sContentType, $iCode, $this->Logger(), 5, -// $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', ''), -// array(), false -// ); - - $sValue = $oHttp->GetUrlAsString(APP_API_PATH.'status/'.\urlencode($sDomain), - 'RainLoop/'.APP_VERSION, $sContentType, $iCode, $this->Logger(), 5, - $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', ''), - array(), false - ); - - $this->Logger()->Write($sValue); - - /*if (404 === $iCode) - { - $sValue = 'NO'; - } - else */if (200 !== $iCode) - { - $sValue = ''; - } - - $oCacher->SetTimer($sDomainKeyValue); - - $oCacher->Set($sDomainKeyValue, $sValue); - $oCacher->Set($sDomainLongKeyValue, $sValue); - - if ($bLongCache) - { - $oCacher->RemoveLock($sDomainLongKeyValue); - } - } - - return $sValue; - } - - /** - * @param string $sInput - * @param int $iExpired = 0 - * - * @return bool - */ - public function licenseParser($sInput, &$iExpired = 0) - { - $aMatch = array(); - if (\preg_match('/^EXPIRED:([\d]+)$/', $sInput, $aMatch)) - { - $iExpired = (int) $aMatch[1]; - return \time() < $iExpired; - } - - return false; - } - /** * @return array */ @@ -3797,14 +3660,16 @@ class Actions $mResult = false; $iErrorCode = -1; - if (2 < \strlen(APP_SITE)) + $oPremProvider = $this->PremProvider(); + + if ($oPremProvider && 2 < \strlen(APP_SITE)) { - $sValue = $this->licenseHelper($bForce); + $sValue = $oPremProvider->Fetcher($bForce); $this->requestSleep(); $iExpired = 0; - if ($this->licenseParser($sValue, $iExpired)) + if ($oPremProvider->Parser($sValue, $iExpired)) { $mResult = array( 'Banned' => false, @@ -3846,23 +3711,12 @@ class Actions $mResult = false; $iErrorCode = -1; - if (2 < \strlen($sDomain) && 2 < \strlen($sKey) && $sDomain === APP_SITE) + $oPrem = $this->PremProvider(); + + if ($oPrem && 2 < \strlen($sDomain) && 2 < \strlen($sKey) && $sDomain === APP_SITE) { $iCode = 0; - $sContentType = ''; - - $oHttp = \MailSo\Base\Http::SingletonInstance(); - - $sValue = $oHttp->GetUrlAsString(APP_API_PATH.'activate/'.\urlencode($sDomain).'/'.\urlencode($sKey), - 'RainLoop/'.APP_VERSION, $sContentType, $iCode, $this->Logger(), 10, - $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', ''), - array(), false - ); - - if (200 !== $iCode) - { - $sValue = ''; - } + $sValue = $oPrem->Activate($sDomain, $sKey, $iCode); $this->requestSleep(); @@ -3878,6 +3732,7 @@ class Actions else if (\preg_match('/^ERROR:(.+)$/', $sValue, $aMatch) && !empty($aMatch[1])) { $mResult = trim($aMatch[1]); + $this->Logger()->Write('Activation error for: '.$sKey.' ('.$sDomain.')', \MailSo\Log\Enumerations\Type::ERROR); $this->Logger()->Write($mResult, \MailSo\Log\Enumerations\Type::ERROR); } @@ -4479,10 +4334,10 @@ class Actions $this->IsAdminLoggined(); $bReal = false; - $sNewVersion = ''; $bRainLoopUpdatable = $this->rainLoopUpdatable(); $bRainLoopAccess = $this->rainLoopCoreAccess(); + $oPremProvider = $this->PremProvider(); $aData = array(); if ($bRainLoopUpdatable && $bRainLoopAccess) @@ -4491,132 +4346,14 @@ class Actions } $bResult = false; - if ($bReal && !empty($aData['file'])) + if ($bReal && $oPremProvider && !empty($aData['file'])) { - $sTmp = $this->downloadRemotePackageByUrl($aData['file']); - if (!empty($sTmp)) - { - include_once APP_VERSION_ROOT_PATH.'app/libraries/pclzip/pclzip.lib.php'; - - $oArchive = new \PclZip($sTmp); - $sTmpFolder = APP_PRIVATE_DATA.\md5($sTmp); - - \mkdir($sTmpFolder); - if (\is_dir($sTmpFolder)) - { - $bResult = 0 !== $oArchive->extract(PCLZIP_OPT_PATH, $sTmpFolder); - if (!$bResult) - { - $this->Logger()->Write('Cannot extract package files: '.$oArchive->errorInfo(), \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); - } - - if ($bResult && \file_exists($sTmpFolder.'/index.php') && - \is_writable(APP_INDEX_ROOT_PATH.'rainloop/') && - \is_writable(APP_INDEX_ROOT_PATH.'index.php') && - \is_dir($sTmpFolder.'/rainloop/')) - { - $aMatch = array(); - $sIndexFile = \file_get_contents($sTmpFolder.'/index.php'); - if (\preg_match('/\'APP_VERSION\', \'([^\']+)\'/', $sIndexFile, $aMatch) && !empty($aMatch[1])) - { - $sNewVersion = \trim($aMatch[1]); - } - - if (empty($sNewVersion)) - { - $this->Logger()->Write('Unknown version', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); - } - else if (!\is_dir(APP_INDEX_ROOT_PATH.'rainloop/v/'.$sNewVersion)) - { - \MailSo\Base\Utils::CopyDir($sTmpFolder.'/rainloop/', APP_INDEX_ROOT_PATH.'rainloop/'); - - if (\is_dir(APP_INDEX_ROOT_PATH.'rainloop/v/'.$sNewVersion) && - \is_file(APP_INDEX_ROOT_PATH.'rainloop/v/'.$sNewVersion.'/index.php')) - { - $bResult = \copy($sTmpFolder.'/index.php', APP_INDEX_ROOT_PATH.'index.php'); - - if ($bResult) - { - if (\MailSo\Base\Utils::FunctionExistsAndEnabled('opcache_invalidate')) - { - @\opcache_invalidate(APP_INDEX_ROOT_PATH.'index.php', true); - } - - if (\MailSo\Base\Utils::FunctionExistsAndEnabled('apc_delete_file')) - { - @\apc_delete_file(APP_INDEX_ROOT_PATH.'index.php'); - } - } - } - else - { - $this->Logger()->Write('Cannot copy new package files', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); - $this->Logger()->Write($sTmpFolder.'/rainloop/ -> '.APP_INDEX_ROOT_PATH.'rainloop/', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); - } - } - else if (!empty($sNewVersion)) - { - $this->Logger()->Write('"'.$sNewVersion.'" version already installed', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); - } - } - else if ($bResult) - { - $this->Logger()->Write('Cannot validate package files', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); - } - - \MailSo\Base\Utils::RecRmDir($sTmpFolder); - } - else - { - $this->Logger()->Write('Cannot create tmp folder: '.$sTmpFolder, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); - } - - @\unlink($sTmp); - } + $bResult = $oPremProvider->UpdateCore($this, $aData['file']); } return $this->DefaultResponse(__FUNCTION__, $bResult); } - public function removeOldVersion() - { - $sVPath = APP_INDEX_ROOT_PATH.'rainloop/v/'; - - $this->Logger()->Write('Versions GC: Begin'); - - $aDirs = @\array_map('basename', @\array_filter(@\glob($sVPath.'*'), 'is_dir')); - - $this->Logger()->Write('Versions GC: Count:'.(\is_array($aDirs) ? \count($aDirs) : 0)); - - if (\is_array($aDirs) && 5 < \count($aDirs)) - { - \uasort($aDirs, 'version_compare'); - - foreach ($aDirs as $sName) - { - if (APP_DEV_VERSION !== $sName && APP_VERSION !== $sName) - { - $this->Logger()->Write('Versions GC: Begin to remove "'.$sVPath.$sName.'" version'); - - if (@\unlink($sVPath.$sName.'/index.php')) - { - @\MailSo\Base\Utils::RecRmDir($sVPath.$sName); - } - else - { - $this->Logger()->Write('Versions GC (Error): index file cant be removed from"'.$sVPath.$sName.'"', - \MailSo\Log\Enumerations\Type::ERROR); - } - - $this->Logger()->Write('Versions GC: End to remove "'.$sVPath.$sName.'" version'); - break; - } - } - } - - $this->Logger()->Write('Versions GC: End'); - } - /** * @return array */ @@ -4658,7 +4395,7 @@ class Actions * * @return string */ - private function downloadRemotePackageByUrl($sUrl) + public function downloadRemotePackageByUrl($sUrl) { $bResult = false; $sTmp = APP_PRIVATE_DATA.\md5(\microtime(true).$sUrl).'.zip'; diff --git a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminPane.html b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminPane.html index 2edd2e437..9c0845f63 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminPane.html +++ b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminPane.html @@ -5,11 +5,11 @@    RainLoop - () + ()    - () + ()
diff --git a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsAbout.html b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsAbout.html index 609f9000d..d4586d32e 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsAbout.html +++ b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsAbout.html @@ -4,10 +4,10 @@
-
@@ -19,7 +19,7 @@

-
+
   diff --git a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsBranding.html b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsBranding.html index 12dbad047..899ba9235 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsBranding.html +++ b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsBranding.html @@ -29,7 +29,7 @@

-