Felamimail - Notification to external email via sieve
authorPaul Mehrer <p.mehrer@metaways.de>
Mon, 12 Jun 2017 15:44:21 +0000 (17:44 +0200)
committerPaul Mehrer <p.mehrer@metaways.de>
Tue, 20 Jun 2017 11:53:16 +0000 (13:53 +0200)
!usermanual

Change-Id: Id7cb1eb331ca34e32f1dd961a79f5e7afca5f506
Reviewed-on: http://gerrit.tine20.com/customers/4863
Tested-by: Jenkins CI (http://ci.tine20.com/)
Reviewed-by: Paul Mehrer <p.mehrer@metaways.de>
Tested-by: Paul Mehrer <p.mehrer@metaways.de>
tests/tine20/Felamimail/Frontend/JsonTest.php
tests/tine20/Tinebase/ApplicationTest.php
tine20/Felamimail/Controller/Sieve.php
tine20/Felamimail/Frontend/Json.php
tine20/Felamimail/Model/Sieve/ScriptPart.php [new file with mode: 0644]
tine20/Felamimail/Setup/Initialize.php
tine20/Felamimail/Setup/Update/Release10.php
tine20/Felamimail/Setup/setup.xml
tine20/Felamimail/Sieve/Backend/Abstract.php
tine20/Felamimail/Sieve/Backend/Script.php
tine20/Felamimail/Sieve/Backend/Sql.php

index b907ad9..a1160f7 100644 (file)
@@ -1828,6 +1828,30 @@ IbVx8ZTO7dJRKrg72aFmWTf0uNla7vicAhpiLWobyNYcZbIjrAGDfg==
         // compare sieve scripts
         $this->assertContains($sieveScriptRules, $sieveScriptVacation, 'rule order changed');
     }
+
+    /**
+     * testSieveRulesOrder
+     *
+     * @see 0007240: order of sieve rules changes when vacation message is saved
+     */
+    public function testSieveEmailNotification()
+    {
+        $this->_setTestScriptname();
+
+        $result = $this->_json->setSieveNotificationEmail($this->_account->getId(), 'test@test.de');
+        static::assertTrue(is_array($result) && count($result) === 1 && isset($result['success']) &&
+            true === $result['success'], print_r($result, true));
+
+        $script = new Felamimail_Sieve_Backend_Sql($this->_account->getId());
+        $scriptParts = $script->getScriptParts();
+        static::assertEquals(1, $scriptParts->count());
+        /** @var Felamimail_Model_Sieve_ScriptPart $scriptPart */
+        $scriptPart = $scriptParts->getFirstRecord();
+        static::assertTrue(count(array_intersect(array('"enotify"', '"variables"', '"copy"'), $scriptPart->xprops(
+            Felamimail_Model_Sieve_ScriptPart::XPROPS_REQUIRES))) === 3, print_r($scriptPart->xprops(
+            Felamimail_Model_Sieve_ScriptPart::XPROPS_REQUIRES), true));
+        static::assertContains('test@test.de', $script->getSieve());
+    }
     
     /**
      * use another name for test sieve script
index b4c0e39..ed13688 100644 (file)
@@ -326,6 +326,7 @@ class Tinebase_ApplicationTest extends TestCase
                 'Felamimail_Model_Account',
                 'Felamimail_Model_Sieve_Vacation',
                 'Felamimail_Model_Sieve_Rule',
+                'Felamimail_Model_Sieve_ScriptPart',
                 'Felamimail_Model_PreparedMessagePart',
                 'Felamimail_Model_Message',
                 'Felamimail_Model_Folder',
index 46555b1..f9937cd 100644 (file)
@@ -6,7 +6,7 @@
  * @subpackage  Controller
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
  * @author      Philipp Schüle <p.schuele@metaways.de>
- * @copyright   Copyright (c) 2010-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2010-2017 Metaways Infosystems GmbH (http://www.metaways.de)
  * 
  * @todo        add __destruct with $_backend->logout()?
  */
@@ -348,13 +348,13 @@ class Felamimail_Controller_Sieve extends Tinebase_Controller_Abstract
     {
         return (preg_match('/dbmail/i', $this->_backend->getImplementation()));
     }
-        
+
     /**
      * put updated sieve script
-     * 
+     *
      * @param string|Felamimail_Model_Account $_accountId
      * @param Felamimail_Sieve_Backend_Abstract $_script
-     * @throws Felamimail_Exception_Sieve
+     * @throws Felamimail_Exception_SievePutScriptFail
      */
     protected function _putScript($_accountId, $_script)
     {
@@ -627,4 +627,88 @@ class Felamimail_Controller_Sieve extends Tinebase_Controller_Abstract
         
         return $result;
     }
+
+    /**
+     * @param string $_accountId
+     * @param string $_email
+     * @throws Tinebase_Exception_UnexpectedValue
+     */
+    public function setNotificationEmail($_accountId, $_email)
+    {
+        $_email = trim($_email);
+        if (!preg_match(Tinebase_Mail::EMAIL_ADDRESS_REGEXP, $_email)) {
+            throw new Tinebase_Exception_UnexpectedValue($_email . ' is not a valid email address');
+        }
+
+        // acl check
+        if (!$_accountId instanceof Felamimail_Model_Account) {
+            Felamimail_Controller_Account::getInstance()->get($_accountId);
+        }
+
+        $fileSystem = Tinebase_FileSystem::getInstance();
+        $scriptParts = new Tinebase_Record_RecordSet('Felamimail_Model_Sieve_ScriptPart', array());
+
+        $translate = Tinebase_Translation::getTranslation('Felamimail');
+        $locale = Tinebase_Core::get(Tinebase_Core::LOCALE);
+        $subject = $translate->_('You have new mail from ', $locale);
+
+        /** @var Tinebase_Model_Tree_Node $sieveNode */
+        foreach ($fileSystem->getTreeNodeChildren(Felamimail_Config::getInstance()->
+                get(Felamimail_Config::EMAIL_NOTIFICATION_TEMPLATES_CONTAINER_ID)) as $sieveNode) {
+            if (Tinebase_Model_Tree_FileObject::TYPE_FILE !== $sieveNode->type) {
+                continue;
+            }
+            $path = Tinebase_Model_Tree_Node_Path::createFromStatPath($fileSystem->getPathOfNode($sieveNode, true));
+            $sieveScript = file_get_contents($path->streamwrapperpath);
+            $sieveScript = str_replace('USER_EXTERNAL_EMAIL', $_email, $sieveScript);
+            $sieveScript = str_replace('TRANSLATE_SUBJECT', $subject, $sieveScript);
+            $scriptParts->addRecord(Felamimail_Model_Sieve_ScriptPart::createFromString(
+                Felamimail_Model_Sieve_ScriptPart::TYPE_NOTIFICATION, $sieveNode->name, $sieveScript));
+        }
+
+        $this->setNotificationScripts($_accountId, $scriptParts);
+    }
+
+    /**
+     * set notification scripts for account
+     *
+     * @param string|Felamimail_Model_Account $_accountId
+     * @param Tinebase_Record_RecordSet $_scriptParts (Felamimail_Model_Sieve_ScriptPart)
+     */
+    public function setNotificationScripts($_accountId, Tinebase_Record_RecordSet $_scriptParts)
+    {
+        // acl check
+        if (!$_accountId instanceof Felamimail_Model_Account) {
+            Felamimail_Controller_Account::getInstance()->get($_accountId);
+        }
+
+        if ($_scriptParts->count() !==
+                $_scriptParts->filter('type', Felamimail_Model_Sieve_ScriptPart::TYPE_NOTIFICATION)->count()) {
+            throw new Tinebase_Exception_UnexpectedValue('all script parts need to be of type '
+                . Felamimail_Model_Sieve_ScriptPart::TYPE_NOTIFICATION);
+        }
+        $_scriptParts->account_id = $_accountId;
+
+        $script = $this->_getSieveScript($_accountId);
+
+        if (null === $script) {
+            $script = $this->_createNewSieveScript($_accountId);
+        }
+
+        try {
+            $script->readScriptData();
+        } catch(Tinebase_Exception_NotFound $tenf) {}
+
+        $oldScripParts = $script->getScriptParts();
+        $oldScripParts->removeRecords($oldScripParts->filter('type',
+            Felamimail_Model_Sieve_ScriptPart::TYPE_NOTIFICATION));
+        $oldScripParts->merge($_scriptParts);
+
+        if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
+            Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Put updated rules SIEVE script ' .
+                $this->_scriptName);
+        }
+
+        $this->_putScript($_accountId, $script);
+    }
 }
index de157a2..8eed362 100644 (file)
@@ -612,4 +612,16 @@ class Felamimail_Frontend_Json extends Tinebase_Frontend_Json_Abstract
         
         return $result;
     }
+
+    /**
+     * @param string $_accountId
+     * @param string $_email
+     * @return array
+     */
+    public function setSieveNotificationEmail($_accountId, $_email)
+    {
+        Felamimail_Controller_Sieve::getInstance()->setNotificationEmail($_accountId, $_email);
+
+        return array('success' => true);
+    }
 }
diff --git a/tine20/Felamimail/Model/Sieve/ScriptPart.php b/tine20/Felamimail/Model/Sieve/ScriptPart.php
new file mode 100644 (file)
index 0000000..fe5178b
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+/**
+ * class to hold Sieve script parts
+ *
+ * @package     Felamimail
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Paul Mehrer <p.mehrer@metaways.de>
+ * @copyright   Copyright (c) 2017 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+
+/**
+ * class to hold script parts
+ *
+ * @property    integer id
+ * @property    string  account_id
+ * @property    string  type
+ * @property    string  name
+ * @property    string  script
+ * @property    array   requires
+ *
+ * @package     Felamimail
+ */
+class Felamimail_Model_Sieve_ScriptPart extends Tinebase_Record_Abstract
+{
+    /** @var string */
+    const XPROPS_REQUIRES = 'requires';
+
+    /** @var string */
+    const TYPE_NOTIFICATION = 'notification';
+
+    /**
+     * key in $_validators/$_properties array for the field which
+     * represents the identifier
+     *
+     * @var string
+     */
+    protected $_identifier = 'id';
+
+    /**
+     * application the record belongs to
+     *
+     * @var string
+     */
+    protected $_application = 'Felamimail';
+
+    /**
+     * list of zend validator
+     *
+     * this validators get used when validating user generated content with Zend_Input_Filter
+     *
+     * @var array
+     */
+    protected $_validators = array(
+        'id'                    => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'account_id'            => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'type'                  => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'name'                  => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'script'                => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'requires'              => array(Zend_Filter_Input::ALLOW_EMPTY => true)
+    );
+
+    /**
+     * @param string $_type
+     * @param string $_name
+     * @param string $_script
+     * @return Felamimail_Model_Sieve_ScriptPart
+     */
+    public static function createFromString($_type, $_name, $_script)
+    {
+        $instance = new self(array(), true);
+        $instance->type = $_type;
+        $instance->name = $_name;
+        if (preg_match('/^require\s+\[([^\]]+)\];/', $_script, $matches)) {
+            $_script = str_replace($matches[0], '', $_script);
+            $require = explode(',', $matches[1]);
+            array_walk($require, function(&$val) {$val = trim($val);});
+            $instance->requires = $require;
+        }
+        $instance->script = $_script;
+
+        return $instance;
+    }
+
+    public function runConvertToData()
+    {
+        if (isset($this->_properties[self::XPROPS_REQUIRES]) && is_array($this->_properties[self::XPROPS_REQUIRES])) {
+            if (count($this->_properties[self::XPROPS_REQUIRES]) > 0) {
+                $this->_properties[self::XPROPS_REQUIRES] = json_encode($this->_properties[self::XPROPS_REQUIRES]);
+            } else {
+                $this->_properties[self::XPROPS_REQUIRES] = null;
+            }
+        }
+
+        parent::runConvertToData();
+    }
+}
index f231423..a653418 100644 (file)
@@ -127,10 +127,17 @@ class Felamimail_Setup_Initialize extends Setup_Initialize
             fwrite($fh, <<<'sieveFile'
 require ["enotify", "variables", "copy"];
 
-if header :contains "X-Tine20-Type" "Notification" {
+if header :contains "Return-Path" "<>" {
+} elsif header :contains "X-Tine20-Type" "Notification" {
     redirect :copy "USER_EXTERNAL_EMAIL"; 
 } else {
-    notify :message "you have a new mail"
+    if header :matches "Subject" "*" {
+        set "subject" "${1}";
+    }
+    if header :matches "From" "*" {
+        set "from" "${1}";
+    }
+    notify :message "TRANSLATE_SUBJECT${from}: ${subject}"
               "mailto:USER_EXTERNAL_EMAIL";
 }
 sieveFile
index 5d3a248..34cad96 100644 (file)
@@ -5,7 +5,7 @@
  * @package     Felamimail
  * @subpackage  Setup
  * @license     http://www.gnu.org/licenses/agpl.html AGPL3
- * @copyright   Copyright (c) 2015-2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2015-2017 Metaways Infosystems GmbH (http://www.metaways.de)
  * @author      Philipp Schüle <p.schuele@metaways.de>
  */
 class Felamimail_Setup_Update_Release10 extends Setup_Update_Abstract
@@ -55,4 +55,79 @@ class Felamimail_Setup_Update_Release10 extends Setup_Update_Abstract
         }
         $this->setApplicationVersion('Felamimail', '10.3');
     }
+
+    /**
+     * update to 10.4
+     *
+     * add sieve script part table
+     */
+    public function update_3()
+    {
+        $tableDefinition = new Setup_Backend_Schema_Table_Xml('<table>
+            <name>felamimail_sieve_scriptpart</name>
+            <version>1</version>
+            <declaration>
+                <field>
+                    <name>id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>account_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>type</name>
+                    <type>text</type>
+                    <length>60</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>name</name>
+                    <type>text</type>
+                    <length>255</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>script</name>
+                    <type>text</type>
+                    <length>65535</length>
+                </field>
+                <field>
+                    <name>requires</name>
+                    <type>text</type>
+                    <length>65535</length>
+                </field>
+                <index>
+                    <name>id</name>
+                    <primary>true</primary>
+                    <field>
+                        <name>id</name>
+                    </field>
+                </index>
+                <index>
+                    <name>account_id-type-name</name>
+                    <unique>true</unique>
+                    <field>
+                        <name>account_id</name>
+                    </field>
+                    <field>
+                        <name>type</name>
+                    </field>
+                    <field>
+                        <name>name</name>
+                    </field>
+                </index>
+            </declaration>
+        </table>');
+
+        if (! $this->_backend->tableExists('felamimail_sieve_scriptpart')) {
+            $this->_backend->createTable($tableDefinition, 'Felamimail', 'felamimail_sieve_scriptpart');
+        }
+
+        $this->setApplicationVersion('Felamimail', '10.4');
+    }
 }
index bed97c7..32adb16 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <application>
     <name>Felamimail</name>
-    <version>10.3</version>
+    <version>10.4</version>
     <order>30</order>
     <status>enabled</status>
     <tables>
             </declaration>
         </table>
         <table>
+            <name>felamimail_sieve_scriptpart</name>
+            <version>1</version>
+            <declaration>
+                <field>
+                    <name>id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>account_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>type</name>
+                    <type>text</type>
+                    <length>60</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>name</name>
+                    <type>text</type>
+                    <length>255</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>script</name>
+                    <type>text</type>
+                    <length>65535</length>
+                </field>
+                <field>
+                    <name>requires</name>
+                    <type>text</type>
+                    <length>65535</length>
+                </field>
+                <index>
+                    <name>id</name>
+                    <primary>true</primary>
+                    <field>
+                        <name>id</name>
+                    </field>
+                </index>
+                <index>
+                    <name>account_id-type-name</name>
+                    <unique>true</unique>
+                    <field>
+                        <name>account_id</name>
+                    </field>
+                    <field>
+                        <name>type</name>
+                    </field>
+                    <field>
+                        <name>name</name>
+                    </field>
+                </index>
+            </declaration>
+        </table>
+        <table>
             <name>felamimail_sieve_vacation</name>
             <version>3</version>
             <declaration>
index e1b5ec6..22bb1dc 100644 (file)
@@ -6,7 +6,7 @@
  * @subpackage  Sieve
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
  * @author      Philipp Schüle <p.schuele@metaways.de>
- * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2011-2017 Metaways Infosystems GmbH (http://www.metaways.de)
  */
 
 /**
@@ -30,6 +30,13 @@ abstract class Felamimail_Sieve_Backend_Abstract
      * @var Felamimail_Sieve_Vacation
      */
     protected $_vacation = NULL;
+
+    /**
+     * recordset of Felamimail_Model_Sieve_ScriptPart
+     *
+     * @var Tinebase_Record_RecordSet
+     */
+    protected $_scriptParts = NULL;
     
     /**
      * generator string in header
@@ -57,6 +64,16 @@ abstract class Felamimail_Sieve_Backend_Abstract
     {
         return $this->_vacation;
     }
+
+    /**
+     * recordset of Felamimail_Model_Sieve_ScriptPart
+     *
+     * @return Tinebase_Record_RecordSet
+     */
+    public function getScriptParts()
+    {
+        return $this->_scriptParts;
+    }
     
     /**
      * parse Sieve script (only pseudo scripts get loaded)
@@ -67,7 +84,6 @@ abstract class Felamimail_Sieve_Backend_Abstract
      * add rule to script
      * 
      * @param Felamimail_Sieve_Rule $rule
-     * @return Felamimail_Sieve_Vacation
      */
     public function addRule(Felamimail_Sieve_Rule $rule)
     {
@@ -91,9 +107,10 @@ abstract class Felamimail_Sieve_Backend_Abstract
     {
         $rules = $this->_getRulesString();
         $vacation = $this->_getVacationString();
-        $header = (! empty($rules) || ! empty($vacation)) ? $this->_getHeaderString() : '';
+        $scriptParts = $this->_getScriptPartsString();
+        $header = (!empty($rules) || !empty($vacation) || !empty($scriptParts)) ? $this->_getHeaderString() : '';
         
-        $sieve = $header . "\r\n\r\n" . $rules . $vacation . "\r\n\r\n";
+        $sieve = $header . "\r\n\r\n" . $rules . $vacation . $scriptParts . "\r\n\r\n";
         
         return $sieve;
     }
@@ -145,11 +162,39 @@ abstract class Felamimail_Sieve_Backend_Abstract
                 $require[] = '"relational"';
             }
         }
+
+        if (null !== $this->_scriptParts) {
+            /** @var Felamimail_Model_Sieve_ScriptPart $scriptPart */
+            foreach ($this->_scriptParts as $scriptPart) {
+                $require = array_merge($require,
+                    $scriptPart->xprops(Felamimail_Model_Sieve_ScriptPart::XPROPS_REQUIRES));
+            }
+        }
+
+        $require = array_unique($require);
         
         return $require;
     }
 
     /**
+     * @return string
+     */
+    protected function _getScriptPartsString()
+    {
+        if (null === $this->_scriptParts) {
+            return '';
+        }
+
+        $result = "\r\n";
+
+        /** @var Felamimail_Model_Sieve_ScriptPart $scriptPart */
+        foreach ($this->_scriptParts as $scriptPart) {
+            $result .= $scriptPart->script . "\r\n";
+        }
+
+        return $result;
+    }
+    /**
      * get sieve rules string
      * 
      * @return string
@@ -193,6 +238,14 @@ abstract class Felamimail_Sieve_Backend_Abstract
     {
         $this->_vacation = $vacation;
     }
+
+    /**
+     * @param Tinebase_Record_RecordSet $_scriptParts
+     */
+    public function setScriptParts(Tinebase_Record_RecordSet $_scriptParts)
+    {
+        $this->_scriptParts = $_scriptParts;
+    }
     
     /**
      * copy data from another script
@@ -203,5 +256,6 @@ abstract class Felamimail_Sieve_Backend_Abstract
     {
         $this->_vacation = $_scriptToCopyFrom->getVacation();
         $this->_rules = $_scriptToCopyFrom->getRules();
+        $this->_scriptParts = $_scriptToCopyFrom->getScriptParts();
     }
 }
index 262cd2e..1f4b02c 100644 (file)
@@ -6,7 +6,7 @@
  * @subpackage  Sieve
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
  * @author      Lars Kneschke <l.kneschke@metaways.de>
- * @copyright   Copyright (c) 2010-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2010-2017 Metaways Infosystems GmbH (http://www.metaways.de)
  * 
  */
 
@@ -31,7 +31,7 @@ class Felamimail_Sieve_Backend_Script extends Felamimail_Sieve_Backend_Abstract
     /**
      * constructor
      * 
-     * @param   string  $script     the Sieve script or null
+     * @param   string  $_script     the Sieve script or null
      */
     public function __construct($_script = null)
     {
index 96cb5fe..d08c389 100644 (file)
@@ -6,7 +6,7 @@
  * @subpackage  Sieve
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
  * @author      Philipp Schüle <p.schuele@metaways.de>
- * @copyright   Copyright (c) 2010-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2010-2017 Metaways Infosystems GmbH (http://www.metaways.de)
  * 
  * @todo        allow multiple scripts with different names for one account?
  */
@@ -32,6 +32,13 @@ class Felamimail_Sieve_Backend_Sql extends Felamimail_Sieve_Backend_Abstract
      * @var Tinebase_Backend_Sql
      */
     protected $_vacationBackend = NULL;
+
+    /**
+     * script part backend
+     *
+     * @var Tinebase_Backend_Sql
+     */
+    protected $_scriptPartBackend = NULL;
     
     /**
      * email account id
@@ -39,12 +46,13 @@ class Felamimail_Sieve_Backend_Sql extends Felamimail_Sieve_Backend_Abstract
      * @var string
      */
     protected $_accountId = NULL;
-    
+
     /**
      * constructor
-     * 
-     * @param   string|Felamimail_Model_Account  $_accountId     the felamimail account id
+     *
+     * @param   string|Felamimail_Model_Account $_accountId the felamimail account id
      * @param   boolean $_readData
+     * @throws Felamimail_Exception
      */
     public function __construct($_accountId, $_readData = TRUE)
     {
@@ -57,6 +65,11 @@ class Felamimail_Sieve_Backend_Sql extends Felamimail_Sieve_Backend_Abstract
             'modelName' => 'Felamimail_Model_Sieve_Vacation', 
             'tableName' => 'felamimail_sieve_vacation',
         ));
+
+        $this->_scriptPartBackend = new Tinebase_Backend_Sql(array(
+            'modelName' => 'Felamimail_Model_Sieve_ScriptPart',
+            'tableName' => 'felamimail_sieve_scriptpart',
+        ));
         
         $this->_accountId = ($_accountId instanceof Felamimail_Model_Account) ? $_accountId->getId() : $_accountId;
         
@@ -78,12 +91,18 @@ class Felamimail_Sieve_Backend_Sql extends Felamimail_Sieve_Backend_Abstract
     {
         $this->_getRules();
         $this->_getVacation();
+        $this->_getScriptParts();
         
-        if (count($this->_rules) === 0 && $this->_vacation === NULL) {
+        if (count($this->_rules) === 0 && $this->_vacation === NULL && $this->_scriptParts->count() === 0) {
             throw new Tinebase_Exception_NotFound('No sieve data found in database for this account.');
         }
     }
-    
+
+    protected function _getScriptParts()
+    {
+        $this->_scriptParts = $this->_scriptPartBackend->getMultipleByProperty($this->_accountId, 'account_id', FALSE, 'id');
+    }
+
     /**
      * get rules
      */
@@ -108,6 +127,7 @@ class Felamimail_Sieve_Backend_Sql extends Felamimail_Sieve_Backend_Abstract
     protected function _getVacation()
     {
         try {
+            /** @var Felamimail_Model_Sieve_Vacation $vacationRecord */
             $vacationRecord = $this->_vacationBackend->getByProperty($this->_accountId, 'account_id');
             $vacationRecord->addresses = Zend_Json::decode($vacationRecord->addresses);
             
@@ -141,6 +161,35 @@ class Felamimail_Sieve_Backend_Sql extends Felamimail_Sieve_Backend_Abstract
     {
         $this->_saveRules();
         $this->_saveVacation();
+        $this->_saveScriptParts();
+    }
+
+    /**
+     * persist script parts data in db
+     *
+     * @throws Exception
+     */
+    protected function _saveScriptParts()
+    {
+        if (empty($this->_scriptParts)) {
+            $this->_scriptPartBackend->deleteByProperty($this->_accountId, 'account_id');
+            return;
+        }
+
+        try {
+            $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
+
+            $this->_scriptPartBackend->deleteByProperty($this->_accountId, 'account_id');
+            /** @var Felamimail_Model_Sieve_ScriptPart $scriptPart */
+            foreach ($this->_scriptParts as $scriptPart) {
+                $this->_scriptPartBackend->create($scriptPart);
+            }
+
+            Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
+        } catch (Exception $e) {
+            Tinebase_TransactionManager::getInstance()->rollBack();
+            throw $e;
+        }
     }
     
     /**
@@ -195,7 +244,7 @@ class Felamimail_Sieve_Backend_Sql extends Felamimail_Sieve_Backend_Abstract
             . ' Saving vacation in DB: ' . print_r($vacationRecord->toArray(), TRUE));
         
         try {
-            $oldVac = $this->_vacationBackend->get($vacationRecord->getId());
+            $this->_vacationBackend->get($vacationRecord->getId());
             $this->_vacationBackend->update($vacationRecord);
         } catch (Tinebase_Exception_NotFound $tenf) {
             $this->_vacationBackend->create($vacationRecord);
@@ -211,11 +260,12 @@ class Felamimail_Sieve_Backend_Sql extends Felamimail_Sieve_Backend_Abstract
             $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
             $this->_rulesBackend->deleteByProperty($this->_accountId, 'account_id');
             $this->_vacationBackend->deleteByProperty($this->_accountId, 'account_id');
+            $this->_scriptPartBackend->deleteByProperty($this->_accountId, 'account_id');
             
             Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
         } catch (Exception $e) {
             Tinebase_TransactionManager::getInstance()->rollBack();
-            throw Exception;
+            throw $e;
         }
     }
 }