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