001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.net.nntp;
019
020import java.io.BufferedReader;
021import java.io.BufferedWriter;
022import java.io.IOException;
023import java.io.InputStreamReader;
024import java.io.OutputStreamWriter;
025
026import org.apache.commons.net.MalformedServerReplyException;
027import org.apache.commons.net.ProtocolCommandListener;
028import org.apache.commons.net.ProtocolCommandSupport;
029import org.apache.commons.net.SocketClient;
030
031/***
032 * The NNTP class is not meant to be used by itself and is provided
033 * only so that you may easily implement your own NNTP client if
034 * you so desire.  If you have no need to perform your own implementation,
035 * you should use {@link org.apache.commons.net.nntp.NNTPClient}.
036 * The NNTP class is made public to provide access to various NNTP constants
037 * and to make it easier for adventurous programmers (or those with special
038 * needs) to interact with the NNTP protocol and implement their own clients.
039 * A set of methods with names corresponding to the NNTP command names are
040 * provided to facilitate this interaction.
041 * <p>
042 * You should keep in mind that the NNTP server may choose to prematurely
043 * close a connection if the client has been idle for longer than a
044 * given time period or if the server is being shutdown by the operator or
045 * some other reason.  The NNTP class will detect a
046 * premature NNTP server connection closing when it receives a
047 * {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED }
048 *  response to a command.
049 * When that occurs, the NNTP class method encountering that reply will throw
050 * an {@link org.apache.commons.net.nntp.NNTPConnectionClosedException}
051 * .
052 * <code>NNTPConectionClosedException</code>
053 * is a subclass of <code> IOException </code> and therefore need not be
054 * caught separately, but if you are going to catch it separately, its
055 * catch block must appear before the more general <code> IOException </code>
056 * catch block.  When you encounter an
057 * {@link org.apache.commons.net.nntp.NNTPConnectionClosedException}
058 * , you must disconnect the connection with
059 * {@link #disconnect  disconnect() } to properly clean up the
060 * system resources used by NNTP.  Before disconnecting, you may check the
061 * last reply code and text with
062 * {@link #getReplyCode  getReplyCode } and
063 * {@link #getReplyString  getReplyString }.
064 * <p>
065 * Rather than list it separately for each method, we mention here that
066 * every method communicating with the server and throwing an IOException
067 * can also throw a
068 * {@link org.apache.commons.net.MalformedServerReplyException}
069 * , which is a subclass
070 * of IOException.  A MalformedServerReplyException will be thrown when
071 * the reply received from the server deviates enough from the protocol
072 * specification that it cannot be interpreted in a useful manner despite
073 * attempts to be as lenient as possible.
074 * <p>
075 * <p>
076 * @author Daniel F. Savarese
077 * @author Rory Winston
078 * @author Ted Wise
079 * @see NNTPClient
080 * @see NNTPConnectionClosedException
081 * @see org.apache.commons.net.MalformedServerReplyException
082 ***/
083
084public class NNTP extends SocketClient
085{
086    /*** The default NNTP port.  Its value is 119 according to RFC 977. ***/
087    public static final int DEFAULT_PORT = 119;
088
089    // We have to ensure that the protocol communication is in ASCII
090    // but we use ISO-8859-1 just in case 8-bit characters cross
091    // the wire.
092    private static final String __DEFAULT_ENCODING = "ISO-8859-1";
093
094    private StringBuffer __commandBuffer;
095
096    boolean _isAllowedToPost;
097    int _replyCode;
098    String _replyString;
099
100    /**
101     * Wraps {@link SocketClient#_input_}
102     * to communicate with server.  Initialized by {@link #_connectAction_}.
103     * All server reads should be done through this variable.
104     */
105    protected BufferedReader _reader_;
106
107    /**
108     * Wraps {@link SocketClient#_output_}
109     * to communicate with server.  Initialized by {@link #_connectAction_}.
110     * All server reads should be done through this variable.
111     */
112    protected BufferedWriter _writer_;
113
114    /***
115     * A ProtocolCommandSupport object used to manage the registering of
116     * ProtocolCommandListeners and te firing of ProtocolCommandEvents.
117     ***/
118    protected ProtocolCommandSupport _commandSupport_;
119
120    /***
121     * The default NNTP constructor.  Sets the default port to
122     * <code>DEFAULT_PORT</code> and initializes internal data structures
123     * for saving NNTP reply information.
124     ***/
125    public NNTP()
126    {
127        setDefaultPort(DEFAULT_PORT);
128        __commandBuffer = new StringBuffer();
129        _replyString = null;
130        _reader_ = null;
131        _writer_ = null;
132        _isAllowedToPost = false;
133        _commandSupport_ = new ProtocolCommandSupport(this);
134    }
135
136    private void __getReply() throws IOException
137    {
138        _replyString = _reader_.readLine();
139
140        if (_replyString == null)
141            throw new NNTPConnectionClosedException(
142                "Connection closed without indication.");
143
144        // In case we run into an anomaly we don't want fatal index exceptions
145        // to be thrown.
146        if (_replyString.length() < 3)
147            throw new MalformedServerReplyException(
148                "Truncated server reply: " + _replyString);
149        try
150        {
151            _replyCode = Integer.parseInt(_replyString.substring(0, 3));
152        }
153        catch (NumberFormatException e)
154        {
155            throw new MalformedServerReplyException(
156                "Could not parse response code.\nServer Reply: " + _replyString);
157        }
158
159        if (_commandSupport_.getListenerCount() > 0)
160            _commandSupport_.fireReplyReceived(_replyCode, _replyString +
161                                               SocketClient.NETASCII_EOL);
162
163        if (_replyCode == NNTPReply.SERVICE_DISCONTINUED)
164            throw new NNTPConnectionClosedException(
165                "NNTP response 400 received.  Server closed connection.");
166    }
167
168    /***
169     * Initiates control connections and gets initial reply, determining
170     * if the client is allowed to post to the server.  Initializes
171     * {@link #_reader_} and {@link #_writer_} to wrap
172     * {@link SocketClient#_input_} and {@link SocketClient#_output_}.
173     ***/
174    @Override
175    protected void _connectAction_() throws IOException
176    {
177        super._connectAction_();
178        _reader_ =
179            new BufferedReader(new InputStreamReader(_input_,
180                                                     __DEFAULT_ENCODING));
181        _writer_ =
182            new BufferedWriter(new OutputStreamWriter(_output_,
183                                                      __DEFAULT_ENCODING));
184        __getReply();
185
186        _isAllowedToPost = (_replyCode == NNTPReply.SERVER_READY_POSTING_ALLOWED);
187    }
188
189    /***
190     * Adds a ProtocolCommandListener.  Delegates this task to
191     * {@link #_commandSupport_  _commandSupport_ }.
192     * <p>
193     * @param listener  The ProtocolCommandListener to add.
194     ***/
195    public void addProtocolCommandListener(ProtocolCommandListener listener)
196    {
197        _commandSupport_.addProtocolCommandListener(listener);
198    }
199
200    /***
201     * Removes a ProtocolCommandListener.  Delegates this task to
202     * {@link #_commandSupport_  _commandSupport_ }.
203     * <p>
204     * @param listener  The ProtocolCommandListener to remove.
205     ***/
206    public void removeProtocolCommandListener(ProtocolCommandListener listener)
207    {
208        _commandSupport_.removeProtocolCommandListener(listener);
209    }
210
211    /***
212     * Closes the connection to the NNTP server and sets to null
213     * some internal data so that the memory may be reclaimed by the
214     * garbage collector.  The reply text and code information from the
215     * last command is voided so that the memory it used may be reclaimed.
216     * <p>
217     * @exception IOException If an error occurs while disconnecting.
218     ***/
219    @Override
220    public void disconnect() throws IOException
221    {
222        super.disconnect();
223        _reader_ = null;
224        _writer_ = null;
225        _replyString = null;
226        _isAllowedToPost = false;
227    }
228
229
230    /***
231     * Indicates whether or not the client is allowed to post articles to
232     * the server it is currently connected to.
233     * <p>
234     * @return True if the client can post articles to the server, false
235     *         otherwise.
236     ***/
237    public boolean isAllowedToPost()
238    {
239        return _isAllowedToPost;
240    }
241
242
243    /***
244     * Sends an NNTP command to the server, waits for a reply and returns the
245     * numerical response code.  After invocation, for more detailed
246     * information, the actual reply text can be accessed by calling
247     * {@link #getReplyString  getReplyString }.
248     * <p>
249     * @param command  The text representation of the  NNTP command to send.
250     * @param args The arguments to the NNTP command.  If this parameter is
251     *             set to null, then the command is sent with no argument.
252     * @return The integer value of the NNTP reply code returned by the server
253     *         in response to the command.
254     * @exception NNTPConnectionClosedException
255     *      If the NNTP server prematurely closes the connection as a result
256     *      of the client being idle or some other reason causing the server
257     *      to send NNTP reply code 400.  This exception may be caught either
258     *      as an IOException or independently as itself.
259     * @exception IOException  If an I/O error occurs while either sending the
260     *      command or receiving the server reply.
261     ***/
262    public int sendCommand(String command, String args) throws IOException
263    {
264        String message;
265
266        __commandBuffer.setLength(0);
267        __commandBuffer.append(command);
268
269        if (args != null)
270        {
271            __commandBuffer.append(' ');
272            __commandBuffer.append(args);
273        }
274        __commandBuffer.append(SocketClient.NETASCII_EOL);
275
276        _writer_.write(message = __commandBuffer.toString());
277        _writer_.flush();
278
279        if (_commandSupport_.getListenerCount() > 0)
280            _commandSupport_.fireCommandSent(command, message);
281
282        __getReply();
283        return _replyCode;
284    }
285
286
287    /***
288     * Sends an NNTP command to the server, waits for a reply and returns the
289     * numerical response code.  After invocation, for more detailed
290     * information, the actual reply text can be accessed by calling
291     * {@link #getReplyString  getReplyString }.
292     * <p>
293     * @param command  The NNTPCommand constant corresponding to the NNTP command
294     *                 to send.
295     * @param args The arguments to the NNTP command.  If this parameter is
296     *             set to null, then the command is sent with no argument.
297     * @return The integer value of the NNTP reply code returned by the server
298     *         in response to the command.
299     *         in response to the command.
300     * @exception NNTPConnectionClosedException
301     *      If the NNTP server prematurely closes the connection as a result
302     *      of the client being idle or some other reason causing the server
303     *      to send NNTP reply code 400.  This exception may be caught either
304     *      as an IOException or independently as itself.
305     * @exception IOException  If an I/O error occurs while either sending the
306     *      command or receiving the server reply.
307     ***/
308    public int sendCommand(int command, String args) throws IOException
309    {
310        return sendCommand(NNTPCommand._commands[command], args);
311    }
312
313
314    /***
315     * Sends an NNTP command with no arguments to the server, waits for a
316     * reply and returns the numerical response code.  After invocation, for
317     * more detailed information, the actual reply text can be accessed by
318     * calling {@link #getReplyString  getReplyString }.
319     * <p>
320     * @param command  The text representation of the  NNTP command to send.
321     * @return The integer value of the NNTP reply code returned by the server
322     *         in response to the command.
323     *         in response to the command.
324     * @exception NNTPConnectionClosedException
325     *      If the NNTP server prematurely closes the connection as a result
326     *      of the client being idle or some other reason causing the server
327     *      to send NNTP reply code 400.  This exception may be caught either
328     *      as an IOException or independently as itself.
329     * @exception IOException  If an I/O error occurs while either sending the
330     *      command or receiving the server reply.
331     ***/
332    public int sendCommand(String command) throws IOException
333    {
334        return sendCommand(command, null);
335    }
336
337
338    /***
339     * Sends an NNTP command with no arguments to the server, waits for a
340     * reply and returns the numerical response code.  After invocation, for
341     * more detailed information, the actual reply text can be accessed by
342     * calling {@link #getReplyString  getReplyString }.
343     * <p>
344     * @param command  The NNTPCommand constant corresponding to the NNTP command
345     *                 to send.
346     * @return The integer value of the NNTP reply code returned by the server
347     *         in response to the command.
348     *         in response to the command.
349     * @exception NNTPConnectionClosedException
350     *      If the NNTP server prematurely closes the connection as a result
351     *      of the client being idle or some other reason causing the server
352     *      to send NNTP reply code 400.  This exception may be caught either
353     *      as an IOException or independently as itself.
354     * @exception IOException  If an I/O error occurs while either sending the
355     *      command or receiving the server reply.
356     ***/
357    public int sendCommand(int command) throws IOException
358    {
359        return sendCommand(command, null);
360    }
361
362
363    /***
364     * Returns the integer value of the reply code of the last NNTP reply.
365     * You will usually only use this method after you connect to the
366     * NNTP server to check that the connection was successful since
367     * <code> connect </code> is of type void.
368     * <p>
369     * @return The integer value of the reply code of the last NNTP reply.
370     ***/
371    public int getReplyCode()
372    {
373        return _replyCode;
374    }
375
376    /***
377     * Fetches a reply from the NNTP server and returns the integer reply
378     * code.  After calling this method, the actual reply text can be accessed
379     * from {@link #getReplyString  getReplyString }.  Only use this
380     * method if you are implementing your own NNTP client or if you need to
381     * fetch a secondary response from the NNTP server.
382     * <p>
383     * @return The integer value of the reply code of the fetched NNTP reply.
384     *         in response to the command.
385     * @exception NNTPConnectionClosedException
386     *      If the NNTP server prematurely closes the connection as a result
387     *      of the client being idle or some other reason causing the server
388     *      to send NNTP reply code 400.  This exception may be caught either
389     *      as an IOException or independently as itself.
390     * @exception IOException  If an I/O error occurs while
391     *      receiving the server reply.
392     ***/
393    public int getReply() throws IOException
394    {
395        __getReply();
396        return _replyCode;
397    }
398
399
400    /***
401     * Returns the entire text of the last NNTP server response exactly
402     * as it was received, not including the end of line marker.
403     * <p>
404     * @return The entire text from the last NNTP response as a String.
405     ***/
406    public String getReplyString()
407    {
408        return _replyString;
409    }
410
411
412    /***
413     * A convenience method to send the NNTP ARTICLE command to the server,
414     * receive the initial reply, and return the reply code.
415     * <p>
416     * @param messageId  The message identifier of the requested article,
417     *                   including the encapsulating &lt and &gt characters.
418     * @return The reply code received from the server.
419     * @exception NNTPConnectionClosedException
420     *      If the NNTP server prematurely closes the connection as a result
421     *      of the client being idle or some other reason causing the server
422     *      to send NNTP reply code 400.  This exception may be caught either
423     *      as an IOException or independently as itself.
424     * @exception IOException  If an I/O error occurs while either sending the
425     *      command or receiving the server reply.
426     ***/
427    public int article(String messageId) throws IOException
428    {
429        return sendCommand(NNTPCommand.ARTICLE, messageId);
430    }
431
432    /***
433     * A convenience method to send the NNTP ARTICLE command to the server,
434     * receive the initial reply, and return the reply code.
435     * <p>
436     * @param articleNumber The number of the article to request from the
437     *                      currently selected newsgroup.
438     * @return The reply code received from the server.
439     * @exception NNTPConnectionClosedException
440     *      If the NNTP server prematurely closes the connection as a result
441     *      of the client being idle or some other reason causing the server
442     *      to send NNTP reply code 400.  This exception may be caught either
443     *      as an IOException or independently as itself.
444     * @exception IOException  If an I/O error occurs while either sending the
445     *      command or receiving the server reply.
446     ***/
447    public int article(int articleNumber) throws IOException
448    {
449        return sendCommand(NNTPCommand.ARTICLE, Integer.toString(articleNumber));
450    }
451
452    /***
453     * A convenience method to send the NNTP ARTICLE command to the server,
454     * receive the initial reply, and return the reply code.
455     * <p>
456     * @return The reply code received from the server.
457     * @exception NNTPConnectionClosedException
458     *      If the NNTP server prematurely closes the connection as a result
459     *      of the client being idle or some other reason causing the server
460     *      to send NNTP reply code 400.  This exception may be caught either
461     *      as an IOException or independently as itself.
462     * @exception IOException  If an I/O error occurs while either sending the
463     *      command or receiving the server reply.
464     ***/
465    public int article() throws IOException
466    {
467        return sendCommand(NNTPCommand.ARTICLE);
468    }
469
470
471
472    /***
473     * A convenience method to send the NNTP BODY command to the server,
474     * receive the initial reply, and return the reply code.
475     * <p>
476     * @param messageId  The message identifier of the requested article,
477     *                   including the encapsulating &lt and &gt characters.
478     * @return The reply code received from the server.
479     * @exception NNTPConnectionClosedException
480     *      If the NNTP server prematurely closes the connection as a result
481     *      of the client being idle or some other reason causing the server
482     *      to send NNTP reply code 400.  This exception may be caught either
483     *      as an IOException or independently as itself.
484     * @exception IOException  If an I/O error occurs while either sending the
485     *      command or receiving the server reply.
486     ***/
487    public int body(String messageId) throws IOException
488    {
489        return sendCommand(NNTPCommand.BODY, messageId);
490    }
491
492    /***
493     * A convenience method to send the NNTP BODY command to the server,
494     * receive the initial reply, and return the reply code.
495     * <p>
496     * @param articleNumber The number of the article to request from the
497     *                      currently selected newsgroup.
498     * @return The reply code received from the server.
499     * @exception NNTPConnectionClosedException
500     *      If the NNTP server prematurely closes the connection as a result
501     *      of the client being idle or some other reason causing the server
502     *      to send NNTP reply code 400.  This exception may be caught either
503     *      as an IOException or independently as itself.
504     * @exception IOException  If an I/O error occurs while either sending the
505     *      command or receiving the server reply.
506     ***/
507    public int body(int articleNumber) throws IOException
508    {
509        return sendCommand(NNTPCommand.BODY, Integer.toString(articleNumber));
510    }
511
512    /***
513     * A convenience method to send the NNTP BODY command to the server,
514     * receive the initial reply, and return the reply code.
515     * <p>
516     * @return The reply code received from the server.
517     * @exception NNTPConnectionClosedException
518     *      If the NNTP server prematurely closes the connection as a result
519     *      of the client being idle or some other reason causing the server
520     *      to send NNTP reply code 400.  This exception may be caught either
521     *      as an IOException or independently as itself.
522     * @exception IOException  If an I/O error occurs while either sending the
523     *      command or receiving the server reply.
524     ***/
525    public int body() throws IOException
526    {
527        return sendCommand(NNTPCommand.BODY);
528    }
529
530
531
532    /***
533     * A convenience method to send the NNTP HEAD command to the server,
534     * receive the initial reply, and return the reply code.
535     * <p>
536     * @param messageId  The message identifier of the requested article,
537     *                   including the encapsulating &lt and &gt characters.
538     * @return The reply code received from the server.
539     * @exception NNTPConnectionClosedException
540     *      If the NNTP server prematurely closes the connection as a result
541     *      of the client being idle or some other reason causing the server
542     *      to send NNTP reply code 400.  This exception may be caught either
543     *      as an IOException or independently as itself.
544     * @exception IOException  If an I/O error occurs while either sending the
545     *      command or receiving the server reply.
546     ***/
547    public int head(String messageId) throws IOException
548    {
549        return sendCommand(NNTPCommand.HEAD, messageId);
550    }
551
552    /***
553     * A convenience method to send the NNTP HEAD command to the server,
554     * receive the initial reply, and return the reply code.
555     * <p>
556     * @param articleNumber The number of the article to request from the
557     *                      currently selected newsgroup.
558     * @return The reply code received from the server.
559     * @exception NNTPConnectionClosedException
560     *      If the NNTP server prematurely closes the connection as a result
561     *      of the client being idle or some other reason causing the server
562     *      to send NNTP reply code 400.  This exception may be caught either
563     *      as an IOException or independently as itself.
564     * @exception IOException  If an I/O error occurs while either sending the
565     *      command or receiving the server reply.
566     ***/
567    public int head(int articleNumber) throws IOException
568    {
569        return sendCommand(NNTPCommand.HEAD, Integer.toString(articleNumber));
570    }
571
572    /***
573     * A convenience method to send the NNTP HEAD command to the server,
574     * receive the initial reply, and return the reply code.
575     * <p>
576     * @return The reply code received from the server.
577     * @exception NNTPConnectionClosedException
578     *      If the NNTP server prematurely closes the connection as a result
579     *      of the client being idle or some other reason causing the server
580     *      to send NNTP reply code 400.  This exception may be caught either
581     *      as an IOException or independently as itself.
582     * @exception IOException  If an I/O error occurs while either sending the
583     *      command or receiving the server reply.
584     ***/
585    public int head() throws IOException
586    {
587        return sendCommand(NNTPCommand.HEAD);
588    }
589
590
591
592    /***
593     * A convenience method to send the NNTP STAT command to the server,
594     * receive the initial reply, and return the reply code.
595     * <p>
596     * @param messageId  The message identifier of the requested article,
597     *                   including the encapsulating &lt and &gt characters.
598     * @return The reply code received from the server.
599     * @exception NNTPConnectionClosedException
600     *      If the NNTP server prematurely closes the connection as a result
601     *      of the client being idle or some other reason causing the server
602     *      to send NNTP reply code 400.  This exception may be caught either
603     *      as an IOException or independently as itself.
604     * @exception IOException  If an I/O error occurs while either sending the
605     *      command or receiving the server reply.
606     ***/
607    public int stat(String messageId) throws IOException
608    {
609        return sendCommand(NNTPCommand.STAT, messageId);
610    }
611
612    /***
613     * A convenience method to send the NNTP STAT command to the server,
614     * receive the initial reply, and return the reply code.
615     * <p>
616     * @param articleNumber The number of the article to request from the
617     *                      currently selected newsgroup.
618     * @return The reply code received from the server.
619     * @exception NNTPConnectionClosedException
620     *      If the NNTP server prematurely closes the connection as a result
621     *      of the client being idle or some other reason causing the server
622     *      to send NNTP reply code 400.  This exception may be caught either
623     *      as an IOException or independently as itself.
624     * @exception IOException  If an I/O error occurs while either sending the
625     *      command or receiving the server reply.
626     ***/
627    public int stat(int articleNumber) throws IOException
628    {
629        return sendCommand(NNTPCommand.STAT, Integer.toString(articleNumber));
630    }
631
632    /***
633     * A convenience method to send the NNTP STAT command to the server,
634     * receive the initial reply, and return the reply code.
635     * <p>
636     * @return The reply code received from the server.
637     * @exception NNTPConnectionClosedException
638     *      If the NNTP server prematurely closes the connection as a result
639     *      of the client being idle or some other reason causing the server
640     *      to send NNTP reply code 400.  This exception may be caught either
641     *      as an IOException or independently as itself.
642     * @exception IOException  If an I/O error occurs while either sending the
643     *      command or receiving the server reply.
644     ***/
645    public int stat() throws IOException
646    {
647        return sendCommand(NNTPCommand.STAT);
648    }
649
650
651    /***
652     * A convenience method to send the NNTP GROUP command to the server,
653     * receive the reply, and return the reply code.
654     * <p>
655     * @param newsgroup  The name of the newsgroup to select.
656     * @return The reply code received from the server.
657     * @exception NNTPConnectionClosedException
658     *      If the NNTP server prematurely closes the connection as a result
659     *      of the client being idle or some other reason causing the server
660     *      to send NNTP reply code 400.  This exception may be caught either
661     *      as an IOException or independently as itself.
662     * @exception IOException  If an I/O error occurs while either sending the
663     *      command or receiving the server reply.
664     ***/
665    public int group(String newsgroup) throws IOException
666    {
667        return sendCommand(NNTPCommand.GROUP, newsgroup);
668    }
669
670
671    /***
672     * A convenience method to send the NNTP HELP command to the server,
673     * receive the reply, and return the reply code.
674     * <p>
675     * @return The reply code received from the server.
676     * @exception NNTPConnectionClosedException
677     *      If the NNTP server prematurely closes the connection as a result
678     *      of the client being idle or some other reason causing the server
679     *      to send NNTP reply code 400.  This exception may be caught either
680     *      as an IOException or independently as itself.
681     * @exception IOException  If an I/O error occurs while either sending the
682     *      command or receiving the server reply.
683     ***/
684    public int help() throws IOException
685    {
686        return sendCommand(NNTPCommand.HELP);
687    }
688
689
690    /***
691     * A convenience method to send the NNTP IHAVE command to the server,
692     * receive the reply, and return the reply code.
693     * <p>
694     * @param messageId  The article identifier,
695     *                   including the encapsulating &lt and &gt characters.
696     * @return The reply code received from the server.
697     * @exception NNTPConnectionClosedException
698     *      If the NNTP server prematurely closes the connection as a result
699     *      of the client being idle or some other reason causing the server
700     *      to send NNTP reply code 400.  This exception may be caught either
701     *      as an IOException or independently as itself.
702     * @exception IOException  If an I/O error occurs while either sending the
703     *      command or receiving the server reply.
704     ***/
705    public int ihave(String messageId) throws IOException
706    {
707        return sendCommand(NNTPCommand.IHAVE, messageId);
708    }
709
710
711    /***
712     * A convenience method to send the NNTP LAST command to the server,
713     * receive the reply, and return the reply code.
714     * <p>
715     * @return The reply code received from the server.
716     * @exception NNTPConnectionClosedException
717     *      If the NNTP server prematurely closes the connection as a result
718     *      of the client being idle or some other reason causing the server
719     *      to send NNTP reply code 400.  This exception may be caught either
720     *      as an IOException or independently as itself.
721     * @exception IOException  If an I/O error occurs while either sending the
722     *      command or receiving the server reply.
723     ***/
724    public int last() throws IOException
725    {
726        return sendCommand(NNTPCommand.LAST);
727    }
728
729
730
731    /***
732     * A convenience method to send the NNTP LIST command to the server,
733     * receive the reply, and return the reply code.
734     * <p>
735     * @return The reply code received from the server.
736     * @exception NNTPConnectionClosedException
737     *      If the NNTP server prematurely closes the connection as a result
738     *      of the client being idle or some other reason causing the server
739     *      to send NNTP reply code 400.  This exception may be caught either
740     *      as an IOException or independently as itself.
741     * @exception IOException  If an I/O error occurs while either sending the
742     *      command or receiving the server reply.
743     ***/
744    public int list() throws IOException
745    {
746        return sendCommand(NNTPCommand.LIST);
747    }
748
749
750
751    /***
752     * A convenience method to send the NNTP NEXT command to the server,
753     * receive the reply, and return the reply code.
754     * <p>
755     * @return The reply code received from the server.
756     * @exception NNTPConnectionClosedException
757     *      If the NNTP server prematurely closes the connection as a result
758     *      of the client being idle or some other reason causing the server
759     *      to send NNTP reply code 400.  This exception may be caught either
760     *      as an IOException or independently as itself.
761     * @exception IOException  If an I/O error occurs while either sending the
762     *      command or receiving the server reply.
763     ***/
764    public int next() throws IOException
765    {
766        return sendCommand(NNTPCommand.NEXT);
767    }
768
769
770    /***
771     * A convenience method to send the NNTP NEWGROUPS command to the server,
772     * receive the reply, and return the reply code.
773     * <p>
774     * @param date The date after which to check for new groups.
775     *             Date format is YYMMDD
776     * @param time The time after which to check for new groups.
777     *             Time format is HHMMSS using a 24-hour clock.
778     * @param GMT  True if the time is in GMT, false if local server time.
779     * @param distributions  Comma-separated distribution list to check for
780     *            new groups. Set to null if no distributions.
781     * @return The reply code received from the server.
782     * @exception NNTPConnectionClosedException
783     *      If the NNTP server prematurely closes the connection as a result
784     *      of the client being idle or some other reason causing the server
785     *      to send NNTP reply code 400.  This exception may be caught either
786     *      as an IOException or independently as itself.
787     * @exception IOException  If an I/O error occurs while either sending the
788     *      command or receiving the server reply.
789     ***/
790    public int newgroups(String date, String time, boolean GMT,
791                         String distributions) throws IOException
792    {
793        StringBuffer buffer = new StringBuffer();
794
795        buffer.append(date);
796        buffer.append(' ');
797        buffer.append(time);
798
799        if (GMT)
800        {
801            buffer.append(' ');
802            buffer.append("GMT");
803        }
804
805        if (distributions != null)
806        {
807            buffer.append(" <");
808            buffer.append(distributions);
809            buffer.append('>');
810        }
811
812        return sendCommand(NNTPCommand.NEWGROUPS, buffer.toString());
813    }
814
815
816    /***
817     * A convenience method to send the NNTP NEWGROUPS command to the server,
818     * receive the reply, and return the reply code.
819     * <p>
820     * @param newsgroups A comma-separated list of newsgroups to check for new
821     *             news.
822     * @param date The date after which to check for new news.
823     *             Date format is YYMMDD
824     * @param time The time after which to check for new news.
825     *             Time format is HHMMSS using a 24-hour clock.
826     * @param GMT  True if the time is in GMT, false if local server time.
827     * @param distributions  Comma-separated distribution list to check for
828     *            new news. Set to null if no distributions.
829     * @return The reply code received from the server.
830     * @exception NNTPConnectionClosedException
831     *      If the NNTP server prematurely closes the connection as a result
832     *      of the client being idle or some other reason causing the server
833     *      to send NNTP reply code 400.  This exception may be caught either
834     *      as an IOException or independently as itself.
835     * @exception IOException  If an I/O error occurs while either sending the
836     *      command or receiving the server reply.
837     ***/
838    public int newnews(String newsgroups, String date, String time, boolean GMT,
839                       String distributions) throws IOException
840    {
841        StringBuffer buffer = new StringBuffer();
842
843        buffer.append(newsgroups);
844        buffer.append(' ');
845        buffer.append(date);
846        buffer.append(' ');
847        buffer.append(time);
848
849        if (GMT)
850        {
851            buffer.append(' ');
852            buffer.append("GMT");
853        }
854
855        if (distributions != null)
856        {
857            buffer.append(" <");
858            buffer.append(distributions);
859            buffer.append('>');
860        }
861
862        return sendCommand(NNTPCommand.NEWNEWS, buffer.toString());
863    }
864
865
866
867    /***
868     * A convenience method to send the NNTP POST command to the server,
869     * receive the reply, and return the reply code.
870     * <p>
871     * @return The reply code received from the server.
872     * @exception NNTPConnectionClosedException
873     *      If the NNTP server prematurely closes the connection as a result
874     *      of the client being idle or some other reason causing the server
875     *      to send NNTP reply code 400.  This exception may be caught either
876     *      as an IOException or independently as itself.
877     * @exception IOException  If an I/O error occurs while either sending the
878     *      command or receiving the server reply.
879     ***/
880    public int post() throws IOException
881    {
882        return sendCommand(NNTPCommand.POST);
883    }
884
885
886
887    /***
888     * A convenience method to send the NNTP QUIT command to the server,
889     * receive the reply, and return the reply code.
890     * <p>
891     * @return The reply code received from the server.
892     * @exception NNTPConnectionClosedException
893     *      If the NNTP server prematurely closes the connection as a result
894     *      of the client being idle or some other reason causing the server
895     *      to send NNTP reply code 400.  This exception may be caught either
896     *      as an IOException or independently as itself.
897     * @exception IOException  If an I/O error occurs while either sending the
898     *      command or receiving the server reply.
899     ***/
900    public int quit() throws IOException
901    {
902        return sendCommand(NNTPCommand.QUIT);
903    }
904
905    /***
906     * A convenience method to send the AUTHINFO USER command to the server,
907     *  receive the reply, and return the reply code. (See RFC 2980)
908     * <p>
909     * @param username A valid username.
910     * @return The reply code received from the server. The server should
911     *          return a 381 or 281 for this command.
912     * @exception NNTPConnectionClosedException
913     *      If the NNTP server prematurely closes the connection as a result
914     *      of the client being idle or some other reason causing the server
915     *      to send NNTP reply code 400.  This exception may be caught either
916     *      as an IOException or independently as itself.
917     * @exception IOException  If an I/O error occurs while either sending the
918     *      command or receiving the server reply.
919     ***/
920    public int authinfoUser(String username) throws IOException {
921        String userParameter = "USER " + username;
922        return sendCommand(NNTPCommand.AUTHINFO, userParameter);
923    }
924
925    /***
926     * A convenience method to send the AUTHINFO PASS command to the server,
927     * receive the reply, and return the reply code.  If this step is
928     * required, it should immediately follow the AUTHINFO USER command
929     * (See RFC 2980)
930     * <p>
931     * @param password a valid password.
932     * @return The reply code received from the server. The server should
933     *         return a 281 or 502 for this command.
934     * @exception NNTPConnectionClosedException
935     *      If the NNTP server prematurely closes the connection as a result
936     *      of the client being idle or some other reason causing the server
937     *      to send NNTP reply code 400.  This exception may be caught either
938     *      as an IOException or independently as itself.
939     * @exception IOException  If an I/O error occurs while either sending the
940     *      command or receiving the server reply.
941     ***/
942    public int authinfoPass(String password) throws IOException {
943        String passParameter = "PASS " + password;
944        return sendCommand(NNTPCommand.AUTHINFO, passParameter);
945    }
946
947    /***
948     * A convenience method to send the NNTP XOVER command to the server,
949     * receive the reply, and return the reply code.
950     * <p>
951     * @param selectedArticles a String representation of the range of
952     * article headers required. This may be an article number, or a
953     * range of article numbers in the form "XXXX-YYYY", where XXXX
954     * and YYYY are valid article numbers in the current group.  It
955     * also may be of the form "XXX-", meaning "return XXX and all
956     * following articles" In this revision, the last format is not
957     * possible (yet).
958     * @return The reply code received from the server.
959     * @exception NNTPConnectionClosedException
960     *      If the NNTP server prematurely closes the connection as a result
961     *      of the client being idle or some other reason causing the server
962     *      to send NNTP reply code 400.  This exception may be caught either
963     *      as an IOException or independently as itself.
964     * @exception IOException  If an I/O error occurs while either sending the
965     *      command or receiving the server reply.
966     ***/
967    public int xover(String selectedArticles) throws IOException {
968        return sendCommand(NNTPCommand.XOVER, selectedArticles);
969    }
970
971    /***
972     * A convenience method to send the NNTP XHDR command to the server,
973     * receive the reply, and return the reply code.
974     * <p>
975     * @param header a String naming a header line (e.g., "subject").  See
976     * RFC-1036 for a list of valid header lines.
977     * @param selectedArticles a String representation of the range of
978     * article headers required. This may be an article number, or a
979     * range of article numbers in the form "XXXX-YYYY", where XXXX
980     * and YYYY are valid article numbers in the current group.  It
981     * also may be of the form "XXX-", meaning "return XXX and all
982     * following articles" In this revision, the last format is not
983     * possible (yet).
984     * @return The reply code received from the server.
985     * @exception NNTPConnectionClosedException
986     *      If the NNTP server prematurely closes the connection as a result
987     *      of the client being idle or some other reason causing the server
988     *      to send NNTP reply code 400.  This exception may be caught either
989     *      as an IOException or independently as itself.
990     * @exception IOException  If an I/O error occurs while either sending the
991     *      command or receiving the server reply.
992     ***/
993    public int xhdr(String header, String selectedArticles) throws IOException {
994        StringBuffer command = new StringBuffer(header);
995        command.append(" ");
996        command.append(selectedArticles);
997        return sendCommand(NNTPCommand.XHDR, command.toString());
998    }
999
1000    /**
1001     * A convenience wrapper for the extended LIST command that takes
1002     * an argument, allowing us to selectively list multiple groups.
1003     * <p>
1004     * @param wildmat A wildmat (pseudo-regex) pattern. See RFC 2980 for
1005     *                details.
1006     * @return the reply code received from the server.
1007     * @throws IOException
1008     */
1009    public int listActive(String wildmat) throws IOException {
1010        StringBuffer command = new StringBuffer("ACTIVE ");
1011        command.append(wildmat);
1012        return sendCommand(NNTPCommand.LIST, command.toString());
1013    }
1014}
1015
1016/* Emacs configuration
1017 * Local variables:        **
1018 * mode:             java  **
1019 * c-basic-offset:   4     **
1020 * indent-tabs-mode: nil   **
1021 * End:                    **
1022 */