src/org/sonews/util/io/ArticleReader.java
author cli
Sun, 29 Aug 2010 17:43:58 +0200
changeset 36 c404a87db5b7
parent 35 ed84c8bdd87b
child 37 74139325d305
permissions -rw-r--r--
Add some checks to prevent #13 happen.
     1 /*
     2  *   SONEWS News Server
     3  *   see AUTHORS for the list of contributors
     4  *
     5  *   This program is free software: you can redistribute it and/or modify
     6  *   it under the terms of the GNU General Public License as published by
     7  *   the Free Software Foundation, either version 3 of the License, or
     8  *   (at your option) any later version.
     9  *
    10  *   This program is distributed in the hope that it will be useful,
    11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  *   GNU General Public License for more details.
    14  *
    15  *   You should have received a copy of the GNU General Public License
    16  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  */
    18 
    19 package org.sonews.util.io;
    20 
    21 import java.io.BufferedInputStream;
    22 import java.io.BufferedOutputStream;
    23 import java.io.ByteArrayOutputStream;
    24 import java.io.IOException;
    25 import java.io.InputStream;
    26 import java.io.UnsupportedEncodingException;
    27 import java.net.Socket;
    28 import java.net.UnknownHostException;
    29 import org.sonews.config.Config;
    30 import org.sonews.util.Log;
    31 
    32 /**
    33  * Reads an news article from a NNTP server.
    34  * @author Christian Lins
    35  * @since sonews/0.5.0
    36  */
    37 public class ArticleReader 
    38 {
    39 
    40   private BufferedOutputStream out;
    41   private BufferedInputStream  in;
    42   private String               messageID;
    43   
    44   public ArticleReader(String host, int port, String messageID)
    45     throws IOException, UnknownHostException
    46   {
    47     this.messageID = messageID;
    48 
    49     // Connect to NNTP server
    50     Socket socket = new Socket(host, port);
    51     this.out = new BufferedOutputStream(socket.getOutputStream());
    52     this.in  = new BufferedInputStream(socket.getInputStream());
    53     String line = readln(this.in);
    54     if(!line.startsWith("200 "))
    55     {
    56       throw new IOException("Invalid hello from server: " + line);
    57     }
    58   }
    59   
    60   private boolean eofArticle(byte[] buf)
    61   {
    62     if(buf.length < 4)
    63     {
    64       return false;
    65     }
    66     
    67     int l = buf.length - 1;
    68     return buf[l-3] == 10 // '*\n'
    69         && buf[l-2] == '.'                   // '.'
    70         && buf[l-1] == 13 && buf[l] == 10;  // '\r\n'
    71   }
    72   
    73   public byte[] getArticleData()
    74     throws IOException, UnsupportedEncodingException
    75   {
    76     long maxSize = Config.inst().get(Config.ARTICLE_MAXSIZE, 1024) * 1024L;
    77 
    78     try
    79     {
    80       this.out.write(("ARTICLE " + this.messageID + "\r\n").getBytes("UTF-8"));
    81       this.out.flush();
    82 
    83       String line = readln(this.in);
    84       if(line.startsWith("220 "))
    85       {
    86         ByteArrayOutputStream buf = new ByteArrayOutputStream();
    87         
    88         while(!eofArticle(buf.toByteArray()))
    89         {
    90           for(int b = in.read(); b != 10; b = in.read())
    91           {
    92             buf.write(b);
    93           }
    94 
    95           buf.write(10);
    96           if(buf.size() > maxSize)
    97           {
    98             Log.get().warning("Skipping message that is too large: " + buf.size());
    99             return null;
   100           }
   101         }
   102         
   103         return buf.toByteArray();
   104       }
   105       else
   106       {
   107         Log.get().warning("ArticleReader: " + line);
   108         return null;
   109       }
   110     }
   111     catch(IOException ex)
   112     {
   113       throw ex;
   114     }
   115     finally
   116     {
   117       this.out.write("QUIT\r\n".getBytes("UTF-8"));
   118       this.out.flush();
   119       this.out.close();
   120     }
   121   }
   122   
   123   private String readln(InputStream in)
   124     throws IOException
   125   {
   126     ByteArrayOutputStream buf = new ByteArrayOutputStream();
   127     for(int b = in.read(); b != 10 /* \n */; b = in.read())
   128     {
   129       buf.write(b);
   130     }
   131     
   132     return new String(buf.toByteArray());
   133   }
   134 
   135 }