001 /****************************************************************
002 * Licensed to the Apache Software Foundation (ASF) under one *
003 * or more contributor license agreements. See the NOTICE file *
004 * distributed with this work for additional information *
005 * regarding copyright ownership. The ASF licenses this file *
006 * to you under the Apache License, Version 2.0 (the *
007 * "License"); you may not use this file except in compliance *
008 * with the License. You may obtain a copy of the License at *
009 * *
010 * http://www.apache.org/licenses/LICENSE-2.0 *
011 * *
012 * Unless required by applicable law or agreed to in writing, *
013 * software distributed under the License is distributed on an *
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015 * KIND, either express or implied. See the License for the *
016 * specific language governing permissions and limitations *
017 * under the License. *
018 ****************************************************************/
019
020
021 package org.apache.james.jspf.terms;
022
023 import org.apache.james.jspf.core.DNSLookupContinuation;
024 import org.apache.james.jspf.core.LogEnabled;
025 import org.apache.james.jspf.core.Logger;
026 import org.apache.james.jspf.core.MacroExpand;
027 import org.apache.james.jspf.core.MacroExpandEnabled;
028 import org.apache.james.jspf.core.SPF1Constants;
029 import org.apache.james.jspf.core.SPFCheckEnabled;
030 import org.apache.james.jspf.core.SPFChecker;
031 import org.apache.james.jspf.core.SPFCheckerExceptionCatcher;
032 import org.apache.james.jspf.core.SPFSession;
033 import org.apache.james.jspf.core.SPFTermsRegexps;
034 import org.apache.james.jspf.core.exceptions.NeutralException;
035 import org.apache.james.jspf.core.exceptions.NoneException;
036 import org.apache.james.jspf.core.exceptions.PermErrorException;
037 import org.apache.james.jspf.core.exceptions.TempErrorException;
038
039 /**
040 * This class represent the incude mechanism
041 *
042 */
043 public class IncludeMechanism implements Mechanism, ConfigurationEnabled, LogEnabled, SPFCheckEnabled, MacroExpandEnabled {
044
045 private final class ExpandedChecker implements SPFChecker {
046
047 /**
048 * @see org.apache.james.jspf.core.SPFChecker#checkSPF(org.apache.james.jspf.core.SPFSession)
049 */
050 public DNSLookupContinuation checkSPF(SPFSession spfData) throws PermErrorException,
051 TempErrorException {
052
053 // throws a PermErrorException that we can pass through
054 String host = macroExpand.expand(getHost(), spfData, MacroExpand.DOMAIN);
055
056 spfData.setCurrentDomain(host);
057
058 // On includes we should not use the explanation of the included domain
059 spfData.setIgnoreExplanation(true);
060 // set a null current result
061 spfData.setCurrentResult(null);
062 spfData.setCurrentResultExpanded(null);
063
064 spfData.pushChecker(spfChecker);
065
066 return null;
067 }
068 }
069
070 private final class CleanupAndResultChecker implements SPFChecker, SPFCheckerExceptionCatcher {
071 private String previousResult;
072 private String previousResultExpanded;
073 private String previousDomain;
074
075 private void restoreSession(SPFSession spfData) {
076 spfData.setIgnoreExplanation(false);
077 spfData.setCurrentDomain(previousDomain);
078 spfData.setCurrentResult(previousResult);
079 spfData.setCurrentResultExpanded(previousResultExpanded);
080 }
081
082 /**
083 * @see org.apache.james.jspf.core.SPFChecker#checkSPF(org.apache.james.jspf.core.SPFSession)
084 */
085 public DNSLookupContinuation checkSPF(SPFSession spfData) throws PermErrorException,
086 TempErrorException, NeutralException, NoneException {
087
088 String currentResult = spfData.getCurrentResult();
089
090 restoreSession(spfData);
091
092 if (currentResult == null) {
093 throw new TempErrorException("included checkSPF returned null");
094 } else if (currentResult.equals(SPF1Constants.PASS)) {
095 // TODO this won't work asynchronously
096 spfData.setAttribute(Directive.ATTRIBUTE_MECHANISM_RESULT, Boolean.TRUE);
097 } else if (currentResult.equals(SPF1Constants.FAIL) || currentResult.equals(SPF1Constants.SOFTFAIL) || currentResult.equals(SPF1Constants.NEUTRAL)) {
098 // TODO this won't work asynchronously
099 spfData.setAttribute(Directive.ATTRIBUTE_MECHANISM_RESULT, Boolean.FALSE);
100 } else {
101 throw new TempErrorException("included checkSPF returned an Illegal result");
102 }
103
104 return null;
105 }
106
107 /**
108 * @see org.apache.james.jspf.core.SPFCheckerExceptionCatcher#onException(java.lang.Exception, org.apache.james.jspf.core.SPFSession)
109 */
110 public void onException(Exception exception, SPFSession session)
111 throws PermErrorException, NoneException,
112 TempErrorException, NeutralException {
113
114 restoreSession(session);
115
116 if (exception instanceof NeutralException) {
117 throw new PermErrorException("included checkSPF returned NeutralException");
118 } else if (exception instanceof NoneException) {
119 throw new PermErrorException("included checkSPF returned NoneException");
120 } else if (exception instanceof PermErrorException){
121 throw (PermErrorException) exception;
122 } else if (exception instanceof TempErrorException){
123 throw (TempErrorException) exception;
124 } else if (exception instanceof RuntimeException){
125 throw (RuntimeException) exception;
126 } else {
127 throw new IllegalStateException(exception.getMessage());
128 }
129 }
130
131 public SPFChecker init(SPFSession spfSession) {
132 // TODO understand what exactly we have to do now that spfData is a session
133 // and contains much more than the input data.
134 // do we need to create a new session at all?
135 // do we need to backup the session attributes and restore them?
136 this.previousResult = spfSession.getCurrentResult();
137 this.previousDomain = spfSession.getCurrentDomain();
138 this.previousResultExpanded = spfSession.getCurrentResultExpanded();
139 return this;
140 }
141 }
142
143 /**
144 * ABNF: include = "include" ":" domain-spec
145 */
146 public static final String REGEX = "[iI][nN][cC][lL][uU][dD][eE]" + "\\:"
147 + SPFTermsRegexps.DOMAIN_SPEC_REGEX;
148
149 protected String host;
150
151 protected Logger log;
152
153 private SPFChecker spfChecker;
154
155 private MacroExpand macroExpand;
156
157 /**
158 * @see org.apache.james.jspf.core.SPFChecker#checkSPF(org.apache.james.jspf.core.SPFSession)
159 */
160 public DNSLookupContinuation checkSPF(SPFSession spfData) throws PermErrorException, TempErrorException, NoneException, NeutralException {
161 // update currentDepth
162 spfData.increaseCurrentDepth();
163
164 SPFChecker cleanupAndResultHandler = new CleanupAndResultChecker().init(spfData);
165 spfData.pushChecker(cleanupAndResultHandler);
166
167 spfData.pushChecker(new ExpandedChecker());
168 return macroExpand.checkExpand(getHost(), spfData, MacroExpand.DOMAIN);
169 }
170
171 /**
172 * @see org.apache.james.jspf.terms.ConfigurationEnabled#config(Configuration)
173 */
174 public synchronized void config(Configuration params) throws PermErrorException {
175 if (params.groupCount() == 0) {
176 throw new PermErrorException("Include mechanism without an host");
177 }
178 host = params.group(1);
179 }
180
181 /**
182 * @return Returns the host.
183 */
184 protected synchronized String getHost() {
185 return host;
186 }
187
188 /**
189 * @see org.apache.james.jspf.core.LogEnabled#enableLogging(org.apache.james.jspf.core.Logger)
190 */
191 public void enableLogging(Logger logger) {
192 this.log = logger;
193 }
194
195 /**
196 * @see java.lang.Object#toString()
197 */
198 public String toString() {
199 return "include:"+getHost();
200 }
201
202 /**
203 * @see org.apache.james.jspf.core.SPFCheckEnabled#enableSPFChecking(org.apache.james.jspf.core.SPFChecker)
204 */
205 public void enableSPFChecking(SPFChecker checker) {
206 this.spfChecker = checker;
207 }
208
209 /**
210 * @see org.apache.james.jspf.core.MacroExpandEnabled#enableMacroExpand(org.apache.james.jspf.core.MacroExpand)
211 */
212 public void enableMacroExpand(MacroExpand macroExpand) {
213 this.macroExpand = macroExpand;
214 }
215 }