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: ****************************************************************/package org.apache.james.jspf.core;
019:
020: import org.apache.james.jspf.core.exceptions.PermErrorException;
021:
022: import java.util.HashMap;
023: import java.util.Map;
024: import java.util.Stack;
025:
026: /**
027: *
028: * This Class is used as a container between the other classes. All necessary
029: * values get stored here and get retrieved from here.
030: *
031: */
032:
033: public class SPFSession implements MacroData {
034:
035: private String ipAddress = ""; // also used for (i)<sending-host>
036:
037: private String mailFrom = ""; // (s)<responsible-sender>
038:
039: private String hostName = ""; // (h)<sender-domain>
040:
041: private String currentSenderPart = ""; // (l)
042:
043: private String currentDomain = ""; // (d)<current-domain>
044:
045: private String inAddress = "in-addr"; // (v)
046:
047: private String clientDomain = null; // (p)
048:
049: private String senderDomain = ""; // (o)
050:
051: private String readableIP = null; // (c)
052:
053: private String receivingDomain = null; // (r)
054:
055: private int currentDepth = 0;
056:
057: /**
058: * The maximum mechanismn which are allowed to use
059: */
060: public static final int MAX_DEPTH = 10;
061:
062: private String explanation = null;
063:
064: private String currentResult = null;
065:
066: private boolean ignoreExplanation = false;
067:
068: private Map attributes = new HashMap();
069:
070: private Stack checkers = new Stack();
071:
072: private String currentResultExpanded;
073:
074: /**
075: * Build the SPFSession from the given parameters
076: *
077: * @param mailFrom
078: * The emailaddress of the sender
079: * @param heloDomain
080: * The helo provided by the sender
081: * @param clientIP
082: * The ipaddress of the client
083: *
084: */
085: public SPFSession(String mailFrom, String heloDomain,
086: String clientIP) {
087: super ();
088: this .mailFrom = mailFrom.trim();
089: this .hostName = heloDomain.trim();
090:
091: try {
092: this .ipAddress = IPAddr.getProperIpAddress(clientIP.trim());
093: // get the in Address
094: this .inAddress = IPAddr.getInAddress(clientIP);
095: } catch (PermErrorException e) {
096: // ip was not rfc conform
097: this .setCurrentResultExpanded(e.getResult());
098: }
099:
100: // if nullsender is used postmaster@helo will be used as email
101: if (mailFrom.equals("")) {
102: this .currentSenderPart = "postmaster";
103: this .senderDomain = hostName;
104: this .mailFrom = currentSenderPart + "@" + hostName;
105: } else {
106: String[] fromParts = mailFrom.split("@");
107: // What to do when mailFrom is "@example.com" ?
108: if (fromParts.length > 1) {
109: this .senderDomain = fromParts[fromParts.length - 1];
110: this .currentSenderPart = mailFrom.substring(0, mailFrom
111: .length()
112: - 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 = (SPFChecker) 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: }
|