dfs 2003/09/04 13:32:43 Modified: net/src/java/org/apache/commons/net/nntp NNTP.java NNTPClient.java NNTPCommand.java NNTPReply.java net/xdocs changes.xml Added: net/src/java/examples ExtendedNNTPOps.java Log: Applied patch (albeit slightly altered) from Rory Winston <[EMAIL PROTECTED]> that adds extended NNTP XOVER, LIST ACTIVE, and AUTHINFO commands. Revision Changes Path 1.1 jakarta-commons/net/src/java/examples/ExtendedNNTPOps.java Index: ExtendedNNTPOps.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Commons" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package examples; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.io.PrintWriter; import java.util.ArrayList; import java.util.StringTokenizer; import org.apache.commons.net.io.DotTerminatedMessageReader; import org.apache.commons.net.nntp.NNTPClient; import org.apache.commons.net.nntp.NewsgroupInfo; public class ExtendedNNTPOps { // simple class that encapsulates some basic info about an NNTP article class Article { private int articleNumber; private String subject; private String date; private String articleId; private String from; private StringBuffer header; public Article() { header = new StringBuffer(); } public void addHeaderField(String name, String val) { header.append(name); header.append(": "); header.append(val); header.append('\n'); } public String getArticleId() { return articleId; } public int getArticleNumber() { return articleNumber; } public String getDate() { return date; } public String getFrom() { return from; } public String getSubject() { return subject; } public void setArticleId(String string) { articleId = string; } public void setArticleNumber(int i) { articleNumber = i; } public void setDate(String string) { date = string; } public void setFrom(String string) { from = string; } public void setSubject(String string) { subject = string; } } NNTPClient client; public ExtendedNNTPOps() { client = new NNTPClient(); client.addProtocolCommandListener(new PrintCommandListener( new PrintWriter(System.out))); } private Article[] getArticleInfo(int lowArticleNumber, int highArticleNumber) throws IOException { ArrayList articles = new ArrayList(); Reader reader = null; String theMessage; char[] buffer = new char[128]; reader = (DotTerminatedMessageReader) client.retrieveArticleInfo(lowArticleNumber, highArticleNumber); if (reader != null) { String theInfo = readerToString(reader); StringTokenizer st = new StringTokenizer(theInfo, "\n"); // Extract the article information // Mandatory format (from NNTP RFC 2980) is : // Subject\tAuthor\tDate\tID\tReference(s)\tByte Count\tLine Count while (st.hasMoreTokens()) { StringTokenizer stt = new StringTokenizer(st.nextToken(), "\t"); Article article = new Article(); article.setArticleNumber(Integer.parseInt(stt.nextToken())); article.setSubject(stt.nextToken()); article.setFrom(stt.nextToken()); article.setDate(stt.nextToken()); article.setArticleId(stt.nextToken()); article.addHeaderField("References", stt.nextToken()); articles.add(article); } } else { return null; } return (Article[]) articles.toArray(new Article[articles.size()]); } private String readerToString(Reader reader) { String temp; StringBuffer sb = null; BufferedReader bufReader = new BufferedReader(reader); boolean endOfHeader = false; sb = new StringBuffer(); try { temp = bufReader.readLine(); while (temp != null) { sb.append(temp); sb.append("\n"); temp = bufReader.readLine(); } } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } public void demo(String host, String user, String password) { try { client.connect(host); // AUTHINFO USER/AUTHINFO PASS boolean success = client.authenticate(user, password); if(success) { System.out.println("Authentication succeeded"); } else { System.out.println("Authentication failed, error =" + client.getReplyString()); } // XOVER NewsgroupInfo testGroup = new NewsgroupInfo(); client.selectNewsgroup("alt.test", testGroup); int lowArticleNumber = testGroup.getFirstArticle(); int highArticleNumber = testGroup.getLastArticle(); Article[] articles = getArticleInfo(lowArticleNumber, highArticleNumber); for(int i =0; i < articles.length; ++i) { System.out.println(articles[i].getSubject()); } // LIST ACTIVE NewsgroupInfo[] fanGroups = client.listNewsgroups("alt.fan.*"); for(int i = 0; i < fanGroups.length; ++i) { System.out.println(fanGroups[i].getNewsgroup()); } } catch(IOException e) { e.printStackTrace(); } } public static void main(String[] args) { ExtendedNNTPOps ops; if(args.length != 3) { System.err.println( "usage: ExtendedNNTPOps nntpserver username password"); System.exit(1); } ops = new ExtendedNNTPOps(); ops.demo(args[0], args[1], args[2]); } } /* Emacs configuration * Local variables: ** * mode: java ** * c-basic-offset: 4 ** * indent-tabs-mode: nil ** * End: ** */ 1.7 +88 -0 jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNTP.java Index: NNTP.java =================================================================== RCS file: /home/cvs/jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNTP.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- NNTP.java 26 Aug 2003 05:43:55 -0000 1.6 +++ NNTP.java 4 Sep 2003 20:32:43 -0000 1.7 @@ -933,5 +933,93 @@ { return sendCommand(NNTPCommand.QUIT); } + + /*** + * A convenience method to send the AUTHINFO USER command to the server, + * receive the reply, and return the reply code. (See RFC 2980) + * <p> + * @param username A valid username. + * @return The reply code received from the server. The server should + * return a 381 or 281 for this command. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int authinfoUser(String username) throws IOException { + String userParameter = "USER " + username; + return sendCommand(NNTPCommand.AUTHINFO, userParameter); + } + /*** + * A convenience method to send the AUTHINFO PASS command to the server, + * receive the reply, and return the reply code. If this step is + * required, it should immediately follow the AUTHINFO USER command + * (See RFC 2980) + * <p> + * @param password a valid password. + * @return The reply code received from the server. The server should + * return a 281 or 502 for this command. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int authinfoPass(String password) throws IOException { + String passParameter = "PASS " + password; + return sendCommand(NNTPCommand.AUTHINFO, passParameter); + } + + /*** + * A convenience method to send the NNTP XOVER command to the server, + * receive the reply, and return the reply code. + * <p> + * @param selectedArticles a String representation of the range of + * article headers required. This may be an article number, or a + * range of article numbers in the form "XXXX-YYYY", where XXXX + * and YYYY are valid article numbers in the current group. It + * also may be of the form "XXX-", meaning "return XXX and all + * following articles" In this revision, the last format is not + * possible (yet). + * @return The reply code received from the server. + * @exception NNTPConnectionClosedException + * If the NNTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send NNTP reply code 400. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int xover(String selectedArticles) throws IOException { + return sendCommand(NNTPCommand.XOVER, selectedArticles); + } + + /** + * A convenience wrapper for the extended LIST command that takes + * an argument, allowing us to selectively list multiple groups. + * <p> + * @param wildmat A wildmat (pseudo-regex) pattern. See RFC 2980 for + * details. + * @return the reply code received from the server. + * @throws IOException + */ + public int listActive(String wildmat) throws IOException { + StringBuffer command = new StringBuffer("ACTIVE "); + command.append(wildmat); + return sendCommand(NNTPCommand.LIST, command.toString()); + } } + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ 1.5 +104 -0 jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNTPClient.java Index: NNTPClient.java =================================================================== RCS file: /home/cvs/jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNTPClient.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- NNTPClient.java 19 Apr 2003 20:49:13 -0000 1.4 +++ NNTPClient.java 4 Sep 2003 20:32:43 -0000 1.5 @@ -959,6 +959,22 @@ return __readNewsgroupListing(); } + + /** + * An overloaded listNewsgroups() command that allows us to + * specify with a pattern what groups we want to list. Wraps the + * LIST ACTIVE command. + * <p> + * @param wildmat a pseudo-regex pattern (cf. RFC 2980) + * @return + * @throws IOException + */ + public NewsgroupInfo[] listNewsgroups(String wildmat) throws IOException + { + if(!NNTPReply.isPositiveCompletion(listActive(wildmat))) + return null; + return __readNewsgroupListing(); + } /*** @@ -1120,6 +1136,7 @@ * @exception IOException If an I/O error occurs while either sending a * command to the server or receiving a reply from the server. ***/ + public Writer postArticle() throws IOException { if (!NNTPReply.isPositiveIntermediate(post())) @@ -1151,5 +1168,92 @@ { return NNTPReply.isPositiveCompletion(quit()); } + + /** + * Log into a news server by sending the AUTHINFO USER/AUTHINFO + * PASS command sequence. This is usually sent in response to a + * 480 reply code from the NNTP server. + * <p> + * @param username a valid username + * @param password the corresponding password + * @return True for successful login, false for a failure + * @throws IOException + */ + public boolean authenticate(String username, String password) + throws IOException + { + int replyCode = authinfoUser(username); + + if (replyCode == NNTPReply.MORE_AUTH_INFO_REQUIRED) + { + replyCode = authinfoPass(password); + + if (replyCode == NNTPReply.AUTHENTICATION_ACCEPTED) + { + _isAllowedToPost = true; + return true; + } + } + return false; + } + + /*** + * Private implementation of XOVER functionality. + * + * See <a href="org.apache.commons.nntp.NNTP.html#xover"> + * for legal agument formats. Alternatively, read RFC 2980 :-) + * <p> + * @param articleRange + * @return Returns a DotTerminatedMessageReader if successful, null + * otherwise + * @exception IOException + */ + private Reader __retrieveArticleInfo(String articleRange) + throws IOException + { + if (!NNTPReply.isPositiveCompletion(xover(articleRange))) + return null; + + return new DotTerminatedMessageReader(_reader_); + } + + /** + * Return article headers for a specified post. + * <p> + * @param articleNumber the article to retrieve headers for + * @return a DotTerminatedReader if successful, null otherwise + * @throws IOException + */ + public Reader retrieveArticleInfo(int articleNumber) throws IOException + { + return __retrieveArticleInfo(new Integer(articleNumber).toString()); + } + + /** + * Return article headers for all articles between lowArticleNumber + * and highArticleNumber, inclusively. + * <p> + * @param lowArticleNumber + * @param highArticleNumber + * @return a DotTerminatedReader if successful, null otherwise + * @throws IOException + */ + public Reader retrieveArticleInfo(int lowArticleNumber, + int highArticleNumber) + throws IOException + { + return + __retrieveArticleInfo(new String(lowArticleNumber + "-" + + highArticleNumber)); + } } + + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ 1.4 +28 -19 jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNTPCommand.java Index: NNTPCommand.java =================================================================== RCS file: /home/cvs/jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNTPCommand.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- NNTPCommand.java 26 Jan 2003 00:21:44 -0000 1.3 +++ NNTPCommand.java 4 Sep 2003 20:32:43 -0000 1.4 @@ -58,38 +58,39 @@ * NNTPCommand stores a set of constants for NNTP command codes. To interpret * the meaning of the codes, familiarity with RFC 977 is assumed. * <p> - * <p> * @author Daniel F. Savarese ***/ public final class NNTPCommand { - public static final int ARTICLE = 0; - public static final int BODY = 1; - public static final int GROUP = 2; - public static final int HEAD = 3; - public static final int HELP = 4; - public static final int IHAVE = 5; - public static final int LAST = 6; - public static final int LIST = 7; + public static final int ARTICLE = 0; + public static final int BODY = 1; + public static final int GROUP = 2; + public static final int HEAD = 3; + public static final int HELP = 4; + public static final int IHAVE = 5; + public static final int LAST = 6; + public static final int LIST = 7; public static final int NEWGROUPS = 8; - public static final int NEWNEWS = 9; - public static final int NEXT = 10; - public static final int POST = 11; - public static final int QUIT = 12; - public static final int SLAVE = 13; - public static final int STAT = 14; - + public static final int NEWNEWS = 9; + public static final int NEXT = 10; + public static final int POST = 11; + public static final int QUIT = 12; + public static final int SLAVE = 13; + public static final int STAT = 14; + public static final int AUTHINFO = 15; + public static final int XOVER = 16; // Cannot be instantiated private NNTPCommand() {} static final String[] _commands = { - "ARTICLE", "BODY", "GROUP", "HEAD", "HELP", "IHAVE", "LAST", "LIST", - "NEWGROUPS", "NEWNEWS", "NEXT", "POST", "QUIT", "SLAVE", "STAT" - }; + "ARTICLE", "BODY", "GROUP", "HEAD", "HELP", "IHAVE", "LAST", "LIST", + "NEWGROUPS", "NEWNEWS", "NEXT", "POST", "QUIT", "SLAVE", "STAT", + "AUTHINFO", "XOVER" + }; /*** @@ -106,3 +107,11 @@ } } + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ 1.4 +46 -29 jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNTPReply.java Index: NNTPReply.java =================================================================== RCS file: /home/cvs/jakarta-commons/net/src/java/org/apache/commons/net/nntp/NNTPReply.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- NNTPReply.java 26 Jan 2003 00:21:44 -0000 1.3 +++ NNTPReply.java 4 Sep 2003 20:32:43 -0000 1.4 @@ -85,9 +85,12 @@ public static final int CODE_231 = 231; public static final int CODE_235 = 235; public static final int CODE_240 = 240; + public static final int CODE_281 = 281; public static final int CODE_335 = 335; public static final int CODE_340 = 340; + public static final int CODE_381 = 381; public static final int CODE_400 = 400; + public static final int CODE_408 = 408; public static final int CODE_411 = 411; public static final int CODE_412 = 412; public static final int CODE_420 = 420; @@ -100,45 +103,51 @@ public static final int CODE_437 = 437; public static final int CODE_440 = 440; public static final int CODE_441 = 441; + public static final int CODE_482 = 482; public static final int CODE_500 = 500; public static final int CODE_501 = 501; public static final int CODE_502 = 502; public static final int CODE_503 = 503; - public static final int HELP_TEXT_FOLLOWS = CODE_100; - public static final int DEBUG_OUTPUT = CODE_199; - public static final int SERVER_READY_POSTING_ALLOWED = CODE_200; + public static final int HELP_TEXT_FOLLOWS = CODE_100; + public static final int DEBUG_OUTPUT = CODE_199; + public static final int SERVER_READY_POSTING_ALLOWED = CODE_200; public static final int SERVER_READY_POSTING_NOT_ALLOWED = CODE_201; - public static final int SLAVE_STATUS_NOTED = CODE_202; - public static final int CLOSING_CONNECTION = CODE_205; - public static final int GROUP_SELECTED = CODE_211; + public static final int SLAVE_STATUS_NOTED = CODE_202; + public static final int CLOSING_CONNECTION = CODE_205; + public static final int GROUP_SELECTED = CODE_211; public static final int ARTICLE_RETRIEVED_HEAD_AND_BODY_FOLLOW = CODE_220; public static final int ARTICLE_RETRIEVED_HEAD_FOLLOWS = CODE_221; public static final int ARTICLE_RETRIEVED_BODY_FOLLOWS = CODE_222; - public static final int ARTICLE_RETRIEVED_REQUEST_TEXT_SEPARATELY = CODE_223; + public static final int + ARTICLE_RETRIEVED_REQUEST_TEXT_SEPARATELY = CODE_223; public static final int ARTICLE_LIST_BY_MESSAGE_ID_FOLLOWS = CODE_230; - public static final int NEW_NEWSGROUP_LIST_FOLLOWS = CODE_231; - public static final int ARTICLE_TRANSFERRED_OK = CODE_235; - public static final int ARTICLE_POSTED_OK = CODE_240; - public static final int SEND_ARTICLE_TO_TRANSFER = CODE_335; - public static final int SEND_ARTICLE_TO_POST = CODE_340; - public static final int SERVICE_DISCONTINUED = CODE_400; - public static final int NO_SUCH_NEWSGROUP = CODE_411; - public static final int NO_NEWSGROUP_SELECTED = CODE_412; - public static final int NO_CURRENT_ARTICLE_SELECTED = CODE_420; - public static final int NO_NEXT_ARTICLE = CODE_421; - public static final int NO_PREVIOUS_ARTICLE = CODE_422; - public static final int NO_SUCH_ARTICLE_NUMBER = CODE_423; - public static final int NO_SUCH_ARTICLE_FOUND = CODE_430; - public static final int ARTICLE_NOT_WANTED = CODE_435; - public static final int TRANSFER_FAILED = CODE_436; - public static final int ARTICLE_REJECTED = CODE_437; - public static final int POSTING_NOT_ALLOWED = CODE_440; - public static final int POSTING_FAILED = CODE_441; - public static final int COMMAND_NOT_RECOGNIZED = CODE_500; - public static final int COMMAND_SYNTAX_ERROR = CODE_501; - public static final int PERMISSION_DENIED = CODE_502; - public static final int PROGRAM_FAULT = CODE_503; + public static final int NEW_NEWSGROUP_LIST_FOLLOWS = CODE_231; + public static final int ARTICLE_TRANSFERRED_OK = CODE_235; + public static final int ARTICLE_POSTED_OK = CODE_240; + public static final int AUTHENTICATION_ACCEPTED = CODE_281; + public static final int SEND_ARTICLE_TO_TRANSFER = CODE_335; + public static final int SEND_ARTICLE_TO_POST = CODE_340; + public static final int MORE_AUTH_INFO_REQUIRED = CODE_381; + public static final int SERVICE_DISCONTINUED = CODE_400; + public static final int NO_SUCH_NEWSGROUP = CODE_411; + public static final int AUTHENTICATION_REQUIRED = CODE_408; + public static final int NO_NEWSGROUP_SELECTED = CODE_412; + public static final int NO_CURRENT_ARTICLE_SELECTED = CODE_420; + public static final int NO_NEXT_ARTICLE = CODE_421; + public static final int NO_PREVIOUS_ARTICLE = CODE_422; + public static final int NO_SUCH_ARTICLE_NUMBER = CODE_423; + public static final int NO_SUCH_ARTICLE_FOUND = CODE_430; + public static final int ARTICLE_NOT_WANTED = CODE_435; + public static final int TRANSFER_FAILED = CODE_436; + public static final int ARTICLE_REJECTED = CODE_437; + public static final int POSTING_NOT_ALLOWED = CODE_440; + public static final int POSTING_FAILED = CODE_441; + public static final int AUTHENTICATION_REJECTED = CODE_482; + public static final int COMMAND_NOT_RECOGNIZED = CODE_500; + public static final int COMMAND_SYNTAX_ERROR = CODE_501; + public static final int PERMISSION_DENIED = CODE_502; + public static final int PROGRAM_FAULT = CODE_503; // Cannot be instantiated @@ -227,3 +236,11 @@ } } + +/* Emacs configuration + * Local variables: ** + * mode: java ** + * c-basic-offset: 4 ** + * indent-tabs-mode: nil ** + * End: ** + */ 1.13 +0 -2 jakarta-commons/net/xdocs/changes.xml Index: changes.xml =================================================================== RCS file: /home/cvs/jakarta-commons/net/xdocs/changes.xml,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- changes.xml 26 Aug 2003 05:43:56 -0000 1.12 +++ changes.xml 4 Sep 2003 20:32:43 -0000 1.13 @@ -7,14 +7,12 @@ <body> <release version="1.0.1" date="In CVS"> -<!-- Pending resubmission of patch. <action dev="dfs" type="add"> Rory Winston <[EMAIL PROTECTED]> provided patches to add the following extended NNTP commands to NNTPClient: XOVER, AUTHINFO USER, AUTHINFO PASS, and LIST ACTIVE. </action> ---> <action dev="dfs" type="fix"> Changed connection hooks for FTP, SMTP, POP3, and NNTP classes to force use of an 8-bit US-ASCII superset (ISO-8859-1) for
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]