Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/commons/net/nntp/NNTPClient.java


1   /*
2    * Copyright 2001-2005 The Apache Software Foundation
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.net.nntp;
17  
18  import java.io.BufferedReader;
19  import java.io.IOException;
20  import java.io.Reader;
21  import java.io.StringWriter;
22  import java.io.Writer;
23  import java.util.StringTokenizer;
24  import java.util.Vector;
25  import org.apache.commons.net.io.DotTerminatedMessageReader;
26  import org.apache.commons.net.io.DotTerminatedMessageWriter;
27  import org.apache.commons.net.io.Util;
28  import org.apache.commons.net.MalformedServerReplyException;
29  
30  /***
31   * NNTPClient encapsulates all the functionality necessary to post and
32   * retrieve articles from an NNTP server.  As with all classes derived
33   * from {@link org.apache.commons.net.SocketClient},
34   * you must first connect to the server with
35   * {@link org.apache.commons.net.SocketClient#connect  connect }
36   * before doing anything, and finally
37   * {@link org.apache.commons.net.nntp.NNTP#disconnect  disconnect() }
38   * after you're completely finished interacting with the server.
39   * Remember that the
40   * {@link org.apache.commons.net.nntp.NNTP#isAllowedToPost isAllowedToPost()}
41   *  method is defined in
42   * {@link org.apache.commons.net.nntp.NNTP}.
43   * <p>
44   * You should keep in mind that the NNTP server may choose to prematurely
45   * close a connection if the client has been idle for longer than a
46   * given time period or if the server is being shutdown by the operator or
47   * some other reason.  The NNTP class will detect a
48   * premature NNTP server connection closing when it receives a
49   * {@link org.apache.commons.net.nntp.NNTPReply#SERVICE_DISCONTINUED NNTPReply.SERVICE_DISCONTINUED }
50   *  response to a command.
51   * When that occurs, the NNTP class method encountering that reply will throw
52   * an {@link org.apache.commons.net.nntp.NNTPConnectionClosedException}
53   * .
54   * <code>NNTPConectionClosedException</code>
55   * is a subclass of <code> IOException </code> and therefore need not be
56   * caught separately, but if you are going to catch it separately, its
57   * catch block must appear before the more general <code> IOException </code>
58   * catch block.  When you encounter an
59   * {@link org.apache.commons.net.nntp.NNTPConnectionClosedException}
60   * , you must disconnect the connection with
61   * {@link org.apache.commons.net.nntp.NNTP#disconnect  disconnect() }
62   *  to properly clean up the
63   * system resources used by NNTP.  Before disconnecting, you may check the
64   * last reply code and text with
65   * {@link org.apache.commons.net.nntp.NNTP#getReplyCode  getReplyCode } and
66   * {@link org.apache.commons.net.nntp.NNTP#getReplyString  getReplyString }.
67   * <p>
68   * Rather than list it separately for each method, we mention here that
69   * every method communicating with the server and throwing an IOException
70   * can also throw a
71   * {@link org.apache.commons.net.MalformedServerReplyException}
72   * , which is a subclass
73   * of IOException.  A MalformedServerReplyException will be thrown when
74   * the reply received from the server deviates enough from the protocol
75   * specification that it cannot be interpreted in a useful manner despite
76   * attempts to be as lenient as possible.
77   * <p>
78   * <p>
79   * @author Daniel F. Savarese
80   * @author Rory Winston
81   * @author Ted Wise
82   * @see NNTP
83   * @see NNTPConnectionClosedException
84   * @see org.apache.commons.net.MalformedServerReplyException
85   ***/
86  
87  public class NNTPClient extends NNTP
88  {
89  
90      private void __parseArticlePointer(String reply, ArticlePointer pointer)
91      throws MalformedServerReplyException
92      {
93          StringTokenizer tokenizer;
94  
95          // Do loop is a kluge to simulate goto
96          do
97          {
98              tokenizer = new StringTokenizer(reply);
99  
100             if (tokenizer.countTokens() < 3)
101                 break;
102 
103             // Skip numeric response value
104             tokenizer.nextToken();
105             // Get article number
106             try
107             {
108                 pointer.articleNumber = Integer.parseInt(tokenizer.nextToken());
109             }
110             catch (NumberFormatException e)
111             {
112                 break;
113             }
114 
115             // Get article id
116             pointer.articleId = tokenizer.nextToken();
117             return ;
118         }
119         while (false);
120 
121         throw new MalformedServerReplyException(
122             "Could not parse article pointer.\nServer reply: " + reply);
123     }
124 
125 
126     private void __parseGroupReply(String reply, NewsgroupInfo info)
127     throws MalformedServerReplyException
128     {
129         String count, first, last;
130         StringTokenizer tokenizer;
131 
132         // Do loop is a kluge to simulate goto
133         do
134         {
135             tokenizer = new StringTokenizer(reply);
136 
137             if (tokenizer.countTokens() < 5)
138                 break;
139 
140             // Skip numeric response value
141             tokenizer.nextToken();
142             // Get estimated article count
143             count = tokenizer.nextToken();
144             // Get first article number
145             first = tokenizer.nextToken();
146             // Get last article number
147             last = tokenizer.nextToken();
148             // Get newsgroup name
149             info._setNewsgroup(tokenizer.nextToken());
150 
151             try
152             {
153                 info._setArticleCount(Integer.parseInt(count));
154                 info._setFirstArticle(Integer.parseInt(first));
155                 info._setLastArticle(Integer.parseInt(last));
156             }
157             catch (NumberFormatException e)
158             {
159                 break;
160             }
161 
162             info._setPostingPermission(NewsgroupInfo.UNKNOWN_POSTING_PERMISSION);
163             return ;
164         }
165         while (false);
166 
167         throw new MalformedServerReplyException(
168             "Could not parse newsgroup info.\nServer reply: " + reply);
169     }
170 
171 
172     private NewsgroupInfo __parseNewsgroupListEntry(String entry)
173     {
174         NewsgroupInfo result;
175         StringTokenizer tokenizer;
176         int lastNum, firstNum;
177         String last, first, permission;
178 
179         result = new NewsgroupInfo();
180         tokenizer = new StringTokenizer(entry);
181 
182         if (tokenizer.countTokens() < 4)
183             return null;
184 
185         result._setNewsgroup(tokenizer.nextToken());
186         last = tokenizer.nextToken();
187         first = tokenizer.nextToken();
188         permission = tokenizer.nextToken();
189 
190         try
191         {
192             lastNum = Integer.parseInt(last);
193             firstNum = Integer.parseInt(first);
194             result._setFirstArticle(firstNum);
195             result._setLastArticle(lastNum);
196 
197       if((firstNum == 0) && (lastNum == 0))
198         result._setArticleCount(0);
199       else
200         result._setArticleCount(lastNum - firstNum + 1);
201         }
202         catch (NumberFormatException e)
203         {
204             return null;
205         }
206 
207         switch (permission.charAt(0))
208         {
209         case 'y':
210         case 'Y':
211             result._setPostingPermission(
212                 NewsgroupInfo.PERMITTED_POSTING_PERMISSION);
213             break;
214         case 'n':
215         case 'N':
216             result._setPostingPermission(
217                 NewsgroupInfo.PROHIBITED_POSTING_PERMISSION);
218             break;
219         case 'm':
220         case 'M':
221             result._setPostingPermission(
222                 NewsgroupInfo.MODERATED_POSTING_PERMISSION);
223             break;
224         default:
225             result._setPostingPermission(
226                 NewsgroupInfo.UNKNOWN_POSTING_PERMISSION);
227             break;
228         }
229 
230         return result;
231     }
232 
233     private NewsgroupInfo[] __readNewsgroupListing() throws IOException
234     {
235         int size;
236         String line;
237         Vector list;
238         BufferedReader reader;
239         NewsgroupInfo tmp, info[];
240 
241         reader = new BufferedReader(new DotTerminatedMessageReader(_reader_));
242         // Start of with a big vector because we may be reading a very large
243         // amount of groups.
244         list = new Vector(2048);
245 
246         while ((line = reader.readLine()) != null)
247         {
248             tmp = __parseNewsgroupListEntry(line);
249             if (tmp != null)
250                 list.addElement(tmp);
251             else
252                 throw new MalformedServerReplyException(line);
253         }
254 
255         if ((size = list.size()) < 1)
256             return new NewsgroupInfo[0];
257 
258         info = new NewsgroupInfo[size];
259         list.copyInto(info);
260 
261         return info;
262     }
263 
264 
265     private Reader __retrieve(int command,
266                               String articleId, ArticlePointer pointer)
267     throws IOException
268     {
269         Reader reader;
270 
271         if (articleId != null)
272         {
273             if (!NNTPReply.isPositiveCompletion(sendCommand(command, articleId)))
274                 return null;
275         }
276         else
277         {
278             if (!NNTPReply.isPositiveCompletion(sendCommand(command)))
279                 return null;
280         }
281 
282 
283         if (pointer != null)
284             __parseArticlePointer(getReplyString(), pointer);
285 
286         reader = new DotTerminatedMessageReader(_reader_);
287         return reader;
288     }
289 
290 
291     private Reader __retrieve(int command,
292                               int articleNumber, ArticlePointer pointer)
293     throws IOException
294     {
295         Reader reader;
296 
297         if (!NNTPReply.isPositiveCompletion(sendCommand(command,
298                                             Integer.toString(articleNumber))))
299             return null;
300 
301         if (pointer != null)
302             __parseArticlePointer(getReplyString(), pointer);
303 
304         reader = new DotTerminatedMessageReader(_reader_);
305         return reader;
306     }
307 
308 
309 
310     /***
311      * Retrieves an article from the NNTP server.  The article is referenced
312      * by its unique article identifier (including the enclosing &lt and &gt).
313      * The article number and identifier contained in the server reply
314      * are returned through an ArticlePointer.  The <code> articleId </code>
315      * field of the ArticlePointer cannot always be trusted because some
316      * NNTP servers do not correctly follow the RFC 977 reply format.
317      * <p>
318      * A DotTerminatedMessageReader is returned from which the article can
319      * be read.  If the article does not exist, null is returned.
320      * <p>
321      * You must not issue any commands to the NNTP server (i.e., call any
322      * other methods) until you finish reading the message from the returned
323      * Reader instance.
324      * The NNTP protocol uses the same stream for issuing commands as it does
325      * for returning results.  Therefore the returned Reader actually reads
326      * directly from the NNTP connection.  After the end of message has been
327      * reached, new commands can be executed and their replies read.  If
328      * you do not follow these requirements, your program will not work
329      * properly.
330      * <p>
331      * @param articleId  The unique article identifier of the article to
332      *     retrieve.  If this parameter is null, the currently selected
333      *     article is retrieved.
334      * @param pointer    A parameter through which to return the article's
335      *   number and unique id.  The articleId field cannot always be trusted
336      *   because of server deviations from RFC 977 reply formats.  You may
337      *   set this parameter to null if you do not desire to retrieve the
338      *   returned article information.
339      * @return A DotTerminatedMessageReader instance from which the article
340      *         be read.  null if the article does not exist.
341      * @exception NNTPConnectionClosedException
342      *      If the NNTP server prematurely closes the connection as a result
343      *      of the client being idle or some other reason causing the server
344      *      to send NNTP reply code 400.  This exception may be caught either
345      *      as an IOException or independently as itself.
346      * @exception IOException  If an I/O error occurs while either sending a
347      *      command to the server or receiving a reply from the server.
348      ***/
349     public Reader retrieveArticle(String articleId, ArticlePointer pointer)
350     throws IOException
351     {
352         return __retrieve(NNTPCommand.ARTICLE, articleId, pointer);
353 
354     }
355 
356     /*** Same as <code> retrieveArticle(articleId, null) </code> ***/
357     public Reader retrieveArticle(String articleId) throws IOException
358     {
359         return retrieveArticle(articleId, null);
360     }
361 
362     /*** Same as <code> retrieveArticle(null) </code> ***/
363     public Reader retrieveArticle() throws IOException
364     {
365         return retrieveArticle(null);
366     }
367 
368 
369     /***
370      * Retrieves an article from the currently selected newsgroup.  The
371      * article is referenced by its article number.
372      * The article number and identifier contained in the server reply
373      * are returned through an ArticlePointer.  The <code> articleId </code>
374      * field of the ArticlePointer cannot always be trusted because some
375      * NNTP servers do not correctly follow the RFC 977 reply format.
376      * <p>
377      * A DotTerminatedMessageReader is returned from which the article can
378      * be read.  If the article does not exist, null is returned.
379      * <p>
380      * You must not issue any commands to the NNTP server (i.e., call any
381      * other methods) until you finish reading the message from the returned
382      * Reader instance.
383      * The NNTP protocol uses the same stream for issuing commands as it does
384      * for returning results.  Therefore the returned Reader actually reads
385      * directly from the NNTP connection.  After the end of message has been
386      * reached, new commands can be executed and their replies read.  If
387      * you do not follow these requirements, your program will not work
388      * properly.
389      * <p>
390      * @param articleNumber  The number of the the article to
391      *     retrieve.
392      * @param pointer    A parameter through which to return the article's
393      *   number and unique id.  The articleId field cannot always be trusted
394      *   because of server deviations from RFC 977 reply formats.  You may
395      *   set this parameter to null if you do not desire to retrieve the
396      *   returned article information.
397      * @return A DotTerminatedMessageReader instance from which the article
398      *         be read.  null if the article does not exist.
399      * @exception NNTPConnectionClosedException
400      *      If the NNTP server prematurely closes the connection as a result
401      *      of the client being idle or some other reason causing the server
402      *      to send NNTP reply code 400.  This exception may be caught either
403      *      as an IOException or independently as itself.
404      * @exception IOException  If an I/O error occurs while either sending a
405      *      command to the server or receiving a reply from the server.
406      ***/
407     public Reader retrieveArticle(int articleNumber, ArticlePointer pointer)
408     throws IOException
409     {
410         return __retrieve(NNTPCommand.ARTICLE, articleNumber, pointer);
411     }
412 
413     /*** Same as <code> retrieveArticle(articleNumber, null) </code> ***/
414     public Reader retrieveArticle(int articleNumber) throws IOException
415     {
416         return retrieveArticle(articleNumber, null);
417     }
418 
419 
420 
421     /***
422      * Retrieves an article header from the NNTP server.  The article is
423      * referenced
424      * by its unique article identifier (including the enclosing &lt and &gt).
425      * The article number and identifier contained in the server reply
426      * are returned through an ArticlePointer.  The <code> articleId </code>
427      * field of the ArticlePointer cannot always be trusted because some
428      * NNTP servers do not correctly follow the RFC 977 reply format.
429      * <p>
430      * A DotTerminatedMessageReader is returned from which the article can
431      * be read.  If the article does not exist, null is returned.
432      * <p>
433      * You must not issue any commands to the NNTP server (i.e., call any
434      * other methods) until you finish reading the message from the returned
435      * Reader instance.
436      * The NNTP protocol uses the same stream for issuing commands as it does
437      * for returning results.  Therefore the returned Reader actually reads
438      * directly from the NNTP connection.  After the end of message has been
439      * reached, new commands can be executed and their replies read.  If
440      * you do not follow these requirements, your program will not work
441      * properly.
442      * <p>
443      * @param articleId  The unique article identifier of the article whose
444      *    header is being retrieved.  If this parameter is null, the
445      *    header of the currently selected article is retrieved.
446      * @param pointer    A parameter through which to return the article's
447      *   number and unique id.  The articleId field cannot always be trusted
448      *   because of server deviations from RFC 977 reply formats.  You may
449      *   set this parameter to null if you do not desire to retrieve the
450      *   returned article information.
451      * @return A DotTerminatedMessageReader instance from which the article
452      *         header can be read.  null if the article does not exist.
453      * @exception NNTPConnectionClosedException
454      *      If the NNTP server prematurely closes the connection as a result
455      *      of the client being idle or some other reason causing the server
456      *      to send NNTP reply code 400.  This exception may be caught either
457      *      as an IOException or independently as itself.
458      * @exception IOException  If an I/O error occurs while either sending a
459      *      command to the server or receiving a reply from the server.
460      ***/
461     public Reader retrieveArticleHeader(String articleId, ArticlePointer pointer)
462     throws IOException
463     {
464         return __retrieve(NNTPCommand.HEAD, articleId, pointer);
465 
466     }
467 
468     /*** Same as <code> retrieveArticleHeader(articleId, null) </code> ***/
469     public Reader retrieveArticleHeader(String articleId) throws IOException
470     {
471         return retrieveArticleHeader(articleId, null);
472     }
473 
474     /*** Same as <code> retrieveArticleHeader(null) </code> ***/
475     public Reader retrieveArticleHeader() throws IOException
476     {
477         return retrieveArticleHeader(null);
478     }
479 
480 
481     /***
482      * Retrieves an article header from the currently selected newsgroup.  The
483      * article is referenced by its article number.
484      * The article number and identifier contained in the server reply
485      * are returned through an ArticlePointer.  The <code> articleId </code>
486      * field of the ArticlePointer cannot always be trusted because some
487      * NNTP servers do not correctly follow the RFC 977 reply format.
488      * <p>
489      * A DotTerminatedMessageReader is returned from which the article can
490      * be read.  If the article does not exist, null is returned.
491      * <p>
492      * You must not issue any commands to the NNTP server (i.e., call any
493      * other methods) until you finish reading the message from the returned
494      * Reader instance.
495      * The NNTP protocol uses the same stream for issuing commands as it does
496      * for returning results.  Therefore the returned Reader actually reads
497      * directly from the NNTP connection.  After the end of message has been
498      * reached, new commands can be executed and their replies read.  If
499      * you do not follow these requirements, your program will not work
500      * properly.
501      * <p>
502      * @param articleNumber  The number of the the article whose header is
503      *     being retrieved.
504      * @param pointer    A parameter through which to return the article's
505      *   number and unique id.  The articleId field cannot always be trusted
506      *   because of server deviations from RFC 977 reply formats.  You may
507      *   set this parameter to null if you do not desire to retrieve the
508      *   returned article information.
509      * @return A DotTerminatedMessageReader instance from which the article
510      *         header can be read.  null if the article does not exist.
511      * @exception NNTPConnectionClosedException
512      *      If the NNTP server prematurely closes the connection as a result
513      *      of the client being idle or some other reason causing the server
514      *      to send NNTP reply code 400.  This exception may be caught either
515      *      as an IOException or independently as itself.
516      * @exception IOException  If an I/O error occurs while either sending a
517      *      command to the server or receiving a reply from the server.
518      ***/
519     public Reader retrieveArticleHeader(int articleNumber,
520                                         ArticlePointer pointer)
521     throws IOException
522     {
523         return __retrieve(NNTPCommand.HEAD, articleNumber, pointer);
524     }
525 
526 
527     /*** Same as <code> retrieveArticleHeader(articleNumber, null) </code> ***/
528     public Reader retrieveArticleHeader(int articleNumber) throws IOException
529     {
530         return retrieveArticleHeader(articleNumber, null);
531     }
532 
533 
534 
535     /***
536      * Retrieves an article body from the NNTP server.  The article is
537      * referenced
538      * by its unique article identifier (including the enclosing &lt and &gt).
539      * The article number and identifier contained in the server reply
540      * are returned through an ArticlePointer.  The <code> articleId </code>
541      * field of the ArticlePointer cannot always be trusted because some
542      * NNTP servers do not correctly follow the RFC 977 reply format.
543      * <p>
544      * A DotTerminatedMessageReader is returned from which the article can
545      * be read.  If the article does not exist, null is returned.
546      * <p>
547      * You must not issue any commands to the NNTP server (i.e., call any
548      * other methods) until you finish reading the message from the returned
549      * Reader instance.
550      * The NNTP protocol uses the same stream for issuing commands as it does
551      * for returning results.  Therefore the returned Reader actually reads
552      * directly from the NNTP connection.  After the end of message has been
553      * reached, new commands can be executed and their replies read.  If
554      * you do not follow these requirements, your program will not work
555      * properly.
556      * <p>
557      * @param articleId  The unique article identifier of the article whose
558      *    body is being retrieved.  If this parameter is null, the
559      *    body of the currently selected article is retrieved.
560      * @param pointer    A parameter through which to return the article's
561      *   number and unique id.  The articleId field cannot always be trusted
562      *   because of server deviations from RFC 977 reply formats.  You may
563      *   set this parameter to null if you do not desire to retrieve the
564      *   returned article information.
565      * @return A DotTerminatedMessageReader instance from which the article
566      *         body can be read.  null if the article does not exist.
567      * @exception NNTPConnectionClosedException
568      *      If the NNTP server prematurely closes the connection as a result
569      *      of the client being idle or some other reason causing the server
570      *      to send NNTP reply code 400.  This exception may be caught either
571      *      as an IOException or independently as itself.
572      * @exception IOException  If an I/O error occurs while either sending a
573      *      command to the server or receiving a reply from the server.
574      ***/
575     public Reader retrieveArticleBody(String articleId, ArticlePointer pointer)
576     throws IOException
577     {
578         return __retrieve(NNTPCommand.BODY, articleId, pointer);
579 
580     }
581 
582     /*** Same as <code> retrieveArticleBody(articleId, null) </code> ***/
583     public Reader retrieveArticleBody(String articleId) throws IOException
584     {
585         return retrieveArticleBody(articleId, null);
586     }
587 
588     /*** Same as <code> retrieveArticleBody(null) </code> ***/
589     public Reader retrieveArticleBody() throws IOException
590     {
591         return retrieveArticleBody(null);
592     }
593 
594 
595     /***
596      * Retrieves an article body from the currently selected newsgroup.  The
597      * article is referenced by its article number.
598      * The article number and identifier contained in the server reply
599      * are returned through an ArticlePointer.  The <code> articleId </code>
600      * field of the ArticlePointer cannot always be trusted because some
601      * NNTP servers do not correctly follow the RFC 977 reply format.
602      * <p>
603      * A DotTerminatedMessageReader is returned from which the article can
604      * be read.  If the article does not exist, null is returned.
605      * <p>
606      * You must not issue any commands to the NNTP server (i.e., call any
607      * other methods) until you finish reading the message from the returned
608      * Reader instance.
609      * The NNTP protocol uses the same stream for issuing commands as it does
610      * for returning results.  Therefore the returned Reader actually reads
611      * directly from the NNTP connection.  After the end of message has been
612      * reached, new commands can be executed and their replies read.  If
613      * you do not follow these requirements, your program will not work
614      * properly.
615      * <p>
616      * @param articleNumber  The number of the the article whose body is
617      *     being retrieved.
618      * @param pointer    A parameter through which to return the article's
619      *   number and unique id.  The articleId field cannot always be trusted
620      *   because of server deviations from RFC 977 reply formats.  You may
621      *   set this parameter to null if you do not desire to retrieve the
622      *   returned article information.
623      * @return A DotTerminatedMessageReader instance from which the article
624      *         body can be read.  null if the article does not exist.
625      * @exception NNTPConnectionClosedException
626      *      If the NNTP server prematurely closes the connection as a result
627      *      of the client being idle or some other reason causing the server
628      *      to send NNTP reply code 400.  This exception may be caught either
629      *      as an IOException or independently as itself.
630      * @exception IOException  If an I/O error occurs while either sending a
631      *      command to the server or receiving a reply from the server.
632      ***/
633     public Reader retrieveArticleBody(int articleNumber,
634                                       ArticlePointer pointer)
635     throws IOException
636     {
637         return __retrieve(NNTPCommand.BODY, articleNumber, pointer);
638     }
639 
640 
641     /*** Same as <code> retrieveArticleBody(articleNumber, null) </code> ***/
642     public Reader retrieveArticleBody(int articleNumber) throws IOException
643     {
644         return retrieveArticleBody(articleNumber, null);
645     }
646 
647 
648     /***
649      * Select the specified newsgroup to be the target of for future article
650      * retrieval and posting operations.  Also return the newsgroup
651      * information contained in the server reply through the info parameter.
652      * <p>
653      * @param newsgroup  The newsgroup to select.
654      * @param info  A parameter through which the newsgroup information of
655      *      the selected newsgroup contained in the server reply is returned.
656      *      Set this to null if you do not desire this information.
657      * @return True if the newsgroup exists and was selected, false otherwise.
658      * @exception NNTPConnectionClosedException
659      *      If the NNTP server prematurely closes the connection as a result
660      *      of the client being idle or some other reason causing the server
661      *      to send NNTP reply code 400.  This exception may be caught either
662      *      as an IOException or independently as itself.
663      * @exception IOException  If an I/O error occurs while either sending a
664      *      command to the server or receiving a reply from the server.
665      ***/
666     public boolean selectNewsgroup(String newsgroup, NewsgroupInfo info)
667     throws IOException
668     {
669         if (!NNTPReply.isPositiveCompletion(group(newsgroup)))
670             return false;
671 
672         if (info != null)
673             __parseGroupReply(getReplyString(), info);
674 
675         return true;
676     }
677 
678     /*** Same as <code> selectNewsgroup(newsgroup, null) </code> ***/
679     public boolean selectNewsgroup(String newsgroup) throws IOException
680     {
681         return selectNewsgroup(newsgroup, null);
682     }
683 
684     /***
685      * List the command help from the server.
686      * <p>
687      * @return The sever help information.
688      * @exception NNTPConnectionClosedException
689      *      If the NNTP server prematurely closes the connection as a result
690      *      of the client being idle or some other reason causing the server
691      *      to send NNTP reply code 400.  This exception may be caught either
692      *      as an IOException or independently as itself.
693      * @exception IOException  If an I/O error occurs while either sending a
694      *      command to the server or receiving a reply from the server.
695      ***/
696     public String listHelp() throws IOException
697     {
698         StringWriter help;
699         Reader reader;
700 
701         if (!NNTPReply.isInformational(help()))
702             return null;
703 
704         help = new StringWriter();
705         reader = new DotTerminatedMessageReader(_reader_);
706         Util.copyReader(reader, help);
707         reader.close();
708         help.close();
709         return help.toString();
710     }
711 
712 
713     /***
714      * Select an article by its unique identifier (including enclosing
715      * &lt and &gt) and return its article number and id through the
716      * pointer parameter.  This is achieved through the STAT command.
717      * According to RFC 977, this will NOT set the current article pointer
718      * on the server.  To do that, you must reference the article by its
719      * number.
720      * <p>
721      * @param articleId  The unique article identifier of the article that
722      *    is being selectedd.  If this parameter is null, the
723      *    body of the current article is selected
724      * @param pointer    A parameter through which to return the article's
725      *   number and unique id.  The articleId field cannot always be trusted
726      *   because of server deviations from RFC 977 reply formats.  You may
727      *   set this parameter to null if you do not desire to retrieve the
728      *   returned article information.
729      * @return True if successful, false if not.
730      * @exception NNTPConnectionClosedException
731      *      If the NNTP server prematurely closes the connection as a result
732      *      of the client being idle or some other reason causing the server
733      *      to send NNTP reply code 400.  This exception may be caught either
734      *      as an IOException or independently as itself.
735      * @exception IOException  If an I/O error occurs while either sending a
736      *      command to the server or receiving a reply from the server.
737      ***/
738     public boolean selectArticle(String articleId, ArticlePointer pointer)
739     throws IOException
740     {
741         if (articleId != null)
742         {
743             if (!NNTPReply.isPositiveCompletion(stat(articleId)))
744                 return false;
745         }
746         else
747         {
748             if (!NNTPReply.isPositiveCompletion(stat()))
749                 return false;
750         }
751 
752         if (pointer != null)
753             __parseArticlePointer(getReplyString(), pointer);
754 
755         return true;
756     }
757 
758     /**** Same as <code> selectArticle(articleId, null) </code> ***/
759     public boolean selectArticle(String articleId) throws IOException
760     {
761         return selectArticle(articleId, null);
762     }
763 
764     /****
765      * Same as <code> selectArticle(null, articleId) </code>.  Useful
766      * for retrieving the current article number.
767      ***/
768     public boolean selectArticle(ArticlePointer pointer) throws IOException
769     {
770         return selectArticle(null, pointer);
771     }
772 
773 
774     /***
775      * Select an article in the currently selected newsgroup by its number.
776      * and return its article number and id through the
777      * pointer parameter.  This is achieved through the STAT command.
778      * According to RFC 977, this WILL set the current article pointer
779      * on the server.  Use this command to select an article before retrieving
780      * it, or to obtain an article's unique identifier given its number.
781      * <p>
782      * @param articleNumber The number of the article to select from the
783      *       currently selected newsgroup.
784      * @param pointer    A parameter through which to return the article's
785      *   number and unique id.  Although the articleId field cannot always
786      *   be trusted because of server deviations from RFC 977 reply formats,
787      *   we haven't found a server that misformats this information in response
788      *   to this particular command.  You may set this parameter to null if
789      *   you do not desire to retrieve the returned article information.
790      * @return True if successful, false if not.
791      * @exception NNTPConnectionClosedException
792      *      If the NNTP server prematurely closes the connection as a result
793      *      of the client being idle or some other reason causing the server
794      *      to send NNTP reply code 400.  This exception may be caught either
795      *      as an IOException or independently as itself.
796      * @exception IOException  If an I/O error occurs while either sending a
797      *      command to the server or receiving a reply from the server.
798      ***/
799     public boolean selectArticle(int articleNumber, ArticlePointer pointer)
800     throws IOException
801     {
802         if (!NNTPReply.isPositiveCompletion(stat(articleNumber)))
803             return false;
804 
805         if (pointer != null)
806             __parseArticlePointer(getReplyString(), pointer);
807 
808         return true;
809     }
810 
811 
812     /*** Same as <code> selectArticle(articleNumber, null) </code> ***/
813     public boolean selectArticle(int articleNumber) throws IOException
814     {
815         return selectArticle(articleNumber, null);
816     }
817 
818 
819     /***
820      * Select the article preceeding the currently selected article in the
821      * currently selected newsgroup and return its number and unique id
822      * through the pointer parameter.  Because of deviating server
823      * implementations, the articleId information cannot be trusted.  To
824      * obtain the article identifier, issue a
825      * <code> selectArticle(pointer.articleNumber, pointer) </code> immediately
826      * afterward.
827      * <p>
828      * @param pointer    A parameter through which to return the article's
829      *   number and unique id.  The articleId field cannot always be trusted
830      *   because of server deviations from RFC 977 reply formats.  You may
831      *   set this parameter to null if you do not desire to retrieve the
832      *   returned article information.
833      * @return True if successful, false if not (e.g., there is no previous
834      *     article).
835      * @exception NNTPConnectionClosedException
836      *      If the NNTP server prematurely closes the connection as a result
837      *      of the client being idle or some other reason causing the server
838      *      to send NNTP reply code 400.  This exception may be caught either
839      *      as an IOException or independently as itself.
840      * @exception IOException  If an I/O error occurs while either sending a
841      *      command to the server or receiving a reply from the server.
842      ***/
843     public boolean selectPreviousArticle(ArticlePointer pointer)
844     throws IOException
845     {
846         if (!NNTPReply.isPositiveCompletion(last()))
847             return false;
848 
849         if (pointer != null)
850             __parseArticlePointer(getReplyString(), pointer);
851 
852         return true;
853     }
854 
855     /*** Same as <code> selectPreviousArticle(null) </code> ***/
856     public boolean selectPreviousArticle() throws IOException
857     {
858         return selectPreviousArticle(null);
859     }
860 
861 
862     /***
863      * Select the article following the currently selected article in the
864      * currently selected newsgroup and return its number and unique id
865      * through the pointer parameter.  Because of deviating server
866      * implementations, the articleId information cannot be trusted.  To
867      * obtain the article identifier, issue a
868      * <code> selectArticle(pointer.articleNumber, pointer) </code> immediately
869      * afterward.
870      * <p>
871      * @param pointer    A parameter through which to return the article's
872      *   number and unique id.  The articleId field cannot always be trusted
873      *   because of server deviations from RFC 977 reply formats.  You may
874      *   set this parameter to null if you do not desire to retrieve the
875      *   returned article information.
876      * @return True if successful, false if not (e.g., there is no following
877      *         article).
878      * @exception NNTPConnectionClosedException
879      *      If the NNTP server prematurely closes the connection as a result
880      *      of the client being idle or some other reason causing the server
881      *      to send NNTP reply code 400.  This exception may be caught either
882      *      as an IOException or independently as itself.
883      * @exception IOException  If an I/O error occurs while either sending a
884      *      command to the server or receiving a reply from the server.
885      ***/
886     public boolean selectNextArticle(ArticlePointer pointer) throws IOException
887     {
888         if (!NNTPReply.isPositiveCompletion(next()))
889             return false;
890 
891         if (pointer != null)
892             __parseArticlePointer(getReplyString(), pointer);
893 
894         return true;
895     }
896 
897 
898     /*** Same as <code> selectNextArticle(null) </code> ***/
899     public boolean selectNextArticle() throws IOException
900     {
901         return selectNextArticle(null);
902     }
903 
904 
905     /***
906      * List all newsgroups served by the NNTP server.  If no newsgroups
907      * are served, a zero length array will be returned.  If the command
908      * fails, null will be returned.
909      * <p>
910      * @return An array of NewsgroupInfo instances containing the information
911      *    for each newsgroup served by the NNTP server.   If no newsgroups
912      *    are served, a zero length array will be returned.  If the command
913      *    fails, null will be returned.
914      * @exception NNTPConnectionClosedException
915      *      If the NNTP server prematurely closes the connection as a result
916      *      of the client being idle or some other reason causing the server
917      *      to send NNTP reply code 400.  This exception may be caught either
918      *      as an IOException or independently as itself.
919      * @exception IOException  If an I/O error occurs while either sending a
920      *      command to the server or receiving a reply from the server.
921      ***/
922     public NewsgroupInfo[] listNewsgroups() throws IOException
923     {
924         if (!NNTPReply.isPositiveCompletion(list()))
925             return null;
926 
927         return __readNewsgroupListing();
928     }
929 
930     /**
931      * An overloaded listNewsgroups() command that allows us to
932      * specify with a pattern what groups we want to list. Wraps the
933      * LIST ACTIVE command.
934      * <p>
935      * @param wildmat a pseudo-regex pattern (cf. RFC 2980)
936      * @return An array of NewsgroupInfo instances containing the information
937      *    for each newsgroup served by the NNTP server corresponding to the
938      *    supplied pattern.   If no such newsgroups are served, a zero length
939      *    array will be returned.  If the command fails, null will be returned.
940      * @throws IOException
941      */
942     public NewsgroupInfo[] listNewsgroups(String wildmat) throws IOException
943     {
944         if(!NNTPReply.isPositiveCompletion(listActive(wildmat)))
945             return null;
946         return __readNewsgroupListing();
947     }
948 
949 
950     /***
951      * List all new newsgroups added to the NNTP server since a particular
952      * date subject to the conditions of the specified query.  If no new
953      * newsgroups were added, a zero length array will be returned.  If the
954      * command fails, null will be returned.
955      * <p>
956      * @param query  The query restricting how to search for new newsgroups.
957      * @return An array of NewsgroupInfo instances containing the information
958      *    for each new newsgroup added to the NNTP server.   If no newsgroups
959      *    were added, a zero length array will be returned.  If the command
960      *    fails, null will be returned.
961      * @exception NNTPConnectionClosedException
962      *      If the NNTP server prematurely closes the connection as a result
963      *      of the client being idle or some other reason causing the server
964      *      to send NNTP reply code 400.  This exception may be caught either
965      *      as an IOException or independently as itself.
966      * @exception IOException  If an I/O error occurs while either sending a
967      *      command to the server or receiving a reply from the server.
968      ***/
969     public NewsgroupInfo[] listNewNewsgroups(NewGroupsOrNewsQuery query)
970     throws IOException
971     {
972         if (!NNTPReply.isPositiveCompletion(newgroups(
973                                                 query.getDate(), query.getTime(),
974                                                 query.isGMT(), query.getDistributions())))
975             return null;
976 
977         return __readNewsgroupListing();
978     }
979 
980 
981     /***
982      * List all new articles added to the NNTP server since a particular
983      * date subject to the conditions of the specified query.  If no new
984      * new news is found, a zero length array will be returned.  If the
985      * command fails, null will be returned.  You must add at least one
986      * newsgroup to the query, else the command will fail.  Each String
987      * in the returned array is a unique message identifier including the
988      * enclosing &lt and &gt.
989      * <p>
990      * @param query  The query restricting how to search for new news.  You
991      *    must add at least one newsgroup to the query.
992      * @return An array of String instances containing the unique message
993      *    identifiers for each new article added to the NNTP server.  If no
994      *    new news is found, a zero length array will be returned.  If the
995      *    command fails, null will be returned.
996      * @exception NNTPConnectionClosedException
997      *      If the NNTP server prematurely closes the connection as a result
998      *      of the client being idle or some other reason causing the server
999      *      to send NNTP reply code 400.  This exception may be caught either
1000     *      as an IOException or independently as itself.
1001     * @exception IOException  If an I/O error occurs while either sending a
1002     *      command to the server or receiving a reply from the server.
1003     ***/
1004    public String[] listNewNews(NewGroupsOrNewsQuery query)
1005    throws IOException
1006    {
1007        int size;
1008        String line;
1009        Vector list;
1010        String[] result;
1011        BufferedReader reader;
1012
1013        if (!NNTPReply.isPositiveCompletion(newnews(
1014                                                query.getNewsgroups(), query.getDate(), query.getTime(),
1015                                                query.isGMT(), query.getDistributions())))
1016            return null;
1017
1018        list = new Vector();
1019        reader = new BufferedReader(new DotTerminatedMessageReader(_reader_));
1020
1021        while ((line = reader.readLine()) != null)
1022            list.addElement(line);
1023
1024        size = list.size();
1025
1026        if (size < 1)
1027            return new String[0];
1028
1029        result = new String[size];
1030        list.copyInto(result);
1031
1032        return result;
1033    }
1034
1035    /***
1036     * There are a few NNTPClient methods that do not complete the
1037     * entire sequence of NNTP commands to complete a transaction.  These
1038     * commands require some action by the programmer after the reception
1039     * of a positive preliminary command.  After the programmer's code
1040     * completes its actions, it must call this method to receive
1041     * the completion reply from the server and verify the success of the
1042     * entire transaction.
1043     * <p>
1044     * For example
1045     * <pre>
1046     * writer = client.postArticle();
1047     * if(writer == null) // failure
1048     *   return false;
1049     * header = new SimpleNNTPHeader("foobar@foo.com", "Just testing");
1050     * header.addNewsgroup("alt.test");
1051     * writer.write(header.toString());
1052     * writer.write("This is just a test");
1053     * writer.close();
1054     * if(!client.completePendingCommand()) // failure
1055     *   return false;
1056     * </pre>
1057     * <p>
1058     * @return True if successfully completed, false if not.
1059     * @exception NNTPConnectionClosedException
1060     *      If the NNTP server prematurely closes the connection as a result
1061     *      of the client being idle or some other reason causing the server
1062     *      to send NNTP reply code 400.  This exception may be caught either
1063     *      as an IOException or independently as itself.
1064     * @exception IOException  If an I/O error occurs while either sending a
1065     *      command to the server or receiving a reply from the server.
1066     ***/
1067    public boolean completePendingCommand() throws IOException
1068    {
1069        return NNTPReply.isPositiveCompletion(getReply());
1070    }
1071
1072    /***
1073     * Post an article to the NNTP server.  This method returns a
1074     * DotTerminatedMessageWriter instance to which the article can be
1075     * written.  Null is returned if the posting attempt fails.  You
1076     * should check {@link NNTP#isAllowedToPost isAllowedToPost() }
1077     *  before trying to post.  However, a posting
1078     * attempt can fail due to malformed headers.
1079     * <p>
1080     * You must not issue any commands to the NNTP server (i.e., call any
1081     * (other methods) until you finish writing to the returned Writer
1082     * instance and close it.  The NNTP protocol uses the same stream for
1083     * issuing commands as it does for returning results.  Therefore the
1084     * returned Writer actually writes directly to the NNTP connection.
1085     * After you close the writer, you can execute new commands.  If you
1086     * do not follow these requirements your program will not work properly.
1087     * <p>
1088     * Different NNTP servers will require different header formats, but
1089     * you can use the provided
1090     * {@link org.apache.commons.net.nntp.SimpleNNTPHeader}
1091     * class to construct the bare minimum acceptable header for most
1092     * news readers.  To construct more complicated headers you should
1093     * refer to RFC 822.  When the Java Mail API is finalized, you will be
1094     * able to use it to compose fully compliant Internet text messages.
1095     * The DotTerminatedMessageWriter takes care of doubling line-leading
1096     * dots and ending the message with a single dot upon closing, so all
1097     * you have to worry about is writing the header and the message.
1098     * <p>
1099     * Upon closing the returned Writer, you need to call
1100     * {@link #completePendingCommand  completePendingCommand() }
1101     * to finalize the posting and verify its success or failure from
1102     * the server reply.
1103     * <p>
1104     * @return A DotTerminatedMessageWriter to which the article (including
1105     *      header) can be written.  Returns null if the command fails.
1106     * @exception IOException  If an I/O error occurs while either sending a
1107     *      command to the server or receiving a reply from the server.
1108     ***/
1109
1110    public Writer postArticle() throws IOException
1111    {
1112        if (!NNTPReply.isPositiveIntermediate(post()))
1113            return null;
1114
1115        return new DotTerminatedMessageWriter(_writer_);
1116    }
1117
1118
1119    public Writer forwardArticle(String articleId) throws IOException
1120    {
1121        if (!NNTPReply.isPositiveIntermediate(ihave(articleId)))
1122            return null;
1123
1124        return new DotTerminatedMessageWriter(_writer_);
1125    }
1126
1127
1128    /***
1129     * Logs out of the news server gracefully by sending the QUIT command.
1130     * However, you must still disconnect from the server before you can open
1131     * a new connection.
1132     * <p>
1133     * @return True if successfully completed, false if not.
1134     * @exception IOException  If an I/O error occurs while either sending a
1135     *      command to the server or receiving a reply from the server.
1136     ***/
1137    public boolean logout() throws IOException
1138    {
1139        return NNTPReply.isPositiveCompletion(quit());
1140    }
1141
1142
1143    /**
1144     * Log into a news server by sending the AUTHINFO USER/AUTHINFO
1145     * PASS command sequence. This is usually sent in response to a
1146     * 480 reply code from the NNTP server.
1147     * <p>
1148     * @param username a valid username
1149     * @param password the corresponding password
1150     * @return True for successful login, false for a failure
1151     * @throws IOException
1152     */
1153    public boolean authenticate(String username, String password)
1154        throws IOException
1155    {
1156        int replyCode = authinfoUser(username);
1157
1158        if (replyCode == NNTPReply.MORE_AUTH_INFO_REQUIRED)
1159            {
1160                replyCode = authinfoPass(password);
1161
1162                if (replyCode == NNTPReply.AUTHENTICATION_ACCEPTED)
1163                    {
1164                        _isAllowedToPost = true;
1165                        return true;
1166                    }
1167            }
1168        return false;
1169    }
1170
1171    /***
1172     * Private implementation of XOVER functionality.
1173     *
1174     * See {@link NNTP#xover}
1175     * for legal agument formats. Alternatively, read RFC 2980 :-)
1176     * <p>
1177     * @param articleRange
1178     * @return Returns a DotTerminatedMessageReader if successful, null
1179     *         otherwise
1180     * @exception IOException
1181     */
1182    private Reader __retrieveArticleInfo(String articleRange)
1183        throws IOException
1184    {
1185        if (!NNTPReply.isPositiveCompletion(xover(articleRange)))
1186            return null;
1187
1188        return new DotTerminatedMessageReader(_reader_);
1189    }
1190
1191    /**
1192     * Return article headers for a specified post.
1193     * <p>
1194     * @param articleNumber the article to retrieve headers for
1195     * @return a DotTerminatedReader if successful, null otherwise
1196     * @throws IOException
1197     */
1198    public Reader retrieveArticleInfo(int articleNumber) throws IOException
1199    {
1200        return __retrieveArticleInfo(Integer.toString(articleNumber));
1201    }
1202
1203    /**
1204     * Return article headers for all articles between lowArticleNumber
1205     * and highArticleNumber, inclusively.
1206     * <p>
1207     * @param lowArticleNumber
1208     * @param highArticleNumber
1209     * @return a DotTerminatedReader if successful, null otherwise
1210     * @throws IOException
1211     */
1212    public Reader retrieveArticleInfo(int lowArticleNumber,
1213                                      int highArticleNumber)
1214        throws IOException
1215    {
1216        return
1217            __retrieveArticleInfo(new String(lowArticleNumber + "-" +
1218                                             highArticleNumber));
1219    }
1220
1221    /***
1222     * Private implementation of XHDR functionality.
1223     *
1224     * See {@link NNTP#xhdr}
1225     * for legal agument formats. Alternatively, read RFC 1036.
1226     * <p>
1227     * @param header
1228     * @param articleRange
1229     * @return Returns a DotTerminatedMessageReader if successful, null
1230     *         otherwise
1231     * @exception IOException
1232     */
1233    private Reader __retrieveHeader(String header, String articleRange)
1234        throws IOException
1235    {
1236        if (!NNTPReply.isPositiveCompletion(xhdr(header, articleRange)))
1237            return null;
1238
1239        return new DotTerminatedMessageReader(_reader_);
1240    }
1241
1242    /**
1243     * Return an article header for a specified post.
1244     * <p>
1245     * @param header the header to retrieve
1246     * @param articleNumber the article to retrieve the header for
1247     * @return a DotTerminatedReader if successful, null otherwise
1248     * @throws IOException
1249     */
1250    public Reader retrieveHeader(String header, int articleNumber)
1251        throws IOException
1252    {
1253        return __retrieveHeader(header, Integer.toString(articleNumber));
1254    }
1255
1256    /**
1257     * Return an article header for all articles between lowArticleNumber
1258     * and highArticleNumber, inclusively.
1259     * <p>
1260     * @param header
1261     * @param lowArticleNumber
1262     * @param highArticleNumber
1263     * @return a DotTerminatedReader if successful, null otherwise
1264     * @throws IOException
1265     */
1266    public Reader retrieveHeader(String header, int lowArticleNumber,
1267                                 int highArticleNumber)
1268        throws IOException
1269    {
1270        return
1271            __retrieveHeader(header,
1272                             new String(lowArticleNumber + "-" +
1273                                        highArticleNumber));
1274    }
1275}
1276
1277
1278/* Emacs configuration
1279 * Local variables:        **
1280 * mode:             java  **
1281 * c-basic-offset:   4     **
1282 * indent-tabs-mode: nil   **
1283 * End:                    **
1284 */