diff --git a/dev/App/Admin.js b/dev/App/Admin.js index 3c675d2b1..d5f5f4bf2 100644 --- a/dev/App/Admin.js +++ b/dev/App/Admin.js @@ -167,6 +167,8 @@ if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { Data.coreReal(!!oData.Result.Real); + Data.coreChannel(oData.Result.Channel || 'stable'); + Data.coreType(oData.Result.Type || 'stable'); Data.coreUpdatable(!!oData.Result.Updatable); Data.coreAccess(!!oData.Result.Access); Data.coreRemoteVersion(oData.Result.RemoteVersion || ''); @@ -176,6 +178,8 @@ else { Data.coreReal(false); + Data.coreChannel('stable'); + Data.coreType('stable'); Data.coreRemoteVersion(''); Data.coreRemoteRelease(''); Data.coreVersionCompare(-2); diff --git a/dev/Common/Enums.js b/dev/Common/Enums.js index f695120c1..faf45d482 100644 --- a/dev/Common/Enums.js +++ b/dev/Common/Enums.js @@ -51,7 +51,7 @@ 'Gravatar': 'GRAVATAR', 'Themes': 'THEMES', 'UserBackground': 'USER_BACKGROUND', - 'Filters': 'FILTERS', + 'Sieve': 'SIEVE', 'AdditionalAccounts': 'ADDITIONAL_ACCOUNTS', 'AdditionalIdentities': 'ADDITIONAL_IDENTITIES' }; @@ -291,7 +291,6 @@ */ Enums.FilterConditionField = { 'From': 'From', - 'To': 'To', 'Recipient': 'Recipient', 'Subject': 'Subject' }; @@ -320,8 +319,8 @@ * @enum {string} */ Enums.FilterRulesType = { - 'And': 'And', - 'Or': 'Or' + 'All': 'All', + 'Any': 'Any' }; /** diff --git a/dev/Common/Globals.js b/dev/Common/Globals.js index 19654ab5b..87d32af36 100644 --- a/dev/Common/Globals.js +++ b/dev/Common/Globals.js @@ -145,7 +145,7 @@ 'removeButtons': 'Format,Undo,Redo,Cut,Copy,Paste,Anchor,Strike,Subscript,Superscript,Image,SelectAll,Source', 'removeDialogTabs': 'link:advanced;link:target;image:advanced;images:advanced', - 'extraPlugins': 'plain', + 'extraPlugins': 'plain,signature', 'allowedContent': true, 'font_defaultLabel': 'Arial', diff --git a/dev/Common/HtmlEditor.js b/dev/Common/HtmlEditor.js index f012711e3..c255ce956 100644 --- a/dev/Common/HtmlEditor.js +++ b/dev/Common/HtmlEditor.js @@ -62,6 +62,19 @@ return this.editor ? 'wysiwyg' === this.editor.mode : false; }; + /** + * @param {string} sSignature + */ + HtmlEditor.prototype.setSignature = function (sSignature) + { + if (this.editor) + { + this.editor.execCommand('insertSignature', { + 'signature': sSignature + }); + } + }; + /** * @return {boolean} */ @@ -172,7 +185,7 @@ bBiti = !!Settings.settingsGet('AllowHtmlEditorBitiButtons') ; - if ((bSource || bBiti) && !oConfig.toolbarGroups.__SourceInited) + if ((bSource || !bBiti) && !oConfig.toolbarGroups.__SourceInited) { oConfig.toolbarGroups.__SourceInited = true; @@ -181,9 +194,9 @@ oConfig.removeButtons = oConfig.removeButtons.replace(',Source', ''); } - if (bBiti) + if (!bBiti) { - oConfig.extraPlugins += (oConfig.extraPlugins ? ',' : '') + 'bidi'; + oConfig.removePlugins += (oConfig.removePlugins ? ',' : '') + 'bidi'; } } diff --git a/dev/Common/Utils.js b/dev/Common/Utils.js index 7df3ac37c..fbc764f5e 100644 --- a/dev/Common/Utils.js +++ b/dev/Common/Utils.js @@ -1059,6 +1059,7 @@ oData.capaAdditionalAccounts = ko.observable(false); oData.capaAdditionalIdentities = ko.observable(false); oData.capaGravatar = ko.observable(false); + oData.capaSieve = ko.observable(false); oData.determineUserLanguage = ko.observable(false); oData.determineUserDomain = ko.observable(false); @@ -1561,6 +1562,8 @@ { sPlain = sPlain.toString().replace(/\r/g, ''); + bFindEmailAndLinks = Utils.isUnd(bFindEmailAndLinks) ? false : !!bFindEmailAndLinks; + var bIn = false, bDo = true, @@ -1627,7 +1630,6 @@ .replace(/>/g, '>').replace(/') .replace(/[\s]*~~~\/blockquote~~~/g, '') - .replace(/ /g, ' ') .replace(/\n/g, '
') ; @@ -1784,11 +1786,12 @@ for (iIndex = 0, iLen = aList.length; iIndex < iLen; iIndex++) { oItem = aList[iIndex]; - if (oItem.subScribed() || !oItem.existen || bBuildUnvisible) +// if (oItem.subScribed() || !oItem.existen || bBuildUnvisible) + if ((oItem.subScribed() || !oItem.existen || bBuildUnvisible) && (oItem.selectable || oItem.hasSubScribedSubfolders())) { if (fVisibleCallback ? fVisibleCallback.call(null, oItem) : true) { - if (Enums.FolderType.User === oItem.type() || !bSystem || 0 < oItem.subFolders().length) + if (Enums.FolderType.User === oItem.type() || !bSystem || oItem.hasSubScribedSubfolders()) { if (bSep && 0 < aResult.length) { diff --git a/dev/External/ko.js b/dev/External/ko.js index 3a0518973..58b9570c8 100644 --- a/dev/External/ko.js +++ b/dev/External/ko.js @@ -36,6 +36,7 @@ var $oEl = null, + bi18n = true, sClass = '', sPlacement = '', oSubscription = null, @@ -47,6 +48,7 @@ { $oEl = $(oElement); sClass = $oEl.data('tooltip-class') || ''; + bi18n = 'on' === ($oEl.data('tooltip-i18n') || 'on'); sPlacement = $oEl.data('tooltip-placement') || 'top'; $oEl.tooltip({ @@ -59,8 +61,9 @@ 'placement': sPlacement, 'trigger': 'hover', 'title': function () { - return $oEl.is('.disabled') || Globals.dropdownVisibility() ? '' : '' + - Utils.i18n(ko.unwrap(fValueAccessor())) + ''; + var sValue = bi18n ? ko.unwrap(fValueAccessor()) : fValueAccessor()(); + return '' === sValue || $oEl.is('.disabled') || Globals.dropdownVisibility() ? '' : + '' + (bi18n ? Utils.i18n(sValue) : sValue) + ''; } }).on('click.koTooltip', function () { $oEl.tooltip('hide'); @@ -75,42 +78,7 @@ } }; - ko.bindingHandlers.tooltip2 = { - 'init': function (oElement, fValueAccessor) { - var - Globals = require('Common/Globals'), - - $oEl = $(oElement), - oSubscription = null, - sClass = $oEl.data('tooltip-class') || '', - sPlacement = $oEl.data('tooltip-placement') || 'top' - ; - - $oEl.tooltip({ - 'delay': { - 'show': 500, - 'hide': 100 - }, - 'html': true, - 'container': 'body', - 'placement': sPlacement, - 'title': function () { - return $oEl.is('.disabled') || Globals.dropdownVisibility() ? '' : - '' + fValueAccessor()() + ''; - } - }).on('click.koTooltip', function () { - $oEl.tooltip('hide'); - }); - - oSubscription = Globals.tooltipTrigger.subscribe(function () { - $oEl.tooltip('hide'); - }); - - fDisposalTooltipHelper(oElement, $oEl, oSubscription); - } - }; - - ko.bindingHandlers.tooltip3 = { + ko.bindingHandlers.tooltipForTest = { 'init': function (oElement) { var diff --git a/dev/Model/Filter.js b/dev/Model/Filter.js index d7bf42618..c1901a09e 100644 --- a/dev/Model/Filter.js +++ b/dev/Model/Filter.js @@ -26,14 +26,10 @@ this.name = ko.observable(''); - this.conditionsType = ko.observable(Enums.FilterRulesType.And); + this.conditionsType = ko.observable(Enums.FilterRulesType.All); this.conditions = ko.observableArray([]); - this.regDisposables(this.conditions.subscribe(function () { - Utils.windowResize(); - })); - // Actions this.actionMarkAsRead = ko.observable(false); this.actionSkipOtherFilters = ko.observable(true); @@ -41,18 +37,27 @@ this.actionType = ko.observable(Enums.FiltersAction.Move); this.actionTypeOptions = [ // TODO i18n - {'id': Enums.FiltersAction.None, 'name': 'Action - None'}, - {'id': Enums.FiltersAction.Move, 'name': 'Action - Move to'}, - // {'id': Enums.FiltersAction.Forward, 'name': 'Action - Forward to'}, - {'id': Enums.FiltersAction.Discard, 'name': 'Action - Discard'} + {'id': Enums.FiltersAction.None, 'name': 'None'}, + {'id': Enums.FiltersAction.Move, 'name': ' Move to'}, + // {'id': Enums.FiltersAction.Forward, 'name': 'Forward to'}, + {'id': Enums.FiltersAction.Discard, 'name': 'Discard'} ]; - this.actionMarkAsReadVisiblity = ko.computed(function () { - return -1 < Utils.inArray(this.actionType(), [ - Enums.FiltersAction.None, Enums.FiltersAction.Forward, Enums.FiltersAction.Move + this.enableSkipOtherFilters = ko.computed(function () { + return -1 === Utils.inArray(this.actionType(), [ + Enums.FiltersAction.Move, Enums.FiltersAction.Forward, Enums.FiltersAction.Discard ]); }, this); + this.actionSkipOtherFiltersResult = ko.computed({ + 'read': function () { + return this.actionSkipOtherFilters() || + !this.enableSkipOtherFilters(); + }, + 'write': this.actionSkipOtherFilters, + 'owner': this + }); + this.actionTemplate = ko.computed(function () { var sTemplate = ''; @@ -75,7 +80,11 @@ }, this); - this.regDisposables([this.actionMarkAsReadVisiblity, this.actionTemplate]); + this.regDisposables(this.conditions.subscribe(function () { + Utils.windowResize(); + })); + + this.regDisposables([this.enableSkipOtherFilters, this.actionSkipOtherFiltersResult, this.actionTemplate]); } _.extend(FilterModel.prototype, AbstractModel.prototype); diff --git a/dev/Model/FilterCondition.js b/dev/Model/FilterCondition.js index 67dba75de..821aeabee 100644 --- a/dev/Model/FilterCondition.js +++ b/dev/Model/FilterCondition.js @@ -27,7 +27,6 @@ this.fieldOptions = [ // TODO i18n {'id': Enums.FilterConditionField.From, 'name': 'From'}, {'id': Enums.FilterConditionField.Recipient, 'name': 'Recipient (To or CC)'}, - {'id': Enums.FilterConditionField.To, 'name': 'To'}, {'id': Enums.FilterConditionField.Subject, 'name': 'Subject'} ]; diff --git a/dev/Model/Folder.js b/dev/Model/Folder.js index 1d6bdd7ea..88d659279 100644 --- a/dev/Model/Folder.js +++ b/dev/Model/Folder.js @@ -86,12 +86,14 @@ }, this); this.visible = ko.computed(function () { + var bSubScribed = this.subScribed(), bSubFolders = this.hasSubScribedSubfolders() ; return (bSubScribed || (bSubFolders && (!this.existen || !this.selectable))); + }, this); this.isSystemFolder = ko.computed(function () { diff --git a/dev/Screen/User/Settings.js b/dev/Screen/User/Settings.js index 007b53bf2..19d1435cb 100644 --- a/dev/Screen/User/Settings.js +++ b/dev/Screen/User/Settings.js @@ -69,7 +69,7 @@ 'SettingsIdentity', 'SETTINGS_LABELS/LABEL_IDENTITY_NAME', 'identity'); } - if (Settings.capa(Enums.Capa.Filters)) + if (Settings.capa(Enums.Capa.Sieve)) { kn.addSettingsViewModel(require('Settings/User/Filters'), 'SettingsFilters', 'SETTINGS_LABELS/LABEL_FILTERS_NAME', 'filters'); diff --git a/dev/Settings/Admin/About.js b/dev/Settings/Admin/About.js index f49ac692b..77ab4804b 100644 --- a/dev/Settings/Admin/About.js +++ b/dev/Settings/Admin/About.js @@ -22,6 +22,8 @@ this.errorDesc = ko.observable(''); this.coreReal = Data.coreReal; + this.coreChannel = Data.coreChannel; + this.coreType = Data.coreType; this.coreUpdatable = Data.coreUpdatable; this.coreAccess = Data.coreAccess; this.coreChecking = Data.coreChecking; diff --git a/dev/Storage/AbstractData.js b/dev/Storage/AbstractData.js index b2912691d..7add1a6d5 100644 --- a/dev/Storage/AbstractData.js +++ b/dev/Storage/AbstractData.js @@ -45,6 +45,7 @@ this.capaAdditionalAccounts(Settings.capa(Enums.Capa.AdditionalAccounts)); this.capaAdditionalIdentities(Settings.capa(Enums.Capa.AdditionalIdentities)); this.capaGravatar(Settings.capa(Enums.Capa.Gravatar)); + this.capaSieve(Settings.capa(Enums.Capa.Sieve)); this.determineUserLanguage(!!Settings.settingsGet('DetermineUserLanguage')); this.determineUserDomain(!!Settings.settingsGet('DetermineUserDomain')); diff --git a/dev/Storage/Admin/Data.js b/dev/Storage/Admin/Data.js index 95dba59cc..158c2c6ad 100644 --- a/dev/Storage/Admin/Data.js +++ b/dev/Storage/Admin/Data.js @@ -31,6 +31,8 @@ this.packages.loading = ko.observable(false).extend({'throttle': 100}); this.coreReal = ko.observable(true); + this.coreChannel = ko.observable('stable'); + this.coreType = ko.observable('stable'); this.coreUpdatable = ko.observable(true); this.coreAccess = ko.observable(true); this.coreChecking = ko.observable(false).extend({'throttle': 100}); diff --git a/dev/Storage/Admin/Remote.js b/dev/Storage/Admin/Remote.js index 11174256e..e768924d2 100644 --- a/dev/Storage/Admin/Remote.js +++ b/dev/Storage/Admin/Remote.js @@ -212,7 +212,7 @@ RemoteAdminStorage.prototype.createOrUpdateDomain = function (fCallback, bCreate, sName, sIncHost, iIncPort, sIncSecure, bIncShortLogin, - bUseSieve, bUseImapServerForSieve, sSieveHost, iSievePort, sSieveSecure, + bUseSieve, sSieveHost, iSievePort, sSieveSecure, sOutHost, iOutPort, sOutSecure, bOutShortLogin, bOutAuth, bOutPhpMail, sWhiteList) { @@ -226,7 +226,6 @@ 'IncShortLogin': bIncShortLogin ? '1' : '0', 'UseSieve': bUseSieve ? '1' : '0', - 'UseImapServerForSieve': bUseImapServerForSieve ? '1' : '0', 'SieveHost': sSieveHost, 'SievePort': iSievePort, 'SieveSecure': sSieveSecure, @@ -244,7 +243,7 @@ RemoteAdminStorage.prototype.testConnectionForDomain = function (fCallback, sName, sIncHost, iIncPort, sIncSecure, - bUseSieve, bUseImapServerForSieve, sSieveHost, iSievePort, sSieveSecure, + bUseSieve, sSieveHost, iSievePort, sSieveSecure, sOutHost, iOutPort, sOutSecure, bOutAuth, bOutPhpMail) { this.defaultRequest(fCallback, 'AdminDomainTest', { @@ -253,7 +252,6 @@ 'IncPort': iIncPort, 'IncSecure': sIncSecure, 'UseSieve': bUseSieve ? '1' : '0', - 'UseImapServerForSieve': bUseImapServerForSieve ? '1' : '0', 'SieveHost': sSieveHost, 'SievePort': iSievePort, 'SieveSecure': sSieveSecure, diff --git a/dev/Styles/@Main.less b/dev/Styles/@Main.less index ea0fd5ecb..d99146e14 100644 --- a/dev/Styles/@Main.less +++ b/dev/Styles/@Main.less @@ -90,6 +90,7 @@ @import "SettingsOpenPGP.less"; @import "SettingsFolders.less"; @import "SettingsThemes.less"; +@import "SettingsFilters.less"; @import "Animations.less"; //@import "Responsive.less"; diff --git a/dev/Styles/Compose.less b/dev/Styles/Compose.less index 343a053bf..e2e1ae4eb 100644 --- a/dev/Styles/Compose.less +++ b/dev/Styles/Compose.less @@ -68,7 +68,7 @@ border-bottom: 1px dashed #555; } } - + .e-row { line-height: 30px; } @@ -135,6 +135,12 @@ } } + .cke_chrome { + border-left-width: 0 !important; + border-right-width: 0 !important; + border-bottom-width: 0 !important; + } + .b-attachment-button { display: inline-block; } diff --git a/dev/Styles/Filter.less b/dev/Styles/Filter.less index fd2cebb19..d4860ab6e 100644 --- a/dev/Styles/Filter.less +++ b/dev/Styles/Filter.less @@ -1,10 +1,14 @@ .popups { .b-filter-content { - width: 800px; + width: 750px; .modal-header { background-color: #fff; } + + .button-delete { + cursor: pointer; + } } } diff --git a/dev/Styles/SettingsFilters.less b/dev/Styles/SettingsFilters.less new file mode 100644 index 000000000..a1c07b5a4 --- /dev/null +++ b/dev/Styles/SettingsFilters.less @@ -0,0 +1,59 @@ + +.b-settings-filters { + + .process-place { + text-align: center; + width: 600px; + padding: 14px 0; + } + + .list-table { + + width: 600px; + + td { + padding: 4px 8px; + line-height: 30px; + } + + .filter-img { + font-size: 12px; + margin-right: 5px; + } + + .filter-name { + display: inline-block; + word-break: break-all; + box-sizing: border-box; + line-height: 22px; + cursor: pointer; + } + } + + .filter-item { + + .e-action { + cursor: pointer; + } + + .button-delete { + margin-right: 15px; + margin-top: 5px; + visibility: hidden; + opacity: 0; + } + + .delete-access { + &.button-delete { + visibility: visible; + margin-right: 0; + opacity: 1; + } + } + + .delete-filter { + cursor: pointer; + opacity: 0.5; + } + } +} diff --git a/dev/Styles/SettingsIdentities.less b/dev/Styles/SettingsIdentities.less index 98917e230..5a600587e 100644 --- a/dev/Styles/SettingsIdentities.less +++ b/dev/Styles/SettingsIdentities.less @@ -10,6 +10,7 @@ .e-signature-place { display: inline-block; width: 680px; + width: 725px; height: 250px; } diff --git a/dev/Styles/SettingsIdentity.less b/dev/Styles/SettingsIdentity.less index e88b2ea3c..a99427467 100644 --- a/dev/Styles/SettingsIdentity.less +++ b/dev/Styles/SettingsIdentity.less @@ -3,6 +3,7 @@ .e-signature-place { display: inline-block; width: 680px; + width: 725px; height: 250px; } } diff --git a/dev/Styles/_CkeFix.less b/dev/Styles/_CkeFix.less index 039b471c5..158f07624 100644 --- a/dev/Styles/_CkeFix.less +++ b/dev/Styles/_CkeFix.less @@ -2,6 +2,40 @@ display: none !important; }*/ +.cke_chrome { + border: 1px solid #ccc !important; +} + +.cke_toolgroup, .cke_combo_button { + border: 1px solid #A6A6A6 !important; +} + +.cke_top { + padding: 6px 4px 1px 6px !important; + -moz-box-shadow: none !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; +} + +.cke_button { + padding: 5px 6px !important; +} + +.cke_combo_text { + line-height: 28px !important; + padding-left: 8px !important; +} + +.cke_combo_button { + background: #FBFBFB !important; +} + +.cke_source { + font-family: Monaco, Menlo, Consolas, 'Courier New', monospace !important; + padding: 10px !important; + padding-right: 0 !important; +} + .cke_plain { background-color: #fff; @@ -38,7 +72,7 @@ } .cke_wysiwyg_div { - + padding: 10px !important; font-family: arial, sans-serif; font-size: 13px; diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js index ffa6d4855..2039a4eb8 100644 --- a/dev/View/Popup/Compose.js +++ b/dev/View/Popup/Compose.js @@ -1052,10 +1052,10 @@ return false; }); - key('ctrl+enter, command+enter', Enums.KeyState.Compose, function () { - self.sendCommand(); - return false; - }); +// key('ctrl+enter, command+enter', Enums.KeyState.Compose, function () { +// self.sendCommand(); +// return false; +// }); key('esc', Enums.KeyState.Compose, function () { if (self.modalVisibility()) diff --git a/dev/View/Popup/Domain.js b/dev/View/Popup/Domain.js index 6beebf39a..732316111 100644 --- a/dev/View/Popup/Domain.js +++ b/dev/View/Popup/Domain.js @@ -12,6 +12,7 @@ Utils = require('Common/Utils'), Remote = require('Storage/Admin/Remote'), + Settings = require('Storage/Settings'), kn = require('Knoin/Knoin'), AbstractView = require('Knoin/AbstractView') @@ -62,14 +63,13 @@ this.name = ko.observable(''); this.name.focused = ko.observable(false); - this.allowSieve = ko.observable(false); + this.allowSieve = ko.observable(Settings.capa(Enums.Capa.Sieve)); this.imapServer = ko.observable(''); this.imapPort = ko.observable('' + Consts.Values.ImapDefaulPort); this.imapSecure = ko.observable(Enums.ServerSecure.None); this.imapShortLogin = ko.observable(false); this.useSieve = ko.observable(false); - this.useImapServerForSieve = ko.observable(true); this.sieveServer = ko.observable(''); this.sievePort = ko.observable('' + Consts.Values.SieveDefaulPort); this.sieveSecure = ko.observable(Enums.ServerSecure.None); @@ -94,14 +94,13 @@ var bPhpMail = this.smtpPhpMail(), bAllowSieve = this.allowSieve(), - bUseSieve = this.useSieve(), - bIseImapServerForSieve = this.useImapServerForSieve() + bUseSieve = this.useSieve() ; return '' !== this.name() && '' !== this.imapServer() && '' !== this.imapPort() && - (bAllowSieve && bUseSieve ? (bIseImapServerForSieve ? true : ('' !== this.sieveServer() && '' !== this.sievePort())) : true) && + (bAllowSieve && bUseSieve ? ('' !== this.sieveServer() && '' !== this.sievePort()) : true) && (('' !== this.smtpServer() && '' !== this.smtpPort()) || bPhpMail); }, this); @@ -127,7 +126,6 @@ this.imapShortLogin(), this.useSieve(), - this.useImapServerForSieve(), this.sieveServer(), Utils.pInt(this.sievePort()), this.sieveSecure(), @@ -162,7 +160,6 @@ this.imapSecure(), this.useSieve(), - this.useImapServerForSieve(), this.sieveServer(), Utils.pInt(this.sievePort()), this.sieveSecure(), @@ -201,9 +198,9 @@ }, this); this.sieveServerFocus.subscribe(function (bValue) { - if (bValue && '' !== this.name() && '' === this.sieveServer()) + if (bValue && '' !== this.imapServer() && '' === this.sieveServer()) { - this.sieveServer(this.name().replace(/[.]?[*][.]?/g, '')); + this.sieveServer(this.imapServer()); } }, this); @@ -356,7 +353,6 @@ this.imapSecure(Utils.trim(oDomain.IncSecure)); this.imapShortLogin(!!oDomain.IncShortLogin); this.useSieve(!!oDomain.UseSieve); - this.useImapServerForSieve(!!oDomain.UseImapServerForSieve); this.sieveServer(Utils.trim(oDomain.SieveHost)); this.sievePort('' + Utils.pInt(oDomain.SievePort)); this.sieveSecure(Utils.trim(oDomain.SieveSecure)); @@ -400,7 +396,6 @@ this.imapShortLogin(false); this.useSieve(false); - this.useImapServerForSieve(true); this.sieveServer(''); this.sievePort('' + Consts.Values.SieveDefaulPort); this.sieveSecure(Enums.ServerSecure.None); diff --git a/dev/View/Popup/Languages.js b/dev/View/Popup/Languages.js index 9762c06aa..6ee6d47f9 100644 --- a/dev/View/Popup/Languages.js +++ b/dev/View/Popup/Languages.js @@ -48,7 +48,8 @@ LanguagesPopupView.prototype.languageEnName = function (sLanguage) { - return Utils.convertLangName(sLanguage, true); + var sResult = Utils.convertLangName(sLanguage, true); + return 'English' === sResult ? '' : sResult; }; LanguagesPopupView.prototype.resetMainLanguage = function () diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js index b31d51587..2fa1cd386 100644 --- a/dev/View/User/MailBox/MessageView.js +++ b/dev/View/User/MailBox/MessageView.js @@ -452,12 +452,6 @@ } }); - // TODO // more toggle - // key('', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { - // self.moreDropdownTrigger(true); - // return false; - // }); - // reply key('r', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { if (Data.message()) diff --git a/dev/bootstrap.js b/dev/bootstrap.js index 6777c7377..2dd1bcd20 100644 --- a/dev/bootstrap.js +++ b/dev/bootstrap.js @@ -42,6 +42,7 @@ window['rl']['remoteRequest'] = _.bind(Plugins.remoteRequest, Plugins); window['rl']['pluginSettingsGet'] = _.bind(Plugins.settingsGet, Plugins); window['rl']['createCommand'] = Utils.createCommand; + window['rl']['i18n'] = Utils.i18n; window['rl']['EmailModel'] = EmailModel; window['rl']['Enums'] = Enums; diff --git a/gulpfile.js b/gulpfile.js index a09f8c757..d1529077d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -30,6 +30,7 @@ var concat = require('gulp-concat-util'), header = require('gulp-header'), eol = require('gulp-eol'), + stripbom = require('gulp-stripbom'), rename = require('gulp-rename'), replace = require('gulp-replace'), uglify = require('gulp-uglify'), @@ -188,7 +189,7 @@ gulp.task('less:main', function() { .pipe(gulp.dest(cfg.paths.staticCSS)); }); -gulp.task('css:main', ['less:main'], function() { +gulp.task('css:main-begin', ['less:main'], function() { var // csslint = require('gulp-csslint'), @@ -208,6 +209,14 @@ gulp.task('css:main', ['less:main'], function() { ; }); +gulp.task('css:clear-less', ['css:main-begin'], function() { + + return gulp.src(cfg.paths.staticCSS + cfg.paths.less.main.name, {read: false}) + .pipe(require('gulp-rimraf')()); +}); + +gulp.task('css:main', ['css:clear-less']); + gulp.task('css:main:min', ['css:main'], function() { var minifyCss = require('gulp-minify-css'); return gulp.src(cfg.paths.staticCSS + cfg.paths.css.main.name) @@ -381,6 +390,39 @@ gulp.task('package-inc-release', function() { (1 + parseInt(pkg.release, 10)) + '",')); }); +gulp.task('fontastic-fonts:clear', function() { + return cleanDir('rainloop/v/' + cfg.devVersion + '/static/css/fonts/rainloop.*'); +}); + +gulp.task('fontastic-fonts:copy', ['fontastic-fonts:clear'], function() { + return gulp.src('vendors/fontastic/fonts/rainloop.*') + .pipe(gulp.dest('rainloop/v/' + cfg.devVersion + '/static/css/fonts')); +}); + +gulp.task('fontastic', ['fontastic-fonts:copy']); + +gulp.task('ckeditor:clear', function() { + return cleanDir('rainloop/v/' + cfg.devVersion + '/static/ckeditor'); +}); + +gulp.task('ckeditor:copy', ['ckeditor:clear'], function() { + return gulp.src('vendors/ckeditor/**/*') + .pipe(gulp.dest('rainloop/v/' + cfg.devVersion + '/static/ckeditor')); +}); + +gulp.task('ckeditor:copy-plugins', ['ckeditor:copy'], function() { + return gulp.src('vendors/ckeditor-plugins/**/*') + .pipe(gulp.dest('rainloop/v/' + cfg.devVersion + '/static/ckeditor/plugins')); +}); + +gulp.task('ckeditor', ['ckeditor:copy-plugins'], function () { + return gulp.src('rainloop/v/' + cfg.devVersion + '/static/ckeditor/*.js') + .pipe(stripbom()) + .pipe(replace("\u200B", "\\u200B")) + .pipe(header("\uFEFF")) // BOM + .pipe(gulp.dest('rainloop/v/' + cfg.devVersion + '/static/ckeditor')); +}); + // BUILD (RainLoop) gulp.task('rainloop:copy', ['default'], function() { @@ -412,8 +454,6 @@ gulp.task('rainloop:setup', ['rainloop:copy'], function() { fs.writeFileSync(dist + 'rainloop/v/' + versionFull + '/index.php.root', fs.readFileSync(dist + 'index.php')); - fs.unlinkSync(dist + 'rainloop/v/' + versionFull + '/static/css/less.css'); - cfg.destPath = cfg.releasesPath + '/webmail/' + versionFull + '/'; cfg.cleanPath = dist; cfg.zipSrcPath = dist; @@ -486,7 +526,7 @@ gulp.task('rainloop:owncloud:clean', ['rainloop:owncloud:copy', 'rainloop:ownclo }); // MAIN -gulp.task('default', ['js:libs', 'js:boot', 'js:openpgp', 'js:min', 'css:main:min']); +gulp.task('default', ['js:libs', 'js:boot', 'js:openpgp', 'js:min', 'css:main:min', 'ckeditor', 'fontastic']); gulp.task('fast', ['js:app', 'js:admin', 'js:chunks', 'css:main']); gulp.task('rainloop', ['js:lint', 'rainloop:copy', 'rainloop:setup', 'rainloop:zip', 'rainloop:md5', 'rainloop:clean']); diff --git a/package.json b/package.json index 6d2ec2704..a35dc8e77 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "RainLoop", "title": "RainLoop Webmail", "version": "1.7.0", - "release": "204", + "release": "207", "description": "Simple, modern & fast web-based email client", "homepage": "http://rainloop.net", "main": "gulpfile.js", @@ -58,6 +58,7 @@ "gulp-replace": "*", "gulp-header": "*", "gulp-eol": "*", + "gulp-stripbom": "*", "gulp-minify-css": "*", "gulp-autoprefixer": "*", "gulp-csscomb": "*", diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php b/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php index 6e65504ac..7c920969c 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Net/NetClient.php @@ -508,10 +508,10 @@ abstract class NetClient $iReadedLen = \strlen($this->sResponseBuffer); if (null === $mReadLen || $bForceLogin) { - $iLimit = 5000; // 5kb + $iLimit = 5000; // 5KB if ($iLimit < $iReadedLen) { - $this->writeLogWithCrlf('[cutted:'.$iReadedLen.'b] < '.\substr($this->sResponseBuffer.'...', 0, $iLimit), + $this->writeLogWithCrlf('[cutted:'.$iReadedLen.'] < '.\substr($this->sResponseBuffer, 0, $iLimit).'...', \MailSo\Log\Enumerations\Type::INFO); } else 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 baddec787..42d42470d 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Actions.php @@ -70,6 +70,11 @@ class Actions */ private $oSettingsProvider; + /** + * @var \RainLoop\Providers\Filters + */ + private $oFiltersProvider; + /** * @var \RainLoop\Providers\AddressBook */ @@ -118,6 +123,7 @@ class Actions $this->oStorageProvider = null; $this->oFilesProvider = null; $this->oSettingsProvider = null; + $this->oFiltersProvider = null; $this->oDomainProvider = null; $this->oAddressBookProvider = null; $this->oSuggestionsProvider = null; @@ -242,6 +248,10 @@ class Actions // \RainLoop\Providers\Domain\DomainAdminInterface $oResult = new \RainLoop\Providers\Domain\DefaultDomain(APP_PRIVATE_DATA.'domains', $this->Cacher()); break; + case 'filters': + // \RainLoop\Providers\Filters\FiltersInterface + $oResult = new \RainLoop\Providers\Filters\SieveStorage(); + break; case 'address-book': // \RainLoop\Providers\AddressBook\AddressBookInterface @@ -574,6 +584,20 @@ class Actions return $this->oSettingsProvider; } + /** + * @return \RainLoop\Providers\Filters + */ + public function FiltersProvider() + { + if (null === $this->oFiltersProvider) + { + $this->oFiltersProvider = new \RainLoop\Providers\Filters( + $this->fabrica('filters')); + } + + return $this->oFiltersProvider; + } + /** * @return \RainLoop\Providers\ChangePassword */ @@ -992,6 +1016,14 @@ class Actions return $bResult; } + /** + * @return bool + */ + private function UseSieve() + { + return false; // TODO + } + /** * @param bool $bAdmin * @param string $sAuthAccountHash = '' @@ -1044,6 +1076,7 @@ class Actions 'ContactsIsAllowed' => false, 'ChangePasswordIsAllowed' => false, 'JsHash' => \md5(\RainLoop\Utils::GetConnectionToken()), + 'UseSieve' => $this->UseSieve(), 'UseImapThread' => (bool) $oConfig->Get('labs', 'use_imap_thread', false), 'UseImapSubscribe' => (bool) $oConfig->Get('labs', 'use_imap_list_subscribe', true), 'AllowAppendMessage' => (bool) $oConfig->Get('labs', 'allow_message_append', false), @@ -3188,10 +3221,27 @@ class Actions return $aResult; } + /** + * @return string + */ + private function getCoreChannel() + { + $sChannel = \trim(\strtolower($this->Config()->Get('labs', 'update_channel', 'stable'))); + if (empty($sChannel) || !\in_array($sChannel, array('stable', 'beta'))) + { + $sChannel = 'stable'; + } + + return $sChannel; + } + private function getCoreData(&$bReal) { $bReal = false; - $sRepo = APP_REPO_CORE_FILE; + + $sChannel = $this->getCoreChannel(); + + $sRepo = \str_replace('{{channel}}', $sChannel, APP_REPO_CORE_FILE); $oHttp = \MailSo\Base\Http::SingletonInstance(); @@ -3341,11 +3391,14 @@ class Actions } $sVersion = empty($aData['version']) ? '' : $aData['version']; + $sType = empty($aData['channel']) ? 'stable' : $aData['channel']; return $this->DefaultResponse(__FUNCTION__, array( 'Real' => $bReal, 'Access' => $bRainLoopAccess, 'Updatable' => $bRainLoopUpdatable, + 'Channel' => $this->getCoreChannel(), + 'Type' => $sType, 'Version' => APP_VERSION, 'RemoteVersion' => $sVersion, 'RemoteRelease' => empty($aData['release']) ? '' : $aData['release'], @@ -6058,19 +6111,19 @@ class Actions * @param string $sFileName * @param string $sContentType * @param string $sMimeIndex + * @param int $iMaxLength = 250 * * @return string */ - public function MainClearFileName($sFileName, $sContentType, $sMimeIndex) + public function MainClearFileName($sFileName, $sContentType, $sMimeIndex, $iMaxLength = 250) { - $sFileName = 0 === strlen($sFileName) ? preg_replace('/[^a-zA-Z0-9]/', '.', (empty($sMimeIndex) ? '' : $sMimeIndex.'.').$sContentType) : $sFileName; - $sClearedFileName = preg_replace('/[\s]+/', ' ', preg_replace('/[\.]+/', '.', $sFileName)); + $sFileName = 0 === \strlen($sFileName) ? \preg_replace('/[^a-zA-Z0-9]/', '.', (empty($sMimeIndex) ? '' : $sMimeIndex.'.').$sContentType) : $sFileName; + $sClearedFileName = \preg_replace('/[\s]+/', ' ', \preg_replace('/[\.]+/', '.', $sFileName)); $sExt = \MailSo\Base\Utils::GetFileExtension($sClearedFileName); - $iSize = 50; - if ($iSize < strlen($sClearedFileName) - strlen($sExt)) + if (10 < $iMaxLength && $iMaxLength < \strlen($sClearedFileName) - \strlen($sExt)) { - $sClearedFileName = substr($sClearedFileName, 0, $iSize).(empty($sExt) ? '' : '.'.$sExt); + $sClearedFileName = \substr($sClearedFileName, 0, $iMaxLength).(empty($sExt) ? '' : '.'.$sExt); } return \MailSo\Base\Utils::ClearFileName(\MailSo\Base\Utils::Utf8Clear($sClearedFileName)); @@ -6787,9 +6840,15 @@ class Actions { $oConfig = $this->Config(); - $aResult = array( -// \RainLoop\Enumerations\Capa::FILTERS - ); + $aResult = array(); + + if ($this->UseSieve()) + { + if ($bAdmin || ($oAccount && $oAccount->Domain()->UseSieve())) + { + $aResult[] = \RainLoop\Enumerations\Capa::SIEVE; + } + } if ($oConfig->Get('webmail', 'allow_additional_accounts', false)) { diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Api.php b/rainloop/v/0.0.0/app/src/RainLoop/Api.php index f9b0d6d50..13b3d7e21 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Api.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Api.php @@ -97,13 +97,22 @@ class Api \MailSo\Config::$SystemLogger = \RainLoop\Api::Logger(); $sSslCafile = \RainLoop\Api::Config()->Get('ssl', 'cafile', ''); - if (!empty($sSslCafile)) + $sSslCapath = \RainLoop\Api::Config()->Get('ssl', 'capath', ''); + + if (!empty($sSslCafile) || !empty($sSslCapath)) { - \MailSo\Hooks::Add('Net.NetClient.StreamContextSettings/Filter', function (&$aStreamContextSettings) use ($sSslCafile) { - if (isset($aStreamContextSettings['ssl']) && \is_array($aStreamContextSettings['ssl']) && - empty($aStreamContextSettings['ssl']['cafile'])) + \MailSo\Hooks::Add('Net.NetClient.StreamContextSettings/Filter', function (&$aStreamContextSettings) use ($sSslCafile, $sSslCapath) { + if (isset($aStreamContextSettings['ssl']) && \is_array($aStreamContextSettings['ssl'])) { - $aStreamContextSettings['ssl']['cafile'] = $sSslCafile; + if (empty($aStreamContextSettings['ssl']['cafile']) && !empty($sSslCafile)) + { + $aStreamContextSettings['ssl']['cafile'] = $sSslCafile; + } + + if (empty($aStreamContextSettings['ssl']['capath']) && !empty($sSslCapath)) + { + $aStreamContextSettings['ssl']['capath'] = $sSslCapath; + } } }); } 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 202b63444..56b870026 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 @@ -119,6 +119,7 @@ class Application extends \RainLoop\Config\AbstractConfig 'ssl' => array( 'verify_certificate' => array(false, 'Require verification of SSL certificate used.'), 'cafile' => array('', 'Location of Certificate Authority file on local filesystem (/etc/ssl/certs/ca-certificates.crt)'), + 'capath' => array('', 'capath must be a correctly hashed certificate directory. (/etc/ssl/certs/)'), ), 'login' => array( @@ -233,6 +234,7 @@ Enables caching in the system'), 'Experimental settings. Handle with care. '), 'check_new_password_strength' => array(true), + 'update_channel' => array('stable'), 'allow_gravatar' => array(true), 'allow_prefetch' => array(true), 'allow_smart_html_links' => array(true), diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Enumerations/Capa.php b/rainloop/v/0.0.0/app/src/RainLoop/Enumerations/Capa.php index 3cea595ea..02e9953f8 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Enumerations/Capa.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Enumerations/Capa.php @@ -11,7 +11,7 @@ class Capa const GRAVATAR = 'GRAVATAR'; const THEMES = 'THEMES'; const USER_BACKGROUND = 'USER_BACKGROUND'; - const FILTERS = 'FILTERS'; + const SIEVE = 'SIEVE'; const ADDITIONAL_ACCOUNTS = 'ADDITIONAL_ACCOUNTS'; const ADDITIONAL_IDENTITIES = 'ADDITIONAL_IDENTITIES'; } diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Model/Domain.php b/rainloop/v/0.0.0/app/src/RainLoop/Model/Domain.php index 4cc54e461..c2873ea80 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Model/Domain.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Model/Domain.php @@ -68,11 +68,6 @@ class Domain */ private $bUseSieve; - /** - * @var bool - */ - private $bUseImapServerForSieve; - /** * @var string */ @@ -100,7 +95,6 @@ class Domain * @param int $iIncSecure * @param bool $bIncShortLogin * @param bool $bUseSieve - * @param bool $bUseImapServerForSieve * @param string $sSieveHost * @param int $iSievePort * @param int $iSieveSecure @@ -114,7 +108,7 @@ class Domain */ private function __construct($sName, $sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin, - $bUseSieve, $bUseImapServerForSieve, $sSieveHost, $iSievePort, $iSieveSecure, + $bUseSieve, $sSieveHost, $iSievePort, $iSieveSecure, $sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth, $bOutUsePhpMail = false, $sWhiteList = '') { @@ -132,7 +126,6 @@ class Domain $this->bOutUsePhpMail = $bOutUsePhpMail; $this->bUseSieve = $bUseSieve; - $this->bUseImapServerForSieve = $bUseImapServerForSieve; $this->sSieveHost = $sSieveHost; $this->iSievePort = $iSievePort; $this->iSieveSecure = $iSieveSecure; @@ -147,7 +140,6 @@ class Domain * @param int $iIncSecure * @param bool $bIncShortLogin * @param bool $bUseSieve - * @param bool $bUseImapServerForSieve * @param string $sSieveHost * @param int $iSievePort * @param int $iSieveSecure @@ -163,13 +155,13 @@ class Domain */ public static function NewInstance($sName, $sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin, - $bUseSieve, $bUseImapServerForSieve, $sSieveHost, $iSievePort, $iSieveSecure, + $bUseSieve, $sSieveHost, $iSievePort, $iSieveSecure, $sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth, $bOutUsePhpMail, $sWhiteList = '') { return new self($sName, $sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin, - $bUseSieve, $bUseImapServerForSieve, $sSieveHost, $iSievePort, $iSieveSecure, + $bUseSieve, $sSieveHost, $iSievePort, $iSieveSecure, $sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth, $bOutUsePhpMail, $sWhiteList); } @@ -191,6 +183,8 @@ class Domain $iIncSecure = self::StrConnectionSecurityTypeToCons( !empty($aDomain['imap_secure']) ? $aDomain['imap_secure'] : ''); + $bUseSieve = isset($aDomain['sieve_use']) ? (bool) $aDomain['sieve_use'] : false; + $sSieveHost = empty($aDomain['sieve_host']) ? '' : (string) $aDomain['sieve_host']; $iSievePort = empty($aDomain['sieve_port']) ? 2000 : (int) $aDomain['sieve_port']; $iSieveSecure = self::StrConnectionSecurityTypeToCons( @@ -205,15 +199,12 @@ class Domain $bOutUsePhpMail = isset($aDomain['smtp_php_mail']) ? (bool) $aDomain['smtp_php_mail'] : false; $sWhiteList = (string) (isset($aDomain['white_list']) ? $aDomain['white_list'] : ''); - $bUseSieve = isset($aDomain['sieve_use']) ? (bool) $aDomain['sieve_use'] : false; - $bUseImapServerForSieve = isset($aDomain['sieve_use_imap_server']) ? (bool) $aDomain['sieve_use_imap_server'] : true; - $bIncShortLogin = isset($aDomain['imap_short_login']) ? (bool) $aDomain['imap_short_login'] : false; $bOutShortLogin = isset($aDomain['smtp_short_login']) ? (bool) $aDomain['smtp_short_login'] : false; $oDomain = self::NewInstance($sName, $sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin, - $bUseSieve, $bUseImapServerForSieve, $sSieveHost, $iSievePort, $iSieveSecure, + $bUseSieve, $sSieveHost, $iSievePort, $iSieveSecure, $sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth, $bOutUsePhpMail, $sWhiteList); } @@ -266,7 +257,6 @@ class Domain 'imap_secure = "'.self::ConstConnectionSecurityTypeToStr($this->iIncSecure).'"', 'imap_short_login = '.($this->bIncShortLogin ? 'On' : 'Off'), 'sieve_use = '.($this->bUseSieve ? 'On' : 'Off'), - 'sieve_use_imap_server = '.($this->bUseImapServerForSieve ? 'On' : 'Off'), 'sieve_host = "'.$this->encodeIniString($this->sSieveHost).'"', 'sieve_port = '.$this->iSievePort, 'sieve_secure = "'.self::ConstConnectionSecurityTypeToStr($this->iSieveSecure).'"', @@ -327,7 +317,6 @@ class Domain * @param int $iIncSecure * @param bool $bIncShortLogin * @param bool $bUseSieve - * @param bool $bUseImapServerForSieve * @param string $sOutHost * @param int $iOutPort * @param int $iOutSecure @@ -340,7 +329,7 @@ class Domain */ public function UpdateInstance( $sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin, - $bUseSieve, $bUseImapServerForSieve, $sSieveHost, $iSievePort, $iSieveSecure, + $bUseSieve, $sSieveHost, $iSievePort, $iSieveSecure, $sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth, $bOutUsePhpMail, $sWhiteList = '') { @@ -350,7 +339,6 @@ class Domain $this->bIncShortLogin = $bIncShortLogin; $this->bUseSieve = $bUseSieve; - $this->bUseImapServerForSieve = $bUseImapServerForSieve; $this->sSieveHost = \MailSo\Base\Utils::IdnToAscii($sSieveHost); $this->iSievePort = $iSievePort; $this->iSieveSecure = $iSieveSecure; @@ -415,14 +403,6 @@ class Domain return $this->bUseSieve; } - /** - * @return bool - */ - public function UseImapServerForSieve() - { - return $this->bUseImapServerForSieve; - } - /** * @return string */ @@ -541,7 +521,6 @@ class Domain 'IncSecure' => $this->IncSecure(), 'IncShortLogin' => $this->IncShortLogin(), 'UseSieve' => $this->UseSieve(), - 'UseImapServerForSieve' => $this->UseImapServerForSieve(), 'SieveHost' => $bAjax ? \MailSo\Base\Utils::IdnToUtf8($this->SieveHost()) : $this->SieveHost(), 'SievePort' => $this->SievePort(), 'SieveSecure' => $this->SieveSecure(), diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Plugins/AbstractPlugin.php b/rainloop/v/0.0.0/app/src/RainLoop/Plugins/AbstractPlugin.php index f4ab21c7c..73cdbeda1 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Plugins/AbstractPlugin.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Plugins/AbstractPlugin.php @@ -130,15 +130,15 @@ abstract class AbstractPlugin { return array(); } - + /** * @return string */ public function Hash() { - return \md5($this->sVersion); + return \md5($this->sName.'@'.$this->sVersion); } - + /** * @return string */ @@ -146,7 +146,7 @@ abstract class AbstractPlugin { return ''; } - + /** * @final * @return array @@ -161,22 +161,41 @@ abstract class AbstractPlugin $this->aConfigMap = array(); } } - + return $this->aConfigMap; } /** * @param string $sPath - * @param string $sName - * @param string $sVersion = '' * * @return self */ - public function SetValues($sPath, $sName, $sVersion = '') + public function SetPath($sPath) { - $this->sName = $sName; $this->sPath = $sPath; + return $this; + } + + /** + * @param string $sName + * + * @return self + */ + public function SetName($sName) + { + $this->sName = $sName; + + return $this; + } + + /** + * @param string $sVersion + * + * @return self + */ + public function SetVersion($sVersion) + { if (0 < \strlen($sVersion)) { $this->sVersion = $sVersion; @@ -222,14 +241,14 @@ abstract class AbstractPlugin */ public function Init() { - + } /** * @param bool $bAdmin * @param bool $bAuth * @param array $aConfig - * + * * @return void */ public function FilterAppDataPluginSection($bAdmin, $bAuth, &$aConfig) diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Plugins/Manager.php b/rainloop/v/0.0.0/app/src/RainLoop/Plugins/Manager.php index e4e0cee89..797c08e30 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Plugins/Manager.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Plugins/Manager.php @@ -107,13 +107,15 @@ class Manager } } } + + $this->RunHook('api.bootstrap.plugins'); } } /** * @param string $sName * - * @return \RainLoop\Plugins\AbstractPlugin | null + * @return \RainLoop\Plugins\AbstractPlugin|null */ public function CreatePluginByName($sName) { @@ -134,9 +136,10 @@ class Manager if ($oPlugin instanceof \RainLoop\Plugins\AbstractPlugin) { $oPlugin - ->SetValues(APP_PLUGINS_PATH.$sName, $sName, - \file_exists(APP_PLUGINS_PATH.$sName.'/VERSION') ? - \file_get_contents(APP_PLUGINS_PATH.$sName.'/VERSION') : '') + ->SetName($sName) + ->SetPath(APP_PLUGINS_PATH.$sName) + ->SetVersion(\file_exists(APP_PLUGINS_PATH.$sName.'/VERSION') ? + \file_get_contents(APP_PLUGINS_PATH.$sName.'/VERSION') : '') ->SetPluginManager($this) ->SetPluginConfig(new \RainLoop\Config\Plugin($sName, $oPlugin->ConfigMap())) ; @@ -167,9 +170,8 @@ class Manager if (\preg_match('/^[a-z0-9\-]+$/', $sName) && \file_exists($sPathName.'/index.php')) { - $sVersion = @\file_get_contents($sPathName.'/VERSION'); $aList[] = array( - $sName, $sVersion + $sName, @\file_get_contents($sPathName.'/VERSION') ); } } @@ -205,7 +207,7 @@ class Manager } /** - * @return \RainLoop\Actions + * @return string */ public function Hash() { @@ -231,14 +233,14 @@ class Manager $aJs = $bAdminScope ? $this->aAdminJs : $this->aJs; foreach ($aJs as $sFile) { - if (file_exists($sFile)) + if (\file_exists($sFile)) { - $aResult[] = file_get_contents($sFile); + $aResult[] = \file_get_contents($sFile); } } } - return implode("\n", $aResult); + return \implode("\n", $aResult); } /** @@ -279,12 +281,13 @@ class Manager /** * @param bool $bAdmin * @param array $aAppData + * @param \RainLoop\Model\Account|null $oAccount = null * * @return \RainLoop\Plugins\Manager */ public function InitAppData($bAdmin, &$aAppData, $oAccount = null) { - if ($this->bIsEnabled && isset($aAppData['Plugins']) && is_array($aAppData['Plugins'])) + if ($this->bIsEnabled && isset($aAppData['Plugins']) && \is_array($aAppData['Plugins'])) { $bAuth = isset($aAppData['Auth']) && !!$aAppData['Auth']; foreach ($this->aPlugins as $oPlugin) @@ -317,6 +320,12 @@ class Manager } $this->RunHook('filter.app-data', array($bAdmin, &$aAppData)); + + $this->RunHook('filter.app-data[2]', array( + 'IsAdmin' => $bAdmin, + 'AppData' => &$aAppData, + 'Account' => $oAccount + )); } return $this; @@ -330,7 +339,7 @@ class Manager */ public function AddHook($sHookName, $mCallbak) { - if ($this->bIsEnabled && is_callable($mCallbak)) + if ($this->bIsEnabled && \is_callable($mCallbak)) { if (!isset($this->aHooks[$sHookName])) { @@ -407,9 +416,9 @@ class Manager $this->WriteLog('Hook: '.$sHookName, \MailSo\Log\Enumerations\Type::NOTE); } - foreach ($this->aHooks[$sHookName] as $mCallbak) + foreach ($this->aHooks[$sHookName] as $mCallback) { - call_user_func_array($mCallbak, $aArg); + \call_user_func_array($mCallback, $aArg); } } } @@ -491,11 +500,11 @@ class Manager if ($bPrepend) { - array_unshift($this->aProcessTemplate[$sName][$sPlace], $sHtml); + \array_unshift($this->aProcessTemplate[$sName][$sPlace], $sHtml); } else { - array_push($this->aProcessTemplate[$sName][$sPlace], $sHtml); + \array_push($this->aProcessTemplate[$sName][$sPlace], $sHtml); } } @@ -510,7 +519,7 @@ class Manager */ public function AddAdditionalAjaxAction($sActionName, $mCallbak) { - if ($this->bIsEnabled && is_callable($mCallbak) && 0 < strlen($sActionName)) + if ($this->bIsEnabled && \is_callable($mCallbak) && 0 < \strlen($sActionName)) { $sActionName = 'Do'.$sActionName; @@ -544,7 +553,7 @@ class Manager { if (isset($this->aAdditionalAjax[$sActionName])) { - return call_user_func($this->aAdditionalAjax[$sActionName]); + return \call_user_func($this->aAdditionalAjax[$sActionName]); } } @@ -641,29 +650,29 @@ class Manager /** * @param string $sDesc - * @param int $iDescType = \MailSo\Log\Enumerations\Type::INFO + * @param int $iType = \MailSo\Log\Enumerations\Type::INFO * * @return void */ - public function WriteLog($sDesc, $iDescType = \MailSo\Log\Enumerations\Type::INFO) + public function WriteLog($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO) { if ($this->oLogger) { - $this->oLogger->Write($sDesc, $iDescType, 'PLUGIN'); + $this->oLogger->Write($sDesc, $iType, 'PLUGIN'); } } /** * @param string $sDesc - * @param int $iDescType = \MailSo\Log\Enumerations\Type::INFO + * @param int $iType = \MailSo\Log\Enumerations\Type::INFO * * @return void */ - public function WriteException($sDesc, $iDescType = \MailSo\Log\Enumerations\Type::INFO) + public function WriteException($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO) { if ($this->oLogger) { - $this->oLogger->WriteException($sDesc, $iDescType, 'PLUGIN'); + $this->oLogger->WriteException($sDesc, $iType, 'PLUGIN'); } } } diff --git a/rainloop/v/0.0.0/app/src/RainLoop/PluginsNext/AbstractPlugin.php b/rainloop/v/0.0.0/app/src/RainLoop/PluginsNext/AbstractPlugin.php deleted file mode 100644 index bb374b0dd..000000000 --- a/rainloop/v/0.0.0/app/src/RainLoop/PluginsNext/AbstractPlugin.php +++ /dev/null @@ -1,340 +0,0 @@ -sName = ''; - $this->sPath = ''; - $this->sVersion = '0.0'; - $this->aConfigMap = null; - - $this->oPluginManager = null; - $this->oPluginConfig = null; - $this->bPluginConfigLoaded = false; - $this->bLangs = false; - } - - /** - * @return \RainLoop\Config\Plugin - */ - public function Config() - { - if (!$this->bPluginConfigLoaded && $this->oPluginConfig) - { - $this->bPluginConfigLoaded = true; - if ($this->oPluginConfig->IsInited()) - { - if (!$this->oPluginConfig->Load()) - { - $this->oPluginConfig->Save(); - } - } - } - - return $this->oPluginConfig; - } - - /** - * @return \RainLoop\PluginsNext\Manager - */ - public function Manager() - { - return $this->oPluginManager; - } - - /** - * @return string - */ - public function Path() - { - return $this->sPath; - } - - /** - * @return string - */ - public function Name() - { - return $this->sName; - } - - /** - * @return string - */ - public function Version() - { - return $this->sVersion; - } - - /** - * @param bool|null $bLangs = null - * @return bool - */ - public function UseLangs($bLangs = null) - { - if (null !== $bLangs) - { - $this->bLangs = (bool) $bLangs; - } - - return $this->bLangs; - } - - /** - * @return array - */ - protected function configMapping() - { - return array(); - } - - /** - * @return string - */ - public function Hash() - { - return \md5($this->sVersion); - } - - /** - * @return string - */ - public function Supported() - { - return ''; - } - - /** - * @final - * @return array - */ - final public function ConfigMap() - { - if (null === $this->aConfigMap) - { - $this->aConfigMap = $this->configMapping(); - if (!\is_array($this->aConfigMap)) - { - $this->aConfigMap = array(); - } - } - - return $this->aConfigMap; - } - - /** - * @param string $sPath - * @param string $sName - * @param string $sVersion = '' - * - * @return self - */ - public function SetValues($sPath, $sName, $sVersion = '') - { - $this->sName = $sName; - $this->sPath = $sPath; - - if (0 < \strlen($sVersion)) - { - $this->sVersion = $sVersion; - } - - return $this; - } - - /** - * @param \RainLoop\PluginsNext\Manager $oPluginManager - * - * @return self - */ - public function SetPluginManager(\RainLoop\PluginsNext\Manager $oPluginManager) - { - $this->oPluginManager = $oPluginManager; - - return $this; - } - - /** - * @param \RainLoop\Config\Plugin $oPluginConfig - * - * @return self - */ - public function SetPluginConfig(\RainLoop\Config\Plugin $oPluginConfig) - { - $this->oPluginConfig = $oPluginConfig; - - return $this; - } - - /** - * @return self - */ - public function Init() - { - - } - - /** - * @param string $sStep - * - * @return self - */ - public function InitStep($sStep) - { - - } - - /** - * @param bool $bAdmin - * @param bool $bAuth - * @param array $aConfig - * - * @return void - */ - public function FilterAppDataPluginSection($bAdmin, $bAuth, &$aConfig) - { - - } - - /** - * @param string $sHookName - * @param string $sFunctionName - * - * @return self - */ - protected function addHook($sHookName, $sFunctionName) - { - if ($this->oPluginManager) - { - $this->oPluginManager->AddHook($sHookName, array(&$this, $sFunctionName)); - } - - return $this; - } - - /** - * @param string $sFile - * @param bool $bAdminScope = false - * - * @return self - */ - protected function addJs($sFile, $bAdminScope = false) - { - if ($this->oPluginManager) - { - $this->oPluginManager->AddJs($this->sPath.'/'.$sFile, $bAdminScope); - } - - return $this; - } - - /** - * @param string $sFile - * @param bool $bAdminScope = false - * - * @return self - */ - protected function addTemplate($sFile, $bAdminScope = false) - { - if ($this->oPluginManager) - { - $this->oPluginManager->AddTemplate($this->sPath.'/'.$sFile, $bAdminScope); - } - - return $this; - } - - /** - * @param string $sActionName - * @param string $sFunctionName - * - * @return self - */ - protected function addPartHook($sActionName, $sFunctionName) - { - if ($this->oPluginManager) - { - $this->oPluginManager->AddAdditionalPartAction($sActionName, array(&$this, $sFunctionName)); - } - - return $this; - } - - /** - * @param string $sActionName - * @param string $sFunctionName - * - * @return self - */ - protected function addAjaxHook($sActionName, $sFunctionName) - { - if ($this->oPluginManager) - { - $this->oPluginManager->AddAdditionalAjaxAction($sActionName, array(&$this, $sFunctionName)); - } - - return $this; - } - - /** - * @param string $sName - * @param string $sPlace - * @param string $sLocalTemplateName - * @param bool $bPrepend = false - * - * @return self - */ - protected function addTemplateHook($sName, $sPlace, $sLocalTemplateName, $bPrepend = false) - { - if ($this->oPluginManager) - { - $this->oPluginManager->AddProcessTemplateAction($sName, $sPlace, - '', $bPrepend); - } - - return $this; - } -} diff --git a/rainloop/v/0.0.0/app/src/RainLoop/PluginsNext/Manager.php b/rainloop/v/0.0.0/app/src/RainLoop/PluginsNext/Manager.php deleted file mode 100644 index cee2acc81..000000000 --- a/rainloop/v/0.0.0/app/src/RainLoop/PluginsNext/Manager.php +++ /dev/null @@ -1,685 +0,0 @@ -oLogger = null; - $this->oActions = $oActions; - $this->aPlugins = array(); - - $this->aHooks = array(); - $this->aJs = array(); - $this->aAdminJs = array(); - $this->aTemplates = array(); - $this->aAdminTemplates = array(); - - $this->aAjaxFilters = array(); - $this->aAdditionalAjax = array(); - $this->aProcessTemplate = array(); - - $this->bIsEnabled = (bool) $this->oActions->Config()->Get('plugins', 'enable', false); - if ($this->bIsEnabled) - { - $sList = \strtolower($this->oActions->Config()->Get('plugins', 'enabled_list', '')); - if (0 < \strlen($sList)) - { - $aList = \explode(',', $sList); - $aList = \array_map('trim', $aList); - - foreach ($aList as $sName) - { - if (0 < \strlen($sName)) - { - $oPlugin = $this->CreatePluginByName($sName); - if ($oPlugin) - { - $oPlugin->InitStep('step1'); - $oPlugin->Init(); - $oPlugin->InitStep('step2'); - - $this->aPlugins[] = $oPlugin; - - $oPlugin->InitStep('spep3'); - } - } - } - } - - $this->RunHook('api.bootstrap.plugins'); - } - } - - /** - * @param string $sName - * - * @return \RainLoop\Plugins\AbstractPlugin|null - */ - public function CreatePluginByName($sName) - { - $oPlugin = null; - if (\preg_match('/^[a-z0-9\-]+$/', $sName) && - \file_exists(APP_PLUGINS_PATH.$sName.'/index.php')) - { - $sClassName = $this->convertPluginFolderNameToClassName($sName); - - if (!\class_exists($sClassName)) - { - include APP_PLUGINS_PATH.$sName.'/index.php'; - } - - if (\class_exists($sClassName)) - { - $oPlugin = new $sClassName(); - if ($oPlugin instanceof \RainLoop\PluginsNext\AbstractPlugin) - { - $oPlugin - ->SetValues(APP_PLUGINS_PATH.$sName, $sName, - \file_exists(APP_PLUGINS_PATH.$sName.'/VERSION') ? - \file_get_contents(APP_PLUGINS_PATH.$sName.'/VERSION') : '') - ->SetPluginManager($this) - ->SetPluginConfig(new \RainLoop\Config\Plugin($sName, $oPlugin->ConfigMap())) - ; - } - else - { - $oPlugin = null; - } - } - } - - return $oPlugin; - } - - /** - * @return array - */ - public function InstalledPlugins() - { - $aList = array(); - - $aGlob = @\glob(APP_PLUGINS_PATH.'*', GLOB_ONLYDIR|GLOB_NOSORT); - if (\is_array($aGlob)) - { - foreach ($aGlob as $sPathName) - { - $sName = \basename($sPathName); - if (\preg_match('/^[a-z0-9\-]+$/', $sName) && - \file_exists($sPathName.'/index.php')) - { - $aList[] = array( - $sName, @\file_get_contents($sPathName.'/VERSION') - ); - } - } - } - else - { - $this->Actions()->Logger()->Write('Cannot get installed plugins from '.APP_PLUGINS_PATH, - \MailSo\Log\Enumerations\Type::ERROR); - } - - return $aList; - } - - /** - * @param string $sFolderName - * - * @return string - */ - private function convertPluginFolderNameToClassName($sFolderName) - { - $aParts = \array_map('ucfirst', \array_map('strtolower', - \explode(' ', \preg_replace('/[^a-z0-9]+/', ' ', $sFolderName)))); - - return \implode($aParts).'Plugin'; - } - - /** - * @return \RainLoop\Actions - */ - public function Actions() - { - return $this->oActions; - } - - /** - * @return string - */ - public function Hash() - { - $sResult = \md5(APP_VERSION); - foreach ($this->aPlugins as $oPlugin) - { - $sResult = \md5($sResult.$oPlugin->Path().$oPlugin->Hash()); - } - - return $sResult; - } - - /** - * @param bool $bAdminScope = false - * - * @return string - */ - public function CompileJs($bAdminScope = false) - { - $aResult = array(); - if ($this->bIsEnabled) - { - $aJs = $bAdminScope ? $this->aAdminJs : $this->aJs; - foreach ($aJs as $sFile) - { - if (\file_exists($sFile)) - { - $aResult[] = \file_get_contents($sFile); - } - } - } - - return \implode("\n", $aResult); - } - - /** - * @todo - * @param bool $bAdminScope = false - * - * @return string - */ - public function CompileCss($bAdminScope = false) - { - return ''; - } - - /** - * @param bool $bAdminScope = false - * @return string - */ - public function CompileTemplate($bAdminScope = false) - { - $sResult = ''; - if ($this->bIsEnabled) - { - foreach ($bAdminScope ? $this->aAdminTemplates : $this->aTemplates as $sFile) - { - if (\file_exists($sFile)) - { - $sTemplateName = \substr(\basename($sFile), 0, -5); - $sResult .= ''; - } - } - } - - return $sResult; - } - - /** - * @param bool $bAdmin - * @param array $aAppData - * @param \RainLoop\Model\Account|null $oAccount = null - * - * @return \RainLoop\PluginsNext\Manager - */ - public function InitAppData($bAdmin, &$aAppData, $oAccount = null) - { - if ($this->bIsEnabled && isset($aAppData['Plugins']) && \is_array($aAppData['Plugins'])) - { - $bAuth = isset($aAppData['Auth']) && !!$aAppData['Auth']; - foreach ($this->aPlugins as $oPlugin) - { - if ($oPlugin) - { - $aConfig = array(); - $aMap = $oPlugin->ConfigMap(); - if (\is_array($aMap)) - { - foreach ($aMap as /* @var $oPluginProperty \RainLoop\PluginsNext\Property */$oPluginProperty) - { - if ($oPluginProperty && $oPluginProperty->AllowedInJs()) - { - $aConfig[$oPluginProperty->Name()] = - $oPlugin->Config()->Get('plugin', - $oPluginProperty->Name(), - $oPluginProperty->DefaultValue()); - } - } - } - - $oPlugin->FilterAppDataPluginSection($bAdmin, $bAuth, $aConfig); - - if (0 < \count($aConfig)) - { - $aAppData['Plugins'][$oPlugin->Name()] = $aConfig; - } - } - } - - $this->RunHook('filter.app-data', array( - 'IsAdmin' => $bAdmin, - 'AppData' => &$aAppData - ), $oAccount); - } - - return $this; - } - - /** - * @param string $sHookName - * @param mixed $mCallbak - * - * @return \RainLoop\PluginsNext\Manager - */ - public function AddHook($sHookName, $mCallbak) - { - if ($this->bIsEnabled && \is_callable($mCallbak)) - { - if (!isset($this->aHooks[$sHookName])) - { - $this->aHooks[$sHookName] = array(); - } - - $this->aHooks[$sHookName][] = $mCallbak; - } - - return $this; - } - - /** - * @param string $sFile - * @param bool $bAdminScope = false - * - * @return \RainLoop\PluginsNext\Manager - */ - public function AddJs($sFile, $bAdminScope = false) - { - if ($this->bIsEnabled) - { - if ($bAdminScope) - { - $this->aAdminJs[$sFile] = $sFile; - } - else - { - $this->aJs[$sFile] = $sFile; - } - } - - return $this; - } - - /** - * @param string $sFile - * @param bool $bAdminScope = false - * - * @return \RainLoop\PluginsNext\Manager - */ - public function AddTemplate($sFile, $bAdminScope = false) - { - if ($this->bIsEnabled) - { - if ($bAdminScope) - { - $this->aAdminTemplates[$sFile] = $sFile; - } - else - { - $this->aTemplates[$sFile] = $sFile; - } - } - - return $this; - } - - /** - * @param string $sHookName - * @param array $aArg = array() - * @param \RainLoop\Model\Account|null $oAccount = null - * @param bool $bLogHook = true - * - * @return \RainLoop\PluginsNext\Manager - */ - public function RunHook($sHookName, $aArg = array(), $oAccount = null, $bLogHook = true) - { - if ($this->bIsEnabled) - { - if (isset($this->aHooks[$sHookName])) - { - if ($bLogHook) - { - $this->WriteLog('Hook: '.$sHookName, \MailSo\Log\Enumerations\Type::NOTE); - } - - $bArgArray = 0 < \count($aArg); - foreach ($this->aHooks[$sHookName] as $mCallbak) - { - if ($bArgArray) - { - \call_user_func_array($mCallbak, array($aArg)); - } - else - { - \call_user_func($mCallbak); - } - } - } - } - - return $this; - } - - /** - * @param string $sActionName - * @param mixed $mCallbak - * - * @return \RainLoop\PluginsNext\Manager - */ - public function AddAdditionalPartAction($sActionName, $mCallbak) - { - if ($this->bIsEnabled && \is_callable($mCallbak)) - { - $sActionName = \strtolower($sActionName); - if (!isset($this->aAdditionalParts[$sActionName])) - { - $this->aAdditionalParts[$sActionName] = array(); - } - - $this->aAdditionalParts[$sActionName][] = $mCallbak; - } - - return $this; - } - - /** - * @param string $sActionName - * @param array $aParts = array() - * - * @return \RainLoop\PluginsNext\Manager - */ - public function RunAdditionalPart($sActionName, $aParts = array()) - { - $bResult = false; - if ($this->bIsEnabled) - { - $sActionName = \strtolower($sActionName); - if (isset($this->aAdditionalParts[$sActionName])) - { - foreach ($this->aAdditionalParts[$sActionName] as $mCallbak) - { - $bCallResult = \call_user_func_array($mCallbak, $aParts); - if ($bCallResult && !$bResult) - { - $bResult = true; - } - } - } - } - - return $bResult; - } - - /** - * @param string $sName - * @param string $sPlace - * @param string $sHtml - * @param bool $bPrepend = false - * - * @return \RainLoop\PluginsNext\Manager - */ - public function AddProcessTemplateAction($sName, $sPlace, $sHtml, $bPrepend = false) - { - if ($this->bIsEnabled) - { - if (!isset($this->aProcessTemplate[$sName])) - { - $this->aProcessTemplate[$sName] = array(); - } - - if (!isset($this->aProcessTemplate[$sName][$sPlace])) - { - $this->aProcessTemplate[$sName][$sPlace] = array(); - } - - if ($bPrepend) - { - \array_unshift($this->aProcessTemplate[$sName][$sPlace], $sHtml); - } - else - { - \array_push($this->aProcessTemplate[$sName][$sPlace], $sHtml); - } - } - - return $this; - } - - /** - * @param string $sActionName - * @param mixed $mCallbak - * - * @return \RainLoop\Plugins\Manager - */ - public function AddAdditionalAjaxAction($sActionName, $mCallbak) - { - if ($this->bIsEnabled && \is_callable($mCallbak) && 0 < \strlen($sActionName)) - { - $sActionName = 'Do'.$sActionName; - - if (!isset($this->aAdditionalAjax[$sActionName])) - { - $this->aAdditionalAjax[$sActionName] = $mCallbak; - } - } - - return $this; - } - - /** - * @param string $sActionName - * - * @return bool - */ - public function HasAdditionalAjax($sActionName) - { - return $this->bIsEnabled && isset($this->aAdditionalAjax[$sActionName]); - } - - /** - * @param string $sActionName - * - * @return mixed - */ - public function RunAdditionalAjax($sActionName) - { - if ($this->bIsEnabled) - { - if (isset($this->aAdditionalAjax[$sActionName])) - { - return \call_user_func($this->aAdditionalAjax[$sActionName]); - } - } - - return false; - } - - /** - * @param string $sLang - * @param array $sActionName - * - * @return \RainLoop\PluginsNext\Manager - */ - public function ReadLang($sLang, &$aLang) - { - if ($this->bIsEnabled) - { - foreach ($this->aPlugins as $oPlugin) - { - if ($oPlugin->UseLangs()) - { - $sPath = $oPlugin->Path(); - - \RainLoop\Utils::ReadAndAddLang($sPath.'/langs/en.ini', $aLang); - if ('en' !== $sLang) - { - \RainLoop\Utils::ReadAndAddLang($sPath.'/langs/'.$sLang.'.ini', $aLang); - } - } - } - } - - return $this; - } - - /** - * @param string $sName - * @param string $sHtml - * - * @return string - */ - public function ProcessTemplate($sName, $sHtml) - { - if (isset($this->aProcessTemplate[$sName])) - { - foreach ($this->aProcessTemplate[$sName] as $sPlace => $aAddHtml) - { - if (\is_array($aAddHtml) && 0 < \count($aAddHtml)) - { - foreach ($aAddHtml as $sAddHtml) - { - $sHtml = \str_replace('{{INCLUDE/'.$sPlace.'/PLACE}}', $sAddHtml.'{{INCLUDE/'.$sPlace.'/PLACE}}', $sHtml); - } - } - } - } - - return $sHtml; - } - - /** - * @return bool - */ - public function bIsEnabled() - { - return $this->bIsEnabled; - } - - /** - * @return int - */ - public function Count() - { - return $this->bIsEnabled ? \count($this->aPlugins) : 0; - } - - /** - * @param \MailSo\Log\Logger $oLogger - * - * @return \RainLoop\PluginsNext\Manager - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function SetLogger($oLogger) - { - if (!($oLogger instanceof \MailSo\Log\Logger)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oLogger = $oLogger; - - return $this; - } - - /** - * @param string $sDesc - * @param int $iType = \MailSo\Log\Enumerations\Type::INFO - * - * @return void - */ - public function WriteLog($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO) - { - if ($this->oLogger) - { - $this->oLogger->Write($sDesc, $iType, 'PLUGIN'); - } - } - - /** - * @param string $sDesc - * @param int $iType = \MailSo\Log\Enumerations\Type::INFO - * - * @return void - */ - public function WriteException($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO) - { - if ($this->oLogger) - { - $this->oLogger->WriteException($sDesc, $iType, 'PLUGIN'); - } - } -} diff --git a/rainloop/v/0.0.0/app/src/RainLoop/PluginsNext/Property.php b/rainloop/v/0.0.0/app/src/RainLoop/PluginsNext/Property.php deleted file mode 100644 index 065ddf588..000000000 --- a/rainloop/v/0.0.0/app/src/RainLoop/PluginsNext/Property.php +++ /dev/null @@ -1,179 +0,0 @@ -sName = $sName; - $this->iType = \RainLoop\Enumerations\PluginPropertyType::STRING; - $this->mDefaultValue = ''; - $this->sLabel = ''; - $this->sDesc = ''; - $this->bAllowedInJs = false; - } - - /** - * @param string $sName - * - * @return \RainLoop\PluginsNext\Property - */ - public static function NewInstance($sName) - { - return new self($sName); - } - - /** - * @param int $iType - * - * @return \RainLoop\PluginsNext\Property - */ - public function SetType($iType) - { - $this->iType = (int) $iType; - - return $this; - } - - /** - * @param mixed $mDefaultValue - * - * @return \RainLoop\PluginsNext\Property - */ - public function SetDefaultValue($mDefaultValue) - { - $this->mDefaultValue = $mDefaultValue; - - return $this; - } - - /** - * @param string $sLabel - * - * @return \RainLoop\PluginsNext\Property - */ - public function SetLabel($sLabel) - { - $this->sLabel = $sLabel; - - return $this; - } - - /** - * @param string $sDesc - * - * @return \RainLoop\PluginsNext\Property - */ - public function SetDescription($sDesc) - { - $this->sDesc = $sDesc; - - return $this; - } - - /** - * @param bool $bValue = true - * - * @return \RainLoop\PluginsNext\Property - */ - public function SetAllowedInJs($bValue = true) - { - $this->bAllowedInJs = !!$bValue; - - return $this; - } - - /** - * @return string - */ - public function Name() - { - return $this->sName; - } - - /** - * @return bool - */ - public function AllowedInJs() - { - return $this->bAllowedInJs; - } - - /** - * @return string - */ - public function Description() - { - return $this->sDesc; - } - - /** - * @return string - */ - public function Label() - { - return $this->sLabel; - } - - /** - * @return int - */ - public function Type() - { - return $this->iType; - } - - /** - * @return mixed - */ - public function DefaultValue() - { - return $this->mDefaultValue; - } - - /** - * @return array - */ - public function ToArray() - { - return array( - '', - $this->sName, - $this->iType, - $this->sLabel, - $this->mDefaultValue, - $this->sDesc - ); - } -} diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Providers/Domain.php b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Domain.php index 8e27a1244..5df222f4e 100644 --- a/rainloop/v/0.0.0/app/src/RainLoop/Providers/Domain.php +++ b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Domain.php @@ -130,7 +130,6 @@ class Domain extends \RainLoop\Providers\AbstractProvider $iIncSecure = (int) $oActions->GetActionParam('IncSecure', \MailSo\Net\Enumerations\ConnectionSecurityType::NONE); $bIncShortLogin = '1' === (string) $oActions->GetActionParam('IncShortLogin', '0'); $bUseSieve = '1' === (string) $oActions->GetActionParam('UseSieve', '0'); - $bUseImapServerForSieve = '1' === (string) $oActions->GetActionParam('UseImapServerForSieve', '1'); $sSieveHost = (string) $oActions->GetActionParam('SieveHost', ''); $iSievePort = (int) $oActions->GetActionParam('SievePort', 2000); $iSieveSecure = (int) $oActions->GetActionParam('SieveSecure', \MailSo\Net\Enumerations\ConnectionSecurityType::NONE); @@ -160,7 +159,7 @@ class Domain extends \RainLoop\Providers\AbstractProvider { $oDomain->UpdateInstance( $sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin, - $bUseSieve, $bUseImapServerForSieve, $sSieveHost, $iSievePort, $iSieveSecure, + $bUseSieve, $sSieveHost, $iSievePort, $iSieveSecure, $sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth, $bOutUsePhpMail, $sWhiteList); } @@ -169,7 +168,7 @@ class Domain extends \RainLoop\Providers\AbstractProvider { $oDomain = \RainLoop\Model\Domain::NewInstance(0 < strlen($sNameForTest) ? $sNameForTest : $sName, $sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin, - $bUseSieve, $bUseImapServerForSieve, $sSieveHost, $iSievePort, $iSieveSecure, + $bUseSieve, $sSieveHost, $iSievePort, $iSieveSecure, $sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth, $bOutUsePhpMail, $sWhiteList); } diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters.php b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters.php new file mode 100644 index 000000000..cf0398763 --- /dev/null +++ b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters.php @@ -0,0 +1,45 @@ +oDriver = $oDriver instanceof \RainLoop\Providers\Filters\FiltersInterface ? $oDriver : null; + } + + /** + * @return array + */ + public function Load() + { + return $this->IsActive() ? $this->oDriver->Load() : array(); + } + + /** + * @param array $aFilters + * + * @return bool + */ + public function Save($aFilters) + { + return $this->IsActive() ? $this->oDriver->Save($aFilters) : false; + } + + /** + * @return bool + */ + public function IsActive() + { + return $this->oDriver instanceof \RainLoop\Providers\Filters\FiltersInterface; + } +} \ No newline at end of file diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Classes/Filter.php b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Classes/Filter.php new file mode 100644 index 000000000..d2522681d --- /dev/null +++ b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Classes/Filter.php @@ -0,0 +1,150 @@ +Clear(); + } + + public function Clear() + { + $this->sName = ''; + + $this->aConditions = array(); + + $this->sFilterRulesType = \RainLoop\Providers\Filters\Enumerations\FilterRulesType::ALL; + + $this->sActionType = \RainLoop\Providers\Filters\Enumerations\ActionType::MOVE_TO; + $this->sActionValue = ''; + + $this->bMarkAsRead = false; + $this->bSkipOthers = false; + } + + /** + * @return string + */ + public function Name() + { + return $this->sName; + } + + /** + * @return array + */ + public function Conditions() + { + return $this->aConditions; + } + + /** + * @return string + */ + public function FilterRulesType() + { + return $this->sFilterRulesType; + } + + /** + * @return string + */ + public function ActionType() + { + return $this->sActionType; + } + + /** + * @return string + */ + public function ActionValue() + { + return $this->sActionValue; + } + + /** + * @return bool + */ + public function MarkAsRead() + { + return $this->bMarkAsRead; + } + + /** + * @return bool + */ + public function SkipOthers() + { + return $this->bSkipOthers; + } + + /** + * @return string + */ + public function serializeToJson() + { + return \json_encode($this->ToSimpleJSON()); + } + + /** + * @param string $sFilterJson + */ + public function unserializeFromJson($sFilterJson) + { + $sFilterJson = \json_decode(\trim($sFilterJson)); + if (!empty($sFilterJson)) + { + } + } + + /** + * @param bool $bAjax = false + * + * @return array + */ + public function ToSimpleJSON($bAjax = false) + { + $aConditions = $this->Conditions(); + return array( + 'Name' => $this->Name(), + 'Conditions' => $aConditions, + 'FilterRulesType' => $this->FilterRulesType(), + 'ActionType' => $this->ActionType(), + 'ActionValue' => $this->ActionValue(), + 'MarkAsRead' => $this->MarkAsRead(), + 'SkipOthers' => $this->SkipOthers() + ); + } +} diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Enumerations/ActionType.php b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Enumerations/ActionType.php new file mode 100644 index 000000000..d7472fc8a --- /dev/null +++ b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Enumerations/ActionType.php @@ -0,0 +1,10 @@ +fileStringToCollection(@\file_get_contents('e:/sieve.txt')); + } + + /** + * @param array $aFilters + * + * @return bool + */ + public function Save($aFilters) + { + return @\file_put_contents('e:/sieve.txt', $this->collectionToFileString($aFilters)); + } + + /** + * @param array $aFilters + * + * @return string + */ + private function collectionToFileString($aFilters) + { + $aParts = array(); + + foreach ($aFilters as /* @var $oItem \RainLoop\Providers\Filters\Classes\Filter */ $oItem) + { + $sItem = $oItem->serializeToJson(); + $sItem = \chunk_split(\base64_encode($sItem), 74, "\n"); + + $aParts[] = $sItem; + } + + return \implode("\n", $aParts); + } + + /** + * @param string $sFileString + * + * @return array + */ + private function fileStringToCollection($sFileString) + { + if (!empty($sFileString)) + { + + } + + return array(); + } +} diff --git a/rainloop/v/0.0.0/app/templates/Index.html b/rainloop/v/0.0.0/app/templates/Index.html index 0395264aa..8effbe0c5 100644 --- a/rainloop/v/0.0.0/app/templates/Index.html +++ b/rainloop/v/0.0.0/app/templates/Index.html @@ -84,24 +84,33 @@ __simplePace(10); window.$LAB - .script('{{BaseAppLibsScriptLink}}') - .script(window.rainloopAppData['TemplatesLink']) - .script(window.rainloopAppData['LangLink']) + .script(function () { + return [ + {'src': '{{BaseAppLibsScriptLink}}', 'type': 'text/javascript', 'charset': 'utf-8'}, + {'src': window.rainloopAppData['TemplatesLink'], 'type': 'text/javascript', 'charset': 'utf-8'}, + {'src': window.rainloopAppData['LangLink'], 'type': 'text/javascript', 'charset': 'utf-8'} + ]; + }) .wait(function () { __simplePace(30); }) - .script('{{BaseAppMainScriptLink}}') + .script(function () { + return {'src': '{{BaseAppMainScriptLink}}', 'type': 'text/javascript', 'charset': 'utf-8'}; + }) .wait(function () { __simplePace(20); }) .script(function () { - return window.rainloopAppData['PluginsLink'] || null; + return window.rainloopAppData['PluginsLink'] ? + {'src': '{{BaseAppMainScriptLink}}', 'type': 'text/javascript', 'charset': 'utf-8'} : null; }) .wait(function () { __simplePace(5); __runBoot(false); }) - .script('{{BaseAppEditorScriptLink}}') + .script(function () { + return {'src': '{{BaseAppEditorScriptLink}}', 'type': 'text/javascript', 'charset': 'utf-8'}; + }) .wait(function () { if (window.CKEDITOR && window.__initEditor) { window.__initEditor(); 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 f740332c1..f7c9d8d40 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 @@ -25,7 +25,12 @@
   - New version is available. + New + + + () + + version is available. () @@ -56,7 +61,11 @@
   - RainLoop is up to date. + RainLoop + + () + + is up to date.
diff --git a/rainloop/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html b/rainloop/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html index f5bb0163c..f6e549ca0 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html +++ b/rainloop/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html @@ -20,8 +20,8 @@
- - IMAP + + IMAP
@@ -73,7 +73,7 @@   - Sieve configuration + Sieve (Filetrs) configuration
@@ -90,18 +90,7 @@ }">
-
-
-
-
-
-
+

@@ -144,7 +133,7 @@
- + SMTP
diff --git a/rainloop/v/0.0.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html b/rainloop/v/0.0.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html index ffbfd2afa..52ec0cebb 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html +++ b/rainloop/v/0.0.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html @@ -77,7 +77,7 @@ W, C Ctrl + Q, Command + Q Ctrl + S, Command + S - Ctrl + Enter, Command + Enter + Esc diff --git a/rainloop/v/0.0.0/app/templates/Views/Common/PopupsLanguages.html b/rainloop/v/0.0.0/app/templates/Views/Common/PopupsLanguages.html index ba6fa3d30..e825ba690 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Common/PopupsLanguages.html +++ b/rainloop/v/0.0.0/app/templates/Views/Common/PopupsLanguages.html @@ -8,8 +8,8 @@