1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
# Copyright (C) 2008 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
"""Base class for terminal chains."""
__all__ = [
'Chain',
'Link',
'TerminalChainBase',
]
__metaclass__ = type
from zope.interface import implements
from Mailman.configuration import config
from Mailman.interfaces import (
IChain, IChainIterator, IChainLink, IMutableChain, LinkAction)
class Link:
"""A chain link."""
implements(IChainLink)
def __init__(self, rule, action=None, chain=None, function=None):
self.rule = rule
self.action = (LinkAction.defer if action is None else action)
self.chain = chain
self.function = function
class TerminalChainBase:
"""A base chain that always matches and executes a method.
The method is called 'process' and must be provided by the subclass.
"""
implements(IChain, IChainIterator)
def _process(self, mlist, msg, msgdata):
"""Process the message for the given mailing list.
This must be overridden by subclasses.
"""
raise NotImplementedError
def get_rule(self, name):
"""See `IChain`.
This always returns the globally registered named rule.
"""
return config.rules[name]
def get_links(self, mlist, msg, msgdata):
"""See `IChain`."""
return iter(self)
def __iter__(self):
"""See `IChainIterator`."""
# First, yield a link that always runs the process method.
yield Link('truth', LinkAction.run, function=self._process)
# Now yield a rule that stops all processing.
yield Link('truth', LinkAction.stop)
class Chain:
"""Generic chain base class."""
implements(IMutableChain)
def __init__(self, name, description):
assert name not in config.chains, 'Duplicate chain name: %s' % name
self.name = name
self.description = description
self._links = []
# Register the chain.
config.chains[name] = self
def append_link(self, link):
"""See `IMutableChain`."""
self._links.append(link)
def flush(self):
"""See `IMutableChain`."""
self._links = []
def get_rule(self, name):
"""See `IChain`.
This always returns the globally registered named rule.
"""
return config.rules[name]
def get_links(self, mlist, msg, msgdata):
"""See `IChain`."""
return iter(ChainIterator(self))
def get_iterator(self):
"""Return an iterator over the links."""
# We do it this way in order to preserve a separation of interfaces,
# and allows .get_links() to be overridden.
for link in self._links:
yield link
class ChainIterator:
"""Generic chain iterator."""
implements(IChainIterator)
def __init__(self, chain):
self._chain = chain
def __iter__(self):
"""See `IChainIterator`."""
return self._chain.get_iterator()
|