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