1 package org.apache.jsieve;
2
3 import java.util.ArrayList;
4 import java.util.HashSet;
5 import java.util.List;
6 import java.util.Set;
7
8 import org.apache.jsieve.exception.LookupException;
9 import org.apache.jsieve.exception.SieveException;
10 import org.apache.jsieve.parser.generated.ASTargument;
11 import org.apache.jsieve.parser.generated.ASTarguments;
12 import org.apache.jsieve.parser.generated.ASTblock;
13 import org.apache.jsieve.parser.generated.ASTcommand;
14 import org.apache.jsieve.parser.generated.ASTcommands;
15 import org.apache.jsieve.parser.generated.ASTstart;
16 import org.apache.jsieve.parser.generated.ASTstring;
17 import org.apache.jsieve.parser.generated.ASTstring_list;
18 import org.apache.jsieve.parser.generated.ASTtest;
19 import org.apache.jsieve.parser.generated.ASTtest_list;
20 import org.apache.jsieve.parser.generated.SieveParserVisitor;
21 import org.apache.jsieve.parser.generated.SimpleNode;
22
23 import static org.apache.jsieve.Constants.*;
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 public class SieveValidationVisitor implements SieveParserVisitor {
49
50 private final CommandManager commandManager;
51 private final TestManager testManager;
52 private final ComparatorManager comparatorManager;
53
54 private final Set<String> declaredComparators;
55
56 private boolean requireAllowed = true;
57
58 private boolean isInRequire = false;
59
60 private boolean nextArgumentIsComparatorName = false;
61
62 private boolean isInComparatorNameArgument = false;
63
64 protected SieveValidationVisitor(final CommandManager commandManager,
65 final TestManager testManager, final ComparatorManager comparatorManager) {
66 super();
67 this.commandManager = commandManager;
68 this.testManager = testManager;
69 this.comparatorManager = comparatorManager;
70 declaredComparators = new HashSet<String>();
71 }
72
73 public Object visit(SimpleNode node, Object data) throws SieveException {
74 return visitNode(node, data);
75 }
76
77 private Object visitNode(SimpleNode node, Object data)
78 throws SieveException {
79 List children = new ArrayList(node.jjtGetNumChildren());
80 node.childrenAccept(this, children);
81 return data;
82 }
83
84 public Object visit(ASTstart node, Object data) throws SieveException {
85 return visitNode(node, data);
86 }
87
88 public Object visit(ASTcommands node, Object data) throws SieveException {
89 declaredComparators.clear();
90 return visitNode(node, data);
91 }
92
93 public Object visit(ASTcommand node, Object data) throws SieveException {
94 final String name = node.getName();
95 commandManager.getCommand(name);
96 if ("require".equalsIgnoreCase(name)) {
97 if (requireAllowed) {
98 isInRequire = true;
99 } else {
100 throw new SieveException(
101 "'require' is only allowed before other commands");
102 }
103 } else {
104 requireAllowed = false;
105 isInRequire = false;
106 }
107 return visitNode(node, data);
108 }
109
110 public Object visit(ASTblock node, Object data) throws SieveException {
111 return visitNode(node, data);
112 }
113
114 public Object visit(ASTarguments node, Object data) throws SieveException {
115
116 nextArgumentIsComparatorName = false;
117 return visitNode(node, data);
118 }
119
120 public Object visit(ASTargument node, Object data) throws SieveException {
121 final Object value = node.getValue();
122 if (value == null) {
123 if (nextArgumentIsComparatorName) {
124
125 isInComparatorNameArgument = true;
126 }
127 nextArgumentIsComparatorName = false;
128 } else {
129 if (value instanceof TagArgument) {
130 final TagArgument tag = (TagArgument) value;
131 nextArgumentIsComparatorName = tag.isComparator();
132 } else {
133 nextArgumentIsComparatorName = false;
134 }
135 }
136 final Object result = visitNode(node, data);
137 isInComparatorNameArgument = false;
138 return result;
139 }
140
141 public Object visit(ASTtest node, Object data) throws SieveException {
142 return visitNode(node, data);
143 }
144
145 public Object visit(ASTtest_list node, Object data) throws SieveException {
146 return visitNode(node, data);
147 }
148
149 public Object visit(ASTstring node, Object data) throws SieveException {
150 if (isInRequire) {
151 requirements(node);
152 }
153 if (isInComparatorNameArgument) {
154 comparatorNameArgument(node);
155 }
156 return visitNode(node, data);
157 }
158
159 private void comparatorNameArgument(ASTstring node) throws SieveException {
160 final Object value = node.getValue();
161 if (value != null && value instanceof String) {
162 final String name = (String) value;
163
164 if (!comparatorManager.isImplicitlyDeclared(name)) {
165 if (!declaredComparators.contains(name)) {
166
167 throw new SieveException("Comparator must be explicitly declared in a require statement.");
168 }
169 }
170 }
171 }
172
173 private void requirements(ASTstring node) throws SieveException {
174 final Object value = node.getValue();
175 if (value != null && value instanceof String) {
176 final String name = (String) value;
177 if (name.startsWith(COMPARATOR_PREFIX)) {
178 final String comparatorName = name.substring(COMPARATOR_PREFIX_LENGTH);
179 if (comparatorManager.isSupported(comparatorName)) {
180 declaredComparators.add(comparatorName);
181 } else {
182
183 throw new SieveException("Comparator " + comparatorName + " is not supported");
184 }
185 } else {
186 try {
187 commandManager.getCommand(name);
188 } catch (LookupException e) {
189
190 testManager.getTest(name);
191 }
192 }
193 }
194 }
195
196 public Object visit(ASTstring_list node, Object data) throws SieveException {
197 return visitNode(node, data);
198 }
199
200 }