home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / win95 / sieciowe / hotja32.lzh / hotjava / classsrc / net / www / protocol / news / newsgroup.java < prev    next >
Text File  |  1995-08-11  |  8KB  |  298 lines

  1. /*
  2.  * @(#)Newsgroup.java    1.7 95/03/28 James Gosling, Jonathan Payne
  3.  * 
  4.  * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for NON-COMMERCIAL purposes and without fee is hereby
  8.  * granted provided that this copyright notice appears in all copies. Please
  9.  * refer to the file "copyright.html" for further important copyright and
  10.  * licensing information.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
  15.  * OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
  16.  * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
  17.  * ITS DERIVATIVES.
  18.  */
  19.  
  20. package net.www.protocol.news;
  21.  
  22. import java.io.*;
  23. import java.util.*;
  24. import net.nntp.*;
  25. import net.smtp.SmtpClient;
  26. import browser.Applet;
  27. import browser.WRWindow;
  28. import browser.DocumentManager;
  29. import net.TelnetInputStream;
  30. import net.UnknownHostException;
  31. import awt.*;
  32.  
  33. /** This news group object maintains a pointer to the newsgroup
  34.     info object, which is obtained from the nntp server, a set of
  35.     integers representing the group of articles that are unread,
  36.     and a pointer to the "current" article in the group.
  37.     currentArticle can be either (1) -1, meaning it is pointing to
  38.     before the first article to read, (2) an unread article (i.e.,
  39.     articles.contains(currentArticle) => true), or (3) 1
  40.     greater than the maximum unread article.
  41.  
  42.     Therefore, when a newsgroup is first opened for reading,
  43.     currentArticle is -1.  After the first article is opened,
  44.     currentArticle is the article that was last requested and
  45.     displayed.  If currentArticle is > the maximum unread article,
  46.     then we are finished with the newsgroup. */
  47.  
  48. class Newsgroup {
  49.     /** Groupinfo as returned from the NNTP server for this group. */
  50.     NewsgroupInfo group;
  51.  
  52.     /** Unread articles in this group, OR, if !subscribed, the
  53.         read articles (so we can save back to newsrc file). */
  54.     NumberSet articles;
  55.  
  56.     /** Current article we're looking at. */
  57.     int currentArticle;
  58.  
  59.     /** Whether or not we're subscribed to this group.  See above
  60.     for how this affects how articles is interpreted. */
  61.     boolean subscribed;
  62.  
  63.     static Newsgroup readNewsrcFile(String name, NntpClient news)[] {
  64.     DataInputStream in;
  65.     Vector groupVector = new Vector(10);
  66.     FileInputStream file = null;
  67.  
  68.     try {
  69.         file = new FileInputStream(name);
  70.         in = new DataInputStream(new BufferedInputStream(file));
  71.  
  72.         String data;
  73.         /* unsubscribed newsgroups are skipped to save space in
  74.            internal data structures.  To preserve compatibility
  75.            with other browsers, writeNewsrcFile compensates for
  76.            this by copying the unsubscribed entries in the original
  77.            .newsrc into the new .newsrc that do not occur in
  78.            the internal database. */
  79.         while ((data = in.readLine()) != null) {
  80.         if (data.indexOf('!') < 0)
  81.         try {
  82.             Newsgroup n = new Newsgroup(data, news);
  83.  
  84.             groupVector.addElement(n);
  85.         } catch(UnknownNewsgroupException e) {
  86.         }
  87.         }
  88.     } catch(FileNotFoundException e) {
  89.     } catch(IOException e) {
  90.         if (file != null)
  91.         file.close();
  92.     }
  93.     if (groupVector.size() > 0) {
  94.         Newsgroup groups[] = new Newsgroup[groupVector.size()];
  95.  
  96.         groupVector.copyInto(groups);
  97.         return groups;
  98.     }
  99.     return null;
  100.     }
  101.  
  102.     public static void writeNewsrcFile(String name, Newsgroup groups[]) {
  103.     PrintStream out;
  104.     int i;
  105.     int cnt;
  106.     String tempname = name+".tmp";
  107.     out = new PrintStream(new BufferedOutputStream
  108.                   (new FileOutputStream(tempname)));
  109.     for (i = 0, cnt = groups.length; --cnt >= 0; i++) {
  110.         out.print(groups[i].newsrcString());
  111.         out.print("\n");
  112.     }
  113.     DataInputStream in;
  114.     FileInputStream file = null;
  115.  
  116.     try {
  117.         file = new FileInputStream(name);
  118.         in = new DataInputStream(new BufferedInputStream(file));
  119.         String data;
  120.         while ((data = in.readLine()) != null) {
  121.         int uns = data.indexOf('!');
  122.         if (uns > 0) {
  123.             for (i = 0, cnt=groups.length; --cnt>=0; i++) {
  124.             String n = groups[i].group.name;
  125.             if (n.length() == uns && data.startsWith(n))
  126.                 break;
  127.             }
  128.             if (cnt < 0) {
  129.             out.print(data);
  130.             out.print("\n");
  131.             }
  132.         }
  133.         }
  134.     } catch(Exception e){};
  135.     if (file != null)
  136.        file.close();
  137.     out.flush();
  138.     out.close();
  139.     try {
  140.         if (!new File(tempname).renameTo(new File(name)))
  141.         System.out.print("Rename failed\n");
  142.     } catch(Exception e) {
  143.     }
  144.     }
  145.  
  146.     public String newsrcString() {
  147.     NumberSet set;
  148.     String result = group.name + (subscribed ? ":" : "!");
  149.     if (articles != null) {
  150.         set = (subscribed ? articles.invert(1, group.lastArticle) : articles);
  151.         if (!set.isEmpty())
  152.         result = result + " " + set.rangesString();
  153.     } else if (subscribed)
  154.         result = result + " 1-" + group.lastArticle;
  155.     return result;
  156.     }
  157.  
  158.     public Newsgroup(String input, NntpClient news) {
  159.     parseNewsrcString(input, news);
  160.     currentArticle = -1;
  161.     }
  162.  
  163.     public void parseNewsrcString(String input, NntpClient news) {
  164.     NumberSet read = null;
  165.     int nameEndIndex;
  166.  
  167.     if ((nameEndIndex = input.indexOf('!')) != -1)
  168.         subscribed = false;
  169.     else if ((nameEndIndex = input.indexOf(':')) == -1)
  170.         throw new Exception("Malformed newsgroup specification: " + input);
  171.     else
  172.         subscribed = true;
  173.     if (subscribed)
  174.         group = news.getGroup(input.substring(0, nameEndIndex));
  175.     else
  176.         group = new NewsgroupInfo(input.substring(0, nameEndIndex), -1, -1);
  177.     if (nameEndIndex + 1 < input.length()) {
  178.         StringTokenizer t;
  179.         t = new StringTokenizer(input.substring(nameEndIndex + 1), ", ");
  180.  
  181.         try {
  182.         do {
  183.             String spec = t.nextToken();
  184.             if (read == null)
  185.             read = new NumberSet();
  186.             read.add(spec);
  187.         } while (t.hasMoreTokens());
  188.         } catch(NoSuchElementException e) {
  189.         }
  190.     }
  191.     if (subscribed) {
  192.         if (group.firstArticle == 0 && group.lastArticle == 0) {
  193.         // This group is empty, read.invert will do the wrong thing.
  194.         articles = new NumberSet();
  195.         } else {
  196.         if (read == null)
  197.             read = new NumberSet();
  198.         articles = read.invert(group.firstArticle, group.lastArticle);
  199.         }
  200.     } else
  201.         articles = read;
  202.     }
  203.  
  204.     /** open prepares this newsgroup for reading.  It resets the
  205.         current article to the first unread article in the group.
  206.     It returns false if there are no articles for reading. */
  207.  
  208.     public boolean open(NntpClient news) {
  209.     group.reload(news);
  210.     return !articles.isEmpty();
  211.     }
  212.  
  213.     public void close() {
  214.     currentArticle = -1;
  215.     }
  216.  
  217.     int firstArticle() {
  218.     return articles.isEmpty() ? -1 : articles.smallest();
  219.     }
  220.  
  221.     int lastArticle() {
  222.     return articles.isEmpty() ? -1 : articles.largest();
  223.     }
  224.  
  225.     /** findNextArticle returns the next article number for
  226.     reading, OR, -1 if there are no more articles. */
  227.     public int findNextArticle() {
  228.     int upper;
  229.  
  230.     if (!subscribed || articles.isEmpty()
  231.         || currentArticle >= lastArticle())
  232.         return -1;
  233.  
  234.     if (currentArticle == -1)
  235.         currentArticle = firstArticle();
  236.     else
  237.         currentArticle += 1;
  238.  
  239.     upper = articles.largest();
  240.     while (currentArticle <= upper) {
  241.         if (articles.contains(currentArticle))
  242.         break;
  243.         currentArticle += 1;
  244.     }
  245.     return currentArticle;
  246.     }
  247.  
  248.     public boolean contains(int articleNumber) {
  249.     return articles != null && articles.contains(articleNumber);
  250.     }
  251.  
  252.     public void markAsRead(int articleNumber) {
  253.     if (articles == null)
  254.         articles = new NumberSet();
  255.     if (articles.contains(articleNumber))
  256.         articles.delete(articleNumber);
  257.     }
  258.  
  259.     public void markAsUnread(int articleNumber) {
  260.     if (articles == null)
  261.         articles = new NumberSet();
  262.     if (!articles.contains(articleNumber))
  263.         articles.add(articleNumber);
  264.     }
  265.  
  266.     public int unreadArticleCount() {
  267.     return articles.size();
  268.     }
  269.  
  270.     public String toString() {
  271.     return "Newsgroup[info=" + group + ", unread=" + articles + "]";
  272.     }
  273.  
  274.     private String spaces = "                              ";
  275.  
  276.     String padded(String arg, int size) {
  277.     int spacesSize = spaces.length();
  278.  
  279.     size -= arg.length();
  280.  
  281.     while (size > 0) {
  282.         if (size < spacesSize) {
  283.         arg = arg + spaces.substring(0, size);
  284.         break;
  285.         } else {
  286.         arg = arg + spaces;
  287.         size -= spacesSize;
  288.         }
  289.     }
  290.     return arg;
  291.     }
  292.  
  293.     public String headerString() {
  294.     return padded(group.name, 40) + articles.size()
  295.         + " total unread articles";
  296.     }
  297. }
  298.