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