You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by br...@apache.org on 2002/04/03 06:39:14 UTC

cvs commit: jakarta-commons-sandbox/net/src/java/org/apache/commons/net/nntp ArticlePointer.java NNTP.java NNTPClient.java NNTPCommand.java NNTPConnectionClosedException.java NNTPReply.java NewGroupsOrNewsQuery.java NewsgroupInfo.java SimpleNNTPHeader.java

brekke      02/04/02 20:39:14

  Added:       net/src/java/org/apache/commons/net/nntp ArticlePointer.java
                        NNTP.java NNTPClient.java NNTPCommand.java
                        NNTPConnectionClosedException.java NNTPReply.java
                        NewGroupsOrNewsQuery.java NewsgroupInfo.java
                        SimpleNNTPHeader.java
  Log:
  Moving com.oroinc.net.nntp to org.apache.commons.net.nntp
  
  Revision  Changes    Path
  1.1                  jakarta-commons-sandbox/net/src/java/org/apache/commons/net/nntp/ArticlePointer.java
  
  Index: ArticlePointer.java
  ===================================================================
  package org.apache.commons.net.nntp;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  /***
   * This class is a structure used to return article number and unique
   * id information extracted from an NNTP server reply.  You will normally
   * want this information when issuing a STAT command, implemented by
   * <a href="org.apache.commons.net.nntp.NNTPClient.html#selectArticle">
   * selectArticle </a>.
   * <p>
   * <p>
   * @author Daniel F. Savarese
   * @see NNTPClient
   ***/
  
  public final class ArticlePointer {
    /*** The number of the referenced article. ***/
    public int articleNumber;
    /***
     * The unique id of the referenced article, including the enclosing
     * &lt and &gt symbols which are technically not part of the
     * identifier, but are required by all NNTP commands taking an
     * article id as an argument.
     ***/
    public String articleId;
  }
  
  
  
  1.1                  jakarta-commons-sandbox/net/src/java/org/apache/commons/net/nntp/NNTP.java
  
  Index: NNTP.java
  ===================================================================
  package org.apache.commons.net.nntp;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  
  import org.apache.commons.net.*;
  
  /***
   * The NNTP class is not meant to be used by itself and is provided
   * only so that you may easily implement your own NNTP client if 
   * you so desire.  If you have no need to perform your own implementation,
   * you should use <a href="org.apache.commons.net.nntp.NNTPClient.html">NNTPClient</a>.
   * The NNTP class is made public to provide access to various NNTP constants
   * and to make it easier for adventurous programmers (or those with special
   * needs) to interact with the NNTP protocol and implement their own clients.
   * A set of methods with names corresponding to the NNTP command names are
   * provided to facilitate this interaction.
   * <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
   * <a href="org.apache.commons.net.nntp.NNTPReply.html#SERVICE_DISCONTINUED">
   * NNTPReply.SERVICE_DISCONTINUED </a> response to a command.
   * When that occurs, the NNTP class method encountering that reply will throw
   * an <a href="org.apache.commons.net.nntp.NNTPConnectionClosedException.html">
   * NNTPConnectionClosedException </a>.
   * <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
   * <a href="org.apache.commons.net.nntp.NNTPConnectionClosedException.html">
   * NNTPConnectionClosedException </a>, you must disconnect the connection with
   * <a href="#disconnect"> disconnect() </a> to properly clean up the
   * system resources used by NNTP.  Before disconnecting, you may check the
   * last reply code and text with
   * <a href="#getReplyCode"> getReplyCode </a> and
   * <a href="#getReplyString"> getReplyString </a>.
   * <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 
   * <a href="org.apache.commons.net.MalformedServerReplyException.html">
   * MalformedServerReplyException </a>, 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.
   * <p>
   * <p>
   * @author Daniel F. Savarese
   * @see NNTPClient
   * @see NNTPConnectionClosedException
   * @see org.apache.commons.net.MalformedServerReplyException
   ***/
  
  public class NNTP extends SocketClient {
    /*** The default NNTP port.  Its value is 119 according to RFC 977. ***/
    public  static final int DEFAULT_PORT    = 119;
  
    private StringBuffer __commandBuffer;
  
    boolean _isAllowedToPost;
    BufferedWriter _writer;
    BufferedReader _reader;
    int _replyCode;
    String  _replyString;
  
    /***
     * A ProtocolCommandSupport object used to manage the registering of
     * ProtocolCommandListeners and te firing of ProtocolCommandEvents.
     ***/
    protected ProtocolCommandSupport _commandSupport_;
  
    /***
     * The default NNTP constructor.  Sets the default port to
     * <code>DEFAULT_PORT</code> and initializes internal data structures
     * for saving NNTP reply information.
     ***/
    public NNTP() {
      setDefaultPort(DEFAULT_PORT);
      __commandBuffer  = new StringBuffer();
      _replyString     = null;
      _reader          = null;
      _writer          = null;
      _isAllowedToPost = false;
      _commandSupport_ = new ProtocolCommandSupport(this);
    }
  
    private void __getReply() throws IOException {
      _replyString = _reader.readLine();
  
      if(_replyString == null)
        throw new NNTPConnectionClosedException(
  		      "Connection closed without indication.");
  
      // In case we run into an anomaly we don't want fatal index exceptions
      // to be thrown.
      if(_replyString.length() < 3)
        throw new MalformedServerReplyException(
  			      "Truncated server reply: " + _replyString);
      try {
        _replyCode = Integer.parseInt(_replyString.substring(0, 3));
      } catch(NumberFormatException e) {
        throw new MalformedServerReplyException(
        "Could not parse response code.\nServer Reply: " + _replyString);
      }
  
      if(_commandSupport_.getListenerCount() > 0)
        _commandSupport_.fireReplyReceived(_replyCode, _replyString +
  					 SocketClient.NETASCII_EOL);
  
      if(_replyCode == NNTPReply.SERVICE_DISCONTINUED)
        throw new NNTPConnectionClosedException(
  	      "NNTP response 400 received.  Server closed connection.");
    }
  
    /*** 
     * Initiates control connections and gets initial reply, determining
     * if the client is allowed to post to the server.
     ***/
    protected void _connectAction_() throws IOException {
      super._connectAction_();
      _reader = 
        new BufferedReader(new InputStreamReader(_input_));
      _writer =
        new BufferedWriter(new OutputStreamWriter(_output_));
      __getReply();
  
      _isAllowedToPost = (_replyCode == NNTPReply.SERVER_READY_POSTING_ALLOWED);
    }
  
    /***
     * Adds a ProtocolCommandListener.  Delegates this task to
     * <a href="#_commandSupport_"> _commandSupport_ </a>.
     * <p>
     * @param listener  The ProtocolCommandListener to add.
     ***/
    public void addProtocolCommandListener(ProtocolCommandListener listener){
      _commandSupport_.addProtocolCommandListener(listener);
    }
  
    /***
     * Removes a ProtocolCommandListener.  Delegates this task to
     * <a href="#_commandSupport_"> _commandSupport_ </a>.
     * <p>
     * @param listener  The ProtocolCommandListener to remove.
     ***/
    public void removeProtocolCommandistener(ProtocolCommandListener listener){
      _commandSupport_.removeProtocolCommandListener(listener);
    }
  
    /***
     * Closes the connection to the NNTP server and sets to null
     * some internal data so that the memory may be reclaimed by the
     * garbage collector.  The reply text and code information from the
     * last command is voided so that the memory it used may be reclaimed.
     * <p>
     * @exception IOException If an error occurs while disconnecting.
     ***/
    public void disconnect() throws IOException {
      super.disconnect();
      _reader          = null;
      _writer          = null;
      _replyString     = null;
      _isAllowedToPost = false;
    }
  
  
    /***
     * Indicates whether or not the client is allowed to post articles to
     * the server it is currently connected to.
     * <p>
     * @return True if the client can post articles to the server, false
     *         otherwise.
     ***/
    public boolean isAllowedToPost() { return _isAllowedToPost; }
  
  
    /***
     * Sends an NNTP command to the server, waits for a reply and returns the
     * numerical response code.  After invocation, for more detailed
     * information, the actual reply text can be accessed by calling
     * <a href="#getReplyString"> getReplyString </a>.
     * <p>
     * @param command  The text representation of the  NNTP command to send.
     * @param args The arguments to the NNTP command.  If this parameter is
     *             set to null, then the command is sent with no argument.
     * @return The integer value of the NNTP reply code returned by the server
     *         in response to the command.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int sendCommand(String command, String args) throws IOException {
      String message;
  
      __commandBuffer.setLength(0);
      __commandBuffer.append(command);
  
      if(args != null) {
        __commandBuffer.append(' ');
        __commandBuffer.append(args);
      }
      __commandBuffer.append(SocketClient.NETASCII_EOL);
  
      _writer.write(message = __commandBuffer.toString());
      _writer.flush();
  
      if(_commandSupport_.getListenerCount() > 0)
        _commandSupport_.fireCommandSent(command, message);
  
      __getReply();
      return _replyCode;
    }
  
  
    /***
     * Sends an NNTP command to the server, waits for a reply and returns the
     * numerical response code.  After invocation, for more detailed
     * information, the actual reply text can be accessed by calling
     * <a href="#getReplyString"> getReplyString </a>.
     * <p>
     * @param command  The NNTPCommand constant corresponding to the NNTP command
     *                 to send.
     * @param args The arguments to the NNTP command.  If this parameter is
     *             set to null, then the command is sent with no argument.
     * @return The integer value of the NNTP reply code returned by the server
     *         in response to the command.
     *         in response to the command.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int sendCommand(int command, String args) throws IOException {
      return sendCommand(NNTPCommand._commands[command], args);
    }
  
  
    /***
     * Sends an NNTP command with no arguments to the server, waits for a
     * reply and returns the numerical response code.  After invocation, for
     * more detailed information, the actual reply text can be accessed by
     * calling <a href="#getReplyString"> getReplyString </a>.
     * <p>
     * @param command  The text representation of the  NNTP command to send.
     * @return The integer value of the NNTP reply code returned by the server
     *         in response to the command.
     *         in response to the command.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int sendCommand(String command) throws IOException {
      return sendCommand(command, null);
    }
  
  
    /***
     * Sends an NNTP command with no arguments to the server, waits for a
     * reply and returns the numerical response code.  After invocation, for
     * more detailed information, the actual reply text can be accessed by
     * calling <a href="#getReplyString"> getReplyString </a>.
     * <p>
     * @param command  The NNTPCommand constant corresponding to the NNTP command
     *                 to send.
     * @return The integer value of the NNTP reply code returned by the server
     *         in response to the command.
     *         in response to the command.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int sendCommand(int command) throws IOException {
      return sendCommand(command, null);
    }
  
  
    /***
     * Returns the integer value of the reply code of the last NNTP reply.
     * You will usually only use this method after you connect to the
     * NNTP server to check that the connection was successful since
     * <code> connect </code> is of type void.
     * <p>
     * @return The integer value of the reply code of the last NNTP reply.
     ***/
    public int getReplyCode() {
      return _replyCode;
    }
  
    /***
     * Fetches a reply from the NNTP server and returns the integer reply
     * code.  After calling this method, the actual reply text can be accessed
     * from <a href="#getReplyString"> getReplyString </a>.  Only use this
     * method if you are implementing your own NNTP client or if you need to
     * fetch a secondary response from the NNTP server.
     * <p>
     * @return The integer value of the reply code of the fetched NNTP reply.
     *         in response to the command.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while 
     *      receiving the server reply.
     ***/
    public int getReply() throws IOException {
      __getReply();
      return _replyCode;
    }
  
  
    /***
     * Returns the entire text of the last NNTP server response exactly
     * as it was received, not including the end of line marker.
     * <p>
     * @return The entire text from the last NNTP response as a String.
     ***/
    public String getReplyString() { return _replyString;  }
  
  
    /***
     * A convenience method to send the NNTP ARTICLE command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @param messageId  The message identifier of the requested article,
     *                   including the encapsulating &lt and &gt characters.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int article(String messageId) throws IOException {
      return sendCommand(NNTPCommand.ARTICLE, messageId);
    }
  
    /***
     * A convenience method to send the NNTP ARTICLE command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @param articleNumber The number of the article to request from the
     *                      currently selected newsgroup.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int article(int articleNumber) throws IOException {
      return sendCommand(NNTPCommand.ARTICLE, Integer.toString(articleNumber));
    }
  
    /***
     * A convenience method to send the NNTP ARTICLE command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int article() throws IOException {
      return sendCommand(NNTPCommand.ARTICLE);
    }
  
  
  
    /***
     * A convenience method to send the NNTP BODY command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @param messageId  The message identifier of the requested article,
     *                   including the encapsulating &lt and &gt characters.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int body(String messageId) throws IOException {
      return sendCommand(NNTPCommand.BODY, messageId);
    }
  
    /***
     * A convenience method to send the NNTP BODY command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @param articleNumber The number of the article to request from the
     *                      currently selected newsgroup.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int body(int articleNumber) throws IOException {
      return sendCommand(NNTPCommand.BODY, Integer.toString(articleNumber));
    }
  
    /***
     * A convenience method to send the NNTP BODY command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int body() throws IOException {
      return sendCommand(NNTPCommand.BODY);
    }
  
  
  
    /***
     * A convenience method to send the NNTP HEAD command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @param messageId  The message identifier of the requested article,
     *                   including the encapsulating &lt and &gt characters.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int head(String messageId) throws IOException {
      return sendCommand(NNTPCommand.HEAD, messageId);
    }
  
    /***
     * A convenience method to send the NNTP HEAD command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @param articleNumber The number of the article to request from the
     *                      currently selected newsgroup.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int head(int articleNumber) throws IOException {
      return sendCommand(NNTPCommand.HEAD, Integer.toString(articleNumber));
    }
  
    /***
     * A convenience method to send the NNTP HEAD command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int head() throws IOException {
      return sendCommand(NNTPCommand.HEAD);
    }
  
  
  
    /***
     * A convenience method to send the NNTP STAT command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @param messageId  The message identifier of the requested article,
     *                   including the encapsulating &lt and &gt characters.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int stat(String messageId) throws IOException {
      return sendCommand(NNTPCommand.STAT, messageId);
    }
  
    /***
     * A convenience method to send the NNTP STAT command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @param articleNumber The number of the article to request from the
     *                      currently selected newsgroup.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int stat(int articleNumber) throws IOException {
      return sendCommand(NNTPCommand.STAT, Integer.toString(articleNumber));
    }
  
    /***
     * A convenience method to send the NNTP STAT command to the server,
     * receive the initial reply, and return the reply code.
     * <p>
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int stat() throws IOException {
      return sendCommand(NNTPCommand.STAT);
    }
  
  
    /***
     * A convenience method to send the NNTP GROUP command to the server,
     * receive the reply, and return the reply code.
     * <p>
     * @param newsgroup  The name of the newsgroup to select.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int group(String newsgroup) throws IOException {
      return sendCommand(NNTPCommand.GROUP, newsgroup);
    }
  
  
    /***
     * A convenience method to send the NNTP HELP command to the server,
     * receive the reply, and return the reply code.
     * <p>
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int help() throws IOException {
      return sendCommand(NNTPCommand.HELP);
    }
  
  
    /***
     * A convenience method to send the NNTP IHAVE command to the server,
     * receive the reply, and return the reply code.
     * <p>
     * @param messageId  The article identifier,
     *                   including the encapsulating &lt and &gt characters.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int ihave(String messageId) throws IOException {
      return sendCommand(NNTPCommand.IHAVE, messageId);
    }
  
  
    /***
     * A convenience method to send the NNTP LAST command to the server,
     * receive the reply, and return the reply code.
     * <p>
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int last() throws IOException {
      return sendCommand(NNTPCommand.LAST);
    }
  
  
  
    /***
     * A convenience method to send the NNTP LIST command to the server,
     * receive the reply, and return the reply code.
     * <p>
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int list() throws IOException {
      return sendCommand(NNTPCommand.LIST);
    }
  
  
  
    /***
     * A convenience method to send the NNTP NEXT command to the server,
     * receive the reply, and return the reply code.
     * <p>
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int next() throws IOException {
      return sendCommand(NNTPCommand.NEXT);
    }
  
  
    /***
     * A convenience method to send the NNTP NEWGROUPS command to the server,
     * receive the reply, and return the reply code.
     * <p>
     * @param date The date after which to check for new groups.
     *             Date format is YYMMDD
     * @param time The time after which to check for new groups.
     *             Time format is HHMMSS using a 24-hour clock.
     * @param GMT  True if the time is in GMT, false if local server time.
     * @param distributions  Comma-separated distribution list to check for
     *            new groups. Set to null if no distributions.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int newgroups(String date, String time, boolean GMT,
  		       String distributions) throws IOException
    {
      StringBuffer buffer = new StringBuffer();
  
      buffer.append(date);
      buffer.append(' ');
      buffer.append(time);
  
      if(GMT) {
        buffer.append(' ');
        buffer.append("GMT");
      }
  
      if(distributions != null) {
        buffer.append(" <");
        buffer.append(distributions);
        buffer.append('>');
      }
  
      return sendCommand(NNTPCommand.NEWGROUPS, buffer.toString());
    }
  
  
    /***
     * A convenience method to send the NNTP NEWGROUPS command to the server,
     * receive the reply, and return the reply code.
     * <p>
     * @param newsgroups A comma-separated list of newsgroups to check for new
     *             news.
     * @param date The date after which to check for new news.
     *             Date format is YYMMDD
     * @param time The time after which to check for new news.
     *             Time format is HHMMSS using a 24-hour clock.
     * @param GMT  True if the time is in GMT, false if local server time.
     * @param distributions  Comma-separated distribution list to check for
     *            new news. Set to null if no distributions.
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int newnews(String newsgroups, String date, String time, boolean GMT,
  		     String distributions) throws IOException
    {
      StringBuffer buffer = new StringBuffer();
  
      buffer.append(newsgroups);
      buffer.append(' ');
      buffer.append(date);
      buffer.append(' ');
      buffer.append(time);
  
      if(GMT) {
        buffer.append(' ');
        buffer.append("GMT");
      }
  
      if(distributions != null) {
        buffer.append(" <");
        buffer.append(distributions);
        buffer.append('>');
      }
  
      return sendCommand(NNTPCommand.NEWNEWS, buffer.toString());
    }
  
  
  
    /***
     * A convenience method to send the NNTP POST command to the server,
     * receive the reply, and return the reply code.
     * <p>
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int post() throws IOException {
      return sendCommand(NNTPCommand.POST);
    }
  
  
  
    /***
     * A convenience method to send the NNTP QUIT command to the server,
     * receive the reply, and return the reply code.
     * <p>
     * @return The reply code received from the server.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending the
     *      command or receiving the server reply.
     ***/
    public int quit() throws IOException {
      return sendCommand(NNTPCommand.QUIT);
    }
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/net/src/java/org/apache/commons/net/nntp/NNTPClient.java
  
  Index: NNTPClient.java
  ===================================================================
  package org.apache.commons.net.nntp;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  
  import org.apache.commons.net.*;
  import org.apache.commons.io.*;
  
  /***
   * NNTPClient encapsulates all the functionality necessary to post and
   * retrieve articles from an NNTP server.  As with all classes derived
   * from <a href="org.apache.commons.net.SocketClient.html"> SocketClient </a>,
   * you must first connect to the server with 
   * <a href="org.apache.commons.net.SocketClient.html#connect"> connect </a>
   * before doing anything, and finally
   * <a href="org.apache.commons.net.nntp.NNTP.html#disconnect"> disconnect() </a>
   * after you're completely finished interacting with the server.
   * Remember that the 
   * <a href="org.apache.commons.net.nntp.NNTP.html#isAllowedToPost">
   * isAllowedToPost()</a> method is defined in
   * <a href="org.apache.commons.net.nntp.NNTP.html"> NNTP </a>.
   * <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
   * <a href="org.apache.commons.net.nntp.NNTPReply.html#SERVICE_DISCONTINUED">
   * NNTPReply.SERVICE_DISCONTINUED </a> response to a command.
   * When that occurs, the NNTP class method encountering that reply will throw
   * an <a href="org.apache.commons.net.nntp.NNTPConnectionClosedException.html">
   * NNTPConnectionClosedException </a>.
   * <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
   * <a href="org.apache.commons.net.nntp.NNTPConnectionClosedException.html">
   * NNTPConnectionClosedException </a>, you must disconnect the connection with
   * <a href="org.apache.commons.net.nntp.NNTP.html#disconnect"> disconnect() </a>
   *  to properly clean up the
   * system resources used by NNTP.  Before disconnecting, you may check the
   * last reply code and text with
   * <a href="org.apache.commons.net.nntp.NNTP.html#getReplyCode"> getReplyCode </a> and
   * <a href="org.apache.commons.net.nntp.NNTP.html#getReplyString"> getReplyString </a>.
   * <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 
   * <a href="org.apache.commons.net.MalformedServerReplyException.html">
   * MalformedServerReplyException </a>, 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.
   * <p>
   * <p>
   * @author Daniel F. Savarese
   * @see NNTP
   * @see NNTPConnectionClosedException
   * @see org.apache.commons.net.MalformedServerReplyException
   ***/
  
  public class NNTPClient extends NNTP {
  
    private void __parseArticlePointer(String reply, ArticlePointer pointer)
         throws MalformedServerReplyException
    {
      StringTokenizer tokenizer;
  
      // Do loop is a kluge to simulate goto
      do {
        tokenizer = new StringTokenizer(reply);
  
        if(tokenizer.countTokens() < 3)
  	break;
  
        // Skip numeric response value
        tokenizer.nextToken();
        // Get article number
        try {
  	pointer.articleNumber = Integer.parseInt(tokenizer.nextToken());
        } catch(NumberFormatException e) {
  	break;
        }
  
        // Get article id
        pointer.articleId = tokenizer.nextToken();
        return;
      } while(false);
  
      throw new MalformedServerReplyException(
  	    "Could not parse article pointer.\nServer reply: " + reply);
    }
  
  
    private void __parseGroupReply(String reply, NewsgroupInfo info)
         throws MalformedServerReplyException
    {
      String count, first, last;
      StringTokenizer tokenizer;
  
      // Do loop is a kluge to simulate goto
      do {
        tokenizer = new StringTokenizer(reply);
  
        if(tokenizer.countTokens() < 5)
  	break;
  
        // Skip numeric response value
        tokenizer.nextToken();
        // Get estimated article count
        count = tokenizer.nextToken();
        // Get first article number
        first = tokenizer.nextToken();
        // Get last article number
        last = tokenizer.nextToken();
        // Get newsgroup name
        info._setNewsgroup(tokenizer.nextToken());
  
        try {
  	info._setArticleCount(Integer.parseInt(count));
  	info._setFirstArticle(Integer.parseInt(first));
  	info._setLastArticle(Integer.parseInt(last));
        } catch(NumberFormatException e) {
  	break;
        }
  
        info._setPostingPermission(NewsgroupInfo.UNKNOWN_POSTING_PERMISSION);
        return;
      } while(false);
  
      throw new MalformedServerReplyException(
  	    "Could not parse newsgroup info.\nServer reply: " + reply);
    }
  
  
    private NewsgroupInfo __parseNewsgroupListEntry(String entry) {
      NewsgroupInfo result;
      StringTokenizer tokenizer;
      int    lastNum, firstNum;
      String last, first, permission;
  
      result    = new NewsgroupInfo();
      tokenizer = new StringTokenizer(entry);
  
      if(tokenizer.countTokens() < 4)
        return null;
      
      result._setNewsgroup(tokenizer.nextToken());
      last       = tokenizer.nextToken();
      first      = tokenizer.nextToken();
      permission = tokenizer.nextToken();
  
      try {
        lastNum  = Integer.parseInt(last);
        firstNum = Integer.parseInt(first);
        result._setFirstArticle(firstNum);
        result._setLastArticle(lastNum);
        result._setArticleCount(lastNum - firstNum + 1);
      } catch(NumberFormatException e) {
        return null;
      }
  
      switch(permission.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;
    }
  
    private NewsgroupInfo[] __readNewsgroupListing() throws IOException {
      int size;
      String line;
      Vector list;
      BufferedReader reader;
      NewsgroupInfo tmp, info[];
  
      reader = new BufferedReader(new DotTerminatedMessageReader(_reader));
      // Start of with a big vector because we may be reading a very large
      // amount of groups.
      list = new Vector(2048);
  
      while((line = reader.readLine()) != null) {
        tmp = __parseNewsgroupListEntry(line);
        if(tmp != null)
  	list.addElement(tmp);
        else
  	throw new MalformedServerReplyException(line);
      }
  
      if((size = list.size()) < 1)
        return new NewsgroupInfo[0];
  
      info = new NewsgroupInfo[size];
      list.copyInto(info);
  
      return info;
    }
  
  
    private Reader __retrieve(int command,
  			    String articleId, ArticlePointer pointer)
         throws IOException
    {
      Reader reader;
  
      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);
  
      reader = new DotTerminatedMessageReader(_reader);
      return reader;
    }
  
  
    private Reader __retrieve(int command,
  			    int articleNumber, ArticlePointer pointer)
         throws IOException {
      Reader reader;
  
      if(!NNTPReply.isPositiveCompletion(sendCommand(command,
  					   Integer.toString(articleNumber))))
        return null;
  
      if(pointer != null)
        __parseArticlePointer(getReplyString(), pointer);
  
      reader = new DotTerminatedMessageReader(_reader);
      return reader;
    }
  
  
  
    /***
     * 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 ArticlePointer.  The <code> articleId </code>
     * field of the ArticlePointer 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
     * Reader instance.
     * The NNTP protocol uses the same stream for issuing commands as it does
     * for returning results.  Therefore the returned Reader 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
     *         be read.  null if the article does not exist.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public Reader retrieveArticle(String articleId, ArticlePointer pointer)
         throws IOException
    {
      return __retrieve(NNTPCommand.ARTICLE, articleId, pointer);
  
    }
  
    /*** Same as <code> retrieveArticle(articleId, null) </code> ***/
    public Reader retrieveArticle(String articleId) throws IOException {
      return retrieveArticle(articleId, null);
    }
  
    /*** Same as <code> retrieveArticle(null) </code> ***/
    public Reader retrieveArticle() throws IOException {
      return retrieveArticle(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 ArticlePointer.  The <code> articleId </code>
     * field of the ArticlePointer 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
     * Reader instance.
     * The NNTP protocol uses the same stream for issuing commands as it does
     * for returning results.  Therefore the returned Reader 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
     *         be read.  null if the article does not exist.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public Reader retrieveArticle(int articleNumber, ArticlePointer pointer)
         throws IOException
    {
      return __retrieve(NNTPCommand.ARTICLE, articleNumber, pointer);
    }
  
    /*** Same as <code> retrieveArticle(articleNumber, null) </code> ***/
    public Reader retrieveArticle(int articleNumber) throws IOException {
      return retrieveArticle(articleNumber, null);
    }
  
  
  
    /***
     * Retrieves an article header from the NNTP server.  The article is
     * referenced
     * by its unique article identifier (including the enclosing &lt and &gt).
     * The article number and identifier contained in the server reply
     * are returned through an ArticlePointer.  The <code> articleId </code>
     * field of the ArticlePointer 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
     * Reader instance.
     * The NNTP protocol uses the same stream for issuing commands as it does
     * for returning results.  Therefore the returned Reader 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.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public Reader retrieveArticleHeader(String articleId, ArticlePointer pointer)
         throws IOException
    {
      return __retrieve(NNTPCommand.HEAD, articleId, pointer);
  
    }
  
    /*** Same as <code> retrieveArticleHeader(articleId, null) </code> ***/
    public Reader retrieveArticleHeader(String articleId) throws IOException {
      return retrieveArticleHeader(articleId, null);
    }
  
    /*** Same as <code> retrieveArticleHeader(null) </code> ***/
    public Reader retrieveArticleHeader() throws IOException {
      return retrieveArticleHeader(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 ArticlePointer.  The <code> articleId </code>
     * field of the ArticlePointer 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
     * Reader instance.
     * The NNTP protocol uses the same stream for issuing commands as it does
     * for returning results.  Therefore the returned Reader 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.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public Reader retrieveArticleHeader(int articleNumber,
  				      ArticlePointer pointer)
         throws IOException
    {
      return __retrieve(NNTPCommand.HEAD, articleNumber, pointer);
    }
  
  
    /*** Same as <code> retrieveArticleHeader(articleNumber, null) </code> ***/
    public Reader retrieveArticleHeader(int articleNumber) throws IOException {
      return retrieveArticleHeader(articleNumber, null);
    }
  
  
  
    /***
     * Retrieves an article body from the NNTP server.  The article is
     * referenced
     * by its unique article identifier (including the enclosing &lt and &gt).
     * The article number and identifier contained in the server reply
     * are returned through an ArticlePointer.  The <code> articleId </code>
     * field of the ArticlePointer 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
     * Reader instance.
     * The NNTP protocol uses the same stream for issuing commands as it does
     * for returning results.  Therefore the returned Reader 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.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public Reader retrieveArticleBody(String articleId, ArticlePointer pointer)
         throws IOException
    {
      return __retrieve(NNTPCommand.BODY, articleId, pointer);
  
    }
  
    /*** Same as <code> retrieveArticleBody(articleId, null) </code> ***/
    public Reader retrieveArticleBody(String articleId) throws IOException {
      return retrieveArticleBody(articleId, null);
    }
  
    /*** Same as <code> retrieveArticleBody(null) </code> ***/
    public Reader retrieveArticleBody() throws IOException {
      return retrieveArticleBody(null);
    }
  
  
    /***
     * Retrieves an article body from the currently selected newsgroup.  The
     * article is referenced by its article number.
     * The article number and identifier contained in the server reply
     * are returned through an ArticlePointer.  The <code> articleId </code>
     * field of the ArticlePointer 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
     * Reader instance.
     * The NNTP protocol uses the same stream for issuing commands as it does
     * for returning results.  Therefore the returned Reader 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.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public Reader retrieveArticleBody(int articleNumber,
  				    ArticlePointer pointer)
         throws IOException
    {
      return __retrieve(NNTPCommand.BODY, articleNumber, pointer);
    }
  
  
    /*** Same as <code> retrieveArticleBody(articleNumber, null) </code> ***/
    public Reader retrieveArticleBody(int articleNumber) throws IOException {
      return retrieveArticleBody(articleNumber, null);
    }
  
  
    /***
     * Select the specified newsgroup to be the target of for future article
     * retrieval and posting operations.  Also return the newsgroup
     * information contained in the server reply through the info parameter.
     * <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.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public boolean selectNewsgroup(String newsgroup, NewsgroupInfo info)
         throws IOException
    {
      if(!NNTPReply.isPositiveCompletion(group(newsgroup)))
        return false;
  
      if(info != null)
        __parseGroupReply(getReplyString(), info);
  
      return true;
    }
  
    /*** Same as <code> selectNewsgroup(newsgroup, null) </code> ***/
    public boolean selectNewsgroup(String newsgroup) throws IOException {
      return selectNewsgroup(newsgroup, null);
    }
  
    /***
     * List the command help from the server.
     * <p>
     * @return The sever help information.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public String listHelp() throws IOException {
      StringWriter help;
      Reader reader;
  
      if(!NNTPReply.isInformational(help()))
        return null;
  
      help = new StringWriter();
      reader = new DotTerminatedMessageReader(_reader);
      Util.copyReader(reader, help);
      reader.close();
      help.close();
      return help.toString();
    }
  
  
    /***
     * 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.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public boolean selectArticle(String articleId, ArticlePointer pointer)
         throws IOException
    {
      if(articleId != null) {
        if(!NNTPReply.isPositiveCompletion(stat(articleId)))
  	return false;
      } else {
        if(!NNTPReply.isPositiveCompletion(stat()))
  	return false;
      }
  
      if(pointer != null)
        __parseArticlePointer(getReplyString(), pointer);
  
      return true;
    }
  
    /**** Same as <code> selectArticle(articleId, null) </code> ***/
    public boolean selectArticle(String articleId) throws IOException {
      return selectArticle(articleId, null);
    }
  
    /****
     * Same as <code> selectArticle(null, articleId) </code>.  Useful
     * for retrieving the current article number.
     ***/
    public boolean selectArticle(ArticlePointer pointer) throws IOException {
      return selectArticle(null, pointer);
    }
  
  
    /***
     * Select an article in the currently selected newsgroup by its number.
     * and return its article number and id through the
     * pointer parameter.  This is achieved through the STAT command.
     * According to RFC 977, this WILL set the current article pointer
     * on the server.  Use this command to select an article before retrieving
     * it, or to obtain an article's unique identifier given its number.
     * <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.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public boolean selectArticle(int articleNumber, ArticlePointer pointer)
         throws IOException
    {
      if(!NNTPReply.isPositiveCompletion(stat(articleNumber)))
        return false;
  
      if(pointer != null)
        __parseArticlePointer(getReplyString(), pointer);
  
      return true;
    }
  
  
    /*** Same as <code> selectArticle(articleNumber, null) </code> ***/
    public boolean selectArticle(int articleNumber) throws IOException {
      return selectArticle(articleNumber, null);
    }
  
  
    /***
     * Select the article preceeding the currently selected article in the
     * currently selected newsgroup and return its number and unique id
     * through the pointer parameter.  Because of deviating server
     * implementations, the articleId information cannot be trusted.  To
     * obtain the article identifier, issue a
     * <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).
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public boolean selectPreviousArticle(ArticlePointer pointer)
         throws IOException
    {
      if(!NNTPReply.isPositiveCompletion(last()))
        return false;
  
      if(pointer != null)
        __parseArticlePointer(getReplyString(), pointer);
  
      return true;
    }
  
    /*** Same as <code> selectPreviousArticle(null) </code> ***/
    public boolean selectPreviousArticle() throws IOException {
      return selectPreviousArticle(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).
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public boolean selectNextArticle(ArticlePointer pointer) throws IOException {
      if(!NNTPReply.isPositiveCompletion(next()))
        return false;
  
      if(pointer != null)
        __parseArticlePointer(getReplyString(), pointer);
  
      return true;
    }
  
  
    /*** Same as <code> selectNextArticle(null) </code> ***/
    public boolean selectNextArticle() throws IOException {
      return selectNextArticle(null);
    }
  
  
    /***
     * List all newsgroups served by the NNTP server.  If no newsgroups
     * are served, a zero length array will be returned.  If the command
     * fails, null will be returned.
     * <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.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public NewsgroupInfo[] listNewsgroups() throws IOException {
      if(!NNTPReply.isPositiveCompletion(list()))
        return null;
  
      return __readNewsgroupListing();
    }
  
  
    /***
     * List all new newsgroups added to the NNTP server since a particular
     * date subject to the conditions of the specified query.  If no new
     * newsgroups were added, a zero length array will be returned.  If the 
     * command fails, null will be returned.
     * <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.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public NewsgroupInfo[] listNewNewsgroups(NewGroupsOrNewsQuery query)
         throws IOException
    {
      if(!NNTPReply.isPositiveCompletion(newgroups(
  				 query.getDate(), query.getTime(),
  				 query.isGMT(), query.getDistributions())))
        return null;
  
      return __readNewsgroupListing();
    }
  
  
    /***
     * List all new 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.
     * <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.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public String[] listNewNews(NewGroupsOrNewsQuery query)
         throws IOException
    {
      int size;
      String line;
      Vector list;
      String[] result;
      BufferedReader reader;
  
      if(!NNTPReply.isPositiveCompletion(newnews(
  		query.getNewsgroups(), query.getDate(), query.getTime(),
  		query.isGMT(), query.getDistributions())))
        return null;
  
      list = new Vector();
      reader = new BufferedReader(new DotTerminatedMessageReader(_reader));
  
      while((line = reader.readLine()) != null)
        list.addElement(line);
  
      size = list.size();
  
      if(size < 1)
        return new String[0];
  
      result = new String[size];
      list.copyInto(result);
  
      return result;
    }
  
    /***
     * 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.
     * @exception NNTPConnectionClosedException
     *      If the NNTP server prematurely closes the connection as a result
     *      of the client being idle or some other reason causing the server
     *      to send NNTP reply code 400.  This exception may be caught either
     *      as an IOException or independently as itself.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public boolean completePendingCommand() throws IOException {
      return NNTPReply.isPositiveCompletion(getReply());
    }
  
    /***
     * Post an article to the NNTP server.  This method returns a
     * DotTerminatedMessageWriter instance to which the article can be
     * written.  Null is returned if the posting attempt fails.  You
     * should check <a href="org.apache.commons.nntp.NNTP.html#isAllowedToPost">
     * isAllowedToPost() </a> 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
     * <a href="org.apache.commons.net.nntp.SimpleNNTPHeader.html"> SimpleNNTPHeader </a>
     * 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
     * <a href="#completePendingCommand"> completePendingCommand() </a>
     * 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.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public Writer postArticle() throws IOException {
      if(!NNTPReply.isPositiveIntermediate(post()))
        return null;
  
      return new DotTerminatedMessageWriter(_writer);
    }
  
  
    public Writer forwardArticle(String articleId) throws IOException {
      if(!NNTPReply.isPositiveIntermediate(ihave(articleId)))
        return null;
  
      return new DotTerminatedMessageWriter(_writer);
    }
  
  
    /***
     * Logs out of the news server gracefully by sending the QUIT command.
     * However, you must still disconnect from the server before you can open
     * a new connection.
     * <p>
     * @return True if successfully completed, false if not.
     * @exception IOException  If an I/O error occurs while either sending a
     *      command to the server or receiving a reply from the server.
     ***/
    public boolean logout() throws IOException {
      return NNTPReply.isPositiveCompletion(quit());
    }
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/net/src/java/org/apache/commons/net/nntp/NNTPCommand.java
  
  Index: NNTPCommand.java
  ===================================================================
  package org.apache.commons.net.nntp;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.net.*;
  import java.io.*;
  
  /***
   * NNTPCommand stores a set of constants for NNTP command codes.  To interpret
   * the meaning of the codes, familiarity with RFC 977 is assumed.
   * <p>
   * <p>
   * @author Daniel F. Savarese
   ***/
  
  public final class NNTPCommand {
  
    public static final int ARTICLE   = 0;
    public static final int BODY      = 1;
    public static final int GROUP     = 2;
    public static final int HEAD      = 3;
    public static final int HELP      = 4;
    public static final int IHAVE     = 5;
    public static final int LAST      = 6;
    public static final int LIST      = 7;
    public static final int NEWGROUPS = 8;
    public static final int NEWNEWS   = 9;
    public static final int NEXT      = 10;
    public static final int POST      = 11;
    public static final int QUIT      = 12;
    public static final int SLAVE     = 13;
    public static final int STAT      = 14;
  
  
    // Cannot be instantiated
    private NNTPCommand() {}
  
    static final String[] _commands =  {
      "ARTICLE", "BODY", "GROUP", "HEAD", "HELP", "IHAVE", "LAST", "LIST",
      "NEWGROUPS", "NEWNEWS", "NEXT", "POST", "QUIT", "SLAVE", "STAT"
    };
  
  
    /***
     * Retrieve the NNTP protocol command string corresponding to a specified
     * command code.
     * <p>
     * @param The command code.
     * @return The NNTP protcol command string corresponding to a specified
     *         command code.
     ***/
    public static final String getCommand(int command) {
      return _commands[command];
    }
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/net/src/java/org/apache/commons/net/nntp/NNTPConnectionClosedException.java
  
  Index: NNTPConnectionClosedException.java
  ===================================================================
  package org.apache.commons.net.nntp;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.io.*;
  
  /***
   * NNTPConnectionClosedException is used to indicate the premature or
   * unexpected closing of an NNTP connection resulting from a 
   * <a href="org.apache.commons.net.nntp.NNTPReply.html#SERVICE_DISCONTINUED">
   * NNTPReply.SERVICE_DISCONTINUED </a> response (NNTP reply code 400) to a
   * failed NNTP command.  This exception is derived from IOException and
   * therefore may be caught either as an IOException or specifically as an
   * NNTPConnectionClosedException.
   * <p>
   * <p>
   * @author Daniel F. Savarese
   * @see NNTP
   * @see NNTPClient
   ***/
  
  public final class NNTPConnectionClosedException extends IOException {
  
    /*** Constructs a NNTPConnectionClosedException with no message ***/
    public NNTPConnectionClosedException() {
      super();
    }
  
    /*** 
     * Constructs a NNTPConnectionClosedException with a specified message.
     * <p>
     * @param message  The message explaining the reason for the exception.
     ***/
    public NNTPConnectionClosedException(String message) {
      super(message);
    }
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/net/src/java/org/apache/commons/net/nntp/NNTPReply.java
  
  Index: NNTPReply.java
  ===================================================================
  package org.apache.commons.net.nntp;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.net.*;
  import java.io.*;
  
  /***
   * NNTPReply stores a set of constants for NNTP reply codes.  To interpret
   * the meaning of the codes, familiarity with RFC 977 is assumed.
   * The mnemonic constant names are transcriptions from the code descriptions
   * of RFC 977.  For those who think in terms of the actual reply code values,
   * a set of CODE_NUM constants are provided where NUM is the numerical value
   * of the code.
   * <p>
   * <p>
   * @author Daniel F. Savarese
   ***/
  
  public final class NNTPReply {
  
    public static final int CODE_100 = 100;
    public static final int CODE_199 = 199;
    public static final int CODE_200 = 200;
    public static final int CODE_201 = 201;
    public static final int CODE_202 = 202;
    public static final int CODE_205 = 205;
    public static final int CODE_211 = 211;
    public static final int CODE_215 = 215;
    public static final int CODE_220 = 220;
    public static final int CODE_221 = 221;
    public static final int CODE_222 = 222;
    public static final int CODE_223 = 223;
    public static final int CODE_230 = 230;
    public static final int CODE_231 = 231;
    public static final int CODE_235 = 235;
    public static final int CODE_240 = 240;
    public static final int CODE_335 = 335;
    public static final int CODE_340 = 340;
    public static final int CODE_400 = 400;
    public static final int CODE_411 = 411;
    public static final int CODE_412 = 412;
    public static final int CODE_420 = 420;
    public static final int CODE_421 = 421;
    public static final int CODE_422 = 422;
    public static final int CODE_423 = 423;
    public static final int CODE_430 = 430;
    public static final int CODE_435 = 435;
    public static final int CODE_436 = 436;
    public static final int CODE_437 = 437;
    public static final int CODE_440 = 440;
    public static final int CODE_441 = 441;
    public static final int CODE_500 = 500;
    public static final int CODE_501 = 501;
    public static final int CODE_502 = 502;
    public static final int CODE_503 = 503;
  
    public static final int HELP_TEXT_FOLLOWS                  = CODE_100;
    public static final int DEBUG_OUTPUT                       = CODE_199;
    public static final int SERVER_READY_POSTING_ALLOWED       = CODE_200;
    public static final int SERVER_READY_POSTING_NOT_ALLOWED   = CODE_201;
    public static final int SLAVE_STATUS_NOTED                 = CODE_202;
    public static final int CLOSING_CONNECTION                 = CODE_205;
    public static final int GROUP_SELECTED                     = CODE_211;
    public static final int ARTICLE_RETRIEVED_HEAD_AND_BODY_FOLLOW = CODE_220;
    public static final int ARTICLE_RETRIEVED_HEAD_FOLLOWS     = CODE_221;
    public static final int ARTICLE_RETRIEVED_BODY_FOLLOWS     = CODE_222;
    public static final int ARTICLE_RETRIEVED_REQUEST_TEXT_SEPARATELY = CODE_223;
    public static final int ARTICLE_LIST_BY_MESSAGE_ID_FOLLOWS = CODE_230;
    public static final int NEW_NEWSGROUP_LIST_FOLLOWS         = CODE_231;
    public static final int ARTICLE_TRANSFERRED_OK             = CODE_235;
    public static final int ARTICLE_POSTED_OK                  = CODE_240;
    public static final int SEND_ARTICLE_TO_TRANSFER           = CODE_335;
    public static final int SEND_ARTICLE_TO_POST               = CODE_340;
    public static final int SERVICE_DISCONTINUED               = CODE_400;
    public static final int NO_SUCH_NEWSGROUP                  = CODE_411;
    public static final int NO_NEWSGROUP_SELECTED              = CODE_412;
    public static final int NO_CURRENT_ARTICLE_SELECTED        = CODE_420;
    public static final int NO_NEXT_ARTICLE                    = CODE_421;
    public static final int NO_PREVIOUS_ARTICLE                = CODE_422;
    public static final int NO_SUCH_ARTICLE_NUMBER             = CODE_423;       
    public static final int NO_SUCH_ARTICLE_FOUND              = CODE_430;
    public static final int ARTICLE_NOT_WANTED                 = CODE_435;
    public static final int TRANSFER_FAILED                    = CODE_436;
    public static final int ARTICLE_REJECTED                   = CODE_437;
    public static final int POSTING_NOT_ALLOWED                = CODE_440;
    public static final int POSTING_FAILED                     = CODE_441;
    public static final int COMMAND_NOT_RECOGNIZED             = CODE_500;
    public static final int COMMAND_SYNTAX_ERROR               = CODE_501;
    public static final int PERMISSION_DENIED                  = CODE_502;
    public static final int PROGRAM_FAULT                      = CODE_503;
  
    // Cannot be instantiated
  
    private NNTPReply() {}
  
    /***
     * Determine if a reply code is an informational response.  All
     * codes beginning with a 1 are positive informational responses.
     * Informational responses are used to provide human readable
     * information such as help text.
     * <p>
     * @param reply  The reply code to test.
     * @return True if a reply code is an informational response, false
     *         if not.
     ***/
    public static boolean isInformational(int reply) {
      return (reply >= 100 && reply < 200);
    }
  
    /***
     * Determine if a reply code is a positive completion response.  All
     * codes beginning with a 2 are positive completion responses.
     * The NNTP server will send a positive completion response on the final
     * successful completion of a command.
     * <p>
     * @param reply  The reply code to test.
     * @return True if a reply code is a postive completion response, false
     *         if not.
     ***/
    public static boolean isPositiveCompletion(int reply) {
      return (reply >= 200 && reply < 300);
    }
  
    /***
     * Determine if a reply code is a positive intermediate response.  All
     * codes beginning with a 3 are positive intermediate responses.
     * The NNTP server will send a positive intermediate response on the
     * successful completion of one part of a multi-part command or
     * sequence of commands.  For example, after a successful POST command,
     * a positive intermediate response will be sent to indicate that the
     * server is ready to receive the article to be posted.
     * <p>
     * @param reply  The reply code to test.
     * @return True if a reply code is a postive intermediate response, false
     *         if not.
     ***/
    public static boolean isPositiveIntermediate(int reply) {
      return (reply >= 300 && reply < 400);
    }
  
    /***
     * Determine if a reply code is a negative transient response.  All
     * codes beginning with a 4 are negative transient responses.
     * The NNTP server will send a negative transient response on the
     * failure of a correctly formatted command that could not be performed
     * for some reason.  For example, retrieving an article that does not
     * exist will result in a negative transient response.
     * <p>
     * @param reply  The reply code to test.
     * @return True if a reply code is a negative transient response, false
     *         if not.
     ***/
    public static boolean isNegativeTransient(int reply) {
      return (reply >= 400 && reply < 500);
    }
  
    /***
     * Determine if a reply code is a negative permanent response.  All
     * codes beginning with a 5 are negative permanent responses.
     * The NNTP server will send a negative permanent response when
     * it does not implement a command, a command is incorrectly formatted,
     * or a serious program error occurs.
     * <p>
     * @param reply  The reply code to test.
     * @return True if a reply code is a negative permanent response, false
     *         if not.
     ***/
    public static boolean isNegativePermanent(int reply) {
      return (reply >= 500 && reply < 600);
    }
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/net/src/java/org/apache/commons/net/nntp/NewGroupsOrNewsQuery.java
  
  Index: NewGroupsOrNewsQuery.java
  ===================================================================
  package org.apache.commons.net.nntp;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.util.*;
  
  /***
   * The NewGroupsOrNewsQuery class is used to issue NNTP NEWGROUPS and
   * NEWNEWS queries, implemented by
   * <a href="org.apache.commons.net.nntp.NNTPClient.html#listNewNewsgroups">
   * listNewNewsGroups </a> and
   * <a href="org.apache.commons.net.nntp.NNTPClient.html#listNewNews">
   * listNewNews </a> respectively.  It prevents you from having to format
   * date, time, distribution, and newgroup arguments.
   * <p>
   * You might use the class as follows:
   * <pre>
   * query = new NewsGroupsOrNewsQuery(new GregorianCalendar(97, 11, 15), false);
   * query.addDistribution("comp");
   * NewsgroupInfo[] newsgroups = client.listNewgroups(query);
   * </pre>
   * This will retrieve the list of newsgroups starting with the comp.
   * distribution prefix created since midnight 11/15/97.
   * <p>
   * <p>
   * @author Daniel F. Savarese
   * @see NNTPClient
   ***/
  
  public final class NewGroupsOrNewsQuery {
    private String __date, __time;
    private StringBuffer __distributions;
    private StringBuffer __newsgroups;
    private boolean __isGMT;
  
  
    /***
     * Creates a new query using the given time as a reference point.
     * <p>
     * @param date  The date since which new groups or news have arrived.
     * @param gmt   True if the date should be considered as GMT, false if not.
     ***/
    public NewGroupsOrNewsQuery(Calendar date, boolean gmt) {
      int num;
      String str;
      StringBuffer buffer;
  
      __distributions = null;
      __newsgroups    = null;
      __isGMT = gmt;
  
      buffer = new StringBuffer();
  
      // Get year
      num    = date.get(Calendar.YEAR);
      str    = Integer.toString(num);
      num    = str.length();
  
      if(num >= 2)
        buffer.append(str.substring(num - 2));
      else
        buffer.append("00");
  
      // Get month
      num    = date.get(Calendar.MONTH) + 1;
      str    = Integer.toString(num);
      num    = str.length();
  
      if(num == 1) {
        buffer.append('0');
        buffer.append(str);
      } else if(num == 2)
        buffer.append(str);
      else
        buffer.append("01");
  
      // Get day
      num    = date.get(Calendar.DAY_OF_MONTH);
      str    = Integer.toString(num);
      num    = str.length();
  
      if(num == 1) {
        buffer.append('0');
        buffer.append(str);
      } else if(num == 2)
        buffer.append(str);
      else
        buffer.append("01");
  
      __date = buffer.toString();
  
      buffer.setLength(0);
  
      // Get hour
      num    = date.get(Calendar.HOUR_OF_DAY);
      str    = Integer.toString(num);
      num    = str.length();
  
      if(num == 1) {
        buffer.append('0');
        buffer.append(str);
      } else if(num == 2)
        buffer.append(str);
      else
        buffer.append("00");
  
      // Get minutes
      num    = date.get(Calendar.MINUTE);
      str    = Integer.toString(num);
      num    = str.length();
  
      if(num == 1) {
        buffer.append('0');
        buffer.append(str);
      } else if(num == 2)
        buffer.append(str);
      else
        buffer.append("00");
  
  
      // Get seconds
      num    = date.get(Calendar.SECOND);
      str    = Integer.toString(num);
      num    = str.length();
  
      if(num == 1) {
        buffer.append('0');
        buffer.append(str);
      } else if(num == 2)
        buffer.append(str);
      else
        buffer.append("00");
  
      __time = buffer.toString();
    }
  
  
    /***
     * Add a newsgroup to the list of newsgroups being queried.  Newsgroups
     * added this way are only meaningful to the NEWNEWS command.  Newsgroup
     * names may include the <code> * </code> wildcard, as in
     * <code>comp.lang.* </code> or <code> comp.lang.java.* </code>.  Adding
     * at least one newsgroup is mandatory for the NEWNEWS command.
     * <p>
     * @param newsgroup  The newsgroup to add to the list of groups to be
     *                   checked for new news.
     ***/
    public void addNewsgroup(String newsgroup) {
      if(__newsgroups != null)
        __newsgroups.append(',');
      else
        __newsgroups = new StringBuffer();
      __newsgroups.append(newsgroup);
    }
  
  
    /***
     * Add a newsgroup to the list of newsgroups being queried, but indicate
     * that group should not be checked for new news.  Newsgroups
     * added this way are only meaningful to the NEWNEWS command.
     * Newsgroup names may include the <code> * </code> wildcard, as in
     * <code>comp.lang.* </code> or <code> comp.lang.java.* </code>.
     * <p>
     * The following would create a query that searched for new news in
     * all comp.lang.java newsgroups except for comp.lang.java.advocacy.
     * <pre>
     * query.addNewsgroup("comp.lang.java.*");
     * query.omitNewsgroup("comp.lang.java.advocacy");
     * </pre>
     * <p>
     * @param newsgroup  The newsgroup to add to the list of groups to be
     *                   checked for new news, but which should be omitted from
     *                   the search for new news..
     ***/
    public void omitNewsgroup(String newsgroup) {
      addNewsgroup("!" + newsgroup);
    }
  
  
    /***
     * Add a distribution group to the query.  The distribution part of a
     * newsgroup is the segment of the name preceding the first dot (e.g.,
     * comp, alt, rec).  Only those newsgroups matching one of the
     * distributions or, in the case of NEWNEWS, an article in a newsgroup
     * matching one of the distributions, will be reported as a query result.
     * Adding distributions is purely optional.
     * <p>
     * @param distribution A distribution to add to the query.
     ***/
    public void addDistribution(String distribution) {
      if(__distributions != null)
        __distributions.append(',');
      else
        __distributions = new StringBuffer();
      __distributions.append(distribution);
    }
  
    /***
     * Return the NNTP query formatted date (year, month, day in the form
     * YYMMDD.
     * <p>
     * @return The NNTP query formatted date.
     ***/
    public String getDate() { return __date; }
  
    /***
     * Return the NNTP query formatted time (hour, minutes, seconds in the form
     * HHMMSS.
     * <p>
     * @return The NNTP query formatted time.
     ***/
    public String getTime() { return __time; }
  
    /***
     * Return whether or not the query date should be treated as GMT.
     * <p>
     * @return True if the query date is to be treated as GMT, false if not.
     ***/
    public boolean isGMT()  { return __isGMT; }
  
    /***
     * Return the comma separated list of distributions.  This may be null
     * if there are no distributions.
     * <p>
     * @return The list of distributions, which may be null if no distributions
     *         have been specified.
     ***/
    public String getDistributions() {
      return (__distributions == null ? null : __distributions.toString());
    }
  
    /***
     * Return the comma separated list of newsgroups.  This may be null
     * if there are no newsgroups
     * <p>
     * @return The list of newsgroups, which may be null if no newsgroups
     *         have been specified.
     ***/
    public String getNewsgroups() {
      return (__newsgroups == null ? null : __newsgroups.toString());
    }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/net/src/java/org/apache/commons/net/nntp/NewsgroupInfo.java
  
  Index: NewsgroupInfo.java
  ===================================================================
  package org.apache.commons.net.nntp;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  /***
   * NewsgroupInfo stores information pertaining to a newsgroup returned by
   * the NNTP GROUP, LIST, and NEWGROUPS commands, implemented by
   * <a href="org.apache.commons.net.nntp.NNTPClient.html#selectNewsgroup">
   * selectNewsgroup </a>,
   * <a href="org.apache.commons.net.nntp.NNTPClient.html#listNewsgroups">
   * listNewsgroups </a>, and
   * <a href="org.apache.commons.net.nntp.NNTPClient.html#listNewNewsgroups">
   * listNewNewsgroups </a> respectively.
   * <p>
   * <p>
   * @author Daniel F. Savarese
   * @see NNTPClient
   ***/
  
  public final class NewsgroupInfo {
    /***
     * A constant indicating that the posting permission of a newsgroup is
     * unknown.  For example, the NNTP GROUP command does not return posting
     * information, so NewsgroupInfo instances obtained from that command
     * willhave an UNKNOWN_POSTING_PERMISSION.
     ***/
    public static final int UNKNOWN_POSTING_PERMISSION    = 0;
  
    /*** A constant indicating that a newsgroup is moderated. ***/
    public static final int MODERATED_POSTING_PERMISSION  = 1;
  
    /*** A constant indicating that a newsgroup is public and unmoderated. ***/
    public static final int PERMITTED_POSTING_PERMISSION  = 2;
  
    /*** 
     * A constant indicating that a newsgroup is closed for general posting.
     ***/
    public static final int PROHIBITED_POSTING_PERMISSION = 3;
  
    private String __newsgroup;
    private int __estimatedArticleCount;
    private int __firstArticle, __lastArticle;
    private int __postingPermission;
  
    void _setNewsgroup(String newsgroup) { __newsgroup = newsgroup; }
  
    void _setArticleCount(int count) { __estimatedArticleCount = count; }
  
    void _setFirstArticle(int first) { __firstArticle = first; }
  
    void _setLastArticle(int last) { __lastArticle = last; }
  
    void _setPostingPermission(int permission) {
      __postingPermission = permission;
    }
  
    /*** 
     * Get the newsgroup name.
     * <p>
     * @return The name of the newsgroup.
     ***/
    public String getNewsgroup() { return __newsgroup; }
  
    /*** 
     * Get the estimated number of articles in the newsgroup.  The
     * accuracy of this value will depend on the server implementation.
     * <p>
     * @return The estimated number of articles in the newsgroup.
     ***/
    public int getArticleCount() { return __estimatedArticleCount; }
  
    /*** 
     * Get the number of the first article in the newsgroup.
     * <p>
     * @return The number of the first article in the newsgroup.
     ***/
    public int getFirstArticle() { return __firstArticle; }
  
    /*** 
     * Get the number of the last article in the newsgroup.
     * <p>
     * @return The number of the last article in the newsgroup.
     ***/
    public int getLastArticle()  { return __lastArticle; }
  
    /*** 
     * Get the posting permission of the newsgroup.  This will be one of
     * the <code> POSTING_PERMISSION </code> constants.
     * <p>
     * @return The posting permission status of the newsgroup.
     ***/
    public int getPostingPermission() { return __postingPermission; }
  
    /*
    public String toString() {
      StringBuffer buffer = new StringBuffer();
      buffer.append(__newsgroup);
      buffer.append(' ');
      buffer.append(__lastArticle);
      buffer.append(' ');
      buffer.append(__firstArticle);
      buffer.append(' ');
      switch(__postingPermission) {
        case 1: buffer.append('m'); break;
        case 2: buffer.append('y'); break;
        case 3: buffer.append('n'); break;
      }
      return buffer.toString();
    }
    */
  }
  
  
  
  1.1                  jakarta-commons-sandbox/net/src/java/org/apache/commons/net/nntp/SimpleNNTPHeader.java
  
  Index: SimpleNNTPHeader.java
  ===================================================================
  package org.apache.commons.net.nntp;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  /***
   * This class is used 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.
   * <p>
   * The main purpose of the class is to faciliatate the article posting
   * process, by relieving the programmer from having to explicitly format
   * an article header.  For example:
   * <pre>
   * writer = client.postArticle();
   * if(writer == null) // failure
   *   return false;
   * header = new SimpleNNTPHeader("foobar@foo.com", "Just testing"); 
   * header.addNewsgroup("alt.test");
   * header.addHeaderField("Organization", "Foobar, Inc.");
   * writer.write(header.toString());
   * writer.write("This is just a test");
   * writer.close();
   * if(!client.completePendingCommand()) // failure
   *   return false;
   * </pre>
   * <p>
   * <p>
   * @author Daniel F. Savarese
   * @see NNTPClient
   ***/
  
  public class SimpleNNTPHeader {
    private String __subject, __from;
    private StringBuffer __newsgroups;
    private StringBuffer __headerFields;
    private int __newsgroupCount;
  
    /***
     * Creates a new SimpleNNTPHeader instance initialized with the given
     * from and subject header field values.
     * <p>
     * @param from  The value of the <code>From:</code> header field.  This
     *              should be the article poster's email address.
     * @param subject  The value of the <code>Subject:</code> header field. 
     *              This should be the subject of the article.
     ***/
    public SimpleNNTPHeader(String from, String subject) {
      __from       = from;
      __subject    = subject;
      __newsgroups = new StringBuffer();
      __headerFields = new StringBuffer();
      __newsgroupCount = 0;
    }
  
    /***
     * Adds a newsgroup to the article <code>Newsgroups:</code> field.
     * <p>
     * @param newsgroup  The newsgroup to add to the article's newsgroup
     *                   distribution list.
     ***/
    public void addNewsgroup(String newsgroup) {
      if(__newsgroupCount++ > 0)
        __newsgroups.append(',');
      __newsgroups.append(newsgroup);
    }
  
    /***
     * Adds an arbitrary header field with the given value to the article
     * header.  These headers will be written after the From, Newsgroups,
     * and Subject fields when the SimpleNNTPHeader is convertered to a string.
     * An example use would be:
     * <pre>
     * header.addHeaderField("Organization", "Foobar, Inc.");
     * </pre>
     * <p>
     * @param headerField  The header field to add, not including the colon.
     * @param value  The value of the added header field.
     ***/
    public void addHeaderField(String headerField, String value) {
      __headerFields.append(headerField);
      __headerFields.append(": ");
      __headerFields.append(value);
      __headerFields.append('\n');
    }
  
  
    /***
     * Returns the address used in the <code> From: </code> header field.
     * <p>
     * @return The from address.
     ***/
    public String getFromAddress() { return __from; }
  
    /***
     * Returns the subject used in the <code> Subject: </code> header field.
     * <p>
     * @return The subject.
     ***/
    public String getSubject()     { return __subject; }
  
    /***
     * Returns the contents of the <code> Newsgroups: </code> header field.
     * <p>
     * @return The comma-separated list of newsgroups to which the article
     *         is being posted.
     ***/
    public String getNewsgroups()  { return __newsgroups.toString(); }
  
    /***
     * Converts the SimpleNNTPHeader to a properly formatted header in
     * the form of a String, including the blank line used to separate
     * the header from the article body.
     * <p>
     * @return The article header in the form of a String.
     ***/
    public String toString() {
      StringBuffer header = new StringBuffer();
  
      header.append("From: ");
      header.append(__from);
      header.append("\nNewsgroups: ");
      header.append(__newsgroups.toString());
      header.append("\nSubject: ");
      header.append(__subject);
      header.append('\n');
      if(__headerFields.length() > 0)
        header.append(__headerFields.toString());
      header.append('\n');
  
      return header.toString();
    }
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>