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.File;
23  import java.io.FileInputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.util.List;
27  
28  import javax.mail.MessagingException;
29  import javax.mail.internet.MimeMessage;
30  
31  import org.apache.jsieve.ConfigurationManager;
32  import org.apache.jsieve.exception.SieveException;
33  import org.apache.jsieve.mail.ActionFileInto;
34  import org.apache.jsieve.mail.ActionKeep;
35  import org.apache.jsieve.mail.ActionRedirect;
36  import org.apache.jsieve.mail.ActionReject;
37  import org.apache.jsieve.parser.generated.ParseException;
38  
39  /**
40   * Checks a <code>sieve</code> script by executing it against a given mail and
41   * reporting the results.
42   */
43  public class ScriptChecker {
44  
45      private final ScriptCheckMailAdapter adapter;
46  
47      public ScriptChecker() {
48          adapter = new ScriptCheckMailAdapter();
49      }
50  
51      /**
52       * Checks the <code>sieve</code> script contained in the given file by
53       * executing it against the given message.
54       * 
55       * @param message
56       *            <code>File</code> containing the mail message to be fed to
57       *            the script, not null
58       * @param script
59       *            <code>File</code> containing the script to be checked
60       * @return <code>Results</code> of that execution
61       * @throws IOException
62       * @throws MessageException
63       */
64      public Results check(final File message, final File script)
65              throws IOException, MessagingException {
66          final FileInputStream messageStream = new FileInputStream(message);
67          final FileInputStream scriptStream = new FileInputStream(script);
68          final Results results = check(messageStream, scriptStream);
69          return results;
70      }
71  
72      /**
73       * Checks the <code>sieve</code> script contained in the given file by
74       * executing it against the given message.
75       * 
76       * @param script
77       *            <code>InputStream</code>, not null
78       * @return <code>Results</code> of the check, not null
79       * @throws IOException
80       * @throws MessagingException
81       */
82      public Results check(final InputStream message, final InputStream script)
83              throws IOException, MessagingException {
84          MimeMessage mimeMessage = new MimeMessage(null, message);
85          adapter.setMail(mimeMessage);
86          Results results;
87          try {
88              new ConfigurationManager().build().interpret(adapter, script);
89              final List executedActions = adapter.getExecutedActions();
90              results = new Results(executedActions);
91          } catch (ParseException e) {
92              e.printStackTrace();
93              results = new Results(e);
94          } catch (SieveException e) {
95              e.printStackTrace();
96              results = new Results(e);
97          }
98          return results;
99      }
100 
101     /**
102      * Contains results of script execution.
103      */
104     public final static class Results {
105         private final boolean pass;
106 
107         private final Exception exception;
108 
109         private final List actionsExecuted;
110 
111         public Results(final Exception ex) {
112             this.exception = ex;
113             pass = false;
114             actionsExecuted = null;
115         }
116 
117         public Results(final List actions) {
118             this.pass = true;
119             exception = null;
120             this.actionsExecuted = actions;
121         }
122 
123         /**
124          * Is this a pass?
125          * 
126          * @return true if the script executed without error, false if errors
127          *         were encountered
128          */
129         public boolean isPass() {
130             return pass;
131         }
132 
133         /**
134          * Gets the exception which was thrown during execution.
135          * 
136          * @return <code>Exception</code> or null if no exception was thrown
137          */
138         public Exception getException() {
139             return exception;
140         }
141 
142         /**
143          * Gets the actions executed by the script.
144          * 
145          * @return <code>List</code> of actions or null if the script failed
146          */
147         public List getActionsExecuted() {
148             return actionsExecuted;
149         }
150 
151         /**
152          * Is the <code>n<code>'th action a <code>FileInto</code>
153          * with given destination?
154          * @param destination <code>String</code> destination for the file into
155          * @param n index to check
156          * @return  true if the <code>n<code>'th action is a <code>FileInto</code>
157          * with given destination
158          */
159         public boolean isActionFileInto(String destination, int n) {
160             boolean result = false;
161             Object action = actionsExecuted.get(n);
162             if (action != null && action instanceof ActionFileInto) {
163                 ActionFileInto actionFileInto = (ActionFileInto) action;
164                 result = destination.equals(actionFileInto.getDestination());
165             }
166             return result;
167         }
168 
169         /**
170          * Is the <code>n<code>'th action a <code>Redirect</code>
171          * with given address?
172          * @param address <code>String</code> redirect address
173          * @param n index to check
174          * @return  true if the <code>n<code>'th action is a <code>Redirect</code>
175          * with given redirect address
176          */
177         public boolean isActionRedirect(String address, int n) {
178             boolean result = false;
179             Object action = actionsExecuted.get(n);
180             if (action != null && action instanceof ActionRedirect) {
181                 ActionRedirect actionRedirect = (ActionRedirect) action;
182                 result = address.equals(actionRedirect.getAddress());
183             }
184             return result;
185         }
186 
187         /**
188          * Is the <code>n<code>'th action a <code>Reject</code>
189          * with given message?
190          * @param message <code>String</code> rejection message
191          * @param n index to check
192          * @return  true if the <code>n<code>'th action is a <code>Reject</code>
193          * with given reject message
194          */
195         public boolean isActionReject(String message, int n) {
196             boolean result = false;
197             Object action = actionsExecuted.get(n);
198             if (action != null && action instanceof ActionReject) {
199                 ActionReject actionReject = (ActionReject) action;
200                 result = message.equals(actionReject.getMessage());
201             }
202             return result;
203         }
204 
205         /**
206          * Is the <code>n<code>'th action a <code>Keep</code>?
207          * @param n index to check
208          * @return  true if the <code>n<code>'th action is a <code>Keep</code>
209          */
210         public boolean isActionKeep(int n) {
211             boolean result = false;
212             Object action = actionsExecuted.get(n);
213             if (action != null && action instanceof ActionKeep) {
214                 result = true;
215             }
216             return result;
217         }
218 
219         /**
220          * Prints out details of results.
221          */
222         public String toString() {
223             StringBuffer buffer = new StringBuffer("Results: ");
224             if (pass) {
225                 buffer.append("PASS");
226             } else {
227                 buffer.append("FAIL: ");
228                 if (exception != null) {
229                     if (exception instanceof ParseException) {
230                         buffer.append("Cannot parse script");
231                     } else {
232                         buffer.append("Cannot excute script");
233                     }
234                     buffer.append(exception.getMessage());
235                 }
236             }
237             return buffer.toString();
238         }
239 
240     }
241 }