001: /*
002: * SmtpSession.java
003: *
004: * Copyright (C) 2000-2003 Peter Graves
005: * $Id: SmtpSession.java,v 1.3 2003/06/28 00:19:36 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j.mail;
023:
024: import java.io.BufferedReader;
025: import java.io.BufferedWriter;
026: import java.io.IOException;
027: import java.io.InputStreamReader;
028: import java.io.OutputStreamWriter;
029: import java.io.Writer;
030: import java.net.ConnectException;
031: import java.net.InetAddress;
032: import java.net.NoRouteToHostException;
033: import java.net.Socket;
034: import java.net.UnknownHostException;
035: import java.util.List;
036: import org.armedbear.j.Debug;
037: import org.armedbear.j.Editor;
038: import org.armedbear.j.File;
039: import org.armedbear.j.FastStringBuffer;
040: import org.armedbear.j.Log;
041: import org.armedbear.j.MessageDialog;
042: import org.armedbear.j.Property;
043: import org.armedbear.j.Utilities;
044:
045: public final class SmtpSession extends Writer {
046: private static final int DEFAULT_PORT = 25;
047:
048: private boolean echo = false;
049: private String hostName;
050: private int port;
051: private Socket socket;
052: private BufferedReader reader;
053: private BufferedWriter writer;
054: private boolean connected;
055: private String errorText;
056:
057: private SmtpSession(String hostName) {
058: this .hostName = hostName;
059: this .port = DEFAULT_PORT;
060: }
061:
062: private SmtpSession(String hostName, int port) {
063: this .hostName = hostName;
064: this .port = port;
065: }
066:
067: public final void setEcho(boolean b) {
068: echo = b;
069: }
070:
071: // Returns session with connection already established (or null).
072: public static SmtpSession getDefaultSession() {
073: return getSession(Editor.preferences().getStringProperty(
074: Property.SMTP));
075: }
076:
077: // Returns session with connection already established (or null).
078: public static SmtpSession getSession(String server) {
079: if (server == null)
080: return null;
081: SmtpSession session = null;
082: // Port may be specified.
083: int index = server.indexOf(':');
084: if (index < 0) {
085: session = new SmtpSession(server);
086: } else {
087: try {
088: int port = Integer
089: .parseInt(server.substring(index + 1));
090: String hostName = server.substring(0, index);
091: session = new SmtpSession(hostName, port);
092: } catch (NumberFormatException e) {
093: Log.error(e);
094: FastStringBuffer sb = new FastStringBuffer();
095: sb.append("Unable to parse SMTP server name \"");
096: sb.append(server);
097: sb.append('"');
098: MessageDialog.showMessageDialog(sb.toString(), "Error");
099: return null;
100: }
101: }
102: Debug.assertTrue(session != null);
103: session.setEcho(true);
104: if (!session.connect())
105: return null;
106: session.setEcho(false);
107: return session;
108: }
109:
110: public final String getErrorText() {
111: return errorText;
112: }
113:
114: public boolean sendMessage(SendMail sm, File messageFile) {
115: List addressees = sm.getAddressees();
116: if (addressees == null || addressees.size() == 0)
117: return false;
118: if (!connect())
119: return false;
120: try {
121: setEcho(true);
122: FastStringBuffer sb = new FastStringBuffer("mail from:<");
123: sb.append(sm.getFromAddress());
124: sb.append('>');
125: writeLine(sb.toString());
126: if (getResponse() != 250)
127: return false;
128: for (int i = 0; i < addressees.size(); i++) {
129: String addressee = (String) addressees.get(i);
130: String addr = sm.getAddress(addressee);
131: if (addr == null) {
132: errorText = "Invalid addressee \"" + addressee
133: + "\"";
134: return false;
135: }
136: sb.setText("rcpt to:<");
137: sb.append(addr);
138: sb.append('>');
139: writeLine(sb.toString());
140: if (getResponse() != 250) {
141: errorText = "Address not accepted \"" + addr + "\"";
142: return false;
143: }
144: }
145: writeLine("data");
146: if (getResponse() != 354)
147: return false;
148: setEcho(false);
149: BufferedReader messageFileReader = new BufferedReader(
150: new InputStreamReader(messageFile.getInputStream()));
151: String s;
152: while ((s = messageFileReader.readLine()) != null)
153: writeLine(s);
154: setEcho(true);
155: writeLine(".");
156: if (getResponse() != 250)
157: return false;
158: quit();
159: } catch (Throwable t) {
160: Log.error(t);
161: } finally {
162: setEcho(false);
163: disconnect();
164: }
165: // Add addressees to address book.
166: AddressBook addressBook = AddressBook.getGlobalAddressBook();
167: for (int i = 0; i < addressees.size(); i++) {
168: String addressee = (String) addressees.get(i);
169: MailAddress a = MailAddress.parseAddress(addressee);
170: if (a != null) {
171: addressBook.maybeAddMailAddress(a);
172: addressBook.promote(a);
173: }
174: }
175: AddressBook.saveGlobalAddressBook();
176: return true;
177: }
178:
179: public boolean connect() {
180: if (connected)
181: return true;
182: Log.debug("connecting to port " + port + " on " + hostName
183: + " ...");
184: try {
185: socket = new Socket(hostName, port);
186: } catch (UnknownHostException e) {
187: errorText = "Unknown SMTP server " + hostName;
188: return false;
189: } catch (NoRouteToHostException e) {
190: errorText = "No route to SMTP server " + hostName;
191: return false;
192: } catch (ConnectException e) {
193: errorText = "Connection refused by SMTP server " + hostName;
194: return false;
195: } catch (IOException e) {
196: Log.error(e);
197: errorText = e.toString();
198: return false;
199: }
200: try {
201: reader = new BufferedReader(new InputStreamReader(socket
202: .getInputStream()));
203: writer = new BufferedWriter(new OutputStreamWriter(socket
204: .getOutputStream()));
205: getResponse();
206: writeLine("HELO "
207: + InetAddress.getLocalHost().getHostAddress());
208: if (getResponse() == 250) {
209: connected = true;
210: return true;
211: }
212: } catch (IOException e) {
213: Log.error(e);
214: }
215: return false;
216: }
217:
218: public void quit() {
219: setEcho(true);
220: writeLine("QUIT");
221: getResponse();
222: setEcho(false);
223: disconnect();
224: }
225:
226: public synchronized void disconnect() {
227: if (connected) {
228: try {
229: socket.close();
230: } catch (IOException e) {
231: Log.error(e);
232: }
233: socket = null;
234: reader = null;
235: writer = null;
236: connected = false;
237: }
238: }
239:
240: public int getResponse() {
241: while (true) {
242: String s = readLine();
243: if (s == null)
244: break;
245: if (s.length() < 4)
246: break;
247: if (s.charAt(3) == ' ') {
248: try {
249: return Utilities.parseInt(s);
250: } catch (NumberFormatException e) {
251: Log.error(e);
252: }
253: break;
254: }
255: }
256: return 0;
257: }
258:
259: private String readLine() {
260: try {
261: String s = reader.readLine();
262: if (echo && s != null)
263: Log.debug("<== " + s);
264: return s;
265: } catch (IOException e) {
266: Log.error(e);
267: return null;
268: }
269: }
270:
271: public void write(int c) throws IOException {
272: writer.write(c);
273: }
274:
275: public void write(char[] chars) throws IOException {
276: writer.write(chars);
277: }
278:
279: public void write(char[] chars, int offset, int length)
280: throws IOException {
281: writer.write(chars, offset, length);
282: }
283:
284: public void write(String s) throws IOException {
285: writer.write(s);
286: }
287:
288: public void write(String s, int offset, int length)
289: throws IOException {
290: writer.write(s, offset, length);
291: }
292:
293: public void flush() throws IOException {
294: writer.flush();
295: }
296:
297: public void close() throws IOException {
298: writer.close();
299: }
300:
301: public boolean writeLine(String s) {
302: if (echo)
303: Log.debug("==> " + s);
304: try {
305: writer.write(s);
306: writer.write("\r\n");
307: writer.flush();
308: return true;
309: } catch (IOException e) {
310: Log.error(e);
311: return false;
312: }
313: }
314: }
|