KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > mail > smtp > SmtpTransport


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.mail.smtp;
31
32 import com.caucho.server.util.CauchoSystem;
33 import com.caucho.util.L10N;
34 import com.caucho.vfs.ReadStream;
35 import com.caucho.vfs.SocketStream;
36 import com.caucho.vfs.WriteStream;
37
38 import javax.mail.Address JavaDoc;
39 import javax.mail.Message JavaDoc;
40 import javax.mail.MessagingException JavaDoc;
41 import javax.mail.Session JavaDoc;
42 import javax.mail.Transport JavaDoc;
43 import javax.mail.URLName JavaDoc;
44 import javax.mail.internet.InternetAddress JavaDoc;
45 import javax.mail.internet.MimeMessage JavaDoc;
46 import java.io.IOException JavaDoc;
47 import java.io.OutputStream JavaDoc;
48 import java.net.Socket JavaDoc;
49 import java.util.logging.Level JavaDoc;
50 import java.util.logging.Logger JavaDoc;
51
52 /**
53  * Resin's SMTP transport implementation.
54  */

55 public class SmtpTransport extends Transport JavaDoc {
56   private static final L10N L = new L10N(SmtpTransport.class);
57   private static final Logger JavaDoc log
58     = Logger.getLogger(SmtpTransport.class.getName());
59
60   private Socket JavaDoc _socket;
61
62   private ReadStream _is;
63   private WriteStream _os;
64   
65   public SmtpTransport(Session JavaDoc session, URLName JavaDoc urlName)
66   {
67     super(session, urlName);
68   }
69   /**
70    * Connect for the protocol.
71    */

72   protected boolean protocolConnect(String JavaDoc host,
73                     int port,
74                     String JavaDoc user,
75                     String JavaDoc password)
76     throws MessagingException JavaDoc
77   {
78     if (host == null)
79       host = "localhost";
80
81     if (port < 0)
82       port = 25;
83
84     // XXX: pooling
85
if (_socket != null)
86       throw new MessagingException JavaDoc(L.l("Attempted to connect to open connection."));
87
88     try {
89       _socket = new Socket JavaDoc(host, port);
90       _socket.setSoTimeout(10000);
91       SocketStream s = new SocketStream(_socket);
92     
93       _os = new WriteStream(s);
94       _is = new ReadStream(s, _os);
95
96       String JavaDoc line = _is.readLine();
97       
98       log.fine("smtp connection to " + host + ":" + port + " succeeded");
99       log.fine("smtp: " + line);
100
101       _os.print("EHLO " + CauchoSystem.getLocalHost() + "\r\n");
102       _os.flush();
103
104       readResponse();
105
106       setConnected(true);
107     } catch (IOException JavaDoc e) {
108       log.fine("smtp connection to " + host + ":" + port + " failed: " + e);
109
110       log.log(Level.FINER, e.toString(), e);
111       
112       throw new MessagingException JavaDoc("smtp connection to " + host + ":" + port + " failed.\n" + e);
113     }
114
115     return true;
116   }
117
118   /**
119    * Sends a message to the specified recipients.
120    *
121    * @param msg the message to send
122    * @param addresses the destination addresses
123    */

124   public void sendMessage(Message JavaDoc msg, Address JavaDoc []addresses)
125     throws MessagingException JavaDoc
126   {
127     if (! isConnected())
128       throw new MessagingException JavaDoc("Transport does not have an active connection.");
129
130     if (! (msg instanceof MimeMessage JavaDoc))
131       throw new MessagingException JavaDoc("message must be a MimeMessage at '"
132                    + msg.getClass().getName() + "'");
133
134     MimeMessage JavaDoc mimeMsg = (MimeMessage JavaDoc) msg;
135
136     try {
137       // XXX: EHLO to resync? or RSET?
138
// XXX: FROM
139

140       String JavaDoc []fromList = mimeMsg.getHeader("From");
141       String JavaDoc from;
142       
143       if (fromList == null || fromList.length < 1) {
144     // XXX: possible should have a default
145
throw new MessagingException JavaDoc("message should have a sender");
146       }
147       else
148     from = fromList[0];
149       
150       _os.print("MAIL FROM:<" + from + ">\r\n");
151       _os.flush();
152
153       if (log.isLoggable(Level.FINER))
154     log.finer("mail from:<" + from + ">");
155
156       readResponse();
157
158       for (int i = 0; i < addresses.length; i++) {
159     InternetAddress JavaDoc addr = (InternetAddress JavaDoc) addresses[i];
160
161     if (log.isLoggable(Level.FINER))
162       log.finer("mail to:<" + addr.getAddress() + ">");
163
164     _os.print("RCPT TO:<" + addr.getAddress() + ">\r\n");
165     _os.flush();
166
167     readResponse();
168       }
169
170       _os.print("DATA\r\n");
171       _os.flush();
172
173       String JavaDoc line = _is.readLine();
174       if (! line.startsWith("354 "))
175     throw new MessagingException JavaDoc("Data not accepted: " + line);
176
177       mimeMsg.writeTo(new DataFilter(_os));
178
179       _os.print("\r\n.\r\n");
180       _os.flush();
181     } catch (IOException JavaDoc e) {
182       log.log(Level.FINER, e.toString(), e);
183
184       throw new MessagingException JavaDoc(e.toString());
185     }
186   }
187
188   private int readResponse()
189     throws IOException JavaDoc, MessagingException JavaDoc
190   {
191     while (true) {
192       String JavaDoc line = _is.readLine();
193       if (line.length() < 4)
194     throw new MessagingException JavaDoc(line);
195
196       int status = 0;
197       for (int i = 0; i < 3; i++) {
198     char ch;
199
200     if ('0' <= (ch = line.charAt(i)) && ch <= '9')
201       status = 10 * status + ch - '0';
202       }
203
204       if ((status / 100) % 10 != 2)
205     throw new MessagingException JavaDoc(line);
206
207       if (line.charAt(3) != '-')
208     return status;
209     }
210   }
211
212   /**
213    * Close connection.
214    */

215   public void close()
216     throws MessagingException JavaDoc
217   {
218     Socket JavaDoc socket = _socket;
219     _socket = null;
220
221     WriteStream os = _os;
222     _os = null;
223     
224     setConnected(false);
225
226     try {
227       if (os != null) {
228     os.print("QUIT\r\n");
229     os.flush();
230       }
231     } catch (IOException JavaDoc e) {
232     }
233
234     try {
235       if (socket != null)
236     socket.close();
237     } catch (IOException JavaDoc e) {
238     }
239   }
240
241   private class DataFilter extends OutputStream JavaDoc {
242     private OutputStream JavaDoc _os;
243     
244     private boolean _isCr;
245     private boolean _isLf;
246
247     DataFilter(OutputStream JavaDoc os)
248     {
249       _os = os;
250     }
251     
252     public void write(int ch)
253       throws IOException JavaDoc
254     {
255       switch (ch) {
256       case '\r':
257     _isCr = true;
258     _isLf = false;
259     break;
260       case '\n':
261     _isLf = _isCr;
262     _isCr = false;
263     break;
264       case '.':
265     if (_isLf)
266       _os.write('.');
267     _isLf = false;
268     _isCr = false;
269     break;
270       default:
271     _isLf = false;
272     _isCr = false;
273     break;
274       }
275
276       _os.write(ch);
277     }
278   }
279 }
280
Popular Tags