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
21 package org.apache.james.jspf.core;
22
23 import org.apache.james.jspf.core.exceptions.PermErrorException;
24
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Stack;
28
29 /**
30 *
31 * This Class is used as a container between the other classes. All necessary
32 * values get stored here and get retrieved from here.
33 *
34 */
35
36 public class SPFSession implements MacroData {
37
38 private String ipAddress = ""; // also used for (i)<sending-host>
39
40 private String mailFrom = ""; // (s)<responsible-sender>
41
42 private String hostName = ""; // (h)<sender-domain>
43
44 private String currentSenderPart = ""; // (l)
45
46 private String currentDomain = ""; // (d)<current-domain>
47
48 private String inAddress = "in-addr"; // (v)
49
50 private String clientDomain = null; // (p)
51
52 private String senderDomain = ""; // (o)
53
54 private String readableIP = null; // (c)
55
56 private String receivingDomain = null; // (r)
57
58 private int currentDepth = 0;
59
60 /**
61 * The maximum mechanismn which are allowed to use
62 */
63 public static final int MAX_DEPTH = 10;
64
65 private String explanation = null;
66
67 private String currentResult = null;
68
69 private boolean ignoreExplanation = false;
70
71 private Map attributes = new HashMap();
72
73 private Stack checkers = new Stack();
74
75 private String currentResultExpanded;
76
77 /**
78 * Build the SPFSession from the given parameters
79 *
80 * @param mailFrom
81 * The emailaddress of the sender
82 * @param heloDomain
83 * The helo provided by the sender
84 * @param clientIP
85 * The ipaddress of the client
86 *
87 */
88 public SPFSession(String mailFrom, String heloDomain, String clientIP) {
89 super();
90 this.mailFrom = mailFrom.trim();
91 this.hostName = heloDomain.trim();
92
93 try {
94 this.ipAddress = IPAddr.getProperIpAddress(clientIP.trim());
95 // get the in Address
96 this.inAddress = IPAddr.getInAddress(clientIP);
97 } catch (PermErrorException e) {
98 // ip was not rfc conform
99 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 = (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 }