c9d6def430612ed51d896eef5b951f80955d8737
[james-jsieve.git] / util / src / main / java / org / apache / jsieve / util / check / ScriptCheckMailAdapter.java
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 org.apache.jsieve.SieveContext;
23 import org.apache.jsieve.exception.SieveException;
24 import org.apache.jsieve.mail.Action;
25 import org.apache.jsieve.mail.MailAdapter;
26 import org.apache.jsieve.mail.MailUtils;
27 import org.apache.jsieve.mail.SieveMailException;
28 import org.apache.jsieve.parser.address.SieveAddressBuilder;
29 import org.apache.jsieve.parser.generated.address.ParseException;
30
31 import javax.mail.internet.MimeUtility;
32 import javax.mail.Header;
33 import javax.mail.Message;
34 import javax.mail.MessagingException;
35 import java.io.IOException;
36 import java.util.*;
37 import java.io.UnsupportedEncodingException;
38
39 /**
40 * Checks script execution for an email. The wrapped email is set by called
41 * {@link #setMail}. Actions are recorded on {@link #executedActions} and can
42 * be retrieved by {@link #getExecutedActions()}.
43 */
44 public class ScriptCheckMailAdapter implements MailAdapter {
45
46 private final List<Action> actions;
47
48 private final List<Action> executedActions;
49
50 private Message mail = null;
51
52 public ScriptCheckMailAdapter() {
53 actions = new ArrayList<Action>();
54 executedActions = new ArrayList<Action>();
55 }
56
57 /**
58 * Gets the wrapped email.
59 *
60 * @return <code>Message</code>, possibly null
61 */
62 public Message getMail() {
63 return mail;
64 }
65
66 /**
67 * Sets the wrapped email and {@link #reset}s the adapter ready for another
68 * execution.
69 *
70 * @param mail <code>Message</code>, possibly null
71 */
72 public void setMail(Message mail) {
73 this.mail = mail;
74 reset();
75 }
76
77 /**
78 * Method addAction adds an Action to the List of Actions to be performed by
79 * the receiver.
80 *
81 * @param action
82 */
83 public void addAction(final Action action) {
84 actions.add(action);
85 }
86
87 /**
88 * Method executeActions. Applies the Actions accumulated by the receiver.
89 */
90 public void executeActions() throws SieveException {
91 executedActions.clear();
92 executedActions.addAll(actions);
93 }
94
95 /**
96 * Gets the actions accumulated when {@link #executedActions} was last
97 * called.
98 *
99 * @return <code>List</code> of {@link Action}s, not null. This list is a
100 * modifiable copy
101 */
102 public List<Action> getExecutedActions() {
103 return new ArrayList<Action>(executedActions);
104 }
105
106 /**
107 * Method getActions answers the List of Actions accumulated by the
108 * receiver. Implementations may elect to supply an unmodifiable collection.
109 *
110 * @return <code>List</code> of {@link Action}'s, not null, possibly
111 * unmodifiable
112 */
113 public List<Action> getActions() {
114 return Collections.unmodifiableList(actions);
115 }
116
117 /**
118 * Resets executed and accumlated actions. An instance may be safely reused
119 * to check a script once this method has been called.
120 */
121 public void reset() {
122 executedActions.clear();
123 actions.clear();
124 }
125
126 /**
127 * Method getHeader answers a List of all of the headers in the receiver
128 * whose name is equal to the passed name. If no headers are found an empty
129 * List is returned.
130 *
131 * @param name
132 * @return <code>List</code> not null, possibly empty
133 * @throws SieveMailException
134 */
135 @SuppressWarnings("unchecked")
136 public List<String> getHeader(String name) throws SieveMailException {
137 List<String> result = Collections.EMPTY_LIST;
138 if (mail != null) {
139 try {
140 String[] values = mail.getHeader(name);
141 if (values != null) {
142 // We need to do unfold headers + decoding here
143 result = new LinkedList<String>();
144 for (String value: values) {
145 result.add(MimeUtility.decodeText(MimeUtility.unfold(value)));
146 }
147 }
148 } catch (MessagingException e) {
149 throw new SieveMailException(e);
150 } catch (UnsupportedEncodingException 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 * <p/>
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 header name, to be matched case insensitively
259 * @param message <code>Message</code>, not null
260 * @return <code>Address</code> array, not null possibly empty
261 * @throws SieveMailException
262 */
263 public Address[] parseAddresses(final String headerName,
264 final Message message) throws SieveMailException {
265 try {
266 final SieveAddressBuilder builder = new SieveAddressBuilder();
267
268 for (Enumeration en = message.getAllHeaders(); en.hasMoreElements(); ) {
269 final Header header = (Header) en.nextElement();
270 final String name = header.getName();
271 if (name.trim().equalsIgnoreCase(headerName)) {
272 builder.addAddresses(MimeUtility.decodeText(MimeUtility.unfold(header.getValue())));
273 }
274 }
275
276 final Address[] results = builder.getAddresses();
277 return results;
278
279 } catch (MessagingException ex) {
280 throw new SieveMailException(ex);
281 } catch (UnsupportedEncodingException ex) {
282 throw new SieveMailException(ex);
283 } catch (ParseException ex) {
284 throw new SieveMailException(ex);
285 }
286 }
287
288 public boolean isInBodyText(List<String> phrasesCaseInsensitive) throws SieveMailException {
289 throw new SieveMailException("Not yet implemented");
290 }
291
292 public boolean isInBodyRaw(List<String> phrasesCaseInsensitive) throws SieveMailException {
293 throw new SieveMailException("Not yet implemented");
294 }
295
296 public boolean isInBodyContent(List<String> contentTypes, List<String> phrasesCaseInsensitive) throws SieveMailException {
297 throw new SieveMailException("Not yet implemented");
298 }
299
300 public void setContext(SieveContext context) {
301 }
302
303 }