001: /*
002: * NntpSession.java
003: *
004: * Copyright (C) 2000-2003 Peter Graves
005: * $Id: NntpSession.java,v 1.8 2003/06/25 18:37:45 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.IOException;
025: import java.io.OutputStreamWriter;
026: import java.net.ConnectException;
027: import java.net.Socket;
028: import java.net.SocketException;
029: import java.net.UnknownHostException;
030: import java.util.StringTokenizer;
031: import javax.swing.SwingUtilities;
032: import org.armedbear.j.Debug;
033: import org.armedbear.j.Editor;
034: import org.armedbear.j.FastStringBuffer;
035: import org.armedbear.j.Log;
036: import org.armedbear.j.ProgressNotifier;
037: import org.armedbear.j.Property;
038:
039: public final class NntpSession {
040: private static final int DEFAULT_PORT = 119;
041:
042: private String errorText;
043: private String host;
044: private int port;
045: private Socket socket;
046: private MailReader reader;
047: private OutputStreamWriter writer;
048: private String groupName;
049: private int count;
050: private int first;
051: private int last;
052:
053: public static final boolean DEFAULT_ECHO = false;
054:
055: private boolean echo = DEFAULT_ECHO;
056:
057: private NntpSession(String host, int port) {
058: this .host = host;
059: this .port = port;
060: }
061:
062: public static NntpSession getSession() {
063: return getSession(Editor.preferences().getStringProperty(
064: Property.NEWS));
065: }
066:
067: public static NntpSession getSession(String host) {
068: if (host == null || host.length() == 0)
069: return null;
070:
071: return new NntpSession(host, DEFAULT_PORT);
072: }
073:
074: public String getErrorText() {
075: return errorText;
076: }
077:
078: private void setErrorText(String s) {
079: errorText = s;
080: }
081:
082: public void setEcho(boolean b) {
083: echo = b;
084: }
085:
086: public String getHost() {
087: return host;
088: }
089:
090: public int getCount() {
091: return count;
092: }
093:
094: public int getFirst() {
095: return first;
096: }
097:
098: public int getLast() {
099: return last;
100: }
101:
102: public String getArticle(int articleNumber,
103: ProgressNotifier progressNotifier) {
104: if (socket == null)
105: return _getArticle(articleNumber, progressNotifier);
106:
107: // Existing connection.
108: int timeout = Editor.preferences().getIntegerProperty(
109: Property.NNTP_READ_TIMEOUT);
110: try {
111: socket.setSoTimeout(timeout);
112: } catch (SocketException e) {
113: Log.error(e);
114: }
115: String s = _getArticle(articleNumber, progressNotifier);
116: if (s != null)
117: return s;
118: if (progressNotifier != null && progressNotifier.cancelled())
119: return null;
120:
121: if (timeout > 0) {
122: Log.debug("reconnecting ...");
123: disconnect();
124: return _getArticle(articleNumber, progressNotifier);
125: }
126:
127: return null;
128: }
129:
130: private String _getArticle(int articleNumber,
131: ProgressNotifier progressNotifier) {
132: writeLine("ARTICLE ".concat(String.valueOf(articleNumber)));
133: String response = readLine();
134: if (response == null)
135: return null;
136: if (!response.startsWith("220"))
137: return null;
138: echo = false;
139: if (progressNotifier != null)
140: progressNotifier.progressStart();
141: FastStringBuffer sb = new FastStringBuffer(1024);
142: while (true) {
143: String s = readLine();
144: if (s == null)
145: return null;
146: if (s.equals("."))
147: break;
148: sb.append(s);
149: sb.append("\r\n");
150: if (progressNotifier != null) {
151: progressNotifier.progress("Received ", sb.length(), 0);
152: if (progressNotifier.cancelled()) {
153: Log.debug("getArticle cancelled!!");
154: abort();
155: break;
156: }
157: }
158: }
159: if (progressNotifier != null) {
160: progressNotifier.progress("Received ", sb.length(), 0);
161: progressNotifier.progressStop();
162: }
163: echo = DEFAULT_ECHO;
164: return sb.toString();
165: }
166:
167: public boolean connect() {
168: boolean succeeded = false;
169: try {
170: socket = new Socket(host, port);
171: reader = new MailReader(socket.getInputStream());
172: writer = new OutputStreamWriter(socket.getOutputStream(),
173: "ISO-8859-1");
174: readLine();
175: return true;
176: } catch (ConnectException e) {
177: setErrorText("Connection refused");
178: return false;
179: } catch (UnknownHostException e) {
180: setErrorText("Unknown host " + host);
181: return false;
182: } catch (IOException e) {
183: Log.error(e);
184: return false;
185: }
186: }
187:
188: public boolean reconnect() {
189: if (connect())
190: if (selectGroup(groupName))
191: return true;
192:
193: return false;
194: }
195:
196: public void disconnect() {
197: if (socket != null) {
198: writeLine("QUIT");
199: readLine();
200: }
201: abort();
202: }
203:
204: public void abort() {
205: if (socket != null) {
206: try {
207: socket.close();
208: } catch (IOException e) {
209: Log.error(e);
210: }
211: socket = null;
212: reader = null;
213: writer = null;
214: }
215: }
216:
217: public boolean selectGroup(String groupName) {
218: writeLine("GROUP " + groupName);
219: String response = readLine();
220: if (response == null)
221: return false;
222: StringTokenizer st = new StringTokenizer(response);
223: String token = st.nextToken();
224: if (!token.equals("211"))
225: return false;
226: count = Integer.parseInt(st.nextToken());
227: first = Integer.parseInt(st.nextToken());
228: last = Integer.parseInt(st.nextToken());
229: this .groupName = groupName;
230: return true;
231: }
232:
233: public String readLine() {
234: if (reader == null) {
235: Debug.bug("readLine reader is null");
236: return null;
237: }
238: try {
239: String s = reader.readLine();
240: if (echo && s != null)
241: Log.debug("<== ".concat(s));
242: return s;
243: } catch (IOException e) {
244: Log.error(e);
245: return null;
246: }
247: }
248:
249: public boolean writeLine(String s) {
250: if (writer == null)
251: if (!reconnect())
252: return false;
253: if (echo)
254: Log.debug("==> ".concat(s));
255: try {
256: writer.write(s);
257: writer.write("\r\n");
258: writer.flush();
259: return true;
260: } catch (Exception e) {
261: Log.error(e);
262: }
263: // Things didn't go exactly as planned. Try to reconnect.
264: Log.debug("writeLine trying to reconnect...");
265: if (connect()) {
266: if (selectGroup(groupName)) {
267: if (echo)
268: Log.debug("==> ".concat(s));
269: try {
270: writer.write(s);
271: writer.write("\r\n");
272: writer.flush();
273: return true;
274: } catch (IOException e) {
275: Log.error(e);
276: }
277: }
278: }
279: return false;
280: }
281: }
|