1 /****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one *
3 * or more contributor license agreements. See the NOTICE file *
4 * distributed with this work for additional information *
5 * regarding copyright ownership. The ASF licenses this file *
6 * to you under the Apache License, Version 2.0 (the *
7 * "License"); you may not use this file except in compliance *
8 * with the License. You may obtain a copy of the License at *
9 * *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, *
13 * software distributed under the License is distributed on an *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15 * KIND, either express or implied. See the License for the *
16 * specific language governing permissions and limitations *
17 * under the License. *
18 ****************************************************************/
19
20 package org.apache.jsieve.util.check;
21
22 import java.io.IOException;
23
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.List;
29 import java.util.ListIterator;
30
31 import javax.mail.Header;
32 import javax.mail.Message;
33 import javax.mail.MessagingException;
34
35 import org.apache.jsieve.exception.SieveException;
36 import org.apache.jsieve.mail.Action;
37 import org.apache.jsieve.mail.MailAdapter;
38 import org.apache.jsieve.mail.MailUtils;
39 import org.apache.jsieve.mail.SieveMailException;
40 import org.apache.jsieve.parser.address.SieveAddressBuilder;
41 import org.apache.jsieve.parser.generated.address.ParseException;
42
43 /**
44 * Checks script execution for an email. The wrapped email is set by called
45 * {@link #setMail}. Actions are recorded on {@link #executedActions} and can
46 * be retrieved by {@link #getExecutedActions()}.
47 */
48 public class ScriptCheckMailAdapter implements MailAdapter {
49
50 private final List actions;
51
52 private final List executedActions;
53
54 private Message mail = null;
55
56 public ScriptCheckMailAdapter() {
57 actions = new ArrayList();
58 executedActions = new ArrayList();
59 }
60
61 /**
62 * Gets the wrapped email.
63 *
64 * @return <code>Message</code>, possibly null
65 */
66 public Message getMail() {
67 return mail;
68 }
69
70 /**
71 * Sets the wrapped email and {@link #reset}s the adapter ready for another
72 * execution.
73 *
74 * @param mail
75 * <code>Message</code>, possibly null
76 */
77 public void setMail(Message mail) {
78 this.mail = mail;
79 reset();
80 }
81
82 /**
83 * Method addAction adds an Action to the List of Actions to be performed by
84 * the receiver.
85 *
86 * @param action
87 */
88 public void addAction(final Action action) {
89 actions.add(action);
90 }
91
92 /**
93 * Method executeActions. Applies the Actions accumulated by the receiver.
94 */
95 public void executeActions() throws SieveException {
96 executedActions.clear();
97 executedActions.addAll(actions);
98 }
99
100 /**
101 * Gets the actions accumulated when {@link #executedActions} was last
102 * called.
103 *
104 * @return <code>List</code> of {@link Action}s, not null. This list is a
105 * modifiable copy
106 */
107 public List getExecutedActions() {
108 final ArrayList result = new ArrayList(executedActions);
109 return result;
110 }
111
112 /**
113 * Method getActions answers the List of Actions accumulated by the
114 * receiver. Implementations may elect to supply an unmodifiable collection.
115 *
116 * @return <code>List</code> of {@link Action}'s, not null, possibly
117 * unmodifiable
118 */
119 public List getActions() {
120 final List result = Collections.unmodifiableList(actions);
121 return result;
122 }
123
124 /**
125 * Method getActionIteraror answers an Iterator over the List of Actions
126 * accumulated by the receiver. Implementations may elect to supply an
127 * unmodifiable iterator.
128 *
129 * @return <code>ListIterator</code>, not null, possibly unmodifiable
130 */
131 public ListIterator getActionsIterator() {
132 final List unmodifiableActions = getActions();
133 final ListIterator result = unmodifiableActions.listIterator();
134 return result;
135 }
136
137 /**
138 * Resets executed and accumlated actions. An instance may be safely reused
139 * to check a script once this method has been called.
140 */
141 public void reset() {
142 executedActions.clear();
143 actions.clear();
144 }
145
146 /**
147 * Method getHeader answers a List of all of the headers in the receiver
148 * whose name is equal to the passed name. If no headers are found an empty
149 * List is returned.
150 *
151 * @param name
152 * @return <code>List</code> not null, possibly empty
153 * @throws SieveMailException
154 */
155 public List getHeader(String name) throws SieveMailException {
156 List result = Collections.EMPTY_LIST;
157 if (mail != null) {
158 try {
159 String[] values = mail.getHeader(name);
160 if (values != null) {
161 result = Arrays.asList(values);
162 }
163 } catch (MessagingException e) {
164 throw new SieveMailException(e);
165 }
166 }
167 return result;
168 }
169
170 /**
171 * Method getHeaderNames answers a List of all of the headers in the
172 * receiver. No duplicates are allowed.
173 *
174 * @return <code>List</code>, not null possible empty, possible
175 * unmodifiable
176 * @throws SieveMailException
177 */
178 public List getHeaderNames() throws SieveMailException {
179 List results = Collections.EMPTY_LIST;
180 if (mail != null) {
181 try {
182 results = new ArrayList();
183 for (final Enumeration en = mail.getAllHeaders(); en
184 .hasMoreElements();) {
185 final Header header = (Header) en.nextElement();
186 final String name = header.getName();
187 if (!results.contains(name)) {
188 results.add(name);
189 }
190 }
191 } catch (MessagingException e) {
192 throw new SieveMailException(e);
193 }
194 }
195 return results;
196 }
197
198 /**
199 * <p>
200 * Method getMatchingHeader answers a List of all of the headers in the
201 * receiver with the passed name. If no headers are found an empty List is
202 * returned.
203 * </p>
204 *
205 * <p>
206 * This method differs from getHeader(String) in that it ignores case and
207 * the whitespace prefixes and suffixes of a header name when performing the
208 * match, as required by RFC 3028. Thus "From", "from ", " From" and " from "
209 * are considered equal.
210 * </p>
211 *
212 * @param name
213 * @return <code>List</code>, not null possibly empty
214 * @throws SieveMailException
215 */
216 public List getMatchingHeader(String name) throws SieveMailException {
217 List result = Collections.EMPTY_LIST;
218 if (mail != null) {
219 result = MailUtils.getMatchingHeader(this, name);
220 }
221 return result;
222 }
223
224 /**
225 * Method getSize answers the receiver's message size in octets.
226 *
227 * @return int
228 * @throws SieveMailException
229 */
230 public int getSize() throws SieveMailException {
231 int result = 0;
232 if (mail != null) {
233 try {
234 result = mail.getSize();
235 } catch (MessagingException e) {
236 throw new SieveMailException(e);
237 }
238 }
239 return result;
240 }
241
242 /**
243 * Method getContentType returns string/mime representation of the message
244 * type.
245 *
246 * @return String
247 * @throws SieveMailException
248 */
249 public String getContentType() throws SieveMailException {
250 String result = null;
251 if (mail != null) {
252 try {
253 result = mail.getContentType();
254 } catch (MessagingException e) {
255 throw new SieveMailException(e);
256 }
257 }
258 return result;
259 }
260
261 /**
262 * Method getContent returns object containing the message content.
263 *
264 * @return Object
265 * @throws SieveMailException
266 */
267 public Object getContent() throws SieveMailException {
268 Object result = null;
269 if (mail != null) {
270 try {
271 result = mail.getContent();
272 } catch (MessagingException e) {
273 throw new SieveMailException(e);
274 } catch (IOException e) {
275 throw new SieveMailException(e);
276 }
277 }
278 return result;
279 }
280
281 public Address[] parseAddresses(String headerName)
282 throws SieveMailException {
283 return parseAddresses(headerName, mail);
284 }
285
286 /**
287 * Parses the value from the given message into addresses.
288 *
289 * @param headerName
290 * header name, to be matched case insensitively
291 * @param message
292 * <code>Message</code>, not null
293 * @return <code>Address</code> array, not null possibly empty
294 * @throws SieveMailException
295 */
296 public Address[] parseAddresses(final String headerName,
297 final Message message) throws SieveMailException {
298 try {
299 final SieveAddressBuilder builder = new SieveAddressBuilder();
300
301 for (Enumeration en = message.getAllHeaders(); en.hasMoreElements();) {
302 final Header header = (Header) en.nextElement();
303 final String name = header.getName();
304 if (name.trim().equalsIgnoreCase(headerName)) {
305 builder.addAddresses(header.getValue());
306 }
307 }
308
309 final Address[] results = builder.getAddresses();
310 return results;
311
312 } catch (MessagingException ex) {
313 throw new SieveMailException(ex);
314 } catch (ParseException ex) {
315 throw new SieveMailException(ex);
316 }
317 }
318
319 }