home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / gnu / emacs / sources / 823 < prev    next >
Encoding:
Text File  |  1992-11-23  |  25.7 KB  |  787 lines

  1. Newsgroups: gnu.emacs.sources
  2. Path: sparky!uunet!cis.ohio-state.edu!east-wind.ORG!kingdon
  3. From: kingdon@east-wind.ORG (Jim Kingdon)
  4. Subject: Hierarchical patches for GNUS 3.14.1
  5. Message-ID: <9211231633.AA11759@relay2.UU.NET>
  6. Sender: kingdon@east-wind.org
  7. Organization: Source only  Discussion and requests in gnu.emacs.help.
  8. Distribution: gnu
  9. Date: Mon, 23 Nov 1992 06:33:59 GMT
  10. Lines: 775
  11.  
  12. Enclosed are patches to make GNUS a hierarchical newsreader.  What I
  13. mean by that is that when you start up GNUS for the first time, rather
  14. than showing you all the newsgroups, it will just show one line for
  15. each top-level hierarchy ("soc", "rec", "alt", etc.).  You can then
  16. unsubscribe to the whole hierarchy with one keystroke, or you can type
  17. space to "explode" the hierarchy into all the second-level groups and
  18. hierarchies (e.g. "comp" will explode into "comp.sys", "comp.os",
  19. "comp.compilers", etc.).
  20.  
  21. These patches should be considered experimental, both in the sense
  22. that some features probably should be added (but I didn't get around
  23. to it, or wasn't sure just how they should work), and that it has not
  24. been extensively tested for bugs.
  25.  
  26. *** gnus.el    Sat Nov 21 14:23:58 1992
  27. --- gnus-hier.el    Sat Nov 21 18:43:30 1992
  28. ***************
  29. *** 224,229 ****
  30. --- 224,250 ----
  31.   (defvar gnus-show-threads t
  32.     "*Show conversation threads in Subject Mode if non-nil.")
  33.   
  34. + ;;; Notes on hierarchy support:
  35. + ;;; * Right now, a hierarchy can be "exploded" into groups, but once
  36. + ;;; this is done, there is no way to "implode" a bunch of groups back
  37. + ;;; into a hierarchy.  One way to implement this would be to have gnus,
  38. + ;;; every time it starts up, look for a bunch of groups in .newsrc all of
  39. + ;;; which are in the same hierarchy, all of which have the same
  40. + ;;; subscribed/unsubscribed status, and all of which show no articles
  41. + ;;; that have been read (excluding articles no longer on the system),
  42. + ;;; and then automatically implode.
  43. + ;;; * The .newsrc written is not really compatible with non-hierarchical
  44. + ;;; newsreaders.  It might be better to rename it, or redesign things
  45. + ;;; somehow to make it easy for people to switch back and forth between
  46. + ;;; hierarchical and non-hierarchical newsreaders.  
  47. + ;;; Note that hierarchical GNUS can read a non-hierarchical .newsrc;
  48. + ;;; this feature should be preserved.
  49. + ;;; * Probably hierarchies should only be shown if some group in them
  50. + ;;; has unread news.  This is not currently the way it works.
  51. + (defvar gnus-show-hierarchies t
  52. +   "*Instead of subscribing users to new newsgroups, subscribe them to
  53. + the hierarchies which contain those groups.")
  54.   (defvar gnus-thread-hide-subject t
  55.     "*Non-nil means hide subjects for thread subtrees.")
  56.   
  57. ***************
  58. *** 330,335 ****
  59. --- 351,357 ----
  60.   (defvar gnus-subscribe-newsgroup-method
  61.     (function gnus-subscribe-alphabetically)
  62.     "*A function called with a newsgroup name when new newsgroup is found.
  63. + The argument is ('hierarchy name) or ('group name).
  64.   The function gnus-subscribe-randomly inserts a new newsgroup a the
  65.   beginning of newsgroups.  The function gnus-subscribe-alphabetically
  66.   inserts it in strict alphabetic order.  The function
  67. ***************
  68. *** 561,567 ****
  69.   
  70.   ;; Internal variables.
  71.   
  72. ! (defconst gnus-version "GNUS 3.14.1"
  73.     "Version numbers of this version of GNUS.")
  74.   
  75.   (defvar gnus-Info-nodes
  76. --- 583,589 ----
  77.   
  78.   ;; Internal variables.
  79.   
  80. ! (defconst gnus-version "GNUS 3.14.1 with hierarchy patches"
  81.     "Version numbers of this version of GNUS.")
  82.   
  83.   (defvar gnus-Info-nodes
  84. ***************
  85. *** 1133,1138 ****
  86. --- 1155,1161 ----
  87.     ;; Insert the message.
  88.     (insert "
  89.                      GNUS Version 3.14.1
  90. +                   with hierarchy patches
  91.   
  92.            NNTP-based News Reader for GNU Emacs
  93.   
  94. ***************
  95. *** 1193,1201 ****
  96.       (newsrc gnus-newsrc-assoc)
  97.       (group-info nil)
  98.       (group-name nil)
  99. !     (unread-count 0)
  100. !     ;; This specifies the format of Group buffer.
  101. !     (cntl "%s%s%5d: %s\n"))
  102.       (erase-buffer)
  103.       ;; List newsgroups.
  104.       (while newsrc
  105. --- 1216,1222 ----
  106.       (newsrc gnus-newsrc-assoc)
  107.       (group-info nil)
  108.       (group-name nil)
  109. !     (unread-count 0))
  110.       (erase-buffer)
  111.       ;; List newsgroups.
  112.       (while newsrc
  113. ***************
  114. *** 1204,1228 ****
  115.         (setq unread-count (nth 1 (gnus-gethash group-name gnus-unread-hashtb)))
  116.         (if (or all
  117.             (and (nth 1 group-info)    ;Subscribed.
  118. !            (> unread-count 0)))    ;There are unread articles.
  119.         ;; Yes, I can use gnus-Group-prepare-line, but this is faster.
  120. !       (insert
  121. !        (format cntl
  122. !            ;; Subscribed or not.
  123. !            (if (nth 1 group-info) " " "U")
  124. !            ;; Has new news?
  125. !            (if (and (> unread-count 0)
  126. !                 (>= 0
  127. !                 (- unread-count
  128. !                    (length
  129. !                     (cdr (assoc group-name
  130. !                         gnus-marked-assoc))))))
  131. !                "*" " ")
  132. !            ;; Number of unread articles.
  133. !            unread-count
  134. !            ;; Newsgroup name.
  135. !            group-name))
  136. !     )
  137.         (setq newsrc (cdr newsrc))
  138.         )
  139.       (setq gnus-have-all-newsgroups all)
  140. --- 1225,1257 ----
  141.         (setq unread-count (nth 1 (gnus-gethash group-name gnus-unread-hashtb)))
  142.         (if (or all
  143.             (and (nth 1 group-info)    ;Subscribed.
  144. !            (or (eq (nth 2 group-info) 'hierarchy)
  145. !                (> unread-count 0))))    ;There are unread articles.
  146.         ;; Yes, I can use gnus-Group-prepare-line, but this is faster.
  147. !       (progn
  148. !         ;; Subscribed or not.
  149. !         (insert (if (nth 1 group-info) " " "U"))
  150. !         ;; Has new news?
  151. !         (if (eq (nth 2 group-info) 'hierarchy)
  152. !         (insert "     H")
  153. !           (insert
  154. !            (if (and (> unread-count 0)
  155. !             (>= 0
  156. !                 (- unread-count
  157. !                    (length
  158. !                 (cdr (assoc group-name
  159. !                         gnus-marked-assoc))))))
  160. !            "*" " ")
  161. !            (format "%5d" unread-count))
  162. !           )
  163. !         (insert
  164. !          ": "
  165. !          ;; Newsgroup name.
  166. !          group-name
  167. !          "\n")))
  168.         (setq newsrc (cdr newsrc))
  169.         )
  170.       (setq gnus-have-all-newsgroups all)
  171. ***************
  172. *** 1235,1262 ****
  173.   INFO is an element of gnus-newsrc-assoc or gnus-killed-assoc."
  174.     (let* ((group-name (car info))
  175.        (unread-count
  176. !       (or (nth 1 (gnus-gethash group-name gnus-unread-hashtb))
  177. !           ;; Not in hash table, so compute it now.
  178. !           (gnus-number-of-articles
  179. !            (gnus-difference-of-range
  180. !         (nth 2 (gnus-gethash group-name gnus-active-hashtb))
  181. !         (nthcdr 2 info)))))
  182. !      ;; This specifies the format of Group buffer.
  183. !      (cntl "%s%s%5d: %s\n"))
  184. !     (format cntl
  185. !         ;; Subscribed or not.
  186. !         (if (nth 1 info) " " "U")
  187. !         ;; Has new news?
  188. !         (if (and (> unread-count 0)
  189. !              (>= 0
  190. !              (- unread-count
  191. !                 (length
  192. !                  (cdr (assoc group-name gnus-marked-assoc))))))
  193. !         "*" " ")
  194. !         ;; Number of unread articles.
  195. !         unread-count
  196.           ;; Newsgroup name.
  197.           group-name
  198.           )))
  199.   
  200.   (defun gnus-Group-update-group (group &optional visible-only)
  201. --- 1264,1298 ----
  202.   INFO is an element of gnus-newsrc-assoc or gnus-killed-assoc."
  203.     (let* ((group-name (car info))
  204.        (unread-count
  205. !       (if (eq (nth 2 info) 'hierarchy)
  206. !           0
  207. !         (or (nth 1 (gnus-gethash group-name gnus-unread-hashtb))
  208. !         ;; Not in hash table, so compute it now.
  209. !         (gnus-number-of-articles
  210. !          (gnus-difference-of-range
  211. !           (nth 2 (gnus-gethash group-name gnus-active-hashtb))
  212. !           (nthcdr 2 info)))))))
  213. !     (concat
  214. !      ;; Subscribed or not.
  215. !      (if (nth 1 info) " " "U")
  216. !      ;; Has new news?
  217. !      (if (and (> unread-count 0)
  218. !           (>= 0
  219. !           (- unread-count
  220. !              (length
  221. !               (cdr (assoc group-name gnus-marked-assoc))))))
  222. !      "*" " ")
  223. !         ;; Number of unread articles or H for hierarchy
  224. !         (if (eq (nth 2 info) 'hierarchy)
  225. !                "    H"
  226. !           (format "%5d" unread-count))
  227. !         ": "
  228.           ;; Newsgroup name.
  229.           group-name
  230. +         "\n"
  231.           )))
  232.   
  233.   (defun gnus-Group-update-group (group &optional visible-only)
  234. ***************
  235. *** 1289,1295 ****
  236.     "Get newsgroup name around point."
  237.     (save-excursion
  238.       (beginning-of-line)
  239. !     (if (looking-at ".[* \t]*[0-9]+:[ \t]+\\([^ \t\n]+\\)$")
  240.       (buffer-substring (match-beginning 1) (match-end 1))
  241.         )))
  242.   
  243. --- 1325,1331 ----
  244.     "Get newsgroup name around point."
  245.     (save-excursion
  246.       (beginning-of-line)
  247. !     (if (looking-at ".[* \t]*[0-9H]+:[ \t]+\\([^ \t\n]+\\)$")
  248.       (buffer-substring (match-beginning 1) (match-end 1))
  249.         )))
  250.   
  251. ***************
  252. *** 1298,1313 ****
  253.   If argument ALL is non-nil, already read articles become readable.
  254.   If optional argument NO-ARTICLE is non-nil, no article body is displayed."
  255.     (interactive "P")
  256. !   (let ((group (gnus-Group-group-name))) ;Newsgroup name to read.
  257.       (if group
  258. !     (gnus-Subject-read-group
  259. !      group
  260. !      (or all
  261. !          ;;(not (nth 1 (assoc group gnus-newsrc-assoc)))    ;Unsubscribed
  262. !          (zerop
  263. !           (nth 1 (gnus-gethash group gnus-unread-hashtb))))    ;No unread
  264. !      no-article
  265. !      ))
  266.       ))
  267.   
  268.   (defun gnus-Group-select-group (all)
  269. --- 1334,1383 ----
  270.   If argument ALL is non-nil, already read articles become readable.
  271.   If optional argument NO-ARTICLE is non-nil, no article body is displayed."
  272.     (interactive "P")
  273. !   (let ((group (gnus-Group-group-name)) ;Newsgroup name to read.
  274. !     (tail gnus-newsrc-assoc)
  275. !     (prev nil))
  276.       (if group
  277. !     (progn
  278. !       ;; First, find the group in gnus-newsrc-assoc so we know
  279. !       ;; whether it is a hierarchy.
  280. !       (catch 'exit-loop
  281. !         (while tail
  282. !           (if (string= (car (car tail)) group)
  283. !           (throw 'exit-loop nil))
  284. !           (setq prev tail)
  285. !           (setq tail (cdr tail))))
  286. !       (if (eq (nth 2 (car tail)) 'hierarchy)
  287. !           (progn
  288. !         (message "Exploding hierarchy %s..." group)
  289. !         ;; Delete group from gnus-newsrc-assoc
  290. !         (if prev
  291. !             (setcdr prev (cdr tail))
  292. !           (setq gnus-newsrc-assoc (cdr tail)))
  293. !         (gnus-update-newsrc-buffer group 'delete)
  294. !         ;; Subscribe to groups and hierarchies
  295. !         ;; one level down from group
  296. !         (let ((new-newsgroups (gnus-find-new-newsgroups group)))
  297. !           (while new-newsgroups
  298. !             (funcall gnus-subscribe-newsgroup-method
  299. !                  (car new-newsgroups))
  300. !             (setq new-newsgroups (cdr new-newsgroups))
  301. !             ))
  302. !         (message "Exploding hierarchy %s...done" group)
  303. !         ;; This is not necessarily the cleanest way to show them;
  304. !         ;; i.e. does it cause unpleasant changes to the display?
  305. !         (gnus-Group-list-groups gnus-have-all-newsgroups)
  306. !         )
  307. !         ;; It's a group.  Read it.
  308. !         (gnus-Subject-read-group
  309. !          group
  310. !          (or all
  311. !          ;;(not (nth 1 (assoc group gnus-newsrc-assoc)))    ;Unsubscribed
  312. !          (zerop
  313. !           (nth 1 (gnus-gethash group gnus-unread-hashtb))))    ;No unread
  314. !          no-article
  315. !          )
  316. !         )))
  317.       ))
  318.   
  319.   (defun gnus-Group-select-group (all)
  320. ***************
  321. *** 1339,1345 ****
  322.       (regexp 
  323.        (format "^%s[ \t]*\\(%s\\):"
  324.            (if any-group ".." " [ \t]")
  325. !          (if any-group "[0-9]+" "[1-9][0-9]*")))
  326.       (found nil))
  327.       (if backward
  328.       (beginning-of-line)
  329. --- 1409,1415 ----
  330.       (regexp 
  331.        (format "^%s[ \t]*\\(%s\\):"
  332.            (if any-group ".." " [ \t]")
  333. !          (if any-group "[0-9H]+" "[1-9][0-9]*")))
  334.       (found nil))
  335.       (if backward
  336.       (beginning-of-line)
  337. ***************
  338. *** 4575,4581 ****
  339.     (let ((groups gnus-newsrc-assoc)
  340.       (before nil))
  341.       (while (and (not before) groups)
  342. !       (if (string< newgroup (car (car groups)))
  343.         (setq before (car (car groups)))
  344.       (setq groups (cdr groups))))
  345.       (gnus-subscribe-newsgroup newgroup before)
  346. --- 4645,4651 ----
  347.     (let ((groups gnus-newsrc-assoc)
  348.       (before nil))
  349.       (while (and (not before) groups)
  350. !       (if (string< (car (cdr newgroup)) (car (car groups)))
  351.         (setq before (car (car groups)))
  352.       (setq groups (cdr groups))))
  353.       (gnus-subscribe-newsgroup newgroup before)
  354. ***************
  355. *** 4586,4592 ****
  356.     ;; Basic ideas by mike-w@cs.aukuni.ac.nz (Mike Williams)
  357.     (save-excursion
  358.       (set-buffer (find-file-noselect gnus-current-startup-file))
  359. !     (let ((groupkey newgroup)
  360.         (before nil))
  361.         (while (and (not before) groupkey)
  362.       (goto-char (point-min))
  363. --- 4656,4662 ----
  364.     ;; Basic ideas by mike-w@cs.aukuni.ac.nz (Mike Williams)
  365.     (save-excursion
  366.       (set-buffer (find-file-noselect gnus-current-startup-file))
  367. !     (let ((groupkey (car (cdr newgroup)))
  368.         (before nil))
  369.         (while (and (not before) groupkey)
  370.       (goto-char (point-min))
  371. ***************
  372. *** 4596,4602 ****
  373.                 (progn
  374.               (setq before (buffer-substring
  375.                         (match-beginning 1) (match-end 1)))
  376. !             (string< before newgroup)))
  377.           ))
  378.       ;; Remove tail of newsgroup name (eg. a.b.c -> a.b)
  379.       (setq groupkey
  380. --- 4666,4672 ----
  381.                 (progn
  382.               (setq before (buffer-substring
  383.                         (match-beginning 1) (match-end 1)))
  384. !             (string< before (car (cdr newgroup)))))
  385.           ))
  386.       ;; Remove tail of newsgroup name (eg. a.b.c -> a.b)
  387.       (setq groupkey
  388. ***************
  389. *** 4606,4615 ****
  390.         )))
  391.   
  392.   (defun gnus-subscribe-newsgroup (newsgroup &optional next)
  393. !   "Subscribe new NEWSGROUP.
  394.   If optional argument NEXT is non-nil, it is inserted before NEXT."
  395. !   (gnus-insert-newsgroup (list newsgroup t) next)
  396. !   (message "Newsgroup %s is subscribed" newsgroup))
  397.   
  398.   ;; For directories
  399.   
  400. --- 4676,4691 ----
  401.         )))
  402.   
  403.   (defun gnus-subscribe-newsgroup (newsgroup &optional next)
  404. !   "Subscribe new NEWSGROUP, which is a list ('group name) or ('hierarchy name).
  405.   If optional argument NEXT is non-nil, it is inserted before NEXT."
  406. !   (gnus-insert-newsgroup
  407. !    (if (eq (car newsgroup) 'hierarchy)
  408. !        (list (car (cdr newsgroup)) t 'hierarchy)
  409. !      (list (car (cdr newsgroup)) t))
  410. !    next)
  411. !   (message "%s %s is subscribed"
  412. !        (if (eq (car newsgroup) 'hierarchy) "Hierarchy" "Newsgroup")
  413. !        (car (cdr newsgroup))))
  414.   
  415.   ;; For directories
  416.   
  417. ***************
  418. *** 5671,5678 ****
  419.   
  420.   ;; GNUS internal format of gnus-newsrc-assoc and gnus-killed-assoc:
  421.   ;; (("general" t (1 . 1))
  422. ! ;;  ("misc"    t (1 . 10) (12 . 15))
  423. ! ;;  ("test"  nil (1 . 99)) ...)
  424.   ;; GNUS internal format of gnus-marked-assoc:
  425.   ;; (("general" 1 2 3)
  426.   ;;  ("misc" 2) ...)
  427. --- 5747,5755 ----
  428.   
  429.   ;; GNUS internal format of gnus-newsrc-assoc and gnus-killed-assoc:
  430.   ;; (("general" t (1 . 1))
  431. ! ;;  ("misc.foo"    t (1 . 10) (12 . 15))
  432. ! ;;  ("test"  nil (1 . 99))
  433. ! ;;  ("talk"  nil 'hierarchy) ...)
  434.   ;; GNUS internal format of gnus-marked-assoc:
  435.   ;; (("general" 1 2 3)
  436.   ;;  ("misc" 2) ...)
  437. ***************
  438. *** 5720,5744 ****
  439.                     (list newsgroup t))
  440.                     (car (car gnus-newsrc-assoc)))))
  441.   
  442. ! (defun gnus-find-new-newsgroups ()
  443. !   "Looking for new newsgroups and return names.
  444. ! `-n' option of options line in .newsrc file is recognized."
  445.     (let ((group nil)
  446.       (new-newsgroups nil))
  447.       (mapatoms
  448.        (function
  449.         (lambda (sym)
  450.       (setq group (symbol-name sym))
  451.       ;; Taking account of `-n' option.
  452.       (and (or (null gnus-newsrc-options-n-no)
  453.            (not (string-match gnus-newsrc-options-n-no group))
  454.            (and gnus-newsrc-options-n-yes
  455.                 (string-match gnus-newsrc-options-n-yes group)))
  456. !          (null (assoc group gnus-killed-assoc)) ;Ignore killed.
  457. !          (null (assoc group gnus-newsrc-assoc)) ;Really new.
  458. !          ;; Find new newsgroup.
  459. !          (setq new-newsgroups
  460. !            (cons group new-newsgroups)))
  461.       ))
  462.        gnus-active-hashtb)
  463.       ;; Return new newsgroups.
  464. --- 5797,5960 ----
  465.                     (list newsgroup t))
  466.                     (car (car gnus-newsrc-assoc)))))
  467.   
  468. ! (defun gnus-group-is-new (group)
  469. !   "Return true if GROUP is not found in gnus-newsrc-assoc or
  470. ! gnus-killed-assoc, either as itself or as a hierarchy which includes
  471. ! GROUP."
  472. !   (catch 'return
  473. !     (let ((group-okay t) ;if nil, need a hierarchy
  474. !       (group-found nil))
  475. !       (while t
  476. !     (setq group-found (or (assoc group gnus-killed-assoc)
  477. !                   (assoc group gnus-newsrc-assoc)))
  478. !     (if (and group-found
  479. !          (or group-okay (eq (nth 2 group-found) 'hierarchy))
  480. !          )
  481. !         (throw 'return nil))
  482. !     (if (not (string-match "\\.[^.]*$" group)) (throw 'return t))
  483. !     (setq group (substring group 0 (match-beginning 0)))
  484. !     (setq group-okay nil)
  485. !     ))))
  486. ! (defun gnus-find-new-newsgroups (&optional prefix)
  487. !   "Look for new newsgroups and return names.
  488. ! `-n' option of options line in .newsrc file is recognized.
  489. ! Return value is a list each element of which is 
  490. !   ('group name) or ('hierarchy name).
  491. ! If PREFIX is specified, it is the name of a hierarchy.  Don't return
  492. ! that hierarchy, instead return an entry for each group or hierarchy
  493. ! underneath that hierarchy.  New groups not under the PREFIX hierarchy
  494. ! are not included in the return value."
  495. !   (if (null prefix)
  496. !       (setq prefix ""))
  497.     (let ((group nil)
  498. +     (group-length 0)
  499.       (new-newsgroups nil))
  500.       (mapatoms
  501.        (function
  502.         (lambda (sym)
  503.       (setq group (symbol-name sym))
  504. +     (setq group-length (length group))
  505.       ;; Taking account of `-n' option.
  506.       (and (or (null gnus-newsrc-options-n-no)
  507.            (not (string-match gnus-newsrc-options-n-no group))
  508.            (and gnus-newsrc-options-n-yes
  509.                 (string-match gnus-newsrc-options-n-yes group)))
  510. !          (>= group-length (length prefix))
  511. !          (string= (substring group 0 (length prefix)) prefix)
  512. !          (gnus-group-is-new group)
  513. !          ;; OK, we got a group which is new.
  514. !          ;; Find what newsgroup or hierarchy we want to add.
  515. !          (let ((new-entry
  516. !             (if (not gnus-show-hierarchies)
  517. !             (list 'group group)
  518. !               ;; Find the most general hierarchy which applies
  519. !               (let ((newsrc gnus-newsrc-assoc)
  520. !                 (spare-assoc gnus-killed-assoc)
  521. !                 (longest-match prefix)
  522. !                 (longest-match-length 0)
  523. !                 (test-string nil)
  524. !                 (test-string-length 0))
  525. !             (setq longest-match-length (length longest-match))
  526. !             (while newsrc
  527. !               (setq test-string (car (car newsrc)))
  528. !               (setq test-string-length (length test-string))
  529. !               (while (> test-string-length longest-match-length)
  530. !                 ;; Would the following be faster? Does it matter?
  531. !                 ;; (and (< test-string-length group-length)
  532. !                 ;;      (string= 
  533. !                 ;;       test-string
  534. !                 ;;       (substring group test-string-length)))
  535. !                 (if (string-match
  536. !                  (concat "^" (regexp-quote test-string))
  537. !                  group)
  538. !                 (progn
  539. !                   (setq longest-match test-string)
  540. !                   (setq longest-match-length
  541. !                     test-string-length))
  542. !                   (if (not (string-match "\\.[^.]*$" test-string))
  543. !                   ;; OK, we've tested everything
  544. !                   (setq test-string-length 0)
  545. !                 (progn
  546. !                   (setq test-string-length (match-beginning 0))
  547. !                   (setq test-string
  548. !                     (substring
  549. !                      test-string 0 test-string-length))
  550. !                   )
  551. !                   )))
  552. !               (setq newsrc (cdr newsrc))
  553. !               (if (null newsrc)
  554. !                   (progn
  555. !                 (setq newsrc spare-assoc)
  556. !                 (setq spare-assoc nil)))
  557. !               )
  558. !             ;; OK, take one more level beyond longest-match.
  559. !             ;; skip the period
  560. !             (if (< longest-match-length group-length)
  561. !                 (setq longest-match-length
  562. !                   (1+ longest-match-length))
  563. !               )
  564. !             (while (and
  565. !                 (< longest-match-length group-length)
  566. !                 (not (string-equal
  567. !                       (substring
  568. !                        group
  569. !                        longest-match-length
  570. !                        (1+ longest-match-length))
  571. !                       ".")))
  572. !               (setq longest-match-length
  573. !                 (1+ longest-match-length)))
  574. !             (if (= longest-match-length group-length)
  575. !                 (list 'group group)
  576. !               (list 'hierarchy
  577. !                 (substring group 0 longest-match-length))
  578. !               )))
  579. !             ))
  580. !            (catch 'got-it
  581. !          (let ((tail new-newsgroups)
  582. !                (group-name (car (cdr new-entry))))
  583. !            (while tail
  584. !              (if (string= (car (cdr (car tail))) group-name)
  585. !              (if (and (eq (car (car tail)) 'group)
  586. !                   (eq (car new-entry) 'hierarchy))
  587. !                  ;; If we are trying to add, for
  588. !                  ;; example, ('hierarchy "misc.consumers")
  589. !                  ;; and ('group "misc.consumers") is
  590. !                  ;; already in there, nuke the 'group
  591. !                  ;; entry and put in the hierarchy.  This
  592. !                  ;; is because logically speaking the
  593. !                  ;; group "misc.consumers" is part of the
  594. !                  ;; "misc.consumers" hierarchy, yet we
  595. !                  ;; don't know there is such a hierarchy
  596. !                  ;; until we find the group
  597. !                  ;; "misc.consumers.house".
  598. !                  (progn
  599. !                    (setcar (car tail) 'hierarchy)
  600. !                    (throw 'got-it nil)
  601. !                    )
  602. !                ;; They are both the same hierarchy, which we see
  603. !                ;; twice, for example, if newgroups are sent out
  604. !                ;; for comp.sys.mac.lawsuits and
  605. !                ;; comp.sys.mac.user-interface
  606. !                ;; at the same time.  Since it's already there,
  607. !                ;; don't need to do anything else
  608. !                ;; The one from new-entry being a hierarchy
  609. !                ;; and the other a group we already checked for.
  610. !                ;; The one from new-entry being a group and
  611. !                ;; the other a hierarchy, or both being groups,
  612. !                ;; "can't happen".
  613. !                (throw 'got-it nil)
  614. !                )
  615. !                (setq tail (cdr tail))
  616. !                ))
  617. !            ;; It is genuinely new.  Add it.
  618. !            (setq new-newsgroups
  619. !              (cons new-entry
  620. !                    new-newsgroups))
  621. !            ))
  622. !          )
  623. !          )
  624.       ))
  625.        gnus-active-hashtb)
  626.       ;; Return new newsgroups.
  627. ***************
  628. *** 5772,5779 ****
  629.         (error "Invalid argument: %s" info))
  630.     (let* ((group (car info))        ;Newsgroup name.
  631.        (range
  632. !       (gnus-difference-of-range
  633. !        (nth 2 (gnus-gethash group gnus-active-hashtb)) (nthcdr 2 info))))
  634.       ;; Check duplication.
  635.       (if (assoc group gnus-newsrc-assoc)
  636.       (error "Duplicated: %s" group))
  637. --- 5988,5997 ----
  638.         (error "Invalid argument: %s" info))
  639.     (let* ((group (car info))        ;Newsgroup name.
  640.        (range
  641. !       (or (eq 'hierarchy (nth 2 info))
  642. !           (gnus-difference-of-range
  643. !            (nth 2 (gnus-gethash group gnus-active-hashtb))
  644. !            (nthcdr 2 info)))))
  645.       ;; Check duplication.
  646.       (if (assoc group gnus-newsrc-assoc)
  647.       (error "Duplicated: %s" group))
  648. ***************
  649. *** 5802,5812 ****
  650.       ;; Then insert to .newsrc.
  651.       (gnus-update-newsrc-buffer group nil next)
  652.       ;; Add to gnus-unread-hashtb.
  653. !     (gnus-sethash group
  654. !           (cons group        ;Newsgroup name.
  655. !             (cons (gnus-number-of-articles range) range))
  656. !           gnus-unread-hashtb)
  657. !     ))
  658.   
  659.   (defun gnus-check-killed-newsgroups ()
  660.     "Check consistency between gnus-newsrc-assoc and gnus-killed-assoc."
  661. --- 6020,6032 ----
  662.       ;; Then insert to .newsrc.
  663.       (gnus-update-newsrc-buffer group nil next)
  664.       ;; Add to gnus-unread-hashtb.
  665. !     (or (eq 'hierarchy (nth 2 info))
  666. !     (gnus-sethash group
  667. !               (cons group        ;Newsgroup name.
  668. !                 (cons (gnus-number-of-articles range) range))
  669. !               gnus-unread-hashtb)
  670. !     ))
  671. !     )
  672.   
  673.   (defun gnus-check-killed-newsgroups ()
  674.     "Check consistency between gnus-newsrc-assoc and gnus-killed-assoc."
  675. ***************
  676. *** 5893,5914 ****
  677.       (while read
  678.         (setq group-info (car read))    ;About one newsgroup
  679.         (setq group-name (car group-info))
  680. !       (setq active (nth 2 (gnus-gethash group-name gnus-active-hashtb)))
  681. !       (if (and gnus-octive-hashtb
  682. !            ;; Is nothing changed?
  683. !            (equal active
  684. !               (nth 2 (gnus-gethash group-name gnus-octive-hashtb)))
  685. !            ;; Is this newsgroup in the unread hash table?
  686. !            (gnus-gethash group-name gnus-unread-hashtb)
  687. !            )
  688. !       nil                ;Nothing to do.
  689. !     (setq range (gnus-difference-of-range active (nthcdr 2 group-info)))
  690. !     (gnus-sethash group-name
  691. !               (cons group-name    ;Group name
  692. !                 (cons (gnus-number-of-articles range)
  693. !                   range)) ;Range of unread articles
  694. !               gnus-unread-hashtb)
  695. !     )
  696.         (setq read (cdr read))
  697.         )
  698.       (message "Checking new news... done")
  699. --- 6113,6140 ----
  700.       (while read
  701.         (setq group-info (car read))    ;About one newsgroup
  702.         (setq group-name (car group-info))
  703. !       (if (not (eq (nth 2 group-info) 'hierarchy))
  704. !       (progn
  705. !         (setq active
  706. !           (nth 2 (gnus-gethash group-name gnus-active-hashtb)))
  707. !         (if (and gnus-octive-hashtb
  708. !              ;; Is nothing changed?
  709. !              (equal active
  710. !                 (nth 2
  711. !                  (gnus-gethash group-name gnus-octive-hashtb)))
  712. !              ;; Is this newsgroup in the unread hash table?
  713. !              (gnus-gethash group-name gnus-unread-hashtb)
  714. !              )
  715. !         nil                ;Nothing to do.
  716. !           (setq range
  717. !             (gnus-difference-of-range active (nthcdr 2 group-info)))
  718. !           (gnus-sethash group-name
  719. !                 (cons group-name    ;Group name
  720. !                   (cons (gnus-number-of-articles range)
  721. !                     range)) ;Range of unread articles
  722. !                 gnus-unread-hashtb)
  723. !           )
  724. !         ))
  725.         (setq read (cdr read))
  726.         )
  727.       (message "Checking new news... done")
  728. ***************
  729. *** 6211,6217 ****
  730.              ":" (buffer-substring (match-beginning 2) (match-end 2))))
  731.       (setq ranges (buffer-substring (match-beginning 3) (match-end 3)))
  732.       (setq read-list nil)
  733. !     (while (string-match "^[, \t]*\\([0-9-]+\\)" ranges)
  734.         (setq subrange (substring ranges (match-beginning 1) (match-end 1)))
  735.         (setq ranges (substring ranges (match-end 1)))
  736.         (cond ((string-match "^\\([0-9]+\\)-\\([0-9]+\\)$" subrange)
  737. --- 6437,6443 ----
  738.              ":" (buffer-substring (match-beginning 2) (match-end 2))))
  739.       (setq ranges (buffer-substring (match-beginning 3) (match-end 3)))
  740.       (setq read-list nil)
  741. !     (while (string-match "^[, \t]*\\([0-9-h]+\\)" ranges)
  742.         (setq subrange (substring ranges (match-beginning 1) (match-end 1)))
  743.         (setq ranges (substring ranges (match-end 1)))
  744.         (cond ((string-match "^\\([0-9]+\\)-\\([0-9]+\\)$" subrange)
  745. ***************
  746. *** 6229,6234 ****
  747. --- 6455,6462 ----
  748.                  (cons (cons (string-to-int subrange)
  749.                      (string-to-int subrange))
  750.                    read-list)))
  751. +         ((string-match "^h$" subrange)
  752. +          (setq read-list (cons 'hierarchy nil)))
  753.           (t
  754.            (ding) (message "Ignoring bogus lines of %s" newsgroup)
  755.            (sit-for 0))
  756. ***************
  757. *** 6404,6409 ****
  758. --- 6632,6639 ----
  759.   
  760.   (defun gnus-ranges-to-newsrc-format (ranges)
  761.     "Insert ranges of read articles."
  762. +   (if (eq (car ranges) 'hierarchy)
  763. +       (insert "h")
  764.     (let ((range nil))            ;Range is a pair of BEGIN and END.
  765.       (while ranges
  766.         (setq range (car ranges))
  767. ***************
  768. *** 6421,6426 ****
  769. --- 6651,6657 ----
  770.            (if ranges (insert ","))
  771.            ))
  772.         )))
  773. +   )
  774.   
  775.   (defun gnus-compress-sequence (numbers)
  776.     "Convert list of sorted numbers to ranges."
  777.  
  778.