| /* |
| * 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 < and >. |
| * <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 < and >. |
| * 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) { |
| list.addElement(tmp); |
| } else { |
| throw new MalformedServerReplyException(line); |
| } |
| } |
| } |
| 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 < and >). |
| * 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 < and >). |
| * 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 < and >). |
| * 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 |
| * < 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. |
| * <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; |
| } |
| } |