54 |
* @author <a hef='mailto:dog@gnu.org'>Chris Burdess</a> |
* @author <a hef='mailto:dog@gnu.org'>Chris Burdess</a> |
55 |
* @version $Revision$ $Date$ |
* @version $Revision$ $Date$ |
56 |
*/ |
*/ |
57 |
public class NNTPConnection |
public class NNTPConnection implements NNTPConstants |
|
implements NNTPConstants |
|
58 |
{ |
{ |
59 |
|
|
60 |
/** |
/** |
61 |
* The default NNTP port. |
* The default NNTP port. |
62 |
*/ |
*/ |
63 |
public static final int DEFAULT_PORT = 119; |
public static final int DEFAULT_PORT = 119; |
64 |
|
|
65 |
/** |
/** |
66 |
* The hostname of the host we are connected to. |
* The hostname of the host we are connected to. |
67 |
*/ |
*/ |
92 |
*/ |
*/ |
93 |
protected LineInputStream in; |
protected LineInputStream in; |
94 |
|
|
95 |
/** |
/** |
96 |
* The socket output stream. |
* The socket output stream. |
97 |
*/ |
*/ |
98 |
protected OutputStream out; |
protected OutputStream out; |
99 |
|
|
100 |
/** |
/** |
101 |
* Whether the host permits posting of articles. |
* Whether the host permits posting of articles. |
118 |
protected boolean debug; |
protected boolean debug; |
119 |
|
|
120 |
private static final String DOT = "."; |
private static final String DOT = "."; |
121 |
private static final String US_ASCII = "US-ASCII"; |
private static final String US_ASCII = "US-ASCII"; |
122 |
|
|
123 |
/** |
/** |
124 |
* Creates a new connection object. |
* Creates a new connection object. |
125 |
* @param hostname the hostname or IP address of the news server |
* @param hostname the hostname or IP address of the news server |
126 |
*/ |
*/ |
127 |
public NNTPConnection(String hostname) |
public NNTPConnection(String hostname) throws IOException |
|
throws IOException |
|
128 |
{ |
{ |
129 |
this(hostname, DEFAULT_PORT, null, null, false); |
this(hostname, DEFAULT_PORT, null, null, false); |
130 |
} |
} |
131 |
|
|
132 |
/** |
/** |
133 |
* Creates a new connection object. |
* Creates a new connection object. |
134 |
* @param hostname the hostname or IP address of the news server |
* @param hostname the hostname or IP address of the news server |
135 |
* @param port the port to connect to |
* @param port the port to connect to |
136 |
*/ |
*/ |
137 |
public NNTPConnection(String hostname, |
public NNTPConnection(String hostname, int port) throws IOException |
|
int port) |
|
|
throws IOException |
|
138 |
{ |
{ |
139 |
this(hostname, port, null, null, false); |
this(hostname, port, null, null, false); |
140 |
} |
} |
141 |
|
|
142 |
/** |
/** |
143 |
* Creates a new connection object. |
* Creates a new connection object. |
144 |
* @param hostname the hostname or IP address of the news server |
* @param hostname the hostname or IP address of the news server |
146 |
* @param password the password if authentication is required |
* @param password the password if authentication is required |
147 |
*/ |
*/ |
148 |
public NNTPConnection(String hostname, |
public NNTPConnection(String hostname, |
149 |
String username, |
String username, String password) throws IOException |
|
String password) |
|
|
throws IOException |
|
150 |
{ |
{ |
151 |
this(hostname, DEFAULT_PORT, username, password, false); |
this(hostname, DEFAULT_PORT, username, password, false); |
152 |
} |
} |
153 |
|
|
154 |
/** |
/** |
155 |
* Creates a new connection object. |
* Creates a new connection object. |
156 |
* @param hostname the hostname or IP address of the news server |
* @param hostname the hostname or IP address of the news server |
159 |
* @param password the password if authentication is required |
* @param password the password if authentication is required |
160 |
*/ |
*/ |
161 |
public NNTPConnection(String hostname, |
public NNTPConnection(String hostname, |
162 |
int port, |
int port, |
163 |
String username, |
String username, String password) throws IOException |
|
String password) |
|
|
throws IOException |
|
164 |
{ |
{ |
165 |
this(hostname, port, username, password, false); |
this(hostname, port, username, password, false); |
166 |
} |
} |
167 |
|
|
168 |
/** |
/** |
169 |
* Creates a new connection object. |
* Creates a new connection object. |
170 |
* @param hostname the hostname or IP address of the news server |
* @param hostname the hostname or IP address of the news server |
174 |
* @param debug whether to use debugging |
* @param debug whether to use debugging |
175 |
*/ |
*/ |
176 |
public NNTPConnection(String hostname, |
public NNTPConnection(String hostname, |
177 |
int port, |
int port, |
178 |
String username, |
String username, |
179 |
String password, |
String password, boolean debug) throws IOException |
|
boolean debug) |
|
|
throws IOException |
|
180 |
{ |
{ |
181 |
if (port<0) |
if (port < 0) |
182 |
port = DEFAULT_PORT; |
port = DEFAULT_PORT; |
183 |
|
|
184 |
this.hostname = hostname; |
this.hostname = hostname; |
185 |
this.port = port; |
this.port = port; |
186 |
this.username = username; |
this.username = username; |
189 |
|
|
190 |
// Set up the socket and streams |
// Set up the socket and streams |
191 |
socket = new Socket(hostname, port); |
socket = new Socket(hostname, port); |
192 |
InputStream in = socket.getInputStream(); |
InputStream in = socket.getInputStream(); |
193 |
in = new CRLFInputStream(in); |
in = new CRLFInputStream(in); |
194 |
this.in = new LineInputStream(in); |
this.in = new LineInputStream(in); |
195 |
OutputStream out = socket.getOutputStream(); |
OutputStream out = socket.getOutputStream(); |
196 |
this.out = new CRLFOutputStream(out); |
this.out = new CRLFOutputStream(out); |
197 |
|
|
198 |
// Read the welcome message (RFC977:2.4.3) |
// Read the welcome message (RFC977:2.4.3) |
199 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
200 |
switch (response.status) |
switch (response.status) |
201 |
{ |
{ |
202 |
case POSTING_ALLOWED: |
case POSTING_ALLOWED: |
203 |
canPost = true; |
canPost = true; |
204 |
case NO_POSTING_ALLOWED: |
case NO_POSTING_ALLOWED:welcome = response.getMessage(); |
205 |
welcome = response.getMessage(); |
break; |
206 |
break; |
default:throw new NNTPException(response); |
|
default: |
|
|
throw new NNTPException(response); |
|
207 |
} |
} |
208 |
|
|
209 |
} |
} |
238 |
/* |
/* |
239 |
* Parse the specfied NNTP date text. |
* Parse the specfied NNTP date text. |
240 |
*/ |
*/ |
241 |
Date parseDate(String text) |
Date parseDate(String text) throws ParseException |
|
throws ParseException |
|
242 |
{ |
{ |
243 |
DateFormat df = new SimpleDateFormat("yyMMdd HHmmss 'GMT'"); |
DateFormat df = new SimpleDateFormat("yyMMdd HHmmss 'GMT'"); |
244 |
return df.parse(text); |
return df.parse(text); |
245 |
} |
} |
246 |
|
|
247 |
// RFC977:3.1 The ARTICLE, BODY, HEAD, and STAT commands |
// RFC977:3.1 The ARTICLE, BODY, HEAD, and STAT commands |
248 |
|
|
249 |
/** |
/** |
250 |
* Send an article retrieval request to the server. |
* Send an article retrieval request to the server. |
251 |
* @param articleNumber the article number of the article to retrieve |
* @param articleNumber the article number of the article to retrieve |
253 |
* message-id, and an iterator over the lines of the article header and |
* message-id, and an iterator over the lines of the article header and |
254 |
* body, separated by an empty line |
* body, separated by an empty line |
255 |
*/ |
*/ |
256 |
public ArticleResponse article(int articleNumber) |
public ArticleResponse article(int articleNumber) throws IOException |
|
throws IOException |
|
257 |
{ |
{ |
258 |
return articleImpl(ARTICLE, Integer.toString(articleNumber)); |
return articleImpl(ARTICLE, Integer.toString(articleNumber)); |
259 |
} |
} |
265 |
* message-id, and an iterator over the lines of the article header and |
* message-id, and an iterator over the lines of the article header and |
266 |
* body, separated by an empty line |
* body, separated by an empty line |
267 |
*/ |
*/ |
268 |
public ArticleResponse article(String messageId) |
public ArticleResponse article(String messageId) throws IOException |
|
throws IOException |
|
269 |
{ |
{ |
270 |
return articleImpl(ARTICLE, messageId); |
return articleImpl(ARTICLE, messageId); |
271 |
} |
} |
272 |
|
|
273 |
/** |
/** |
274 |
* Send an article head retrieval request to the server. |
* Send an article head retrieval request to the server. |
275 |
* @param articleNumber the article number of the article to head |
* @param articleNumber the article number of the article to head |
276 |
* @return an article response consisting of the article number and |
* @return an article response consisting of the article number and |
277 |
* message-id, and an iterator over the lines of the article header |
* message-id, and an iterator over the lines of the article header |
278 |
*/ |
*/ |
279 |
public ArticleResponse head(int articleNumber) |
public ArticleResponse head(int articleNumber) throws IOException |
|
throws IOException |
|
280 |
{ |
{ |
281 |
return articleImpl(HEAD, Integer.toString(articleNumber)); |
return articleImpl(HEAD, Integer.toString(articleNumber)); |
282 |
} |
} |
287 |
* @return an article response consisting of the article number and |
* @return an article response consisting of the article number and |
288 |
* message-id, and an iterator over the lines of the article header |
* message-id, and an iterator over the lines of the article header |
289 |
*/ |
*/ |
290 |
public ArticleResponse head(String messageId) |
public ArticleResponse head(String messageId) throws IOException |
|
throws IOException |
|
291 |
{ |
{ |
292 |
return articleImpl(HEAD, messageId); |
return articleImpl(HEAD, messageId); |
293 |
} |
} |
298 |
* @return an article response consisting of the article number and |
* @return an article response consisting of the article number and |
299 |
* message-id, and an iterator over the lines of the article body |
* message-id, and an iterator over the lines of the article body |
300 |
*/ |
*/ |
301 |
public ArticleResponse body(int articleNumber) |
public ArticleResponse body(int articleNumber) throws IOException |
|
throws IOException |
|
302 |
{ |
{ |
303 |
return articleImpl(BODY, Integer.toString(articleNumber)); |
return articleImpl(BODY, Integer.toString(articleNumber)); |
304 |
} |
} |
309 |
* @return an article response consisting of the article number and |
* @return an article response consisting of the article number and |
310 |
* message-id, and an iterator over the lines of the article body |
* message-id, and an iterator over the lines of the article body |
311 |
*/ |
*/ |
312 |
public ArticleResponse body(String messageId) |
public ArticleResponse body(String messageId) throws IOException |
|
throws IOException |
|
313 |
{ |
{ |
314 |
return articleImpl(BODY, messageId); |
return articleImpl(BODY, messageId); |
315 |
} |
} |
320 |
* @return an article response consisting of the article number and |
* @return an article response consisting of the article number and |
321 |
* message-id |
* message-id |
322 |
*/ |
*/ |
323 |
public ArticleResponse stat(int articleNumber) |
public ArticleResponse stat(int articleNumber) throws IOException |
|
throws IOException |
|
324 |
{ |
{ |
325 |
return articleImpl(STAT, Integer.toString(articleNumber)); |
return articleImpl(STAT, Integer.toString(articleNumber)); |
326 |
} |
} |
331 |
* @return an article response consisting of the article number and |
* @return an article response consisting of the article number and |
332 |
* message-id |
* message-id |
333 |
*/ |
*/ |
334 |
public ArticleResponse stat(String messageId) |
public ArticleResponse stat(String messageId) throws IOException |
|
throws IOException |
|
335 |
{ |
{ |
336 |
return articleImpl(STAT, messageId); |
return articleImpl(STAT, messageId); |
337 |
} |
} |
344 |
protected ArticleResponse articleImpl(String command, String messageId) |
protected ArticleResponse articleImpl(String command, String messageId) |
345 |
throws IOException |
throws IOException |
346 |
{ |
{ |
347 |
if (messageId!=null) |
if (messageId != null) |
348 |
{ |
{ |
349 |
StringBuffer line = new StringBuffer(command); |
StringBuffer line = new StringBuffer(command); |
350 |
line.append(' '); |
line.append(' '); |
351 |
line.append(messageId); |
line.append(messageId); |
352 |
send(line.toString()); |
send(line.toString()); |
353 |
} |
} |
354 |
else |
else |
355 |
send(command); |
send(command); |
356 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
357 |
switch (response.status) |
switch (response.status) |
358 |
{ |
{ |
359 |
case ARTICLE_FOLLOWS: |
case ARTICLE_FOLLOWS: |
360 |
case HEAD_FOLLOWS: |
case HEAD_FOLLOWS: |
361 |
case BODY_FOLLOWS: |
case BODY_FOLLOWS: |
362 |
ArticleResponse aresponse = (ArticleResponse)response; |
ArticleResponse aresponse = (ArticleResponse) response; |
363 |
ArticleStream astream = new ArticleStream(new MessageInputStream(in)); |
ArticleStream astream = new ArticleStream(new MessageInputStream(in)); |
364 |
pendingData = astream; |
pendingData = astream; |
365 |
aresponse.in = astream; |
aresponse.in = astream; |
366 |
return aresponse; |
return aresponse; |
367 |
case ARTICLE_RETRIEVED: |
case ARTICLE_RETRIEVED: |
368 |
return (ArticleResponse)response; |
return (ArticleResponse) response; |
369 |
default: |
default: |
370 |
// NO_GROUP_SELECTED |
// NO_GROUP_SELECTED |
371 |
// NO_ARTICLE_SELECTED |
// NO_ARTICLE_SELECTED |
372 |
// NO_SUCH_ARTICLE_NUMBER |
// NO_SUCH_ARTICLE_NUMBER |
373 |
// NO_SUCH_ARTICLE |
// NO_SUCH_ARTICLE |
374 |
// NO_PREVIOUS_ARTICLE |
// NO_PREVIOUS_ARTICLE |
375 |
// NO_NEXT_ARTICLE |
// NO_NEXT_ARTICLE |
376 |
throw new NNTPException(response); |
throw new NNTPException(response); |
377 |
} |
} |
378 |
} |
} |
379 |
|
|
380 |
// RFC977:3.2 The GROUP command |
// RFC977:3.2 The GROUP command |
381 |
|
|
382 |
/** |
/** |
383 |
* Send a group selection command to the server. |
* Send a group selection command to the server. |
384 |
* Returns a group status response. |
* Returns a group status response. |
385 |
* @param name the name of the group to select |
* @param name the name of the group to select |
386 |
*/ |
*/ |
387 |
public GroupResponse group(String name) |
public GroupResponse group(String name) throws IOException |
|
throws IOException |
|
388 |
{ |
{ |
389 |
StringBuffer line = new StringBuffer(GROUP); |
StringBuffer line = new StringBuffer(GROUP); |
390 |
line.append(' '); |
line.append(' '); |
391 |
line.append(name); |
line.append(name); |
392 |
send(line.toString()); |
send(line.toString()); |
393 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
394 |
switch (response.status) |
switch (response.status) |
395 |
{ |
{ |
396 |
case GROUP_SELECTED: |
case GROUP_SELECTED: |
397 |
return (GroupResponse)response; |
return (GroupResponse) response; |
398 |
default: |
default: |
399 |
// NO_SUCH_GROUP |
// NO_SUCH_GROUP |
400 |
throw new NNTPException(response); |
throw new NNTPException(response); |
401 |
} |
} |
402 |
} |
} |
403 |
|
|
404 |
// RFC977:3.3 The HELP command |
// RFC977:3.3 The HELP command |
405 |
|
|
406 |
/** |
/** |
407 |
* Requests a help listing. |
* Requests a help listing. |
408 |
* @return an iterator over a collection of help lines. |
* @return an iterator over a collection of help lines. |
409 |
*/ |
*/ |
410 |
public LineIterator help() |
public LineIterator help() throws IOException |
|
throws IOException |
|
411 |
{ |
{ |
412 |
send(HELP); |
send(HELP); |
413 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
414 |
switch (response.status) |
switch (response.status) |
415 |
{ |
{ |
416 |
case HELP_TEXT: |
case HELP_TEXT: |
417 |
LineIterator li = new LineIterator(this); |
LineIterator li = new LineIterator(this); |
418 |
pendingData = li; |
pendingData = li; |
419 |
return li; |
return li; |
420 |
default: |
default:throw new NNTPException(response); |
|
throw new NNTPException(response); |
|
421 |
} |
} |
422 |
} |
} |
423 |
|
|
424 |
// RFC977:3.4 The IHAVE command |
// RFC977:3.4 The IHAVE command |
425 |
|
|
426 |
/** |
/** |
427 |
* Sends an ihave command indicating that the client has an article with |
* Sends an ihave command indicating that the client has an article with |
428 |
* the specified message-id. |
* the specified message-id. |
430 |
* @return a PostStream if the server wants the specified article, null |
* @return a PostStream if the server wants the specified article, null |
431 |
* otherwise |
* otherwise |
432 |
*/ |
*/ |
433 |
public PostStream ihave(String messageId) |
public PostStream ihave(String messageId) throws IOException |
|
throws IOException |
|
434 |
{ |
{ |
435 |
send(IHAVE); |
send(IHAVE); |
436 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
437 |
switch (response.status) |
switch (response.status) |
438 |
{ |
{ |
439 |
case SEND_TRANSFER_ARTICLE: |
case SEND_TRANSFER_ARTICLE: |
440 |
return new PostStream(this, false); |
return new PostStream(this, false); |
441 |
case ARTICLE_NOT_WANTED: |
case ARTICLE_NOT_WANTED:return null; |
442 |
return null; |
default:throw new NNTPException(response); |
|
default: |
|
|
throw new NNTPException(response); |
|
443 |
} |
} |
444 |
} |
} |
445 |
|
|
446 |
// RFC(77:3.5 The LAST command |
// RFC(77:3.5 The LAST command |
447 |
|
|
448 |
/** |
/** |
450 |
* @return the article number/message-id pair associated with the new |
* @return the article number/message-id pair associated with the new |
451 |
* article |
* article |
452 |
*/ |
*/ |
453 |
public ArticleResponse last() |
public ArticleResponse last() throws IOException |
|
throws IOException |
|
454 |
{ |
{ |
455 |
return articleImpl(LAST, null); |
return articleImpl(LAST, null); |
456 |
} |
} |
457 |
|
|
458 |
// RFC977:3.6 The LIST command |
// RFC977:3.6 The LIST command |
459 |
|
|
460 |
/** |
/** |
461 |
* Send a group listing command to the server. |
* Send a group listing command to the server. |
462 |
* Returns a GroupIterator. This must be read fully before other commands |
* Returns a GroupIterator. This must be read fully before other commands |
463 |
* are issued. |
* are issued. |
464 |
*/ |
*/ |
465 |
public GroupIterator list() |
public GroupIterator list() throws IOException |
|
throws IOException |
|
466 |
{ |
{ |
467 |
return listImpl(LIST); |
return listImpl(LIST); |
468 |
} |
} |
469 |
|
|
470 |
GroupIterator listImpl(String command) |
GroupIterator listImpl(String command) throws IOException |
|
throws IOException |
|
471 |
{ |
{ |
472 |
send(command); |
send(command); |
473 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
474 |
switch (response.status) |
switch (response.status) |
475 |
{ |
{ |
476 |
case LIST_FOLLOWS: |
case LIST_FOLLOWS: |
477 |
GroupIterator gi = new GroupIterator(this); |
GroupIterator gi = new GroupIterator(this); |
478 |
pendingData = gi; |
pendingData = gi; |
479 |
return gi; |
return gi; |
480 |
default: |
default:throw new NNTPException(response); |
|
throw new NNTPException(response); |
|
481 |
} |
} |
482 |
} |
} |
483 |
|
|
491 |
* @param since the date from which to list new groups |
* @param since the date from which to list new groups |
492 |
* @param distributions if non-null, an array of distributions to match |
* @param distributions if non-null, an array of distributions to match |
493 |
*/ |
*/ |
494 |
public LineIterator newGroups(Date since, String[] distributions) |
public LineIterator newGroups(Date since, String[]distributions) |
495 |
throws IOException |
throws IOException |
496 |
{ |
{ |
497 |
StringBuffer buffer = new StringBuffer(NEWGROUPS); |
StringBuffer buffer = new StringBuffer(NEWGROUPS); |
498 |
buffer.append(' '); |
buffer.append(' '); |
499 |
buffer.append(formatDate(since)); |
buffer.append(formatDate(since)); |
500 |
if (distributions!=null) |
if (distributions != null) |
501 |
{ |
{ |
502 |
buffer.append(' '); |
buffer.append(' '); |
503 |
for (int i=0; i<distributions.length; i++) |
for (int i = 0; i < distributions.length; i++) |
504 |
{ |
{ |
505 |
if (i>0) |
if (i > 0) |
506 |
buffer.append(','); |
buffer.append(','); |
507 |
buffer.append(distributions[i]); |
buffer.append(distributions[i]); |
508 |
} |
} |
509 |
} |
} |
510 |
send (buffer.toString()); |
send(buffer.toString()); |
511 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
512 |
switch (response.status) |
switch (response.status) |
513 |
{ |
{ |
514 |
case NEWGROUPS_LIST_FOLLOWS: |
case NEWGROUPS_LIST_FOLLOWS: |
515 |
LineIterator li = new LineIterator(this); |
LineIterator li = new LineIterator(this); |
516 |
pendingData = li; |
pendingData = li; |
517 |
return li; |
return li; |
518 |
default: |
default: |
519 |
throw new NNTPException(response); |
throw new NNTPException(response); |
520 |
} |
} |
521 |
} |
} |
522 |
|
|
523 |
// RFC977:3.8 The NEWNEWS command |
// RFC977:3.8 The NEWNEWS command |
524 |
|
|
525 |
/** |
/** |
532 |
* @param distributions if non-null, a list of distributions to match |
* @param distributions if non-null, a list of distributions to match |
533 |
*/ |
*/ |
534 |
public LineIterator newNews(String newsgroup, Date since, |
public LineIterator newNews(String newsgroup, Date since, |
535 |
String[] distributions) |
String[]distributions) throws IOException |
|
throws IOException |
|
536 |
{ |
{ |
537 |
StringBuffer buffer = new StringBuffer(NEWNEWS); |
StringBuffer buffer = new StringBuffer(NEWNEWS); |
538 |
buffer.append(' '); |
buffer.append(' '); |
539 |
buffer.append(newsgroup); |
buffer.append(newsgroup); |
540 |
buffer.append(' '); |
buffer.append(' '); |
541 |
buffer.append(formatDate(since)); |
buffer.append(formatDate(since)); |
542 |
if (distributions!=null) |
if (distributions != null) |
543 |
{ |
{ |
544 |
buffer.append(' '); |
buffer.append(' '); |
545 |
for (int i=0; i<distributions.length; i++) |
for (int i = 0; i < distributions.length; i++) |
546 |
{ |
{ |
547 |
if (i>0) |
if (i > 0) |
548 |
buffer.append(','); |
buffer.append(','); |
549 |
buffer.append(distributions[i]); |
buffer.append(distributions[i]); |
550 |
} |
} |
551 |
} |
} |
552 |
send (buffer.toString()); |
send(buffer.toString()); |
553 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
554 |
switch (response.status) |
switch (response.status) |
555 |
{ |
{ |
556 |
case NEWNEWS_LIST_FOLLOWS: |
case NEWNEWS_LIST_FOLLOWS: |
557 |
LineIterator li = new LineIterator(this); |
LineIterator li = new LineIterator(this); |
558 |
pendingData = li; |
pendingData = li; |
559 |
return li; |
return li; |
560 |
default: |
default: |
561 |
throw new NNTPException(response); |
throw new NNTPException(response); |
562 |
} |
} |
563 |
} |
} |
564 |
|
|
565 |
// RFC977:3.9 The NEXT command |
// RFC977:3.9 The NEXT command |
566 |
|
|
567 |
/** |
/** |
568 |
* Sends a next article positioning command to the server. |
* Sends a next article positioning command to the server. |
569 |
* @return the article number/message-id pair associated with the new |
* @return the article number/message-id pair associated with the new |
570 |
* article |
* article |
571 |
*/ |
*/ |
572 |
public ArticleResponse next() |
public ArticleResponse next() throws IOException |
|
throws IOException |
|
573 |
{ |
{ |
574 |
return articleImpl(NEXT, null); |
return articleImpl(NEXT, null); |
575 |
} |
} |
576 |
|
|
577 |
// RFC977:3.10 The POST command |
// RFC977:3.10 The POST command |
578 |
|
|
579 |
/** |
/** |
585 |
* No other method should be called in between. |
* No other method should be called in between. |
586 |
* @see #postComplete |
* @see #postComplete |
587 |
*/ |
*/ |
588 |
public OutputStream post() |
public OutputStream post() throws IOException |
|
throws IOException |
|
589 |
{ |
{ |
590 |
send(POST); |
send(POST); |
591 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
592 |
switch (response.status) |
switch (response.status) |
593 |
{ |
{ |
594 |
case SEND_ARTICLE: |
case SEND_ARTICLE: |
595 |
return new PostStream(this, false); |
return new PostStream(this, false); |
596 |
default: |
default: |
597 |
// POSTING_NOT_ALLOWED |
// POSTING_NOT_ALLOWED |
598 |
throw new NNTPException(response); |
throw new NNTPException(response); |
599 |
} |
} |
600 |
} |
} |
601 |
|
|
605 |
* Called by the PostStream during <code>close()</code>. |
* Called by the PostStream during <code>close()</code>. |
606 |
* @see #post |
* @see #post |
607 |
*/ |
*/ |
608 |
void postComplete() |
void postComplete() throws IOException |
|
throws IOException |
|
609 |
{ |
{ |
610 |
send(DOT); |
send(DOT); |
611 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
612 |
switch (response.status) |
switch (response.status) |
613 |
{ |
{ |
614 |
case ARTICLE_POSTED: |
case ARTICLE_POSTED: |
615 |
case ARTICLE_TRANSFERRED: |
case ARTICLE_TRANSFERRED: |
616 |
return; |
return; |
617 |
default: |
default: |
618 |
// POSTING_FAILED |
// POSTING_FAILED |
619 |
// TRANSFER_FAILED |
// TRANSFER_FAILED |
620 |
// ARTICLE_REJECTED |
// ARTICLE_REJECTED |
621 |
throw new NNTPException(response); |
throw new NNTPException(response); |
622 |
} |
} |
623 |
} |
} |
624 |
|
|
625 |
// RFC977:3.11 The QUIT command |
// RFC977:3.11 The QUIT command |
626 |
|
|
627 |
/** |
/** |
628 |
* Close the connection. |
* Close the connection. |
629 |
* After calling this method, no further calls on this object are valid. |
* After calling this method, no further calls on this object are valid. |
630 |
*/ |
*/ |
631 |
public void quit() |
public void quit() throws IOException |
|
throws IOException |
|
632 |
{ |
{ |
633 |
send(QUIT); |
send(QUIT); |
634 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
635 |
switch (response.status) |
switch (response.status) |
636 |
{ |
{ |
637 |
case CLOSING_CONNECTION: |
case CLOSING_CONNECTION: |
638 |
socket.close(); |
socket.close(); |
639 |
return; |
return; |
640 |
default: |
default:throw new NNTPException(response); |
|
throw new NNTPException(response); |
|
641 |
} |
} |
642 |
} |
} |
643 |
|
|
646 |
/** |
/** |
647 |
* Indicates to the server that this is a slave connection. |
* Indicates to the server that this is a slave connection. |
648 |
*/ |
*/ |
649 |
public void slave() |
public void slave() throws IOException |
|
throws IOException |
|
650 |
{ |
{ |
651 |
send(SLAVE); |
send(SLAVE); |
652 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
653 |
switch (response.status) |
switch (response.status) |
654 |
{ |
{ |
655 |
case SLAVE_ACKNOWLEDGED: |
case SLAVE_ACKNOWLEDGED: |
656 |
break; |
break; |
657 |
default: |
default:throw new NNTPException(response); |
|
throw new NNTPException(response); |
|
658 |
} |
} |
659 |
} |
} |
660 |
|
|
661 |
// RFC2980:1.1 The CHECK command |
// RFC2980:1.1 The CHECK command |
662 |
|
|
663 |
public boolean check(String messageId) |
public boolean check(String messageId) throws IOException |
|
throws IOException |
|
664 |
{ |
{ |
665 |
StringBuffer buffer = new StringBuffer(CHECK); |
StringBuffer buffer = new StringBuffer(CHECK); |
666 |
buffer.append(' '); |
buffer.append(' '); |
667 |
buffer.append(messageId); |
buffer.append(messageId); |
668 |
send(buffer.toString()); |
send(buffer.toString()); |
669 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
670 |
switch (response.status) |
switch (response.status) |
671 |
{ |
{ |
672 |
case SEND_ARTICLE_VIA_TAKETHIS: |
case SEND_ARTICLE_VIA_TAKETHIS: |
673 |
return true; |
return true; |
674 |
case ARTICLE_NOT_WANTED_VIA_TAKETHIS: |
case ARTICLE_NOT_WANTED_VIA_TAKETHIS:return false; |
|
return false; |
|
675 |
default: |
default: |
676 |
// SERVICE_DISCONTINUED |
// SERVICE_DISCONTINUED |
677 |
// TRY_AGAIN_LATER |
// TRY_AGAIN_LATER |
678 |
// TRANSFER_PERMISSION_DENIED |
// TRANSFER_PERMISSION_DENIED |
679 |
// COMMAND_NOT_RECOGNIZED |
// COMMAND_NOT_RECOGNIZED |
680 |
throw new NNTPException(response); |
throw new NNTPException(response); |
681 |
} |
} |
682 |
} |
} |
683 |
|
|
690 |
* |
* |
691 |
* @return true if the server supports streaming mode |
* @return true if the server supports streaming mode |
692 |
*/ |
*/ |
693 |
public boolean modeStream() |
public boolean modeStream() throws IOException |
|
throws IOException |
|
694 |
{ |
{ |
695 |
send(MODE_STREAM); |
send(MODE_STREAM); |
696 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
697 |
switch (response.status) |
switch (response.status) |
698 |
{ |
{ |
699 |
case STREAMING_OK: |
case STREAMING_OK: |
700 |
return true; |
return true; |
701 |
default: |
default: |
702 |
// COMMAND_NOT_RECOGNIZED |
// COMMAND_NOT_RECOGNIZED |
703 |
return false; |
return false; |
704 |
} |
} |
705 |
} |
} |
706 |
|
|
713 |
* stream. |
* stream. |
714 |
* @see #takethisComplete |
* @see #takethisComplete |
715 |
*/ |
*/ |
716 |
public OutputStream takethis(String messageId) |
public OutputStream takethis(String messageId) throws IOException |
|
throws IOException |
|
717 |
{ |
{ |
718 |
send(TAKETHIS); |
send(TAKETHIS); |
719 |
return new PostStream(this, true); |
return new PostStream(this, true); |
724 |
* Called by PostStream.close(). |
* Called by PostStream.close(). |
725 |
* @see #takethis |
* @see #takethis |
726 |
*/ |
*/ |
727 |
void takethisComplete() |
void takethisComplete() throws IOException |
|
throws IOException |
|
728 |
{ |
{ |
729 |
send(DOT); |
send(DOT); |
730 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
731 |
switch (response.status) |
switch (response.status) |
732 |
{ |
{ |
733 |
case ARTICLE_TRANSFERRED_OK: |
case ARTICLE_TRANSFERRED_OK: |
734 |
return; |
return; |
735 |
default: |
default: |
736 |
// SERVICE_DISCONTINUED |
// SERVICE_DISCONTINUED |
737 |
// ARTICLE_TRANSFER_FAILED |
// ARTICLE_TRANSFER_FAILED |
738 |
// TRANSFER_PERMISSION_DENIED |
// TRANSFER_PERMISSION_DENIED |
739 |
// COMMAND_NOT_RECOGNIZED |
// COMMAND_NOT_RECOGNIZED |
740 |
throw new NNTPException(response); |
throw new NNTPException(response); |
741 |
} |
} |
742 |
} |
} |
743 |
|
|
754 |
* @param wildmat the wildmat pattern. If null, returns all groups. If no |
* @param wildmat the wildmat pattern. If null, returns all groups. If no |
755 |
* groups are matched, returns an empty iterator. |
* groups are matched, returns an empty iterator. |
756 |
*/ |
*/ |
757 |
public GroupIterator listActive(String wildmat) |
public GroupIterator listActive(String wildmat) throws IOException |
|
throws IOException |
|
758 |
{ |
{ |
759 |
StringBuffer buffer = new StringBuffer(LIST_ACTIVE); |
StringBuffer buffer = new StringBuffer(LIST_ACTIVE); |
760 |
if (wildmat!=null) |
if (wildmat != null) |
761 |
{ |
{ |
762 |
buffer.append(' '); |
buffer.append(' '); |
763 |
buffer.append(wildmat); |
buffer.append(wildmat); |
772 |
* Each ActiveTime object returned provides details of who created the |
* Each ActiveTime object returned provides details of who created the |
773 |
* newsgroup and when. |
* newsgroup and when. |
774 |
*/ |
*/ |
775 |
public ActiveTimesIterator listActiveTimes() |
public ActiveTimesIterator listActiveTimes() throws IOException |
|
throws IOException |
|
776 |
{ |
{ |
777 |
send(LIST_ACTIVE_TIMES); |
send(LIST_ACTIVE_TIMES); |
778 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
779 |
switch (response.status) |
switch (response.status) |
780 |
{ |
{ |
781 |
case LIST_FOLLOWS: |
case LIST_FOLLOWS: |
782 |
return new ActiveTimesIterator(this); |
return new ActiveTimesIterator(this); |
783 |
default: |
default:throw new NNTPException(response); |
|
throw new NNTPException(response); |
|
784 |
} |
} |
785 |
} |
} |
786 |
|
|
794 |
|
|
795 |
// RFC2980:2.1.6 The LIST NEWSGROUPS command |
// RFC2980:2.1.6 The LIST NEWSGROUPS command |
796 |
|
|
797 |
/** |
/** |
798 |
* Returns an iterator over the group descriptions for the given groups. |
* Returns an iterator over the group descriptions for the given groups. |
799 |
* @param wildmat if non-null, limits the groups in the iterator to the |
* @param wildmat if non-null, limits the groups in the iterator to the |
800 |
* specified pattern |
* specified pattern |
801 |
* @return an iterator over group name/description pairs |
* @return an iterator over group name/description pairs |
802 |
* @see #xgtitle |
* @see #xgtitle |
803 |
*/ |
*/ |
804 |
public PairIterator listNewsgroups(String wildmat) |
public PairIterator listNewsgroups(String wildmat) throws IOException |
805 |
throws IOException |
{ |
806 |
{ |
StringBuffer buffer = new StringBuffer(LIST_NEWSGROUPS); |
807 |
StringBuffer buffer = new StringBuffer(LIST_NEWSGROUPS); |
if (wildmat != null) |
808 |
if (wildmat!=null) |
{ |
809 |
{ |
buffer.append(' '); |
810 |
buffer.append(' '); |
buffer.append(wildmat); |
811 |
buffer.append(wildmat); |
} |
812 |
} |
send(buffer.toString()); |
813 |
send(buffer.toString()); |
StatusResponse response = parseResponse(read()); |
814 |
StatusResponse response = parseResponse(read()); |
switch (response.status) |
815 |
switch (response.status) |
{ |
816 |
{ |
case LIST_FOLLOWS: |
817 |
case LIST_FOLLOWS: |
PairIterator pi = new PairIterator(this); |
818 |
PairIterator pi = new PairIterator(this); |
pendingData = pi; |
819 |
pendingData = pi; |
return pi; |
820 |
return pi; |
default: |
821 |
default: |
throw new NNTPException(response); |
822 |
throw new NNTPException(response); |
} |
823 |
} |
} |
|
} |
|
824 |
|
|
825 |
// RFC2980:2.1.7 The LIST OVERVIEW.FMT command |
// RFC2980:2.1.7 The LIST OVERVIEW.FMT command |
826 |
|
|
830 |
* Each line returned by the iterator contains one header field. |
* Each line returned by the iterator contains one header field. |
831 |
* @see #xover |
* @see #xover |
832 |
*/ |
*/ |
833 |
public LineIterator listOverviewFmt() |
public LineIterator listOverviewFmt() throws IOException |
|
throws IOException |
|
834 |
{ |
{ |
835 |
send(LIST_OVERVIEW_FMT); |
send(LIST_OVERVIEW_FMT); |
836 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
837 |
switch (response.status) |
switch (response.status) |
838 |
{ |
{ |
839 |
case LIST_FOLLOWS: |
case LIST_FOLLOWS: |
840 |
LineIterator li = new LineIterator(this); |
LineIterator li = new LineIterator(this); |
841 |
pendingData = li; |
pendingData = li; |
842 |
return li; |
return li; |
843 |
default: |
default:throw new NNTPException(response); |
|
throw new NNTPException(response); |
|
844 |
} |
} |
845 |
} |
} |
846 |
|
|
849 |
/** |
/** |
850 |
* Returns a list of newsgroups suitable for new users of the server. |
* Returns a list of newsgroups suitable for new users of the server. |
851 |
*/ |
*/ |
852 |
public GroupIterator listSubscriptions() |
public GroupIterator listSubscriptions() throws IOException |
|
throws IOException |
|
853 |
{ |
{ |
854 |
return listImpl(LIST_SUBSCRIPTIONS); |
return listImpl(LIST_SUBSCRIPTIONS); |
855 |
} |
} |
862 |
* selected group is assumed. |
* selected group is assumed. |
863 |
* @param group the name of the group to list articles for |
* @param group the name of the group to list articles for |
864 |
*/ |
*/ |
865 |
public ArticleNumberIterator listGroup(String group) |
public ArticleNumberIterator listGroup(String group) throws IOException |
866 |
throws IOException |
{ |
867 |
{ |
StringBuffer buffer = new StringBuffer(LIST_NEWSGROUPS); |
868 |
StringBuffer buffer = new StringBuffer(LIST_NEWSGROUPS); |
if (group != null) |
869 |
if (group!=null) |
{ |
870 |
{ |
buffer.append(' '); |
871 |
buffer.append(' '); |
buffer.append(group); |
872 |
buffer.append(group); |
} |
873 |
} |
send(buffer.toString()); |
874 |
send(buffer.toString()); |
StatusResponse response = parseResponse(read()); |
875 |
StatusResponse response = parseResponse(read()); |
switch (response.status) |
876 |
switch (response.status) |
{ |
877 |
{ |
case GROUP_SELECTED: |
878 |
case GROUP_SELECTED: |
ArticleNumberIterator ani = new ArticleNumberIterator(this); |
879 |
ArticleNumberIterator ani = new ArticleNumberIterator(this); |
pendingData = ani; |
880 |
pendingData = ani; |
return ani; |
881 |
return ani; |
default: |
882 |
default: |
throw new NNTPException(response); |
883 |
throw new NNTPException(response); |
} |
884 |
} |
} |
|
} |
|
885 |
|
|
886 |
|
|
887 |
// RFC2980:2.3 The MODE READER command |
// RFC2980:2.3 The MODE READER command |
890 |
* Indicates to the server that this is a user-agent. |
* Indicates to the server that this is a user-agent. |
891 |
* @return true if posting is allowed, false otherwise. |
* @return true if posting is allowed, false otherwise. |
892 |
*/ |
*/ |
893 |
public boolean modeReader() |
public boolean modeReader() throws IOException |
|
throws IOException |
|
894 |
{ |
{ |
895 |
send(MODE_READER); |
send(MODE_READER); |
896 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
897 |
switch (response.status) |
switch (response.status) |
898 |
{ |
{ |
899 |
case POSTING_ALLOWED: |
case POSTING_ALLOWED: |
900 |
canPost = true; |
canPost = true; |
901 |
return canPost; |
return canPost; |
902 |
case POSTING_NOT_ALLOWED: |
case POSTING_NOT_ALLOWED:canPost = false; |
903 |
canPost = false; |
return canPost; |
904 |
return canPost; |
default:throw new NNTPException(response); |
|
default: |
|
|
throw new NNTPException(response); |
|
905 |
} |
} |
906 |
} |
} |
907 |
|
|
911 |
* Returns an iterator over the list of newsgroup descriptions. |
* Returns an iterator over the list of newsgroup descriptions. |
912 |
* @param wildmat if non-null, the newsgroups to match |
* @param wildmat if non-null, the newsgroups to match |
913 |
*/ |
*/ |
914 |
public PairIterator xgtitle(String wildmat) |
public PairIterator xgtitle(String wildmat) throws IOException |
|
throws IOException |
|
915 |
{ |
{ |
916 |
StringBuffer buffer = new StringBuffer(XGTITLE); |
StringBuffer buffer = new StringBuffer(XGTITLE); |
917 |
if (wildmat!=null) |
if (wildmat != null) |
918 |
{ |
{ |
919 |
buffer.append(' '); |
buffer.append(' '); |
920 |
buffer.append(wildmat); |
buffer.append(wildmat); |
923 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
924 |
switch (response.status) |
switch (response.status) |
925 |
{ |
{ |
926 |
case XGTITLE_LIST_FOLLOWS: |
case XGTITLE_LIST_FOLLOWS: |
927 |
PairIterator pi = new PairIterator(this); |
PairIterator pi = new PairIterator(this); |
928 |
pendingData = pi; |
pendingData = pi; |
929 |
return pi; |
return pi; |
930 |
default: |
default: |
931 |
throw new NNTPException(response); |
throw new NNTPException(response); |
932 |
} |
} |
933 |
} |
} |
934 |
|
|
935 |
// RFC2980:2.6 The XHDR command |
// RFC2980:2.6 The XHDR command |
936 |
|
|
937 |
public HeaderIterator xhdr(String header, String range) |
public HeaderIterator xhdr(String header, String range) throws IOException |
|
throws IOException |
|
938 |
{ |
{ |
939 |
StringBuffer buffer = new StringBuffer(XHDR); |
StringBuffer buffer = new StringBuffer(XHDR); |
940 |
buffer.append(' '); |
buffer.append(' '); |
941 |
buffer.append(header); |
buffer.append(header); |
942 |
if (range!=null) |
if (range != null) |
943 |
{ |
{ |
944 |
buffer.append(' '); |
buffer.append(' '); |
945 |
buffer.append(range); |
buffer.append(range); |
948 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
949 |
switch (response.status) |
switch (response.status) |
950 |
{ |
{ |
951 |
case HEAD_FOLLOWS: |
case HEAD_FOLLOWS: |
952 |
HeaderIterator hi = new HeaderIterator(this); |
HeaderIterator hi = new HeaderIterator(this); |
953 |
pendingData = hi; |
pendingData = hi; |
954 |
return hi; |
return hi; |
955 |
default: |
default: |
956 |
// NO_GROUP_SELECTED |
// NO_GROUP_SELECTED |
957 |
// NO_SUCH_ARTICLE |
// NO_SUCH_ARTICLE |
958 |
throw new NNTPException(response); |
throw new NNTPException(response); |
959 |
} |
} |
960 |
} |
} |
961 |
|
|
965 |
|
|
966 |
// RFC2980:2.8 The XOVER command |
// RFC2980:2.8 The XOVER command |
967 |
|
|
968 |
public OverviewIterator xover(Range range) |
public OverviewIterator xover(Range range) throws IOException |
|
throws IOException |
|
969 |
{ |
{ |
970 |
StringBuffer buffer = new StringBuffer(XOVER); |
StringBuffer buffer = new StringBuffer(XOVER); |
971 |
if (range!=null) |
if (range != null) |
972 |
{ |
{ |
973 |
buffer.append(' '); |
buffer.append(' '); |
974 |
buffer.append(range.toString()); |
buffer.append(range.toString()); |
975 |
} |
} |
976 |
send (buffer.toString()); |
send(buffer.toString()); |
977 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
978 |
switch (response.status) |
switch (response.status) |
979 |
{ |
{ |
980 |
case OVERVIEW_FOLLOWS: |
case OVERVIEW_FOLLOWS: |
981 |
OverviewIterator oi = new OverviewIterator(this); |
OverviewIterator oi = new OverviewIterator(this); |
982 |
pendingData = oi; |
pendingData = oi; |
983 |
return oi; |
return oi; |
984 |
default: |
default: |
985 |
// NO_GROUP_SELECTED |
// NO_GROUP_SELECTED |
986 |
// PERMISSION_DENIED |
// PERMISSION_DENIED |
987 |
throw new NNTPException(response); |
throw new NNTPException(response); |
988 |
} |
} |
989 |
} |
} |
990 |
|
|
1012 |
* @param password the (cleartext) password |
* @param password the (cleartext) password |
1013 |
* @return true on success, false on failure |
* @return true on success, false on failure |
1014 |
*/ |
*/ |
1015 |
public boolean authinfo(String username, String password) |
public boolean authinfo(String username, String password) throws IOException |
|
throws IOException |
|
1016 |
{ |
{ |
1017 |
StringBuffer buffer = new StringBuffer(AUTHINFO_USER); |
StringBuffer buffer = new StringBuffer(AUTHINFO_USER); |
1018 |
buffer.append(' '); |
buffer.append(' '); |
1019 |
buffer.append(username); |
buffer.append(username); |
1020 |
send(buffer.toString()); |
send(buffer.toString()); |
1021 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
1022 |
switch (response.status) |
switch (response.status) |
1023 |
{ |
{ |
1024 |
|
case AUTHINFO_OK: |
1025 |
|
return true; |
1026 |
|
case SEND_AUTHINFOPASS:buffer.setLength(0); |
1027 |
|
buffer.append(AUTHINFO_PASS); |
1028 |
|
buffer.append(' '); |
1029 |
|
buffer.append(password); |
1030 |
|
send(buffer.toString()); |
1031 |
|
response = parseResponse(read()); |
1032 |
|
switch (response.status) |
1033 |
|
{ |
1034 |
case AUTHINFO_OK: |
case AUTHINFO_OK: |
1035 |
return true; |
return true; |
1036 |
case SEND_AUTHINFOPASS: |
case PERMISSION_DENIED:return false; |
1037 |
buffer.setLength(0); |
default:throw new NNTPException(response); |
1038 |
buffer.append(AUTHINFO_PASS); |
} |
|
buffer.append(' '); |
|
|
buffer.append(password); |
|
|
send(buffer.toString()); |
|
|
response = parseResponse(read()); |
|
|
switch (response.status) |
|
|
{ |
|
|
case AUTHINFO_OK: |
|
|
return true; |
|
|
case PERMISSION_DENIED: |
|
|
return false; |
|
|
default: |
|
|
throw new NNTPException(response); |
|
|
} |
|
1039 |
default: |
default: |
1040 |
// AUTHINFO_REJECTED |
// AUTHINFO_REJECTED |
1041 |
throw new NNTPException(response); |
throw new NNTPException(response); |
1056 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
1057 |
switch (response.status) |
switch (response.status) |
1058 |
{ |
{ |
1059 |
case SEND_AUTHINFO_SIMPLE: |
case SEND_AUTHINFO_SIMPLE: |
1060 |
StringBuffer buffer = new StringBuffer(username); |
StringBuffer buffer = new StringBuffer(username); |
1061 |
buffer.append(' '); |
buffer.append(' '); |
1062 |
buffer.append(password); |
buffer.append(password); |
1063 |
send(buffer.toString()); |
send(buffer.toString()); |
1064 |
response = parseResponse(read()); |
response = parseResponse(read()); |
1065 |
switch (response.status) |
switch (response.status) |
1066 |
{ |
{ |
1067 |
case AUTHINFO_SIMPLE_OK: |
case AUTHINFO_SIMPLE_OK: |
1068 |
return true; |
return true; |
1069 |
case AUTHINFO_SIMPLE_DENIED: |
case AUTHINFO_SIMPLE_DENIED:return false; |
1070 |
return false; |
default:throw new NNTPException(response); |
1071 |
default: |
} |
1072 |
throw new NNTPException(response); |
default:throw new NNTPException(response); |
|
} |
|
|
default: |
|
|
throw new NNTPException(response); |
|
1073 |
} |
} |
1074 |
} |
} |
1075 |
|
|
1084 |
throws IOException |
throws IOException |
1085 |
{ |
{ |
1086 |
StringBuffer buffer = new StringBuffer(AUTHINFO_GENERIC); |
StringBuffer buffer = new StringBuffer(AUTHINFO_GENERIC); |
1087 |
buffer.append(' '); |
buffer.append(' '); |
1088 |
buffer.append(authenticator); |
buffer.append(authenticator); |
1089 |
buffer.append(' '); |
buffer.append(' '); |
1090 |
buffer.append(args); |
buffer.append(args); |
1091 |
send(buffer.toString()); |
send(buffer.toString()); |
1092 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
1093 |
switch (response.status) |
switch (response.status) |
1094 |
{ |
{ |
1095 |
case COMMAND_NOT_RECOGNIZED: |
case COMMAND_NOT_RECOGNIZED: |
1096 |
case SYNTAX_ERROR: |
case SYNTAX_ERROR: |
1097 |
case INTERNAL_ERROR: |
case INTERNAL_ERROR: |
1098 |
throw new NNTPException(response); |
throw new NNTPException(response); |
1099 |
default: |
default: |
1100 |
// TODO attempt to connect authenticator |
// TODO attempt to connect authenticator |
1101 |
// ... do stuff ... |
// ... do stuff ... |
1110 |
/** |
/** |
1111 |
* Returns the date on the server. |
* Returns the date on the server. |
1112 |
*/ |
*/ |
1113 |
public Date date() |
public Date date() throws IOException |
|
throws IOException |
|
1114 |
{ |
{ |
1115 |
send(DATE); |
send(DATE); |
1116 |
StatusResponse response = parseResponse(read()); |
StatusResponse response = parseResponse(read()); |
1117 |
switch (response.status) |
switch (response.status) |
1118 |
{ |
{ |
1119 |
case DATE_OK: |
case DATE_OK: |
1120 |
String message = response.getMessage(); |
String message = response.getMessage(); |
1121 |
try |
try |
1122 |
{ |
{ |
1123 |
DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); |
DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); |
1124 |
return df.parse(message); |
return df.parse(message); |
1125 |
} |
} |
1126 |
catch (ParseException e) |
catch(ParseException e) |
1127 |
{ |
{ |
1128 |
throw new IOException("Invalid date: "+message); |
throw new IOException("Invalid date: " + message); |
1129 |
} |
} |
1130 |
default: |
default: |
1131 |
throw new NNTPException(response); |
throw new NNTPException(response); |
1132 |
} |
} |
1133 |
} |
} |
1134 |
|
|
1143 |
String statusText = line; |
String statusText = line; |
1144 |
String message = null; |
String message = null; |
1145 |
end = line.indexOf(' ', start); |
end = line.indexOf(' ', start); |
1146 |
if (end>start) |
if (end > start) |
1147 |
{ |
{ |
1148 |
statusText = line.substring(start, end); |
statusText = line.substring(start, end); |
1149 |
message = line.substring(end+1); |
message = line.substring(end + 1); |
1150 |
} |
} |
1151 |
short status = Short.parseShort(statusText); |
short status = Short.parseShort(statusText); |
1152 |
StatusResponse response; |
StatusResponse response; |
1153 |
switch (status) |
switch (status) |
1154 |
{ |
{ |
1155 |
case ARTICLE_FOLLOWS: |
case ARTICLE_FOLLOWS: |
1156 |
case HEAD_FOLLOWS: |
case HEAD_FOLLOWS: |
1157 |
case BODY_FOLLOWS: |
case BODY_FOLLOWS: |
1158 |
case ARTICLE_RETRIEVED: |
case ARTICLE_RETRIEVED: |
1159 |
try |
try |
1160 |
{ |
{ |
1161 |
ArticleResponse aresponse = new ArticleResponse(status, message); |
ArticleResponse aresponse = new ArticleResponse(status, message); |
1162 |
// article number |
// article number |
1163 |
start = end+1; |
start = end + 1; |
|
end = line.indexOf(' ', start); |
|
|
if (end>start) |
|
|
aresponse.articleNumber = |
|
|
Integer.parseInt(line.substring(start, end)); |
|
|
// message-id |
|
|
start = end+1; |
|
|
end = line.indexOf(' ', start); |
|
|
if (end>start) |
|
|
aresponse.messageId = line.substring(start, end); |
|
|
else |
|
|
aresponse.messageId = line.substring(start); |
|
|
response = aresponse; |
|
|
} |
|
|
catch (NumberFormatException e) |
|
|
{ |
|
|
// This will happen for XHDR |
|
|
response = new StatusResponse(status, message); |
|
|
} |
|
|
break; |
|
|
case GROUP_SELECTED: |
|
|
GroupResponse gresponse = new GroupResponse(status, message); |
|
|
// count |
|
|
start = end+1; |
|
|
end = line.indexOf(' ', start); |
|
|
if (end>start) |
|
|
gresponse.count = Integer.parseInt(line.substring(start, end)); |
|
|
// first |
|
|
start = end+1; |
|
|
end = line.indexOf(' ', start); |
|
|
if (end>start) |
|
|
gresponse.first = Integer.parseInt(line.substring(start, end)); |
|
|
// last |
|
|
start = end+1; |
|
1164 |
end = line.indexOf(' ', start); |
end = line.indexOf(' ', start); |
1165 |
if (end>start) |
if (end > start) |
1166 |
gresponse.last = Integer.parseInt(line.substring(start, end)); |
aresponse.articleNumber = |
1167 |
// group |
Integer.parseInt(line.substring(start, end)); |
1168 |
start = end+1; |
// message-id |
1169 |
|
start = end + 1; |
1170 |
end = line.indexOf(' ', start); |
end = line.indexOf(' ', start); |
1171 |
if (end>start) |
if (end > start) |
1172 |
gresponse.group = line.substring(start, end); |
aresponse.messageId = line.substring(start, end); |
1173 |
else |
else |
1174 |
gresponse.group = line.substring(start); |
aresponse.messageId = line.substring(start); |
1175 |
response = gresponse; |
response = aresponse; |
1176 |
break; |
} |
1177 |
default: |
catch(NumberFormatException e) |
1178 |
|
{ |
1179 |
|
// This will happen for XHDR |
1180 |
response = new StatusResponse(status, message); |
response = new StatusResponse(status, message); |
1181 |
|
} |
1182 |
|
break; |
1183 |
|
case GROUP_SELECTED: |
1184 |
|
GroupResponse gresponse = new GroupResponse(status, message); |
1185 |
|
// count |
1186 |
|
start = end + 1; |
1187 |
|
end = line.indexOf(' ', start); |
1188 |
|
if (end > start) |
1189 |
|
gresponse.count = Integer.parseInt(line.substring(start, end)); |
1190 |
|
// first |
1191 |
|
start = end + 1; |
1192 |
|
end = line.indexOf(' ', start); |
1193 |
|
if (end > start) |
1194 |
|
gresponse.first = Integer.parseInt(line.substring(start, end)); |
1195 |
|
// last |
1196 |
|
start = end + 1; |
1197 |
|
end = line.indexOf(' ', start); |
1198 |
|
if (end > start) |
1199 |
|
gresponse.last = Integer.parseInt(line.substring(start, end)); |
1200 |
|
// group |
1201 |
|
start = end + 1; |
1202 |
|
end = line.indexOf(' ', start); |
1203 |
|
if (end > start) |
1204 |
|
gresponse.group = line.substring(start, end); |
1205 |
|
else |
1206 |
|
gresponse.group = line.substring(start); |
1207 |
|
response = gresponse; |
1208 |
|
break; |
1209 |
|
default: |
1210 |
|
response = new StatusResponse(status, message); |
1211 |
} |
} |
1212 |
return response; |
return response; |
1213 |
} |
} |
1216 |
* Send a single line to the server. |
* Send a single line to the server. |
1217 |
* @param line the line to send |
* @param line the line to send |
1218 |
*/ |
*/ |
1219 |
protected void send(String line) |
protected void send(String line) throws IOException |
|
throws IOException |
|
1220 |
{ |
{ |
1221 |
if (pendingData!=null) |
if (pendingData != null) |
1222 |
{ |
{ |
1223 |
// Clear pending data |
// Clear pending data |
1224 |
pendingData.readToEOF(); |
pendingData.readToEOF(); |
1225 |
pendingData = null; |
pendingData = null; |
1226 |
} |
} |
1227 |
if (debug) |
if (debug) |
1228 |
{ |
{ |
1229 |
Logger logger = Logger.getInstance(); |
Logger logger = Logger.getInstance(); |
1230 |
logger.log("nntp", ">"+line); |
logger.log("nntp", ">" + line); |
1231 |
} |
} |
1232 |
byte[] data = line.getBytes(US_ASCII); |
byte[]data = line.getBytes(US_ASCII); |
1233 |
out.write(data); |
out.write(data); |
1234 |
out.write('\n'); |
out.write('\n'); |
1235 |
out.flush(); |
out.flush(); |
1236 |
} |
} |
1237 |
|
|
1238 |
/** |
/** |
1239 |
* Read a single line from the server. |
* Read a single line from the server. |
1240 |
* @return a line of text |
* @return a line of text |
1241 |
*/ |
*/ |
1242 |
protected String read() |
protected String read() throws IOException |
|
throws IOException |
|
1243 |
{ |
{ |
1244 |
String line = in.readLine(); |
String line = in.readLine(); |
1245 |
if (debug) |
if (debug) |
1246 |
{ |
{ |
1247 |
Logger logger = Logger.getInstance(); |
Logger logger = Logger.getInstance(); |
1248 |
if (line==null) |
if (line == null) |
1249 |
logger.log("nntp", "<EOF"); |
logger.log("nntp", "<EOF"); |
1250 |
else |
else |
1251 |
logger.log("nntp", "<"+line); |
logger.log("nntp", "<" + line); |
1252 |
} |
} |
1253 |
return line; |
return line; |
1254 |
} |
} |
1255 |
|
|