PageRenderTime 183ms CodeModel.GetById 18ms app.highlight 123ms RepoModel.GetById 0ms app.codeStats 1ms

/projects/james-2.2.0/src/java/org/apache/james/fetchmail/MessageProcessor.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1494 lines | 807 code | 148 blank | 539 comment | 105 complexity | dc53f165ce25e96fd530c7fe881a4409 MD5 | raw file
   1/***********************************************************************
   2 * Copyright (c) 2003-2004 The Apache Software Foundation.             *
   3 * All rights reserved.                                                *
   4 * ------------------------------------------------------------------- *
   5 * Licensed under the Apache License, Version 2.0 (the "License"); you *
   6 * may not use this file except in compliance with the License. You    *
   7 * may obtain a copy of the License at:                                *
   8 *                                                                     *
   9 *     http://www.apache.org/licenses/LICENSE-2.0                      *
  10 *                                                                     *
  11 * Unless required by applicable law or agreed to in writing, software *
  12 * distributed under the License is distributed on an "AS IS" BASIS,   *
  13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
  14 * implied.  See the License for the specific language governing       *
  15 * permissions and limitations under the License.                      *
  16 ***********************************************************************/
  17 
  18package org.apache.james.fetchmail;
  19
  20import java.io.InputStream;
  21import java.net.InetAddress;
  22import java.net.UnknownHostException;
  23import java.util.ArrayList;
  24import java.util.Collection;
  25import java.util.Enumeration;
  26import java.util.Iterator;
  27import java.util.StringTokenizer;
  28
  29import javax.mail.Address;
  30import javax.mail.Flags;
  31import javax.mail.Folder;
  32import javax.mail.MessagingException;
  33import javax.mail.Session;
  34import javax.mail.internet.InternetAddress;
  35import javax.mail.internet.InternetHeaders;
  36import javax.mail.internet.MimeMessage;
  37import javax.mail.internet.ParseException;
  38
  39import org.apache.james.core.MailImpl;
  40import org.apache.james.util.RFC2822Headers;
  41import org.apache.mailet.Mail;
  42import org.apache.mailet.MailAddress;
  43
  44/**
  45 * <p>Class <code>MessageProcessor</code> handles the delivery of 
  46 * <code>MimeMessages</code> to the James input spool.</p>
  47 * 
  48 * <p>Messages written to the input spool always have the following Mail
  49 * Attributes set:</p>
  50 * <dl>
  51 * <dt>org.apache.james.fetchmail.taskName (java.lang.String)</dt>
  52 *      <dd>The name of the fetch task that processed the message</dd>
  53 * <dt>org.apache.james.fetchmail.folderName (java.lang.String)</dt>
  54 *      <dd>The name of the folder from which the message was fetched</dd>
  55 * </dl>
  56 * 
  57 * <p>Messages written to the input spool have the following Mail Attributes
  58 *  set if the corresponding condition is satisfied:
  59 * <dl>
  60 * <dt>org.apache.james.fetchmail.isBlacklistedRecipient</dt>
  61 *      <dd>The recipient is in the configured blacklist</dd>
  62 * <dt>org.apache.james.fetchmail.isMaxMessageSizeExceeded (java.lang.String)</dt>
  63 *      <dd>The message size exceeds the configured limit. An empty message is
  64 *          written to the input spool. The Mail Attribute value is a String
  65 *          representing the size of the original message in bytes.</dd>
  66 * <dt>org.apache.james.fetchmail.isRecipientNotFound</dt>
  67 *      <dd>The recipient could not be found. Delivery is to the configured recipient. 
  68 *          See the discussion of delivery to a sole intended recipient below.</dd>
  69 * <dt>org.apache.james.fetchmail.isRemoteRecievedHeaderInvalid</dt>
  70 *       <dd>The Receieved header at the index specified by parameter
  71 *       <code>remoteReceivedHeaderIndex</code> is invalid.</dd>
  72 * <dt>org.apache.james.fetchmail.isRemoteRecipient</dt>
  73 *      <dd>The recipient is on a remote host</dd>
  74 * <dt>org.apache.james.fetchmail.isUserUndefined</dt>
  75 *      <dd>The recipient is on a localhost but not defined to James</dd>
  76 * </dl>
  77 * 
  78 * <p>Configuration settings -
  79 *  see <code>org.apache.james.fetchmail.ParsedConfiguration</code>
  80 * - control the messages that are written to the James input spool, those that
  81 * are rejected and what happens to messages that are rejected.</p>
  82 * 
  83 * <p>Rejection processing is based on the following filters:</p>
  84 * <dl> 
  85 * <dt>RejectRemoteRecipient</dt> 
  86 *      <dd>Rejects recipients on remote hosts</dd>
  87 * <dt>RejectBlacklistedRecipient</dt>
  88 *      <dd>Rejects recipients configured in a blacklist</dd>
  89 * <dt>RejectUserUndefined</dt>
  90 *      <dd>Rejects recipients on local hosts who are not defined as James users</dd>
  91 * <dt>RejectRecipientNotFound</dt>
  92 *      <dd>See the discussion of delivery to a sole intended recipient below</dd>
  93 * <dt>RejectMaxMessageSizeExceeded</dt>
  94 *      <dd>Rejects messages whose size exceeds the configured limit</dd>
  95 * <dt>RejectRemoteReceievedHeaderInvalid</dt>
  96 *      <dd>Rejects messages whose Received header is invalid.</dd>
  97 * </dl>
  98 * 
  99 * <p>Rejection processing is intentionally limited to managing the status of the
 100 * messages that are rejected on the server from which they were fetched. View
 101 * it as a simple automation of the manual processing an end-user would perform 
 102 * through a mail client. Messages may be marked as seen or be deleted.</p> 
 103 * 
 104 * <p>Further processing can be achieved by configuring to disable rejection for 
 105 * one or more filters. This enables Messages that would have been rejected to
 106 * be written to the James input spool. The conditional Mail Attributes 
 107 * described above identify the filter states. The Matcher/Mailet chain can 
 108 * then be used to perform any further processing required, such as notifying
 109 * the Postmaster and/or sender, marking the message for error processing, etc.</p>
 110 * 
 111 * <p>Note that in the case of a message exceeding the message size limit, the
 112 * message that is written to the input spool has no content. This enables 
 113 * configuration of a mailet notifying the sender that their mail has not been
 114 * delivered due to its size while maintaining the purpose of the filter which is
 115 * to avoid injecting excessively large messages into the input spool.</p>
 116 * 
 117 * <p>Delivery is to a sole intended recipient. The recipient is determined in the
 118 * following manner:</p>
 119 *
 120 * <ol> 
 121 * <li>If isIgnoreIntendedRecipient(), use the configured recipient</li>
 122 * <li>If the Envelope contains a for: stanza, use the recipient in the stanza</li>
 123 * <li>If the Message has a sole intended recipient, use this recipient</li>
 124 * <li>If not rejectRecipientNotFound(), use the configured recipient</li>
 125 * </ol>
 126 * 
 127 * <p>If a recipient cannot be determined after these steps, the message is 
 128 * rejected.</p>
 129 * 
 130 * <p>Every delivered message CURRENTLY has an "X-fetched-from" header added 
 131 * containing the name of the fetch task. Its primary uses are to detect bouncing
 132 * mail and provide backwards compatibility with the fetchPop task that inserted
 133 * this header to enable injected messages to be detected in the Matcher/Mailet 
 134 * chain. This header is DEPRECATED and WILL BE REMOVED in a future version of 
 135 * fetchmail. Use the Mail Attribute <code>org.apache.james.fetchmail.taskName</code>
 136 * instead.
 137 * 
 138 * <p><code>MessageProcessor</code> is as agnostic as it can be about the format
 139 * and contents of the messages it delivers. There are no RFCs that govern its
 140 * behavior. The most releveant RFCs relate to the exchange of messages between
 141 * MTA servers, but not POP3 or IMAP servers which are normally end-point
 142 * servers and not expected to re-inject mail into MTAs. None the less, the
 143 * intent is to conform to the 'spirit' of the RFCs.
 144 * <code>MessageProcessor</code> relies on the MTA (James in this
 145 * implementation) to manage and validate the injected mail just as it would
 146 * when receiving mail from an upstream MTA.</p> 
 147 * 
 148 * <p>The only correction applied by <code>MessageProcessor</code> is to correct a
 149 * partial originator address. If the originator address has a valid user part
 150 * but no domain part, a domain part is added. The added domain is either the 
 151 * default domain specified in the configuration, or if not specified, the 
 152 * fully qualified name of the machine on which the fetch task is running.</p>
 153 * 
 154 * <p>The status of messages on the server from which they were fetched that 
 155 * cannot be injected into the input spool due to non-correctable errors is 
 156 * determined by the undeliverable configuration options.</p>
 157 * 
 158 * <p>Creation Date: 27-May-03</p>
 159 *
 160 */
 161public class MessageProcessor extends ProcessorAbstract
 162{
 163    private MimeMessage fieldMessageIn;
 164
 165    /**
 166     * Recipient cannot be found
 167     */ 
 168    private boolean fieldRecipientNotFound = false;
 169
 170    /**
 171     * Recipient is a local user on a local host
 172     */ 
 173    private boolean fieldRemoteRecipient = true;
 174
 175    /**
 176     * The mail's Received header at index remoteReceivedHeaderIndex is invalid.
 177     */     
 178    private Boolean fieldRemoteReceivedHeaderInvalid;
 179
 180    /**
 181     * Recipient is not a local user
 182     */ 
 183    private boolean fieldUserUndefined = false;
 184    
 185    /**
 186     * The Maximum Message has been exceeded
 187     */ 
 188    private Boolean fieldMaxMessageSizeExceeded;    
 189    
 190    
 191    /**
 192     * Field names for an RFC2822 compliant RECEIVED Header
 193     */
 194    static final private String fieldRFC2822RECEIVEDHeaderFields =
 195        "from by via with id for ;";
 196    
 197    /**
 198     * Recipient is blacklisted
 199     */ 
 200    private boolean fieldBlacklistedRecipient = false;
 201    
 202    /**
 203     * The RFC2822 compliant "Received : from" domain
 204     */
 205    private String fieldRemoteDomain;
 206    
 207    /**
 208     * The remote address derived from the remote domain
 209     */
 210    private String fieldRemoteAddress;
 211    
 212    /**
 213     * The remote host name derived from the remote domain
 214     */
 215    private String fieldRemoteHostName;           
 216    
 217    /**
 218     * Constructor for MessageProcessor.
 219     * 
 220     * @param account
 221     */
 222    private MessageProcessor(Account account)
 223    {
 224        super(account);
 225    }
 226    
 227    /**
 228     * Constructor for MessageProcessor.
 229     * 
 230     * @param messageIn
 231     * @param account
 232     */
 233
 234    MessageProcessor(
 235        MimeMessage messageIn,
 236         Account account)
 237    {
 238        this(account);
 239        setMessageIn(messageIn);
 240    }   
 241
 242    
 243    /**
 244     * Method process attempts to deliver a fetched message.
 245     * 
 246     * @see org.apache.james.fetchmail.ProcessorAbstract#process()
 247     */
 248    public void process() throws MessagingException
 249    {
 250        // Log delivery attempt
 251        if (getLogger().isDebugEnabled())
 252        {
 253            StringBuffer logMessageBuffer =
 254                new StringBuffer("Attempting delivery of message with id. ");
 255            logMessageBuffer.append(getMessageIn().getMessageID());
 256            getLogger().debug(logMessageBuffer.toString());
 257        }
 258
 259        // Determine the intended recipient
 260        MailAddress intendedRecipient = getIntendedRecipient();
 261        setRecipientNotFound(null == intendedRecipient);
 262
 263        if (isRecipientNotFound())
 264        {
 265            if (isDeferRecipientNotFound())
 266            {
 267
 268                String messageID = getMessageIn().getMessageID();
 269                if (!getDeferredRecipientNotFoundMessageIDs()
 270                    .contains(messageID))
 271                {
 272                    getDeferredRecipientNotFoundMessageIDs().add(messageID);
 273                    if (getLogger().isDebugEnabled())
 274                    {
 275                        StringBuffer messageBuffer =
 276                            new StringBuffer("Deferred processing of message for which the intended recipient could not be found. Message ID: ");
 277                        messageBuffer.append(messageID);
 278                        getLogger().debug(messageBuffer.toString());
 279                    }
 280                    return;
 281                }
 282                else
 283                {
 284                    getDeferredRecipientNotFoundMessageIDs().remove(messageID);
 285                    if (getLogger().isDebugEnabled())
 286                    {
 287                        StringBuffer messageBuffer =
 288                            new StringBuffer("Processing deferred message for which the intended recipient could not be found. Message ID: ");
 289                        messageBuffer.append(messageID);
 290                        getLogger().debug(messageBuffer.toString());
 291                    }
 292                }
 293            }
 294
 295            if (isRejectRecipientNotFound())
 296            {
 297                rejectRecipientNotFound();
 298                return;
 299            }
 300            intendedRecipient = getRecipient();
 301            StringBuffer messageBuffer =
 302                new StringBuffer("Intended recipient not found. Using configured recipient as new envelope recipient - ");
 303            messageBuffer.append(intendedRecipient);
 304            messageBuffer.append('.');
 305            logStatusInfo(messageBuffer.toString());
 306        }
 307
 308        // Set the filter states
 309        setBlacklistedRecipient(isBlacklistedRecipient(intendedRecipient));
 310        setRemoteRecipient(!isLocalServer(intendedRecipient));
 311        setUserUndefined(!isLocalRecipient(intendedRecipient));
 312
 313        // Apply the filters. Return if rejected
 314        if (isRejectBlacklisted() && isBlacklistedRecipient())
 315        {
 316            rejectBlacklistedRecipient(intendedRecipient);
 317            return;
 318        }
 319
 320        if (isRejectRemoteRecipient() && isRemoteRecipient())
 321        {
 322            rejectRemoteRecipient(intendedRecipient);
 323            return;
 324        }
 325
 326        if (isRejectUserUndefined() && isUserUndefined())
 327        {
 328            rejectUserUndefined(intendedRecipient);
 329            return;
 330        }
 331
 332        if (isRejectMaxMessageSizeExceeded()
 333            && isMaxMessageSizeExceeded().booleanValue())
 334        {
 335            rejectMaxMessageSizeExceeded(getMessageIn().getSize());
 336            return;
 337        }
 338        
 339        if (isRejectRemoteReceivedHeaderInvalid()
 340            && isRemoteReceivedHeaderInvalid().booleanValue())
 341        {
 342            rejectRemoteReceivedHeaderInvalid();
 343            return;
 344        }        
 345
 346        // Create the mail
 347        // If any of the mail addresses are malformed, we will get a
 348        // ParseException. 
 349        // If the IP address and host name for the remote domain cannot
 350        // be found, we will get an UnknownHostException.
 351        // In both cases, we log the problem and
 352        // return. The message disposition is defined by the
 353        // <undeliverable> attributes.
 354        Mail mail = null;
 355        try
 356        {
 357            mail = createMail(createMessage(), intendedRecipient);
 358        }
 359        catch (ParseException ex)
 360        {
 361            handleParseException(ex);
 362            return;
 363        }
 364        catch (UnknownHostException ex)
 365        {
 366            handleUnknownHostException(ex);
 367            return;
 368        }
 369
 370        addMailAttributes(mail);
 371        addErrorMessages(mail);        
 372
 373        // If this mail is bouncing move it to the ERROR repository
 374        if (isBouncing())
 375        {
 376            handleBouncing(mail);
 377            return;
 378        }
 379
 380        // OK, lets send that mail!
 381        sendMail(mail);
 382    }
 383
 384    /**
 385     * Method rejectRemoteRecipient.
 386     * @param recipient
 387     * @throws MessagingException
 388     */
 389    protected void rejectRemoteRecipient(MailAddress recipient)
 390        throws MessagingException
 391    {
 392        // Update the flags of the received message
 393        if (!isLeaveRemoteRecipient())
 394            setMessageDeleted();
 395
 396        if (isMarkRemoteRecipientSeen())
 397            setMessageSeen();
 398
 399        StringBuffer messageBuffer =
 400            new StringBuffer("Rejected mail intended for remote recipient: ");
 401        messageBuffer.append(recipient);
 402        messageBuffer.append('.');          
 403        logStatusInfo(messageBuffer.toString());
 404
 405        return;
 406    }
 407    
 408    /**
 409     * Method rejectBlacklistedRecipient.
 410     * @param recipient
 411     * @throws MessagingException
 412     */
 413    protected void rejectBlacklistedRecipient(MailAddress recipient)
 414        throws MessagingException
 415    {
 416        // Update the flags of the received message
 417        if (!isLeaveBlacklisted())
 418            setMessageDeleted();
 419        if (isMarkBlacklistedSeen())
 420            setMessageSeen();
 421
 422        StringBuffer messageBuffer =
 423            new StringBuffer("Rejected mail intended for blacklisted recipient: ");
 424        messageBuffer.append(recipient);
 425        messageBuffer.append('.');        
 426        logStatusInfo(messageBuffer.toString());
 427
 428        return;
 429    }
 430
 431    /**
 432     * Method rejectRecipientNotFound.
 433     * @throws MessagingException
 434     */
 435    protected void rejectRecipientNotFound() throws MessagingException
 436    {
 437        // Update the flags of the received message
 438        if (!isLeaveRecipientNotFound())
 439            setMessageDeleted();
 440
 441        if (isMarkRecipientNotFoundSeen())
 442            setMessageSeen();
 443
 444        StringBuffer messageBuffer =
 445            new StringBuffer("Rejected mail for which a sole intended recipient could not be found.");
 446        messageBuffer.append(" Recipients: ");
 447        Address[] allRecipients = getMessageIn().getAllRecipients();
 448        for (int i = 0; i < allRecipients.length; i++)
 449        {
 450            messageBuffer.append(allRecipients[i]);
 451            messageBuffer.append(' ');
 452        }
 453        messageBuffer.append('.');          
 454        logStatusInfo(messageBuffer.toString());
 455        return;
 456    }
 457    
 458    /**
 459     * Method rejectUserUndefined.
 460     * @param recipient
 461     * @throws MessagingException
 462     */
 463    protected void rejectUserUndefined(MailAddress recipient)
 464        throws MessagingException
 465    {
 466        // Update the flags of the received message
 467        if (!isLeaveUserUndefined())
 468            setMessageDeleted();
 469
 470        if (isMarkUserUndefinedSeen())
 471            setMessageSeen();
 472
 473        StringBuffer messageBuffer =
 474            new StringBuffer("Rejected mail intended for undefined user: ");
 475        messageBuffer.append(recipient);
 476        messageBuffer.append('.');          
 477        logStatusInfo(messageBuffer.toString());
 478
 479        return;
 480    }
 481    
 482    /**
 483     * Method rejectMaxMessageSizeExceeded.
 484     * @param message size
 485     * @throws MessagingException
 486     */
 487    protected void rejectMaxMessageSizeExceeded(int messageSize)
 488        throws MessagingException
 489    {
 490        // Update the flags of the received message
 491        if (!isLeaveMaxMessageSizeExceeded())
 492            setMessageDeleted();
 493
 494        if (isMarkMaxMessageSizeExceededSeen())
 495            setMessageSeen();
 496
 497        StringBuffer messageBuffer =
 498            new StringBuffer("Rejected mail exceeding message size limit. Message size: ");
 499        messageBuffer.append(messageSize/1024);
 500        messageBuffer.append("KB.");          
 501        logStatusInfo(messageBuffer.toString());
 502
 503        return;
 504    }
 505    
 506    /**
 507     * Method rejectRemoteReceivedHeaderInvalid.
 508     * @throws MessagingException
 509     */
 510    protected void rejectRemoteReceivedHeaderInvalid()
 511        throws MessagingException
 512    {
 513        // Update the flags of the received message
 514        if (!isLeaveRemoteReceivedHeaderInvalid())
 515            setMessageDeleted();
 516
 517        if (isMarkRemoteReceivedHeaderInvalidSeen())
 518            setMessageSeen();
 519
 520        StringBuffer messageBuffer =
 521            new StringBuffer("Rejected mail with an invalid Received: header at index ");
 522        messageBuffer.append(getRemoteReceivedHeaderIndex());
 523        messageBuffer.append(".");          
 524        logStatusInfo(messageBuffer.toString());       
 525        return;
 526    }           
 527    
 528    /**
 529     * <p>Method createMessage answers a new <code>MimeMessage</code> from the
 530     * fetched message.</p>
 531     * 
 532     * <p>If the maximum message size is exceeded, an empty message is created,
 533     * else the new message is a copy of the received message.</p>
 534     * 
 535     * @return MimeMessage
 536     * @throws MessagingException
 537     */
 538    protected MimeMessage createMessage() throws MessagingException
 539    {
 540        // Create a new messsage from the received message
 541        MimeMessage messageOut = null;
 542        if (isMaxMessageSizeExceeded().booleanValue())
 543            messageOut = createEmptyMessage();
 544        else
 545            messageOut = new MimeMessage(getMessageIn());
 546
 547        // set the X-fetched headers
 548        // Note this is still required to detect bouncing mail and
 549        // for backwards compatibility with fetchPop 
 550        messageOut.addHeader("X-fetched-from", getFetchTaskName());
 551
 552        return messageOut;
 553    }
 554    
 555    /**
 556     * Method createEmptyMessage answers a new 
 557     * <code>MimeMessage</code> from the fetched message with the message 
 558     * contents removed. 
 559     * 
 560     * @return MimeMessage
 561     * @throws MessagingException
 562     */
 563    protected MimeMessage createEmptyMessage()
 564        throws MessagingException
 565    {
 566        // Create an empty messsage
 567        MimeMessage messageOut = new MimeMessage(getSession());
 568
 569        // Propogate the headers and subject
 570        Enumeration headersInEnum = getMessageIn().getAllHeaderLines();
 571        while (headersInEnum.hasMoreElements())
 572            messageOut.addHeaderLine((String) headersInEnum.nextElement());
 573        messageOut.setSubject(getMessageIn().getSubject());
 574
 575        // Add empty text
 576        messageOut.setText("");
 577
 578        // Save
 579        messageOut.saveChanges();
 580
 581        return messageOut;
 582    }       
 583
 584    /**
 585     * Method createMail creates a new <code>Mail</code>.
 586     * 
 587     * @param message
 588     * @param recipient
 589     * @return Mail
 590     * @throws MessagingException
 591     */
 592    protected Mail createMail(MimeMessage message, MailAddress recipient)
 593        throws MessagingException, UnknownHostException
 594    {
 595        Collection recipients = new ArrayList(1);
 596        recipients.add(recipient);
 597        MailImpl mail =
 598            new MailImpl(getServer().getId(), getSender(), recipients, message);
 599        // Ensure the mail is created with non-null remote host name and address,
 600        // otherwise the Mailet chain may go splat!
 601        if (getRemoteAddress() == null || getRemoteHostName() == null)
 602        {
 603            mail.setRemoteAddr("127.0.0.1");
 604            mail.setRemoteHost("localhost");
 605        }
 606        else
 607        {
 608            mail.setRemoteAddr(getRemoteAddress());
 609            mail.setRemoteHost(getRemoteHostName());
 610        }
 611
 612        if (getLogger().isDebugEnabled())
 613        {
 614            StringBuffer messageBuffer =
 615                new StringBuffer("Created mail with name: ");
 616            messageBuffer.append(mail.getName());
 617            messageBuffer.append(", sender: ");
 618            messageBuffer.append(mail.getSender());
 619            messageBuffer.append(", recipients: ");
 620            Iterator recipientIterator = mail.getRecipients().iterator();
 621            while (recipientIterator.hasNext())
 622            {
 623                messageBuffer.append(recipientIterator.next());
 624                messageBuffer.append(' ');
 625            }
 626            messageBuffer.append(", remote address: ");
 627            messageBuffer.append(mail.getRemoteAddr());
 628            messageBuffer.append(", remote host name: ");
 629            messageBuffer.append(mail.getRemoteHost());
 630            messageBuffer.append('.');
 631            getLogger().debug(messageBuffer.toString());
 632        }
 633        return mail;
 634    }
 635     
 636
 637    /**
 638     * Method getSender answers a <code>MailAddress</code> for the sender.
 639     * 
 640     * @return MailAddress
 641     * @throws MessagingException
 642     */
 643    protected MailAddress getSender() throws MessagingException
 644    {
 645        String from = "FETCHMAIL-SERVICE";
 646        try {
 647            from = ((InternetAddress) getMessageIn().getFrom()[0]).getAddress().trim();
 648        }
 649        catch (Exception _) {
 650            getLogger().info("Could not identify sender -- using default value");
 651        }
 652
 653        InternetAddress internetAddress = null;
 654
 655        // Check for domain part, add default if missing
 656        if (from.indexOf('@') < 0)
 657        {
 658            StringBuffer fromBuffer = new StringBuffer(from);
 659            fromBuffer.append('@');
 660            fromBuffer.append(getDefaultDomainName());
 661            internetAddress = new InternetAddress(fromBuffer.toString());
 662        }
 663        else
 664            internetAddress = new InternetAddress(from);
 665
 666        return new MailAddress(internetAddress);
 667    }
 668    
 669    /**
 670     * <p>Method computeRemoteDomain answers a <code>String</code> that is the
 671     * RFC2822 compliant "Received : from" domain extracted from the message
 672     * being processed.</p>
 673     * 
 674     * <p>Normally this is the domain that sent the message to the host for the
 675     * message store as reported by the second "received" header. The index of
 676     * the header to use is specified by the configuration parameter
 677     * <code>RemoteReceivedHeaderIndex</code>. If a header at this index does
 678     * not exist, the domain of the successively closer "received" headers
 679     * is tried until they are exhausted, then "localhost" is used.</p>
 680     * 
 681     * @return String
 682     */
 683    protected String computeRemoteDomain() throws MessagingException
 684    {
 685        StringBuffer domainBuffer = new StringBuffer();        
 686        String[] headers = null; 
 687        if (getRemoteReceivedHeaderIndex() > -1)
 688              getMessageIn().getHeader(RFC2822Headers.RECEIVED);
 689              
 690        if (null != headers)
 691        {
 692            // If there are RECEIVED headers and the index to begin at is greater
 693            // than -1, try and extract the domain
 694            if (headers.length > 0)
 695            {
 696                final String headerTokens = " \n\r";
 697
 698                // Search the headers for a domain
 699                for (int headerIndex =
 700                    headers.length > getRemoteReceivedHeaderIndex()
 701                        ? getRemoteReceivedHeaderIndex()
 702                        : headers.length - 1;
 703                    headerIndex >= 0 && domainBuffer.length() == 0;
 704                    headerIndex--)
 705                {
 706                    // Find the "from" token
 707                    StringTokenizer tokenizer =
 708                        new StringTokenizer(headers[headerIndex], headerTokens);
 709                    boolean inFrom = false;
 710                    while (!inFrom && tokenizer.hasMoreTokens())
 711                        inFrom = tokenizer.nextToken().equals("from");
 712
 713                    // Add subsequent tokens to the domain buffer until another 
 714                    // field is encountered or there are no more tokens
 715                    while (inFrom && tokenizer.hasMoreTokens())
 716                    {
 717                        String token = tokenizer.nextToken();
 718                        if (inFrom =
 719                            getRFC2822RECEIVEDHeaderFields().indexOf(token)
 720                                == -1)
 721                        {
 722                            domainBuffer.append(token);
 723                            domainBuffer.append(' ');
 724                        }
 725                    }
 726                }
 727            }
 728        }
 729
 730        // Default is "localhost"
 731        if (domainBuffer.length() == 0)
 732            domainBuffer.append("localhost");
 733
 734        return domainBuffer.toString().trim();
 735    }    
 736    
 737    /**
 738     * Method handleBouncing sets the Mail state to ERROR and delete from
 739     * the message store.
 740     * 
 741     * @param mail
 742     */
 743    protected void handleBouncing(Mail mail) throws MessagingException
 744    {
 745        mail.setState(Mail.ERROR);
 746        setMessageDeleted();
 747
 748        mail.setErrorMessage(
 749            "This mail from FetchMail task "
 750                + getFetchTaskName()
 751                + " seems to be bouncing!");
 752        logStatusError("Message is bouncing! Deleted from message store and moved to the Error repository.");
 753    }
 754    
 755    /**
 756     * Method handleParseException.
 757     * @param ex
 758     * @throws MessagingException
 759     */
 760    protected void handleParseException(ParseException ex)
 761        throws MessagingException
 762    {
 763        // Update the flags of the received message
 764        if (!isLeaveUndeliverable())
 765            setMessageDeleted();
 766        if (isMarkUndeliverableSeen())
 767            setMessageSeen();
 768        logStatusWarn("Message could not be delivered due to an error parsing a mail address.");
 769        if (getLogger().isDebugEnabled())
 770        {
 771            StringBuffer messageBuffer =
 772                new StringBuffer("UNDELIVERABLE Message ID: ");
 773            messageBuffer.append(getMessageIn().getMessageID());
 774            getLogger().debug(messageBuffer.toString(), ex);
 775        }
 776    }
 777    
 778    /**
 779     * Method handleUnknownHostException.
 780     * @param ex
 781     * @throws MessagingException
 782     */
 783    protected void handleUnknownHostException(UnknownHostException ex)
 784        throws MessagingException
 785    {
 786        // Update the flags of the received message
 787        if (!isLeaveUndeliverable())
 788            setMessageDeleted();
 789    
 790        if (isMarkUndeliverableSeen())
 791            setMessageSeen();
 792    
 793        logStatusWarn("Message could not be delivered due to an error determining the remote domain.");
 794        if (getLogger().isDebugEnabled())
 795        {
 796            StringBuffer messageBuffer =
 797                new StringBuffer("UNDELIVERABLE Message ID: ");
 798            messageBuffer.append(getMessageIn().getMessageID());
 799            getLogger().debug(messageBuffer.toString(), ex);
 800        }
 801    }    
 802    
 803    /**
 804     * Method isLocalRecipient.
 805     * @param recipient
 806     * @return boolean
 807     */
 808    protected boolean isLocalRecipient(MailAddress recipient)
 809    {
 810        return isLocalUser(recipient) && isLocalServer(recipient);
 811    }
 812    
 813    /**
 814     * Method isLocalServer.
 815     * @param recipient
 816     * @return boolean
 817     */
 818    protected boolean isLocalServer(MailAddress recipient)
 819    {
 820        return getServer().isLocalServer(recipient.getHost());
 821    }
 822    
 823    /**
 824     * Method isLocalUser.
 825     * @param recipient
 826     * @return boolean
 827     */
 828    protected boolean isLocalUser(MailAddress recipient)
 829    {
 830        return getLocalUsers().containsCaseInsensitive(recipient.getUser());
 831    }       
 832    
 833    /**
 834     * Method isBlacklistedRecipient.
 835     * @param recipient
 836     * @return boolean
 837     */
 838    protected boolean isBlacklistedRecipient(MailAddress recipient)
 839    {
 840        return getBlacklist().contains(recipient);
 841    }       
 842
 843    /**
 844     * Check if this mail has been bouncing by counting the X-fetched-from 
 845     * headers for this task
 846     * 
 847     * @return boolean
 848     */
 849    protected boolean isBouncing() throws MessagingException
 850    {
 851        Enumeration enum =
 852            getMessageIn().getMatchingHeaderLines(
 853                new String[] { "X-fetched-from" });
 854        int count = 0;
 855        while (enum.hasMoreElements())
 856        {
 857            String header = (String) enum.nextElement();
 858            if (header.equals(getFetchTaskName()))
 859                count++;
 860        }
 861        return count >= 3;
 862    }
 863    
 864    /**
 865     * Method sendMail.
 866     * @param mail
 867     * @throws MessagingException
 868     */
 869    protected void sendMail(Mail mail) throws MessagingException
 870    {
 871        // send the mail
 872        getServer().sendMail(mail);
 873
 874        // Update the flags of the received message
 875        if (!isLeave())
 876            setMessageDeleted();
 877
 878        if (isMarkSeen())
 879            setMessageSeen();
 880
 881        // Log the status
 882        StringBuffer messageBuffer =
 883            new StringBuffer("Spooled message to recipients: ");
 884        Iterator recipientIterator = mail.getRecipients().iterator();
 885        while (recipientIterator.hasNext())
 886        {
 887            messageBuffer.append(recipientIterator.next());
 888            messageBuffer.append(' ');
 889        }
 890        messageBuffer.append('.');
 891        logStatusInfo(messageBuffer.toString());
 892    }   
 893
 894
 895    /**
 896     * Method getEnvelopeRecipient answers the recipient if found else null.
 897     * 
 898     * Try and parse the "for" parameter from a Received header
 899     * Maybe not the most accurate parsing in the world but it should do
 900     * I opted not to use ORO (maybe I should have)
 901     * 
 902     * @param msg
 903     * @return String
 904     */
 905
 906    protected String getEnvelopeRecipient(MimeMessage msg) throws MessagingException
 907    {
 908        try
 909        {
 910            Enumeration enum =
 911                msg.getMatchingHeaderLines(new String[] { "Received" });
 912            while (enum.hasMoreElements())
 913            {
 914                String received = (String) enum.nextElement();
 915
 916                int nextSearchAt = 0;
 917                int i = 0;
 918                int start = 0;
 919                int end = 0;
 920                boolean hasBracket = false;
 921                boolean usableAddress = false;
 922                while (!usableAddress && (i != -1))
 923                {
 924                    hasBracket = false;
 925                    i = received.indexOf("for ", nextSearchAt);
 926                    if (i > 0)
 927                    {
 928                        start = i + 4;
 929                        end = 0;
 930                        nextSearchAt = start;
 931                        for (int c = start; c < received.length(); c++)
 932                        {
 933                            char ch = received.charAt(c);
 934                            switch (ch)
 935                            {
 936                                case '<' :
 937                                    hasBracket = true;
 938                                    continue;
 939                                case '@' :
 940                                    usableAddress = true;
 941                                    continue;
 942                                case ' ' :
 943                                    end = c;
 944                                    break;
 945                                case ';' :
 946                                    end = c;
 947                                    break;
 948                            }
 949                            if (end > 0)
 950                                break;
 951                        }
 952                    }
 953                }
 954                if (usableAddress)
 955                {
 956                    // lets try and grab the email address
 957                    String mailFor = received.substring(start, end);
 958
 959                    // strip the <> around the address if there are any
 960                    if (mailFor.startsWith("<") && mailFor.endsWith(">"))
 961                        mailFor = mailFor.substring(1, (mailFor.length() - 1));
 962
 963                    return mailFor;
 964                }
 965            }
 966        }
 967        catch (MessagingException me)
 968        {
 969            logStatusWarn("No Received headers found.");
 970        }
 971        return null;
 972    }
 973    
 974    /**
 975     * Method getIntendedRecipient answers the sole intended recipient else null.
 976     * 
 977     * @return MailAddress
 978     * @throws MessagingException
 979     */
 980    protected MailAddress getIntendedRecipient() throws MessagingException
 981    {
 982        // If the original recipient should be ignored, answer the 
 983        // hard-coded recipient
 984        if (isIgnoreRecipientHeader())
 985        {
 986            StringBuffer messageBuffer =
 987                new StringBuffer("Ignoring recipient header. Using configured recipient as new envelope recipient: ");
 988            messageBuffer.append(getRecipient());
 989            messageBuffer.append('.');            
 990            logStatusInfo(messageBuffer.toString());
 991            return getRecipient();
 992        }
 993
 994        // If we can determine who the message was received for, answer
 995        // the target recipient
 996        String targetRecipient = getEnvelopeRecipient(getMessageIn());
 997        if (targetRecipient != null)
 998        {
 999            MailAddress recipient = new MailAddress(targetRecipient);
1000            StringBuffer messageBuffer =
1001                new StringBuffer("Using original envelope recipient as new envelope recipient: ");
1002            messageBuffer.append(recipient);
1003            messageBuffer.append('.');              
1004            logStatusInfo(messageBuffer.toString());
1005            return recipient;
1006        }
1007
1008        // If we can determine the intended recipient from all of the recipients,
1009        // answer the intended recipient. This requires that there is exactly one
1010        // recipient answered by getAllRecipients(), which examines the TO: CC: and
1011        // BCC: headers
1012        Address[] allRecipients = getMessageIn().getAllRecipients();
1013        if (allRecipients.length == 1)
1014        {
1015            MailAddress recipient =
1016                new MailAddress((InternetAddress) allRecipients[0]);
1017            StringBuffer messageBuffer =
1018                new StringBuffer("Using sole recipient header address as new envelope recipient: ");
1019            messageBuffer.append(recipient);
1020            messageBuffer.append('.');              
1021            logStatusInfo(messageBuffer.toString());
1022            return recipient;
1023        }
1024
1025        return null;
1026    }           
1027
1028    /**
1029     * Returns the messageIn.
1030     * @return MimeMessage
1031     */
1032    protected MimeMessage getMessageIn()
1033    {
1034        return fieldMessageIn;
1035    }
1036
1037    /**
1038     * Sets the messageIn.
1039     * @param messageIn The messageIn to set
1040     */
1041    protected void setMessageIn(MimeMessage messageIn)
1042    {
1043        fieldMessageIn = messageIn;
1044    }
1045
1046    /**
1047     * Returns the localRecipient.
1048     * @return boolean
1049     */
1050    protected boolean isRemoteRecipient()
1051    {
1052        return fieldRemoteRecipient;
1053    }
1054    
1055    /**
1056     * Returns <code>boolean</code> indicating if the message to be delivered
1057     * was unprocessed in a previous delivery attempt.
1058     * @return boolean
1059     */
1060    protected boolean isPreviouslyUnprocessed()
1061    {
1062        return true;
1063    }
1064    
1065    /**
1066     * Log the status of the current message as INFO.
1067     * @param detailMsg
1068     */
1069    protected void logStatusInfo(String detailMsg) throws MessagingException
1070    {
1071        getLogger().info(getStatusReport(detailMsg).toString());
1072    }
1073
1074    /**
1075     * Log the status the current message as WARN.
1076     * @param detailMsg
1077     */
1078    protected void logStatusWarn(String detailMsg) throws MessagingException
1079    {
1080        getLogger().warn(getStatusReport(detailMsg).toString());
1081    }
1082    
1083    /**
1084     * Log the status the current message as ERROR.
1085     * @param detailMsg
1086     */
1087    protected void logStatusError(String detailMsg) throws MessagingException
1088    {
1089        getLogger().error(getStatusReport(detailMsg).toString());
1090    }    
1091
1092    /**
1093     * Answer a <code>StringBuffer</code> containing a message reflecting
1094     * the current status of the message being processed.
1095     * 
1096     * @param detailMsg
1097     * @return StringBuffer
1098     */
1099    protected StringBuffer getStatusReport(String detailMsg) throws MessagingException
1100    {
1101        StringBuffer messageBuffer = new StringBuffer(detailMsg);
1102        if (detailMsg.length() > 0)
1103            messageBuffer.append(' ');
1104        messageBuffer.append("Message ID: ");
1105        messageBuffer.append(getMessageIn().getMessageID());
1106        messageBuffer.append(". Flags: Seen = ");
1107        messageBuffer.append(new Boolean(isMessageSeen()));
1108        messageBuffer.append(", Delete = ");
1109        messageBuffer.append(new Boolean(isMessageDeleted()));
1110        messageBuffer.append('.');
1111        return messageBuffer;
1112    }    
1113    
1114    /**
1115     * Returns the userUndefined.
1116     * @return boolean
1117     */
1118    protected boolean isUserUndefined()
1119    {
1120        return fieldUserUndefined;
1121    }
1122    
1123    /**
1124     * Is the DELETED flag set?
1125     * @throws MessagingException
1126     */
1127    protected boolean isMessageDeleted() throws MessagingException
1128    {
1129       return getMessageIn().isSet(Flags.Flag.DELETED);
1130    }
1131    
1132    /**
1133     * Is the SEEN flag set?
1134     * @throws MessagingException
1135     */
1136    protected boolean isMessageSeen() throws MessagingException
1137    {
1138       return getMessageIn().isSet(Flags.Flag.SEEN);
1139    }    
1140    
1141    /**
1142     * Set the DELETED flag.
1143     * @throws MessagingException
1144     */
1145    protected void setMessageDeleted() throws MessagingException
1146    {
1147            getMessageIn().setFlag(Flags.Flag.DELETED, true);
1148    }    
1149    
1150    /*    /**
1151     * Set the SEEN flag.
1152     * @throws MessagingException
1153     */
1154    protected void setMessageSeen() throws MessagingException
1155    {
1156        // If the Seen flag is not handled by the folder
1157        // allow a handler to do whatever it deems necessary
1158        if (!getMessageIn()
1159            .getFolder()
1160            .getPermanentFlags()
1161            .contains(Flags.Flag.SEEN))
1162            handleMarkSeenNotPermanent();
1163        else
1164            getMessageIn().setFlag(Flags.Flag.SEEN, true);
1165    }
1166    
1167    /**
1168     * <p>Handler for when the folder does not support the SEEN flag.
1169     * The default behaviour implemented here is to log a warning and set the
1170     * flag anyway.</p>
1171     * 
1172     * <p> Subclasses may choose to override this and implement their own
1173     * solutions.</p>
1174     *  
1175     * @throws MessagingException
1176     */
1177    protected void handleMarkSeenNotPermanent() throws MessagingException
1178    {
1179        getMessageIn().setFlag(Flags.Flag.SEEN, true);
1180        logStatusWarn("Message marked as SEEN, but the folder does not support a permanent SEEN flag.");
1181    }            
1182
1183    /**
1184     * Returns the Blacklisted.
1185     * @return boolean
1186     */
1187    protected boolean isBlacklistedRecipient()
1188    {
1189        return fieldBlacklistedRecipient;
1190    }
1191
1192    /**
1193     * Sets the localRecipient.
1194     * @param localRecipient The localRecipient to set
1195     */
1196    protected void setRemoteRecipient(boolean localRecipient)
1197    {
1198        fieldRemoteRecipient = localRecipient;
1199    }
1200
1201    /**
1202     * Sets the userUndefined.
1203     * @param userUndefined The userUndefined to set
1204     */
1205    protected void setUserUndefined(boolean userUndefined)
1206    {
1207        fieldUserUndefined = userUndefined;
1208    }
1209    
1210    /**
1211     * Adds the mail attributes to a <code>Mail</code>. 
1212     * @param aMail a Mail instance
1213     */
1214    protected void addMailAttributes(Mail aMail) throws MessagingException
1215    {
1216        aMail.setAttribute(
1217            getAttributePrefix() + "taskName",
1218            getFetchTaskName());
1219
1220        aMail.setAttribute(
1221            getAttributePrefix() + "folderName",
1222            getMessageIn().getFolder().getFullName());
1223
1224        if (isRemoteRecipient())
1225            aMail.setAttribute(
1226                getAttributePrefix() + "isRemoteRecipient",
1227                null);
1228
1229        if (isUserUndefined())
1230            aMail.setAttribute(getAttributePrefix() + "isUserUndefined", null);
1231
1232        if (isBlacklistedRecipient())
1233            aMail.setAttribute(
1234                getAttributePrefix() + "isBlacklistedRecipient",
1235                null);
1236
1237        if (isRecipientNotFound())
1238            aMail.setAttribute(
1239                getAttributePrefix() + "isRecipientNotFound",
1240                null);
1241
1242        if (isMaxMessageSizeExceeded().booleanValue())
1243            aMail.setAttribute(
1244                getAttributePrefix() + "isMaxMessageSizeExceeded",
1245                new Integer(getMessageIn().getSize()).toString());
1246                
1247        if (isRemoteReceivedHeaderInvalid().booleanValue())
1248            aMail.setAttribute(
1249                getAttributePrefix() + "isRemoteReceivedHeaderInvalid",
1250                null);                
1251    }
1252
1253    /**
1254     * Adds any  required error messages to a <code>Mail</code>. 
1255     * @param aMail a Mail instance
1256     */
1257    protected void addErrorMessages(Mail mail) throws MessagingException
1258    {
1259        if (isMaxMessageSizeExceeded().booleanValue())
1260        {
1261            StringBuffer msgBuffer =
1262                new StringBuffer("550 - Rejected - This message has been rejected as the message size of ");
1263            msgBuffer.append(getMessageIn().getSize() * 1000 / 1024 / 1000f);
1264            msgBuffer.append("KB exceeds the maximum permitted size of ");
1265            msgBuffer.append(getMaxMessageSizeLimit() / 1024);
1266            msgBuffer.append("KB.");
1267            mail.setErrorMessage(msgBuffer.toString());
1268        }
1269    }         
1270
1271    /**
1272     * Sets the Blacklisted.
1273     * @param blacklisted The blacklisted to set
1274     */
1275    protected void setBlacklistedRecipient(boolean blacklisted)
1276    {
1277        fieldBlacklistedRecipient = blacklisted;
1278    }
1279
1280    /**
1281     * Returns the recipientNotFound.
1282     * @return boolean
1283     */
1284    protected boolean isRecipientNotFound()
1285    {
1286        return fieldRecipientNotFound;
1287    }
1288
1289    /**
1290     * Sets the recipientNotFound.
1291     * @param recipientNotFound The recipientNotFound to set
1292     */
1293    protected void setRecipientNotFound(boolean recipientNotFound)
1294    {
1295        fieldRecipientNotFound = recipientNotFound;
1296    }
1297
1298    /**
1299     * Returns the remoteDomain, lazily initialised as required.
1300     * @return String
1301     */
1302    protected String getRemoteDomain() throws MessagingException
1303    {
1304        String remoteDomain;
1305        if (null == (remoteDomain = getRemoteDomainBasic()))
1306        {
1307            updateRemoteDomain();
1308            return getRemoteDomain();
1309        }    
1310        return remoteDomain;
1311    }
1312    
1313    /**
1314     * Returns the remoteDomain.
1315     * @return String
1316     */
1317    private String getRemoteDomainBasic()
1318    {
1319        return fieldRemoteDomain;
1320    }    
1321
1322    /**
1323     * Sets the remoteDomain.
1324     * @param remoteDomain The remoteDomain to set
1325     */
1326    protected void setRemoteDomain(String remoteDomain)
1327    {
1328        fieldRemoteDomain = remoteDomain;
1329    }
1330    
1331    /**
1332     * Updates the remoteDomain.
1333     */
1334    protected void updateRemoteDomain() throws MessagingException
1335    {
1336        setRemoteDomain(computeRemoteDomain());
1337    }
1338    
1339    /**
1340     * Answer the IP Address of the remote server for the message being 
1341     * processed.
1342     * @return String
1343     * @throws MessagingException
1344     * @throws UnknownHostException
1345     */
1346    protected String computeRemoteAddress()
1347        throws MessagingException, UnknownHostException
1348    {
1349        String domain = getRemoteDomain();
1350        String address = null;
1351        String validatedAddress = null;
1352        int ipAddressStart = domain.indexOf('[');
1353        int ipAddressEnd = -1;
1354        if (ipAddressStart > -1)
1355            ipAddressEnd = domain.indexOf(']', ipAddressStart);
1356        if (ipAddressEnd > -1)
1357            address = domain.substring(ipAddressStart + 1, ipAddressEnd);
1358        else
1359        {
1360            int hostNameEnd = domain.indexOf(' ');
1361            if (hostNameEnd == -1)
1362                hostNameEnd = domain.length();
1363            address = domain.substring(0, hostNameEnd);
1364        }
1365        validatedAddress = org.apache.james.dnsserver.DNSServer.getByName(address).getHostAddress();
1366
1367        return validatedAddress;
1368    }
1369
1370    /**
1371     * Answer the Canonical host name of the remote server for the message 
1372     * being processed.
1373     * @return String
1374     * @throws MessagingException
1375     * @throws UnknownHostException
1376     */
1377    protected String computeRemoteHostName()
1378        throws MessagingException, UnknownHostException
1379    {
1380        // These shenanigans are required to get the fully qualified
1381        // hostname prior to JDK 1.4 in which get getCanonicalHostName()
1382        // does the job for us
1383        InetAddress addr1 = org.apache.james.dnsserver.DNSServer.getByName(getRemoteAddress());
1384        InetAddress addr2 = org.apache.james.dnsserver.DNSServer.getByName(addr1.getHostAddress());
1385        return addr2.getHostName();
1386    }        
1387
1388    /**
1389     * Returns the remoteAddress, lazily initialised as required.
1390     * @return String
1391     */
1392    protected String getRemoteAddress()
1393        throws MessagingException, UnknownHostException
1394    {
1395        String remoteAddress;
1396        if (null == (remoteAddress = getRemoteAddressBasic()))
1397        {
1398            updateRemoteAddress();
1399            return getRemoteAddress();
1400        }
1401        return remoteAddress;
1402    }
1403    
1404    /**
1405     * Returns the remoteAddress.
1406     * @return String
1407     */
1408    private String getRemoteAddressBasic()
1409    {
1410        return fieldRemoteAddress;
1411    }    
1412
1413    /**
1414     * Returns the remoteHostName, lazily initialised as required.
1415     * @return String
1416     */
1417    protected String getRemoteHostName()
1418        throws MessagingException, UnknownHostException
1419    {
1420        String remoteHostName;
1421        if (null == (remoteHostName = getRemoteHostNameBasic()))
1422        {
1423            updateRemoteHostName();
1424            return getRemoteHostName();
1425        }
1426        return remoteHostName;
1427    }
1428    
1429    /**
1430     * Returns the remoteHostName.
1431     * @return String
1432     */
1433    private String getRemoteHostNameBasic()
1434    {
1435        return fieldRemoteHostName;
1436    }    
1437
1438    /**
1439     * Sets the remoteAddress.
1440     * @param remoteAddress The remoteAddress to set
1441     */
1442    protected void setRemoteAddress(String remoteAddress)
1443    {
1444        fieldRemoteAddress = remoteAddress;
1445    }
1446    
1447    /**
1448     * Updates the remoteAddress.
1449     */
1450    protected void updateRemoteAddress()
1451        throws MessagingException, UnknownHostException
1452    {
1453        setRemoteAddress(computeRemoteAddress());
1454    }    
1455
1456    /**
1457     * Sets the remoteHostName.
1458     * @param remoteHostName The remoteHostName to set
1459     */
1460    protected void setRemoteHostName(String remoteHostName)
1461    {
1462        fieldRemoteHostName = remoteHostName;
1463    }
1464    
1465    /**
1466     * Updates the remoteHostName.
1467     */
1468    protected void updateRemoteHostName()
1469        throws MessagingException, UnknownHostException
1470    {
1471        setRemoteHostName(computeRemoteHostName());
1472    }    
1473
1474    /**
1475     * Returns the rFC2822RECEIVEDHeaderFields.
1476     * @return String
1477     */
1478    public static String getRFC2822RECEIVEDHeaderFields()
1479    {
1480        return fieldRFC2822RECEIVEDHeaderFields;
1481    }
1482
1483    /**
1484     * Returns the maxMessageSizeExceeded, lazily initialised as required.
1485     * @return Boolean
1486     */
1487    protected Boolean isMaxMessageSizeExceeded() throws MessagingException
1488    {
1489        Boolean isMaxMessageSizeExceeded = null;
1490        if (null
1491            == (isMaxMessageSizeExceeded = isMaxMessageSizeExceededBasic()))
1492        {
1493            updateMaxMessageSizeExceeded();
1494            return isMaxMe