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