[Python-modules-commits] [python-sievelib] 01/02: Imported Upstream version 0.8+git20150929.71f2dee

Michael Fladischer fladi at moszumanska.debian.org
Tue Sep 29 10:44:24 UTC 2015


This is an automated email from the git hooks/post-receive script.

fladi pushed a commit to branch master
in repository python-sievelib.

commit e2c299abedf441438fc41aaabe0b658b45476ae4
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date:   Tue Sep 29 12:18:23 2015 +0200

    Imported Upstream version 0.8+git20150929.71f2dee
---
 .travis.yml                         |  10 +
 COPYING                             |  13 +
 MANIFEST.in                         |   2 +
 README.rst                          | 154 ++++++++
 requirements.txt                    |   1 +
 setup.py                            |  76 ++++
 sievelib/__init__.py                |   0
 sievelib/commands.py                | 736 ++++++++++++++++++++++++++++++++++++
 sievelib/digest_md5.py              |  77 ++++
 sievelib/factory.py                 | 390 +++++++++++++++++++
 sievelib/managesieve.py             | 683 +++++++++++++++++++++++++++++++++
 sievelib/parser.py                  | 455 ++++++++++++++++++++++
 sievelib/tests/__init__.py          |   0
 sievelib/tests/files/utf8_sieve.txt |   7 +
 sievelib/tests/test_factory.py      | 129 +++++++
 sievelib/tests/test_parser.py       | 691 +++++++++++++++++++++++++++++++++
 16 files changed, 3424 insertions(+)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..8f5e8ca
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,10 @@
+language: python
+python:
+  - "2.7"
+  - "3.4"
+
+install:
+  - pip install nose --use-mirrors
+  - python setup.py -q install
+
+script: nosetests
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..0027393
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,13 @@
+Copyright (c) 2011-2013, Antoine Nguyen <tonio at ngyn.org>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..9491f80
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,2 @@
+include README.rst
+include COPYING
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..431c0c5
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,154 @@
+sievelib
+========
+
+|travis| |latest-version| |downloads|
+
+Client-side Sieve and Managesieve library written in Python.
+
+* Sieve : An Email Filtering Language
+  (`RFC 5228 <http://tools.ietf.org/html/rfc5228>`_)
+* ManageSieve : A Protocol for Remotely Managing Sieve Scripts
+  (`RFC 5804 <http://tools.ietf.org/html/rfc5804>`_)
+
+Installation
+------------
+
+To install ``sievelib`` from PyPI::
+
+  pip install sievelib
+
+To install sievelib from git::
+
+  git clone git at github.com:tonioo/sievelib.git
+  cd sievelib
+  python ./setup.py install
+
+Sieve tools
+-----------
+
+What is supported
+^^^^^^^^^^^^^^^^^
+
+Currently, the provided parser supports most of the functionalities
+described in the RFC. The only exception concerns section
+*2.4.2.4. Encoding Characters Using "encoded-character"* which is not
+supported.
+
+The following extensions are also supported:
+
+* Date and Index (`RFC 5260 <https://tools.ietf.org/html/rfc5260>`_)
+* Vacation (`RFC 5230 <http://tools.ietf.org/html/rfc5230>`_)
+
+Extending the parser
+^^^^^^^^^^^^^^^^^^^^
+
+It is possible to extend the parser by adding new supported
+commands. For example::
+
+  import sievelib
+
+  def MyCommand(sievelib.commands.ActionCommand):
+      args_definition = [
+          {"name": "testtag",
+              "type": ["tag"],
+              "write_tag": True,
+              "values": [":testtag"],
+              "extra_arg": {"type": "number",
+                            "required": False},
+              "required": False},
+          {"name": "recipients",
+              "type": ["string", "stringlist"],
+              "required": True}
+      ]
+
+  sievelib.commands.add_commands(MyCommand)
+
+Basic usage
+^^^^^^^^^^^
+
+The parser can either be used from the command-line::
+
+  $ cd sievelib
+  $ python parser.py test.sieve
+  Syntax OK
+  $
+
+Or can be used from a python environment (or script/module)::
+
+  >>> from sievelib.parser import Parser
+  >>> p = Parser()
+  >>> p.parse('require ["fileinto"];')
+  True
+  >>> p.dump()
+  require (type: control)
+      ["fileinto"]
+  >>> 
+  >>> p.parse('require ["fileinto"]')
+  False
+  >>> p.error
+  'line 1: parsing error: end of script reached while semicolon expected'
+  >>>
+
+Simple filters creation
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Some high-level classes are provided with the ``factory`` module, they
+make the generation of Sieve rules easier::
+
+  >>> from sievelib.factory import FiltersSet
+  >>> fs = FiltersSet("test")
+  >>> fs.addfilter("rule1",
+  ...              [("Sender", ":is", "toto at toto.com"),],
+  ...              [("fileinto", "Toto"),])
+  >>> fs.tosieve()
+  require ["fileinto"];
+  
+  # Filter: rule1
+  if anyof (header :is "Sender" "toto at toto.com") {
+      fileinto "Toto";
+  }
+  >>> 
+
+Additional documentation is available within source code.
+
+ManageSieve tools
+-----------------
+
+What is supported
+^^^^^^^^^^^^^^^^^
+
+All mandatory commands are supported. The ``RENAME`` extension is
+supported, with a simulated behaviour for server that do not support
+it.
+
+For the ``AUTHENTICATE`` command, supported mechanisms are ``DIGEST-MD5``,
+``PLAIN`` and ``LOGIN``.
+    
+Basic usage
+^^^^^^^^^^^
+
+The ManageSieve client is intended to be used from another python
+application (there isn't any shell provided)::
+
+  >>> from sievelib.managesieve import Client
+  >>> c = Client("server.example.com")
+  >>> c.connect("user", "password", starttls=False, authmech="DIGEST-MD5")
+  True
+  >>> c.listscripts()
+  ("active_script", ["script1", "script2"])
+  >>> c.setactive("script1")
+  True
+  >>> c.havespace("script3", 45)
+  True
+  >>>
+
+Additional documentation is available with source code.
+
+.. |latest-version| image:: https://pypip.in/v/sievelib/badge.png
+   :alt: Latest version on Pypi
+   :target: https://crate.io/packages/sievelib/
+.. |downloads| image:: https://pypip.in/d/sievelib/badge.png
+   :alt: Downloads from Pypi
+   :target: https://crate.io/packages/sievelib/
+.. |travis| image:: https://travis-ci.org/tonioo/sievelib.png?branch=master
+   :target: https://travis-ci.org/tonioo/sievelib
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..ffe2fce
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+six
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..8171994
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,76 @@
+# coding=utf-8
+import os
+import re
+from setuptools import setup, find_packages
+
+ROOT = os.path.dirname(__file__)
+PIP_REQUIRES = os.path.join(ROOT, "requirements.txt")
+
+
+def parse_requirements(*filenames):
+    """
+    We generate our install_requires from the pip-requires and test-requires
+    files so that we don't have to maintain the dependency definitions in
+    two places.
+    """
+    requirements = []
+    for f in filenames:
+        for line in open(f, 'r').read().split('\n'):
+            # Comment lines. Skip.
+            if re.match(r'(\s*#)|(\s*$)', line):
+                continue
+            # Editable matches. Put the egg name into our reqs list.
+            if re.match(r'\s*-e\s+', line):
+                pkg = re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1', line)
+                requirements.append("%s" % pkg)
+            # File-based installs not supported/needed. Skip.
+            elif re.match(r'\s*-f\s+', line):
+                pass
+            else:
+                requirements.append(line)
+    return requirements
+
+
+def parse_dependency_links(*filenames):
+    """
+    We generate our dependency_links from the pip-requires and test-requires
+    files for the dependencies pulled from github (prepended with -e).
+    """
+    dependency_links = []
+    for f in filenames:
+        for line in open(f, 'r').read().split('\n'):
+            if re.match(r'\s*-[ef]\s+', line):
+                line = re.sub(r'\s*-[ef]\s+', '', line)
+                line = re.sub(r'\s*git\+https', 'http', line)
+                line = re.sub(r'\.git#', '/tarball/master#', line)
+                dependency_links.append(line)
+    return dependency_links
+
+
+def read(fname):
+    return open(os.path.join(ROOT, fname)).read()
+
+setup(
+    name="sievelib",
+    packages=find_packages(),
+    include_package_data=True,
+    version="0.8",
+    description="Client-side SIEVE library",
+    author="Antoine Nguyen",
+    author_email="tonio at ngyn.org",
+    url="https://github.com/tonioo/sievelib",
+    license="MIT",
+    keywords=["sieve", "managesieve", "parser", "client"],
+    install_requires=parse_requirements(PIP_REQUIRES),
+    dependency_links=parse_dependency_links(PIP_REQUIRES),
+    classifiers=[
+        "Programming Language :: Python",
+        "Development Status :: 4 - Beta",
+        "Intended Audience :: Developers",
+        "License :: OSI Approved :: MIT License",
+        "Operating System :: OS Independent",
+        "Topic :: Software Development :: Libraries :: Python Modules",
+        "Topic :: Communications :: Email :: Filters"
+    ],
+    long_description=read("README.rst")
+)
diff --git a/sievelib/__init__.py b/sievelib/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sievelib/commands.py b/sievelib/commands.py
new file mode 100644
index 0000000..5a27f05
--- /dev/null
+++ b/sievelib/commands.py
@@ -0,0 +1,736 @@
+# coding: utf-8
+
+"""
+SIEVE commands representation
+
+This module contains classes that represent known commands. They all
+inherit from the Command class which provides generic method for
+command manipulation or parsing.
+
+There are three command types (each one represented by a class):
+ * control (ControlCommand) : Control structures are needed to allow
+   for multiple and conditional actions
+ * action (ActionCommand) : Actions that can be applied on emails
+ * test (TestCommand) : Tests are used in conditionals to decide which
+   part(s) of the conditional to execute
+
+Finally, each known command is represented by its own class which
+provides extra information such as:
+ * expected arguments,
+ * completion callback,
+ * etc.
+
+"""
+from __future__ import unicode_literals
+
+import sys
+from collections import Iterable
+
+
+class UnknownCommand(Exception):
+    """Specific exception raised when an unknown command is encountered"""
+
+    def __init__(self, name):
+        self.name = name
+
+    def __str__(self):
+        return "unknown command %s" % self.name
+
+
+class BadArgument(Exception):
+    """Specific exception raised when a bad argument is encountered"""
+
+    def __init__(self, command, seen, expected):
+        self.command = command
+        self.seen = seen
+        self.expected = expected
+
+    def __str__(self):
+        return "bad argument %s for command %s (%s expected)" \
+               % (self.seen, self.command, self.expected)
+
+
+class BadValue(Exception):
+    """Specific exception raised when a bad argument value is encountered"""
+
+    def __init__(self, argument, value):
+        self.argument = argument
+        self.value = value
+
+    def __str__(self):
+        return "bad value %s for argument %s" \
+               % (self.value, self.argument)
+
+
+# Statement elements (see RFC, section 8.3)
+# They are used in different commands.
+comparator = {"name": "comparator",
+              "type": ["tag"],
+              "values": [":comparator"],
+              "extra_arg": {"type": "string",
+                            "values": ['"i;octet"', '"i;ascii-casemap"']},
+              "required": False}
+address_part = {"name": "address-part",
+                "values": [":localpart", ":domain", ":all"],
+                "type": ["tag"],
+                "required": False}
+match_type = {"name": "match-type",
+              "values": [":is", ":contains", ":matches"],
+              "type": ["tag"],
+              "required": False}
+
+
+class Command(object):
+    """Generic command representation.
+
+    A command is described as follow:
+     * A name
+     * A type
+     * A description of supported arguments
+     * Does it accept an unknown quantity of arguments? (ex: anyof, allof)
+     * Does it accept children? (ie. subcommands)
+     * Is it an extension?
+     * Must follow only certain commands
+
+    """
+    _type = None
+    variable_args_nb = False
+    accept_children = False
+    must_follow = None
+    is_extension = False
+
+    def __init__(self, parent=None):
+        self.parent = parent
+        self.arguments = {}
+        self.children = []
+
+        self.nextargpos = 0
+        self.required_args = -1
+        self.rargs_cnt = 0
+        self.curarg = None  # for arguments that expect an argument :p (ex: :comparator)
+
+        self.name = self.__class__.__name__.replace("Command", "")
+        self.name = self.name.lower()
+
+        self.hash_comments = []
+
+    def __repr__(self):
+        return "%s (type: %s)" % (self.name, self._type)
+
+    def tosieve(self, indentlevel=0, target=sys.stdout):
+        """Generate the sieve syntax corresponding to this command
+
+        Recursive method.
+
+        :param indentlevel: current indentation level
+        :param target: opened file pointer where the content will be printed
+        """
+        self.__print(self.name, indentlevel, nocr=True, target=target)
+        if self.has_arguments():
+            for arg in self.args_definition:
+                if not arg["name"] in self.arguments:
+                    continue
+                target.write(" ")
+                value = self.arguments[arg["name"]]
+
+                if "tag" in arg["type"] and arg.get("write_tag", False):
+                    target.write("%s " % arg["values"][0])
+
+                if type(value) == list:
+                    if self.__get_arg_type(arg["name"]) == ["testlist"]:
+                        target.write("(")
+                        for t in value:
+                            t.tosieve(target=target)
+                            if value.index(t) != len(value) - 1:
+                                target.write(", ")
+                        target.write(")")
+                    else:
+                        target.write("[" + ((", ".join(['"%s"' % v.strip('"') for v in value]))) + "]")
+                    continue
+                if isinstance(value, Command):
+                    value.tosieve(indentlevel, target=target)
+                    continue
+
+                if "string" in arg["type"]:
+                    target.write(value)
+                    if not value.startswith('"'):
+                        target.write("\n")
+                else:
+                    target.write(value)
+
+        if not self.accept_children:
+            if self.get_type() != "test":
+                target.write(";\n")
+            return
+        if self.get_type() != "control":
+            return
+        target.write(" {\n")
+        for ch in self.children:
+            ch.tosieve(indentlevel + 4, target=target)
+        self.__print("}", indentlevel, target=target)
+
+    def __print(self, data, indentlevel, nocr=False, target=sys.stdout):
+        text = "%s%s" % (" " * indentlevel, data)
+        if nocr:
+            target.write(text)
+        else:
+            target.write(text + "\n")
+
+    def __get_arg_type(self, arg):
+        """Return the type corresponding to the given name.
+
+        :param arg: a defined argument name
+        """
+        for a in self.args_definition:
+            if a["name"] == arg:
+                return a["type"]
+        return None
+
+    def complete_cb(self):
+        """Completion callback
+
+        Called when a command is considered as complete by the parser.
+        """
+        pass
+
+    def get_expected_first(self):
+        """Return the first expected token for this command"""
+        return None
+
+    def has_arguments(self):
+        return len(self.args_definition) != 0
+
+    def dump(self, indentlevel=0, target=sys.stdout):
+        """Display the command
+
+        Pretty printing of this command and its eventual arguments and
+        children. (recursively)
+
+        :param indentlevel: integer that indicates indentation level to apply
+        """
+        self.__print(self, indentlevel, target=target)
+        indentlevel += 4
+        if self.has_arguments():
+            for arg in self.args_definition:
+                if not arg["name"] in self.arguments:
+                    continue
+                value = self.arguments[arg["name"]]
+                if type(value) == list:
+                    if self.__get_arg_type(arg["name"]) == ["testlist"]:
+                        for t in value:
+                            t.dump(indentlevel, target)
+                    else:
+                        self.__print("[" + (",".join(value)) + "]", indentlevel, target=target)
+                    continue
+                if isinstance(value, Command):
+                    value.dump(indentlevel, target)
+                    continue
+                self.__print(str(value), indentlevel, target=target)
+        for ch in self.children:
+            ch.dump(indentlevel, target)
+
+    def addchild(self, child):
+        """Add a new child to the command
+
+        A child corresponds to a command located into a block (this
+        command's block). It can be either an action or a control.
+
+        :param child: the new child
+        :return: True on succes, False otherwise
+        """
+        if not self.accept_children:
+            return False
+        self.children += [child]
+        return True
+
+    def iscomplete(self):
+        """Check if the command is complete
+
+        Check if all required arguments have been encountered. For
+        commands that allow an undefined number of arguments, this
+        method always returns False.
+
+        :return: True if command is complete, False otherwise
+        """
+        if self.variable_args_nb:
+            return False
+        if self.required_args == -1:
+            self.required_args = 0
+            for arg in self.args_definition:
+                if arg["required"]:
+                    self.required_args += 1
+        return (not self.curarg or not "extra_arg" in self.curarg) \
+            and (self.rargs_cnt == self.required_args)
+
+    def get_type(self):
+        """Return the command's type"""
+        if self._type is None:
+            raise NotImplementedError
+        return self._type
+
+    def __is_valid_value_for_arg(self, arg, value):
+        """Check if value is allowed for arg
+
+        Some commands only allow a limited set of values. The method
+        always returns True for methods that do not provide such a
+        set.
+
+        :param arg: the argument's name
+        :param value: the value to check
+        :return: True on succes, False otherwise
+        """
+        if not "values" in arg:
+            return True
+        return value.lower() in arg["values"]
+
+    def check_next_arg(self, atype, avalue, add=True):
+        """Argument validity checking
+
+        This method is usually used by the parser to check if detected
+        argument is allowed for this command.
+
+        We make a distinction between required and optional
+        arguments. Optional (or tagged) arguments can be provided
+        unordered but not the required ones.
+
+        A special handling is also done for arguments that require an
+        argument (example: the :comparator argument expects a string
+        argument).
+
+        The "testlist" type is checked separately as we can't know in
+        advance how many arguments will be provided.
+
+        If the argument is incorrect, the method raises the
+        appropriate exception, or return False to let the parser
+        handle the exception.
+
+        :param atype: the argument's type
+        :param avalue: the argument's value
+        :param add: indicates if this argument should be recorded on success
+        :return: True on success, False otherwise
+        """
+        if not self.has_arguments():
+            return False
+        if self.iscomplete():
+            return False
+
+        if self.curarg is not None and "extra_arg" in self.curarg:
+            if atype == self.curarg["extra_arg"]["type"]:
+                if not "values" in self.curarg["extra_arg"] \
+                   or avalue in self.curarg["extra_arg"]["values"]:
+                    if add:
+                        self.arguments[self.curarg["name"]] = avalue
+                    self.curarg = None
+                    return True
+            raise BadValue(self.curarg["name"], avalue)
+
+        failed = False
+        pos = self.nextargpos
+        while pos < len(self.args_definition):
+            curarg = self.args_definition[pos]
+            if curarg["required"]:
+                if curarg["type"] == ["testlist"]:
+                    if atype != "test":
+                        failed = True
+                    elif add:
+                        if not curarg["name"] in self.arguments:
+                            self.arguments[curarg["name"]] = []
+                        self.arguments[curarg["name"]] += [avalue]
+                elif atype not in curarg["type"] or \
+                        not self.__is_valid_value_for_arg(curarg, avalue):
+                    failed = True
+                else:
+                    self.curarg = curarg
+                    self.rargs_cnt += 1
+                    self.nextargpos = pos + 1
+                    if add:
+                        self.arguments[curarg["name"]] = avalue
+                break
+
+            if atype in curarg["type"]:
+                if self.__is_valid_value_for_arg(curarg, avalue):
+                    if "extra_arg" in curarg:
+                        self.curarg = curarg
+                        break
+                    if add:
+                        self.arguments[curarg["name"]] = avalue
+                    break
+
+            pos += 1
+
+        if failed:
+            raise BadArgument(self.name, avalue,
+                              self.args_definition[pos]["type"])
+        return True
+
+    def __getitem__(self, name):
+        """Shorcut to access a command argument
+
+        :param name: the argument's name
+        """
+        found = False
+        for ad in self.args_definition:
+            if ad["name"] == name:
+                found = True
+                break
+        if not found:
+            raise KeyError(name)
+        if not name in self.arguments:
+            raise KeyError(name)
+        return self.arguments[name]
+
+
+class ControlCommand(Command):
+    """Indermediate class to represent "control" commands"""
+    _type = "control"
+
+
+class RequireCommand(ControlCommand):
+    """The 'require' command
+
+    This class has one big difference with others as it is used to
+    store loaded extension names. (The result is we can check for
+    unloaded extensions during the parsing)
+    """
+    args_definition = [
+        {"name": "capabilities",
+         "type": ["string", "stringlist"],
+         "required": True}
+    ]
+
+    loaded_extensions = []
+
+    def complete_cb(self):
+        if type(self.arguments["capabilities"]) == str:
+            exts = [self.arguments["capabilities"]]
+        else:
+            exts = self.arguments["capabilities"]
+        for ext in exts:
+            ext = ext.strip('"')
+            if not ext in RequireCommand.loaded_extensions:
+                RequireCommand.loaded_extensions += [ext]
+
+
+class StopCommand(ControlCommand):
+    args_definition = []
+
+
+class IfCommand(ControlCommand):
+    accept_children = True
+
+    args_definition = [
+        {"name": "test",
+         "type": ["test"],
+         "required": True}
+    ]
+
+    def get_expected_first(self):
+        return ["identifier"]
+
+
+class ElsifCommand(ControlCommand):
+    accept_children = True
+    must_follow = ["if", "elsif"]
+    args_definition = [
+        {"name": "test",
+         "type": ["test"],
+         "required": True}
+    ]
+
+    def get_expected_first(self):
+        return ["identifier"]
+
+
+class ElseCommand(ControlCommand):
+    accept_children = True
+    must_follow = ["if", "elsif"]
+    args_definition = []
+
+
+class ActionCommand(Command):
+    """Indermediate class to represent "action" commands"""
+    _type = "action"
+
+
+class FileintoCommand(ActionCommand):
+    is_extension = True
+    args_definition = [
+        {"name": "mailbox",
+         "type": ["string"],
+         "required": True}
+    ]
+
+
+class RedirectCommand(ActionCommand):
+    args_definition = [
+        {"name": "address",
+         "type": ["string"],
+         "required": True}
+    ]
+
+
+class RejectCommand(ActionCommand):
+    is_extension = True
+    args_definition = [
+        {"name": "text",
+         "type": ["string"],
+         "required": True}
+    ]
+
+
+class KeepCommand(ActionCommand):
+    args_definition = []
+
+
+class DiscardCommand(ActionCommand):
+    args_definition = []
+
+
+class TestCommand(Command):
+    """Indermediate class to represent "test" commands"""
+    _type = "test"
+
+
+class AddressCommand(TestCommand):
+    args_definition = [
+        comparator,
+        address_part,
+        match_type,
+        {"name": "header-list",
+         "type": ["string", "stringlist"],
+         "required": True},
+        {"name": "key-list",
+         "type": ["string", "stringlist"],
+         "required": True}
+    ]
+
+
+class AllofCommand(TestCommand):
+    accept_children = True
+    variable_args_nb = True
+
+    args_definition = [
+        {"name": "tests",
+         "type": ["testlist"],
+         "required": True}
+    ]
+
+    def get_expected_first(self):
+        return ["left_parenthesis"]
+
+
+class AnyofCommand(TestCommand):
+    accept_children = True
+    variable_args_nb = True
+
+    args_definition = [
+        {"name": "tests",
+         "type": ["testlist"],
+         "required": True}
+    ]
+
+    def get_expected_first(self):
+        return ["left_parenthesis"]
+
+
+class EnvelopeCommand(TestCommand):
+    args_definition = [
+        comparator,
+        address_part,
+        match_type,
+        {"name": "header-list",
+         "type": ["string", "stringlist"],
+         "required": True},
+        {"name": "key-list",
+         "type": ["string", "stringlist"],
+         "required": True}
+    ]
+
+
+class ExistsCommand(TestCommand):
+    args_definition = [
+        {"name": "header-names",
+         "type": ["stringlist"],
+         "required": True}
+    ]
+
+
+class TrueCommand(TestCommand):
+    args_definition = []
+
+
+class FalseCommand(TestCommand):
+    args_definition = []
+
+
+class HeaderCommand(TestCommand):
+    args_definition = [
+        comparator,
+        match_type,
+        {"name": "header-names",
+         "type": ["string", "stringlist"],
+         "required": True},
+        {"name": "key-list",
+         "type": ["string", "stringlist"],
+         "required": True}
+    ]
+
+
+class NotCommand(TestCommand):
+    accept_children = True
+
+    args_definition = [
+        {"name": "test",
+         "type": ["test"],
+         "required": True}
+    ]
+
+    def get_expected_first(self):
+        return ["identifier"]
+
+
+class SizeCommand(TestCommand):
+    args_definition = [
+        {"name": "comparator",
+         "type": ["tag"],
+         "values": [":over", ":under"],
+         "required": True},
+        {"name": "limit",
+         "type": ["number"],
+         "required": True},
+    ]
+
+
+class VacationCommand(ActionCommand):
+    args_definition = [
+        {"name": "subject",
+         "type": ["tag"],
+         "write_tag": True,
+         "values": [":subject"],
+         "extra_arg": {"type": "string"},
+         "required": False},
+        {"name": "days",
+         "type": ["tag"],
+         "write_tag": True,
+         "values": [":days"],
+         "extra_arg": {"type": "number"},
+         "required": False},
+        {"name": "from",
+         "type": ["tag"],
+         "write_tag": True,
+         "values": [":from"],
+         "extra_arg": {"type": "string"},
+         "required": False},
+        {"name": "addresses",
+         "type": ["tag"],
+         "write_tag": True,
+         "values": [":addresses"],
+         "extra_arg": {"type": "stringlist"},
+         "required": False},
+        {"name": "handle",
+         "type": ["tag"],
+         "write_tag": True,
+         "values": [":handle"],
+         "extra_arg": {"type": "string"},
+         "required": False},
+        {"name": "mime",
+         "type": ["tag"],
+         "write_tag": True,
+         "values": [":mime"],
+         "required": False},
+        {"name": "reason",
+         "type": ["string"],
+         "required": True},
+    ]
+
+class SetCommand(ControlCommand):
+    """currentdate command, part of the variables extension
+
+    http://tools.ietf.org/html/rfc5229
+    """
+    is_extension = True
+    args_definition = [
+            {"name": "startend", 
+             "type": ["string"], 
+             "required": True},
+            {"name": "date",
+             "type": ["string"],
+             "required": True}
+    ]
+    
+class CurrentdateCommand(ControlCommand):
+    """currentdate command, part of the date extension
+
+    http://tools.ietf.org/html/rfc5260#section-5
+    """
+    is_extension = True
+    accept_children = True
+    args_definition = [
+            {"name": "zone",
+             "type": ["tag"],
+             "write_tag": True,
+             "values": [":zone"],
+             "extra_arg": {"type": "string"},
+             "required": False},
+            {"name": "match-value",
... 2538 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-sievelib.git



More information about the Python-modules-commits mailing list