Source refactoring

This commit is contained in:
RainLoop Team 2015-05-03 00:22:32 +04:00
parent 09b04740e7
commit 104ac0806a
27 changed files with 204 additions and 715 deletions

1
.gitignore vendored
View file

@ -5,7 +5,6 @@
/rainloop.sublime-project /rainloop.sublime-project
/rainloop.sublime-workspace /rainloop.sublime-workspace
/rainloop/v/0.0.0/static/css/*.css /rainloop/v/0.0.0/static/css/*.css
/rainloop/v/0.0.0/static/js/*.js
/rainloop/v/0.0.0/static/js/**/*.js /rainloop/v/0.0.0/static/js/**/*.js
/node_modules /node_modules
/build/local /build/local

View file

@ -51,6 +51,7 @@
"jquery" : true, "jquery" : true,
"globals": { "globals": {
"RL_COMMUNITY" : true,
"module" : true, "module" : true,
"require" : true, "require" : true,
"ko" : true, "ko" : true,

View file

@ -28,6 +28,11 @@
*/ */
Globals.startMicrotime = (new window.Date()).getTime(); Globals.startMicrotime = (new window.Date()).getTime();
/**
* @type {boolean}
*/
Globals.community = RL_COMMUNITY;
/** /**
* @type {?} * @type {?}
*/ */

View file

@ -103,7 +103,7 @@
*/ */
HtmlEditor.prototype.clearSignatureSigns = function (sText) HtmlEditor.prototype.clearSignatureSigns = function (sText)
{ {
return sText.replace(/(\u0002|\u0003|\u200C|\u200D)/g, ''); return sText.replace(/(\u200C|<x-signature>|<\/x-signature>)/g, '');
}; };
/** /**

View file

@ -861,10 +861,7 @@
; ;
sText = sHtml sText = sHtml
// specials for signature .replace(/<x-signature>([\s\S]*)<\/x-signature>/gm, '\u200C$1\u200C')
.replace(/\u0002\u0002/g, '\u200C\u200C')
.replace(/\u0003\u0003/g, '\u200D\u200D')
.replace(/<pre[^>]*>([\s\S\r\n]*)<\/pre>/gmi, convertPre) .replace(/<pre[^>]*>([\s\S\r\n]*)<\/pre>/gmi, convertPre)
.replace(/[\s]+/gm, ' ') .replace(/[\s]+/gm, ' ')
.replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gmi, fixAttibuteValue) .replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gmi, fixAttibuteValue)
@ -1012,16 +1009,12 @@
sPlain = aText.join("\n"); sPlain = aText.join("\n");
sPlain = sPlain sPlain = sPlain
// specials for signature
.replace(/\u200C\u200C/g, '\u0002\u0002')
.replace(/\u200D\u200D/g, '\u0003\u0003')
// .replace(/~~~\/blockquote~~~\n~~~blockquote~~~/g, '\n') // .replace(/~~~\/blockquote~~~\n~~~blockquote~~~/g, '\n')
.replace(/&/g, '&amp;') .replace(/&/g, '&amp;')
.replace(/>/g, '&gt;').replace(/</g, '&lt;') .replace(/>/g, '&gt;').replace(/</g, '&lt;')
.replace(/~~~blockquote~~~[\s]*/g, '<blockquote>') .replace(/~~~blockquote~~~[\s]*/g, '<blockquote>')
.replace(/[\s]*~~~\/blockquote~~~/g, '</blockquote>') .replace(/[\s]*~~~\/blockquote~~~/g, '</blockquote>')
.replace(/\u200C([\s\S]*)\u200C/g, '<x-signature>$1</x-signature>')
.replace(/\n/g, '<br />') .replace(/\n/g, '<br />')
; ;

View file

@ -38,8 +38,16 @@
kn.addSettingsViewModel(require('Settings/Admin/Login'), kn.addSettingsViewModel(require('Settings/Admin/Login'),
'AdminSettingsLogin', 'TABS_LABELS/LABEL_LOGIN_NAME', 'login'); 'AdminSettingsLogin', 'TABS_LABELS/LABEL_LOGIN_NAME', 'login');
if (RL_COMMUNITY)
{
kn.addSettingsViewModel(require('Settings/Admin/Branding'), kn.addSettingsViewModel(require('Settings/Admin/Branding'),
'AdminSettingsBranding', 'TABS_LABELS/LABEL_BRANDING_NAME', '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'), kn.addSettingsViewModel(require('Settings/Admin/Contacts'),
'AdminSettingsContacts', 'TABS_LABELS/LABEL_CONTACTS_NAME', 'contacts'); 'AdminSettingsContacts', 'TABS_LABELS/LABEL_CONTACTS_NAME', 'contacts');
@ -56,11 +64,14 @@
kn.addSettingsViewModel(require('Settings/Admin/Plugins'), kn.addSettingsViewModel(require('Settings/Admin/Plugins'),
'AdminSettingsPlugins', 'TABS_LABELS/LABEL_PLUGINS_NAME', 'plugins'); 'AdminSettingsPlugins', 'TABS_LABELS/LABEL_PLUGINS_NAME', 'plugins');
kn.addSettingsViewModel(require('Settings/Admin/Packages'), if (!RL_COMMUNITY)
{
kn.addSettingsViewModel(require('Settings/Admin/Prem/Packages'),
'AdminSettingsPackages', 'TABS_LABELS/LABEL_PACKAGES_NAME', 'packages'); 'AdminSettingsPackages', 'TABS_LABELS/LABEL_PACKAGES_NAME', 'packages');
kn.addSettingsViewModel(require('Settings/Admin/Licensing'), kn.addSettingsViewModel(require('Settings/Admin/Prem/Licensing'),
'AdminSettingsLicensing', 'TABS_LABELS/LABEL_LICENSING_NAME', 'licensing'); 'AdminSettingsLicensing', 'TABS_LABELS/LABEL_LICENSING_NAME', 'licensing');
}
kn.addSettingsViewModel(require('Settings/Admin/About'), kn.addSettingsViewModel(require('Settings/Admin/About'),
'AdminSettingsAbout', 'TABS_LABELS/LABEL_ABOUT_NAME', 'about'); 'AdminSettingsAbout', 'TABS_LABELS/LABEL_ABOUT_NAME', 'about');

2
dev/Settings/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/Admin/Prem/**
/Admin/_Prem/**

View file

@ -9,7 +9,8 @@
Translator = require('Common/Translator'), Translator = require('Common/Translator'),
Settings = require('Storage/Settings'), 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.coreRemoteRelease = CoreStore.coreRemoteRelease;
this.coreVersionCompare = CoreStore.coreVersionCompare; this.coreVersionCompare = CoreStore.coreVersionCompare;
this.community = RL_COMMUNITY || AppStore.community();
this.coreRemoteVersionHtmlDesc = ko.computed(function () { this.coreRemoteVersionHtmlDesc = ko.computed(function () {
Translator.trigger(); Translator.trigger();
return Translator.i18n('TAB_ABOUT/HTML_NEW_VERSION', {'VERSION': this.coreRemoteVersion()}); return Translator.i18n('TAB_ABOUT/HTML_NEW_VERSION', {'VERSION': this.coreRemoteVersion()});
@ -78,7 +81,7 @@
AboutAdminSettings.prototype.onBuild = function () AboutAdminSettings.prototype.onBuild = function ()
{ {
if (this.access()) if (this.access() && !this.community)
{ {
require('App/Admin').reloadCoreData(); require('App/Admin').reloadCoreData();
} }
@ -86,7 +89,7 @@
AboutAdminSettings.prototype.updateCoreData = function () AboutAdminSettings.prototype.updateCoreData = function ()
{ {
if (!this.coreUpdating()) if (!this.coreUpdating() && !this.community)
{ {
require('App/Admin').updateCoreData(); require('App/Admin').updateCoreData();
} }

View file

@ -67,6 +67,8 @@
}); });
this.loginPowered = ko.observable(!!Settings.settingsGet('LoginPowered')); this.loginPowered = ko.observable(!!Settings.settingsGet('LoginPowered'));
this.community = RL_COMMUNITY || AppStore.community();
} }
BrandingAdminSettings.prototype.onBuild = function () BrandingAdminSettings.prototype.onBuild = function ()
@ -76,85 +78,6 @@
Remote = require('Remote/Admin/Ajax') 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 () { _.delay(function () {
var var

View file

@ -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;
}());

View file

@ -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;
}());

View file

@ -12,7 +12,10 @@
Translator = require('Common/Translator'), Translator = require('Common/Translator'),
Settings = require('Storage/Settings'), Settings = require('Storage/Settings'),
AppStore = require('Stores/Admin/App'),
PluginStore = require('Stores/Admin/Plugin'), PluginStore = require('Stores/Admin/Plugin'),
Remote = require('Remote/Admin/Ajax') Remote = require('Remote/Admin/Ajax')
; ;
@ -26,6 +29,8 @@
this.plugins = PluginStore.plugins; this.plugins = PluginStore.plugins;
this.pluginsError = PluginStore.plugins.error; this.pluginsError = PluginStore.plugins.error;
this.community = RL_COMMUNITY || AppStore.community();
this.visibility = ko.computed(function () { this.visibility = ko.computed(function () {
return PluginStore.plugins.loading() ? 'visible' : 'hidden'; return PluginStore.plugins.loading() ? 'visible' : 'hidden';
}, this); }, this);

View file

@ -29,6 +29,7 @@
this.interfaceAnimation.valueHasMutated(); this.interfaceAnimation.valueHasMutated();
this.prem = ko.observable(false); this.prem = ko.observable(false);
this.community = ko.observable(true);
} }
AppStore.prototype.populate = function() AppStore.prototype.populate = function()
@ -39,6 +40,7 @@
this.interfaceAnimation(!!Settings.settingsGet('InterfaceAnimation')); this.interfaceAnimation(!!Settings.settingsGet('InterfaceAnimation'));
this.prem(!!Settings.settingsGet('PremType')); this.prem(!!Settings.settingsGet('PremType'));
this.community(!!Settings.settingsGet('Community'));
}; };
module.exports = AppStore; module.exports = AppStore;

View file

@ -26,6 +26,7 @@
this.version = ko.observable(Settings.settingsGet('Version')); this.version = ko.observable(Settings.settingsGet('Version'));
this.capa = !!Settings.settingsGet('PremType'); this.capa = !!Settings.settingsGet('PremType');
this.community = RL_COMMUNITY;
this.adminManLoading = ko.computed(function () { this.adminManLoading = ko.computed(function () {
return '000' !== [ return '000' !== [

View file

@ -299,6 +299,11 @@
{ {
var self = this; var self = this;
if (0 < this.messageListChecked().length)
{
return false;
}
window.clearTimeout(this.iGoToUpUpOrDownDownTimeout); window.clearTimeout(this.iGoToUpUpOrDownDownTimeout);
this.iGoToUpUpOrDownDownTimeout = window.setTimeout(function () { this.iGoToUpUpOrDownDownTimeout = window.setTimeout(function () {

View file

@ -6,6 +6,7 @@ var
cfg = { cfg = {
devVersion: '0.0.0', devVersion: '0.0.0',
releasesPath: 'build/dist/releases', releasesPath: 'build/dist/releases',
community: true,
rainloopBuilded: false, rainloopBuilded: false,
destPath: '', 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() { gulp.task('css:clear-less', ['css:main-begin'], function() {
return gulp.src(cfg.paths.staticCSS + cfg.paths.less.main.name, {read: false}) 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) { gulp.task('js:webpack', ['js:webpack:clear'], function(callback) {
var var
webpack = require('webpack'), webpack = require('webpack'),
webpackCfg = require('./webpack.config.js') webpackCfg = require('./webpack.config.js')
@ -300,6 +312,13 @@ gulp.task('js:webpack', ['js:webpack:clear'], function(callback) {
webpackCfg.output.publicPath = cfg.paths.staticJS; 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) { webpack(webpackCfg, function(err, stats) {
if (err) { if (err) {
throw new gutil.PluginError('webpack', 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.destPath = cfg.releasesPath + '/webmail/' + versionFull + '/';
cfg.cleanPath = dist; cfg.cleanPath = dist;
cfg.zipSrcPath = dist; cfg.zipSrcPath = dist;
cfg.zipFile = 'rainloop-' + versionFull + '.zip'; cfg.zipFile = 'rainloop-' + (cfg.community ? 'community-' : '') + versionFull + '.zip';
cfg.md5File = cfg.zipFile; cfg.md5File = cfg.zipFile;
cfg.rainloopBuilded = true; cfg.rainloopBuilded = true;
@ -538,7 +557,7 @@ gulp.task('rainloop:owncloud:setup', ['rainloop:owncloud:copy',
cfg.destPath = cfg.releasesPath + '/owncloud/' + versionFull + '/'; cfg.destPath = cfg.releasesPath + '/owncloud/' + versionFull + '/';
cfg.cleanPath = dist; cfg.cleanPath = dist;
cfg.zipSrcPath = 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; 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('fast', ['js:app', 'js:admin', 'js:chunks', 'css:main']);
gulp.task('rainloop:start', ['js:lint', 'rainloop:copy', 'rainloop:setup']); 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:copy-rainloop', 'rainloop:owncloud:copy-rainloop:clean',
'rainloop:owncloud:setup', 'rainloop:owncloud:zip', 'rainloop:owncloud:md5', 'rainloop:owncloud:clean']); 'rainloop:owncloud:setup', 'rainloop:owncloud:zip', 'rainloop:owncloud:md5', 'rainloop:owncloud:clean']);
gulp.task('owncloud+', ['package:community-off', 'owncloud']);
//WATCH //WATCH
gulp.task('watch', ['fast'], function() { gulp.task('watch', ['fast'], function() {
gulp.watch(cfg.paths.globjs, {interval: 1000}, ['js:app', 'js:admin']); 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('build', ['rainloop']);
gulp.task('js:hint', ['js:lint']); gulp.task('js:hint', ['js:lint']);
gulp.task('own', ['owncloud']);
gulp.task('rl', ['rainloop']);
gulp.task('w', ['watch']); gulp.task('w', ['watch']);
gulp.task('f', ['fast']); gulp.task('f', ['fast']);
gulp.task('o', ['owncloud']);
gulp.task('b', ['build']); gulp.task('b', ['build']);
gulp.task('b+', ['build+']);
gulp.task('o', ['owncloud']);
gulp.task('o+', ['owncloud+']);
gulp.task('h', ['js:lint']); gulp.task('h', ['js:lint']);

View file

@ -1,8 +1,8 @@
{ {
"name": "RainLoop", "name": "RainLoop",
"title": "RainLoop Webmail", "title": "RainLoop Webmail",
"version": "1.8.4", "version": "1.9.0",
"release": "314", "release": "315",
"description": "Simple, modern & fast web-based email client", "description": "Simple, modern & fast web-based email client",
"homepage": "http://rainloop.net", "homepage": "http://rainloop.net",
"main": "gulpfile.js", "main": "gulpfile.js",

View file

@ -0,0 +1,2 @@
/Prem/**
/_Prem/**

View file

@ -110,6 +110,11 @@ class Actions
*/ */
private $oTwoFactorAuthProvider; private $oTwoFactorAuthProvider;
/**
* @var \RainLoop\Providers\Prem
*/
private $oPremProvider;
/** /**
* @var \RainLoop\Config\Application * @var \RainLoop\Config\Application
*/ */
@ -146,6 +151,7 @@ class Actions
$this->oSuggestionsProvider = null; $this->oSuggestionsProvider = null;
$this->oChangePasswordProvider = null; $this->oChangePasswordProvider = null;
$this->oTwoFactorAuthProvider = null; $this->oTwoFactorAuthProvider = null;
$this->oPremProvider = null;
$this->sSpecAuthToken = ''; $this->sSpecAuthToken = '';
@ -738,6 +744,28 @@ class Actions
return $this->oTwoFactorAuthProvider; 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 * @param bool $bLocal = false
* *
@ -1248,20 +1276,6 @@ class Actions
return $this->GetAccountFromCustomToken($this->getAuthToken(), $bThrowExceptionOnFalse); 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 bool $bAdmin
* @param string $sAuthAccountHash = '' * @param string $sAuthAccountHash = ''
@ -1278,6 +1292,8 @@ class Actions
$oAccount = null; $oAccount = null;
$oConfig = $this->Config(); $oConfig = $this->Config();
$oPremProvider = $this->PremProvider();
$aResult = array( $aResult = array(
'Version' => APP_VERSION, 'Version' => APP_VERSION,
'Auth' => false, 'Auth' => false,
@ -1329,7 +1345,8 @@ class Actions
'UseImapSubscribe' => (bool) $oConfig->Get('labs', 'use_imap_list_subscribe', true), 'UseImapSubscribe' => (bool) $oConfig->Get('labs', 'use_imap_list_subscribe', true),
'AllowAppendMessage' => (bool) $oConfig->Get('labs', 'allow_message_append', false), 'AllowAppendMessage' => (bool) $oConfig->Get('labs', 'allow_message_append', false),
'MaterialDesign' => (bool) $oConfig->Get('labs', 'use_material_design', true), 'MaterialDesign' => (bool) $oConfig->Get('labs', 'use_material_design', true),
'PremType' => $this->PremType(), 'Community' => true,
'PremType' => false,
'Admin' => array(), 'Admin' => array(),
'Capa' => array(), 'Capa' => array(),
'AttahcmentsActions' => array(), 'AttahcmentsActions' => array(),
@ -1383,21 +1400,15 @@ class Actions
$aResult['Title'] = $oConfig->Get('webmail', 'title', ''); $aResult['Title'] = $oConfig->Get('webmail', 'title', '');
$aResult['LoadingDescription'] = $oConfig->Get('webmail', 'loading_description', ''); $aResult['LoadingDescription'] = $oConfig->Get('webmail', 'loading_description', '');
if ($this->PremType()) if ($oPremProvider)
{ {
$aResult['LoginLogo'] = $oConfig->Get('branding', 'login_logo', ''); $oPremProvider->PopulateAppData($aResult);
$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'));
} }
$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; $oSettings = null;
$oSettingsLocal = null; $oSettingsLocal = null;
@ -3318,7 +3329,11 @@ class Actions
} }
else if ($bVersionsCache) else if ($bVersionsCache)
{ {
$this->removeOldVersion(); $oPremProvider = $this->PremProvider();
if ($oPremProvider)
{
$oPremProvider->ClearOldVersion();
}
} }
$this->Plugins()->RunHook('service.app-delay-start-end'); $this->Plugins()->RunHook('service.app-delay-start-end');
@ -3354,7 +3369,7 @@ class Actions
* @param string $sType = 'string' * @param string $sType = 'string'
* @param callable|null $mStringCallback = null * @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, ''); $sValue = $this->GetActionParam($sParamName, '');
if ($this->HasActionParam($sParamName)) if ($this->HasActionParam($sParamName))
@ -3531,26 +3546,6 @@ class Actions
$this->setConfigFromParams($oConfig, 'Title', 'webmail', 'title', 'string'); $this->setConfigFromParams($oConfig, 'Title', 'webmail', 'title', 'string');
$this->setConfigFromParams($oConfig, 'LoadingDescription', 'webmail', 'loading_description', '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, 'TokenProtection', 'security', 'csrf_protection', 'bool');
$this->setConfigFromParams($oConfig, 'EnabledPlugins', 'plugins', 'enable', '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, 'DropboxEnable', 'social', 'dropbox_enable', 'bool');
$this->setConfigFromParams($oConfig, 'DropboxApiKey', 'social', 'dropbox_api_key', 'string'); $this->setConfigFromParams($oConfig, 'DropboxApiKey', 'social', 'dropbox_api_key', 'string');
$oPremProvider = $this->PremProvider();
if ($oPremProvider)
{
$oPremProvider->PremSection($this, $oConfig);
}
return $this->DefaultResponse(__FUNCTION__, $oConfig->Save()); 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 * @return array
*/ */
@ -3797,14 +3660,16 @@ class Actions
$mResult = false; $mResult = false;
$iErrorCode = -1; $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(); $this->requestSleep();
$iExpired = 0; $iExpired = 0;
if ($this->licenseParser($sValue, $iExpired)) if ($oPremProvider->Parser($sValue, $iExpired))
{ {
$mResult = array( $mResult = array(
'Banned' => false, 'Banned' => false,
@ -3846,23 +3711,12 @@ class Actions
$mResult = false; $mResult = false;
$iErrorCode = -1; $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; $iCode = 0;
$sContentType = ''; $sValue = $oPrem->Activate($sDomain, $sKey, $iCode);
$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 = '';
}
$this->requestSleep(); $this->requestSleep();
@ -3878,6 +3732,7 @@ class Actions
else if (\preg_match('/^ERROR:(.+)$/', $sValue, $aMatch) && !empty($aMatch[1])) else if (\preg_match('/^ERROR:(.+)$/', $sValue, $aMatch) && !empty($aMatch[1]))
{ {
$mResult = trim($aMatch[1]); $mResult = trim($aMatch[1]);
$this->Logger()->Write('Activation error for: '.$sKey.' ('.$sDomain.')', \MailSo\Log\Enumerations\Type::ERROR); $this->Logger()->Write('Activation error for: '.$sKey.' ('.$sDomain.')', \MailSo\Log\Enumerations\Type::ERROR);
$this->Logger()->Write($mResult, \MailSo\Log\Enumerations\Type::ERROR); $this->Logger()->Write($mResult, \MailSo\Log\Enumerations\Type::ERROR);
} }
@ -4479,10 +4334,10 @@ class Actions
$this->IsAdminLoggined(); $this->IsAdminLoggined();
$bReal = false; $bReal = false;
$sNewVersion = '';
$bRainLoopUpdatable = $this->rainLoopUpdatable(); $bRainLoopUpdatable = $this->rainLoopUpdatable();
$bRainLoopAccess = $this->rainLoopCoreAccess(); $bRainLoopAccess = $this->rainLoopCoreAccess();
$oPremProvider = $this->PremProvider();
$aData = array(); $aData = array();
if ($bRainLoopUpdatable && $bRainLoopAccess) if ($bRainLoopUpdatable && $bRainLoopAccess)
@ -4491,132 +4346,14 @@ class Actions
} }
$bResult = false; $bResult = false;
if ($bReal && !empty($aData['file'])) if ($bReal && $oPremProvider && !empty($aData['file']))
{ {
$sTmp = $this->downloadRemotePackageByUrl($aData['file']); $bResult = $oPremProvider->UpdateCore($this, $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);
}
} }
return $this->DefaultResponse(__FUNCTION__, $bResult); 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 * @return array
*/ */
@ -4658,7 +4395,7 @@ class Actions
* *
* @return string * @return string
*/ */
private function downloadRemotePackageByUrl($sUrl) public function downloadRemotePackageByUrl($sUrl)
{ {
$bResult = false; $bResult = false;
$sTmp = APP_PRIVATE_DATA.\md5(\microtime(true).$sUrl).'.zip'; $sTmp = APP_PRIVATE_DATA.\md5(\microtime(true).$sUrl).'.zip';

View file

@ -5,11 +5,11 @@
<i class="icon-spinner animated" style="margin-top: 2px" data-bind="style: {'visibility': adminManLoadingVisibility }"></i> <i class="icon-spinner animated" style="margin-top: 2px" data-bind="style: {'visibility': adminManLoadingVisibility }"></i>
&nbsp;&nbsp; &nbsp;&nbsp;
RainLoop RainLoop
<span data-bind="visible: capa">(<span data-i18n="TOP_PANEL/LABEL_PREMIUM"></span>)</span> <span data-bind="visible: capa && !community">(<span data-i18n="TOP_PANEL/LABEL_PREMIUM"></span>)</span>
&mdash; &mdash;
<span data-i18n="TOP_PANEL/LABEL_ADMIN_PANEL"></span> <span data-i18n="TOP_PANEL/LABEL_ADMIN_PANEL"></span>
&nbsp;&nbsp; &nbsp;&nbsp;
(<span data-bind="text: adminDomain"></span>) <span data-bind="visible: !community">(<span data-bind="text: adminDomain"></span>)</span>
</h4> </h4>
<div class="btn-group pull-right"> <div class="btn-group pull-right">
<a class="btn single btn-narrow" data-bind="click: logoutClick"> <a class="btn single btn-narrow" data-bind="click: logoutClick">

View file

@ -4,10 +4,10 @@
<div class="row" style="min-width: 800px;"> <div class="row" style="min-width: 800px;">
<div class="span4"> <div class="span4">
<div class="rl-logo"></div> <div class="rl-logo"></div>
<div style="margin-left: 45px;"> <div style="margin-left: 30px;">
2015 &copy; <span data-i18n="TAB_ABOUT/LABEL_ALL_RIGHTS_RESERVED"></span> 2015 &copy; <span data-i18n="TAB_ABOUT/LABEL_ALL_RIGHTS_RESERVED"></span>
<br /> <br />
<a class="g-ui-link" href="http://www.rainloop.net/" target="_blank">http://rainloop.net/</a> <a class="g-ui-link" href="http://www.rainloop.net/" target="_blank" style="padding-left: 0">http://rainloop.net/</a>
</div> </div>
</div> </div>
<div class="span8 rl-desc"> <div class="span8 rl-desc">
@ -19,7 +19,7 @@
</span> </span>
</h4> </h4>
<h4 style="color: #aaa; font-weight: normal;" data-i18n="TAB_ABOUT/LABEL_TAG_HINT"></h4> <h4 style="color: #aaa; font-weight: normal;" data-i18n="TAB_ABOUT/LABEL_TAG_HINT"></h4>
<h5 style="font-weight: normal; margin-top: 40px;"> <h5 style="font-weight: normal; margin-top: 40px;" data-bind="visible: !community">
<div data-bind="visible: 'error' === statusType()"> <div data-bind="visible: 'error' === statusType()">
<i class="icon-warning" style="color: red"></i> <i class="icon-warning" style="color: red"></i>
&nbsp;&nbsp; &nbsp;&nbsp;

View file

@ -29,7 +29,7 @@
</div> </div>
</div> </div>
<br /> <br />
<ul class="nav nav-tabs"> <ul class="nav nav-tabs" data-bind="visible: !community">
<li class="active"> <li class="active">
<a class="i18n" data-i18n="TAB_BRANDING/LEGEND_LOGIN" <a class="i18n" data-i18n="TAB_BRANDING/LEGEND_LOGIN"
href="#branding-login-section-id" data-toggle="tab"></a> href="#branding-login-section-id" data-toggle="tab"></a>
@ -44,7 +44,7 @@
</li> </li>
</ul> </ul>
<br /> <br />
<div class="row"> <div class="row" data-bind="visible: !community">
<div class="tab-content span12"> <div class="tab-content span12">
<div class="tab-pane active" id="branding-login-section-id"> <div class="tab-pane active" id="branding-login-section-id">
@ -214,7 +214,7 @@
</div> </div>
</div> </div>
<div class="row" data-bind="visible: !capa()"> <div class="row" data-bind="visible: !capa() && !community">
<div class="alert span8" style="margin-top: 10px;" data-i18n="[html]TAB_BRANDING/HTML_ALERT_PREMIUM"></div> <div class="alert span8" style="margin-top: 10px;" data-i18n="[html]TAB_BRANDING/HTML_ALERT_PREMIUM"></div>
</div> </div>

View file

@ -19,9 +19,11 @@
<div class="row"> <div class="row">
<div class="alert alert-info span8" data-bind="visible: 0 === plugins().length"> <div class="alert alert-info span8" data-bind="visible: 0 === plugins().length">
<span data-i18n="TAB_PLUGINS/ALERT_NO_PLUGINS"></span> <span data-i18n="TAB_PLUGINS/ALERT_NO_PLUGINS"></span>
<br /><br /> <div data-bind="visible: !community">
<br />
<strong><a href="#/packages" data-i18n="TAB_PLUGINS/LINK_INSTALL_NEW"></a></strong> <strong><a href="#/packages" data-i18n="TAB_PLUGINS/LINK_INSTALL_NEW"></a></strong>
</div> </div>
</div>
<div class="span8" data-bind="visible: 0 < plugins().length"> <div class="span8" data-bind="visible: 0 < plugins().length">
<blockquote><p class="muted" data-i18n="TAB_PLUGINS/HINT_CLICK_NAME"></p></blockquote> <blockquote><p class="muted" data-i18n="TAB_PLUGINS/HINT_CLICK_NAME"></p></blockquote>
</div> </div>

View file

@ -199,25 +199,25 @@ Options -Indexes
} }
} }
$sClearedSiteName = preg_replace('/^(www|demo|rainloop|webmail|email|mail|imap|imap4|smtp|pop|pop3)\./i', '', trim(APP_SITE)); // $sClearedSiteName = preg_replace('/^(www|demo|rainloop|webmail|email|mail|imap|imap4|smtp|pop|pop3)\./i', '', trim(APP_SITE));
if (!empty($sClearedSiteName) && @file_exists(APP_VERSION_ROOT_PATH.'app/domains/default.ini.dist') && // if (!empty($sClearedSiteName) && @file_exists(APP_VERSION_ROOT_PATH.'app/domains/default.ini.dist') &&
!@file_exists(APP_PRIVATE_DATA.'domains/'.$sClearedSiteName.'.ini')) // !@file_exists(APP_PRIVATE_DATA.'domains/'.$sClearedSiteName.'.ini'))
{ // {
$sConfigTemplate = @file_get_contents(APP_VERSION_ROOT_PATH.'app/domains/default.ini.dist'); // $sConfigTemplate = @file_get_contents(APP_VERSION_ROOT_PATH.'app/domains/default.ini.dist');
if (!empty($sConfigTemplate)) // if (!empty($sConfigTemplate))
{ // {
@file_put_contents(APP_PRIVATE_DATA.'domains/'.$sClearedSiteName.'.ini', strtr($sConfigTemplate, array( // @file_put_contents(APP_PRIVATE_DATA.'domains/'.$sClearedSiteName.'.ini', strtr($sConfigTemplate, array(
'IMAP_HOST' => 'localhost' !== $sClearedSiteName? 'imap.'.$sClearedSiteName : $sClearedSiteName, // 'IMAP_HOST' => 'localhost' !== $sClearedSiteName? 'imap.'.$sClearedSiteName : $sClearedSiteName,
'IMAP_PORT' => '993', // 'IMAP_PORT' => '993',
'SMTP_HOST' => 'localhost' !== $sClearedSiteName? 'smtp.'.$sClearedSiteName : $sClearedSiteName, // 'SMTP_HOST' => 'localhost' !== $sClearedSiteName? 'smtp.'.$sClearedSiteName : $sClearedSiteName,
'SMTP_PORT' => '465' // 'SMTP_PORT' => '465'
))); // )));
} // }
//
// unset($sConfigTemplate);
// }
unset($sConfigTemplate); unset($aFiles, $sFile, $sNewFileName, $sNewFile);
}
unset($aFiles, $sFile, $sNewFileName, $sNewFile, $sClearedSiteName);
} }
} }
} }

View file

@ -4,50 +4,38 @@ rl_signature_replacer = function (editor, sText, sSignature, bHtml, bInsertBefor
if (!bHtml) if (!bHtml)
{ {
sText = sText sText = sText
.replace(/\u200C\u200C/g, '\u0002\u0002') .replace(/\u200C([\s\S]*)\u200C/g, '<x-signature>$1</x-signature>')
.replace(/\u200D\u200D/g, '\u0003\u0003') .replace(/\u200C/g, '')
; ;
} }
sText = sText.replace(/<x-signature>[\s\S]*<\/x-signature>/gm, '');
var var
sTextWithoutSignature = sText bEmptyText = '' === $.trim(sText),
.replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, '')
.replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, ''),
bEmptyText = '' === $.trim(sTextWithoutSignature),
sNewLine = (bHtml ? '<br />' : "\n") sNewLine = (bHtml ? '<br />' : "\n")
; ;
if (!bEmptyText && bHtml) if (!bEmptyText && bHtml)
{ {
bEmptyText = '' !== $.trim(editor.__plainUtils.htmlToPlain(sTextWithoutSignature)); bEmptyText = '' !== $.trim(editor.__plainUtils.htmlToPlain(sText));
}
if (!/\u0002\u0002/gm.test(sText))
{
sText = "\u0002\u0002\u0002\u0002" + sText;
}
if (!/\u0003\u0003/gm.test(sText))
{
sText = sText + "\u0003\u0003\u0003\u0003";
} }
if (bInsertBefore) if (bInsertBefore)
{ {
sText = sText.replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, "\u0002\u0002" + sSignature + (bEmptyText ? '' : sNewLine) + "\u0002\u0002"); sText = '<x-signature>' + sSignature + (bEmptyText ? '' : sNewLine) + '</x-signature>' + sText;
sText = sText.replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, "\u0003\u0003\u0003\u0003");
} }
else else
{ {
sText = sText.replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, "\u0002\u0002\u0002\u0002"); sText = sText + '<x-signature>' + (bEmptyText ? '' : sNewLine) + sSignature + '</x-signature>';
sText = sText.replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, "\u0003\u0003" + (bEmptyText ? '' : sNewLine) + sSignature + "\u0003\u0003");
} }
if (!bHtml) if (!bHtml)
{ {
sText = sText sText = sText
.replace(/\u0002\u0002/g, '\u200C\u200C') .replace(/<x-signature>([\s\S]*)<\/x-signature>/gm, '\u200C$1\u200C')
.replace(/\u0003\u0003/g, '\u200D\u200D') .replace(/<x-signature>/gm, '')
.replace(/<\/x-signature>/gm, '')
; ;
} }
@ -90,8 +78,7 @@ CKEDITOR.plugins.add('signature', {
} }
editor.__plain.setRawData( editor.__plain.setRawData(
rl_signature_replacer(editor, rl_signature_replacer(editor, editor.__plain.getRawData(), sResultSignature, false, bInsertBefore));
editor.__plain.getRawData(), sResultSignature, false, bInsertBefore));
} }
else else
@ -105,8 +92,7 @@ CKEDITOR.plugins.add('signature', {
} }
editor.setData( editor.setData(
rl_signature_replacer(editor, rl_signature_replacer(editor, editor.getData(), sResultSignature, true, bInsertBefore));
editor.getData(), sResultSignature, true, bInsertBefore));
} }
} }
catch (e) {} catch (e) {}

View file

@ -4,50 +4,38 @@ rl_signature_replacer = function (editor, sText, sSignature, bHtml, bInsertBefor
if (!bHtml) if (!bHtml)
{ {
sText = sText sText = sText
.replace(/\u200C\u200C/g, '\u0002\u0002') .replace(/\u200C([\s\S]*)\u200C/g, '<x-signature>$1</x-signature>')
.replace(/\u200D\u200D/g, '\u0003\u0003') .replace(/\u200C/g, '')
; ;
} }
sText = sText.replace(/<x-signature>[\s\S]*<\/x-signature>/gm, '');
var var
sTextWithoutSignature = sText bEmptyText = '' === $.trim(sText),
.replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, '')
.replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, ''),
bEmptyText = '' === $.trim(sTextWithoutSignature),
sNewLine = (bHtml ? '<br />' : "\n") sNewLine = (bHtml ? '<br />' : "\n")
; ;
if (!bEmptyText && bHtml) if (!bEmptyText && bHtml)
{ {
bEmptyText = '' !== $.trim(editor.__plainUtils.htmlToPlain(sTextWithoutSignature)); bEmptyText = '' !== $.trim(editor.__plainUtils.htmlToPlain(sText));
}
if (!/\u0002\u0002/gm.test(sText))
{
sText = "\u0002\u0002\u0002\u0002" + sText;
}
if (!/\u0003\u0003/gm.test(sText))
{
sText = sText + "\u0003\u0003\u0003\u0003";
} }
if (bInsertBefore) if (bInsertBefore)
{ {
sText = sText.replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, "\u0002\u0002" + sSignature + (bEmptyText ? '' : sNewLine) + "\u0002\u0002"); sText = '<x-signature>' + sSignature + (bEmptyText ? '' : sNewLine) + '</x-signature>' + sText;
sText = sText.replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, "\u0003\u0003\u0003\u0003");
} }
else else
{ {
sText = sText.replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, "\u0002\u0002\u0002\u0002"); sText = sText + '<x-signature>' + (bEmptyText ? '' : sNewLine) + sSignature + '</x-signature>';
sText = sText.replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, "\u0003\u0003" + (bEmptyText ? '' : sNewLine) + sSignature + "\u0003\u0003");
} }
if (!bHtml) if (!bHtml)
{ {
sText = sText sText = sText
.replace(/\u0002\u0002/g, '\u200C\u200C') .replace(/<x-signature>([\s\S]*)<\/x-signature>/gm, '\u200C$1\u200C')
.replace(/\u0003\u0003/g, '\u200D\u200D') .replace(/<x-signature>/gm, '')
.replace(/<\/x-signature>/gm, '')
; ;
} }
@ -90,8 +78,7 @@ CKEDITOR.plugins.add('signature', {
} }
editor.__plain.setRawData( editor.__plain.setRawData(
rl_signature_replacer(editor, rl_signature_replacer(editor, editor.__plain.getRawData(), sResultSignature, false, bInsertBefore));
editor.__plain.getRawData(), sResultSignature, false, bInsertBefore));
} }
else else
@ -105,8 +92,7 @@ CKEDITOR.plugins.add('signature', {
} }
editor.setData( editor.setData(
rl_signature_replacer(editor, rl_signature_replacer(editor, editor.getData(), sResultSignature, true, bInsertBefore));
editor.getData(), sResultSignature, true, bInsertBefore));
} }
} }
catch (e) {} catch (e) {}