1 21 22 27 28 package com.sun.mail.smtp; 29 30 import java.io.*; 31 import java.net.*; 32 import java.util.*; 33 34 import javax.mail.*; 35 import javax.mail.event.*; 36 import javax.mail.internet.*; 37 38 import com.sun.mail.util.*; 39 40 55 56 public class SMTPTransport extends Transport { 57 58 private String name = "smtp"; private int defaultPort = 25; private boolean isSSL = false; 62 private MimeMessage message; private Address[] addresses; private Address[] validSentAddr, validUnsentAddr, invalidAddr; 67 boolean sendPartiallyFailed = false; 69 MessagingException exception; 71 72 private Hashtable extMap; 74 75 private boolean quitWait = false; private String saslRealm = UNKNOWN; 77 78 private boolean reportSuccess; private boolean useStartTLS; private boolean useRset; 82 private PrintStream out; private String localHostName; private String lastServerResponse; private int lastReturnCode; 87 88 private static final String [] ignoreList = { "Bcc", "Content-Length" }; 89 private static final byte[] CRLF = { (byte)'\r', (byte)'\n' }; 90 private static final String UNKNOWN = "UNKNOWN"; 92 96 public SMTPTransport(Session session, URLName urlname) { 97 this(session, urlname, "smtp", 25, false); 98 } 99 100 103 protected SMTPTransport(Session session, URLName urlname, 104 String name, int defaultPort, boolean isSSL) { 105 super(session, urlname); 106 if (urlname != null) 107 name = urlname.getProtocol(); 108 this.name = name; 109 this.defaultPort = defaultPort; 110 this.isSSL = isSSL; 111 112 out = session.getDebugOut(); 113 114 String s = session.getProperty("mail." + name + ".quitwait"); 117 quitWait = s == null || s.equalsIgnoreCase("true"); 118 119 s = session.getProperty("mail." + name + ".reportsuccess"); 121 reportSuccess = s != null && s.equalsIgnoreCase("true"); 122 123 s = session.getProperty("mail." + name + ".starttls.enable"); 125 useStartTLS = s != null && s.equalsIgnoreCase("true"); 126 127 s = session.getProperty("mail." + name + ".userset"); 130 useRset = s != null && s.equalsIgnoreCase("true"); 131 } 132 133 138 public String getLocalHost() { 139 try { 140 if (localHostName == null || localHostName.length() <= 0) 142 localHostName = 143 session.getProperty("mail." + name + ".localhost"); 144 if (localHostName == null || localHostName.length() <= 0) 145 localHostName = 146 session.getProperty("mail." + name + ".localaddress"); 147 if (localHostName == null || localHostName.length() <= 0) { 148 InetAddress localHost = InetAddress.getLocalHost(); 149 localHostName = localHost.getHostName(); 150 if (localHostName == null) 152 localHostName = "[" + localHost.getHostAddress() + "]"; 154 } 155 } catch (UnknownHostException uhex) { 156 } 157 return localHostName; 158 } 159 160 165 public void setLocalHost(String localhost) { 166 localHostName = localhost; 167 } 168 169 177 public synchronized void connect(Socket socket) throws MessagingException { 178 serverSocket = socket; 179 super.connect(); 180 } 181 182 189 public String getSASLRealm() { 190 if (saslRealm == UNKNOWN) { 191 saslRealm = session.getProperty("mail." + name + ".sasl.realm"); 192 if (saslRealm == null) saslRealm = session.getProperty("mail." + name + ".saslrealm"); 194 } 195 return saslRealm; 196 } 197 198 206 public void setSASLRealm(String saslRealm) { 207 this.saslRealm = saslRealm; 208 } 209 210 223 public boolean getReportSuccess() { 224 return reportSuccess; 225 } 226 227 235 public void setReportSuccess(boolean reportSuccess) { 236 this.reportSuccess = reportSuccess; 237 } 238 239 247 public boolean getStartTLS() { 248 return useStartTLS; 249 } 250 251 258 public void setStartTLS(boolean useStartTLS) { 259 this.useStartTLS = useStartTLS; 260 } 261 262 270 public boolean getUseRset() { 271 return useRset; 272 } 273 274 282 public void setUseRset(boolean useRset) { 283 this.useRset = useRset; 284 } 285 286 297 public String getLastServerResponse() { 298 return lastServerResponse; 299 } 300 301 private DigestMD5 md5support; 302 303 private synchronized DigestMD5 getMD5() { 304 if (md5support == null) 305 md5support = new DigestMD5(debug ? out : null); 306 return md5support; 307 } 308 309 327 protected boolean protocolConnect(String host, int port, String user, 328 String passwd) throws MessagingException { 329 String ehloStr = session.getProperty("mail." + name + ".ehlo"); 331 boolean useEhlo = ehloStr == null || !ehloStr.equalsIgnoreCase("false"); 332 String authStr = session.getProperty("mail." + name + ".auth"); 334 boolean useAuth = authStr != null && authStr.equalsIgnoreCase("true"); 335 DigestMD5 md5; 336 if (debug) 337 out.println("DEBUG SMTP: useEhlo " + useEhlo + 338 ", useAuth " + useAuth); 339 340 346 if (useAuth && (user == null || passwd == null)) 347 return false; 348 349 353 if (port == -1) { 354 String portstring = session.getProperty("mail." + name + ".port"); 355 if (portstring != null) { 356 port = Integer.parseInt(portstring); 357 } else { 358 port = defaultPort; 359 } 360 } 361 362 if (host == null || host.length() == 0) 363 host = "localhost"; 364 365 boolean succeed = false; 366 367 if (serverSocket != null) 368 openServer(); else 370 openServer(host, port); 371 372 if (useEhlo) 373 succeed = ehlo(getLocalHost()); 374 if (!succeed) 375 helo(getLocalHost()); 376 377 if (useStartTLS && supportsExtension("STARTTLS")) { 378 startTLS(); 379 384 ehlo(getLocalHost()); 385 } 386 387 if (useAuth && 388 (supportsExtension("AUTH") || supportsExtension("AUTH=LOGIN"))) { 389 if (debug) { 390 out.println("DEBUG SMTP: Attempt to authenticate"); 391 if (!supportsAuthentication("LOGIN") && 392 supportsExtension("AUTH=LOGIN")) 393 out.println("DEBUG SMTP: use AUTH=LOGIN hack"); 394 } 395 if (supportsAuthentication("LOGIN") || 397 supportsExtension("AUTH=LOGIN")) { 398 int resp = simpleCommand("AUTH LOGIN"); 400 401 405 if (resp == 530) { 406 startTLS(); 407 resp = simpleCommand("AUTH LOGIN"); 408 } 409 410 419 try { 420 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 421 OutputStream b64os = 422 new BASE64EncoderStream(bos, Integer.MAX_VALUE); 423 424 if (resp == 334) { 425 b64os.write(ASCIIUtility.getBytes(user)); 427 b64os.flush(); 429 resp = simpleCommand(bos.toByteArray()); 431 bos.reset(); } 433 if (resp == 334) { 434 b64os.write(ASCIIUtility.getBytes(passwd)); 436 b64os.flush(); 438 resp = simpleCommand(bos.toByteArray()); 440 bos.reset(); } 442 } catch (IOException ex) { } finally { 444 if (resp != 235) { 445 closeConnection(); 446 return false; 447 } 448 } 449 } else if (supportsAuthentication("PLAIN")) { 450 int resp = simpleCommand("AUTH PLAIN"); 452 try { 453 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 454 OutputStream b64os = 455 new BASE64EncoderStream(bos, Integer.MAX_VALUE); 456 if (resp == 334) { 457 b64os.write(0); 460 b64os.write(ASCIIUtility.getBytes(user)); 461 b64os.write(0); 462 b64os.write(ASCIIUtility.getBytes(passwd)); 463 b64os.flush(); 465 resp = simpleCommand(bos.toByteArray()); 467 } 468 } catch (IOException ex) { } finally { 470 if (resp != 235) { 471 closeConnection(); 472 return false; 473 } 474 } 475 } else if (supportsAuthentication("DIGEST-MD5") && 476 (md5 = getMD5()) != null) { 477 int resp = simpleCommand("AUTH DIGEST-MD5"); 478 try { 479 if (resp == 334) { 480 byte[] b = md5.authClient(host, user, passwd, 481 getSASLRealm(), lastServerResponse); 482 resp = simpleCommand(b); 483 if (resp == 334) { if (!md5.authServer(lastServerResponse)) { 485 resp = -1; 487 } else { 488 resp = simpleCommand(new byte[0]); 490 } 491 } 492 } 493 } catch (Exception ex) { if (debug) 495 out.println("DEBUG SMTP: DIGEST-MD5: " + ex); 496 } finally { 497 if (resp != 235) { 498 closeConnection(); 499 return false; 500 } 501 } 502 } 503 } 504 505 return true; 507 } 508 509 510 545 public synchronized void sendMessage(Message message, Address[] addresses) 546 throws MessagingException, SendFailedException { 547 548 checkConnected(); 549 550 if (!(message instanceof MimeMessage)) { 553 if (debug) 554 out.println("DEBUG SMTP: Can only send RFC822 msgs"); 555 throw new MessagingException("SMTP can only send RFC822 messages"); 556 } 557 for (int i = 0; i < addresses.length; i++) { 558 if (!(addresses[i] instanceof InternetAddress)) { 559 throw new MessagingException(addresses[i] + 560 " is not an InternetAddress"); 561 } 562 } 563 564 this.message = (MimeMessage)message; 565 this.addresses = addresses; 566 validUnsentAddr = addresses; expandGroups(); 568 569 boolean use8bit = false; 570 if (message instanceof SMTPMessage) 571 use8bit = ((SMTPMessage)message).getAllow8bitMIME(); 572 if (!use8bit) { 573 String ebStr = 574 session.getProperty("mail." + name + ".allow8bitmime"); 575 use8bit = ebStr != null && ebStr.equalsIgnoreCase("true"); 576 } 577 if (debug) 578 out.println("DEBUG SMTP: use8bit " + use8bit); 579 if (use8bit && supportsExtension("8BITMIME")) 580 convertTo8Bit(this.message); 581 582 try { 583 mailFrom(); 584 rcptTo(); 585 this.message.writeTo(data(), ignoreList); 586 finishData(); 587 if (sendPartiallyFailed) { 588 if (debug) 591 out.println("DEBUG SMTP: Sending partially failed " + 592 "because of invalid destination addresses"); 593 notifyTransportListeners( 594 TransportEvent.MESSAGE_PARTIALLY_DELIVERED, 595 validSentAddr, validUnsentAddr, invalidAddr, 596 this.message); 597 598 throw new SMTPSendFailedException(".", lastReturnCode, 599 lastServerResponse, exception, 600 validSentAddr, validUnsentAddr, invalidAddr); 601 } 602 notifyTransportListeners(TransportEvent.MESSAGE_DELIVERED, 603 validSentAddr, validUnsentAddr, 604 invalidAddr, this.message); 605 } catch (MessagingException mex) { 606 if (debug) 607 mex.printStackTrace(out); 608 notifyTransportListeners(TransportEvent.MESSAGE_NOT_DELIVERED, 609 validSentAddr, validUnsentAddr, 610 invalidAddr, this.message); 611 612 throw mex; 613 } catch (IOException ex) { 614 if (debug) 615 ex.printStackTrace(out); 616 try { 619 closeConnection(); 620 } catch (MessagingException mex) { } 621 notifyTransportListeners(TransportEvent.MESSAGE_NOT_DELIVERED, 622 validSentAddr, validUnsentAddr, 623 invalidAddr, this.message); 624 625 throw new MessagingException("IOException while sending message", 626 ex); 627 } finally { 628 validSentAddr = validUnsentAddr = invalidAddr = null; 630 this.addresses = null; 631 this.message = null; 632 this.exception = null; 633 sendPartiallyFailed = false; 634 } 635 } 636 637 638 public synchronized void close() throws MessagingException { 639 if (!super.isConnected()) return; 641 try { 642 if (serverSocket != null) { 643 sendCommand("QUIT"); 644 if (quitWait) { 645 int resp = readServerResponse(); 646 if (resp != 221 && resp != -1) 647 out.println("DEBUG SMTP: QUIT failed with " + resp); 648 } 649 } 650 } finally { 651 closeConnection(); 652 } 653 } 654 655 private void closeConnection() throws MessagingException { 656 try { 657 if (serverSocket != null) 658 serverSocket.close(); 659 } catch (IOException ioex) { throw new MessagingException("Server Close Failed", ioex); 661 } finally { 662 serverSocket = null; 663 serverOutput = null; 664 serverInput = null; 665 lineInputStream = null; 666 if (super.isConnected()) super.close(); 668 } 669 } 670 671 675 public synchronized boolean isConnected() { 676 if (!super.isConnected()) 677 return false; 679 680 try { 681 if (useRset) 684 sendCommand("RSET"); 685 else 686 sendCommand("NOOP"); 687 int resp = readServerResponse(); 688 689 if (resp >= 0 && resp != 421) { 698 return true; 699 } else { 700 try { 701 closeConnection(); 702 } catch (MessagingException mex) { } return false; 704 } 705 } catch (Exception ex) { 706 try { 707 closeConnection(); 708 } catch (MessagingException mex) { } return false; 710 } 711 } 712 713 716 private void expandGroups() { 717 Vector groups = null; 718 for (int i = 0; i < addresses.length; i++) { 719 InternetAddress a = (InternetAddress)addresses[i]; 720 if (a.isGroup()) { 721 if (groups == null) { 722 groups = new Vector(); 724 for (int k = 0; k < i; k++) 725 groups.addElement(addresses[k]); 726 } 727 try { 729 InternetAddress[] ia = a.getGroup(true); 730 if (ia != null) { 731 for (int j = 0; j < ia.length; j++) 732 groups.addElement(ia[j]); 733 } else 734 groups.addElement(a); 735 } catch (ParseException pex) { 736 groups.addElement(a); 738 } 739 } else { 740 if (groups != null) 742 groups.addElement(a); 743 } 744 } 745 746 if (groups != null) { 748 InternetAddress[] newa = new InternetAddress[groups.size()]; 749 groups.copyInto(newa); 750 addresses = newa; 751 } 752 } 753 754 762 private void convertTo8Bit(MimePart part) { 763 try { 764 if (part.isMimeType("text/*")) { 765 String enc = part.getEncoding(); 766 if (enc.equalsIgnoreCase("quoted-printable") || 767 enc.equalsIgnoreCase("base64")) { 768 InputStream is = part.getInputStream(); 769 if (is8Bit(is)) 770 part.setHeader("Content-Transfer-Encoding", "8bit"); 771 } 772 } else if (part.isMimeType("multipart/*")) { 773 MimeMultipart mp = (MimeMultipart)part.getContent(); 774 int count = mp.getCount(); 775 for (int i = 0; i < count; i++) 776 convertTo8Bit((MimePart)mp.getBodyPart(i)); 777 } 778 } catch (IOException ioex) { 779 } catch (MessagingException mex) { 781 } 783 } 784 785 792 private boolean is8Bit(InputStream is) { 793 int b; 794 int linelen = 0; 795 boolean need8bit = false; 796 try { 797 while ((b = is.read()) >= 0) { 798 b &= 0xff; 799 if (b == '\r' || b == '\n') 800 linelen = 0; 801 else if (b == 0) 802 return false; 803 else { 804 linelen++; 805 if (linelen > 998) return false; 807 } 808 if (b > 0x7f) 809 need8bit = true; 810 } 811 } catch (IOException ex) { 812 return false; 813 } 814 if (debug && need8bit) 815 out.println("DEBUG SMTP: found an 8bit part"); 816 return need8bit; 817 } 818 819 protected void finalize() throws Throwable { 820 super.finalize(); 821 try { 822 closeConnection(); 823 } catch (MessagingException mex) { } } 825 826 private BufferedInputStream serverInput; 828 private LineInputStream lineInputStream; 829 private OutputStream serverOutput; 830 private Socket serverSocket; 831 832 834 private void helo(String domain) throws MessagingException { 835 if (domain != null) 836 issueCommand("HELO " + domain, 250); 837 else 838 issueCommand("HELO", 250); 839 } 840 841 private boolean ehlo(String domain) throws MessagingException { 842 String cmd; 843 if (domain != null) 844 cmd = "EHLO " + domain; 845 else 846 cmd = "EHLO"; 847 sendCommand(cmd); 848 int resp = readServerResponse(); 849 if (resp == 250) { 850 BufferedReader rd = 852 new BufferedReader(new StringReader(lastServerResponse)); 853 String line; 854 extMap = new Hashtable(); 855 try { 856 boolean first = true; 857 while ((line = rd.readLine()) != null) { 858 if (first) { first = false; 860 continue; 861 } 862 if (line.length() < 5) 863 continue; line = line.substring(4); int i = line.indexOf(' '); 866 String arg = ""; 867 if (i > 0) { 868 arg = line.substring(i + 1); 869 line = line.substring(0, i); 870 } 871 if (debug) 872 out.println("DEBUG SMTP: Found extension \"" + 873 line + "\", arg \"" + arg + "\""); 874 extMap.put(line.toUpperCase(), arg); 875 } 876 } catch (IOException ex) { } } 878 return resp == 250; 879 } 880 881 888 private void mailFrom() throws MessagingException { 889 String from = null; 890 if (message instanceof SMTPMessage) 891 from = ((SMTPMessage)message).getEnvelopeFrom(); 892 if (from == null || from.length() <= 0) 893 from = session.getProperty("mail." + name + ".from"); 894 if (from == null || from.length() <= 0) { 895 Address[] fa; 896 Address me; 897 if (message != null && (fa = message.getFrom()) != null && 898 fa.length > 0) 899 me = fa[0]; 900 else 901 me = InternetAddress.getLocalAddress(session); 902 903 if (me != null) 904 from = ((InternetAddress)me).getAddress(); 905 else 906 throw new MessagingException( 907 "can't determine local email address"); 908 } 909 910 String cmd = "MAIL FROM:" + normalizeAddress(from); 911 912 if (supportsExtension("DSN")) { 914 String ret = null; 915 if (message instanceof SMTPMessage) 916 ret = ((SMTPMessage)message).getDSNRet(); 917 if (ret == null) 918 ret = session.getProperty("mail." + name + ".dsn.ret"); 919 if (ret != null) 921 cmd += " RET=" + ret; 922 } 923 924 929 if (supportsExtension("AUTH")) { 930 String submitter = null; 931 if (message instanceof SMTPMessage) 932 submitter = ((SMTPMessage)message).getSubmitter(); 933 if (submitter == null) 934 submitter = session.getProperty("mail." + name + ".submitter"); 935 if (submitter != null) { 937 try { 938 String s = xtext(submitter); 939 cmd += " AUTH=" + s; 940 } catch (IllegalArgumentException ex) { 941 if (debug) 942 out.println("DEBUG SMTP: ignoring invalid submitter: " + 943 submitter + ", Exception: " + ex); 944 } 945 } 946 } 947 948 951 String ext = null; 952 if (message instanceof SMTPMessage) 953 ext = ((SMTPMessage)message).getMailExtension(); 954 if (ext == null) 955 ext = session.getProperty("mail." + name + ".mailextension"); 956 if (ext != null && ext.length() > 0) 957 cmd += " " + ext; 958 959 issueSendCommand(cmd, 250); 960 } 961 962 968 980 private void rcptTo() throws MessagingException { 981 Vector valid = new Vector(); 982 Vector validUnsent = new Vector(); 983 Vector invalid = new Vector(); 984 int retCode = -1; 985 MessagingException mex = null; 986 boolean sendFailed = false; 987 MessagingException sfex = null; 988 validSentAddr = validUnsentAddr = invalidAddr = null; 989 boolean sendPartial = false; 990 if (message instanceof SMTPMessage) 991 sendPartial = ((SMTPMessage)message).getSendPartial(); 992 if (!sendPartial) { 993 String sp = session.getProperty("mail." + name + ".sendpartial"); 994 sendPartial = sp != null && sp.equalsIgnoreCase("true"); 995 } 996 if (debug && sendPartial) 997 out.println("DEBUG SMTP: sendPartial set"); 998 999 boolean dsn = false; 1000 String notify = null; 1001 if (supportsExtension("DSN")) { 1002 if (message instanceof SMTPMessage) 1003 notify = ((SMTPMessage)message).getDSNNotify(); 1004 if (notify == null) 1005 notify = session.getProperty("mail." + name + ".dsn.notify"); 1006 if (notify != null) 1008 dsn = true; 1009 } 1010 1011 for (int i = 0; i < addresses.length; i++) { 1013 1014 sfex = null; 1015 InternetAddress ia = (InternetAddress)addresses[i]; 1016 String cmd = "RCPT TO:" + normalizeAddress(ia.getAddress()); 1017 if (dsn) 1018 cmd += " NOTIFY=" + notify; 1019 sendCommand(cmd); 1021 retCode = readServerResponse(); 1023 switch (retCode) { 1024 case 250: case 251: 1025 valid.addElement(ia); 1026 if (!reportSuccess) 1027 break; 1028 1029 1032 sfex = new SMTPAddressSucceededException(ia, cmd, retCode, 1034 lastServerResponse); 1035 if (mex == null) 1036 mex = sfex; 1037 else 1038 mex.setNextException(sfex); 1039 break; 1040 1041 case 550: case 553: case 503: case 551: case 501: 1042 if (!sendPartial) 1044 sendFailed = true; 1045 invalid.addElement(ia); 1046 sfex = new SMTPAddressFailedException(ia, cmd, retCode, 1048 lastServerResponse); 1049 if (mex == null) 1050 mex = sfex; 1051 else 1052 mex.setNextException(sfex); 1053 break; 1054 1055 case 552: case 450: case 451: case 452: 1056 if (!sendPartial) 1058 sendFailed = true; 1059 validUnsent.addElement(ia); 1060 sfex = new SMTPAddressFailedException(ia, cmd, retCode, 1062 lastServerResponse); 1063 if (mex == null) 1064 mex = sfex; 1065 else 1066 mex.setNextException(sfex); 1067 break; 1068 1069 default: 1070 if (retCode >= 400 && retCode <= 499) { 1072 validUnsent.addElement(ia); 1074 } else if (retCode >= 500 && retCode <= 599) { 1075 invalid.addElement(ia); 1077 } else { 1078 if (debug) 1080 out.println("DEBUG SMTP: got response code " + retCode + 1081 ", with response: " + lastServerResponse); 1082 String _lsr = lastServerResponse; int _lrc = lastReturnCode; 1084 if (serverSocket != null) issueCommand("RSET", 250); 1086 lastServerResponse = _lsr; lastReturnCode = _lrc; 1088 throw new SMTPAddressFailedException(ia, cmd, retCode, 1089 _lsr); 1090 } 1091 if (!sendPartial) 1092 sendFailed = true; 1093 sfex = new SMTPAddressFailedException(ia, cmd, retCode, 1095 lastServerResponse); 1096 if (mex == null) 1097 mex = sfex; 1098 else 1099 mex.setNextException(sfex); 1100 break; 1101 } 1102 } 1103 1104 if (sendPartial && valid.size() == 0) 1107 sendFailed = true; 1108 1109 if (sendFailed) { 1111 invalidAddr = new Address[invalid.size()]; 1113 invalid.copyInto(invalidAddr); 1114 1115 validUnsentAddr = new Address[valid.size() + validUnsent.size()]; 1117 int i = 0; 1118 for (int j = 0; j < valid.size(); j++) 1119 validUnsentAddr[i++] = (Address)valid.elementAt(j); 1120 for (int j = 0; j < validUnsent.size(); j++) 1121 validUnsentAddr[i++] = (Address)validUnsent.elementAt(j); 1122 } else if (reportSuccess || (sendPartial && 1123 (invalid.size() > 0 || validUnsent.size() > 0))) { 1124 sendPartiallyFailed = true; 1127 exception = mex; 1128 1129 invalidAddr = new Address[invalid.size()]; 1131 invalid.copyInto(invalidAddr); 1132 1133 validUnsentAddr = new Address[validUnsent.size()]; 1135 validUnsent.copyInto(validUnsentAddr); 1136 1137 validSentAddr = new Address[valid.size()]; 1139 valid.copyInto(validSentAddr); 1140 } else { validSentAddr = addresses; 1142 } 1143 1144 1145 if (debug) { 1147 if (validSentAddr != null && validSentAddr.length > 0) { 1148 out.println("DEBUG SMTP: Verified Addresses"); 1149 for (int l = 0; l < validSentAddr.length; l++) { 1150 out.println("DEBUG SMTP: " + validSentAddr[l]); 1151 } 1152 } 1153 if (validUnsentAddr != null && validUnsentAddr.length > 0) { 1154 out.println("DEBUG SMTP: Valid Unsent Addresses"); 1155 for (int j = 0; j < validUnsentAddr.length; j++) { 1156 out.println("DEBUG SMTP: " + validUnsentAddr[j]); 1157 } 1158 } 1159 if (invalidAddr != null && invalidAddr.length > 0) { 1160 out.println("DEBUG SMTP: Invalid Addresses"); 1161 for (int k = 0; k < invalidAddr.length; k++) { 1162 out.println("DEBUG SMTP: " + invalidAddr[k]); 1163 } 1164 } 1165 } 1166 1167 if (sendFailed) { 1169 if (debug) 1170 out.println("DEBUG SMTP: Sending failed " + 1171 "because of invalid destination addresses"); 1172 notifyTransportListeners(TransportEvent.MESSAGE_NOT_DELIVERED, 1173 validSentAddr, validUnsentAddr, 1174 invalidAddr, this.message); 1175 1176 String lsr = lastServerResponse; int lrc = lastReturnCode; 1179 try { 1180 if (serverSocket != null) 1181 issueCommand("RSET", 250); 1182 } catch (MessagingException ex) { 1183 try { 1185 close(); 1186 } catch (MessagingException ex2) { 1187 if (debug) 1189 ex2.printStackTrace(out); 1190 } 1191 } finally { 1192 lastServerResponse = lsr; lastReturnCode = lrc; 1194 } 1195 1196 throw new SendFailedException("Invalid Addresses", mex, 1197 validSentAddr, 1198 validUnsentAddr, invalidAddr); 1199 } 1200 } 1201 1202 1206 private OutputStream data() throws MessagingException { 1207 issueSendCommand("DATA", 354); 1208 return new SMTPOutputStream(serverOutput); 1209 } 1210 1211 1214 private void finishData() throws MessagingException { 1215 issueSendCommand("\r\n.", 250); } 1217 1218 1222 private void startTLS() throws MessagingException { 1223 issueCommand("STARTTLS", 220); 1224 try { 1226 serverSocket = SocketFetcher.startTLS(serverSocket); 1227 initStreams(); 1228 } catch (IOException ioex) { 1229 closeConnection(); 1230 throw new MessagingException("Could not convert socket to TLS", 1231 ioex); 1232 } 1233 } 1234 1235 1237 1240 private void openServer(String server, int port) 1241 throws MessagingException { 1242 1243 if (debug) 1244 out.println("DEBUG SMTP: trying to connect to host \"" + server + 1245 "\", port " + port + ", isSSL " + isSSL); 1246 1247 try { 1248 Properties props = session.getProperties(); 1249 1250 serverSocket = SocketFetcher.getSocket(server, port, 1251 props, "mail." + name, isSSL); 1252 1253 port = serverSocket.getPort(); 1256 1257 initStreams(); 1258 1259 int r = -1; 1260 if ((r = readServerResponse()) != 220) { 1261 serverSocket.close(); 1262 serverSocket = null; 1263 serverOutput = null; 1264 serverInput = null; 1265 lineInputStream = null; 1266 if (debug) 1267 out.println("DEBUG SMTP: could not connect to host \"" + 1268 server + "\", port: " + port + 1269 ", response: " + r + "\n"); 1270 throw new MessagingException( 1271 "Could not connect to SMTP host: " + server + 1272 ", port: " + port + 1273 ", response: " + r); 1274 } else { 1275 if (debug) 1276 out.println("DEBUG SMTP: connected to host \"" + 1277 server + "\", port: " + port + "\n"); 1278 } 1279 } catch (UnknownHostException uhex) { 1280 throw new MessagingException("Unknown SMTP host: " + server, uhex); 1281 } catch (IOException ioe) { 1282 throw new MessagingException("Could not connect to SMTP host: " + 1283 server + ", port: " + port, ioe); 1284 } 1285 } 1286 1287 1291 private void openServer() throws MessagingException { 1292 int port = -1; 1293 String server = "UNKNOWN"; 1294 try { 1295 port = serverSocket.getPort(); 1296 server = serverSocket.getInetAddress().getHostName(); 1297 if (debug) 1298 out.println("DEBUG SMTP: starting protocol to host \"" + 1299 server + "\", port " + port); 1300 1301 initStreams(); 1302 1303 int r = -1; 1304 if ((r = readServerResponse()) != 220) { 1305 serverSocket.close(); 1306 serverSocket = null; 1307 serverOutput = null; 1308 serverInput = null; 1309 lineInputStream = null; 1310 if (debug) 1311 out.println("DEBUG SMTP: got bad greeting from host \"" + 1312 server + "\", port: " + port + 1313 ", response: " + r + "\n"); 1314 throw new MessagingException( 1315 "Got bad greeting from SMTP host: " + server + 1316 ", port: " + port + 1317 ", response: " + r); 1318 } else { 1319 if (debug) 1320 out.println("DEBUG SMTP: protocol started to host \"" + 1321 server + "\", port: " + port + "\n"); 1322 } 1323 } catch (IOException ioe) { 1324 throw new MessagingException( 1325 "Could not start protocol to SMTP host: " + 1326 server + ", port: " + port, ioe); 1327 } 1328 } 1329 1330 1331 private void initStreams() throws IOException { 1332 Properties props = session.getProperties(); 1333 PrintStream out = session.getDebugOut(); 1334 boolean debug = session.getDebug(); 1335 1336 String s = props.getProperty("mail.debug.quote"); 1337 boolean quote = s != null && s.equalsIgnoreCase("true"); 1338 1339 TraceInputStream traceInput = 1340 new TraceInputStream(serverSocket.getInputStream(), out); 1341 traceInput.setTrace(debug); 1342 traceInput.setQuote(quote); 1343 1344 TraceOutputStream traceOutput = 1345 new TraceOutputStream(serverSocket.getOutputStream(), out); 1346 traceOutput.setTrace(debug); 1347 traceOutput.setQuote(quote); 1348 1349 serverOutput = 1350 new BufferedOutputStream(traceOutput); 1351 serverInput = 1352 new BufferedInputStream(traceInput); 1353 lineInputStream = new LineInputStream(serverInput); 1354 } 1355 1356 private void issueCommand(String cmd, int expect) 1357 throws MessagingException { 1358 sendCommand(cmd); 1359 1360 if (readServerResponse() != expect) 1363 throw new MessagingException(lastServerResponse); 1364 } 1365 1366 1369 private void issueSendCommand(String cmd, int expect) 1370 throws MessagingException { 1371 sendCommand(cmd); 1372 1373 int ret; 1376 if ((ret = readServerResponse()) != expect) { 1377 int vsl = validSentAddr == null ? 0 : validSentAddr.length; 1380 int vul = validUnsentAddr == null ? 0 : validUnsentAddr.length; 1381 Address[] valid = new Address[vsl + vul]; 1382 if (vsl > 0) 1383 System.arraycopy(validSentAddr, 0, valid, 0, vsl); 1384 if (vul > 0) 1385 System.arraycopy(validUnsentAddr, 0, valid, vsl, vul); 1386 validSentAddr = null; 1387 validUnsentAddr = valid; 1388 throw new SMTPSendFailedException(cmd, ret, lastServerResponse, 1389 exception, validSentAddr, validUnsentAddr, invalidAddr); 1390 } 1391 } 1392 1393 private int simpleCommand(String cmd) throws MessagingException { 1394 sendCommand(cmd); 1395 return readServerResponse(); 1396 } 1397 1398 private int simpleCommand(byte[] cmd) throws MessagingException { 1399 sendCommand(cmd); 1400 return readServerResponse(); 1401 } 1402 1403 1407 private void sendCommand(String cmd) throws MessagingException { 1408 sendCommand(ASCIIUtility.getBytes(cmd)); 1409 } 1410 1411 private void sendCommand(byte[] cmdBytes) throws MessagingException { 1412 1415 try { 1416 serverOutput.write(cmdBytes); 1417 serverOutput.write(CRLF); 1418 serverOutput.flush(); 1419 } catch (IOException ex) { 1420 throw new MessagingException("Can't send command to SMTP host", ex); 1421 } 1422 } 1423 1424 1429 private int readServerResponse() throws MessagingException { 1430 String serverResponse = ""; 1431 int returnCode = 0; 1432 StringBuffer buf = new StringBuffer (100); 1433 1434 try { 1437 String line = null; 1438 1439 do { 1440 line = lineInputStream.readLine(); 1441 if (line == null) { 1442 serverResponse = buf.toString(); 1443 if (serverResponse.length() == 0) 1444 serverResponse = "[EOF]"; 1445 lastServerResponse = serverResponse; 1446 lastReturnCode = -1; 1447 if (debug) 1448 out.println("DEBUG SMTP: EOF: " + serverResponse); 1449 return -1; 1450 } 1451 buf.append(line); 1452 buf.append("\n"); 1453 } while (isNotLastLine(line)); 1454 1455 serverResponse = buf.toString(); 1456 } catch (IOException ioex) { 1457 if (debug) 1458 out.println("DEBUG SMTP: exception reading response: " + ioex); 1459 lastServerResponse = ""; 1461 lastReturnCode = 0; 1462 throw new MessagingException("Exception reading response", ioex); 1463 } 1465 1466 1470 if (serverResponse != null && serverResponse.length() >= 3) { 1472 try { 1473 returnCode = Integer.parseInt(serverResponse.substring(0, 3)); 1474 } catch (NumberFormatException nfe) { 1475 try { 1476 close(); 1477 } catch (MessagingException mex) { 1478 if (debug) 1480 mex.printStackTrace(out); 1481 } 1482 returnCode = -1; 1483 } catch (StringIndexOutOfBoundsException ex) { 1484 try { 1486 close(); 1487 } catch (MessagingException mex) { 1488 if (debug) 1490 mex.printStackTrace(out); 1491 } 1492 returnCode = -1; 1493 } 1494 } else { 1495 returnCode = -1; 1496 } 1497 if (returnCode == -1 && debug) 1498 out.println("DEBUG SMTP: bad server response: " + serverResponse); 1499 1500 lastServerResponse = serverResponse; 1501 lastReturnCode = returnCode; 1502 return returnCode; 1503 } 1504 1505 1509 private void checkConnected() { 1510 if (!super.isConnected()) 1511 throw new IllegalStateException ("Not connected"); 1512 } 1513 1514 private boolean isNotLastLine(String line) { 1516 return line != null && line.length() >= 4 && line.charAt(3) == '-'; 1517 } 1518 1519 private String normalizeAddress(String addr) { 1521 if ((!addr.startsWith("<")) && (!addr.endsWith(">"))) 1522 return "<" + addr + ">"; 1523 else 1524 return addr; 1525 } 1526 1527 1539 public boolean supportsExtension(String ext) { 1540 return extMap != null && extMap.get(ext.toUpperCase()) != null; 1541 } 1542 1543 1552 public String getExtensionParameter(String ext) { 1553 return extMap == null ? null : (String )extMap.get(ext.toUpperCase()); 1554 } 1555 1556 private boolean supportsAuthentication(String auth) { 1557 if (extMap == null) 1558 return false; 1559 String a = (String )extMap.get("AUTH"); 1560 if (a == null) 1561 return false; 1562 StringTokenizer st = new StringTokenizer(a); 1563 while (st.hasMoreTokens()) { 1564 String tok = st.nextToken(); 1565 if (tok.equalsIgnoreCase(auth)) 1566 return true; 1567 } 1568 return false; 1569 } 1570 1571 private static char[] hexchar = { 1572 '0', '1', '2', '3', '4', '5', '6', '7', 1573 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 1574 }; 1575 1576 1592 private String xtext(String s) { 1593 StringBuffer sb = null; 1594 for (int i = 0; i < s.length(); i++) { 1595 char c = s.charAt(i); 1596 if (c >= 128) throw new IllegalArgumentException ( 1598 "Non-ASCII character in SMTP submitter: " + s); 1599 if (c < '!' || c > '~' || c == '+' || c == '=') { 1600 if (sb == null) { 1601 sb = new StringBuffer (s.length() + 4); 1602 sb.append(s.substring(0, i)); 1603 } 1604 sb.append('+'); 1605 sb.append(hexchar[(((int)c)& 0xf0) >> 4]); 1606 sb.append(hexchar[((int)c)& 0x0f]); 1607 } else { 1608 if (sb != null) 1609 sb.append(c); 1610 } 1611 } 1612 return sb != null ? sb.toString() : s; 1613 } 1614} 1615 | Popular Tags |