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.core;
022
023 import org.apache.james.jspf.core.exceptions.PermErrorException;
024
025 import java.util.HashMap;
026 import java.util.Map;
027 import java.util.Stack;
028
029 /**
030 *
031 * This Class is used as a container between the other classes. All necessary
032 * values get stored here and get retrieved from here.
033 *
034 */
035
036 public class SPFSession implements MacroData {
037
038 private String ipAddress = ""; // also used for (i)<sending-host>
039
040 private String mailFrom = ""; // (s)<responsible-sender>
041
042 private String hostName = ""; // (h)<sender-domain>
043
044 private String currentSenderPart = ""; // (l)
045
046 private String currentDomain = ""; // (d)<current-domain>
047
048 private String inAddress = "in-addr"; // (v)
049
050 private String clientDomain = null; // (p)
051
052 private String senderDomain = ""; // (o)
053
054 private String readableIP = null; // (c)
055
056 private String receivingDomain = null; // (r)
057
058 private int currentDepth = 0;
059
060 /**
061 * The maximum mechanismn which are allowed to use
062 */
063 public static final int MAX_DEPTH = 10;
064
065 private String explanation = null;
066
067 private String currentResult = null;
068
069 private boolean ignoreExplanation = false;
070
071 private Map<String,Object> attributes = new HashMap<String,Object>();
072
073 private Stack<SPFChecker> checkers = new Stack<SPFChecker>();
074
075 private String currentResultExpanded;
076
077 /**
078 * Build the SPFSession from the given parameters
079 *
080 * @param mailFrom
081 * The emailaddress of the sender
082 * @param heloDomain
083 * The helo provided by the sender
084 * @param clientIP
085 * The ipaddress of the client
086 *
087 */
088 public SPFSession(String mailFrom, String heloDomain, String clientIP) {
089 super();
090 this.mailFrom = mailFrom.trim();
091 this.hostName = heloDomain.trim();
092
093 try {
094 this.ipAddress = IPAddr.getProperIpAddress(clientIP.trim());
095 // get the in Address
096 this.inAddress = IPAddr.getInAddress(clientIP);
097 } catch (PermErrorException e) {
098 // ip was not rfc conform
099 this.setCurrentResultExpanded(e.getResult());
100 }
101
102 // if nullsender is used postmaster@helo will be used as email
103 if (mailFrom.equals("")) {
104 this.currentSenderPart = "postmaster";
105 this.senderDomain = hostName;
106 this.mailFrom = currentSenderPart + "@" + hostName;
107 } else {
108 String[] fromParts = mailFrom.split("@");
109 // What to do when mailFrom is "@example.com" ?
110 if (fromParts.length > 1) {
111 this.senderDomain = fromParts[fromParts.length -1];
112 this.currentSenderPart = mailFrom.substring(0, mailFrom.length() - senderDomain.length() - 1);
113 if (this.currentSenderPart.length() == 0) {
114 this.currentSenderPart = "postmaster";
115 }
116 } else {
117 this.currentSenderPart = "postmaster";
118 this.senderDomain = mailFrom;
119 }
120 }
121 this.currentDomain = this.senderDomain;
122 }
123
124 /**
125 * @see org.apache.james.jspf.core.MacroData#getCurrentSenderPart()
126 */
127 public String getCurrentSenderPart() {
128 return currentSenderPart;
129 }
130
131 /**
132 * @see org.apache.james.jspf.core.MacroData#getMailFrom()
133 */
134 public String getMailFrom() {
135 return mailFrom;
136 }
137
138 /**
139 * @see org.apache.james.jspf.core.MacroData#getHostName()
140 */
141 public String getHostName() {
142 return hostName;
143 }
144
145 /**
146 * @see org.apache.james.jspf.core.MacroData#getCurrentDomain()
147 */
148 public String getCurrentDomain() {
149 return currentDomain;
150 }
151
152 /**
153 * @see org.apache.james.jspf.core.MacroData#getInAddress()
154 */
155 public String getInAddress() {
156 return inAddress;
157 }
158
159 /**
160 * @see org.apache.james.jspf.core.MacroData#getClientDomain()
161 */
162 public String getClientDomain() {
163 return clientDomain;
164 }
165
166 /**
167 * Sets the calculated clientDomain
168 * @param clientDomain the new clientDomain
169 */
170 public void setClientDomain(String clientDomain) {
171 this.clientDomain = clientDomain;
172 }
173
174 /**
175 * @see org.apache.james.jspf.core.MacroData#getSenderDomain()
176 */
177 public String getSenderDomain() {
178 return senderDomain;
179 }
180
181 /**
182 * Get the ipAddress which was used to connect
183 *
184 * @return ipAddres
185 */
186 public String getIpAddress() {
187 return ipAddress;
188 }
189
190 /**
191 * @see org.apache.james.jspf.core.MacroData#getMacroIpAddress()
192 */
193 public String getMacroIpAddress() {
194
195 if (IPAddr.isIPV6(ipAddress)) {
196 try {
197 return IPAddr.getAddress(ipAddress).getNibbleFormat();
198 } catch (PermErrorException e) {
199 }
200 }
201
202 return ipAddress;
203
204 }
205
206 /**
207 * @see org.apache.james.jspf.core.MacroData#getTimeStamp()
208 */
209 public long getTimeStamp() {
210 return System.currentTimeMillis();
211 }
212
213 /**
214 * @see org.apache.james.jspf.core.MacroData#getReadableIP()
215 */
216 public String getReadableIP() {
217 if (readableIP == null) {
218 readableIP = IPAddr.getReadableIP(ipAddress);
219 }
220 return readableIP;
221 }
222
223 /**
224 * @see org.apache.james.jspf.core.MacroData#getReceivingDomain()
225 */
226 public String getReceivingDomain() {
227 return receivingDomain;
228 }
229
230 /**
231 * Sets the new receiving domain
232 *
233 * @param receivingDomain the new receiving domain
234 */
235 public void setReceivingDomain(String receivingDomain) {
236 this.receivingDomain = receivingDomain;
237 }
238
239 /**
240 * Increase the current depth:
241 *
242 * if we reach maximum calls we must throw a PermErrorException. See
243 * SPF-RFC Section 10.1. Processing Limits
244 */
245 public void increaseCurrentDepth() throws PermErrorException {
246 this.currentDepth++;
247 if (currentDepth > MAX_DEPTH)
248 throw new PermErrorException(
249 "Maximum mechanism/modifiers calls done: "
250 + currentDepth);
251 }
252
253 /**
254 * Set the currentDomain
255 *
256 * @param domain The current used domain
257 */
258 public void setCurrentDomain(String domain) {
259 this.currentDomain = domain;
260 }
261
262 /**
263 * Set the explanation which will returned when a fail match
264 *
265 * @param explanation
266 * This String is set as explanation
267 */
268 public void setExplanation(String explanation) {
269 this.explanation = explanation;
270 }
271
272 /**
273 * Get the explanation
274 *
275 * @return explanation
276 */
277 public String getExplanation() {
278 return explanation;
279 }
280
281 /**
282 * Set the current result
283 *
284 * @param result
285 * result
286 */
287 public void setCurrentResult(String result) {
288 this.currentResult = result;
289 }
290
291 /**
292 * Get the current result
293 *
294 * @return current result
295 */
296 public String getCurrentResult() {
297 return currentResult;
298 }
299
300 /**
301 * Get set to true if the explanation should be ignored
302 *
303 * @param ignoreExplanation true or false
304 */
305 public void setIgnoreExplanation(boolean ignoreExplanation) {
306 this.ignoreExplanation = ignoreExplanation;
307 }
308
309 /**
310 * Return true if the explanation should be ignored
311 *
312 * @return true of false
313 */
314 public boolean ignoreExplanation() {
315 return ignoreExplanation;
316 }
317
318 /**
319 * Retrieve a stored attribute
320 *
321 * @param key the attribute key
322 * @return the stored attribute
323 */
324 public Object getAttribute(String key) {
325 return attributes.get(key);
326 }
327
328 /**
329 * Sets a new attribute in the session
330 *
331 * @param key attribute key
332 * @param value the value for this attribute
333 */
334 public void setAttribute(String key, Object value) {
335 this.attributes.put(key, value);
336 }
337
338 /**
339 * Remove the attribute stored under the given key
340 *
341 * @param key the key of the attribute
342 * @return object the attribute which was stored with the key
343 */
344 public Object removeAttribute(String key) {
345 return this.attributes.remove(key);
346 }
347
348 /**
349 * Add the given SPFChecker on top of the stack
350 *
351 * @param checker
352 */
353 public void pushChecker(SPFChecker checker) {
354 checkers.push(checker);
355 }
356
357 /**
358 * Remove the SPFChecker on the top and return it. If no SPFChecker is left
359 * null is returned
360 *
361 * @return the last checker
362 */
363 public SPFChecker popChecker() {
364 if (checkers.isEmpty()) {
365 return null;
366 } else {
367 SPFChecker checker = checkers.pop();
368 return checker;
369 }
370 }
371
372 /**
373 * @param result
374 */
375 public void setCurrentResultExpanded(String result) {
376 this.currentResultExpanded = result;
377 }
378
379 /**
380 * @return current result converted/expanded
381 */
382 public String getCurrentResultExpanded() {
383 return currentResultExpanded;
384 }
385
386 }