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 }