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