Home | History | Annotate | Download | only in smtp
      1 /*
      2  * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package sun.net.smtp;
     27 
     28 import java.util.StringTokenizer;
     29 import java.io.*;
     30 import java.net.*;
     31 import sun.net.TransferProtocolClient;
     32 
     33 /**
     34  * This class implements the SMTP client.
     35  * You can send a piece of mail by creating a new SmtpClient, calling
     36  * the "to" method to add destinations, calling "from" to name the
     37  * sender, calling startMessage to return a stream to which you write
     38  * the message (with RFC733 headers) and then you finally close the Smtp
     39  * Client.
     40  *
     41  * @author      James Gosling
     42  */
     43 
     44 public class SmtpClient extends TransferProtocolClient {
     45 
     46     String mailhost;
     47     SmtpPrintStream message;
     48 
     49     /**
     50      * issue the QUIT command to the SMTP server and close the connection.
     51      */
     52     public void closeServer() throws IOException {
     53         if (serverIsOpen()) {
     54             closeMessage();
     55             issueCommand("QUIT\r\n", 221);
     56             super.closeServer();
     57         }
     58     }
     59 
     60     void issueCommand(String cmd, int expect) throws IOException {
     61         sendServer(cmd);
     62         int reply;
     63         while ((reply = readServerResponse()) != expect)
     64             if (reply != 220) {
     65                 throw new SmtpProtocolException(getResponseString());
     66             }
     67     }
     68 
     69     private void toCanonical(String s) throws IOException {
     70         if (s.startsWith("<"))
     71             issueCommand("rcpt to: " + s + "\r\n", 250);
     72         else
     73             issueCommand("rcpt to: <" + s + ">\r\n", 250);
     74     }
     75 
     76     public void to(String s) throws IOException {
     77         int st = 0;
     78         int limit = s.length();
     79         int pos = 0;
     80         int lastnonsp = 0;
     81         int parendepth = 0;
     82         boolean ignore = false;
     83         while (pos < limit) {
     84             int c = s.charAt(pos);
     85             if (parendepth > 0) {
     86                 if (c == '(')
     87                     parendepth++;
     88                 else if (c == ')')
     89                     parendepth--;
     90                 if (parendepth == 0)
     91                     if (lastnonsp > st)
     92                         ignore = true;
     93                     else
     94                         st = pos + 1;
     95             } else if (c == '(')
     96                 parendepth++;
     97             else if (c == '<')
     98                 st = lastnonsp = pos + 1;
     99             else if (c == '>')
    100                 ignore = true;
    101             else if (c == ',') {
    102                 if (lastnonsp > st)
    103                     toCanonical(s.substring(st, lastnonsp));
    104                 st = pos + 1;
    105                 ignore = false;
    106             } else {
    107                 if (c > ' ' && !ignore)
    108                     lastnonsp = pos + 1;
    109                 else if (st == pos)
    110                     st++;
    111             }
    112             pos++;
    113         }
    114         if (lastnonsp > st)
    115             toCanonical(s.substring(st, lastnonsp));
    116     }
    117 
    118     public void from(String s) throws IOException {
    119         if (s.startsWith("<"))
    120             issueCommand("mail from: " + s + "\r\n", 250);
    121         else
    122             issueCommand("mail from: <" + s + ">\r\n", 250);
    123     }
    124 
    125     /** open a SMTP connection to host <i>host</i>. */
    126     private void openServer(String host) throws IOException {
    127         mailhost = host;
    128         openServer(mailhost, 25);
    129         issueCommand("helo "+InetAddress.getLocalHost().getHostName()+"\r\n", 250);
    130     }
    131 
    132     public PrintStream startMessage() throws IOException {
    133         issueCommand("data\r\n", 354);
    134         try {
    135             message = new SmtpPrintStream(serverOutput, this);
    136         } catch (UnsupportedEncodingException e) {
    137             throw new InternalError(encoding+" encoding not found");
    138         }
    139         return message;
    140     }
    141 
    142     void closeMessage() throws IOException {
    143         if (message != null)
    144             message.close();
    145     }
    146 
    147     /** New SMTP client connected to host <i>host</i>. */
    148     public SmtpClient (String host) throws IOException {
    149         super();
    150         if (host != null) {
    151             try {
    152                 openServer(host);
    153                 mailhost = host;
    154                 return;
    155             } catch(Exception e) {
    156             }
    157         }
    158         try {
    159             String s;
    160             mailhost = java.security.AccessController.doPrivileged(
    161                     new sun.security.action.GetPropertyAction("mail.host"));
    162             if (mailhost != null) {
    163                 openServer(mailhost);
    164                 return;
    165             }
    166         } catch(Exception e) {
    167         }
    168         try {
    169             mailhost = "localhost";
    170             openServer(mailhost);
    171         } catch(Exception e) {
    172             mailhost = "mailhost";
    173             openServer(mailhost);
    174         }
    175     }
    176 
    177     /** Create an uninitialized SMTP client. */
    178     public SmtpClient () throws IOException {
    179         this(null);
    180     }
    181 
    182     public SmtpClient(int to) throws IOException {
    183         super();
    184         setConnectTimeout(to);
    185         try {
    186             String s;
    187             mailhost = java.security.AccessController.doPrivileged(
    188                     new sun.security.action.GetPropertyAction("mail.host"));
    189             if (mailhost != null) {
    190                 openServer(mailhost);
    191                 return;
    192             }
    193         } catch(Exception e) {
    194         }
    195         try {
    196             mailhost = "localhost";
    197             openServer(mailhost);
    198         } catch(Exception e) {
    199             mailhost = "mailhost";
    200             openServer(mailhost);
    201         }
    202     }
    203 
    204     public String getMailHost() {
    205         return mailhost;
    206     }
    207 
    208     String getEncoding () {
    209         return encoding;
    210     }
    211 }
    212 
    213 class SmtpPrintStream extends java.io.PrintStream {
    214     private SmtpClient target;
    215     private int lastc = '\n';
    216 
    217     SmtpPrintStream (OutputStream fos, SmtpClient cl) throws UnsupportedEncodingException {
    218         super(fos, false, cl.getEncoding());
    219         target = cl;
    220     }
    221 
    222     public void close() {
    223         if (target == null)
    224             return;
    225         if (lastc != '\n') {
    226             write('\n');
    227         }
    228         try {
    229             target.issueCommand(".\r\n", 250);
    230             target.message = null;
    231             out = null;
    232             target = null;
    233         } catch (IOException e) {
    234         }
    235     }
    236 
    237     public void write(int b) {
    238         try {
    239             // quote a dot at the beginning of a line
    240             if (lastc == '\n' && b == '.') {
    241                 out.write('.');
    242             }
    243 
    244             // translate NL to CRLF
    245             if (b == '\n' && lastc != '\r') {
    246                 out.write('\r');
    247             }
    248             out.write(b);
    249             lastc = b;
    250         } catch (IOException e) {
    251         }
    252     }
    253 
    254     public void write(byte b[], int off, int len) {
    255         try {
    256             int lc = lastc;
    257             while (--len >= 0) {
    258                 int c = b[off++];
    259 
    260                 // quote a dot at the beginning of a line
    261                 if (lc == '\n' && c == '.')
    262                     out.write('.');
    263 
    264                 // translate NL to CRLF
    265                 if (c == '\n' && lc != '\r') {
    266                     out.write('\r');
    267                 }
    268                 out.write(c);
    269                 lc = c;
    270             }
    271             lastc = lc;
    272         } catch (IOException e) {
    273         }
    274     }
    275     public void print(String s) {
    276         int len = s.length();
    277         for (int i = 0; i < len; i++) {
    278             write(s.charAt(i));
    279         }
    280     }
    281 }
    282