diff -r 9f0b95aafaa3 -r ed84c8bdd87b org/sonews/daemon/command/OverCommand.java --- a/org/sonews/daemon/command/OverCommand.java Sun Aug 29 17:04:25 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,294 +0,0 @@ -/* - * SONEWS News Server - * see AUTHORS for the list of contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sonews.daemon.command; - -import java.io.IOException; -import java.util.List; -import org.sonews.util.Log; -import org.sonews.daemon.NNTPConnection; -import org.sonews.storage.Article; -import org.sonews.storage.ArticleHead; -import org.sonews.storage.Headers; -import org.sonews.storage.StorageBackendException; -import org.sonews.util.Pair; - -/** - * Class handling the OVER/XOVER command. - * - * Description of the XOVER command: - *
- * XOVER [range]
- *
- * The XOVER command returns information from the overview
- * database for the article(s) specified.
- *
- * The optional range argument may be any of the following:
- *              an article number
- *              an article number followed by a dash to indicate
- *                 all following
- *              an article number followed by a dash followed by
- *                 another article number
- *
- * If no argument is specified, then information from the
- * current article is displayed. Successful responses start
- * with a 224 response followed by the overview information
- * for all matched messages. Once the output is complete, a
- * period is sent on a line by itself. If no argument is
- * specified, the information for the current article is
- * returned.  A news group must have been selected earlier,
- * else a 412 error response is returned. If no articles are
- * in the range specified, a 420 error response is returned
- * by the server. A 502 response will be returned if the
- * client only has permission to transfer articles.
- *
- * Each line of output will be formatted with the article number,
- * followed by each of the headers in the overview database or the
- * article itself (when the data is not available in the overview
- * database) for that article separated by a tab character.  The
- * sequence of fields must be in this order: subject, author,
- * date, message-id, references, byte count, and line count. Other
- * optional fields may follow line count. Other optional fields may
- * follow line count. These fields are specified by examining the
- * response to the LIST OVERVIEW.FMT command. Where no data exists,
- * a null field must be provided (i.e. the output will have two tab
- * characters adjacent to each other). Servers should not output
- * fields for articles that have been removed since the XOVER database
- * was created.
- *
- * The LIST OVERVIEW.FMT command should be implemented if XOVER
- * is implemented. A client can use LIST OVERVIEW.FMT to determine
- * what optional fields  and in which order all fields will be
- * supplied by the XOVER command. 
- *
- * Note that any tab and end-of-line characters in any header
- * data that is returned will be converted to a space character.
- *
- * Responses:
- *
- *   224 Overview information follows
- *   412 No news group current selected
- *   420 No article(s) selected
- *   502 no permission
- *
- * OVER defines additional responses:
- *
- *  First form (message-id specified)
- *    224    Overview information follows (multi-line)
- *    430    No article with that message-id
- *
- *  Second form (range specified)
- *    224    Overview information follows (multi-line)
- *    412    No newsgroup selected
- *    423    No articles in that range
- *
- *  Third form (current article number used)
- *    224    Overview information follows (multi-line)
- *    412    No newsgroup selected
- *    420    Current article number is invalid
- *
- * 
- * @author Christian Lins - * @since sonews/0.5.0 - */ -public class OverCommand implements Command -{ - - public static final int MAX_LINES_PER_DBREQUEST = 200; - - @Override - public String[] getSupportedCommandStrings() - { - return new String[]{"OVER", "XOVER"}; - } - - @Override - public boolean hasFinished() - { - return true; - } - - @Override - public String impliedCapability() - { - return null; - } - - @Override - public boolean isStateful() - { - return false; - } - - @Override - public void processLine(NNTPConnection conn, final String line, byte[] raw) - throws IOException, StorageBackendException - { - if(conn.getCurrentChannel() == null) - { - conn.println("412 no newsgroup selected"); - } - else - { - String[] command = line.split(" "); - - // If no parameter was specified, show information about - // the currently selected article(s) - if(command.length == 1) - { - final Article art = conn.getCurrentArticle(); - if(art == null) - { - conn.println("420 no article(s) selected"); - return; - } - - conn.println(buildOverview(art, -1)); - } - // otherwise print information about the specified range - else - { - long artStart; - long artEnd = conn.getCurrentChannel().getLastArticleNumber(); - String[] nums = command[1].split("-"); - if(nums.length >= 1) - { - try - { - artStart = Integer.parseInt(nums[0]); - } - catch(NumberFormatException e) - { - Log.get().info(e.getMessage()); - artStart = Integer.parseInt(command[1]); - } - } - else - { - artStart = conn.getCurrentChannel().getFirstArticleNumber(); - } - - if(nums.length >=2) - { - try - { - artEnd = Integer.parseInt(nums[1]); - } - catch(NumberFormatException e) - { - e.printStackTrace(); - } - } - - if(artStart > artEnd) - { - if(command[0].equalsIgnoreCase("OVER")) - { - conn.println("423 no articles in that range"); - } - else - { - conn.println("224 (empty) overview information follows:"); - conn.println("."); - } - } - else - { - for(long n = artStart; n <= artEnd; n += MAX_LINES_PER_DBREQUEST) - { - long nEnd = Math.min(n + MAX_LINES_PER_DBREQUEST - 1, artEnd); - List> articleHeads = conn.getCurrentChannel() - .getArticleHeads(n, nEnd); - if(articleHeads.isEmpty() && n == artStart - && command[0].equalsIgnoreCase("OVER")) - { - // This reply is only valid for OVER, not for XOVER command - conn.println("423 no articles in that range"); - return; - } - else if(n == artStart) - { - // XOVER replies this although there is no data available - conn.println("224 overview information follows"); - } - - for(Pair article : articleHeads) - { - String overview = buildOverview(article.getB(), article.getA()); - conn.println(overview); - } - } // for - conn.println("."); - } - } - } - } - - private String buildOverview(ArticleHead art, long nr) - { - StringBuilder overview = new StringBuilder(); - overview.append(nr); - overview.append('\t'); - - String subject = art.getHeader(Headers.SUBJECT)[0]; - if("".equals(subject)) - { - subject = ""; - } - overview.append(escapeString(subject)); - overview.append('\t'); - - overview.append(escapeString(art.getHeader(Headers.FROM)[0])); - overview.append('\t'); - overview.append(escapeString(art.getHeader(Headers.DATE)[0])); - overview.append('\t'); - overview.append(escapeString(art.getHeader(Headers.MESSAGE_ID)[0])); - overview.append('\t'); - overview.append(escapeString(art.getHeader(Headers.REFERENCES)[0])); - overview.append('\t'); - - String bytes = art.getHeader(Headers.BYTES)[0]; - if("".equals(bytes)) - { - bytes = "0"; - } - overview.append(escapeString(bytes)); - overview.append('\t'); - - String lines = art.getHeader(Headers.LINES)[0]; - if("".equals(lines)) - { - lines = "0"; - } - overview.append(escapeString(lines)); - overview.append('\t'); - overview.append(escapeString(art.getHeader(Headers.XREF)[0])); - - // Remove trailing tabs if some data is empty - return overview.toString().trim(); - } - - private String escapeString(String str) - { - String nstr = str.replace("\r", ""); - nstr = nstr.replace('\n', ' '); - nstr = nstr.replace('\t', ' '); - return nstr.trim(); - } - -}