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