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    package org.apache.james.jspf.policies.local;
021    
022    import org.apache.james.jspf.core.DNSLookupContinuation;
023    import org.apache.james.jspf.core.Logger;
024    import org.apache.james.jspf.core.MacroExpand;
025    import org.apache.james.jspf.core.SPF1Constants;
026    import org.apache.james.jspf.core.SPF1Record;
027    import org.apache.james.jspf.core.SPF1Utils;
028    import org.apache.james.jspf.core.SPFChecker;
029    import org.apache.james.jspf.core.SPFSession;
030    import org.apache.james.jspf.core.exceptions.NeutralException;
031    import org.apache.james.jspf.core.exceptions.NoneException;
032    import org.apache.james.jspf.core.exceptions.PermErrorException;
033    import org.apache.james.jspf.core.exceptions.TempErrorException;
034    import org.apache.james.jspf.policies.PolicyPostFilter;
035    import org.apache.james.jspf.terms.Modifier;
036    
037    /**
038     * Policy to add a default explanation
039     */
040    public final class DefaultExplanationPolicy implements PolicyPostFilter {
041    
042        
043        private final class ExplanationChecker implements SPFChecker {
044            
045            /**
046             * @see org.apache.james.jspf.core.SPFChecker#checkSPF(org.apache.james.jspf.core.SPFSession)
047             */
048            public DNSLookupContinuation checkSPF(SPFSession spfData)
049                    throws PermErrorException,
050                    NoneException, TempErrorException,
051                    NeutralException {
052                String attExplanation = (String) spfData.getAttribute(ATTRIBUTE_DEFAULT_EXPLANATION_POLICY_EXPLANATION);
053                try {
054                    String explanation = macroExpand.expand(attExplanation, spfData, MacroExpand.EXPLANATION);
055                    
056                    spfData.setExplanation(explanation);
057                } catch (PermErrorException e) {
058                    // Should never happen !
059                    log.debug("Invalid defaulfExplanation: " + attExplanation);
060                }
061                return null;
062            }
063        }
064    
065        private final class DefaultExplanationChecker implements Modifier {
066            
067            private SPFChecker explanationCheckr = new ExplanationChecker();
068            
069            /**
070             * @see org.apache.james.jspf.core.SPFChecker#checkSPF(org.apache.james.jspf.core.SPFSession)
071             */
072            public DNSLookupContinuation checkSPF(SPFSession spfData) throws PermErrorException, NoneException, TempErrorException, NeutralException {
073                
074                if (SPF1Constants.FAIL.equals(spfData.getCurrentResult())) {  
075                    if (spfData.getExplanation()==null || spfData.getExplanation().equals("")) {
076                        String explanation;
077                        if (defExplanation == null) {
078                            explanation = SPF1Utils.DEFAULT_EXPLANATION;
079                        } else {
080                            explanation = defExplanation;
081                        }
082                        spfData.setAttribute(ATTRIBUTE_DEFAULT_EXPLANATION_POLICY_EXPLANATION, explanation);
083                        spfData.pushChecker(explanationCheckr);
084                        return macroExpand.checkExpand(explanation, spfData, MacroExpand.EXPLANATION);
085                    }
086                }
087                
088                return null;
089            }
090    
091            public String toString() {
092                if (defExplanation == null) {
093                    return "defaultExplanation";
094                } else {
095                    return "defaultExplanation="+defExplanation;
096                }
097            }
098    
099            /**
100             * (non-Javadoc)
101             * @see org.apache.james.jspf.terms.Modifier#enforceSingleInstance()
102             */
103                    public boolean enforceSingleInstance() {
104                            return false;
105                    }
106        }
107    
108        private static final String ATTRIBUTE_DEFAULT_EXPLANATION_POLICY_EXPLANATION = "DefaultExplanationPolicy.explanation";
109        
110        /**
111         * log
112         */
113        private Logger log;
114        /**
115         * the default explanation
116         */
117        private String defExplanation;
118        
119        private MacroExpand macroExpand;
120        
121        /**
122         * @param log the logger
123         * @param explanation the default explanation
124         * @param macroExpand the MacroExpand service
125         */
126        public DefaultExplanationPolicy(Logger log, String explanation, MacroExpand macroExpand) {
127            this.log = log;
128            this.defExplanation = explanation;
129            this.macroExpand = macroExpand;
130        }
131    
132        /**
133         * @see org.apache.james.jspf.policies.PolicyPostFilter#getSPFRecord(java.lang.String, org.apache.james.jspf.core.SPF1Record)
134         */
135        public SPF1Record getSPFRecord(String currentDomain, SPF1Record spfRecord) throws PermErrorException, TempErrorException, NoneException, NeutralException {
136            if (spfRecord == null) return null;
137            // Default explanation policy.
138            spfRecord.getModifiers().add(new DefaultExplanationChecker());
139            return spfRecord;
140        }
141    }