blob: a0c28dcd3336ee0d3b007fac268d1363831078a0 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1995-2003 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.net.smtp;
27
28import java.util.StringTokenizer;
29import java.io.*;
30import java.net.*;
31import 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
44public 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
213class 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}