All Downloads are FREE. Search and download functionalities are using the official Maven repository.

panda.net.nntp.NNTPClient Maven / Gradle / Ivy

There is a newer version: 1.8.0
Show newest version
package panda.net.nntp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Vector;

import panda.net.MalformedServerReplyException;
import panda.net.io.DotTerminatedMessageReader;
import panda.net.io.DotTerminatedMessageWriter;
import panda.net.io.Util;

/***
 * NNTPClient encapsulates all the functionality necessary to post and retrieve articles from an
 * NNTP server. As with all classes derived from {@link panda.net.SocketClient}, you must first
 * connect to the server with {@link panda.net.SocketClient#connect connect } before doing anything,
 * and finally {@link panda.net.nntp.NNTP#disconnect disconnect() } after you're completely finished
 * interacting with the server. Remember that the {@link panda.net.nntp.NNTP#isAllowedToPost
 * isAllowedToPost()} method is defined in {@link panda.net.nntp.NNTP}.
 * 

* You should keep in mind that the NNTP server may choose to prematurely close a connection if the * client has been idle for longer than a given time period or if the server is being shutdown by * the operator or some other reason. The NNTP class will detect a premature NNTP server connection * closing when it receives a {@link panda.net.nntp.NNTPReply#SERVICE_DISCONTINUED * NNTPReply.SERVICE_DISCONTINUED } response to a command. When that occurs, the NNTP class method * encountering that reply will throw an {@link panda.net.nntp.NNTPConnectionClosedException} . * NNTPConectionClosedException is a subclass of IOException and * therefore need not be caught separately, but if you are going to catch it separately, its catch * block must appear before the more general IOException catch block. When you * encounter an {@link panda.net.nntp.NNTPConnectionClosedException} , you must disconnect the * connection with {@link panda.net.nntp.NNTP#disconnect disconnect() } to properly clean up the * system resources used by NNTP. Before disconnecting, you may check the last reply code and text * with {@link panda.net.nntp.NNTP#getReplyCode getReplyCode } and * {@link panda.net.nntp.NNTP#getReplyString getReplyString }. *

* Rather than list it separately for each method, we mention here that every method communicating * with the server and throwing an IOException can also throw a * {@link panda.net.MalformedServerReplyException} , which is a subclass of IOException. A * MalformedServerReplyException will be thrown when the reply received from the server deviates * enough from the protocol specification that it cannot be interpreted in a useful manner despite * attempts to be as lenient as possible. * * @see NNTP * @see NNTPConnectionClosedException * @see panda.net.MalformedServerReplyException ***/ public class NNTPClient extends NNTP { /** * Parse the reply and store the id and number in the pointer. * * @param reply the reply to parse "22n nnn " * @param pointer the pointer to update * @throws MalformedServerReplyException if response could not be parsed */ private void __parseArticlePointer(String reply, ArticleInfo pointer) throws MalformedServerReplyException { String tokens[] = reply.split(" "); if (tokens.length >= 3) { // OK, we can parset the line int i = 1; // skip reply code try { // Get article number pointer.articleNumber = Long.parseLong(tokens[i++]); // Get article id pointer.articleId = tokens[i++]; return; // done } catch (NumberFormatException e) { // drop through and raise exception } } throw new MalformedServerReplyException("Could not parse article pointer.\nServer reply: " + reply); } /* * 211 n f l s group selected (n = estimated number of articles in group, f = first article * number in the group, l = last article number in the group, s = name of the group.) */ private static void __parseGroupReply(String reply, NewsgroupInfo info) throws MalformedServerReplyException { String tokens[] = reply.split(" "); if (tokens.length >= 5) { int i = 1; // Skip numeric response value try { // Get estimated article count info._setArticleCount(Long.parseLong(tokens[i++])); // Get first article number info._setFirstArticle(Long.parseLong(tokens[i++])); // Get last article number info._setLastArticle(Long.parseLong(tokens[i++])); // Get newsgroup name info._setNewsgroup(tokens[i++]); info._setPostingPermission(NewsgroupInfo.UNKNOWN_POSTING_PERMISSION); return; } catch (NumberFormatException e) { // drop through to report error } } throw new MalformedServerReplyException("Could not parse newsgroup info.\nServer reply: " + reply); } // Format: group last first p static NewsgroupInfo __parseNewsgroupListEntry(String entry) { String tokens[] = entry.split(" "); if (tokens.length < 4) { return null; } NewsgroupInfo result = new NewsgroupInfo(); int i = 0; result._setNewsgroup(tokens[i++]); try { long lastNum = Long.parseLong(tokens[i++]); long firstNum = Long.parseLong(tokens[i++]); result._setFirstArticle(firstNum); result._setLastArticle(lastNum); if ((firstNum == 0) && (lastNum == 0)) { result._setArticleCount(0); } else { result._setArticleCount(lastNum - firstNum + 1); } } catch (NumberFormatException e) { return null; } switch (tokens[i++].charAt(0)) { case 'y': case 'Y': result._setPostingPermission(NewsgroupInfo.PERMITTED_POSTING_PERMISSION); break; case 'n': case 'N': result._setPostingPermission(NewsgroupInfo.PROHIBITED_POSTING_PERMISSION); break; case 'm': case 'M': result._setPostingPermission(NewsgroupInfo.MODERATED_POSTING_PERMISSION); break; default: result._setPostingPermission(NewsgroupInfo.UNKNOWN_POSTING_PERMISSION); break; } return result; } /** * Parse a response line from {@link #retrieveArticleInfo(long, long)}. * * @param line a response line * @return the parsed {@link Article}, if unparseable then isDummy() will be true, and the * subject will contain the raw info. * @since 3.0 */ static Article __parseArticleEntry(String line) { // Extract the article information // Mandatory format (from NNTP RFC 2980) is : // articleNumber\tSubject\tAuthor\tDate\tID\tReference(s)\tByte Count\tLine Count Article article = new Article(); article.setSubject(line); // in case parsing fails String parts[] = line.split("\t"); if (parts.length > 6) { int i = 0; try { article.setArticleNumber(Long.parseLong(parts[i++])); article.setSubject(parts[i++]); article.setFrom(parts[i++]); article.setDate(parts[i++]); article.setArticleId(parts[i++]); article.addReference(parts[i++]); } catch (NumberFormatException e) { // ignored, already handled } } return article; } private NewsgroupInfo[] __readNewsgroupListing() throws IOException { BufferedReader reader = new DotTerminatedMessageReader(_reader_); // Start of with a big vector because we may be reading a very large // amount of groups. Vector list = new Vector(2048); String line; try { while ((line = reader.readLine()) != null) { NewsgroupInfo tmp = __parseNewsgroupListEntry(line); if (tmp != null) { list.addElement(tmp); } else { throw new MalformedServerReplyException(line); } } } finally { reader.close(); } int size; if ((size = list.size()) < 1) { return new NewsgroupInfo[0]; } NewsgroupInfo[] info = new NewsgroupInfo[size]; list.copyInto(info); return info; } private BufferedReader __retrieve(int command, String articleId, ArticleInfo pointer) throws IOException { if (articleId != null) { if (!NNTPReply.isPositiveCompletion(sendCommand(command, articleId))) { return null; } } else { if (!NNTPReply.isPositiveCompletion(sendCommand(command))) { return null; } } if (pointer != null) { __parseArticlePointer(getReplyString(), pointer); } return new DotTerminatedMessageReader(_reader_); } private BufferedReader __retrieve(int command, long articleNumber, ArticleInfo pointer) throws IOException { if (!NNTPReply.isPositiveCompletion(sendCommand(command, Long.toString(articleNumber)))) { return null; } if (pointer != null) { __parseArticlePointer(getReplyString(), pointer); } return new DotTerminatedMessageReader(_reader_); } /*** * Retrieves an article from the NNTP server. The article is referenced by its unique article * identifier (including the enclosing < and >). The article number and identifier * contained in the server reply are returned through an ArticleInfo. The * articleId field of the ArticleInfo cannot always be trusted because some NNTP * servers do not correctly follow the RFC 977 reply format. *

* A DotTerminatedMessageReader is returned from which the article can be read. If the article * does not exist, null is returned. *

* You must not issue any commands to the NNTP server (i.e., call any other methods) until you * finish reading the message from the returned BufferedReader instance. The NNTP protocol uses * the same stream for issuing commands as it does for returning results. Therefore the returned * BufferedReader actually reads directly from the NNTP connection. After the end of message has * been reached, new commands can be executed and their replies read. If you do not follow these * requirements, your program will not work properly. *

* * @param articleId The unique article identifier of the article to retrieve. If this parameter * is null, the currently selected article is retrieved. * @param pointer A parameter through which to return the article's number and unique id. The * articleId field cannot always be trusted because of server deviations from RFC 977 * reply formats. You may set this parameter to null if you do not desire to retrieve * the returned article information. * @return A DotTerminatedMessageReader instance from which the article can be read. null if the * article does not exist. * @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 a command to the server or * receiving a reply from the server. ***/ public BufferedReader retrieveArticle(String articleId, ArticleInfo pointer) throws IOException { return __retrieve(NNTPCommand.ARTICLE, articleId, pointer); } /** * Same as retrieveArticle(articleId, (ArticleInfo) null) Note: the return can be * cast to a {@link BufferedReader} * * @param articleId the article id to retrieve * @return A DotTerminatedMessageReader instance from which the article can be read. null if the * article does not exist. * @throws IOException if an IO error occurs */ public Reader retrieveArticle(String articleId) throws IOException { return retrieveArticle(articleId, (ArticleInfo)null); } /** * Same as retrieveArticle((String) null) Note: the return can be cast to a * {@link BufferedReader} * * @return A DotTerminatedMessageReader instance from which the article can be read. null if the * article does not exist. * @throws IOException if an IO error occurs */ public Reader retrieveArticle() throws IOException { return retrieveArticle((String)null); } /*** * Retrieves an article from the currently selected newsgroup. The article is referenced by its * article number. The article number and identifier contained in the server reply are returned * through an ArticleInfo. The articleId field of the ArticleInfo cannot always * be trusted because some NNTP servers do not correctly follow the RFC 977 reply format. *

* A DotTerminatedMessageReader is returned from which the article can be read. If the article * does not exist, null is returned. *

* You must not issue any commands to the NNTP server (i.e., call any other methods) until you * finish reading the message from the returned BufferedReader instance. The NNTP protocol uses * the same stream for issuing commands as it does for returning results. Therefore the returned * BufferedReader actually reads directly from the NNTP connection. After the end of message has * been reached, new commands can be executed and their replies read. If you do not follow these * requirements, your program will not work properly. *

* * @param articleNumber The number of the the article to retrieve. * @param pointer A parameter through which to return the article's number and unique id. The * articleId field cannot always be trusted because of server deviations from RFC 977 * reply formats. You may set this parameter to null if you do not desire to retrieve * the returned article information. * @return A DotTerminatedMessageReader instance from which the article can be read. null if the * article does not exist. * @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 a command to the server or * receiving a reply from the server. ***/ public BufferedReader retrieveArticle(long articleNumber, ArticleInfo pointer) throws IOException { return __retrieve(NNTPCommand.ARTICLE, articleNumber, pointer); } /** * Same as retrieveArticle(articleNumber, null) * * @param articleNumber the article number to fetch * @return A DotTerminatedMessageReader instance from which the article can be read. null if the * article does not exist. * @throws IOException if an IO error occurs */ public BufferedReader retrieveArticle(long articleNumber) throws IOException { return retrieveArticle(articleNumber, null); } /*** * Retrieves an article header from the NNTP server. The article is referenced by its unique * article identifier (including the enclosing < and >). The article number and identifier * contained in the server reply are returned through an ArticleInfo. The * articleId field of the ArticleInfo cannot always be trusted because some NNTP * servers do not correctly follow the RFC 977 reply format. *

* A DotTerminatedMessageReader is returned from which the article can be read. If the article * does not exist, null is returned. *

* You must not issue any commands to the NNTP server (i.e., call any other methods) until you * finish reading the message from the returned BufferedReader instance. The NNTP protocol uses * the same stream for issuing commands as it does for returning results. Therefore the returned * BufferedReader actually reads directly from the NNTP connection. After the end of message has * been reached, new commands can be executed and their replies read. If you do not follow these * requirements, your program will not work properly. *

* * @param articleId The unique article identifier of the article whose header is being * retrieved. If this parameter is null, the header of the currently selected article * is retrieved. * @param pointer A parameter through which to return the article's number and unique id. The * articleId field cannot always be trusted because of server deviations from RFC 977 * reply formats. You may set this parameter to null if you do not desire to retrieve * the returned article information. * @return A DotTerminatedMessageReader instance from which the article header can be read. null * if the article does not exist. * @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 a command to the server or * receiving a reply from the server. ***/ public BufferedReader retrieveArticleHeader(String articleId, ArticleInfo pointer) throws IOException { return __retrieve(NNTPCommand.HEAD, articleId, pointer); } /** * Same as retrieveArticleHeader(articleId, (ArticleInfo) null) Note: the return * can be cast to a {@link BufferedReader} * * @param articleId the article id to fetch * @return the reader * @throws IOException if an error occurs */ public Reader retrieveArticleHeader(String articleId) throws IOException { return retrieveArticleHeader(articleId, (ArticleInfo)null); } /** * Same as retrieveArticleHeader((String) null) Note: the return can be cast to a * {@link BufferedReader} * * @return the reader * @throws IOException if an error occurs */ public Reader retrieveArticleHeader() throws IOException { return retrieveArticleHeader((String)null); } /*** * Retrieves an article header from the currently selected newsgroup. The article is referenced * by its article number. The article number and identifier contained in the server reply are * returned through an ArticleInfo. The articleId field of the ArticleInfo cannot * always be trusted because some NNTP servers do not correctly follow the RFC 977 reply format. *

* A DotTerminatedMessageReader is returned from which the article can be read. If the article * does not exist, null is returned. *

* You must not issue any commands to the NNTP server (i.e., call any other methods) until you * finish reading the message from the returned BufferedReader instance. The NNTP protocol uses * the same stream for issuing commands as it does for returning results. Therefore the returned * BufferedReader actually reads directly from the NNTP connection. After the end of message has * been reached, new commands can be executed and their replies read. If you do not follow these * requirements, your program will not work properly. *

* * @param articleNumber The number of the the article whose header is being retrieved. * @param pointer A parameter through which to return the article's number and unique id. The * articleId field cannot always be trusted because of server deviations from RFC 977 * reply formats. You may set this parameter to null if you do not desire to retrieve * the returned article information. * @return A DotTerminatedMessageReader instance from which the article header can be read. null * if the article does not exist. * @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 a command to the server or * receiving a reply from the server. ***/ public BufferedReader retrieveArticleHeader(long articleNumber, ArticleInfo pointer) throws IOException { return __retrieve(NNTPCommand.HEAD, articleNumber, pointer); } /** * Same as retrieveArticleHeader(articleNumber, null) * * @param articleNumber the article number * @return the reader * @throws IOException if an error occurs */ public BufferedReader retrieveArticleHeader(long articleNumber) throws IOException { return retrieveArticleHeader(articleNumber, null); } /*** * Retrieves an article body from the NNTP server. The article is referenced by its unique * article identifier (including the enclosing < and >). The article number and identifier * contained in the server reply are returned through an ArticleInfo. The * articleId field of the ArticleInfo cannot always be trusted because some NNTP * servers do not correctly follow the RFC 977 reply format. *

* A DotTerminatedMessageReader is returned from which the article can be read. If the article * does not exist, null is returned. *

* You must not issue any commands to the NNTP server (i.e., call any other methods) until you * finish reading the message from the returned BufferedReader instance. The NNTP protocol uses * the same stream for issuing commands as it does for returning results. Therefore the returned * BufferedReader actually reads directly from the NNTP connection. After the end of message has * been reached, new commands can be executed and their replies read. If you do not follow these * requirements, your program will not work properly. *

* * @param articleId The unique article identifier of the article whose body is being retrieved. * If this parameter is null, the body of the currently selected article is * retrieved. * @param pointer A parameter through which to return the article's number and unique id. The * articleId field cannot always be trusted because of server deviations from RFC 977 * reply formats. You may set this parameter to null if you do not desire to retrieve * the returned article information. * @return A DotTerminatedMessageReader instance from which the article body can be read. null * if the article does not exist. * @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 a command to the server or * receiving a reply from the server. ***/ public BufferedReader retrieveArticleBody(String articleId, ArticleInfo pointer) throws IOException { return __retrieve(NNTPCommand.BODY, articleId, pointer); } /** * Same as retrieveArticleBody(articleId, (ArticleInfo) null) Note: the return * can be cast to a {@link BufferedReader} * * @param articleId the article id * @return A DotTerminatedMessageReader instance from which the article body can be read. null * if the article does not exist. * @throws IOException if an error occurs */ public Reader retrieveArticleBody(String articleId) throws IOException { return retrieveArticleBody(articleId, (ArticleInfo)null); } /** * Same as retrieveArticleBody(null) Note: the return can be cast to a * {@link BufferedReader} * * @return A DotTerminatedMessageReader instance from which the article body can be read. null * if the article does not exist. * @throws IOException if an error occurs */ public Reader retrieveArticleBody() throws IOException { return retrieveArticleBody(null); } /*** * Retrieves an article body from the currently selected newsgroup. The article is referenced by * its article number. The article number and identifier contained in the server reply are * returned through an ArticleInfo. The articleId field of the ArticleInfo cannot * always be trusted because some NNTP servers do not correctly follow the RFC 977 reply format. *

* A DotTerminatedMessageReader is returned from which the article can be read. If the article * does not exist, null is returned. *

* You must not issue any commands to the NNTP server (i.e., call any other methods) until you * finish reading the message from the returned BufferedReader instance. The NNTP protocol uses * the same stream for issuing commands as it does for returning results. Therefore the returned * BufferedReader actually reads directly from the NNTP connection. After the end of message has * been reached, new commands can be executed and their replies read. If you do not follow these * requirements, your program will not work properly. *

* * @param articleNumber The number of the the article whose body is being retrieved. * @param pointer A parameter through which to return the article's number and unique id. The * articleId field cannot always be trusted because of server deviations from RFC 977 * reply formats. You may set this parameter to null if you do not desire to retrieve * the returned article information. * @return A DotTerminatedMessageReader instance from which the article body can be read. null * if the article does not exist. * @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 a command to the server or * receiving a reply from the server. ***/ public BufferedReader retrieveArticleBody(long articleNumber, ArticleInfo pointer) throws IOException { return __retrieve(NNTPCommand.BODY, articleNumber, pointer); } /** * Same as retrieveArticleBody(articleNumber, null) * * @param articleNumber the article number * @return the reader * @throws IOException if an error occurs */ public BufferedReader retrieveArticleBody(long articleNumber) throws IOException { return retrieveArticleBody(articleNumber, null); } /*** * Select the specified newsgroup to be the target of for future article retrieval and posting * operations. Also return the newsgroup information contained in the server reply through the * info parameter. *

* * @param newsgroup The newsgroup to select. * @param info A parameter through which the newsgroup information of the selected newsgroup * contained in the server reply is returned. Set this to null if you do not desire * this information. * @return True if the newsgroup exists and was selected, false otherwise. * @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 a command to the server or * receiving a reply from the server. ***/ public boolean selectNewsgroup(String newsgroup, NewsgroupInfo info) throws IOException { if (!NNTPReply.isPositiveCompletion(group(newsgroup))) { return false; } if (info != null) { __parseGroupReply(getReplyString(), info); } return true; } /** * Same as selectNewsgroup(newsgroup, null) * * @param newsgroup the newsgroup name * @return true if newsgroup exist and was selected * @throws IOException if an error occurs */ public boolean selectNewsgroup(String newsgroup) throws IOException { return selectNewsgroup(newsgroup, null); } /*** * List the command help from the server. *

* * @return The sever help information. * @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 a command to the server or * receiving a reply from the server. ***/ public String listHelp() throws IOException { if (!NNTPReply.isInformational(help())) { return null; } StringWriter help = new StringWriter(); BufferedReader reader = new DotTerminatedMessageReader(_reader_); Util.copyReader(reader, help); reader.close(); help.close(); return help.toString(); } /** * Send a "LIST OVERVIEW.FMT" command to the server. * * @return the contents of the Overview format, of {@code null} if the command failed * @throws IOException on error */ public String[] listOverviewFmt() throws IOException { if (!NNTPReply.isPositiveCompletion(sendCommand("LIST", "OVERVIEW.FMT"))) { return null; } BufferedReader reader = new DotTerminatedMessageReader(_reader_); String line; ArrayList list = new ArrayList(); while ((line = reader.readLine()) != null) { list.add(line); } reader.close(); return list.toArray(new String[list.size()]); } /*** * Select an article by its unique identifier (including enclosing < and >) and return its * article number and id through the pointer parameter. This is achieved through the STAT * command. According to RFC 977, this will NOT set the current article pointer on the server. * To do that, you must reference the article by its number. *

* * @param articleId The unique article identifier of the article that is being selectedd. If * this parameter is null, the body of the current article is selected * @param pointer A parameter through which to return the article's number and unique id. The * articleId field cannot always be trusted because of server deviations from RFC 977 * reply formats. You may set this parameter to null if you do not desire to retrieve * the returned article information. * @return True if successful, false if not. * @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 a command to the server or * receiving a reply from the server. ***/ public boolean selectArticle(String articleId, ArticleInfo pointer) throws IOException { if (articleId != null) { if (!NNTPReply.isPositiveCompletion(stat(articleId))) { return false; } } else { if (!NNTPReply.isPositiveCompletion(stat())) { return false; } } if (pointer != null) { __parseArticlePointer(getReplyString(), pointer); } return true; } /** * Same as selectArticle(articleId, (ArticleInfo) null) * * @param articleId the article Id * @return true if successful * @throws IOException on error */ public boolean selectArticle(String articleId) throws IOException { return selectArticle(articleId, (ArticleInfo)null); } /**** * Same as selectArticle((String) null, articleId) . Useful for retrieving the * current article number. * * @param pointer to the article * @return true if OK * @throws IOException on error ***/ public boolean selectArticle(ArticleInfo pointer) throws IOException { return selectArticle(null, pointer); } /*** * Select an article in the currently selected newsgroup by its number. and return its article * number and id through the pointer parameter. This is achieved through the STAT command. * According to RFC 977, this WILL set the current article pointer on the server. Use this * command to select an article before retrieving it, or to obtain an article's unique * identifier given its number. *

* * @param articleNumber The number of the article to select from the currently selected * newsgroup. * @param pointer A parameter through which to return the article's number and unique id. * Although the articleId field cannot always be trusted because of server deviations * from RFC 977 reply formats, we haven't found a server that misformats this * information in response to this particular command. You may set this parameter to * null if you do not desire to retrieve the returned article information. * @return True if successful, false if not. * @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 a command to the server or * receiving a reply from the server. ***/ public boolean selectArticle(long articleNumber, ArticleInfo pointer) throws IOException { if (!NNTPReply.isPositiveCompletion(stat(articleNumber))) { return false; } if (pointer != null) { __parseArticlePointer(getReplyString(), pointer); } return true; } /*** * Same as selectArticle(articleNumber, null) * * @param articleNumber the numger * @return true if successful * @throws IOException on error ***/ public boolean selectArticle(long articleNumber) throws IOException { return selectArticle(articleNumber, null); } /*** * Select the article preceeding the currently selected article in the currently selected * newsgroup and return its number and unique id through the pointer parameter. Because of * deviating server implementations, the articleId information cannot be trusted. To obtain the * article identifier, issue a selectArticle(pointer.articleNumber, pointer) * immediately afterward. *

* * @param pointer A parameter through which to return the article's number and unique id. The * articleId field cannot always be trusted because of server deviations from RFC 977 * reply formats. You may set this parameter to null if you do not desire to retrieve * the returned article information. * @return True if successful, false if not (e.g., there is no previous article). * @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 a command to the server or * receiving a reply from the server. ***/ public boolean selectPreviousArticle(ArticleInfo pointer) throws IOException { if (!NNTPReply.isPositiveCompletion(last())) { return false; } if (pointer != null) { __parseArticlePointer(getReplyString(), pointer); } return true; } /*** * Same as selectPreviousArticle((ArticleInfo) null) * * @return true if successful * @throws IOException on error ***/ public boolean selectPreviousArticle() throws IOException { return selectPreviousArticle((ArticleInfo)null); } /*** * Select the article following the currently selected article in the currently selected * newsgroup and return its number and unique id through the pointer parameter. Because of * deviating server implementations, the articleId information cannot be trusted. To obtain the * article identifier, issue a selectArticle(pointer.articleNumber, pointer) * immediately afterward. *

* * @param pointer A parameter through which to return the article's number and unique id. The * articleId field cannot always be trusted because of server deviations from RFC 977 * reply formats. You may set this parameter to null if you do not desire to retrieve * the returned article information. * @return True if successful, false if not (e.g., there is no following article). * @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 a command to the server or * receiving a reply from the server. ***/ public boolean selectNextArticle(ArticleInfo pointer) throws IOException { if (!NNTPReply.isPositiveCompletion(next())) { return false; } if (pointer != null) { __parseArticlePointer(getReplyString(), pointer); } return true; } /*** * Same as selectNextArticle((ArticleInfo) null) * * @return true if successful * @throws IOException on error ***/ public boolean selectNextArticle() throws IOException { return selectNextArticle((ArticleInfo)null); } /*** * List all newsgroups served by the NNTP server. If no newsgroups are served, a zero length * array will be returned. If the command fails, null will be returned. The method uses the * "LIST" command. *

* * @return An array of NewsgroupInfo instances containing the information for each newsgroup * served by the NNTP server. If no newsgroups are served, a zero length array will be * returned. If the command fails, null will be returned. * @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 a command to the server or * receiving a reply from the server. * @see #iterateNewsgroupListing() * @see #iterateNewsgroups() ***/ public NewsgroupInfo[] listNewsgroups() throws IOException { if (!NNTPReply.isPositiveCompletion(list())) { return null; } return __readNewsgroupListing(); } /** * List all newsgroups served by the NNTP server. If no newsgroups are served, no entries will * be returned. The method uses the "LIST" command. *

* * @return An iterable of NewsgroupInfo instances containing the information for each newsgroup * served by the NNTP server. If no newsgroups are served, no entries will be returned. * @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 a command to the server or * receiving a reply from the server. * @since 3.0 */ public Iterable iterateNewsgroupListing() throws IOException { if (NNTPReply.isPositiveCompletion(list())) { return new ReplyIterator(_reader_); } throw new IOException("LIST command failed: " + getReplyString()); } /** * List all newsgroups served by the NNTP server. If no newsgroups are served, no entries will * be returned. The method uses the "LIST" command. *

* * @return An iterable of Strings containing the raw information for each newsgroup served by * the NNTP server. If no newsgroups are served, no entries will be returned. * @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 a command to the server or * receiving a reply from the server. * @since 3.0 */ public Iterable iterateNewsgroups() throws IOException { return new NewsgroupIterator(iterateNewsgroupListing()); } /** * List the newsgroups that match a given pattern. Uses the "LIST ACTIVE" command. *

* * @param wildmat a pseudo-regex pattern (cf. RFC 2980) * @return An array of NewsgroupInfo instances containing the information for each newsgroup * served by the NNTP server corresponding to the supplied pattern. If no such * newsgroups are served, a zero length array will be returned. If the command fails, * null will be returned. * @throws IOException on error * @see #iterateNewsgroupListing(String) * @see #iterateNewsgroups(String) */ public NewsgroupInfo[] listNewsgroups(String wildmat) throws IOException { if (!NNTPReply.isPositiveCompletion(listActive(wildmat))) { return null; } return __readNewsgroupListing(); } /** * List the newsgroups that match a given pattern. Uses the "LIST ACTIVE" command. *

* * @param wildmat a pseudo-regex pattern (cf. RFC 2980) * @return An iterable of Strings containing the raw information for each newsgroup served by * the NNTP server corresponding to the supplied pattern. If no such newsgroups are * served, no entries will be returned. * @throws IOException on error * @since 3.0 */ public Iterable iterateNewsgroupListing(String wildmat) throws IOException { if (NNTPReply.isPositiveCompletion(listActive(wildmat))) { return new ReplyIterator(_reader_); } throw new IOException("LIST ACTIVE " + wildmat + " command failed: " + getReplyString()); } /** * List the newsgroups that match a given pattern. Uses the "LIST ACTIVE" command. *

* * @param wildmat a pseudo-regex pattern (cf. RFC 2980) * @return An iterable NewsgroupInfo instances containing the information for each newsgroup * served by the NNTP server corresponding to the supplied pattern. If no such * newsgroups are served, no entries will be returned. * @throws IOException on error * @since 3.0 */ public Iterable iterateNewsgroups(String wildmat) throws IOException { return new NewsgroupIterator(iterateNewsgroupListing(wildmat)); } /*** * List all new newsgroups added to the NNTP server since a particular date subject to the * conditions of the specified query. If no new newsgroups were added, a zero length array will * be returned. If the command fails, null will be returned. This uses the "NEWGROUPS" command. *

* * @param query The query restricting how to search for new newsgroups. * @return An array of NewsgroupInfo instances containing the information for each new newsgroup * added to the NNTP server. If no newsgroups were added, a zero length array will be * returned. If the command fails, null will be returned. * @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 a command to the server or * receiving a reply from the server. * @see #iterateNewNewsgroups(NewGroupsOrNewsQuery) * @see #iterateNewNewsgroupListing(NewGroupsOrNewsQuery) ***/ public NewsgroupInfo[] listNewNewsgroups(NewGroupsOrNewsQuery query) throws IOException { if (!NNTPReply.isPositiveCompletion(newgroups(query.getDate(), query.getTime(), query.isGMT(), query.getDistributions()))) { return null; } return __readNewsgroupListing(); } /** * List all new newsgroups added to the NNTP server since a particular date subject to the * conditions of the specified query. If no new newsgroups were added, no entries will be * returned. This uses the "NEWGROUPS" command. *

* * @param query The query restricting how to search for new newsgroups. * @return An iterable of Strings containing the raw information for each new newsgroup added to * the NNTP server. If no newsgroups were added, no entries will be returned. * @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 a command to the server or * receiving a reply from the server. * @since 3.0 */ public Iterable iterateNewNewsgroupListing(NewGroupsOrNewsQuery query) throws IOException { if (NNTPReply.isPositiveCompletion(newgroups(query.getDate(), query.getTime(), query.isGMT(), query.getDistributions()))) { return new ReplyIterator(_reader_); } throw new IOException("NEWGROUPS command failed: " + getReplyString()); } /** * List all new newsgroups added to the NNTP server since a particular date subject to the * conditions of the specified query. If no new newsgroups were added, no entries will be * returned. This uses the "NEWGROUPS" command. *

* * @param query The query restricting how to search for new newsgroups. * @return An iterable of NewsgroupInfo instances containing the information for each new * newsgroup added to the NNTP server. If no newsgroups were added, no entries will be * returned. * @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 a command to the server or * receiving a reply from the server. * @since 3.0 */ public Iterable iterateNewNewsgroups(NewGroupsOrNewsQuery query) throws IOException { return new NewsgroupIterator(iterateNewNewsgroupListing(query)); } /*** * List all new articles added to the NNTP server since a particular date subject to the * conditions of the specified query. If no new new news is found, a zero length array will be * returned. If the command fails, null will be returned. You must add at least one newsgroup to * the query, else the command will fail. Each String in the returned array is a unique message * identifier including the enclosing < and >. This uses the "NEWNEWS" command. *

* * @param query The query restricting how to search for new news. You must add at least one * newsgroup to the query. * @return An array of String instances containing the unique message identifiers for each new * article added to the NNTP server. If no new news is found, a zero length array will * be returned. If the command fails, null will be returned. * @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 a command to the server or * receiving a reply from the server. * @see #iterateNewNews(NewGroupsOrNewsQuery) ***/ public String[] listNewNews(NewGroupsOrNewsQuery query) throws IOException { if (!NNTPReply.isPositiveCompletion(newnews(query.getNewsgroups(), query.getDate(), query.getTime(), query.isGMT(), query.getDistributions()))) { return null; } Vector list = new Vector(); BufferedReader reader = new DotTerminatedMessageReader(_reader_); String line; try { while ((line = reader.readLine()) != null) { list.addElement(line); } } finally { reader.close(); } int size = list.size(); if (size < 1) { return new String[0]; } String[] result = new String[size]; list.copyInto(result); return result; } /** * List all new articles added to the NNTP server since a particular date subject to the * conditions of the specified query. If no new new news is found, no entries will be returned. * This uses the "NEWNEWS" command. You must add at least one newsgroup to the query, else the * command will fail. Each String which is returned is a unique message identifier including the * enclosing < and >. *

* * @param query The query restricting how to search for new news. You must add at least one * newsgroup to the query. * @return An iterator of String instances containing the unique message identifiers for each * new article added to the NNTP server. If no new news is found, no strings will be * returned. * @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 a command to the server or * receiving a reply from the server. * @since 3.0 */ public Iterable iterateNewNews(NewGroupsOrNewsQuery query) throws IOException { if (NNTPReply.isPositiveCompletion(newnews(query.getNewsgroups(), query.getDate(), query.getTime(), query.isGMT(), query.getDistributions()))) { return new ReplyIterator(_reader_); } throw new IOException("NEWNEWS command failed: " + getReplyString()); } /*** * There are a few NNTPClient methods that do not complete the entire sequence of NNTP commands * to complete a transaction. These commands require some action by the programmer after the * reception of a positive preliminary command. After the programmer's code completes its * actions, it must call this method to receive the completion reply from the server and verify * the success of the entire transaction. *

* For example * *

	 * writer = client.postArticle();
	 * if (writer == null) // failure
	 * 	return false;
	 * header = new SimpleNNTPHeader("[email protected]", "Just testing");
	 * header.addNewsgroup("alt.test");
	 * writer.write(header.toString());
	 * writer.write("This is just a test");
	 * writer.close();
	 * if (!client.completePendingCommand()) // failure
	 * 	return false;
	 * 
*

* * @return True if successfully completed, false if not. * @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 a command to the server or * receiving a reply from the server. ***/ public boolean completePendingCommand() throws IOException { return NNTPReply.isPositiveCompletion(getReply()); } /*** * Post an article to the NNTP server. This method returns a DotTerminatedMessageWriter instance * to which the article can be written. Null is returned if the posting attempt fails. You * should check {@link NNTP#isAllowedToPost isAllowedToPost() } before trying to post. However, * a posting attempt can fail due to malformed headers. *

* You must not issue any commands to the NNTP server (i.e., call any (other methods) until you * finish writing to the returned Writer instance and close it. The NNTP protocol uses the same * stream for issuing commands as it does for returning results. Therefore the returned Writer * actually writes directly to the NNTP connection. After you close the writer, you can execute * new commands. If you do not follow these requirements your program will not work properly. *

* Different NNTP servers will require different header formats, but you can use the provided * {@link panda.net.nntp.SimpleNNTPHeader} class to construct the bare minimum acceptable header * for most news readers. To construct more complicated headers you should refer to RFC 822. * When the Java Mail API is finalized, you will be able to use it to compose fully compliant * Internet text messages. The DotTerminatedMessageWriter takes care of doubling line-leading * dots and ending the message with a single dot upon closing, so all you have to worry about is * writing the header and the message. *

* Upon closing the returned Writer, you need to call {@link #completePendingCommand * completePendingCommand() } to finalize the posting and verify its success or failure from the * server reply. *

* * @return A DotTerminatedMessageWriter to which the article (including header) can be written. * Returns null if the command fails. * @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())) { return null; } return new DotTerminatedMessageWriter(_writer_); } public Writer forwardArticle(String articleId) throws IOException { if (!NNTPReply.isPositiveIntermediate(ihave(articleId))) { return null; } return new DotTerminatedMessageWriter(_writer_); } /*** * Logs out of the news server gracefully by sending the QUIT command. However, you must still * disconnect from the server before you can open a new connection. *

* * @return True if successfully completed, false if not. * @exception IOException If an I/O error occurs while either sending a command to the server or * receiving a reply from the server. ***/ public boolean logout() throws IOException { 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. *

* * @param username a valid username * @param password the corresponding password * @return True for successful login, false for a failure * @throws IOException on error */ 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 {@link NNTP#xover} for legal agument * formats. Alternatively, read RFC 2980 :-) *

* * @param articleRange * @return Returns a DotTerminatedMessageReader if successful, null otherwise * @exception IOException */ private BufferedReader __retrieveArticleInfo(String articleRange) throws IOException { if (!NNTPReply.isPositiveCompletion(xover(articleRange))) { return null; } return new DotTerminatedMessageReader(_reader_); } /** * Return article headers for a specified post. *

* * @param articleNumber the article to retrieve headers for * @return a DotTerminatedReader if successful, null otherwise * @throws IOException on error */ public BufferedReader retrieveArticleInfo(long articleNumber) throws IOException { return __retrieveArticleInfo(Long.toString(articleNumber)); } /** * Return article headers for all articles between lowArticleNumber and highArticleNumber, * inclusively. Uses the XOVER command. *

* * @param lowArticleNumber low number * @param highArticleNumber high number * @return a DotTerminatedReader if successful, null otherwise * @throws IOException on error */ public BufferedReader retrieveArticleInfo(long lowArticleNumber, long highArticleNumber) throws IOException { return __retrieveArticleInfo(lowArticleNumber + "-" + highArticleNumber); } /** * Return article headers for all articles between lowArticleNumber and highArticleNumber, * inclusively, using the XOVER command. *

* * @param lowArticleNumber low * @param highArticleNumber high * @return an Iterable of Articles * @throws IOException if the command failed * @since 3.0 */ public Iterable

iterateArticleInfo(long lowArticleNumber, long highArticleNumber) throws IOException { BufferedReader info = retrieveArticleInfo(lowArticleNumber, highArticleNumber); if (info == null) { throw new IOException("XOVER command failed: " + getReplyString()); } // N.B. info is already DotTerminated, so don't rewrap return new ArticleIterator(new ReplyIterator(info, false)); } /*** * Private implementation of XHDR functionality. See {@link NNTP#xhdr} for legal agument * formats. Alternatively, read RFC 1036. *

* * @param header * @param articleRange * @return Returns a DotTerminatedMessageReader if successful, null otherwise * @exception IOException */ private BufferedReader __retrieveHeader(String header, String articleRange) throws IOException { if (!NNTPReply.isPositiveCompletion(xhdr(header, articleRange))) { return null; } return new DotTerminatedMessageReader(_reader_); } /** * Return an article header for a specified post. *

* * @param header the header to retrieve * @param articleNumber the article to retrieve the header for * @return a DotTerminatedReader if successful, null otherwise * @throws IOException on error */ public BufferedReader retrieveHeader(String header, long articleNumber) throws IOException { return __retrieveHeader(header, Long.toString(articleNumber)); } /** * Return an article header for all articles between lowArticleNumber and highArticleNumber, * inclusively. *

* * @param header the header * @param lowArticleNumber to fetch * @param highArticleNumber to fetch * @return a DotTerminatedReader if successful, null otherwise * @throws IOException on error */ public BufferedReader retrieveHeader(String header, long lowArticleNumber, long highArticleNumber) throws IOException { return __retrieveHeader(header, lowArticleNumber + "-" + highArticleNumber); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy