blob: 806fcc79bd6e66966ba1ccb33846806ad5562c64 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.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 org.apache.commons.net.MalformedServerReplyException;
import org.apache.commons.net.io.DotTerminatedMessageReader;
import org.apache.commons.net.io.DotTerminatedMessageWriter;
import org.apache.commons.net.io.Util;
import org.apache.commons.net.util.NetConstants;
/**
* NNTPClient encapsulates all the functionality necessary to post and
* retrieve articles from an NNTP server. As with all classes derived
* from {@link org.apache.commons.net.SocketClient},
* you must first connect to the server with
* {@link org.apache.commons.net.SocketClient#connect connect }
* before doing anything, and finally
* {@link org.apache.commons.net.nntp.NNTP#disconnect disconnect() }
* after you're completely finished interacting with the server.
* Remember that the
* {@link org.apache.commons.net.nntp.NNTP#isAllowedToPost isAllowedToPost()}
* method is defined in
* {@link org.apache.commons.net.nntp.NNTP}.
* <p>
* 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 org.apache.commons.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 org.apache.commons.net.nntp.NNTPConnectionClosedException}
* .
* <code>NNTPConectionClosedException</code>
* is a subclass of <code> IOException </code> 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 <code> IOException </code>
* catch block. When you encounter an
* {@link org.apache.commons.net.nntp.NNTPConnectionClosedException}
* , you must disconnect the connection with
* {@link org.apache.commons.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 org.apache.commons.net.nntp.NNTP#getReplyCode getReplyCode } and
* {@link org.apache.commons.net.nntp.NNTP#getReplyString getReplyString }.
* <p>
* 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 org.apache.commons.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 org.apache.commons.net.MalformedServerReplyException
*/
public class NNTPClient extends NNTP
{
private static final NewsgroupInfo[] EMPTY_NEWSGROUP_INFO_ARRAY = new NewsgroupInfo[0];
/**
* 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(final String line) {
// Extract the article information
// Mandatory format (from NNTP RFC 2980) is :
// articleNumber\tSubject\tAuthor\tDate\tID\tReference(s)\tByte Count\tLine Count
final Article article = new Article();
article.setSubject(line); // in case parsing fails
final 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 (final NumberFormatException e) {
// ignored, already handled
}
}
return article;
}
/*
* 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(final String reply, final NewsgroupInfo info)
throws MalformedServerReplyException
{
final 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 (final 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(final String entry)
{
final String tokens[] = entry.split(" ");
if (tokens.length < 4) {
return null;
}
final NewsgroupInfo result = new NewsgroupInfo();
int i = 0;
result.setNewsgroup(tokens[i++]);
try
{
final long lastNum = Long.parseLong(tokens[i++]);
final 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 (final 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;
}
@SuppressWarnings("deprecation")
private void ai2ap(final ArticleInfo ai, final ArticlePointer ap){
if (ap != null) { // ai cannot be null
ap.articleId = ai.articleId;
ap.articleNumber = (int) ai.articleNumber;
}
}
private ArticleInfo ap2ai(@SuppressWarnings("deprecation") final ArticlePointer ap) {
if (ap == null) {
return null;
}
final ArticleInfo ai = new ArticleInfo();
return ai;
}
/**
* 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 on error
*/
public boolean authenticate(final String username, final String password)
throws IOException
{
int replyCode = authinfoUser(username);
if (replyCode == NNTPReply.MORE_AUTH_INFO_REQUIRED)
{
replyCode = authinfoPass(password);
if (replyCode == NNTPReply.AUTHENTICATION_ACCEPTED)
{
this._isAllowedToPost = true;
return true;
}
}
return false;
}
/**
* 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.
* <p>
* For example
* <pre>
* writer = client.postArticle();
* if(writer == null) // failure
* return false;
* header = new SimpleNNTPHeader("foobar@foo.com", "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;
* </pre>
* <p>
* @return True if successfully completed, false if not.
* @throws 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.
* @throws 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());
}
public Writer forwardArticle(final String articleId) throws IOException
{
if (!NNTPReply.isPositiveIntermediate(ihave(articleId))) {
return null;
}
return new DotTerminatedMessageWriter(_writer_);
}
/**
* Return article headers for all articles between lowArticleNumber
* and highArticleNumber, inclusively, using the XOVER command.
* <p>
* @param lowArticleNumber low
* @param highArticleNumber high
* @return an Iterable of Articles
* @throws IOException if the command failed
* @since 3.0
*/
public Iterable<Article> iterateArticleInfo(final long lowArticleNumber, final long highArticleNumber)
throws IOException
{
final 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));
}
/**
* 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 &lt; and &gt;.
* <p>
* @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.
* @throws 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.
* @throws 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<String> iterateNewNews(final 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());
}
/**
* 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.
* <p>
* @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.
* @throws 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.
* @throws 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<String> iterateNewNewsgroupListing(final 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.
* <p>
* @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.
* @throws 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.
* @throws 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<NewsgroupInfo> iterateNewNewsgroups(final NewGroupsOrNewsQuery query) throws IOException {
return new NewsgroupIterator(iterateNewNewsgroupListing(query));
}
/**
* List all newsgroups served by the NNTP server. If no newsgroups
* are served, no entries will be returned.
* The method uses the "LIST" command.
* <p>
* @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.
* @throws 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.
* @throws 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<String> iterateNewsgroupListing() throws IOException {
if (NNTPReply.isPositiveCompletion(list())) {
return new ReplyIterator(_reader_);
}
throw new IOException("LIST command failed: "+getReplyString());
}
/**
* List the newsgroups that match a given pattern.
* Uses the "LIST ACTIVE" command.
* <p>
* @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<String> iterateNewsgroupListing(final String wildmat) throws IOException {
if(NNTPReply.isPositiveCompletion(listActive(wildmat))) {
return new ReplyIterator(_reader_);
}
throw new IOException("LIST ACTIVE "+wildmat+" 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.
* <p>
* @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.
* @throws 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.
* @throws 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<NewsgroupInfo> iterateNewsgroups() throws IOException {
return new NewsgroupIterator(iterateNewsgroupListing());
}
/**
* List the newsgroups that match a given pattern.
* Uses the "LIST ACTIVE" command.
* <p>
* @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<NewsgroupInfo> iterateNewsgroups(final String wildmat) throws IOException {
return new NewsgroupIterator(iterateNewsgroupListing(wildmat));
}
/**
* List the command help from the server.
* <p>
* @return The sever help information.
* @throws 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.
* @throws 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;
}
try (final StringWriter help = new StringWriter();
final BufferedReader reader = new DotTerminatedMessageReader(_reader_)) {
Util.copyReader(reader, help);
return help.toString();
}
}
/**
* 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 &lt; and &gt;.
* This uses the "NEWNEWS" command.
* <p>
* @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.
* @throws 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.
* @throws 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(final NewGroupsOrNewsQuery query)
throws IOException
{
if (!NNTPReply.isPositiveCompletion(newnews(query.getNewsgroups(), query.getDate(), query.getTime(),
query.isGMT(), query.getDistributions()))) {
return null;
}
final Vector<String> list = new Vector<>();
try (final BufferedReader reader = new DotTerminatedMessageReader(_reader_)) {
String line;
while ((line = reader.readLine()) != null) {
list.addElement(line);
}
}
final int size = list.size();
if (size < 1) {
return NetConstants.EMPTY_STRING_ARRAY;
}
final String[] result = new String[size];
list.copyInto(result);
return result;
}
/**
* 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.
* <p>
* @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.
* @throws 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.
* @throws 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(final NewGroupsOrNewsQuery query)
throws IOException
{
if (!NNTPReply.isPositiveCompletion(newgroups(
query.getDate(), query.getTime(),
query.isGMT(), query.getDistributions())))
{
return null;
}
return readNewsgroupListing();
}
/**
* 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.
* <p>
* @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.
* @throws 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.
* @throws 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 the newsgroups that match a given pattern.
* Uses the "LIST ACTIVE" command.
* <p>
* @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(final String wildmat) throws IOException
{
if(!NNTPReply.isPositiveCompletion(listActive(wildmat))) {
return null;
}
return readNewsgroupListing();
}
/**
* 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;
}
try (final BufferedReader reader = new DotTerminatedMessageReader(_reader_)) {
String line;
final ArrayList<String> list = new ArrayList<>();
while ((line = reader.readLine()) != null) {
list.add(line);
}
return list.toArray(NetConstants.EMPTY_STRING_ARRAY);
}
}
/**
* 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.
* <p>
* @return True if successfully completed, false if not.
* @throws 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());
}
/**
* Parse the reply and store the id and number in the pointer.
*
* @param reply the reply to parse "22n nnn <aaa>"
* @param pointer the pointer to update
*
* @throws MalformedServerReplyException if response could not be parsed
*/
private void parseArticlePointer(final String reply, final ArticleInfo pointer)
throws MalformedServerReplyException
{
final 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 (final NumberFormatException e)
{
// drop through and raise exception
}
}
throw new MalformedServerReplyException(
"Could not parse article pointer.\nServer reply: " + reply);
}
/**
* 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.
* <p>
* 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.
* <p>
* Different NNTP servers will require different header formats, but
* you can use the provided
* {@link org.apache.commons.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.
* <p>
* 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.
* <p>
* @return A DotTerminatedMessageWriter to which the article (including
* header) can be written. Returns null if the command fails.
* @throws 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_);
}
private NewsgroupInfo[] readNewsgroupListing() throws IOException
{
// Start of with a big vector because we may be reading a very large
// amount of groups.
final Vector<NewsgroupInfo> list = new Vector<>(2048);
String line;
try (final BufferedReader reader = new DotTerminatedMessageReader(_reader_)) {
while ((line = reader.readLine()) != null) {
final NewsgroupInfo tmp = parseNewsgroupListEntry(line);
if (tmp == null) {
throw new MalformedServerReplyException(line);
}
list.addElement(tmp);
}
}
final int size;
if ((size = list.size()) < 1) {
return EMPTY_NEWSGROUP_INFO_ARRAY;
}
final NewsgroupInfo[] info = new NewsgroupInfo[size];
list.copyInto(info);
return info;
}
private BufferedReader retrieve(final int command, final long articleNumber, final ArticleInfo pointer)
throws IOException
{
if (!NNTPReply.isPositiveCompletion(sendCommand(command,
Long.toString(articleNumber)))) {
return null;
}
if (pointer != null) {
parseArticlePointer(getReplyString(), pointer);
}
return new DotTerminatedMessageReader(_reader_);
}
private BufferedReader retrieve(final int command, final String articleId, final 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_);
}
/**
* Same as <code> retrieveArticle((String) null) </code>
* 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);
}
/**
* @param articleNumber The number of the the article to retrieve
* @return A DotTerminatedMessageReader instance from which the article
* can be read. null if the article does not exist.
* @throws IOException on error
* @deprecated 3.0 use {@link #retrieveArticle(long)} instead
*/
@Deprecated
public Reader retrieveArticle(final int articleNumber) throws IOException {
return retrieveArticle((long) articleNumber);
}
/**
* @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
* @return A DotTerminatedMessageReader instance from which the article
* can be read. null if the article does not exist.
* @throws IOException on error
* @deprecated 3.0 use {@link #retrieveArticle(long, ArticleInfo)} instead
*/
@Deprecated
public Reader retrieveArticle(final int articleNumber, final ArticlePointer pointer) throws IOException {
final ArticleInfo ai = ap2ai(pointer);
final Reader rdr = retrieveArticle(articleNumber, ai);
ai2ap(ai, pointer);
return rdr;
}
/**
* Same as <code> retrieveArticle(articleNumber, null) </code>
* @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(final long articleNumber) throws IOException
{
return retrieveArticle(articleNumber, 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 <code> articleId </code>
* field of the ArticleInfo cannot always be trusted because some
* NNTP servers do not correctly follow the RFC 977 reply format.
* <p>
* A DotTerminatedMessageReader is returned from which the article can
* be read. If the article does not exist, null is returned.
* <p>
* 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.
* <p>
* @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.
* @throws 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.
* @throws 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(final long articleNumber, final ArticleInfo pointer)
throws IOException
{
return retrieve(NNTPCommand.ARTICLE, articleNumber, pointer);
}
/**
* Same as <code> retrieveArticle(articleId, (ArticleInfo) null) </code>
* 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(final String articleId) throws IOException
{
return retrieveArticle(articleId, (ArticleInfo) null);
}
/**
* Retrieves an article from the NNTP server. The article is referenced
* by its unique article identifier (including the enclosing &lt; and &gt;).
* The article number and identifier contained in the server reply
* are returned through an ArticleInfo. The <code> articleId </code>
* field of the ArticleInfo cannot always be trusted because some
* NNTP servers do not correctly follow the RFC 977 reply format.
* <p>
* A DotTerminatedMessageReader is returned from which the article can
* be read. If the article does not exist, null is returned.
* <p>
* 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.
* <p>
* @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.
* @throws 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.
* @throws 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(final String articleId, final ArticleInfo pointer)
throws IOException
{
return retrieve(NNTPCommand.ARTICLE, articleId, pointer);
}
/**
* @param articleId The unique article identifier of the article to retrieve
* @param pointer A parameter through which to return the article's number and unique id
* @deprecated 3.0 use {@link #retrieveArticle(String, ArticleInfo)} instead
* @return A DotTerminatedMessageReader instance from which the article can be read.
* null if the article does not exist.
* @throws IOException on error
*/
@Deprecated
public Reader retrieveArticle(final String articleId, final ArticlePointer pointer) throws IOException {
final ArticleInfo ai = ap2ai(pointer);
final Reader rdr = retrieveArticle(articleId, ai);
ai2ap(ai, pointer);
return rdr;
}
/**
* Same as <code> retrieveArticleBody(null) </code>
* 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);
}
/**
* @param a tba
* @return tba
* @throws IOException tba
* @deprecated 3.0 use {@link #retrieveArticleBody(long)} instead
*/
@Deprecated
public Reader retrieveArticleBody(final int a) throws IOException {
return retrieveArticleBody((long) a);
}
/**
* @param a tba
* @param ap tba
* @return tba
* @throws IOException tba
* @deprecated 3.0 use {@link #retrieveArticleBody(long, ArticleInfo)} instead
*/
@Deprecated
public Reader retrieveArticleBody(final int a, final ArticlePointer ap) throws IOException {
final ArticleInfo ai = ap2ai(ap);
final Reader rdr = retrieveArticleBody(a, ai);
ai2ap(ai, ap);
return rdr;
}
/**
* Same as <code> retrieveArticleBody(articleNumber, null) </code>
* @param articleNumber the article number
* @return the reader
* @throws IOException if an error occurs
*/
public BufferedReader retrieveArticleBody(final long articleNumber) throws IOException
{
return retrieveArticleBody(articleNumber, 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 <code> articleId </code>
* field of the ArticleInfo cannot always be trusted because some
* NNTP servers do not correctly follow the RFC 977 reply format.
* <p>
* A DotTerminatedMessageReader is returned from which the article can
* be read. If the article does not exist, null is returned.
* <p>
* 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.
* <p>
* @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.
* @throws 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.
* @throws 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(final long articleNumber,
final ArticleInfo pointer)
throws IOException
{
return retrieve(NNTPCommand.BODY, articleNumber, pointer);
}
/**
* Same as <code> retrieveArticleBody(articleId, (ArticleInfo) null) </code>
* 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(final String articleId) throws IOException
{
return retrieveArticleBody(articleId, (ArticleInfo) null);
}
/**
* Retrieves an article body from the NNTP server. The article is
* referenced
* by its unique article identifier (including the enclosing &lt; and &gt;).
* The article number and identifier contained in the server reply
* are returned through an ArticleInfo. The <code> articleId </code>
* field of the ArticleInfo cannot always be trusted because some
* NNTP servers do not correctly follow the RFC 977 reply format.
* <p>
* A DotTerminatedMessageReader is returned from which the article can
* be read. If the article does not exist, null is returned.
* <p>
* 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.
* <p>
* @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.
* @throws 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.
* @throws 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(final String articleId, final ArticleInfo pointer)
throws IOException
{
return retrieve(NNTPCommand.BODY, articleId, pointer);
}
/**
* @param articleId The unique article identifier of the article to retrieve
* @param pointer A parameter through which to return the article's number and unique id
* @return A DotTerminatedMessageReader instance from which the article
* body can be read. null if the article does not exist.
* @throws IOException on error
* @deprecated 3.0 use {@link #retrieveArticleBody(String, ArticleInfo)} instead
*/
@Deprecated
public Reader retrieveArticleBody(final String articleId, final ArticlePointer pointer) throws IOException {
final ArticleInfo ai = ap2ai(pointer);
final Reader rdr = retrieveArticleBody(articleId, ai);
ai2ap(ai, pointer);
return rdr;
}
/**
* Same as <code> retrieveArticleHeader((String) null) </code>
* 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);
}
/**
* @param a tba
* @return tba
* @throws IOException tba
* @deprecated 3.0 use {@link #retrieveArticleHeader(long)} instead
*/
@Deprecated
public Reader retrieveArticleHeader(final int a) throws IOException {
return retrieveArticleHeader((long) a);
}
/**
* @param a tba
* @param ap tba
* @return tba
* @throws IOException tba
* @deprecated 3.0 use {@link #retrieveArticleHeader(long, ArticleInfo)} instead
*/
@Deprecated
public Reader retrieveArticleHeader(final int a, final ArticlePointer ap) throws IOException {
final ArticleInfo ai = ap2ai(ap);
final Reader rdr = retrieveArticleHeader(a, ai);
ai2ap(ai, ap);
return rdr;
}
/**
* Same as <code> retrieveArticleHeader(articleNumber, null) </code>
*
* @param articleNumber the article number
* @return the reader
* @throws IOException if an error occurs
*/
public BufferedReader retrieveArticleHeader(final long articleNumber) throws IOException
{
return retrieveArticleHeader(articleNumber, 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 <code> articleId </code>
* field of the ArticleInfo cannot always be trusted because some
* NNTP servers do not correctly follow the RFC 977 reply format.
* <p>
* A DotTerminatedMessageReader is returned from which the article can
* be read. If the article does not exist, null is returned.
* <p>
* 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.
* <p>
* @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.
* @throws 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.
* @throws 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(final long articleNumber,
final ArticleInfo pointer)
throws IOException
{
return retrieve(NNTPCommand.HEAD, articleNumber, pointer);
}
/**
* Same as <code> retrieveArticleHeader(articleId, (ArticleInfo) null) </code>
* 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(final String articleId) throws IOException
{
return retrieveArticleHeader(articleId, (ArticleInfo) null);
}
/**
* Retrieves an article header from the NNTP server. The article is
* referenced
* by its unique article identifier (including the enclosing &lt; and &gt;).
* The article number and identifier contained in the server reply
* are returned through an ArticleInfo. The <code> articleId </code>
* field of the ArticleInfo cannot always be trusted because some
* NNTP servers do not correctly follow the RFC 977 reply format.
* <p>
* A DotTerminatedMessageReader is returned from which the article can
* be read. If the article does not exist, null is returned.
* <p>
* 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.
* <p>
* @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.
* @throws 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.
* @throws 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(final String articleId, final ArticleInfo pointer)
throws IOException
{
return retrieve(NNTPCommand.HEAD, articleId, pointer);
}
/**
* @param articleId The unique article identifier of the article to retrieve
* @param pointer A parameter through which to return the article's number and unique id
* @return A DotTerminatedMessageReader instance from which the article
* body can be read. null if the article does not exist.
* @throws IOException on error
* @deprecated 3.0 use {@link #retrieveArticleHeader(String, ArticleInfo)} instead
*/
@Deprecated
public Reader retrieveArticleHeader(final String articleId, final ArticlePointer pointer) throws IOException {
final ArticleInfo ai = ap2ai(pointer);
final Reader rdr = retrieveArticleHeader(articleId, ai);
ai2ap(ai, pointer);
return rdr;
}
/**
* @param lowArticleNumber to fetch
* @return a DotTerminatedReader if successful, null otherwise
* @throws IOException tba
* @deprecated 3.0 use {@link #retrieveArticleInfo(long)} instead
*/
@Deprecated
public Reader retrieveArticleInfo(final int lowArticleNumber) throws IOException {
return retrieveArticleInfo((long) lowArticleNumber);
}
/**
* @param lowArticleNumber to fetch
* @param highArticleNumber to fetch
* @return a DotTerminatedReader if successful, null otherwise
* @throws IOException on error
* @deprecated 3.0 use {@link #retrieveArticleInfo(long, long)} instead
*/
@Deprecated
public Reader retrieveArticleInfo(final int lowArticleNumber, final int highArticleNumber) throws IOException {
return retrieveArticleInfo((long) lowArticleNumber, (long) highArticleNumber);
}
/**
* 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 on error
*/
public BufferedReader retrieveArticleInfo(final long articleNumber) throws IOException
{
return retrieveArticleInfo(Long.toString(articleNumber));
}
/**
* Return article headers for all articles between lowArticleNumber
* and highArticleNumber, inclusively. Uses the XOVER command.
* <p>
* @param lowArticleNumber low number
* @param highArticleNumber high number
* @return a DotTerminatedReader if successful, null otherwise
* @throws IOException on error
*/
public BufferedReader retrieveArticleInfo(final long lowArticleNumber,
final long highArticleNumber)
throws IOException
{
return
retrieveArticleInfo(lowArticleNumber + "-" +
highArticleNumber);
}
/**
* Private implementation of XOVER functionality.
*
* See {@link NNTP#xover}
* for legal agument formats. Alternatively, read RFC 2980 :-)
* <p>
* @param articleRange
* @return Returns a DotTerminatedMessageReader if successful, null
* otherwise
* @throws IOException
*/
private BufferedReader retrieveArticleInfo(final String articleRange)
throws IOException
{
if (!NNTPReply.isPositiveCompletion(xover(articleRange))) {
return null;
}
return new DotTerminatedMessageReader(_reader_);
}
/**
* @param a tba
* @param b tba
* @return tba
* @throws IOException tba
* @deprecated 3.0 use {@link #retrieveHeader(String, long)} instead
*/
@Deprecated
public Reader retrieveHeader(final String a, final int b) throws IOException {
return retrieveHeader(a, (long) b);
}
// DEPRECATED METHODS - for API compatibility only - DO NOT USE
// ============================================================
/**
* @param header the header
* @param lowArticleNumber to fetch
* @param highArticleNumber to fetch
* @return a DotTerminatedReader if successful, null otherwise
* @throws IOException on error
* @deprecated 3.0 use {@link #retrieveHeader(String, long, long)} instead
*/
@Deprecated
public Reader retrieveHeader(final String header, final int lowArticleNumber, final int highArticleNumber)
throws IOException
{
return retrieveHeader(header, (long) lowArticleNumber, (long) highArticleNumber);
}
/**
* Return an article header for a specified post.
* <p>
* @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(final String header, final long articleNumber)
throws IOException
{
return retrieveHeader(header, Long.toString(articleNumber));
}
/**
* Return an article header for all articles between lowArticleNumber
* and highArticleNumber, inclusively.
* <p>
* @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(final String header, final long lowArticleNumber,
final long highArticleNumber)
throws IOException
{
return
retrieveHeader(header,lowArticleNumber + "-" + highArticleNumber);
}
/**
* Private implementation of XHDR functionality.
*
* See {@link NNTP#xhdr}
* for legal agument formats. Alternatively, read RFC 1036.
* <p>
* @param header
* @param articleRange
* @return Returns a DotTerminatedMessageReader if successful, null
* otherwise
* @throws IOException
*/
private BufferedReader retrieveHeader(final String header, final String articleRange)
throws IOException
{
if (!NNTPReply.isPositiveCompletion(xhdr(header, articleRange))) {
return null;
}
return new DotTerminatedMessageReader(_reader_);
}
/***
* Same as <code> selectArticle((String) null, articleId) </code>. Useful
* for retrieving the current article number.
* @param pointer to the article
* @return true if OK
* @throws IOException on error
*/
public boolean selectArticle(final ArticleInfo pointer) throws IOException
{
return selectArticle(null, pointer);
}
/**
* @param pointer A parameter through which to return the article's number and unique id
* @return True if successful, false if not.
* @throws IOException on error
* @deprecated 3.0 use {@link #selectArticle(ArticleInfo)} instead
*/
@Deprecated
public boolean selectArticle(final ArticlePointer pointer) throws IOException {
final ArticleInfo ai = ap2ai(pointer);
final boolean b = selectArticle(ai);
ai2ap(ai, pointer);
return b;
}
/**
* @param a tba
* @return tba
* @throws IOException tba
* @deprecated 3.0 use {@link #selectArticle(long)} instead
*/
@Deprecated
public boolean selectArticle(final int a) throws IOException {
return selectArticle((long) a);
}
/**
* @param a tba
* @param ap tba
* @return tba
* @throws IOException tba
* @deprecated 3.0 use {@link #selectArticle(long, ArticleInfo)} instead
*/
@Deprecated
public boolean selectArticle(final int a, final ArticlePointer ap) throws IOException {
final ArticleInfo ai = ap2ai(ap);
final boolean b = selectArticle(a, ai);
ai2ap(ai, ap);
return b;
}
/** Same as <code> selectArticle(articleNumber, null) </code>
* @param articleNumber the numger
* @return true if successful
* @throws IOException on error */
public boolean selectArticle(final long articleNumber) throws IOException
{
return selectArticle(articleNumber, null);
}
/**
* 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.
* <p>
* @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.
* @throws 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.
* @throws 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(final long articleNumber, final ArticleInfo pointer)
throws IOException
{
if (!NNTPReply.isPositiveCompletion(stat(articleNumber))) {
return false;
}
if (pointer != null) {
parseArticlePointer(getReplyString(), pointer);
}
return true;
}
/**
* Same as <code> selectArticle(articleId, (ArticleInfo) null) </code>
* @param articleId the article Id
* @return true if successful
* @throws IOException on error
*/
public boolean selectArticle(final String articleId) throws IOException
{
return selectArticle(articleId, (ArticleInfo) null);
}
/**
* Select an article by its unique identifier (including enclosing
* &lt; and &gt;) 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.
* <p>
* @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.
* @throws 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.
* @throws 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(final String articleId, final 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;
}
/**
* @param articleId The unique article identifier of the article to retrieve
* @param pointer A parameter through which to return the article's number and unique id
* @return A DotTerminatedMessageReader instance from which the article
* body can be read. null if the article does not exist.
* @throws IOException on error
* @deprecated 3.0 use {@link #selectArticle(String, ArticleInfo)} instead
*/
@Deprecated
public boolean selectArticle(final String articleId, final ArticlePointer pointer) throws IOException {
final ArticleInfo ai = ap2ai(pointer);
final boolean b = selectArticle(articleId, ai);
ai2ap(ai, pointer);
return b;
}
/**
* Same as <code> selectNewsgroup(newsgroup, null) </code>
* @param newsgroup the newsgroup name
* @return true if newsgroup exist and was selected
* @throws IOException if an error occurs
*/
public boolean selectNewsgroup(final String newsgroup) throws IOException
{
return selectNewsgroup(newsgroup, 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.
* <p>
* @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.
* @throws 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.
* @throws 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(final String newsgroup, final NewsgroupInfo info)
throws IOException
{
if (!NNTPReply.isPositiveCompletion(group(newsgroup))) {
return false;
}
if (info != null) {
parseGroupReply(getReplyString(), info);
}
return true;
}
/** Same as <code> selectNextArticle((ArticleInfo) null) </code>
* @return true if successful
* @throws IOException on error */
public boolean selectNextArticle() throws IOException
{
return selectNextArticle((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
* <code> selectArticle(pointer.articleNumber, pointer) </code> immediately
* afterward.
* <p>
* @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).
* @throws 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.
* @throws 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(final ArticleInfo pointer) throws IOException
{
if (!NNTPReply.isPositiveCompletion(next())) {
return false;
}
if (pointer != null) {
parseArticlePointer(getReplyString(), pointer);
}
return true;
}
/**
* @param pointer A parameter through which to return the article's number and unique id
* @return True if successful, false if not.
* @throws IOException on error
* @deprecated 3.0 use {@link #selectNextArticle(ArticleInfo)} instead
*/
@Deprecated
public boolean selectNextArticle(final ArticlePointer pointer) throws IOException {
final ArticleInfo ai = ap2ai(pointer);
final boolean b = selectNextArticle(ai);
ai2ap(ai, pointer);
return b;
}
/** Same as <code> selectPreviousArticle((ArticleInfo) null) </code>
* @return true if successful
* @throws IOException on error */
public boolean selectPreviousArticle() throws IOException
{
return selectPreviousArticle((ArticleInfo) null);
}
// Helper methods
/**
* 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
* <code> selectArticle(pointer.articleNumber, pointer) </code> immediately
* afterward.
* <p>
* @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).
* @throws 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.
* @throws 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(final ArticleInfo pointer)
throws IOException
{
if (!NNTPReply.isPositiveCompletion(last())) {
return false;
}
if (pointer != null) {
parseArticlePointer(getReplyString(), pointer);
}
return true;
}
/**
* @param pointer A parameter through which to return the article's number and unique id
* @return True if successful, false if not.
* @throws IOException on error
* @deprecated 3.0 use {@link #selectPreviousArticle(ArticleInfo)} instead
*/
@Deprecated
public boolean selectPreviousArticle(final ArticlePointer pointer) throws IOException {
final ArticleInfo ai = ap2ai(pointer);
final boolean b = selectPreviousArticle(ai);
ai2ap(ai, pointer);
return b;
}
}