Here is a patch for the NNTP component to facilitate message threading - i.e. organizing messages in a structured 'threaded' format based on the References: value in their headers. The algorithm for this was originally devised by Jamie Zawinski (see his explanation at http://www.jwz.org/doc/threading.html). The implementation is based on his original implementation for Grendel, a defunct Mozilla component. In order for an Article object to be threadable, it must implement the Threadable interface, and contain some pointers to other messages that will be populated when the message tree is constructed. Here is a sample of how this works (This uses the Extended NNTP command XOVER that I added in a previous patch, which was commited by Daniel):
// get the article headers Article[] articles = getArticleInfo(lowArticleNumber, highArticleNumber); // Now thread the articles and display them Threader threader = new Threader(); // This will return a tree of articles in threaded format Article theRootArticle = (Article) threader.thread(articles); Article.printThread(theRootArticle, 0); This simple console-based example, when invoked on a group like comp.lang.ada, will result in an output like: ... ctags for ada "Xenos" <[EMAIL PROTECTED]> ==>Re: ctags for ada Stephen Leake <[EMAIL PROTECTED]> ==>Re: ctags for ada Preben Randhol <[EMAIL PROTECTED]> New, fixed, version of AdaGraph Jerry van Dijk <[EMAIL PROTECTED]> ANN: New SPARK (including RavenSPARK) definition now available [EMAIL PROTECTED] (Rod Chapman) ==>Re: ANN: New SPARK (including RavenSPARK) definition now available [EMAIL PROTECTED] (Mike Silva) CString Szymon Guz <[EMAIL PROTECTED]> ==>Re: CString "Luke A. Guest" <[EMAIL PROTECTED]> ==>Re: CString Szymon Guz <[EMAIL PROTECTED]> ==>Re: CString Duncan Sands <[EMAIL PROTECTED]> ==>Re: CString David Marceau <[EMAIL PROTECTED]> ==>Re: CString "Frank J. Lhota" <[EMAIL PROTECTED]> httpng "Andrew Carroll" <[EMAIL PROTECTED]> ==>Re: httpng "amado.alves" <[EMAIL PROTECTED]> ==>Re: httpng "Stephane Richard" <[EMAIL PROTECTED]> ==>Re: httpng Pascal Obry <[EMAIL PROTECTED]> Latin_1 and portability [EMAIL PROTECTED] (Xavier Serrand) ==>RE: Latin_1 and portability [EMAIL PROTECTED] (Larry Kilgallen) ==>RE: Latin_1 and portability "amado.alves" <[EMAIL PROTECTED]> ==>RE: Latin_1 and portability "amado.alves" <[EMAIL PROTECTED]> ==>Re: Latin_1 and portability =?ISO-8859-1?Q?Bj=F6rn?= Persson <[EMAIL PROTECTED]> ==>Re: Latin_1 and portability Pascal Obry <[EMAIL PROTECTED]> ==>Re: Latin_1 and portability =?ISO-8859-1?Q?Bj=F6rn?= Persson <[EMAIL PROTECTED]> ==>Re: Latin_1 and portability "Jeff C," <[EMAIL PROTECTED]> ==>Re: Latin_1 and portability Georg Bauhaus <[EMAIL PROTECTED]> ... The functionality is an optional add-on to the existing NNTP functionality. With this in mind, I have provided the implementation in the examples package. I have modified the ExtendedNNTPOps class to demonstrate this in action. I have also refactored the NNTP examples package from examples to examples.nntp, as the proliferation of separate classes in a single examples package was getting confusing. Cheers, Rory Index: .cvsignore =================================================================== RCS file: /home/cvspublic/jakarta-commons/net/.cvsignore,v retrieving revision 1.1 diff -u -r1.1 .cvsignore --- .cvsignore 17 Jul 2002 08:04:50 -0000 1.1 +++ .cvsignore 20 Jan 2004 13:09:25 -0000 @@ -1,3 +1,4 @@ .project target -dist \ No newline at end of file +dist +.classpath Index: src/java/examples/ExtendedNNTPOps.java =================================================================== RCS file: src/java/examples/ExtendedNNTPOps.java diff -N src/java/examples/ExtendedNNTPOps.java --- src/java/examples/ExtendedNNTPOps.java 2 Jan 2004 03:39:03 -0000 1.5 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,266 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2001-2004 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.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 - { - Reader reader = null; - Article[] articles = new Article[0]; - 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 - - int count = st.countTokens(); - articles = new Article[count]; - int index = 0; - - 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[index++] = article; - } - } else { - return null; - } - - return articles; - } - - private String readerToString(Reader reader) - { - String temp; - StringBuffer sb = null; - BufferedReader bufReader = new BufferedReader(reader); - - 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: ** - */ Index: src/java/examples/newsgroups.java =================================================================== RCS file: src/java/examples/newsgroups.java diff -N src/java/examples/newsgroups.java --- src/java/examples/newsgroups.java 2 Jan 2004 03:39:03 -0000 1.7 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,126 +0,0 @@ -package examples; - -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2001-2004 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/>. - */ - -import java.io.IOException; -import org.apache.commons.net.nntp.NNTPClient; -import org.apache.commons.net.nntp.NewsgroupInfo; - -/*** - * This is a trivial example using the NNTP package to approximate the - * Unix newsgroups command. It merely connects to the specified news - * server and issues fetches the list of newsgroups stored by the server. - * On servers that store a lot of newsgroups, this command can take a very - * long time (listing upwards of 30,000 groups). - * <p> - ***/ - -public final class newsgroups -{ - - public final static void main(String[] args) - { - NNTPClient client; - NewsgroupInfo[] list; - - if (args.length < 1) - { - System.err.println("Usage: newsgroups newsserver"); - System.exit(1); - } - - client = new NNTPClient(); - - try - { - client.connect(args[0]); - - list = client.listNewsgroups(); - - if (list != null) - { - for (int i = 0; i < list.length; i++) - System.out.println(list[i].getNewsgroup()); - } - else - { - System.err.println("LIST command failed."); - System.err.println("Server reply: " + client.getReplyString()); - } - } - catch (IOException e) - { - e.printStackTrace(); - } - finally - { - try - { - if (client.isConnected()) - client.disconnect(); - } - catch (IOException e) - { - System.err.println("Error disconnecting from server."); - e.printStackTrace(); - System.exit(1); - } - } - - } - -} - - Index: src/java/examples/post.java =================================================================== RCS file: src/java/examples/post.java diff -N src/java/examples/post.java --- src/java/examples/post.java 2 Jan 2004 03:39:03 -0000 1.7 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,205 +0,0 @@ -package examples; - -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2001-2004 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/>. - */ - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.io.Writer; -import org.apache.commons.net.io.Util; -import org.apache.commons.net.nntp.NNTPClient; -import org.apache.commons.net.nntp.NNTPReply; -import org.apache.commons.net.nntp.SimpleNNTPHeader; - -/*** - * This is an example program using the NNTP package to post an article - * to the specified newsgroup(s). It prompts you for header information and - * a filename to post. - * <p> - ***/ - -public final class post -{ - - public final static void main(String[] args) - { - String from, subject, newsgroup, filename, server, organization; - String references; - BufferedReader stdin; - FileReader fileReader = null; - SimpleNNTPHeader header; - NNTPClient client; - - if (args.length < 1) - { - System.err.println("Usage: post newsserver"); - System.exit(1); - } - - server = args[0]; - - stdin = new BufferedReader(new InputStreamReader(System.in)); - - try - { - System.out.print("From: "); - System.out.flush(); - - from = stdin.readLine(); - - System.out.print("Subject: "); - System.out.flush(); - - subject = stdin.readLine(); - - header = new SimpleNNTPHeader(from, subject); - - System.out.print("Newsgroup: "); - System.out.flush(); - - newsgroup = stdin.readLine(); - header.addNewsgroup(newsgroup); - - while (true) - { - System.out.print("Additional Newsgroup <Hit enter to end>: "); - System.out.flush(); - - // Of course you don't want to do this because readLine() may be null - newsgroup = stdin.readLine().trim(); - - if (newsgroup.length() == 0) - break; - - header.addNewsgroup(newsgroup); - } - - System.out.print("Organization: "); - System.out.flush(); - - organization = stdin.readLine(); - - System.out.print("References: "); - System.out.flush(); - - references = stdin.readLine(); - - if (organization != null && organization.length() > 0) - header.addHeaderField("Organization", organization); - - if (references != null && organization.length() > 0) - header.addHeaderField("References", references); - - header.addHeaderField("X-Newsreader", "NetComponents"); - - System.out.print("Filename: "); - System.out.flush(); - - filename = stdin.readLine(); - - try - { - fileReader = new FileReader(filename); - } - catch (FileNotFoundException e) - { - System.err.println("File not found. " + e.getMessage()); - System.exit(1); - } - - client = new NNTPClient(); - client.addProtocolCommandListener(new PrintCommandListener( - new PrintWriter(System.out))); - - client.connect(server); - - if (!NNTPReply.isPositiveCompletion(client.getReplyCode())) - { - client.disconnect(); - System.err.println("NNTP server refused connection."); - System.exit(1); - } - - if (client.isAllowedToPost()) - { - Writer writer = client.postArticle(); - - if (writer != null) - { - writer.write(header.toString()); - Util.copyReader(fileReader, writer); - writer.close(); - client.completePendingCommand(); - } - } - - fileReader.close(); - - client.logout(); - - client.disconnect(); - } - catch (IOException e) - { - e.printStackTrace(); - System.exit(1); - } - } -} - -
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
