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