/[classpath]/inetlib/source/gnu/inet/nntp/NNTPConnection.java
ViewVC logotype

Diff of /inetlib/source/gnu/inet/nntp/NNTPConnection.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.11 by dog, Thu Oct 21 15:21:55 2004 UTC revision 1.12 by dog, Thu Nov 25 22:15:05 2004 UTC
# Line 1  Line 1 
1  /*  /*
2   * $Id$   * NNTPConnection.java
3   * Copyright (C) 2002 The Free Software Foundation   * Copyright (C) 2002 The Free Software Foundation
4   *   *
5   * This file is part of GNU inetlib, a library.   * This file is part of GNU inetlib, a library.
# Line 76  import gnu.inet.util.SaslOutputStream; Line 76  import gnu.inet.util.SaslOutputStream;
76   * server.   * server.
77   *   *
78   * @author <a hef='mailto:dog@gnu.org'>Chris Burdess</a>   * @author <a hef='mailto:dog@gnu.org'>Chris Burdess</a>
  * @version $Revision$ $Date$  
79   */   */
80  public class NNTPConnection  public class NNTPConnection
81    implements NNTPConstants    implements NNTPConstants
# Line 139  public class NNTPConnection Line 138  public class NNTPConnection
138     * Creates a new connection object.     * Creates a new connection object.
139     * @param hostname the hostname or IP address of the news server     * @param hostname the hostname or IP address of the news server
140     */     */
141    public NNTPConnection (String hostname)    public NNTPConnection(String hostname)
142      throws IOException      throws IOException
143    {    {
144      this (hostname, DEFAULT_PORT, 0, 0, false);      this(hostname, DEFAULT_PORT, 0, 0, false);
145    }    }
146    
147    /**    /**
# Line 150  public class NNTPConnection Line 149  public class NNTPConnection
149     * @param hostname the hostname or IP address of the news server     * @param hostname the hostname or IP address of the news server
150     * @param port the port to connect to     * @param port the port to connect to
151     */     */
152    public NNTPConnection (String hostname, int port)    public NNTPConnection(String hostname, int port)
153      throws IOException      throws IOException
154    {    {
155      this (hostname, port, 0, 0, false);      this(hostname, port, 0, 0, false);
156    }    }
157    
158    /**    /**
# Line 164  public class NNTPConnection Line 163  public class NNTPConnection
163     * @param timeout the read timeout on the socket     * @param timeout the read timeout on the socket
164     * @param debug whether to use debugging     * @param debug whether to use debugging
165     */     */
166    public NNTPConnection (String hostname, int port,    public NNTPConnection(String hostname, int port,
167                           int connectionTimeout, int timeout,                          int connectionTimeout, int timeout,
168                           boolean debug)                          boolean debug)
169      throws IOException      throws IOException
170    {    {
171      if (port < 0)      if (port < 0)
# Line 179  public class NNTPConnection Line 178  public class NNTPConnection
178      this.debug = debug;      this.debug = debug;
179            
180      // Set up the socket and streams      // Set up the socket and streams
181      socket = new Socket ();      socket = new Socket();
182      InetSocketAddress address = new InetSocketAddress (hostname, port);      InetSocketAddress address = new InetSocketAddress(hostname, port);
183      if (connectionTimeout > 0)      if (connectionTimeout > 0)
184        {        {
185          socket.connect (address, connectionTimeout);          socket.connect(address, connectionTimeout);
186        }        }
187      else      else
188        {        {
189          socket.connect (address);          socket.connect(address);
190        }        }
191      if (timeout > 0)      if (timeout > 0)
192        {        {
193          socket.setSoTimeout (timeout);          socket.setSoTimeout(timeout);
194        }        }
195      InputStream in = socket.getInputStream ();      InputStream in = socket.getInputStream();
196      in = new CRLFInputStream (in);      in = new CRLFInputStream(in);
197      this.in = new LineInputStream (in);      this.in = new LineInputStream(in);
198      OutputStream out = socket.getOutputStream ();      OutputStream out = socket.getOutputStream();
199      out = new BufferedOutputStream (out);      out = new BufferedOutputStream(out);
200      this.out = new CRLFOutputStream (out);      this.out = new CRLFOutputStream(out);
201            
202      // Read the welcome message (RFC977:2.4.3)      // Read the welcome message(RFC977:2.4.3)
203      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
204      switch (response.status)      switch (response.status)
205        {        {
206        case POSTING_ALLOWED:        case POSTING_ALLOWED:
207          canPost = true;          canPost = true;
208        case NO_POSTING_ALLOWED:        case NO_POSTING_ALLOWED:
209          welcome = response.getMessage ();          welcome = response.getMessage();
210          break;          break;
211        default:        default:
212          throw new NNTPException (response);          throw new NNTPException(response);
213        }        }
214    }    }
215        
# Line 220  public class NNTPConnection Line 219  public class NNTPConnection
219     * This message sometimes contains disclaimers or help information that     * This message sometimes contains disclaimers or help information that
220     * may be relevant to the user.     * may be relevant to the user.
221     */     */
222    public String getWelcome ()    public String getWelcome()
223    {    {
224      return welcome;      return welcome;
225    }    }
# Line 230  public class NNTPConnection Line 229  public class NNTPConnection
229     * This is only required when clients use the NEWGROUPS or NEWNEWS     * This is only required when clients use the NEWGROUPS or NEWNEWS
230     * methods, therefore rarely: we don't cache any of the variables here.     * methods, therefore rarely: we don't cache any of the variables here.
231     */     */
232    String formatDate (Date date)    String formatDate(Date date)
233    {    {
234      DateFormat df = new SimpleDateFormat ("yyMMdd HHmmss 'GMT'");      DateFormat df = new SimpleDateFormat("yyMMdd HHmmss 'GMT'");
235      Calendar cal = new GregorianCalendar ();      Calendar cal = new GregorianCalendar();
236      TimeZone gmt = TimeZone.getTimeZone ("GMT");      TimeZone gmt = TimeZone.getTimeZone("GMT");
237      cal.setTimeZone (gmt);      cal.setTimeZone(gmt);
238      df.setCalendar (cal);      df.setCalendar(cal);
239      cal.setTime (date);      cal.setTime(date);
240      return df.format (date);      return df.format(date);
241    }    }
242    
243    /*    /*
244     * Parse the specfied NNTP date text.     * Parse the specfied NNTP date text.
245     */     */
246    Date parseDate (String text)    Date parseDate(String text)
247      throws ParseException      throws ParseException
248    {    {
249      DateFormat df = new SimpleDateFormat ("yyMMdd HHmmss 'GMT'");      DateFormat df = new SimpleDateFormat("yyMMdd HHmmss 'GMT'");
250      return df.parse (text);      return df.parse(text);
251    }    }
252    
253    // RFC977:3.1 The ARTICLE, BODY, HEAD, and STAT commands    // RFC977:3.1 The ARTICLE, BODY, HEAD, and STAT commands
# Line 260  public class NNTPConnection Line 259  public class NNTPConnection
259     * 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
260     * body, separated by an empty line     * body, separated by an empty line
261     */     */
262    public ArticleResponse article (int articleNumber)    public ArticleResponse article(int articleNumber)
263      throws IOException      throws IOException
264    {    {
265      return articleImpl (ARTICLE, Integer.toString(articleNumber));      return articleImpl(ARTICLE, Integer.toString(articleNumber));
266    }    }
267        
268    /**    /**
# Line 273  public class NNTPConnection Line 272  public class NNTPConnection
272     * 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
273     * body, separated by an empty line     * body, separated by an empty line
274     */     */
275    public ArticleResponse article (String messageId)    public ArticleResponse article(String messageId)
276      throws IOException      throws IOException
277    {    {
278      return articleImpl (ARTICLE, messageId);      return articleImpl(ARTICLE, messageId);
279    }    }
280    
281    /**    /**
# Line 285  public class NNTPConnection Line 284  public class NNTPConnection
284     * @return an article response consisting of the article number and     * @return an article response consisting of the article number and
285     * message-id, and an iterator over the lines of the article header     * message-id, and an iterator over the lines of the article header
286     */     */
287    public ArticleResponse head (int articleNumber)    public ArticleResponse head(int articleNumber)
288      throws IOException      throws IOException
289    {    {
290      return articleImpl (HEAD, Integer.toString (articleNumber));      return articleImpl(HEAD, Integer.toString(articleNumber));
291    }    }
292    
293    /**    /**
# Line 297  public class NNTPConnection Line 296  public class NNTPConnection
296     * @return an article response consisting of the article number and     * @return an article response consisting of the article number and
297     * message-id, and an iterator over the lines of the article header     * message-id, and an iterator over the lines of the article header
298     */     */
299    public ArticleResponse head (String messageId)    public ArticleResponse head(String messageId)
300      throws IOException      throws IOException
301    {    {
302      return articleImpl (HEAD, messageId);      return articleImpl(HEAD, messageId);
303    }    }
304    
305    /**    /**
# Line 309  public class NNTPConnection Line 308  public class NNTPConnection
308     * @return an article response consisting of the article number and     * @return an article response consisting of the article number and
309     * message-id, and an iterator over the lines of the article body     * message-id, and an iterator over the lines of the article body
310     */     */
311    public ArticleResponse body (int articleNumber)    public ArticleResponse body(int articleNumber)
312      throws IOException      throws IOException
313    {    {
314      return articleImpl (BODY, Integer.toString (articleNumber));      return articleImpl(BODY, Integer.toString(articleNumber));
315    }    }
316    
317    /**    /**
# Line 321  public class NNTPConnection Line 320  public class NNTPConnection
320     * @return an article response consisting of the article number and     * @return an article response consisting of the article number and
321     * message-id, and an iterator over the lines of the article body     * message-id, and an iterator over the lines of the article body
322     */     */
323    public ArticleResponse body (String messageId)    public ArticleResponse body(String messageId)
324      throws IOException      throws IOException
325    {    {
326      return articleImpl (BODY, messageId);      return articleImpl(BODY, messageId);
327    }    }
328    
329    /**    /**
# Line 333  public class NNTPConnection Line 332  public class NNTPConnection
332     * @return an article response consisting of the article number and     * @return an article response consisting of the article number and
333     * message-id     * message-id
334     */     */
335    public ArticleResponse stat (int articleNumber)    public ArticleResponse stat(int articleNumber)
336      throws IOException      throws IOException
337    {    {
338      return articleImpl (STAT, Integer.toString (articleNumber));      return articleImpl(STAT, Integer.toString(articleNumber));
339    }    }
340    
341    /**    /**
# Line 345  public class NNTPConnection Line 344  public class NNTPConnection
344     * @return an article response consisting of the article number and     * @return an article response consisting of the article number and
345     * message-id     * message-id
346     */     */
347    public ArticleResponse stat (String messageId)    public ArticleResponse stat(String messageId)
348      throws IOException      throws IOException
349    {    {
350      return articleImpl (STAT, messageId);      return articleImpl(STAT, messageId);
351    }    }
352    
353    /**    /**
# Line 356  public class NNTPConnection Line 355  public class NNTPConnection
355     * @param command one of the above commands     * @param command one of the above commands
356     * @param messageId the article-number or message-id in string form     * @param messageId the article-number or message-id in string form
357     */     */
358    protected ArticleResponse articleImpl (String command, String messageId)    protected ArticleResponse articleImpl(String command, String messageId)
359      throws IOException      throws IOException
360    {    {
361      if (messageId != null)      if (messageId != null)
362        {        {
363          StringBuffer line = new StringBuffer (command);          StringBuffer line = new StringBuffer(command);
364          line.append (' ');          line.append(' ');
365          line.append (messageId);          line.append(messageId);
366          send (line.toString ());          send(line.toString());
367        }        }
368      else      else
369        {        {
370          send (command);          send(command);
371        }        }
372      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
373      switch (response.status)      switch (response.status)
374        {        {
375        case ARTICLE_FOLLOWS:        case ARTICLE_FOLLOWS:
# Line 378  public class NNTPConnection Line 377  public class NNTPConnection
377        case BODY_FOLLOWS:        case BODY_FOLLOWS:
378          ArticleResponse aresponse = (ArticleResponse) response;          ArticleResponse aresponse = (ArticleResponse) response;
379          ArticleStream astream =          ArticleStream astream =
380            new ArticleStream (new MessageInputStream (in));            new ArticleStream(new MessageInputStream(in));
381          pendingData = astream;          pendingData = astream;
382          aresponse.in = astream;          aresponse.in = astream;
383          return aresponse;          return aresponse;
# Line 391  public class NNTPConnection Line 390  public class NNTPConnection
390          // NO_SUCH_ARTICLE          // NO_SUCH_ARTICLE
391          // NO_PREVIOUS_ARTICLE          // NO_PREVIOUS_ARTICLE
392          // NO_NEXT_ARTICLE          // NO_NEXT_ARTICLE
393          throw new NNTPException (response);          throw new NNTPException(response);
394        }        }
395    }    }
396        
# Line 402  public class NNTPConnection Line 401  public class NNTPConnection
401     * Returns a group status response.     * Returns a group status response.
402     * @param name the name of the group to select     * @param name the name of the group to select
403     */     */
404    public GroupResponse group (String name)    public GroupResponse group(String name)
405      throws IOException      throws IOException
406    {    {
407      send (GROUP + ' ' + name);      send(GROUP + ' ' + name);
408      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
409      switch (response.status)      switch (response.status)
410        {        {
411        case GROUP_SELECTED:        case GROUP_SELECTED:
412          return (GroupResponse) response;          return (GroupResponse) response;
413        default:        default:
414          // NO_SUCH_GROUP          // NO_SUCH_GROUP
415          throw new NNTPException (response);          throw new NNTPException(response);
416        }        }
417    }    }
418    
# Line 423  public class NNTPConnection Line 422  public class NNTPConnection
422     * Requests a help listing.     * Requests a help listing.
423     * @return an iterator over a collection of help lines.     * @return an iterator over a collection of help lines.
424     */     */
425    public LineIterator help ()    public LineIterator help()
426      throws IOException      throws IOException
427    {    {
428      send (HELP);      send(HELP);
429      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
430      switch (response.status)      switch (response.status)
431        {        {
432        case HELP_TEXT:        case HELP_TEXT:
433          LineIterator li = new LineIterator (this);          LineIterator li = new LineIterator(this);
434          pendingData = li;          pendingData = li;
435          return li;          return li;
436        default:        default:
437          throw new NNTPException (response);          throw new NNTPException(response);
438        }        }
439    }    }
440        
# Line 448  public class NNTPConnection Line 447  public class NNTPConnection
447     * @return a PostStream if the server wants the specified article, null     * @return a PostStream if the server wants the specified article, null
448     * otherwise     * otherwise
449     */     */
450    public PostStream ihave (String messageId)    public PostStream ihave(String messageId)
451      throws IOException      throws IOException
452    {    {
453      send (IHAVE + ' ' + messageId);      send(IHAVE + ' ' + messageId);
454      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
455      switch (response.status)      switch (response.status)
456        {        {
457        case SEND_TRANSFER_ARTICLE:        case SEND_TRANSFER_ARTICLE:
458          return new PostStream (this, false);          return new PostStream(this, false);
459        case ARTICLE_NOT_WANTED:        case ARTICLE_NOT_WANTED:
460          return null;          return null;
461        default:        default:
462          throw new NNTPException (response);          throw new NNTPException(response);
463        }        }
464    }    }
465    
# Line 471  public class NNTPConnection Line 470  public class NNTPConnection
470     * @return the article number/message-id pair associated with the new     * @return the article number/message-id pair associated with the new
471     * article     * article
472     */     */
473    public ArticleResponse last ()    public ArticleResponse last()
474      throws IOException      throws IOException
475    {    {
476      return articleImpl (LAST, null);      return articleImpl(LAST, null);
477    }    }
478    
479    // RFC977:3.6 The LIST command    // RFC977:3.6 The LIST command
# Line 484  public class NNTPConnection Line 483  public class NNTPConnection
483     * Returns a GroupIterator. This must be read fully before other commands     * Returns a GroupIterator. This must be read fully before other commands
484     * are issued.     * are issued.
485     */     */
486    public GroupIterator list ()    public GroupIterator list()
487      throws IOException      throws IOException
488    {    {
489      return listImpl (LIST);      return listImpl(LIST);
490    }    }
491        
492    GroupIterator listImpl (String command)    GroupIterator listImpl(String command)
493      throws IOException      throws IOException
494    {    {
495      send (command);      send(command);
496      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
497      switch (response.status)      switch (response.status)
498        {        {
499        case LIST_FOLLOWS:        case LIST_FOLLOWS:
500          GroupIterator gi = new GroupIterator (this);          GroupIterator gi = new GroupIterator(this);
501          pendingData = gi;          pendingData = gi;
502          return gi;          return gi;
503        default:        default:
504          throw new NNTPException (response);          throw new NNTPException(response);
505        }        }
506    }    }
507    
# Line 516  public class NNTPConnection Line 515  public class NNTPConnection
515     * @param since the date from which to list new groups     * @param since the date from which to list new groups
516     * @param distributions if non-null, an array of distributions to match     * @param distributions if non-null, an array of distributions to match
517     */     */
518    public LineIterator newGroups (Date since, String[]distributions)    public LineIterator newGroups(Date since, String[]distributions)
519      throws IOException      throws IOException
520    {    {
521      StringBuffer buffer = new StringBuffer (NEWGROUPS);      StringBuffer buffer = new StringBuffer(NEWGROUPS);
522      buffer.append (' ');      buffer.append(' ');
523      buffer.append (formatDate (since));      buffer.append(formatDate(since));
524      if (distributions != null)      if (distributions != null)
525        {        {
526          buffer.append (' ');          buffer.append(' ');
527          for (int i = 0; i < distributions.length; i++)          for (int i = 0; i < distributions.length; i++)
528            {            {
529              if (i > 0)              if (i > 0)
530                {                {
531                  buffer.append (',');                  buffer.append(',');
532                }                }
533              buffer.append (distributions[i]);              buffer.append(distributions[i]);
534            }            }
535        }        }
536      send (buffer.toString ());      send(buffer.toString());
537      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
538      switch (response.status)      switch (response.status)
539        {        {
540        case NEWGROUPS_LIST_FOLLOWS:        case NEWGROUPS_LIST_FOLLOWS:
541          LineIterator li = new LineIterator (this);          LineIterator li = new LineIterator(this);
542          pendingData = li;          pendingData = li;
543          return li;          return li;
544        default:        default:
545          throw new NNTPException (response);          throw new NNTPException(response);
546        }        }
547    }    }
548        
# Line 558  public class NNTPConnection Line 557  public class NNTPConnection
557     * @param since the date from which to list new articles     * @param since the date from which to list new articles
558     * @param distributions if non-null, a list of distributions to match     * @param distributions if non-null, a list of distributions to match
559     */     */
560    public LineIterator newNews (String newsgroup, Date since,    public LineIterator newNews(String newsgroup, Date since,
561                                 String[] distributions)                                String[] distributions)
562      throws IOException      throws IOException
563    {    {
564      StringBuffer buffer = new StringBuffer (NEWNEWS);      StringBuffer buffer = new StringBuffer(NEWNEWS);
565      buffer.append (' ');      buffer.append(' ');
566      buffer.append (newsgroup);      buffer.append(newsgroup);
567      buffer.append (' ');      buffer.append(' ');
568      buffer.append (formatDate (since));      buffer.append(formatDate(since));
569      if (distributions != null)      if (distributions != null)
570        {        {
571          buffer.append (' ');          buffer.append(' ');
572          for (int i = 0; i < distributions.length; i++)          for (int i = 0; i < distributions.length; i++)
573            {            {
574              if (i > 0)              if (i > 0)
575                {                {
576                  buffer.append (',');                  buffer.append(',');
577                }                }
578              buffer.append (distributions[i]);              buffer.append(distributions[i]);
579            }            }
580        }        }
581      send (buffer.toString ());      send(buffer.toString());
582      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
583      switch (response.status)      switch (response.status)
584        {        {
585        case NEWNEWS_LIST_FOLLOWS:        case NEWNEWS_LIST_FOLLOWS:
586          LineIterator li = new LineIterator (this);          LineIterator li = new LineIterator(this);
587          pendingData = li;          pendingData = li;
588          return li;          return li;
589        default:        default:
590          throw new NNTPException (response);          throw new NNTPException(response);
591        }        }
592    }    }
593        
# Line 599  public class NNTPConnection Line 598  public class NNTPConnection
598     * @return the article number/message-id pair associated with the new     * @return the article number/message-id pair associated with the new
599     * article     * article
600     */     */
601    public ArticleResponse next ()    public ArticleResponse next()
602      throws IOException      throws IOException
603    {    {
604      return articleImpl (NEXT, null);      return articleImpl(NEXT, null);
605    }    }
606    
607    // RFC977:3.10 The POST command    // RFC977:3.10 The POST command
# Line 616  public class NNTPConnection Line 615  public class NNTPConnection
615     * No other method should be called in between.     * No other method should be called in between.
616     * @see #postComplete     * @see #postComplete
617     */     */
618    public OutputStream post ()    public OutputStream post()
619      throws IOException      throws IOException
620    {    {
621      send (POST);      send(POST);
622      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
623      switch (response.status)      switch (response.status)
624        {        {
625        case SEND_ARTICLE:        case SEND_ARTICLE:
626          return new PostStream (this, false);          return new PostStream(this, false);
627        default:        default:
628          // POSTING_NOT_ALLOWED          // POSTING_NOT_ALLOWED
629          throw new NNTPException (response);          throw new NNTPException(response);
630        }        }
631    }    }
632        
# Line 637  public class NNTPConnection Line 636  public class NNTPConnection
636     * Called by the PostStream during <code>close()</code>.     * Called by the PostStream during <code>close()</code>.
637     * @see #post     * @see #post
638     */     */
639    void postComplete ()    void postComplete()
640      throws IOException      throws IOException
641    {    {
642      send (DOT);      send(DOT);
643      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
644      switch (response.status)      switch (response.status)
645        {        {
646        case ARTICLE_POSTED:        case ARTICLE_POSTED:
# Line 651  public class NNTPConnection Line 650  public class NNTPConnection
650          // POSTING_FAILED          // POSTING_FAILED
651          // TRANSFER_FAILED          // TRANSFER_FAILED
652          // ARTICLE_REJECTED          // ARTICLE_REJECTED
653          throw new NNTPException (response);          throw new NNTPException(response);
654        }        }
655    }    }
656    
# Line 661  public class NNTPConnection Line 660  public class NNTPConnection
660     * Close the connection.     * Close the connection.
661     * After calling this method, no further calls on this object are valid.     * After calling this method, no further calls on this object are valid.
662     */     */
663    public void quit ()    public void quit()
664      throws IOException      throws IOException
665    {    {
666      send (QUIT);      send(QUIT);
667      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
668      switch (response.status)      switch (response.status)
669        {        {
670        case CLOSING_CONNECTION:        case CLOSING_CONNECTION:
671          socket.close ();          socket.close();
672          return;          return;
673        default:        default:
674          throw new NNTPException (response);          throw new NNTPException(response);
675        }        }
676    }    }
677        
# Line 681  public class NNTPConnection Line 680  public class NNTPConnection
680    /**    /**
681     * Indicates to the server that this is a slave connection.     * Indicates to the server that this is a slave connection.
682     */     */
683    public void slave ()    public void slave()
684      throws IOException      throws IOException
685    {    {
686      send (SLAVE);      send(SLAVE);
687      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
688      switch (response.status)      switch (response.status)
689        {        {
690        case SLAVE_ACKNOWLEDGED:        case SLAVE_ACKNOWLEDGED:
691          break;          break;
692        default:        default:
693          throw new NNTPException (response);          throw new NNTPException(response);
694        }        }
695    }    }
696        
697    // RFC2980:1.1 The CHECK command    // RFC2980:1.1 The CHECK command
698    
699    public boolean check (String messageId)    public boolean check(String messageId)
700      throws IOException      throws IOException
701    {    {
702      StringBuffer buffer = new StringBuffer (CHECK);      StringBuffer buffer = new StringBuffer(CHECK);
703      buffer.append (' ');      buffer.append(' ');
704      buffer.append (messageId);      buffer.append(messageId);
705      send (buffer.toString ());      send(buffer.toString());
706      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
707      switch (response.status)      switch (response.status)
708        {        {
709        case SEND_ARTICLE_VIA_TAKETHIS:        case SEND_ARTICLE_VIA_TAKETHIS:
# Line 716  public class NNTPConnection Line 715  public class NNTPConnection
715          // TRY_AGAIN_LATER          // TRY_AGAIN_LATER
716          // TRANSFER_PERMISSION_DENIED          // TRANSFER_PERMISSION_DENIED
717          // COMMAND_NOT_RECOGNIZED          // COMMAND_NOT_RECOGNIZED
718          throw new NNTPException (response);          throw new NNTPException(response);
719        }        }
720    }    }
721    
# Line 729  public class NNTPConnection Line 728  public class NNTPConnection
728     *     *
729     * @return true if the server supports streaming mode     * @return true if the server supports streaming mode
730     */     */
731    public boolean modeStream ()    public boolean modeStream()
732      throws IOException      throws IOException
733    {    {
734      send (MODE_STREAM);      send(MODE_STREAM);
735      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
736      switch (response.status)      switch (response.status)
737        {        {
738        case STREAMING_OK:        case STREAMING_OK:
# Line 753  public class NNTPConnection Line 752  public class NNTPConnection
752     * stream.     * stream.
753     * @see #takethisComplete     * @see #takethisComplete
754     */     */
755    public OutputStream takethis (String messageId)    public OutputStream takethis(String messageId)
756      throws IOException      throws IOException
757    {    {
758      send (TAKETHIS + ' ' + messageId);      send(TAKETHIS + ' ' + messageId);
759      return new PostStream (this, true);      return new PostStream(this, true);
760    }    }
761    
762    /**    /**
# Line 765  public class NNTPConnection Line 764  public class NNTPConnection
764     * Called by PostStream.close().     * Called by PostStream.close().
765     * @see #takethis     * @see #takethis
766     */     */
767    void takethisComplete ()    void takethisComplete()
768      throws IOException      throws IOException
769    {    {
770      send (DOT);      send(DOT);
771      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
772      switch (response.status)      switch (response.status)
773        {        {
774        case ARTICLE_TRANSFERRED_OK:        case ARTICLE_TRANSFERRED_OK:
# Line 779  public class NNTPConnection Line 778  public class NNTPConnection
778          // ARTICLE_TRANSFER_FAILED          // ARTICLE_TRANSFER_FAILED
779          // TRANSFER_PERMISSION_DENIED          // TRANSFER_PERMISSION_DENIED
780          // COMMAND_NOT_RECOGNIZED          // COMMAND_NOT_RECOGNIZED
781          throw new NNTPException (response);          throw new NNTPException(response);
782        }        }
783    }    }
784        
# Line 796  public class NNTPConnection Line 795  public class NNTPConnection
795     * @param wildmat the wildmat pattern. If null, returns all groups. If no     * @param wildmat the wildmat pattern. If null, returns all groups. If no
796     * groups are matched, returns an empty iterator.     * groups are matched, returns an empty iterator.
797     */     */
798    public GroupIterator listActive (String wildmat)    public GroupIterator listActive(String wildmat)
799      throws IOException      throws IOException
800    {    {
801      StringBuffer buffer = new StringBuffer (LIST_ACTIVE);      StringBuffer buffer = new StringBuffer(LIST_ACTIVE);
802      if (wildmat != null)      if (wildmat != null)
803        {        {
804          buffer.append (' ');          buffer.append(' ');
805          buffer.append (wildmat);          buffer.append(wildmat);
806        }        }
807      return listImpl (buffer.toString ());      return listImpl(buffer.toString());
808    }    }
809        
810    // RFC2980:2.1.3 The LIST ACTIVE.TIMES command    // RFC2980:2.1.3 The LIST ACTIVE.TIMES command
# Line 815  public class NNTPConnection Line 814  public class NNTPConnection
814     * Each ActiveTime object returned provides details of who created the     * Each ActiveTime object returned provides details of who created the
815     * newsgroup and when.     * newsgroup and when.
816     */     */
817    public ActiveTimesIterator listActiveTimes ()    public ActiveTimesIterator listActiveTimes()
818      throws IOException      throws IOException
819    {    {
820      send (LIST_ACTIVE_TIMES);      send(LIST_ACTIVE_TIMES);
821      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
822      switch (response.status)      switch (response.status)
823        {        {
824        case LIST_FOLLOWS:        case LIST_FOLLOWS:
825          return new ActiveTimesIterator (this);          return new ActiveTimesIterator(this);
826        default:        default:
827          throw new NNTPException (response);          throw new NNTPException(response);
828        }        }
829    }    }
830    
# Line 846  public class NNTPConnection Line 845  public class NNTPConnection
845     * @return an iterator over group name/description pairs     * @return an iterator over group name/description pairs
846     * @see #xgtitle     * @see #xgtitle
847     */     */
848    public PairIterator listNewsgroups (String wildmat)    public PairIterator listNewsgroups(String wildmat)
849      throws IOException      throws IOException
850    {    {
851      StringBuffer buffer = new StringBuffer (LIST_NEWSGROUPS);      StringBuffer buffer = new StringBuffer(LIST_NEWSGROUPS);
852      if (wildmat != null)      if (wildmat != null)
853        {        {
854          buffer.append (' ');          buffer.append(' ');
855          buffer.append (wildmat);          buffer.append(wildmat);
856        }        }
857      send (buffer.toString ());      send(buffer.toString());
858      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
859      switch (response.status)      switch (response.status)
860        {        {
861        case LIST_FOLLOWS:        case LIST_FOLLOWS:
862          PairIterator pi = new PairIterator (this);          PairIterator pi = new PairIterator(this);
863          pendingData = pi;          pendingData = pi;
864          return pi;          return pi;
865        default:        default:
866          throw new NNTPException (response);          throw new NNTPException(response);
867        }        }
868    }    }
869    
# Line 876  public class NNTPConnection Line 875  public class NNTPConnection
875     * Each line returned by the iterator contains one header field.     * Each line returned by the iterator contains one header field.
876     * @see #xover     * @see #xover
877     */     */
878    public LineIterator listOverviewFmt ()    public LineIterator listOverviewFmt()
879      throws IOException      throws IOException
880    {    {
881      send (LIST_OVERVIEW_FMT);      send(LIST_OVERVIEW_FMT);
882      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
883      switch (response.status)      switch (response.status)
884        {        {
885        case LIST_FOLLOWS:        case LIST_FOLLOWS:
886          LineIterator li = new LineIterator (this);          LineIterator li = new LineIterator(this);
887          pendingData = li;          pendingData = li;
888          return li;          return li;
889        default:        default:
890          throw new NNTPException (response);          throw new NNTPException(response);
891        }        }
892    }    }
893        
# Line 897  public class NNTPConnection Line 896  public class NNTPConnection
896    /**    /**
897     * Returns a list of newsgroups suitable for new users of the server.     * Returns a list of newsgroups suitable for new users of the server.
898     */     */
899    public GroupIterator listSubscriptions ()    public GroupIterator listSubscriptions()
900      throws IOException      throws IOException
901    {    {
902      return listImpl (LIST_SUBSCRIPTIONS);      return listImpl(LIST_SUBSCRIPTIONS);
903    }    }
904    
905    // RFC2980:2.2 The LISTGROUP command    // RFC2980:2.2 The LISTGROUP command
# Line 911  public class NNTPConnection Line 910  public class NNTPConnection
910     * selected group is assumed.     * selected group is assumed.
911     * @param group the name of the group to list articles for     * @param group the name of the group to list articles for
912     */     */
913    public ArticleNumberIterator listGroup (String group)    public ArticleNumberIterator listGroup(String group)
914      throws IOException      throws IOException
915    {    {
916      StringBuffer buffer = new StringBuffer (LISTGROUP);      StringBuffer buffer = new StringBuffer(LISTGROUP);
917      if (group != null)      if (group != null)
918        {        {
919          buffer.append (' ');          buffer.append(' ');
920          buffer.append (group);          buffer.append(group);
921        }        }
922      send (buffer.toString ());      send(buffer.toString());
923      StatusResponse response = parseResponse (read (), true);      StatusResponse response = parseResponse(read(), true);
924      switch (response.status)      switch (response.status)
925        {        {
926        case GROUP_SELECTED:        case GROUP_SELECTED:
927          ArticleNumberIterator ani = new ArticleNumberIterator (this);          ArticleNumberIterator ani = new ArticleNumberIterator(this);
928          pendingData = ani;          pendingData = ani;
929          return ani;          return ani;
930        default:        default:
931          throw new NNTPException (response);          throw new NNTPException(response);
932        }        }
933    }    }
934    
# Line 939  public class NNTPConnection Line 938  public class NNTPConnection
938     * Indicates to the server that this is a user-agent.     * Indicates to the server that this is a user-agent.
939     * @return true if posting is allowed, false otherwise.     * @return true if posting is allowed, false otherwise.
940     */     */
941    public boolean modeReader ()    public boolean modeReader()
942      throws IOException      throws IOException
943    {    {
944      send (MODE_READER);      send(MODE_READER);
945      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
946      switch (response.status)      switch (response.status)
947        {        {
948        case POSTING_ALLOWED:        case POSTING_ALLOWED:
# Line 953  public class NNTPConnection Line 952  public class NNTPConnection
952          canPost = false;          canPost = false;
953          return canPost;          return canPost;
954        default:        default:
955          throw new NNTPException (response);          throw new NNTPException(response);
956        }        }
957    }    }
958        
# Line 963  public class NNTPConnection Line 962  public class NNTPConnection
962     * Returns an iterator over the list of newsgroup descriptions.     * Returns an iterator over the list of newsgroup descriptions.
963     * @param wildmat if non-null, the newsgroups to match     * @param wildmat if non-null, the newsgroups to match
964     */     */
965    public PairIterator xgtitle (String wildmat)    public PairIterator xgtitle(String wildmat)
966      throws IOException      throws IOException
967    {    {
968      StringBuffer buffer = new StringBuffer (XGTITLE);      StringBuffer buffer = new StringBuffer(XGTITLE);
969      if (wildmat != null)      if (wildmat != null)
970        {        {
971          buffer.append (' ');          buffer.append(' ');
972          buffer.append (wildmat);          buffer.append(wildmat);
973        }        }
974      send (buffer.toString ());      send(buffer.toString());
975      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
976      switch (response.status)      switch (response.status)
977        {        {
978        case XGTITLE_LIST_FOLLOWS:        case XGTITLE_LIST_FOLLOWS:
979          PairIterator pi = new PairIterator (this);          PairIterator pi = new PairIterator(this);
980          pendingData = pi;          pendingData = pi;
981          return pi;          return pi;
982        default:        default:
983          throw new NNTPException (response);          throw new NNTPException(response);
984        }        }
985    }    }
986        
987    // RFC2980:2.6 The XHDR command    // RFC2980:2.6 The XHDR command
988    
989    public HeaderIterator xhdr (String header, String range)    public HeaderIterator xhdr(String header, String range)
990      throws IOException      throws IOException
991    {    {
992      StringBuffer buffer = new StringBuffer (XHDR);      StringBuffer buffer = new StringBuffer(XHDR);
993      buffer.append (' ');      buffer.append(' ');
994      buffer.append (header);      buffer.append(header);
995      if (range != null)      if (range != null)
996        {        {
997          buffer.append (' ');          buffer.append(' ');
998          buffer.append (range);          buffer.append(range);
999        }        }
1000      send (buffer.toString ());      send(buffer.toString());
1001      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
1002      switch (response.status)      switch (response.status)
1003        {        {
1004        case HEAD_FOLLOWS:        case HEAD_FOLLOWS:
1005          HeaderIterator hi = new HeaderIterator (this);          HeaderIterator hi = new HeaderIterator(this);
1006          pendingData = hi;          pendingData = hi;
1007          return hi;          return hi;
1008        default:        default:
1009          // NO_GROUP_SELECTED          // NO_GROUP_SELECTED
1010          // NO_SUCH_ARTICLE          // NO_SUCH_ARTICLE
1011          throw new NNTPException (response);          throw new NNTPException(response);
1012        }        }
1013    }    }
1014    
# Line 1019  public class NNTPConnection Line 1018  public class NNTPConnection
1018    
1019    // RFC2980:2.8 The XOVER command    // RFC2980:2.8 The XOVER command
1020    
1021    public OverviewIterator xover (Range range)    public OverviewIterator xover(Range range)
1022      throws IOException      throws IOException
1023    {    {
1024      StringBuffer buffer = new StringBuffer (XOVER);      StringBuffer buffer = new StringBuffer(XOVER);
1025      if (range != null)      if (range != null)
1026        {        {
1027          buffer.append (' ');          buffer.append(' ');
1028          buffer.append (range.toString());          buffer.append(range.toString());
1029        }        }
1030      send (buffer.toString ());      send(buffer.toString());
1031      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
1032      switch (response.status)      switch (response.status)
1033        {        {
1034        case OVERVIEW_FOLLOWS:        case OVERVIEW_FOLLOWS:
1035          OverviewIterator oi = new OverviewIterator (this);          OverviewIterator oi = new OverviewIterator(this);
1036          pendingData = oi;          pendingData = oi;
1037          return oi;          return oi;
1038        default:        default:
1039          // NO_GROUP_SELECTED          // NO_GROUP_SELECTED
1040          // PERMISSION_DENIED          // PERMISSION_DENIED
1041          throw new NNTPException (response);          throw new NNTPException(response);
1042        }        }
1043    }    }
1044        
# Line 1064  public class NNTPConnection Line 1063  public class NNTPConnection
1063    /**    /**
1064     * Basic authentication strategy.     * Basic authentication strategy.
1065     * @param username the user to authenticate     * @param username the user to authenticate
1066     * @param password the (cleartext) password     * @param password the(cleartext) password
1067     * @return true on success, false on failure     * @return true on success, false on failure
1068     */     */
1069    public boolean authinfo (String username, String password)    public boolean authinfo(String username, String password)
1070      throws IOException      throws IOException
1071    {    {
1072      StringBuffer buffer = new StringBuffer (AUTHINFO_USER);      StringBuffer buffer = new StringBuffer(AUTHINFO_USER);
1073      buffer.append (' ');      buffer.append(' ');
1074      buffer.append (username);      buffer.append(username);
1075      send (buffer.toString ());      send(buffer.toString());
1076      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
1077      switch (response.status)      switch (response.status)
1078        {        {
1079        case AUTHINFO_OK:        case AUTHINFO_OK:
1080          return true;          return true;
1081        case SEND_AUTHINFOPASS:        case SEND_AUTHINFOPASS:
1082          buffer.setLength (0);          buffer.setLength(0);
1083          buffer.append (AUTHINFO_PASS);          buffer.append(AUTHINFO_PASS);
1084          buffer.append (' ');          buffer.append(' ');
1085          buffer.append (password);          buffer.append(password);
1086          send (buffer.toString ());          send(buffer.toString());
1087          response = parseResponse (read ());          response = parseResponse(read());
1088          switch (response.status)          switch (response.status)
1089            {            {
1090            case AUTHINFO_OK:            case AUTHINFO_OK:
# Line 1093  public class NNTPConnection Line 1092  public class NNTPConnection
1092            case PERMISSION_DENIED:            case PERMISSION_DENIED:
1093              return false;              return false;
1094            default:            default:
1095              throw new NNTPException (response);              throw new NNTPException(response);
1096            }            }
1097        default:        default:
1098          // AUTHINFO_REJECTED          // AUTHINFO_REJECTED
1099          throw new NNTPException (response);          throw new NNTPException(response);
1100        }        }
1101    }    }
1102    
# Line 1108  public class NNTPConnection Line 1107  public class NNTPConnection
1107     * Note that use of this authentication strategy is highly deprecated,     * Note that use of this authentication strategy is highly deprecated,
1108     * only use on servers that won't accept any other form of authentication.     * only use on servers that won't accept any other form of authentication.
1109     */     */
1110    public boolean authinfoSimple (String username, String password)    public boolean authinfoSimple(String username, String password)
1111      throws IOException      throws IOException
1112    {    {
1113      send (AUTHINFO_SIMPLE);      send(AUTHINFO_SIMPLE);
1114      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
1115      switch (response.status)      switch (response.status)
1116        {        {
1117        case SEND_AUTHINFO_SIMPLE:        case SEND_AUTHINFO_SIMPLE:
1118          StringBuffer buffer = new StringBuffer (username);          StringBuffer buffer = new StringBuffer(username);
1119          buffer.append (' ');          buffer.append(' ');
1120          buffer.append (password);          buffer.append(password);
1121          send (buffer.toString ());          send(buffer.toString());
1122          response = parseResponse (read ());          response = parseResponse(read());
1123          switch (response.status)          switch (response.status)
1124            {            {
1125            case AUTHINFO_SIMPLE_OK:            case AUTHINFO_SIMPLE_OK:
1126              return true;              return true;
1127            case AUTHINFO_SIMPLE_DENIED:            case AUTHINFO_SIMPLE_DENIED:
1128              return false;              return false;
1129            default:throw new NNTPException (response);            default:throw new NNTPException(response);
1130            }            }
1131        default:        default:
1132          throw new NNTPException (response);          throw new NNTPException(response);
1133        }        }
1134    }    }
1135        
# Line 1144  public class NNTPConnection Line 1143  public class NNTPConnection
1143     * @param username the authentication principal     * @param username the authentication principal
1144     * @param password the authentication credentials     * @param password the authentication credentials
1145     */     */
1146    public boolean authinfoGeneric (String mechanism,    public boolean authinfoGeneric(String mechanism,
1147                                    String username, String password)                                    String username, String password)
1148      throws IOException      throws IOException
1149    {    {
1150      String[] m = new String[] { mechanism };      String[] m = new String[] { mechanism };
1151      CallbackHandler ch = new SaslCallbackHandler (username, password);      CallbackHandler ch = new SaslCallbackHandler(username, password);
1152      // Avoid lengthy callback procedure for GNU Crypto      // Avoid lengthy callback procedure for GNU Crypto
1153      Properties p = new Properties ();      Properties p = new Properties();
1154      p.put ("gnu.crypto.sasl.username", username);      p.put("gnu.crypto.sasl.username", username);
1155      p.put ("gnu.crypto.sasl.password", password);      p.put("gnu.crypto.sasl.password", password);
1156      SaslClient sasl =      SaslClient sasl =
1157        Sasl.createSaslClient (m, null, "smtp",        Sasl.createSaslClient(m, null, "smtp",
1158                               socket.getInetAddress ().getHostName (),                               socket.getInetAddress().getHostName(),
1159                               p, ch);                               p, ch);
1160      if (sasl == null)      if (sasl == null)
1161        {        {
1162          return false;          return false;
1163        }        }
1164            
1165      StringBuffer cmd = new StringBuffer (AUTHINFO_GENERIC);      StringBuffer cmd = new StringBuffer(AUTHINFO_GENERIC);
1166      cmd.append (' ');      cmd.append(' ');
1167      cmd.append (mechanism);      cmd.append(mechanism);
1168      if (sasl.hasInitialResponse ())      if (sasl.hasInitialResponse())
1169        {        {
1170          cmd.append (' ');          cmd.append(' ');
1171          byte[] init = sasl.evaluateChallenge (new byte[0]);          byte[] init = sasl.evaluateChallenge(new byte[0]);
1172          cmd.append (new String (init, "US-ASCII"));          cmd.append(new String(init, "US-ASCII"));
1173        }        }
1174      send (cmd.toString ());      send(cmd.toString());
1175      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
1176      switch (response.status)      switch (response.status)
1177        {        {
1178        case AUTHINFO_OK:        case AUTHINFO_OK:
1179          String qop = (String) sasl.getNegotiatedProperty (Sasl.QOP);          String qop = (String) sasl.getNegotiatedProperty(Sasl.QOP);
1180          if ("auth-int".equalsIgnoreCase (qop)          if ("auth-int".equalsIgnoreCase(qop)
1181              || "auth-conf".equalsIgnoreCase (qop))              || "auth-conf".equalsIgnoreCase(qop))
1182            {            {
1183              InputStream in = socket.getInputStream ();              InputStream in = socket.getInputStream();
1184              in = new BufferedInputStream (in);              in = new BufferedInputStream(in);
1185              in = new SaslInputStream (sasl, in);              in = new SaslInputStream(sasl, in);
1186              in = new CRLFInputStream (in);              in = new CRLFInputStream(in);
1187              this.in = new LineInputStream (in);              this.in = new LineInputStream(in);
1188              OutputStream out = socket.getOutputStream ();              OutputStream out = socket.getOutputStream();
1189              out = new BufferedOutputStream (out);              out = new BufferedOutputStream(out);
1190              out = new SaslOutputStream (sasl, out);              out = new SaslOutputStream(sasl, out);
1191              this.out = new CRLFOutputStream (out);              this.out = new CRLFOutputStream(out);
1192            }            }
1193          return true;          return true;
1194        case PERMISSION_DENIED:        case PERMISSION_DENIED:
# Line 1198  public class NNTPConnection Line 1197  public class NNTPConnection
1197        case SYNTAX_ERROR:        case SYNTAX_ERROR:
1198        case INTERNAL_ERROR:        case INTERNAL_ERROR:
1199        default:        default:
1200          throw new NNTPException (response);          throw new NNTPException(response);
1201          // FIXME how does the server send continuations?          // FIXME how does the server send continuations?
1202        }        }
1203    }    }
# Line 1208  public class NNTPConnection Line 1207  public class NNTPConnection
1207    /**    /**
1208     * Returns the date on the server.     * Returns the date on the server.
1209     */     */
1210    public Date date ()    public Date date()
1211      throws IOException      throws IOException
1212    {    {
1213      send (DATE);      send(DATE);
1214      StatusResponse response = parseResponse (read ());      StatusResponse response = parseResponse(read());
1215      switch (response.status)      switch (response.status)
1216        {        {
1217        case DATE_OK:        case DATE_OK:
1218          String message = response.getMessage ();          String message = response.getMessage();
1219          try          try
1220            {            {
1221              DateFormat df = new SimpleDateFormat ("yyyyMMddHHmmss");              DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
1222              return df.parse (message);              return df.parse(message);
1223            }            }
1224          catch (ParseException e)          catch (ParseException e)
1225            {            {
1226              throw new IOException ("Invalid date: " + message);              throw new IOException("Invalid date: " + message);
1227            }            }
1228        default:        default:
1229          throw new NNTPException (response);          throw new NNTPException(response);
1230        }        }
1231    }    }
1232    
# Line 1236  public class NNTPConnection Line 1235  public class NNTPConnection
1235    /**    /**
1236     * Parse a response object from a response line sent by the server.     * Parse a response object from a response line sent by the server.
1237     */     */
1238    protected StatusResponse parseResponse (String line)    protected StatusResponse parseResponse(String line)
1239      throws ProtocolException      throws ProtocolException
1240    {    {
1241      return parseResponse (line, false);      return parseResponse(line, false);
1242    }    }
1243        
1244    /**    /**
1245     * Parse a response object from a response line sent by the server.     * Parse a response object from a response line sent by the server.
1246     * @param isListGroup whether we are invoking the LISTGROUP command     * @param isListGroup whether we are invoking the LISTGROUP command
1247     */     */
1248    protected StatusResponse parseResponse (String line, boolean isListGroup)    protected StatusResponse parseResponse(String line, boolean isListGroup)
1249      throws ProtocolException      throws ProtocolException
1250    {    {
1251      if (line == null)      if (line == null)
1252        {        {
1253          throw new ProtocolException (hostname + " closed connection");          throw new ProtocolException(hostname + " closed connection");
1254        }        }
1255      int start = 0, end;      int start = 0, end;
1256      short status = -1;      short status = -1;
1257      String statusText = line;      String statusText = line;
1258      String message = null;      String message = null;
1259      end = line.indexOf (' ', start);      end = line.indexOf(' ', start);
1260      if (end > start)      if (end > start)
1261        {        {
1262          statusText = line.substring (start, end);          statusText = line.substring(start, end);
1263          message = line.substring (end + 1);          message = line.substring(end + 1);
1264        }        }
1265      try      try
1266        {        {
1267          status = Short.parseShort (statusText);          status = Short.parseShort(statusText);
1268        }        }
1269      catch (NumberFormatException e)      catch (NumberFormatException e)
1270        {        {
1271          throw new ProtocolException (line);          throw new ProtocolException(line);
1272        }        }
1273      StatusResponse response;      StatusResponse response;
1274      switch (status)      switch (status)
# Line 1287  public class NNTPConnection Line 1286  public class NNTPConnection
1286              try              try
1287                {                {
1288                  ArticleResponse aresponse =                  ArticleResponse aresponse =
1289                    new ArticleResponse (status, message);                    new ArticleResponse(status, message);
1290                  // article number                  // article number
1291                  start = end + 1;                  start = end + 1;
1292                  end = line.indexOf (' ', start);                  end = line.indexOf(' ', start);
1293                  if (end > start)                  if (end > start)
1294                    {                    {
1295                      aresponse.articleNumber =                      aresponse.articleNumber =
1296                        Integer.parseInt (line.substring (start, end));                        Integer.parseInt(line.substring(start, end));
1297                    }                    }
1298                  // message-id                  // message-id
1299                  start = end + 1;                  start = end + 1;
1300                  end = line.indexOf (' ', start);                  end = line.indexOf(' ', start);
1301                  if (end > start)                  if (end > start)
1302                    {                    {
1303                      aresponse.messageId = line.substring (start, end);                      aresponse.messageId = line.substring(start, end);
1304                    }                    }
1305                  else                  else
1306                    {                    {
1307                      aresponse.messageId = line.substring (start);                      aresponse.messageId = line.substring(start);
1308                    }                    }
1309                  response = aresponse;                  response = aresponse;
1310                }                }
1311              catch (NumberFormatException e)              catch (NumberFormatException e)
1312                {                {
1313                  // This will happen for XHDR                  // This will happen for XHDR
1314                  response = new StatusResponse (status, message);                  response = new StatusResponse(status, message);
1315                }                }
1316              break;              break;
1317            }            }
1318          // This is the normal case for GROUP_SELECTED          // This is the normal case for GROUP_SELECTED
1319          GroupResponse gresponse = new GroupResponse (status, message);          GroupResponse gresponse = new GroupResponse(status, message);
1320          try          try
1321            {            {
1322              // count              // count
1323              start = end + 1;              start = end + 1;
1324              end = line.indexOf (' ', start);              end = line.indexOf(' ', start);
1325              if (end > start)              if (end > start)
1326                {                {
1327                  gresponse.count =                  gresponse.count =
1328                    Integer.parseInt (line.substring (start, end));                    Integer.parseInt(line.substring(start, end));
1329                }                }
1330              // first              // first
1331              start = end + 1;              start = end + 1;
1332              end = line.indexOf (' ', start);              end = line.indexOf(' ', start);
1333              if (end > start)              if (end > start)
1334                {                {
1335                  gresponse.first =                  gresponse.first =
1336                    Integer.parseInt (line.substring (start, end));                    Integer.parseInt(line.substring(start, end));
1337                }                }
1338              // last              // last
1339              start = end + 1;              start = end + 1;
1340              end = line.indexOf (' ', start);              end = line.indexOf(' ', start);
1341              if (end > start)              if (end > start)
1342                {                {
1343                  gresponse.last =                  gresponse.last =
1344                    Integer.parseInt (line.substring (start, end));                    Integer.parseInt(line.substring(start, end));
1345                }                }
1346              // group              // group
1347              start = end + 1;              start = end + 1;
1348              end = line.indexOf (' ', start);              end = line.indexOf(' ', start);
1349              if (end > start)              if (end > start)
1350                {                {
1351                  gresponse.group = line.substring (start, end);                  gresponse.group = line.substring(start, end);
1352                }                }
1353              else              else
1354                {                {
1355                  gresponse.group = line.substring (start);                  gresponse.group = line.substring(start);
1356                }                }
1357            }            }
1358          catch (NumberFormatException e)          catch (NumberFormatException e)
1359            {            {
1360              throw new ProtocolException (line);              throw new ProtocolException(line);
1361            }            }
1362          response = gresponse;          response = gresponse;
1363          break;          break;
1364        default:        default:
1365          response = new StatusResponse (status, message);          response = new StatusResponse(status, message);
1366        }        }
1367      return response;      return response;
1368    }    }
# Line 1372  public class NNTPConnection Line 1371  public class NNTPConnection
1371     * Send a single line to the server.     * Send a single line to the server.
1372     * @param line the line to send     * @param line the line to send
1373     */     */
1374    protected void send (String line)    protected void send(String line)
1375      throws IOException      throws IOException
1376    {    {
1377      if (pendingData != null)      if (pendingData != null)
1378        {        {
1379          // Clear pending data          // Clear pending data
1380          pendingData.readToEOF ();          pendingData.readToEOF();
1381          pendingData = null;          pendingData = null;
1382        }        }
1383      if (debug)      if (debug)
1384        {        {
1385          Logger logger = Logger.getInstance ();          Logger logger = Logger.getInstance();
1386          logger.log ("nntp", ">" + line);          logger.log("nntp", ">" + line);
1387        }        }
1388      byte[] data = line.getBytes (US_ASCII);      byte[] data = line.getBytes(US_ASCII);
1389      out.write (data);      out.write(data);
1390      out.writeln ();      out.writeln();
1391      out.flush ();      out.flush();
1392    }    }
1393        
1394    /**    /**
1395     * Read a single line from the server.     * Read a single line from the server.
1396     * @return a line of text     * @return a line of text
1397     */     */
1398    protected String read ()    protected String read()
1399      throws IOException      throws IOException
1400    {    {
1401      String line = in.readLine ();      String line = in.readLine();
1402      if (debug)      if (debug)
1403        {        {
1404          Logger logger = Logger.getInstance ();          Logger logger = Logger.getInstance();
1405          if (line == null)          if (line == null)
1406            {            {
1407              logger.log ("nntp", "<EOF");              logger.log("nntp", "<EOF");
1408            }            }
1409          else          else
1410            {            {
1411              logger.log ("nntp", "<" + line);              logger.log("nntp", "<" + line);
1412            }            }
1413        }        }
1414      return line;      return line;
1415    }    }
1416        
1417  }  }
1418    

Legend:
Removed from v.1.11  
changed lines
  Added in v.1.12

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26