mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-08 22:18:28 +03:00
Cleanup and improved handling of Sieve scripts
This commit is contained in:
parent
61908dd0c0
commit
58cd2fcacb
14 changed files with 28 additions and 802 deletions
|
|
@ -294,8 +294,9 @@ export class SieveScriptModel extends AbstractModel
|
|||
return {
|
||||
name: this.name(),
|
||||
active: this.active() ? 1 : 0,
|
||||
body: this.body(),
|
||||
filters: this.filters.map(item => item.toJson())
|
||||
body: this.body()
|
||||
// body: this.allowFilters() ? this.body() : this.filtersToRaw()
|
||||
// filters: this.filters.map(item => item.toJson())
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ export class SieveScriptPopupView extends rl.pluginPopupView {
|
|||
saveError: false,
|
||||
errorText: '',
|
||||
rawActive: false,
|
||||
allowToggle: false,
|
||||
script: null,
|
||||
saving: false,
|
||||
|
||||
sieveCapabilities: '',
|
||||
availableActions: '',
|
||||
|
|
@ -31,8 +31,6 @@ export class SieveScriptPopupView extends rl.pluginPopupView {
|
|||
availableTests: ''
|
||||
});
|
||||
|
||||
this.saving = false;
|
||||
|
||||
this.filterForDeletion = ko.observable(null).askDeleteHelper();
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +46,7 @@ export class SieveScriptPopupView extends rl.pluginPopupView {
|
|||
saveScript() {
|
||||
let self = this,
|
||||
script = self.script();
|
||||
if (!self.saving/* && script.hasChanges()*/) {
|
||||
if (!self.saving()/* && script.hasChanges()*/) {
|
||||
this.errorText('');
|
||||
self.saveError(false);
|
||||
|
||||
|
|
@ -62,21 +60,21 @@ export class SieveScriptPopupView extends rl.pluginPopupView {
|
|||
}
|
||||
|
||||
try {
|
||||
parseScript(this.script().body());
|
||||
parseScript(script.body());
|
||||
} catch (e) {
|
||||
this.errorText(e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
self.saving = true;
|
||||
self.saving(true);
|
||||
|
||||
if (self.allowToggle()) {
|
||||
if (script.allowFilters()) {
|
||||
script.body(script.filtersToRaw());
|
||||
}
|
||||
|
||||
Remote.request('FiltersScriptSave',
|
||||
(iError, data) => {
|
||||
self.saving = false;
|
||||
self.saving(false);
|
||||
|
||||
if (iError) {
|
||||
self.saveError(true);
|
||||
|
|
@ -85,6 +83,7 @@ export class SieveScriptPopupView extends rl.pluginPopupView {
|
|||
script.exists() || scripts.push(script);
|
||||
script.exists(true);
|
||||
script.hasChanges(false);
|
||||
// this.close();
|
||||
}
|
||||
},
|
||||
script.toJson()
|
||||
|
|
@ -110,17 +109,18 @@ export class SieveScriptPopupView extends rl.pluginPopupView {
|
|||
const clonedFilter = filter.assignTo();
|
||||
FilterPopupView.showModal([
|
||||
clonedFilter,
|
||||
() => clonedFilter.assignTo(filter),
|
||||
() => {
|
||||
clonedFilter.assignTo(filter);
|
||||
const script = this.script();
|
||||
script.hasChanges(script.body() != script.filtersToRaw());
|
||||
},
|
||||
true
|
||||
]);
|
||||
}
|
||||
|
||||
toggleFiltersRaw() {
|
||||
let script = this.script(), notRaw = !this.rawActive();
|
||||
if (notRaw) {
|
||||
script.body(script.filtersToRaw());
|
||||
script.hasChanges(script.hasChanges());
|
||||
}
|
||||
const script = this.script(), notRaw = !this.rawActive();
|
||||
notRaw && script.body(script.filtersToRaw());
|
||||
this.rawActive(notRaw);
|
||||
}
|
||||
|
||||
|
|
@ -140,10 +140,8 @@ export class SieveScriptPopupView extends rl.pluginPopupView {
|
|||
this.availableTests([...Object.keys(availableTests())].join(', '));
|
||||
|
||||
oScript = oScript || new SieveScriptModel();
|
||||
let raw = !oScript.allowFilters();
|
||||
this.script(oScript);
|
||||
this.rawActive(raw);
|
||||
this.allowToggle(!raw);
|
||||
this.rawActive(!oScript.allowFilters());
|
||||
this.saveError(false);
|
||||
this.errorText('');
|
||||
|
||||
|
|
|
|||
|
|
@ -39,25 +39,12 @@ trait Filters
|
|||
|
||||
$sName = $this->GetActionParam('name', '');
|
||||
|
||||
$aFilters = array();
|
||||
if (\RainLoop\Providers\Filters\SieveStorage::SIEVE_FILE_NAME === $sName) {
|
||||
$aIncFilters = $this->GetActionParam('filters', array());
|
||||
foreach ($aIncFilters as $aFilter) {
|
||||
if (\is_array($aFilter)) {
|
||||
$oFilter = new \RainLoop\Providers\Filters\Classes\Filter();
|
||||
if ($oFilter->FromJSON($aFilter)) {
|
||||
$aFilters[] = $oFilter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->GetActionParam('active', false)) {
|
||||
// $this->FiltersProvider()->ActivateScript($oAccount, $sName);
|
||||
}
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, $this->FiltersProvider()->Save(
|
||||
$oAccount, $sName, $aFilters, $this->GetActionParam('body', '')
|
||||
$oAccount, $sName, $this->GetActionParam('body', '')
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,12 +41,12 @@ class Filters extends \RainLoop\Providers\AbstractProvider
|
|||
}
|
||||
}
|
||||
|
||||
public function Save(\RainLoop\Model\Account $oAccount, string $sScriptName, array $aFilters, string $sRaw = '') : bool
|
||||
public function Save(\RainLoop\Model\Account $oAccount, string $sScriptName, string $sRaw) : bool
|
||||
{
|
||||
try
|
||||
{
|
||||
return $this->IsActive()
|
||||
? $this->oDriver->Save($oAccount, $sScriptName, $aFilters, $sRaw)
|
||||
? $this->oDriver->Save($oAccount, $sScriptName, $sRaw)
|
||||
: false;
|
||||
}
|
||||
catch (\Throwable $oException)
|
||||
|
|
|
|||
|
|
@ -1,227 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Providers\Filters\Classes;
|
||||
|
||||
class Filter implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sID;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $bEnabled;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sName;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $aConditions;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sConditionsType;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sActionType;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sActionValue;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sActionValueSecond;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sActionValueThird;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sActionValueFourth;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $bMarkAsRead;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $bSkipOthers;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $bKeep;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $bStop;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->Clear();
|
||||
}
|
||||
|
||||
public function Clear()
|
||||
{
|
||||
$this->sID = '';
|
||||
$this->sName = '';
|
||||
|
||||
$this->bEnabled = true;
|
||||
|
||||
$this->aConditions = array();
|
||||
|
||||
$this->sConditionsType = \RainLoop\Providers\Filters\Enumerations\ConditionsType::ANY;
|
||||
|
||||
$this->sActionType = \RainLoop\Providers\Filters\Enumerations\ActionType::MOVE_TO;
|
||||
$this->sActionValue = '';
|
||||
$this->sActionValueSecond = '';
|
||||
$this->sActionValueThird = '';
|
||||
$this->sActionValueFourth = '';
|
||||
|
||||
$this->bMarkAsRead = false;
|
||||
$this->bKeep = true;
|
||||
$this->bStop = true;
|
||||
}
|
||||
|
||||
public function ID() : string
|
||||
{
|
||||
return $this->sID;
|
||||
}
|
||||
|
||||
public function Enabled() : bool
|
||||
{
|
||||
return $this->bEnabled;
|
||||
}
|
||||
|
||||
public function Name() : string
|
||||
{
|
||||
return $this->sName;
|
||||
}
|
||||
|
||||
public function Conditions() : array
|
||||
{
|
||||
return $this->aConditions;
|
||||
}
|
||||
|
||||
public function ConditionsType() : string
|
||||
{
|
||||
return $this->sConditionsType;
|
||||
}
|
||||
|
||||
public function ActionType() : string
|
||||
{
|
||||
return $this->sActionType;
|
||||
}
|
||||
|
||||
public function ActionValue() : string
|
||||
{
|
||||
return $this->sActionValue;
|
||||
}
|
||||
|
||||
public function ActionValueSecond() : string
|
||||
{
|
||||
return $this->sActionValueSecond;
|
||||
}
|
||||
|
||||
public function ActionValueThird() : string
|
||||
{
|
||||
return $this->sActionValueThird;
|
||||
}
|
||||
|
||||
public function ActionValueFourth() : string
|
||||
{
|
||||
return $this->sActionValueFourth;
|
||||
}
|
||||
|
||||
public function MarkAsRead() : bool
|
||||
{
|
||||
return $this->bMarkAsRead;
|
||||
}
|
||||
|
||||
public function Stop() : bool
|
||||
{
|
||||
return $this->bStop;
|
||||
}
|
||||
|
||||
public function Keep() : bool
|
||||
{
|
||||
return $this->bKeep;
|
||||
}
|
||||
|
||||
public function unserializeFromJson(string $sFilterJson)
|
||||
{
|
||||
$aFilterJson = \json_decode(\trim($sFilterJson), true);
|
||||
if (\is_array($aFilterJson))
|
||||
{
|
||||
return $this->FromJSON($aFilterJson);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function FromJSON(array $aFilter) : bool
|
||||
{
|
||||
$this->sID = $aFilter['ID'] ?? '';
|
||||
$this->sName = $aFilter['Name'] ?? '';
|
||||
|
||||
$this->bEnabled = !isset($aFilter['Enabled']) || !empty($aFilter['Enabled']);
|
||||
|
||||
$this->sConditionsType = $aFilter['ConditionsType']
|
||||
?? \RainLoop\Providers\Filters\Enumerations\ConditionsType::ANY;
|
||||
|
||||
$this->sActionType = $aFilter['ActionType']
|
||||
?? \RainLoop\Providers\Filters\Enumerations\ActionType::MOVE_TO;
|
||||
|
||||
$this->sActionValue = $aFilter['ActionValue'] ?? '';
|
||||
$this->sActionValueSecond = $aFilter['ActionValueSecond'] ?? '';
|
||||
$this->sActionValueThird = $aFilter['ActionValueThird'] ?? '';
|
||||
$this->sActionValueFourth = $aFilter['ActionValueFourth'] ?? '';
|
||||
|
||||
$this->bKeep = !isset($aFilter['Keep']) || !empty($aFilter['Keep']);
|
||||
$this->bStop = !isset($aFilter['Stop']) || !empty($aFilter['Stop']);
|
||||
$this->bMarkAsRead = !isset($aFilter['MarkAsRead']) || !empty($aFilter['MarkAsRead']);
|
||||
|
||||
$this->aConditions = empty($aFilter['Conditions']) ? array() : FilterCondition::CollectionFromJSON($aFilter['Conditions']);
|
||||
|
||||
return !empty($this->aConditions);
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return array(
|
||||
'@Object' => 'Object/Filter',
|
||||
'ID' => $this->ID(),
|
||||
'Enabled' => $this->Enabled(),
|
||||
'Name' => $this->Name(),
|
||||
'Conditions' => $this->Conditions(),
|
||||
'ConditionsType' => $this->ConditionsType(),
|
||||
'ActionType' => $this->ActionType(),
|
||||
'ActionValue' => $this->ActionValue(),
|
||||
'ActionValueSecond' => $this->ActionValueSecond(),
|
||||
'ActionValueThird' => $this->ActionValueThird(),
|
||||
'ActionValueFourth' => $this->ActionValueFourth(),
|
||||
'Keep' => $this->Keep(),
|
||||
'Stop' => $this->Stop(),
|
||||
'MarkAsRead' => $this->MarkAsRead()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Providers\Filters\Classes;
|
||||
|
||||
class FilterCondition implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sField = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sType = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sValue = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sValueSecond = '';
|
||||
|
||||
public function Field() : string
|
||||
{
|
||||
return $this->sField;
|
||||
}
|
||||
|
||||
public function Type() : string
|
||||
{
|
||||
return $this->sType;
|
||||
}
|
||||
|
||||
public function Value() : string
|
||||
{
|
||||
return $this->sValue;
|
||||
}
|
||||
|
||||
public function ValueSecond() : string
|
||||
{
|
||||
return $this->sValueSecond;
|
||||
}
|
||||
|
||||
public function FromJSON(array $aData) : bool
|
||||
{
|
||||
if (empty($aData['Field']) || empty($aData['Type']) || empty($aData['Value'])) {
|
||||
return false;
|
||||
}
|
||||
$this->sField = $aData['Field'];
|
||||
$this->sType = $aData['Type'];
|
||||
$this->sValue = (string) $aData['Value'];
|
||||
$this->sValueSecond = isset($aData['ValueSecond']) ? (string) $aData['ValueSecond'] : '';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function CollectionFromJSON(array $aCollection) : array
|
||||
{
|
||||
$aResult = array();
|
||||
foreach ($aCollection as $aItem)
|
||||
{
|
||||
if (\is_array($aItem) && \count($aItem))
|
||||
{
|
||||
$oItem = new \RainLoop\Providers\Filters\Classes\FilterCondition();
|
||||
if ($oItem->FromJSON($aItem))
|
||||
{
|
||||
$aResult[] = $oItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return array(
|
||||
'@Object' => 'Object/FilterCondition',
|
||||
'Field' => $this->Field(),
|
||||
'Type' => $this->Type(),
|
||||
'Value' => $this->Value(),
|
||||
'ValueSecond' => $this->ValueSecond()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Providers\Filters\Enumerations;
|
||||
|
||||
class ActionType
|
||||
{
|
||||
const NONE = 'None';
|
||||
const MOVE_TO = 'MoveTo';
|
||||
const DISCARD = 'Discard';
|
||||
const VACATION = 'Vacation';
|
||||
const REJECT = 'Reject';
|
||||
const FORWARD = 'Forward';
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Providers\Filters\Enumerations;
|
||||
|
||||
class ConditionField
|
||||
{
|
||||
const
|
||||
FROM = 'From',
|
||||
RECIPIENT = 'Recipient',
|
||||
SUBJECT = 'Subject',
|
||||
HEADER = 'Header',
|
||||
BODY = 'Body',
|
||||
SIZE = 'Size';
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Providers\Filters\Enumerations;
|
||||
|
||||
class ConditionType
|
||||
{
|
||||
const
|
||||
EQUAL_TO = 'EqualTo',
|
||||
NOT_EQUAL_TO = 'NotEqualTo',
|
||||
CONTAINS = 'Contains',
|
||||
NOT_CONTAINS = 'NotContains',
|
||||
REGEX = 'Regex',
|
||||
OVER = 'Over',
|
||||
UNDER = 'Under',
|
||||
TEXT = 'Text',
|
||||
RAW = 'Raw';
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Providers\Filters\Enumerations;
|
||||
|
||||
class ConditionsType
|
||||
{
|
||||
const ALL = 'All';
|
||||
const ANY = 'Any';
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ interface FiltersInterface
|
|||
{
|
||||
public function Load(\RainLoop\Model\Account $oAccount) : array;
|
||||
|
||||
public function Save(\RainLoop\Model\Account $oAccount, string $sScriptName, array $aFilters, string $sRaw = '') : bool;
|
||||
public function Save(\RainLoop\Model\Account $oAccount, string $sScriptName, string $sRaw) : bool;
|
||||
|
||||
public function Activate(\RainLoop\Model\Account $oAccount, string $sScriptName) : bool;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,383 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Providers\Filters;
|
||||
|
||||
class Sieve
|
||||
{
|
||||
const NEW_LINE = "\r\n";
|
||||
|
||||
public static function collectionToFileString(array $aFilters) : string
|
||||
{
|
||||
$sNL = static::NEW_LINE;
|
||||
|
||||
$aCapa = array();
|
||||
$aParts = [
|
||||
'# This is SnappyMail sieve script.',
|
||||
'# Please don\'t change anything here.',
|
||||
'# RAINLOOP:SIEVE',
|
||||
''
|
||||
];
|
||||
|
||||
foreach ($aFilters as /* @var $oItem \RainLoop\Providers\Filters\Classes\Filter */ $oItem)
|
||||
{
|
||||
$aParts[] = \implode($sNL, [
|
||||
'/*',
|
||||
'BEGIN:FILTER:'.$oItem->ID(),
|
||||
'BEGIN:HEADER',
|
||||
\chunk_split(\base64_encode(\json_encode($oItem)), 74, $sNL).'END:HEADER',
|
||||
'*/',
|
||||
$oItem->Enabled() ? '' : '/* @Filter is disabled ',
|
||||
static::filterToSieveScript($oItem, $aCapa),
|
||||
$oItem->Enabled() ? '' : '*/',
|
||||
'/* END:FILTER */',
|
||||
''
|
||||
]);
|
||||
}
|
||||
|
||||
$aCapa = \array_keys($aCapa);
|
||||
$sCapa = \count($aCapa)
|
||||
? $sNL . 'require ' . \str_replace('","', '", "', \json_encode($aCapa)).';' . $sNL
|
||||
: '';
|
||||
|
||||
return $sCapa . $sNL . \implode($sNL, $aParts);
|
||||
}
|
||||
|
||||
public static function fileStringToCollection(string $sFileString) : array
|
||||
{
|
||||
$aResult = array();
|
||||
if (!empty($sFileString) && false !== \strpos($sFileString, 'RAINLOOP:SIEVE'))
|
||||
{
|
||||
$aMatch = array();
|
||||
if (\preg_match_all('/BEGIN:FILTER(.+?)BEGIN:HEADER(.+?)END:HEADER/s', $sFileString, $aMatch) &&
|
||||
isset($aMatch[2]) && \is_array($aMatch[2]))
|
||||
{
|
||||
foreach ($aMatch[2] as $sEncodedLine)
|
||||
{
|
||||
if (!empty($sEncodedLine))
|
||||
{
|
||||
$sDecodedLine = \base64_decode(\preg_replace('/\\s+/s', '', $sEncodedLine));
|
||||
if (!empty($sDecodedLine))
|
||||
{
|
||||
$oItem = new Classes\Filter();
|
||||
if ($oItem && $oItem->unserializeFromJson($sDecodedLine))
|
||||
{
|
||||
$aResult[] = $oItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
private static function conditionToSieveScript(Classes\FilterCondition $oCondition, array &$aCapa) : string
|
||||
{
|
||||
$sResult = '';
|
||||
$sTypeWord = '';
|
||||
$bTrue = true;
|
||||
|
||||
$sValue = \trim($oCondition->Value());
|
||||
$sValueSecond = \trim($oCondition->ValueSecond());
|
||||
|
||||
if (\strlen($sValue) ||
|
||||
(\strlen($sValue) && \strlen($sValueSecond) &&
|
||||
Enumerations\ConditionField::HEADER === $oCondition->Field()))
|
||||
{
|
||||
switch ($oCondition->Type())
|
||||
{
|
||||
case Enumerations\ConditionType::TEXT:
|
||||
case Enumerations\ConditionType::RAW:
|
||||
case Enumerations\ConditionType::OVER:
|
||||
case Enumerations\ConditionType::UNDER:
|
||||
$sTypeWord = ':' . \strtolower($oCondition->Type());
|
||||
break;
|
||||
case Enumerations\ConditionType::NOT_EQUAL_TO:
|
||||
$sResult .= 'not ';
|
||||
case Enumerations\ConditionType::EQUAL_TO:
|
||||
$sTypeWord = ':is';
|
||||
break;
|
||||
case Enumerations\ConditionType::NOT_CONTAINS:
|
||||
$sResult .= 'not ';
|
||||
case Enumerations\ConditionType::CONTAINS:
|
||||
$sTypeWord = ':contains';
|
||||
break;
|
||||
case Enumerations\ConditionType::REGEX:
|
||||
$sTypeWord = ':regex';
|
||||
$aCapa['regex'] = true;
|
||||
break;
|
||||
default:
|
||||
$bTrue = false;
|
||||
$sResult = '/* @Error: unknown type value */ false';
|
||||
break;
|
||||
}
|
||||
|
||||
switch ($oCondition->Field())
|
||||
{
|
||||
case Enumerations\ConditionField::FROM:
|
||||
$sResult .= 'header '.$sTypeWord.' ["From"]';
|
||||
break;
|
||||
case Enumerations\ConditionField::RECIPIENT:
|
||||
$sResult .= 'header '.$sTypeWord.' ["To", "CC"]';
|
||||
break;
|
||||
case Enumerations\ConditionField::SUBJECT:
|
||||
$sResult .= 'header '.$sTypeWord.' ["Subject"]';
|
||||
break;
|
||||
case Enumerations\ConditionField::HEADER:
|
||||
$sResult .= 'header '.$sTypeWord.' ["'.static::quote($sValueSecond).'"]';
|
||||
break;
|
||||
case Enumerations\ConditionField::BODY:
|
||||
// :text :raw :content
|
||||
$sResult .= 'body '.$sTypeWord.' :contains';
|
||||
$aCapa['body'] = true;
|
||||
break;
|
||||
case Enumerations\ConditionField::SIZE:
|
||||
$sResult .= 'size '.$sTypeWord;
|
||||
break;
|
||||
default:
|
||||
$bTrue = false;
|
||||
$sResult = '/* @Error: unknown field value */ false';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($bTrue)
|
||||
{
|
||||
if (\in_array($oCondition->Field(), array(
|
||||
Enumerations\ConditionField::FROM,
|
||||
Enumerations\ConditionField::RECIPIENT
|
||||
)) && false !== \strpos($sValue, ','))
|
||||
{
|
||||
$aValue = \array_map(function ($sValue) use ($self) {
|
||||
return '"'.static::quote(\trim($sValue)).'"';
|
||||
}, \explode(',', $sValue));
|
||||
|
||||
$sResult .= ' ['.\trim(\implode(', ', $aValue)).']';
|
||||
}
|
||||
else if (Enumerations\ConditionField::SIZE === $oCondition->Field())
|
||||
{
|
||||
$sResult .= ' '.static::quote($sValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult .= ' "'.static::quote($sValue).'"';
|
||||
}
|
||||
|
||||
$sResult = \MailSo\Base\Utils::StripSpaces($sResult);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult = '/* @Error: empty condition value */ false';
|
||||
}
|
||||
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
private static function filterToSieveScript(Classes\Filter $oFilter, array &$aCapa) : string
|
||||
{
|
||||
$sNL = static::NEW_LINE;
|
||||
$sTab = ' ';
|
||||
|
||||
$bBlock = true;
|
||||
$aResult = array();
|
||||
|
||||
// Conditions
|
||||
$aConditions = $oFilter->Conditions();
|
||||
if (1 < \count($aConditions))
|
||||
{
|
||||
if (Enumerations\ConditionsType::ANY ===
|
||||
$oFilter->ConditionsType())
|
||||
{
|
||||
$aResult[] = 'if anyof(';
|
||||
|
||||
$bTrim = false;
|
||||
foreach ($aConditions as $oCond)
|
||||
{
|
||||
$bTrim = true;
|
||||
$sCons = static::conditionToSieveScript($oCond, $aCapa);
|
||||
if (!empty($sCons))
|
||||
{
|
||||
$aResult[] = $sTab.$sCons.',';
|
||||
}
|
||||
}
|
||||
if ($bTrim)
|
||||
{
|
||||
$aResult[\count($aResult) - 1] = \rtrim($aResult[\count($aResult) - 1], ',');
|
||||
}
|
||||
|
||||
$aResult[] = ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResult[] = 'if allof(';
|
||||
foreach ($aConditions as $oCond)
|
||||
{
|
||||
$aResult[] = $sTab . static::conditionToSieveScript($oCond, $aCapa) . ',';
|
||||
}
|
||||
|
||||
$aResult[\count($aResult) - 1] = \rtrim($aResult[\count($aResult) - 1], ',');
|
||||
$aResult[] = ')';
|
||||
}
|
||||
}
|
||||
else if (1 === \count($aConditions))
|
||||
{
|
||||
$aResult[] = 'if ' . static::conditionToSieveScript($aConditions[0], $aCapa);
|
||||
}
|
||||
else
|
||||
{
|
||||
$bBlock = false;
|
||||
}
|
||||
|
||||
// actions
|
||||
if ($bBlock)
|
||||
{
|
||||
$aResult[] = '{';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sTab = '';
|
||||
}
|
||||
|
||||
if ($oFilter->MarkAsRead() && \in_array($oFilter->ActionType(), array(
|
||||
Enumerations\ActionType::NONE,
|
||||
Enumerations\ActionType::MOVE_TO,
|
||||
Enumerations\ActionType::FORWARD
|
||||
)))
|
||||
{
|
||||
$aCapa['imap4flags'] = true;
|
||||
$aResult[] = $sTab.'addflag "\\\\Seen";';
|
||||
}
|
||||
|
||||
switch ($oFilter->ActionType())
|
||||
{
|
||||
case Enumerations\ActionType::NONE:
|
||||
if ($oFilter->Stop())
|
||||
{
|
||||
$aResult[] = $sTab.'stop;';
|
||||
}
|
||||
break;
|
||||
case Enumerations\ActionType::DISCARD:
|
||||
$aResult[] = $sTab.'discard;';
|
||||
if ($oFilter->Stop())
|
||||
{
|
||||
$aResult[] = $sTab.'stop;';
|
||||
}
|
||||
break;
|
||||
case Enumerations\ActionType::VACATION:
|
||||
$sValue = \trim($oFilter->ActionValue());
|
||||
$sValueSecond = \trim($oFilter->ActionValueSecond());
|
||||
$sValueThird = \trim($oFilter->ActionValueThird());
|
||||
$sValueFourth = \trim($oFilter->ActionValueFourth());
|
||||
if (\strlen($sValue))
|
||||
{
|
||||
$aCapa['vacation'] = true;
|
||||
|
||||
$iDays = 1;
|
||||
$sSubject = '';
|
||||
if (\strlen($sValueSecond))
|
||||
{
|
||||
$sSubject = ':subject "'.
|
||||
static::quote(\MailSo\Base\Utils::StripSpaces($sValueSecond)).'" ';
|
||||
}
|
||||
|
||||
if (\strlen($sValueThird) && \is_numeric($sValueThird) && 1 < (int) $sValueThird)
|
||||
{
|
||||
$iDays = (int) $sValueThird;
|
||||
}
|
||||
|
||||
$sAddresses = '';
|
||||
if (\strlen($sValueFourth))
|
||||
{
|
||||
$aAddresses = \explode(',', $sValueFourth);
|
||||
$aAddresses = \array_filter(\array_map(function ($sEmail) use ($self) {
|
||||
$sEmail = \trim($sEmail);
|
||||
return \strlen($sEmail) ? '"'.static::quote($sEmail).'"' : '';
|
||||
}, $aAddresses), 'strlen');
|
||||
|
||||
if (\count($aAddresses))
|
||||
{
|
||||
$sAddresses = ':addresses ['.\implode(', ', $aAddresses).'] ';
|
||||
}
|
||||
}
|
||||
|
||||
$aResult[] = $sTab.'vacation :days '.$iDays.' '.$sAddresses.$sSubject.'"'.static::quote($sValue).'";';
|
||||
if ($oFilter->Stop())
|
||||
{
|
||||
$aResult[] = $sTab.'stop;';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResult[] = $sTab.'# @Error (vacation): empty action value';
|
||||
}
|
||||
break;
|
||||
case Enumerations\ActionType::REJECT:
|
||||
$sValue = \trim($oFilter->ActionValue());
|
||||
if (\strlen($sValue))
|
||||
{
|
||||
$aCapa['reject'] = true;
|
||||
|
||||
$aResult[] = $sTab.'reject "'.static::quote($sValue).'";';
|
||||
if ($oFilter->Stop())
|
||||
{
|
||||
$aResult[] = $sTab.'stop;';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResult[] = $sTab.'# @Error (reject): empty action value';
|
||||
}
|
||||
break;
|
||||
case Enumerations\ActionType::FORWARD:
|
||||
$sValue = $oFilter->ActionValue();
|
||||
if (\strlen($sValue))
|
||||
{
|
||||
if ($oFilter->Keep())
|
||||
{
|
||||
$aCapa['fileinto'] = true;
|
||||
$aResult[] = $sTab.'fileinto "INBOX";';
|
||||
}
|
||||
|
||||
$aResult[] = $sTab.'redirect "'.static::quote($sValue).'";';
|
||||
if ($oFilter->Stop())
|
||||
{
|
||||
$aResult[] = $sTab.'stop;';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResult[] = $sTab.'# @Error (redirect): empty action value';
|
||||
}
|
||||
break;
|
||||
case Enumerations\ActionType::MOVE_TO:
|
||||
$sFolderName = $oFilter->ActionValue();
|
||||
if (\strlen($sFolderName))
|
||||
{
|
||||
$aCapa['fileinto'] = true;
|
||||
$aResult[] = $sTab.'fileinto "'.static::quote($sFolderName).'";';
|
||||
if ($oFilter->Stop())
|
||||
{
|
||||
$aResult[] = $sTab.'stop;';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResult[] = $sTab.'# @Error (fileinto): empty action value';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ($bBlock)
|
||||
{
|
||||
$aResult[] = '}';
|
||||
}
|
||||
|
||||
return \implode($sNL, $aResult);
|
||||
}
|
||||
|
||||
private static function quote(string $sValue) : string
|
||||
{
|
||||
return \str_replace(array('\\', '"'), array('\\\\', '\\"'), \trim($sValue));
|
||||
}
|
||||
}
|
||||
|
|
@ -81,22 +81,11 @@ class SieveStorage implements FiltersInterface
|
|||
);
|
||||
}
|
||||
|
||||
public function Save(\RainLoop\Model\Account $oAccount, string $sScriptName, array $aFilters, string $sRaw = '') : bool
|
||||
public function Save(\RainLoop\Model\Account $oAccount, string $sScriptName, string $sRaw) : bool
|
||||
{
|
||||
if ($aFilters && !$sRaw) {
|
||||
$sRaw = Sieve::collectionToFileString($aFilters);
|
||||
}
|
||||
$oSieveClient = $this->getConnection($oAccount);
|
||||
if ($oSieveClient) {
|
||||
if (empty($sRaw)) {
|
||||
$aList = $oSieveClient->ListScripts();
|
||||
if (isset($aList[$sScriptName])) {
|
||||
$oSieveClient->DeleteScript($sScriptName);
|
||||
}
|
||||
} else {
|
||||
$oSieveClient->PutScript($sScriptName, $sRaw);
|
||||
}
|
||||
$oSieveClient->Disconnect();
|
||||
$oSieveClient->PutScript($sScriptName, $sRaw);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -129,7 +118,9 @@ class SieveStorage implements FiltersInterface
|
|||
{
|
||||
$oSieveClient = $this->getConnection($oAccount);
|
||||
if ($oSieveClient) {
|
||||
$oSieveClient->DeleteScript(\trim($sScriptName));
|
||||
if (isset($oSieveClient->ListScripts()[$sScriptName])) {
|
||||
$oSieveClient->DeleteScript(\trim($sScriptName));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<a class="btn" data-bind="visible: $root.allowToggle, click: function() { $root.toggleFiltersRaw(); }, css: {'active': $root.rawActive }" data-i18n="[title]POPUPS_SIEVE_SCRIPT/BUTTON_RAW_SCRIPT">
|
||||
<a class="btn" data-bind="visible: allowFilters(), click: function() { $root.toggleFiltersRaw(); }, css: {'active': $root.rawActive }" data-i18n="[title]POPUPS_SIEVE_SCRIPT/BUTTON_RAW_SCRIPT">
|
||||
<i class="icon-file-code"></i>
|
||||
</a>
|
||||
<!--
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue