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