chris@1: /* chris@1: * SONEWS News Server chris@1: * see AUTHORS for the list of contributors chris@1: * chris@1: * This program is free software: you can redistribute it and/or modify chris@1: * it under the terms of the GNU General Public License as published by chris@1: * the Free Software Foundation, either version 3 of the License, or chris@1: * (at your option) any later version. chris@1: * chris@1: * This program is distributed in the hope that it will be useful, chris@1: * but WITHOUT ANY WARRANTY; without even the implied warranty of chris@1: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the chris@1: * GNU General Public License for more details. chris@1: * chris@1: * You should have received a copy of the GNU General Public License chris@1: * along with this program. If not, see . chris@1: */ chris@1: chris@1: package org.sonews.util.io; chris@1: chris@1: import java.io.BufferedInputStream; chris@1: import java.io.BufferedOutputStream; chris@1: import java.io.ByteArrayOutputStream; chris@1: import java.io.IOException; chris@1: import java.io.InputStream; chris@1: import java.io.UnsupportedEncodingException; chris@1: import java.net.Socket; chris@1: import java.net.UnknownHostException; chris@3: import org.sonews.config.Config; chris@1: import org.sonews.util.Log; chris@1: chris@1: /** chris@1: * Reads an news article from a NNTP server. chris@1: * @author Christian Lins chris@1: * @since sonews/0.5.0 chris@1: */ chris@1: public class ArticleReader chris@1: { chris@1: chris@1: private BufferedOutputStream out; chris@1: private BufferedInputStream in; chris@1: private String messageID; chris@1: chris@1: public ArticleReader(String host, int port, String messageID) chris@1: throws IOException, UnknownHostException chris@1: { chris@1: this.messageID = messageID; chris@1: chris@1: // Connect to NNTP server chris@1: Socket socket = new Socket(host, port); chris@1: this.out = new BufferedOutputStream(socket.getOutputStream()); chris@1: this.in = new BufferedInputStream(socket.getInputStream()); chris@1: String line = readln(this.in); chris@1: if(!line.startsWith("200 ")) chris@1: { chris@1: throw new IOException("Invalid hello from server: " + line); chris@1: } chris@1: } chris@1: chris@1: private boolean eofArticle(byte[] buf) chris@1: { chris@1: if(buf.length < 4) chris@1: { chris@1: return false; chris@1: } chris@1: chris@1: int l = buf.length - 1; chris@1: return buf[l-3] == 10 // '*\n' chris@1: && buf[l-2] == '.' // '.' chris@1: && buf[l-1] == 13 && buf[l] == 10; // '\r\n' chris@1: } chris@1: chris@1: public byte[] getArticleData() chris@1: throws IOException, UnsupportedEncodingException chris@1: { chris@3: long maxSize = Config.inst().get(Config.ARTICLE_MAXSIZE, 1024) * 1024L; chris@3: chris@1: try chris@1: { chris@1: this.out.write(("ARTICLE " + this.messageID + "\r\n").getBytes("UTF-8")); chris@1: this.out.flush(); chris@1: chris@1: String line = readln(this.in); chris@1: if(line.startsWith("220 ")) chris@1: { chris@1: ByteArrayOutputStream buf = new ByteArrayOutputStream(); chris@1: chris@1: while(!eofArticle(buf.toByteArray())) chris@1: { chris@1: for(int b = in.read(); b != 10; b = in.read()) chris@1: { chris@1: buf.write(b); chris@1: } chris@1: chris@1: buf.write(10); chris@3: if(buf.size() > maxSize) chris@3: { cli@16: Log.get().warning("Skipping message that is too large: " + buf.size()); chris@3: return null; chris@3: } chris@1: } chris@1: chris@1: return buf.toByteArray(); chris@1: } chris@1: else chris@1: { cli@16: Log.get().warning("ArticleReader: " + line); chris@1: return null; chris@1: } chris@1: } chris@1: catch(IOException ex) chris@1: { chris@1: throw ex; chris@1: } chris@1: finally chris@1: { chris@1: this.out.write("QUIT\r\n".getBytes("UTF-8")); chris@1: this.out.flush(); chris@1: this.out.close(); chris@1: } chris@1: } chris@1: chris@1: private String readln(InputStream in) chris@1: throws IOException chris@1: { chris@1: ByteArrayOutputStream buf = new ByteArrayOutputStream(); chris@1: for(int b = in.read(); b != 10 /* \n */; b = in.read()) chris@1: { chris@1: buf.write(b); chris@1: } chris@1: chris@1: return new String(buf.toByteArray()); chris@1: } chris@1: chris@1: }