612 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			612 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php namespace Sieve;
 | 
						|
 | 
						|
require_once('SieveKeywordRegistry.php');
 | 
						|
require_once('SieveToken.php');
 | 
						|
require_once('SieveException.php');
 | 
						|
 | 
						|
class SieveSemantics
 | 
						|
{
 | 
						|
    protected static $requiredExtensions_ = array();
 | 
						|
 | 
						|
    protected $comparator_;
 | 
						|
    protected $matchType_;
 | 
						|
    protected $addressPart_;
 | 
						|
    protected $tags_ = array();
 | 
						|
    protected $arguments_;
 | 
						|
    protected $deps_ = array();
 | 
						|
    protected $followupToken_;
 | 
						|
 | 
						|
    public function __construct($token, $prevToken)
 | 
						|
    {
 | 
						|
        $this->registry_ = SieveKeywordRegistry::get();
 | 
						|
        $command = strtolower($token->text);
 | 
						|
 | 
						|
        // Check the registry for $command
 | 
						|
        if ($this->registry_->isCommand($command))
 | 
						|
        {
 | 
						|
            $xml = $this->registry_->command($command);
 | 
						|
            $this->arguments_ = $this->makeArguments_($xml);
 | 
						|
            $this->followupToken_ = SieveToken::Semicolon;
 | 
						|
        }
 | 
						|
        else if ($this->registry_->isTest($command))
 | 
						|
        {
 | 
						|
            $xml = $this->registry_->test($command);
 | 
						|
            $this->arguments_ = $this->makeArguments_($xml);
 | 
						|
            $this->followupToken_ = SieveToken::BlockStart;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            throw new SieveException($token, 'unknown command '. $command);
 | 
						|
        }
 | 
						|
 | 
						|
        // Check if command may appear at this position within the script
 | 
						|
        if ($this->registry_->isTest($command))
 | 
						|
        {
 | 
						|
            if (is_null($prevToken))
 | 
						|
                throw new SieveException($token, $command .' may not appear as first command');
 | 
						|
 | 
						|
            if (!preg_match('/^(if|elsif|anyof|allof|not)$/i', $prevToken->text))
 | 
						|
                throw new SieveException($token, $command .' may not appear after '. $prevToken->text);
 | 
						|
        }
 | 
						|
        else if (isset($prevToken))
 | 
						|
        {
 | 
						|
            switch ($command)
 | 
						|
            {
 | 
						|
            case 'require':
 | 
						|
                $valid_after = 'require';
 | 
						|
                break;
 | 
						|
            case 'elsif':
 | 
						|
            case 'else':
 | 
						|
                $valid_after = '(if|elsif)';
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                $valid_after = $this->commandsRegex_();
 | 
						|
            }
 | 
						|
 | 
						|
            if (!preg_match('/^'. $valid_after .'$/i', $prevToken->text))
 | 
						|
                throw new SieveException($token, $command .' may not appear after '. $prevToken->text);
 | 
						|
        }
 | 
						|
 | 
						|
        // Check for extension arguments to add to the command
 | 
						|
        foreach ($this->registry_->arguments($command) as $arg)
 | 
						|
        {
 | 
						|
            switch ((string) $arg['type'])
 | 
						|
            {
 | 
						|
            case 'tag':
 | 
						|
                array_unshift($this->arguments_, array(
 | 
						|
                    'type'       => SieveToken::Tag,
 | 
						|
                    'occurrence' => $this->occurrence_($arg),
 | 
						|
                    'regex'      => $this->regex_($arg),
 | 
						|
                    'call'       => 'tagHook_',
 | 
						|
                    'name'       => $this->name_($arg),
 | 
						|
                    'subArgs'    => $this->makeArguments_($arg->children())
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public function __destruct()
 | 
						|
    {
 | 
						|
        $this->registry_->put();
 | 
						|
    }
 | 
						|
 | 
						|
    // TODO: the *Regex functions could possibly also be static properties
 | 
						|
    protected function requireStringsRegex_()
 | 
						|
    {
 | 
						|
        return '('. implode('|', $this->registry_->requireStrings()) .')';
 | 
						|
    }
 | 
						|
 | 
						|
    protected function matchTypeRegex_()
 | 
						|
    {
 | 
						|
        return '('. implode('|', $this->registry_->matchTypes()) .')';
 | 
						|
    }
 | 
						|
 | 
						|
    protected function addressPartRegex_()
 | 
						|
    {
 | 
						|
        return '('. implode('|', $this->registry_->addressParts()) .')';
 | 
						|
    }
 | 
						|
 | 
						|
    protected function commandsRegex_()
 | 
						|
    {
 | 
						|
        return '('. implode('|', $this->registry_->commands()) .')';
 | 
						|
    }
 | 
						|
 | 
						|
    protected function testsRegex_()
 | 
						|
    {
 | 
						|
        return '('. implode('|', $this->registry_->tests()) .')';
 | 
						|
    }
 | 
						|
 | 
						|
    protected function comparatorRegex_()
 | 
						|
    {
 | 
						|
        return '('. implode('|', $this->registry_->comparators()) .')';
 | 
						|
    }
 | 
						|
 | 
						|
    protected function occurrence_($arg)
 | 
						|
    {
 | 
						|
        if (isset($arg['occurrence']))
 | 
						|
        {
 | 
						|
            switch ((string) $arg['occurrence'])
 | 
						|
            {
 | 
						|
            case 'optional':
 | 
						|
                return '?';
 | 
						|
            case 'any':
 | 
						|
                return '*';
 | 
						|
            case 'some':
 | 
						|
                return '+';
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return '1';
 | 
						|
    }
 | 
						|
 | 
						|
    protected function name_($arg)
 | 
						|
    {
 | 
						|
        if (isset($arg['name']))
 | 
						|
        {
 | 
						|
            return (string) $arg['name'];
 | 
						|
        }
 | 
						|
        return (string) $arg['type'];
 | 
						|
    }
 | 
						|
 | 
						|
    protected function regex_($arg)
 | 
						|
    {
 | 
						|
        if (isset($arg['regex']))
 | 
						|
        {
 | 
						|
            return (string) $arg['regex'];
 | 
						|
        }
 | 
						|
        return '.*';
 | 
						|
    }
 | 
						|
 | 
						|
    protected function case_($arg)
 | 
						|
    {
 | 
						|
        if (isset($arg['case']))
 | 
						|
        {
 | 
						|
            return (string) $arg['case'];
 | 
						|
        }
 | 
						|
        return 'adhere';
 | 
						|
    }
 | 
						|
 | 
						|
    protected function follows_($arg)
 | 
						|
    {
 | 
						|
        if (isset($arg['follows']))
 | 
						|
        {
 | 
						|
            return (string) $arg['follows'];
 | 
						|
        }
 | 
						|
        return '.*';
 | 
						|
    }
 | 
						|
 | 
						|
    protected function makeValue_($arg)
 | 
						|
    {
 | 
						|
        if (isset($arg->value))
 | 
						|
        {
 | 
						|
            $res = $this->makeArguments_($arg->value);
 | 
						|
            return array_shift($res);
 | 
						|
        }
 | 
						|
        return null;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Convert an extension (test) commands parameters from XML to
 | 
						|
     * a PHP array the {@see Semantics} class understands.
 | 
						|
     * @param array(SimpleXMLElement) $parameters
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    protected function makeArguments_($parameters)
 | 
						|
    {
 | 
						|
        $arguments = array();
 | 
						|
 | 
						|
        foreach ($parameters as $arg)
 | 
						|
        {
 | 
						|
            // Ignore anything not a <parameter>
 | 
						|
            if ($arg->getName() != 'parameter')
 | 
						|
                continue;
 | 
						|
 | 
						|
            switch ((string) $arg['type'])
 | 
						|
            {
 | 
						|
            case 'addresspart':
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::Tag,
 | 
						|
                    'occurrence' => $this->occurrence_($arg),
 | 
						|
                    'regex'      => $this->addressPartRegex_(),
 | 
						|
                    'call'       => 'addressPartHook_',
 | 
						|
                    'name'       => 'address part',
 | 
						|
                    'subArgs'    => $this->makeArguments_($arg)
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'block':
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::BlockStart,
 | 
						|
                    'occurrence' => '1',
 | 
						|
                    'regex'      => '{',
 | 
						|
                    'name'       => 'block',
 | 
						|
                    'subArgs'    => $this->makeArguments_($arg)
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'comparator':
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::Tag,
 | 
						|
                    'occurrence' => $this->occurrence_($arg),
 | 
						|
                    'regex'      => 'comparator',
 | 
						|
                    'name'       => 'comparator',
 | 
						|
                    'subArgs'    => array( array(
 | 
						|
                        'type'       => SieveToken::String,
 | 
						|
                        'occurrence' => '1',
 | 
						|
                        'call'       => 'comparatorHook_',
 | 
						|
                        'case'       => 'adhere',
 | 
						|
                        'regex'      => $this->comparatorRegex_(),
 | 
						|
                        'name'       => 'comparator string',
 | 
						|
                        'follows'    => 'comparator'
 | 
						|
                    ))
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'matchtype':
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::Tag,
 | 
						|
                    'occurrence' => $this->occurrence_($arg),
 | 
						|
                    'regex'      => $this->matchTypeRegex_(),
 | 
						|
                    'call'       => 'matchTypeHook_',
 | 
						|
                    'name'       => 'match type',
 | 
						|
                    'subArgs'    => $this->makeArguments_($arg)
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'number':
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::Number,
 | 
						|
                    'occurrence' => $this->occurrence_($arg),
 | 
						|
                    'regex'      => $this->regex_($arg),
 | 
						|
                    'name'       => $this->name_($arg),
 | 
						|
                    'follows'    => $this->follows_($arg)
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'requirestrings':
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::StringList,
 | 
						|
                    'occurrence' => $this->occurrence_($arg),
 | 
						|
                    'call'       => 'setRequire_',
 | 
						|
                    'case'       => 'adhere',
 | 
						|
                    'regex'      => $this->requireStringsRegex_(),
 | 
						|
                    'name'       => $this->name_($arg)
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'string':
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::String,
 | 
						|
                    'occurrence' => $this->occurrence_($arg),
 | 
						|
                    'regex'      => $this->regex_($arg),
 | 
						|
                    'case'       => $this->case_($arg),
 | 
						|
                    'name'       => $this->name_($arg),
 | 
						|
                    'follows'    => $this->follows_($arg)
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'stringlist':
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::StringList,
 | 
						|
                    'occurrence' => $this->occurrence_($arg),
 | 
						|
                    'regex'      => $this->regex_($arg),
 | 
						|
                    'case'       => $this->case_($arg),
 | 
						|
                    'name'       => $this->name_($arg),
 | 
						|
                    'follows'    => $this->follows_($arg)
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'tag':
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::Tag,
 | 
						|
                    'occurrence' => $this->occurrence_($arg),
 | 
						|
                    'regex'      => $this->regex_($arg),
 | 
						|
                    'call'       => 'tagHook_',
 | 
						|
                    'name'       => $this->name_($arg),
 | 
						|
                    'subArgs'    => $this->makeArguments_($arg->children()),
 | 
						|
                    'follows'    => $this->follows_($arg)
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'test':
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::Identifier,
 | 
						|
                    'occurrence' => $this->occurrence_($arg),
 | 
						|
                    'regex'      => $this->testsRegex_(),
 | 
						|
                    'name'       => $this->name_($arg),
 | 
						|
                    'subArgs'    => $this->makeArguments_($arg->children())
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'testlist':
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::LeftParenthesis,
 | 
						|
                    'occurrence' => '1',
 | 
						|
                    'regex'      => '\(',
 | 
						|
                    'name'       => $this->name_($arg),
 | 
						|
                    'subArgs'    => null
 | 
						|
                ));
 | 
						|
                array_push($arguments, array(
 | 
						|
                    'type'       => SieveToken::Identifier,
 | 
						|
                    'occurrence' => '+',
 | 
						|
                    'regex'      => $this->testsRegex_(),
 | 
						|
                    'name'       => $this->name_($arg),
 | 
						|
                    'subArgs'    => $this->makeArguments_($arg->children())
 | 
						|
                ));
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $arguments;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add argument(s) expected / allowed to appear next.
 | 
						|
     * @param array $value
 | 
						|
     */
 | 
						|
    protected function addArguments_($identifier, $subArgs)
 | 
						|
    {
 | 
						|
        for ($i = count($subArgs); $i > 0; $i--)
 | 
						|
        {
 | 
						|
            $arg = $subArgs[$i-1];
 | 
						|
            if (preg_match('/^'. $arg['follows'] .'$/si', $identifier))
 | 
						|
                array_unshift($this->arguments_, $arg);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add dependency that is expected to be fullfilled when parsing
 | 
						|
     * of the current command is {@see done}.
 | 
						|
     * @param array $dependency
 | 
						|
     */
 | 
						|
    protected function addDependency_($type, $name, $dependencies)
 | 
						|
    {
 | 
						|
        foreach ($dependencies as $d)
 | 
						|
        {
 | 
						|
            array_push($this->deps_, array(
 | 
						|
                'o_type' => $type,
 | 
						|
                'o_name' => $name,
 | 
						|
                'type'   => $d['type'],
 | 
						|
                'name'   => $d['name'],
 | 
						|
                'regex'  => $d['regex']
 | 
						|
            ));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    protected function invoke_($token, $func, $arg = array())
 | 
						|
    {
 | 
						|
        if (!is_array($arg))
 | 
						|
            $arg = array($arg);
 | 
						|
 | 
						|
        $err = call_user_func_array(array(&$this, $func), $arg);
 | 
						|
 | 
						|
        if ($err)
 | 
						|
            throw new SieveException($token, $err);
 | 
						|
    }
 | 
						|
 | 
						|
    protected function setRequire_($extension)
 | 
						|
    {
 | 
						|
        array_push(self::$requiredExtensions_, $extension);
 | 
						|
        $this->registry_->activate($extension);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Hook function that is called after a address part match was found
 | 
						|
     * in a command. The kind of address part is remembered in case it's
 | 
						|
     * needed later {@see done}. For address parts from a extension
 | 
						|
     * dependency information and valid values are looked up as well.
 | 
						|
     * @param string $addresspart
 | 
						|
     */
 | 
						|
    protected function addressPartHook_($addresspart)
 | 
						|
    {
 | 
						|
        $this->addressPart_ = $addresspart;
 | 
						|
        $xml = $this->registry_->addresspart($this->addressPart_);
 | 
						|
 | 
						|
        if (isset($xml))
 | 
						|
        {
 | 
						|
            // Add possible value and dependancy
 | 
						|
            $this->addArguments_($this->addressPart_, $this->makeArguments_($xml));
 | 
						|
            $this->addDependency_('address part', $this->addressPart_, $xml->requires);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Hook function that is called after a match type was found in a
 | 
						|
     * command. The kind of match type is remembered in case it's
 | 
						|
     * needed later {@see done}. For a match type from extensions
 | 
						|
     * dependency information and valid values are looked up as well.
 | 
						|
     * @param string $matchtype
 | 
						|
     */
 | 
						|
    protected function matchTypeHook_($matchtype)
 | 
						|
    {
 | 
						|
        $this->matchType_ = $matchtype;
 | 
						|
        $xml = $this->registry_->matchtype($this->matchType_);
 | 
						|
 | 
						|
        if (isset($xml))
 | 
						|
        {
 | 
						|
            // Add possible value and dependancy
 | 
						|
            $this->addArguments_($this->matchType_, $this->makeArguments_($xml));
 | 
						|
            $this->addDependency_('match type', $this->matchType_, $xml->requires);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Hook function that is called after a comparator was found in
 | 
						|
     * a command. The comparator is remembered in case it's needed for
 | 
						|
     * comparsion later {@see done}. For a comparator from extensions
 | 
						|
     * dependency information is looked up as well.
 | 
						|
     * @param string $comparator
 | 
						|
     */
 | 
						|
    protected function comparatorHook_($comparator)
 | 
						|
    {
 | 
						|
        $this->comparator_ = $comparator;
 | 
						|
        $xml = $this->registry_->comparator($this->comparator_);
 | 
						|
 | 
						|
        if (isset($xml))
 | 
						|
        {
 | 
						|
            // Add possible dependancy
 | 
						|
            $this->addDependency_('comparator', $this->comparator_, $xml->requires);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Hook function that is called after a tag was found in
 | 
						|
     * a command. The tag is remembered in case it's needed for
 | 
						|
     * comparsion later {@see done}. For a tags from extensions
 | 
						|
     * dependency information is looked up as well.
 | 
						|
     * @param string $tag
 | 
						|
     */
 | 
						|
    protected function tagHook_($tag)
 | 
						|
    {
 | 
						|
        array_push($this->tags_, $tag);
 | 
						|
        $xml = $this->registry_->argument($tag);
 | 
						|
 | 
						|
        // Add possible dependancies
 | 
						|
        if (isset($xml))
 | 
						|
            $this->addDependency_('tag', $tag, $xml->requires);
 | 
						|
    }
 | 
						|
 | 
						|
    protected function validType_($token)
 | 
						|
    {
 | 
						|
        foreach ($this->arguments_ as $arg)
 | 
						|
        {
 | 
						|
            if ($arg['occurrence'] == '0')
 | 
						|
            {
 | 
						|
                array_shift($this->arguments_);
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            if ($token->is($arg['type']))
 | 
						|
                return;
 | 
						|
 | 
						|
            // Is the argument required
 | 
						|
            if ($arg['occurrence'] != '?' && $arg['occurrence'] != '*')
 | 
						|
                throw new SieveException($token, $arg['type']);
 | 
						|
 | 
						|
            array_shift($this->arguments_);
 | 
						|
        }
 | 
						|
 | 
						|
        // Check if command expects any (more) arguments
 | 
						|
        if (empty($this->arguments_))
 | 
						|
            throw new SieveException($token, $this->followupToken_);
 | 
						|
 | 
						|
        throw new SieveException($token, 'unexpected '. SieveToken::typeString($token->type) .' '. $token->text);
 | 
						|
    }
 | 
						|
 | 
						|
    public function startStringList($token)
 | 
						|
    {
 | 
						|
        $this->validType_($token);
 | 
						|
        $this->arguments_[0]['type'] = SieveToken::String;
 | 
						|
        $this->arguments_[0]['occurrence'] = '+';
 | 
						|
    }
 | 
						|
 | 
						|
    public function continueStringList()
 | 
						|
    {
 | 
						|
        $this->arguments_[0]['occurrence'] = '+';
 | 
						|
    }
 | 
						|
 | 
						|
    public function endStringList()
 | 
						|
    {
 | 
						|
        array_shift($this->arguments_);
 | 
						|
    }
 | 
						|
 | 
						|
    public function validateToken($token)
 | 
						|
    {
 | 
						|
        // Make sure the argument has a valid type
 | 
						|
        $this->validType_($token);
 | 
						|
 | 
						|
        foreach ($this->arguments_ as &$arg)
 | 
						|
        {
 | 
						|
            // Build regular expression according to argument type
 | 
						|
            switch ($arg['type'])
 | 
						|
            {
 | 
						|
            case SieveToken::String:
 | 
						|
            case SieveToken::StringList:
 | 
						|
                $regex = '/^(?:text:[^\n]*\n(?P<one>'. $arg['regex'] .')\.\r?\n?|"(?P<two>'. $arg['regex'] .')")$/'
 | 
						|
                       . ($arg['case'] == 'ignore' ? 'si' : 's');
 | 
						|
                break;
 | 
						|
            case SieveToken::Tag:
 | 
						|
                $regex = '/^:(?P<one>'. $arg['regex'] .')$/si';
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                $regex = '/^(?P<one>'. $arg['regex'] .')$/si';
 | 
						|
            }
 | 
						|
 | 
						|
            if (preg_match($regex, $token->text, $match))
 | 
						|
            {
 | 
						|
                $text = ($match['one'] ? $match['one'] : $match['two']);
 | 
						|
 | 
						|
                // Add argument(s) that may now appear after this one
 | 
						|
                if (isset($arg['subArgs']))
 | 
						|
                    $this->addArguments_($text, $arg['subArgs']);
 | 
						|
 | 
						|
                // Call extra processing function if defined
 | 
						|
                if (isset($arg['call']))
 | 
						|
                    $this->invoke_($token, $arg['call'], $text);
 | 
						|
 | 
						|
                // Check if a possible value of this argument may occur
 | 
						|
                if ($arg['occurrence'] == '?' || $arg['occurrence'] == '1')
 | 
						|
                {
 | 
						|
                    $arg['occurrence'] = '0';
 | 
						|
                }
 | 
						|
                else if ($arg['occurrence'] == '+')
 | 
						|
                {
 | 
						|
                    $arg['occurrence'] = '*';
 | 
						|
                }
 | 
						|
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            if ($token->is($arg['type']) && $arg['occurrence'] == 1)
 | 
						|
            {
 | 
						|
                throw new SieveException($token,
 | 
						|
                    SieveToken::typeString($token->type) ." $token->text where ". $arg['name'] .' expected');
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        throw new SieveException($token, 'unexpected '. SieveToken::typeString($token->type) .' '. $token->text);
 | 
						|
    }
 | 
						|
 | 
						|
    public function done($token)
 | 
						|
    {
 | 
						|
        // Check if there are required arguments left
 | 
						|
        foreach ($this->arguments_ as $arg)
 | 
						|
        {
 | 
						|
            if ($arg['occurrence'] == '+' || $arg['occurrence'] == '1')
 | 
						|
                throw new SieveException($token, $arg['type']);
 | 
						|
        }
 | 
						|
 | 
						|
        // Check if the command depends on use of a certain tag
 | 
						|
        foreach ($this->deps_ as $d)
 | 
						|
        {
 | 
						|
            switch ($d['type'])
 | 
						|
            {
 | 
						|
            case 'addresspart':
 | 
						|
                $values = array($this->addressPart_);
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'matchtype':
 | 
						|
                $values = array($this->matchType_);
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'comparator':
 | 
						|
                $values = array($this->comparator_);
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'tag':
 | 
						|
                $values = $this->tags_;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
 | 
						|
            foreach ($values as $value)
 | 
						|
            {
 | 
						|
                if (preg_match('/^'. $d['regex'] .'$/mi', $value))
 | 
						|
                    break 2;
 | 
						|
            }
 | 
						|
 | 
						|
            throw new SieveException($token,
 | 
						|
                $d['o_type'] .' '. $d['o_name'] .' requires use of '. $d['type'] .' '. $d['name']);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |