0001: /****************************************************************
0002: * Licensed to the Apache Software Foundation (ASF) under one *
0003: * or more contributor license agreements. See the NOTICE file *
0004: * distributed with this work for additional information *
0005: * regarding copyright ownership. The ASF licenses this file *
0006: * to you under the Apache License, Version 2.0 (the *
0007: * "License"); you may not use this file except in compliance *
0008: * with the License. You may obtain a copy of the License at *
0009: * *
0010: * http://www.apache.org/licenses/LICENSE-2.0 *
0011: * *
0012: * Unless required by applicable law or agreed to in writing, *
0013: * software distributed under the License is distributed on an *
0014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
0015: * KIND, either express or implied. See the License for the *
0016: * specific language governing permissions and limitations *
0017: * under the License. *
0018: ****************************************************************/package org.apache.james.fetchmail;
0019:
0020: import java.net.InetAddress;
0021: import java.net.UnknownHostException;
0022: import java.util.ArrayList;
0023: import java.util.Collection;
0024: import java.util.Enumeration;
0025: import java.util.Iterator;
0026: import java.util.StringTokenizer;
0027:
0028: import javax.mail.Address;
0029: import javax.mail.Flags;
0030: import javax.mail.MessagingException;
0031: import javax.mail.internet.InternetAddress;
0032: import javax.mail.internet.MimeMessage;
0033: import javax.mail.internet.ParseException;
0034:
0035: import org.apache.james.core.MailImpl;
0036: import org.apache.mailet.RFC2822Headers;
0037: import org.apache.mailet.Mail;
0038: import org.apache.mailet.MailAddress;
0039:
0040: /**
0041: * <p>Class <code>MessageProcessor</code> handles the delivery of
0042: * <code>MimeMessages</code> to the James input spool.</p>
0043: *
0044: * <p>Messages written to the input spool always have the following Mail
0045: * Attributes set:</p>
0046: * <dl>
0047: * <dt>org.apache.james.fetchmail.taskName (java.lang.String)</dt>
0048: * <dd>The name of the fetch task that processed the message</dd>
0049: * <dt>org.apache.james.fetchmail.folderName (java.lang.String)</dt>
0050: * <dd>The name of the folder from which the message was fetched</dd>
0051: * </dl>
0052: *
0053: * <p>Messages written to the input spool have the following Mail Attributes
0054: * set if the corresponding condition is satisfied:
0055: * <dl>
0056: * <dt>org.apache.james.fetchmail.isBlacklistedRecipient</dt>
0057: * <dd>The recipient is in the configured blacklist</dd>
0058: * <dt>org.apache.james.fetchmail.isMaxMessageSizeExceeded (java.lang.String)</dt>
0059: * <dd>The message size exceeds the configured limit. An empty message is
0060: * written to the input spool. The Mail Attribute value is a String
0061: * representing the size of the original message in bytes.</dd>
0062: * <dt>org.apache.james.fetchmail.isRecipientNotFound</dt>
0063: * <dd>The recipient could not be found. Delivery is to the configured recipient.
0064: * See the discussion of delivery to a sole intended recipient below.</dd>
0065: * <dt>org.apache.james.fetchmail.isRemoteRecievedHeaderInvalid</dt>
0066: * <dd>The Receieved header at the index specified by parameter
0067: * <code>remoteReceivedHeaderIndex</code> is invalid.</dd>
0068: * <dt>org.apache.james.fetchmail.isRemoteRecipient</dt>
0069: * <dd>The recipient is on a remote host</dd>
0070: * <dt>org.apache.james.fetchmail.isUserUndefined</dt>
0071: * <dd>The recipient is on a localhost but not defined to James</dd>
0072: * <dt>org.apache.james.fetchmail.isDefaultSenderLocalPart</dt>
0073: * <dd>The local part of the sender address could not be obtained. The
0074: * default value has been used.</dd>
0075: * <dt>org.apache.james.fetchmail.isDefaultSenderDomainPart</dt>
0076: * <dd>The domain part of the sender address could not be obtained. The
0077: * default value has been used.</dd>
0078: * <dt>org.apache.james.fetchmail.isDefaultRemoteAddress</dt>
0079: * <dd>The remote address could not be determined. The default value
0080: * (localhost/127.0.0.1)has been used.</dd>
0081: * </dl>
0082: *
0083: * <p>Configuration settings -
0084: * see <code>org.apache.james.fetchmail.ParsedConfiguration</code>
0085: * - control the messages that are written to the James input spool, those that
0086: * are rejected and what happens to messages that are rejected.</p>
0087: *
0088: * <p>Rejection processing is based on the following filters:</p>
0089: * <dl>
0090: * <dt>RejectRemoteRecipient</dt>
0091: * <dd>Rejects recipients on remote hosts</dd>
0092: * <dt>RejectBlacklistedRecipient</dt>
0093: * <dd>Rejects recipients configured in a blacklist</dd>
0094: * <dt>RejectUserUndefined</dt>
0095: * <dd>Rejects recipients on local hosts who are not defined as James users</dd>
0096: * <dt>RejectRecipientNotFound</dt>
0097: * <dd>See the discussion of delivery to a sole intended recipient below</dd>
0098: * <dt>RejectMaxMessageSizeExceeded</dt>
0099: * <dd>Rejects messages whose size exceeds the configured limit</dd>
0100: * <dt>RejectRemoteReceievedHeaderInvalid</dt>
0101: * <dd>Rejects messages whose Received header is invalid.</dd>
0102: * </dl>
0103: *
0104: * <p>Rejection processing is intentionally limited to managing the status of the
0105: * messages that are rejected on the server from which they were fetched. View
0106: * it as a simple automation of the manual processing an end-user would perform
0107: * through a mail client. Messages may be marked as seen or be deleted.</p>
0108: *
0109: * <p>Further processing can be achieved by configuring to disable rejection for
0110: * one or more filters. This enables Messages that would have been rejected to
0111: * be written to the James input spool. The conditional Mail Attributes
0112: * described above identify the filter states. The Matcher/Mailet chain can
0113: * then be used to perform any further processing required, such as notifying
0114: * the Postmaster and/or sender, marking the message for error processing, etc.</p>
0115: *
0116: * <p>Note that in the case of a message exceeding the message size limit, the
0117: * message that is written to the input spool has no content. This enables
0118: * configuration of a mailet notifying the sender that their mail has not been
0119: * delivered due to its size while maintaining the purpose of the filter which is
0120: * to avoid injecting excessively large messages into the input spool.</p>
0121: *
0122: * <p>Delivery is to a sole intended recipient. The recipient is determined in the
0123: * following manner:</p>
0124: *
0125: * <ol>
0126: * <li>If isIgnoreIntendedRecipient(), use the configured recipient</li>
0127: * <li>If the Envelope contains a for: stanza, use the recipient in the stanza</li>
0128: * <li>If the Message has a sole intended recipient, use this recipient</li>
0129: * <li>If not rejectRecipientNotFound(), use the configured recipient</li>
0130: * </ol>
0131: *
0132: * <p>If a recipient cannot be determined after these steps, the message is
0133: * rejected.</p>
0134: *
0135: * <p>Every delivered message CURRENTLY has an "X-fetched-from" header added
0136: * containing the name of the fetch task. Its primary uses are to detect bouncing
0137: * mail and provide backwards compatibility with the fetchPop task that inserted
0138: * this header to enable injected messages to be detected in the Matcher/Mailet
0139: * chain. This header is DEPRECATED and WILL BE REMOVED in a future version of
0140: * fetchmail. Use the Mail Attribute <code>org.apache.james.fetchmail.taskName</code>
0141: * instead.
0142: *
0143: * <p><code>MessageProcessor</code> is as agnostic as it can be about the format
0144: * and contents of the messages it delivers. There are no RFCs that govern its
0145: * behavior. The most releveant RFCs relate to the exchange of messages between
0146: * MTA servers, but not POP3 or IMAP servers which are normally end-point
0147: * servers and not expected to re-inject mail into MTAs. None the less, the
0148: * intent is to conform to the 'spirit' of the RFCs.
0149: * <code>MessageProcessor</code> relies on the MTA (James in this
0150: * implementation) to manage and validate the injected mail just as it would
0151: * when receiving mail from an upstream MTA.</p>
0152: *
0153: * <p>The only correction applied by <code>MessageProcessor</code> is to correct a
0154: * missing or partial sender address. If the sender address can not be obtained,
0155: * the default local part and default domain part is added. If the sender domain
0156: * part is absent, the default domain part is added.</p>
0157: *
0158: * <p>Mail with corrections applied to the sender address will most likely pass
0159: * Matcher tests on the sender that they might otherwise fail. The
0160: * Mail Attributes <code>org.apache.james.fetchmail.isDefaultSenderLocalPart</code>
0161: * and <code>org.apache.james.fetchmail.isDefaultSenderDomainPart</code> are added
0162: * to the injected mail to enable such mail to be detected and processed accordingly.
0163: * </p>
0164: *
0165: * <p>The status of messages on the server from which they were fetched that
0166: * cannot be injected into the input spool due to non-correctable errors is
0167: * determined by the undeliverable configuration options.</p>
0168: *
0169: */
0170: public class MessageProcessor extends ProcessorAbstract {
0171: private MimeMessage fieldMessageIn;
0172:
0173: /**
0174: * Recipient cannot be found
0175: */
0176: private boolean fieldRecipientNotFound = false;
0177:
0178: /**
0179: * Recipient is a local user on a local host
0180: */
0181: private boolean fieldRemoteRecipient = true;
0182:
0183: /**
0184: * The mail's Received header at index remoteReceivedHeaderIndex is invalid.
0185: */
0186: private Boolean fieldRemoteReceivedHeaderInvalid;
0187:
0188: /**
0189: * Recipient is not a local user
0190: */
0191: private boolean fieldUserUndefined = false;
0192:
0193: /**
0194: * The Maximum Message has been exceeded
0195: */
0196: private Boolean fieldMaxMessageSizeExceeded;
0197:
0198: /**
0199: * Field names for an RFC2822 compliant RECEIVED Header
0200: */
0201: static final private String fieldRFC2822RECEIVEDHeaderFields = "from by via with id for ;";
0202:
0203: /**
0204: * Recipient is blacklisted
0205: */
0206: private boolean fieldBlacklistedRecipient = false;
0207:
0208: /**
0209: * The RFC2822 compliant "Received : from" domain
0210: */
0211: private String fieldRemoteDomain;
0212:
0213: /**
0214: * The remote address derived from the remote domain
0215: */
0216: private String fieldRemoteAddress;
0217:
0218: /**
0219: * The remote host name derived from the remote domain
0220: */
0221: private String fieldRemoteHostName;
0222:
0223: /**
0224: * The default sender local part has been used.
0225: */
0226: private boolean fieldDefaultSenderLocalPart = false;
0227:
0228: /**
0229: * The default sender domain part has been used.
0230: */
0231: private boolean fieldDefaultSenderDomainPart = false;
0232:
0233: /**
0234: * The default remote address has been used.
0235: */
0236: private boolean fieldDefaultRemoteAddress = false;
0237:
0238: /**
0239: * Constructor for MessageProcessor.
0240: *
0241: * @param account
0242: */
0243: private MessageProcessor(Account account) {
0244: super (account);
0245: }
0246:
0247: /**
0248: * Constructor for MessageProcessor.
0249: *
0250: * @param messageIn
0251: * @param account
0252: */
0253:
0254: MessageProcessor(MimeMessage messageIn, Account account) {
0255: this (account);
0256: setMessageIn(messageIn);
0257: }
0258:
0259: /**
0260: * Method process attempts to deliver a fetched message.
0261: *
0262: * @see org.apache.james.fetchmail.ProcessorAbstract#process()
0263: */
0264: public void process() throws MessagingException {
0265: // Log delivery attempt
0266: if (getLogger().isDebugEnabled()) {
0267: StringBuffer logMessageBuffer = new StringBuffer(
0268: "Attempting delivery of message with id. ");
0269: logMessageBuffer.append(getMessageIn().getMessageID());
0270: getLogger().debug(logMessageBuffer.toString());
0271: }
0272:
0273: // Determine the intended recipient
0274: MailAddress intendedRecipient = getIntendedRecipient();
0275: setRecipientNotFound(null == intendedRecipient);
0276:
0277: if (isRecipientNotFound()) {
0278: if (isDeferRecipientNotFound()) {
0279:
0280: String messageID = getMessageIn().getMessageID();
0281: if (!getDeferredRecipientNotFoundMessageIDs().contains(
0282: messageID)) {
0283: getDeferredRecipientNotFoundMessageIDs().add(
0284: messageID);
0285: if (getLogger().isDebugEnabled()) {
0286: StringBuffer messageBuffer = new StringBuffer(
0287: "Deferred processing of message for which the intended recipient could not be found. Message ID: ");
0288: messageBuffer.append(messageID);
0289: getLogger().debug(messageBuffer.toString());
0290: }
0291: return;
0292: } else {
0293: getDeferredRecipientNotFoundMessageIDs().remove(
0294: messageID);
0295: if (getLogger().isDebugEnabled()) {
0296: StringBuffer messageBuffer = new StringBuffer(
0297: "Processing deferred message for which the intended recipient could not be found. Message ID: ");
0298: messageBuffer.append(messageID);
0299: getLogger().debug(messageBuffer.toString());
0300: }
0301: }
0302: }
0303:
0304: if (isRejectRecipientNotFound()) {
0305: rejectRecipientNotFound();
0306: return;
0307: }
0308: intendedRecipient = getRecipient();
0309: StringBuffer messageBuffer = new StringBuffer(
0310: "Intended recipient not found. Using configured recipient as new envelope recipient - ");
0311: messageBuffer.append(intendedRecipient);
0312: messageBuffer.append('.');
0313: logStatusInfo(messageBuffer.toString());
0314: }
0315:
0316: // Set the filter states
0317: setBlacklistedRecipient(isBlacklistedRecipient(intendedRecipient));
0318: setRemoteRecipient(!isLocalServer(intendedRecipient));
0319: setUserUndefined(!isLocalRecipient(intendedRecipient));
0320:
0321: // Apply the filters. Return if rejected
0322: if (isRejectBlacklisted() && isBlacklistedRecipient()) {
0323: rejectBlacklistedRecipient(intendedRecipient);
0324: return;
0325: }
0326:
0327: if (isRejectRemoteRecipient() && isRemoteRecipient()) {
0328: rejectRemoteRecipient(intendedRecipient);
0329: return;
0330: }
0331:
0332: if (isRejectUserUndefined() && isUserUndefined()) {
0333: rejectUserUndefined(intendedRecipient);
0334: return;
0335: }
0336:
0337: if (isRejectMaxMessageSizeExceeded()
0338: && isMaxMessageSizeExceeded().booleanValue()) {
0339: rejectMaxMessageSizeExceeded(getMessageIn().getSize());
0340: return;
0341: }
0342:
0343: if (isRejectRemoteReceivedHeaderInvalid()
0344: && isRemoteReceivedHeaderInvalid().booleanValue()) {
0345: rejectRemoteReceivedHeaderInvalid();
0346: return;
0347: }
0348:
0349: // Create the mail
0350: // If any of the mail addresses are malformed, we will get a
0351: // ParseException.
0352: // If the IP address and host name for the remote domain cannot
0353: // be found, we will get an UnknownHostException.
0354: // In both cases, we log the problem and
0355: // return. The message disposition is defined by the
0356: // <undeliverable> attributes.
0357: Mail mail = null;
0358: try {
0359: mail = createMail(createMessage(), intendedRecipient);
0360: } catch (ParseException ex) {
0361: handleParseException(ex);
0362: return;
0363: } catch (UnknownHostException ex) {
0364: handleUnknownHostException(ex);
0365: return;
0366: }
0367:
0368: addMailAttributes(mail);
0369: addErrorMessages(mail);
0370:
0371: // If this mail is bouncing move it to the ERROR repository
0372: if (isBouncing()) {
0373: handleBouncing(mail);
0374: return;
0375: }
0376:
0377: // OK, lets send that mail!
0378: sendMail(mail);
0379: }
0380:
0381: /**
0382: * Method rejectRemoteRecipient.
0383: * @param recipient
0384: * @throws MessagingException
0385: */
0386: protected void rejectRemoteRecipient(MailAddress recipient)
0387: throws MessagingException {
0388: // Update the flags of the received message
0389: if (!isLeaveRemoteRecipient())
0390: setMessageDeleted();
0391:
0392: if (isMarkRemoteRecipientSeen())
0393: setMessageSeen();
0394:
0395: StringBuffer messageBuffer = new StringBuffer(
0396: "Rejected mail intended for remote recipient: ");
0397: messageBuffer.append(recipient);
0398: messageBuffer.append('.');
0399: logStatusInfo(messageBuffer.toString());
0400:
0401: return;
0402: }
0403:
0404: /**
0405: * Method rejectBlacklistedRecipient.
0406: * @param recipient
0407: * @throws MessagingException
0408: */
0409: protected void rejectBlacklistedRecipient(MailAddress recipient)
0410: throws MessagingException {
0411: // Update the flags of the received message
0412: if (!isLeaveBlacklisted())
0413: setMessageDeleted();
0414: if (isMarkBlacklistedSeen())
0415: setMessageSeen();
0416:
0417: StringBuffer messageBuffer = new StringBuffer(
0418: "Rejected mail intended for blacklisted recipient: ");
0419: messageBuffer.append(recipient);
0420: messageBuffer.append('.');
0421: logStatusInfo(messageBuffer.toString());
0422:
0423: return;
0424: }
0425:
0426: /**
0427: * Method rejectRecipientNotFound.
0428: * @throws MessagingException
0429: */
0430: protected void rejectRecipientNotFound() throws MessagingException {
0431: // Update the flags of the received message
0432: if (!isLeaveRecipientNotFound())
0433: setMessageDeleted();
0434:
0435: if (isMarkRecipientNotFoundSeen())
0436: setMessageSeen();
0437:
0438: StringBuffer messageBuffer = new StringBuffer(
0439: "Rejected mail for which a sole intended recipient could not be found.");
0440: messageBuffer.append(" Recipients: ");
0441: Address[] allRecipients = getMessageIn().getAllRecipients();
0442: for (int i = 0; i < allRecipients.length; i++) {
0443: messageBuffer.append(allRecipients[i]);
0444: messageBuffer.append(' ');
0445: }
0446: messageBuffer.append('.');
0447: logStatusInfo(messageBuffer.toString());
0448: return;
0449: }
0450:
0451: /**
0452: * Method rejectUserUndefined.
0453: * @param recipient
0454: * @throws MessagingException
0455: */
0456: protected void rejectUserUndefined(MailAddress recipient)
0457: throws MessagingException {
0458: // Update the flags of the received message
0459: if (!isLeaveUserUndefined())
0460: setMessageDeleted();
0461:
0462: if (isMarkUserUndefinedSeen())
0463: setMessageSeen();
0464:
0465: StringBuffer messageBuffer = new StringBuffer(
0466: "Rejected mail intended for undefined user: ");
0467: messageBuffer.append(recipient);
0468: messageBuffer.append('.');
0469: logStatusInfo(messageBuffer.toString());
0470:
0471: return;
0472: }
0473:
0474: /**
0475: * Method rejectMaxMessageSizeExceeded.
0476: * @param message size
0477: * @throws MessagingException
0478: */
0479: protected void rejectMaxMessageSizeExceeded(int messageSize)
0480: throws MessagingException {
0481: // Update the flags of the received message
0482: if (!isLeaveMaxMessageSizeExceeded())
0483: setMessageDeleted();
0484:
0485: if (isMarkMaxMessageSizeExceededSeen())
0486: setMessageSeen();
0487:
0488: StringBuffer messageBuffer = new StringBuffer(
0489: "Rejected mail exceeding message size limit. Message size: ");
0490: messageBuffer.append(messageSize / 1024);
0491: messageBuffer.append("KB.");
0492: logStatusInfo(messageBuffer.toString());
0493:
0494: return;
0495: }
0496:
0497: /**
0498: * Method rejectRemoteReceivedHeaderInvalid.
0499: * @throws MessagingException
0500: */
0501: protected void rejectRemoteReceivedHeaderInvalid()
0502: throws MessagingException {
0503: // Update the flags of the received message
0504: if (!isLeaveRemoteReceivedHeaderInvalid())
0505: setMessageDeleted();
0506:
0507: if (isMarkRemoteReceivedHeaderInvalidSeen())
0508: setMessageSeen();
0509:
0510: StringBuffer messageBuffer = new StringBuffer(
0511: "Rejected mail with an invalid Received: header at index ");
0512: messageBuffer.append(getRemoteReceivedHeaderIndex());
0513: messageBuffer.append(".");
0514: logStatusInfo(messageBuffer.toString());
0515: return;
0516: }
0517:
0518: /**
0519: * <p>Method createMessage answers a new <code>MimeMessage</code> from the
0520: * fetched message.</p>
0521: *
0522: * <p>If the maximum message size is exceeded, an empty message is created,
0523: * else the new message is a copy of the received message.</p>
0524: *
0525: * @return MimeMessage
0526: * @throws MessagingException
0527: */
0528: protected MimeMessage createMessage() throws MessagingException {
0529: // Create a new messsage from the received message
0530: MimeMessage messageOut = null;
0531: if (isMaxMessageSizeExceeded().booleanValue())
0532: messageOut = createEmptyMessage();
0533: else
0534: messageOut = new MimeMessage(getMessageIn());
0535:
0536: // set the X-fetched headers
0537: // Note this is still required to detect bouncing mail and
0538: // for backwards compatibility with fetchPop
0539: messageOut.addHeader("X-fetched-from", getFetchTaskName());
0540:
0541: return messageOut;
0542: }
0543:
0544: /**
0545: * Method createEmptyMessage answers a new
0546: * <code>MimeMessage</code> from the fetched message with the message
0547: * contents removed.
0548: *
0549: * @return MimeMessage
0550: * @throws MessagingException
0551: */
0552: protected MimeMessage createEmptyMessage()
0553: throws MessagingException {
0554: // Create an empty messsage
0555: MimeMessage messageOut = new MimeMessage(getSession());
0556:
0557: // Propogate the headers and subject
0558: Enumeration headersInEnum = getMessageIn().getAllHeaderLines();
0559: while (headersInEnum.hasMoreElements())
0560: messageOut.addHeaderLine((String) headersInEnum
0561: .nextElement());
0562: messageOut.setSubject(getMessageIn().getSubject());
0563:
0564: // Add empty text
0565: messageOut.setText("");
0566:
0567: // Save
0568: messageOut.saveChanges();
0569:
0570: return messageOut;
0571: }
0572:
0573: /**
0574: * Method createMail creates a new <code>Mail</code>.
0575: *
0576: * @param message
0577: * @param recipient
0578: * @return Mail
0579: * @throws MessagingException
0580: */
0581: protected Mail createMail(MimeMessage message, MailAddress recipient)
0582: throws MessagingException, UnknownHostException {
0583: Collection recipients = new ArrayList(1);
0584: recipients.add(recipient);
0585: MailImpl mail = new MailImpl(getServer().getId(), getSender(),
0586: recipients, message);
0587: // Ensure the mail is created with non-null remote host name and address,
0588: // otherwise the Mailet chain may go splat!
0589: if (getRemoteAddress() == null || getRemoteHostName() == null) {
0590: mail.setRemoteAddr("127.0.0.1");
0591: mail.setRemoteHost("localhost");
0592: setDefaultRemoteAddress(true);
0593: logStatusInfo("Remote address could not be determined. Using localhost/127.0.0.1");
0594: } else {
0595: mail.setRemoteAddr(getRemoteAddress());
0596: mail.setRemoteHost(getRemoteHostName());
0597: setDefaultRemoteAddress(false);
0598: }
0599:
0600: if (getLogger().isDebugEnabled()) {
0601: StringBuffer messageBuffer = new StringBuffer(
0602: "Created mail with name: ");
0603: messageBuffer.append(mail.getName());
0604: messageBuffer.append(", sender: ");
0605: messageBuffer.append(mail.getSender());
0606: messageBuffer.append(", recipients: ");
0607: Iterator recipientIterator = mail.getRecipients()
0608: .iterator();
0609: while (recipientIterator.hasNext()) {
0610: messageBuffer.append(recipientIterator.next());
0611: messageBuffer.append(' ');
0612: }
0613: messageBuffer.append(", remote address: ");
0614: messageBuffer.append(mail.getRemoteAddr());
0615: messageBuffer.append(", remote host name: ");
0616: messageBuffer.append(mail.getRemoteHost());
0617: messageBuffer.append('.');
0618: getLogger().debug(messageBuffer.toString());
0619: }
0620: return mail;
0621: }
0622:
0623: /**
0624: * <p>
0625: * Method getSender answers a <code>MailAddress</code> for the sender.
0626: * When the sender local part and/or domain part can not be obtained
0627: * from the mail, default values are used. The flags
0628: * 'defaultSenderLocalPart' and 'defaultSenderDomainPart' are set
0629: * accordingly.
0630: * </p>
0631: *
0632: * @return MailAddress
0633: * @throws MessagingException
0634: */
0635: protected MailAddress getSender() throws MessagingException {
0636: String from = null;
0637: InternetAddress internetAddress = null;
0638:
0639: try {
0640: from = ((InternetAddress) getMessageIn().getFrom()[0])
0641: .getAddress().trim();
0642: setDefaultSenderLocalPart(false);
0643: } catch (Exception _) {
0644: from = getDefaultLocalPart();
0645: setDefaultSenderLocalPart(true);
0646: StringBuffer buffer = new StringBuffer(32);
0647: buffer
0648: .append("Sender localpart is absent. Using default value (");
0649: buffer.append(getDefaultLocalPart());
0650: buffer.append(')');
0651: logStatusInfo(buffer.toString());
0652: }
0653:
0654: // Check for domain part, add default if missing
0655: if (from.indexOf('@') < 0) {
0656: StringBuffer fromBuffer = new StringBuffer(from);
0657: fromBuffer.append('@');
0658: fromBuffer.append(getDefaultDomainName());
0659: internetAddress = new InternetAddress(fromBuffer.toString());
0660: setDefaultSenderDomainPart(true);
0661:
0662: StringBuffer buffer = new StringBuffer(32);
0663: buffer
0664: .append("Sender domain is absent. Using default value (");
0665: buffer.append(getDefaultDomainName());
0666: buffer.append(')');
0667: logStatusInfo(buffer.toString());
0668: } else {
0669: internetAddress = new InternetAddress(from);
0670: setDefaultSenderDomainPart(false);
0671: }
0672:
0673: return new MailAddress(internetAddress);
0674: }
0675:
0676: /**
0677: * <p>Method computeRemoteDomain answers a <code>String</code> that is the
0678: * RFC2822 compliant "Received : from" domain extracted from the message
0679: * being processed for the remote domain that sent the message.</p>
0680: *
0681: * <p>Often the remote domain is the domain that sent the message to the
0682: * host of the message store, the second "received" header, which has an
0683: * index of 1. Other times, messages may be received by a edge mail server
0684: * and relayed internally through one or more internal mail servers prior
0685: * to arriving at the message store host. In these cases the index is
0686: * 1 + the number of internal servers through which a mail passes.
0687: * </p>
0688: * <p>The index of the header to use is specified by the configuration
0689: * parameter <code>RemoteReceivedHeaderIndex</code>. This is set to
0690: * point to the received header prior to the remote mail server, the one
0691: * prior to the edge mail server.
0692: * </p>
0693: * <p>"received" headers are searched starting at the specified index.
0694: * If a domain in the "received" header is not found, successively closer
0695: * "received" headers are tried. If a domain is not found in this way, the
0696: * local machine is used as the domain. Finally, if the local domain cannot
0697: * be determined, the local address 127.0.0.1 is used.
0698: * </p>
0699: *
0700: * @return String An RFC2822 compliant "Received : from" domain name
0701: */
0702: protected String computeRemoteDomain() throws MessagingException {
0703: StringBuffer domainBuffer = new StringBuffer();
0704: String[] headers = null;
0705:
0706: if (getRemoteReceivedHeaderIndex() > -1)
0707: headers = getMessageIn().getHeader(RFC2822Headers.RECEIVED);
0708:
0709: // There are RECEIVED headers if the array is not null
0710: // and its length at is greater than 0
0711: boolean hasHeaders = (null == headers ? false
0712: : headers.length > 0);
0713:
0714: // If there are RECEIVED headers try and extract the domain
0715: if (hasHeaders) {
0716: final String headerTokens = " \n\r";
0717:
0718: // Search the headers for a domain
0719: for (int headerIndex = headers.length > getRemoteReceivedHeaderIndex() ? getRemoteReceivedHeaderIndex()
0720: : headers.length - 1; headerIndex >= 0
0721: && domainBuffer.length() == 0; headerIndex--) {
0722: // Find the "from" token
0723: StringTokenizer tokenizer = new StringTokenizer(
0724: headers[headerIndex], headerTokens);
0725: boolean inFrom = false;
0726: while (!inFrom && tokenizer.hasMoreTokens())
0727: inFrom = tokenizer.nextToken().equals("from");
0728: // Add subsequent tokens to the domain buffer until another
0729: // field is encountered or there are no more tokens
0730: while (inFrom && tokenizer.hasMoreTokens()) {
0731: String token = tokenizer.nextToken();
0732: if (inFrom = getRFC2822RECEIVEDHeaderFields()
0733: .indexOf(token) == -1) {
0734: domainBuffer.append(token);
0735: domainBuffer.append(' ');
0736: }
0737: }
0738: }
0739: }
0740: // If a domain was not found, the default is the local host and
0741: // if we cannot resolve this, the local address 127.0.0.1
0742: // Note that earlier versions of this code simply used 'localhost'
0743: // which works fine with java.net but is not resolved by dnsjava
0744: // which was introduced in v2.2.0. See Jira issue JAMES-302.
0745: if (domainBuffer.length() == 0) {
0746: try {
0747: InetAddress addr1 = java.net.InetAddress.getLocalHost();
0748: // These shenanigans are required to get the fully qualified
0749: // hostname prior to JDK 1.4 in which getCanonicalHostName()
0750: // does the job for us
0751: InetAddress addr2 = java.net.InetAddress
0752: .getByName(addr1.getHostAddress());
0753: InetAddress addr3 = java.net.InetAddress
0754: .getByName(addr2.getHostName());
0755: domainBuffer.append(addr3.getHostName());
0756: } catch (UnknownHostException ue) {
0757: domainBuffer.append("[127.0.0.1]");
0758: }
0759: }
0760: return domainBuffer.toString().trim();
0761: }
0762:
0763: /**
0764: * Method handleBouncing sets the Mail state to ERROR and delete from
0765: * the message store.
0766: *
0767: * @param mail
0768: */
0769: protected void handleBouncing(Mail mail) throws MessagingException {
0770: mail.setState(Mail.ERROR);
0771: setMessageDeleted();
0772:
0773: mail.setErrorMessage("This mail from FetchMail task "
0774: + getFetchTaskName() + " seems to be bouncing!");
0775: logStatusError("Message is bouncing! Deleted from message store and moved to the Error repository.");
0776: }
0777:
0778: /**
0779: * Method handleParseException.
0780: * @param ex
0781: * @throws MessagingException
0782: */
0783: protected void handleParseException(ParseException ex)
0784: throws MessagingException {
0785: // Update the flags of the received message
0786: if (!isLeaveUndeliverable())
0787: setMessageDeleted();
0788: if (isMarkUndeliverableSeen())
0789: setMessageSeen();
0790: logStatusWarn("Message could not be delivered due to an error parsing a mail address.");
0791: if (getLogger().isDebugEnabled()) {
0792: StringBuffer messageBuffer = new StringBuffer(
0793: "UNDELIVERABLE Message ID: ");
0794: messageBuffer.append(getMessageIn().getMessageID());
0795: getLogger().debug(messageBuffer.toString(), ex);
0796: }
0797: }
0798:
0799: /**
0800: * Method handleUnknownHostException.
0801: * @param ex
0802: * @throws MessagingException
0803: */
0804: protected void handleUnknownHostException(UnknownHostException ex)
0805: throws MessagingException {
0806: // Update the flags of the received message
0807: if (!isLeaveUndeliverable())
0808: setMessageDeleted();
0809:
0810: if (isMarkUndeliverableSeen())
0811: setMessageSeen();
0812:
0813: logStatusWarn("Message could not be delivered due to an error determining the remote domain.");
0814: if (getLogger().isDebugEnabled()) {
0815: StringBuffer messageBuffer = new StringBuffer(
0816: "UNDELIVERABLE Message ID: ");
0817: messageBuffer.append(getMessageIn().getMessageID());
0818: getLogger().debug(messageBuffer.toString(), ex);
0819: }
0820: }
0821:
0822: /**
0823: * Method isLocalRecipient.
0824: * @param recipient
0825: * @return boolean
0826: */
0827: protected boolean isLocalRecipient(MailAddress recipient) {
0828: return isLocalUser(recipient) && isLocalServer(recipient);
0829: }
0830:
0831: /**
0832: * Method isLocalServer.
0833: * @param recipient
0834: * @return boolean
0835: */
0836: protected boolean isLocalServer(MailAddress recipient) {
0837: return getServer().isLocalServer(recipient.getHost());
0838: }
0839:
0840: /**
0841: * Method isLocalUser.
0842: * @param recipient
0843: * @return boolean
0844: */
0845: protected boolean isLocalUser(MailAddress recipient) {
0846: return getLocalUsers().containsCaseInsensitive(
0847: recipient.getUser());
0848: }
0849:
0850: /**
0851: * Method isBlacklistedRecipient.
0852: * @param recipient
0853: * @return boolean
0854: */
0855: protected boolean isBlacklistedRecipient(MailAddress recipient) {
0856: return getBlacklist().contains(recipient);
0857: }
0858:
0859: /**
0860: * Check if this mail has been bouncing by counting the X-fetched-from
0861: * headers for this task
0862: *
0863: * @return boolean
0864: */
0865: protected boolean isBouncing() throws MessagingException {
0866: Enumeration enumeration = getMessageIn()
0867: .getMatchingHeaderLines(
0868: new String[] { "X-fetched-from" });
0869: int count = 0;
0870: while (enumeration.hasMoreElements()) {
0871: String header = (String) enumeration.nextElement();
0872: if (header.equals(getFetchTaskName()))
0873: count++;
0874: }
0875: return count >= 3;
0876: }
0877:
0878: /**
0879: * Method sendMail.
0880: * @param mail
0881: * @throws MessagingException
0882: */
0883: protected void sendMail(Mail mail) throws MessagingException {
0884: // send the mail
0885: getServer().sendMail(mail);
0886:
0887: // Update the flags of the received message
0888: if (!isLeave())
0889: setMessageDeleted();
0890:
0891: if (isMarkSeen())
0892: setMessageSeen();
0893:
0894: // Log the status
0895: StringBuffer messageBuffer = new StringBuffer(
0896: "Spooled message to recipients: ");
0897: Iterator recipientIterator = mail.getRecipients().iterator();
0898: while (recipientIterator.hasNext()) {
0899: messageBuffer.append(recipientIterator.next());
0900: messageBuffer.append(' ');
0901: }
0902: messageBuffer.append('.');
0903: logStatusInfo(messageBuffer.toString());
0904: }
0905:
0906: /**
0907: * Method getEnvelopeRecipient answers the recipient if found else null.
0908: *
0909: * Try and parse the "for" parameter from a Received header
0910: * Maybe not the most accurate parsing in the world but it should do
0911: * I opted not to use ORO (maybe I should have)
0912: *
0913: * @param msg
0914: * @return String
0915: */
0916:
0917: protected String getEnvelopeRecipient(MimeMessage msg)
0918: throws MessagingException {
0919: String res = getCustomRecipientHeader();
0920: if (res != null && res.length() > 0) {
0921: String[] headers = msg
0922: .getHeader(getCustomRecipientHeader());
0923: if (headers != null) {
0924: String mailFor = headers[0];
0925: if (mailFor.startsWith("<") && mailFor.endsWith(">"))
0926: mailFor = mailFor.substring(1,
0927: (mailFor.length() - 1));
0928: return mailFor;
0929: }
0930: } else {
0931: try {
0932: Enumeration enumeration = msg
0933: .getMatchingHeaderLines(new String[] { "Received" });
0934: while (enumeration.hasMoreElements()) {
0935: String received = (String) enumeration
0936: .nextElement();
0937:
0938: int nextSearchAt = 0;
0939: int i = 0;
0940: int start = 0;
0941: int end = 0;
0942: boolean hasBracket = false;
0943: boolean usableAddress = false;
0944: while (!usableAddress && (i != -1)) {
0945: hasBracket = false;
0946: i = received.indexOf("for ", nextSearchAt);
0947: if (i > 0) {
0948: start = i + 4;
0949: end = 0;
0950: nextSearchAt = start;
0951: for (int c = start; c < received.length(); c++) {
0952: char ch = received.charAt(c);
0953: switch (ch) {
0954: case '<':
0955: hasBracket = true;
0956: continue;
0957: case '@':
0958: usableAddress = true;
0959: continue;
0960: case ' ':
0961: end = c;
0962: break;
0963: case ';':
0964: end = c;
0965: break;
0966: }
0967: if (end > 0)
0968: break;
0969: }
0970: }
0971: }
0972: if (usableAddress) {
0973: // lets try and grab the email address
0974: String mailFor = received.substring(start, end);
0975:
0976: // strip the <> around the address if there are any
0977: if (mailFor.startsWith("<")
0978: && mailFor.endsWith(">"))
0979: mailFor = mailFor.substring(1, (mailFor
0980: .length() - 1));
0981:
0982: return mailFor;
0983: }
0984: }
0985: } catch (MessagingException me) {
0986: logStatusWarn("No Received headers found.");
0987: }
0988: }
0989: return null;
0990: }
0991:
0992: /**
0993: * Method getIntendedRecipient answers the sole intended recipient else null.
0994: *
0995: * @return MailAddress
0996: * @throws MessagingException
0997: */
0998: protected MailAddress getIntendedRecipient()
0999: throws MessagingException {
1000: // If the original recipient should be ignored, answer the
1001: // hard-coded recipient
1002: if (isIgnoreRecipientHeader()) {
1003: StringBuffer messageBuffer = new StringBuffer(
1004: "Ignoring recipient header. Using configured recipient as new envelope recipient: ");
1005: messageBuffer.append(getRecipient());
1006: messageBuffer.append('.');
1007: logStatusInfo(messageBuffer.toString());
1008: return getRecipient();
1009: }
1010:
1011: // If we can determine who the message was received for, answer
1012: // the target recipient
1013: String targetRecipient = getEnvelopeRecipient(getMessageIn());
1014: if (targetRecipient != null) {
1015: MailAddress recipient = new MailAddress(targetRecipient);
1016: StringBuffer messageBuffer = new StringBuffer(
1017: "Using original envelope recipient as new envelope recipient: ");
1018: messageBuffer.append(recipient);
1019: messageBuffer.append('.');
1020: logStatusInfo(messageBuffer.toString());
1021: return recipient;
1022: }
1023:
1024: // If we can determine the intended recipient from all of the recipients,
1025: // answer the intended recipient. This requires that there is exactly one
1026: // recipient answered by getAllRecipients(), which examines the TO: CC: and
1027: // BCC: headers
1028: Address[] allRecipients = getMessageIn().getAllRecipients();
1029: if (allRecipients.length == 1) {
1030: MailAddress recipient = new MailAddress(
1031: (InternetAddress) allRecipients[0]);
1032: StringBuffer messageBuffer = new StringBuffer(
1033: "Using sole recipient header address as new envelope recipient: ");
1034: messageBuffer.append(recipient);
1035: messageBuffer.append('.');
1036: logStatusInfo(messageBuffer.toString());
1037: return recipient;
1038: }
1039:
1040: return null;
1041: }
1042:
1043: /**
1044: * Returns the messageIn.
1045: * @return MimeMessage
1046: */
1047: protected MimeMessage getMessageIn() {
1048: return fieldMessageIn;
1049: }
1050:
1051: /**
1052: * Sets the messageIn.
1053: * @param messageIn The messageIn to set
1054: */
1055: protected void setMessageIn(MimeMessage messageIn) {
1056: fieldMessageIn = messageIn;
1057: }
1058:
1059: /**
1060: * Returns the localRecipient.
1061: * @return boolean
1062: */
1063: protected boolean isRemoteRecipient() {
1064: return fieldRemoteRecipient;
1065: }
1066:
1067: /**
1068: * Returns <code>boolean</code> indicating if the message to be delivered
1069: * was unprocessed in a previous delivery attempt.
1070: * @return boolean
1071: */
1072: protected boolean isPreviouslyUnprocessed() {
1073: return true;
1074: }
1075:
1076: /**
1077: * Log the status of the current message as INFO.
1078: * @param detailMsg
1079: */
1080: protected void logStatusInfo(String detailMsg)
1081: throws MessagingException {
1082: getLogger().info(getStatusReport(detailMsg).toString());
1083: }
1084:
1085: /**
1086: * Log the status the current message as WARN.
1087: * @param detailMsg
1088: */
1089: protected void logStatusWarn(String detailMsg)
1090: throws MessagingException {
1091: getLogger().warn(getStatusReport(detailMsg).toString());
1092: }
1093:
1094: /**
1095: * Log the status the current message as ERROR.
1096: * @param detailMsg
1097: */
1098: protected void logStatusError(String detailMsg)
1099: throws MessagingException {
1100: getLogger().error(getStatusReport(detailMsg).toString());
1101: }
1102:
1103: /**
1104: * Answer a <code>StringBuffer</code> containing a message reflecting
1105: * the current status of the message being processed.
1106: *
1107: * @param detailMsg
1108: * @return StringBuffer
1109: */
1110: protected StringBuffer getStatusReport(String detailMsg)
1111: throws MessagingException {
1112: StringBuffer messageBuffer = new StringBuffer(detailMsg);
1113: if (detailMsg.length() > 0)
1114: messageBuffer.append(' ');
1115: messageBuffer.append("Message ID: ");
1116: messageBuffer.append(getMessageIn().getMessageID());
1117: messageBuffer.append(". Flags: Seen = ");
1118: messageBuffer.append(new Boolean(isMessageSeen()));
1119: messageBuffer.append(", Delete = ");
1120: messageBuffer.append(new Boolean(isMessageDeleted()));
1121: messageBuffer.append('.');
1122: return messageBuffer;
1123: }
1124:
1125: /**
1126: * Returns the userUndefined.
1127: * @return boolean
1128: */
1129: protected boolean isUserUndefined() {
1130: return fieldUserUndefined;
1131: }
1132:
1133: /**
1134: * Is the DELETED flag set?
1135: * @throws MessagingException
1136: */
1137: protected boolean isMessageDeleted() throws MessagingException {
1138: return getMessageIn().isSet(Flags.Flag.DELETED);
1139: }
1140:
1141: /**
1142: * Is the SEEN flag set?
1143: * @throws MessagingException
1144: */
1145: protected boolean isMessageSeen() throws MessagingException {
1146: return getMessageIn().isSet(Flags.Flag.SEEN);
1147: }
1148:
1149: /**
1150: * Set the DELETED flag.
1151: * @throws MessagingException
1152: */
1153: protected void setMessageDeleted() throws MessagingException {
1154: getMessageIn().setFlag(Flags.Flag.DELETED, true);
1155: }
1156:
1157: /* /**
1158: * Set the SEEN flag.
1159: * @throws MessagingException
1160: */
1161: protected void setMessageSeen() throws MessagingException {
1162: // If the Seen flag is not handled by the folder
1163: // allow a handler to do whatever it deems necessary
1164: if (!getMessageIn().getFolder().getPermanentFlags().contains(
1165: Flags.Flag.SEEN))
1166: handleMarkSeenNotPermanent();
1167: else
1168: getMessageIn().setFlag(Flags.Flag.SEEN, true);
1169: }
1170:
1171: /**
1172: * <p>Handler for when the folder does not support the SEEN flag.
1173: * The default behaviour implemented here is to log a warning and set the
1174: * flag anyway.</p>
1175: *
1176: * <p> Subclasses may choose to override this and implement their own
1177: * solutions.</p>
1178: *
1179: * @throws MessagingException
1180: */
1181: protected void handleMarkSeenNotPermanent()
1182: throws MessagingException {
1183: getMessageIn().setFlag(Flags.Flag.SEEN, true);
1184: logStatusWarn("Message marked as SEEN, but the folder does not support a permanent SEEN flag.");
1185: }
1186:
1187: /**
1188: * Returns the Blacklisted.
1189: * @return boolean
1190: */
1191: protected boolean isBlacklistedRecipient() {
1192: return fieldBlacklistedRecipient;
1193: }
1194:
1195: /**
1196: * Sets the localRecipient.
1197: * @param localRecipient The localRecipient to set
1198: */
1199: protected void setRemoteRecipient(boolean localRecipient) {
1200: fieldRemoteRecipient = localRecipient;
1201: }
1202:
1203: /**
1204: * Sets the userUndefined.
1205: * @param userUndefined The userUndefined to set
1206: */
1207: protected void setUserUndefined(boolean userUndefined) {
1208: fieldUserUndefined = userUndefined;
1209: }
1210:
1211: /**
1212: * Adds the mail attributes to a <code>Mail</code>.
1213: * @param aMail a Mail instance
1214: */
1215: protected void addMailAttributes(Mail aMail)
1216: throws MessagingException {
1217: aMail.setAttribute(getAttributePrefix() + "taskName",
1218: getFetchTaskName());
1219:
1220: aMail.setAttribute(getAttributePrefix() + "folderName",
1221: getMessageIn().getFolder().getFullName());
1222:
1223: if (isRemoteRecipient())
1224: aMail.setAttribute(getAttributePrefix()
1225: + "isRemoteRecipient", null);
1226:
1227: if (isUserUndefined())
1228: aMail.setAttribute(
1229: getAttributePrefix() + "isUserUndefined", null);
1230:
1231: if (isBlacklistedRecipient())
1232: aMail.setAttribute(getAttributePrefix()
1233: + "isBlacklistedRecipient", null);
1234:
1235: if (isRecipientNotFound())
1236: aMail.setAttribute(getAttributePrefix()
1237: + "isRecipientNotFound", null);
1238:
1239: if (isMaxMessageSizeExceeded().booleanValue())
1240: aMail.setAttribute(getAttributePrefix()
1241: + "isMaxMessageSizeExceeded", new Integer(
1242: getMessageIn().getSize()).toString());
1243:
1244: if (isRemoteReceivedHeaderInvalid().booleanValue())
1245: aMail.setAttribute(getAttributePrefix()
1246: + "isRemoteReceivedHeaderInvalid", null);
1247:
1248: if (isDefaultSenderLocalPart())
1249: aMail.setAttribute(getAttributePrefix()
1250: + "isDefaultSenderLocalPart", null);
1251:
1252: if (isDefaultSenderDomainPart())
1253: aMail.setAttribute(getAttributePrefix()
1254: + "isDefaultSenderDomainPart", null);
1255:
1256: if (isDefaultRemoteAddress())
1257: aMail.setAttribute(getAttributePrefix()
1258: + "isDefaultRemoteAddress", null);
1259: }
1260:
1261: /**
1262: * Adds any required error messages to a <code>Mail</code>.
1263: * @param aMail a Mail instance
1264: */
1265: protected void addErrorMessages(Mail mail)
1266: throws MessagingException {
1267: if (isMaxMessageSizeExceeded().booleanValue()) {
1268: StringBuffer msgBuffer = new StringBuffer(
1269: "550 - Rejected - This message has been rejected as the message size of ");
1270: msgBuffer
1271: .append(getMessageIn().getSize() * 1000 / 1024 / 1000f);
1272: msgBuffer
1273: .append("KB exceeds the maximum permitted size of ");
1274: msgBuffer.append(getMaxMessageSizeLimit() / 1024);
1275: msgBuffer.append("KB.");
1276: mail.setErrorMessage(msgBuffer.toString());
1277: }
1278: }
1279:
1280: /**
1281: * Sets the Blacklisted.
1282: * @param blacklisted The blacklisted to set
1283: */
1284: protected void setBlacklistedRecipient(boolean blacklisted) {
1285: fieldBlacklistedRecipient = blacklisted;
1286: }
1287:
1288: /**
1289: * Returns the recipientNotFound.
1290: * @return boolean
1291: */
1292: protected boolean isRecipientNotFound() {
1293: return fieldRecipientNotFound;
1294: }
1295:
1296: /**
1297: * Sets the recipientNotFound.
1298: * @param recipientNotFound The recipientNotFound to set
1299: */
1300: protected void setRecipientNotFound(boolean recipientNotFound) {
1301: fieldRecipientNotFound = recipientNotFound;
1302: }
1303:
1304: /**
1305: * Returns the remoteDomain, lazily initialised as required.
1306: * @return String
1307: */
1308: protected String getRemoteDomain() throws MessagingException {
1309:
1310: String remoteDomain;
1311: if (null == (remoteDomain = getRemoteDomainBasic())) {
1312: updateRemoteDomain();
1313: return getRemoteDomain();
1314: }
1315: return remoteDomain;
1316: }
1317:
1318: /**
1319: * Returns the remoteDomain.
1320: * @return String
1321: */
1322: private String getRemoteDomainBasic() {
1323: return fieldRemoteDomain;
1324: }
1325:
1326: /**
1327: * Sets the remoteDomain.
1328: * @param remoteDomain The remoteDomain to set
1329: */
1330: protected void setRemoteDomain(String remoteDomain) {
1331: fieldRemoteDomain = remoteDomain;
1332: }
1333:
1334: /**
1335: * Updates the remoteDomain.
1336: */
1337: protected void updateRemoteDomain() throws MessagingException {
1338: setRemoteDomain(computeRemoteDomain());
1339: }
1340:
1341: /**
1342: * Answer the IP Address of the remote server for the message being
1343: * processed.
1344: * @return String
1345: * @throws MessagingException
1346: * @throws UnknownHostException
1347: */
1348: protected String computeRemoteAddress() throws MessagingException,
1349: UnknownHostException {
1350: String domain = getRemoteDomain();
1351: String address = null;
1352: String validatedAddress = null;
1353: int ipAddressStart = domain.indexOf('[');
1354: int ipAddressEnd = -1;
1355: if (ipAddressStart > -1)
1356: ipAddressEnd = domain.indexOf(']', ipAddressStart);
1357: if (ipAddressEnd > -1)
1358: address = domain
1359: .substring(ipAddressStart + 1, ipAddressEnd);
1360: else {
1361: int hostNameEnd = domain.indexOf(' ');
1362: if (hostNameEnd == -1)
1363: hostNameEnd = domain.length();
1364: address = domain.substring(0, hostNameEnd);
1365: }
1366: validatedAddress = org.apache.james.dnsserver.DNSServer
1367: .getByName(address).getHostAddress();
1368:
1369: return validatedAddress;
1370: }
1371:
1372: /**
1373: * Answer the Canonical host name of the remote server for the message
1374: * being processed.
1375: * @return String
1376: * @throws MessagingException
1377: * @throws UnknownHostException
1378: */
1379: protected String computeRemoteHostName() throws MessagingException,
1380: UnknownHostException {
1381: // These shenanigans are required to get the fully qualified
1382: // hostname prior to JDK 1.4 in which get getCanonicalHostName()
1383: // does the job for us
1384: InetAddress addr1 = org.apache.james.dnsserver.DNSServer
1385: .getByName(getRemoteAddress());
1386: InetAddress addr2 = org.apache.james.dnsserver.DNSServer
1387: .getByName(addr1.getHostAddress());
1388: return addr2.getHostName();
1389: }
1390:
1391: /**
1392: * Returns the remoteAddress, lazily initialised as required.
1393: * @return String
1394: */
1395: protected String getRemoteAddress() throws MessagingException,
1396: UnknownHostException {
1397: String remoteAddress;
1398: if (null == (remoteAddress = getRemoteAddressBasic())) {
1399: updateRemoteAddress();
1400: return getRemoteAddress();
1401: }
1402: return remoteAddress;
1403: }
1404:
1405: /**
1406: * Returns the remoteAddress.
1407: * @return String
1408: */
1409: private String getRemoteAddressBasic() {
1410: return fieldRemoteAddress;
1411: }
1412:
1413: /**
1414: * Returns the remoteHostName, lazily initialised as required.
1415: * @return String
1416: */
1417: protected String getRemoteHostName() throws MessagingException,
1418: UnknownHostException {
1419: String remoteHostName;
1420: if (null == (remoteHostName = getRemoteHostNameBasic())) {
1421: updateRemoteHostName();
1422: return getRemoteHostName();
1423: }
1424: return remoteHostName;
1425: }
1426:
1427: /**
1428: * Returns the remoteHostName.
1429: * @return String
1430: */
1431: private String getRemoteHostNameBasic() {
1432: return fieldRemoteHostName;
1433: }
1434:
1435: /**
1436: * Sets the remoteAddress.
1437: * @param remoteAddress The remoteAddress to set
1438: */
1439: protected void setRemoteAddress(String remoteAddress) {
1440: fieldRemoteAddress = remoteAddress;
1441: }
1442:
1443: /**
1444: * Updates the remoteAddress.
1445: */
1446: protected void updateRemoteAddress() throws MessagingException,
1447: UnknownHostException {
1448: setRemoteAddress(computeRemoteAddress());
1449: }
1450:
1451: /**
1452: * Sets the remoteHostName.
1453: * @param remoteHostName The remoteHostName to set
1454: */
1455: protected void setRemoteHostName(String remoteHostName) {
1456: fieldRemoteHostName = remoteHostName;
1457: }
1458:
1459: /**
1460: * Updates the remoteHostName.
1461: */
1462: protected void updateRemoteHostName() throws MessagingException,
1463: UnknownHostException {
1464: setRemoteHostName(computeRemoteHostName());
1465: }
1466:
1467: /**
1468: * Returns the rFC2822RECEIVEDHeaderFields.
1469: * @return String
1470: */
1471: public static String getRFC2822RECEIVEDHeaderFields() {
1472: return fieldRFC2822RECEIVEDHeaderFields;
1473: }
1474:
1475: /**
1476: * Returns the maxMessageSizeExceeded, lazily initialised as required.
1477: * @return Boolean
1478: */
1479: protected Boolean isMaxMessageSizeExceeded()
1480: throws MessagingException {
1481: Boolean isMaxMessageSizeExceeded = null;
1482: if (null == (isMaxMessageSizeExceeded = isMaxMessageSizeExceededBasic())) {
1483: updateMaxMessageSizeExceeded();
1484: return isMaxMessageSizeExceeded();
1485: }
1486: return isMaxMessageSizeExceeded;
1487: }
1488:
1489: /**
1490: * Refreshes the maxMessageSizeExceeded.
1491: */
1492: protected void updateMaxMessageSizeExceeded()
1493: throws MessagingException {
1494: setMaxMessageSizeExceeded(computeMaxMessageSizeExceeded());
1495: }
1496:
1497: /**
1498: * Compute the maxMessageSizeExceeded.
1499: * @return Boolean
1500: */
1501: protected Boolean computeMaxMessageSizeExceeded()
1502: throws MessagingException {
1503: if (0 == getMaxMessageSizeLimit())
1504: return Boolean.FALSE;
1505: return new Boolean(
1506: getMessageIn().getSize() > getMaxMessageSizeLimit());
1507: }
1508:
1509: /**
1510: * Returns the maxMessageSizeExceeded.
1511: * @return Boolean
1512: */
1513: private Boolean isMaxMessageSizeExceededBasic() {
1514: return fieldMaxMessageSizeExceeded;
1515: }
1516:
1517: /**
1518: * Sets the maxMessageSizeExceeded.
1519: * @param maxMessageSizeExceeded The maxMessageSizeExceeded to set
1520: */
1521: protected void setMaxMessageSizeExceeded(
1522: Boolean maxMessageSizeExceeded) {
1523: fieldMaxMessageSizeExceeded = maxMessageSizeExceeded;
1524: }
1525:
1526: /**
1527: * Returns the remoteReceivedHeaderInvalid, lazily initialised.
1528: * @return Boolean
1529: */
1530: protected Boolean isRemoteReceivedHeaderInvalid()
1531: throws MessagingException {
1532: Boolean isInvalid = null;
1533: if (null == (isInvalid = isRemoteReceivedHeaderInvalidBasic())) {
1534: updateRemoteReceivedHeaderInvalid();
1535: return isRemoteReceivedHeaderInvalid();
1536: }
1537: return isInvalid;
1538: }
1539:
1540: /**
1541: * Computes the remoteReceivedHeaderInvalid.
1542: * @return Boolean
1543: */
1544: protected Boolean computeRemoteReceivedHeaderInvalid()
1545: throws MessagingException {
1546: Boolean isInvalid = Boolean.FALSE;
1547: try {
1548: getRemoteAddress();
1549: } catch (UnknownHostException e) {
1550: isInvalid = Boolean.TRUE;
1551: }
1552: return isInvalid;
1553: }
1554:
1555: /**
1556: * Returns the remoteReceivedHeaderInvalid.
1557: * @return Boolean
1558: */
1559: private Boolean isRemoteReceivedHeaderInvalidBasic() {
1560: return fieldRemoteReceivedHeaderInvalid;
1561: }
1562:
1563: /**
1564: * Sets the remoteReceivedHeaderInvalid.
1565: * @param remoteReceivedHeaderInvalid The remoteReceivedHeaderInvalid to set
1566: */
1567: protected void setRemoteReceivedHeaderInvalid(
1568: Boolean remoteReceivedHeaderInvalid) {
1569: fieldRemoteReceivedHeaderInvalid = remoteReceivedHeaderInvalid;
1570: }
1571:
1572: /**
1573: * Updates the remoteReceivedHeaderInvalid.
1574: */
1575: protected void updateRemoteReceivedHeaderInvalid()
1576: throws MessagingException {
1577: setRemoteReceivedHeaderInvalid(computeRemoteReceivedHeaderInvalid());
1578: }
1579:
1580: /**
1581: * Returns the defaultSenderDomainPart.
1582: * @return boolean
1583: */
1584: protected boolean isDefaultSenderDomainPart() {
1585: return fieldDefaultSenderDomainPart;
1586: }
1587:
1588: /**
1589: * Returns the defaultSenderLocalPart.
1590: * @return boolean
1591: */
1592: protected boolean isDefaultSenderLocalPart() {
1593: return fieldDefaultSenderLocalPart;
1594: }
1595:
1596: /**
1597: * Sets the defaultSenderDomainPart.
1598: * @param defaultSenderDomainPart The defaultSenderDomainPart to set
1599: */
1600: protected void setDefaultSenderDomainPart(
1601: boolean defaultSenderDomainPart) {
1602: fieldDefaultSenderDomainPart = defaultSenderDomainPart;
1603: }
1604:
1605: /**
1606: * Sets the defaultSenderLocalPart.
1607: * @param defaultSenderLocalPart The defaultSenderLocalPart to set
1608: */
1609: protected void setDefaultSenderLocalPart(
1610: boolean defaultSenderLocalPart) {
1611: fieldDefaultSenderLocalPart = defaultSenderLocalPart;
1612: }
1613:
1614: /**
1615: * Returns the defaultRemoteAddress.
1616: * @return boolean
1617: */
1618: protected boolean isDefaultRemoteAddress() {
1619: return fieldDefaultRemoteAddress;
1620: }
1621:
1622: /**
1623: * Sets the defaultRemoteAddress.
1624: * @param defaultRemoteAddress The defaultRemoteAddress to set
1625: */
1626: protected void setDefaultRemoteAddress(boolean defaultRemoteAddress) {
1627: fieldDefaultRemoteAddress = defaultRemoteAddress;
1628: }
1629:
1630: }
|