| 1 17 18 package org.apache.james.fetchmail; 19 20 import java.io.InputStream; 21 import java.net.InetAddress; 22 import java.net.UnknownHostException; 23 import java.util.ArrayList; 24 import java.util.Collection; 25 import java.util.Enumeration; 26 import java.util.Iterator; 27 import java.util.StringTokenizer; 28 29 import javax.mail.Address; 30 import javax.mail.Flags; 31 import javax.mail.Folder; 32 import javax.mail.MessagingException; 33 import javax.mail.Session; 34 import javax.mail.internet.InternetAddress; 35 import javax.mail.internet.InternetHeaders; 36 import javax.mail.internet.MimeMessage; 37 import javax.mail.internet.ParseException; 38 39 import org.apache.james.core.MailImpl; 40 import org.apache.james.util.RFC2822Headers; 41 import org.apache.mailet.Mail; 42 import org.apache.mailet.MailAddress; 43 44 161 public class MessageProcessor extends ProcessorAbstract 162 { 163 private MimeMessage fieldMessageIn; 164 165 168 private boolean fieldRecipientNotFound = false; 169 170 173 private boolean fieldRemoteRecipient = true; 174 175 178 private Boolean fieldRemoteReceivedHeaderInvalid; 179 180 183 private boolean fieldUserUndefined = false; 184 185 188 private Boolean fieldMaxMessageSizeExceeded; 189 190 191 194 static final private String fieldRFC2822RECEIVEDHeaderFields = 195 "from by via with id for ;"; 196 197 200 private boolean fieldBlacklistedRecipient = false; 201 202 205 private String fieldRemoteDomain; 206 207 210 private String fieldRemoteAddress; 211 212 215 private String fieldRemoteHostName; 216 217 222 private MessageProcessor(Account account) 223 { 224 super(account); 225 } 226 227 233 234 MessageProcessor( 235 MimeMessage messageIn, 236 Account account) 237 { 238 this(account); 239 setMessageIn(messageIn); 240 } 241 242 243 248 public void process() throws MessagingException 249 { 250 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 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 setBlacklistedRecipient(isBlacklistedRecipient(intendedRecipient)); 310 setRemoteRecipient(!isLocalServer(intendedRecipient)); 311 setUserUndefined(!isLocalRecipient(intendedRecipient)); 312 313 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 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 (isBouncing()) 375 { 376 handleBouncing(mail); 377 return; 378 } 379 380 sendMail(mail); 382 } 383 384 389 protected void rejectRemoteRecipient(MailAddress recipient) 390 throws MessagingException 391 { 392 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 413 protected void rejectBlacklistedRecipient(MailAddress recipient) 414 throws MessagingException 415 { 416 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 435 protected void rejectRecipientNotFound() throws MessagingException 436 { 437 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 463 protected void rejectUserUndefined(MailAddress recipient) 464 throws MessagingException 465 { 466 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 487 protected void rejectMaxMessageSizeExceeded(int messageSize) 488 throws MessagingException 489 { 490 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 510 protected void rejectRemoteReceivedHeaderInvalid() 511 throws MessagingException 512 { 513 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 538 protected MimeMessage createMessage() throws MessagingException 539 { 540 MimeMessage messageOut = null; 542 if (isMaxMessageSizeExceeded().booleanValue()) 543 messageOut = createEmptyMessage(); 544 else 545 messageOut = new MimeMessage(getMessageIn()); 546 547 messageOut.addHeader("X-fetched-from", getFetchTaskName()); 551 552 return messageOut; 553 } 554 555 563 protected MimeMessage createEmptyMessage() 564 throws MessagingException 565 { 566 MimeMessage messageOut = new MimeMessage(getSession()); 568 569 Enumeration headersInEnum = getMessageIn().getAllHeaderLines(); 571 while (headersInEnum.hasMoreElements()) 572 messageOut.addHeaderLine((String) headersInEnum.nextElement()); 573 messageOut.setSubject(getMessageIn().getSubject()); 574 575 messageOut.setText(""); 577 578 messageOut.saveChanges(); 580 581 return messageOut; 582 } 583 584 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 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 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 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 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 (headers.length > 0) 695 { 696 final String headerTokens = " \n\r"; 697 698 for (int headerIndex = 700 headers.length > getRemoteReceivedHeaderIndex() 701 ? getRemoteReceivedHeaderIndex() 702 : headers.length - 1; 703 headerIndex >= 0 && domainBuffer.length() == 0; 704 headerIndex--) 705 { 706 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 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 if (domainBuffer.length() == 0) 732 domainBuffer.append("localhost"); 733 734 return domainBuffer.toString().trim(); 735 } 736 737 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 760 protected void handleParseException(ParseException ex) 761 throws MessagingException 762 { 763 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 783 protected void handleUnknownHostException(UnknownHostException ex) 784 throws MessagingException 785 { 786 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 808 protected boolean isLocalRecipient(MailAddress recipient) 809 { 810 return isLocalUser(recipient) && isLocalServer(recipient); 811 } 812 813 818 protected boolean isLocalServer(MailAddress recipient) 819 { 820 return getServer().isLocalServer(recipient.getHost()); 821 } 822 823 828 protected boolean isLocalUser(MailAddress recipient) 829 { 830 return getLocalUsers().containsCaseInsensitive(recipient.getUser()); 831 } 832 833 838 protected boolean isBlacklistedRecipient(MailAddress recipient) 839 { 840 return getBlacklist().contains(recipient); 841 } 842 843 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 869 protected void sendMail(Mail mail) throws MessagingException 870 { 871 getServer().sendMail(mail); 873 874 if (!isLeave()) 876 setMessageDeleted(); 877 878 if (isMarkSeen()) 879 setMessageSeen(); 880 881 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 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 &
|