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