* gnus-agent.el (gnus-agent-read-agentview): Removed support for
[gnus] / lisp / gnus-agent.el
index 8d54f68..d77b6fa 100644 (file)
@@ -1,5 +1,5 @@
 ;;; gnus-agent.el --- unplugged support for Gnus
-;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
+;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -69,7 +69,8 @@
   :type 'integer)
 
 (defcustom gnus-agent-expire-days 7
-  "Read articles older than this will be expired."
+  "Read articles older than this will be expired.
+If you wish to disable Agent expiring, see `gnus-agent-enable-expiration'."
   :group 'gnus-agent
   :type '(number :tag "days"))
 
@@ -143,7 +144,13 @@ If this is `ask' the hook will query the user."
   :group 'gnus-agent)
 
 (defcustom gnus-agent-consider-all-articles nil
-  "If non-nil, consider also the read articles for downloading."
+  "When non-nil, the agent will let the agent predicate decide
+whether articles need to be downloaded or not, for all articles.  When
+nil, the default, the agent will only let the predicate decide
+whether unread articles are downloaded or not.  If you enable this,
+groups with large active ranges may open slower and you may also want
+to look into the agent expiry settings to block the expiration of
+read articles as they would just be downloaded again."
   :version "21.4"
   :type 'boolean
   :group 'gnus-agent)
@@ -167,9 +174,34 @@ enable expiration per categories, topics, and groups."
                 (const :format "Disable " DISABLE)))
 
 (defcustom gnus-agent-expire-unagentized-dirs t
-"Have gnus-agent-expire scan the directories under
-\(gnus-agent-directory) for groups that are no longer agentized.  When
-found, offer to remove them.")
+  "*Whether expiration should expire in unagentized directories.
+Have gnus-agent-expire scan the directories under
+\(gnus-agent-directory) for groups that are no longer agentized.
+When found, offer to remove them."
+  :type 'boolean
+  :group 'gnus-agent)
+
+(defcustom gnus-agent-auto-agentize-methods '(nntp nnimap)
+  "Initially, all servers from these methods are agentized.
+The user may remove or add servers using the Server buffer.
+See Info node `(gnus)Server Buffer'."
+  :type '(repeat symbol)
+  :group 'gnus-agent)
+
+(defcustom gnus-agent-queue-mail t
+  "Whether and when outgoing mail should be queued by the agent.
+When `always', always queue outgoing mail.  When nil, never
+queue.  Otherwise, queue if and only if unplugged."
+  :group 'gnus-agent
+  :type '(radio (const :format "Always" always)
+               (const :format "Never" nil)
+               (const :format "When plugged" t)))
+
+(defcustom gnus-agent-prompt-send-queue nil
+  "If non-nil, `gnus-group-send-queue' will prompt if called when
+unplugged."
+  :group 'gnus-agent
+  :type 'boolean)
 
 ;;; Internal variables
 
@@ -197,12 +229,6 @@ NOTES:
 (defvar gnus-agent-send-mail-function nil)
 (defvar gnus-agent-file-coding-system 'raw-text)
 (defvar gnus-agent-file-loading-cache nil)
-(defvar gnus-agent-file-header-cache nil)
-
-(defvar gnus-agent-auto-agentize-methods '(nntp nnimap)
-  "Initially, all servers from these methods are agentized.
-The user may remove or add servers using the Server buffer.  See Info
-node `(gnus)Server Buffer'.")
 
 ;; Dynamic variables
 (defvar gnus-headers)
@@ -331,9 +357,9 @@ manipulated as follows:
 (gnus-agent-cat-defaccessor
  gnus-agent-cat-score-file                 agent-score-file)
 (gnus-agent-cat-defaccessor
- gnus-agent-cat-disable-undownloaded-faces agent-disable-undownloaded-faces)
+ gnus-agent-cat-enable-undownloaded-faces agent-enable-undownloaded-faces)
 
-(eval-when-compile
+(eval-and-compile
   (defsetf gnus-agent-cat-groups (category) (groups)
     (list 'gnus-agent-set-cat-groups category groups)))
 
@@ -595,19 +621,24 @@ minor mode in all Gnus buffers."
   (unless gnus-agent-send-mail-function
     (setq gnus-agent-send-mail-function
          (or message-send-mail-real-function
-              message-send-mail-function)
+             message-send-mail-function)
          message-send-mail-real-function 'gnus-agent-send-mail))
 
-  (unless gnus-agent-covered-methods
+  ;; If the servers file doesn't exist, auto-agentize some servers and
+  ;; save the servers file so this auto-agentizing isn't invoked
+  ;; again.
+  (unless (file-exists-p (nnheader-concat gnus-agent-directory "lib/servers"))
+    (gnus-message 3 "First time agent user, agentizing remote groups...")
     (mapc
      (lambda (server-or-method)
        (let ((method (gnus-server-to-method server-or-method)))
-         (when (memq (car method)
-                     gnus-agent-auto-agentize-methods)
-           (push (gnus-method-to-server method)
-                 gnus-agent-covered-methods)
-           (setq gnus-agent-method-p-cache nil))))
-     (cons gnus-select-method gnus-secondary-select-methods))))
+        (when (memq (car method)
+                    gnus-agent-auto-agentize-methods)
+          (push (gnus-method-to-server method)
+                gnus-agent-covered-methods)
+          (setq gnus-agent-method-p-cache nil))))
+     (cons gnus-select-method gnus-secondary-select-methods))
+    (gnus-agent-write-servers)))
 
 (defun gnus-agent-queue-setup (&optional group-name)
   "Make sure the queue group exists.
@@ -623,7 +654,8 @@ Optional arg GROUP-NAME allows to specify another group."
      'gnus-dummy '((gnus-draft-mode)))))
 
 (defun gnus-agent-send-mail ()
-  (if gnus-plugged
+  (if (or (not gnus-agent-queue-mail)
+         (and gnus-plugged (not (eq gnus-agent-queue-mail 'always))))
       (funcall gnus-agent-send-mail-function)
     (goto-char (point-min))
     (re-search-forward
@@ -788,30 +820,39 @@ be a select method."
 ;;; Server mode commands
 ;;;
 
-(defun gnus-agent-add-server (server)
+(defun gnus-agent-add-server ()
   "Enroll SERVER in the agent program."
-  (interactive (list (gnus-server-server-name)))
-  (unless server
-    (error "No server on the current line"))
-  (let ((method (gnus-server-get-method nil (gnus-server-server-name))))
+  (interactive)
+  (let* ((server       (gnus-server-server-name))
+         (named-server (gnus-server-named-server))
+         (method       (and server
+                            (gnus-server-get-method nil server))))
+    (unless server
+      (error "No server on the current line"))
+
     (when (gnus-agent-method-p method)
       (error "Server already in the agent program"))
-    (push (gnus-method-to-server method) gnus-agent-covered-methods)
+
+    (push named-server gnus-agent-covered-methods)
+
     (setq gnus-agent-method-p-cache nil)
     (gnus-server-update-server server)
     (gnus-agent-write-servers)
     (gnus-message 1 "Entered %s into the Agent" server)))
 
-(defun gnus-agent-remove-server (server)
+(defun gnus-agent-remove-server ()
   "Remove SERVER from the agent program."
-  (interactive (list (gnus-server-server-name)))
-  (unless server
-    (error "No server on the current line"))
-  (let* ((server (gnus-server-server-name)))
-    (unless (member server gnus-agent-covered-methods)
+  (interactive)
+  (let* ((server       (gnus-server-server-name))
+         (named-server (gnus-server-named-server)))
+    (unless server
+      (error "No server on the current line"))
+
+    (unless (member named-server gnus-agent-covered-methods)
       (error "Server not in the agent program"))
+
     (setq gnus-agent-covered-methods 
-          (delete server gnus-agent-covered-methods)
+          (delete named-server gnus-agent-covered-methods)
           gnus-agent-method-p-cache nil)
 
     (gnus-server-update-server server)
@@ -919,11 +960,9 @@ article's mark is toggled."
              (setq gnus-newsgroup-downloadable
                    (delq article gnus-newsgroup-downloadable))
              (gnus-article-mark article))
-         (progn
-           (setq gnus-newsgroup-downloadable
-                 (gnus-add-to-sorted-list gnus-newsgroup-downloadable article))
-           gnus-downloadable-mark)
-         )
+        (setq gnus-newsgroup-downloadable
+              (gnus-add-to-sorted-list gnus-newsgroup-downloadable article))
+        gnus-downloadable-mark)
        'unread))))
 
 (defun gnus-agent-get-undownloaded-list ()
@@ -1046,10 +1085,6 @@ Optional arg ALL, if non-nil, means to fetch all articles."
                    (setq gnus-newsgroup-downloadable
                          (delq article gnus-newsgroup-downloadable))
 
-                   ;; The downloadable mark is implemented as a
-                   ;; type of read mark.  Therefore, marking the
-                   ;; article as unread is sufficient to clear
-                   ;; its downloadable flag.  
                    (gnus-summary-mark-article article gnus-unread-mark))
                   (was-marked-downloadable
                    (gnus-summary-set-agent-mark article t)))
@@ -1074,68 +1109,75 @@ This can be added to `gnus-select-article-hook' or
 ;;; Internal functions
 ;;;
 
-;;; NOTES:
-;;; The agent's active range is defined as follows:
-;;;  If the agent has no record of the group, use the actual active
-;;;    range.
-;;;  If the agent has a record, set the agent's active range to
-;;;    include the max limit of the actual active range.
-;;;  When expiring, update the min limit to match the smallest of the
-;;;    min article not expired or the min actual active range.
-
 (defun gnus-agent-save-active (method)
-  (gnus-agent-save-active-1 method 'gnus-active-to-gnus-format))
-
-(defun gnus-agent-save-active-1 (method function)
   (when (gnus-agent-method-p method)
     (let* ((gnus-command-method method)
           (new (gnus-make-hashtable (count-lines (point-min) (point-max))))
           (file (gnus-agent-lib-file "active")))
-      (funcall function nil new)
+      (gnus-active-to-gnus-format nil new)
       (gnus-agent-write-active file new)
       (erase-buffer)
       (nnheader-insert-file-contents file))))
 
-(defun gnus-agent-write-active (file new &optional literal-replacement)
-  (let ((old new))
-    (when (and (not literal-replacement)
-               (file-exists-p file))
-      (setq old (gnus-make-hashtable (count-lines (point-min) (point-max))))
-      (with-temp-buffer
-        (nnheader-insert-file-contents file)
-        (gnus-active-to-gnus-format nil old))
-      ;; Iterate over the current active groups, the current active
-      ;; range may expand, but NOT CONTRACT, the agent's active range.
-      (mapatoms
-       (lambda (nsym)
-         (let ((new-active (and nsym (boundp nsym) (symbol-value nsym))))
-           (when new-active
-             (let* ((osym       (intern (symbol-name nsym) old))
-                    (old-active (and (boundp osym) (symbol-value osym))))
-               (if old-active
-                   (let ((new-min (car new-active))
-                         (old-min (car old-active))
-                         (new-max (cdr new-active))
-                         (old-max (cdr old-active)))
-                     (if (and (integerp new-min)
-                              (< new-min old-min))
-                         (setcar old-active new-min))
-                     (if (and (integerp new-max)
-                              (> new-max old-max))
-                         (setcdr old-active new-max)))
-                 (set osym new-active))))))
-       new))
+(defun gnus-agent-write-active (file new)
     (gnus-make-directory (file-name-directory file))
     (let ((nnmail-active-file-coding-system gnus-agent-file-coding-system))
       ;; The hashtable contains real names of groups.  However, do NOT
       ;; add the foreign server prefix as gnus-active-to-gnus-format
       ;; will add it while reading the file.
-      (gnus-write-active-file file old nil))))
+      (gnus-write-active-file file new nil)))
 
-(defun gnus-agent-save-groups (method)
-  (gnus-agent-save-active-1 method 'gnus-groups-to-gnus-format))
+(defun gnus-agent-possibly-alter-active (group active &optional info)
+  "Possibly expand a group's active range to include articles
+downloaded into the agent."
+  (let* ((gnus-command-method (or gnus-command-method
+                                  (gnus-find-method-for-group group))))
+    (when (gnus-agent-method-p gnus-command-method)
+      (let* ((local (gnus-agent-get-local group))
+             (active-min (or (car active) 0))
+             (active-max (or (cdr active) 0))
+             (agent-min (or (car local) active-min))
+             (agent-max (or (cdr local) active-max)))
+
+        (when (< agent-min active-min)
+          (setcar active agent-min))
+
+        (when (> agent-max active-max)
+          (setcdr active agent-max))
+
+        (when (and info (< agent-max (- active-min 100)))
+          ;; I'm expanding the active range by such a large amount
+          ;; that there is a gap of more than 100 articles between the
+          ;; last article known to the agent and the first article
+          ;; currently available on the server.  This gap contains
+          ;; articles that have been lost, mark them as read so that
+          ;; gnus doesn't waste resources trying to fetch them.
+
+          ;; NOTE: I don't do this for smaller gaps (< 100) as I don't
+          ;; want to modify the local file everytime someone restarts
+          ;; gnus.  The small gap will cause a tiny performance hit
+          ;; when gnus tries, and fails, to retrieve the articles.
+          ;; Still that should be smaller than opening a buffer,
+          ;; printing this list to the buffer, and then writing it to a
+          ;; file.
+
+          (let ((read (gnus-info-read info)))
+            (gnus-info-set-read 
+             info 
+             (gnus-range-add 
+              read 
+              (list (cons (1+ agent-max) 
+                          (1- active-min))))))
+
+          ;; Lie about the agent's local range for this group to
+          ;; disable the set read each time this server is opened.
+          ;; NOTE: Opening this group will restore the valid local
+          ;; range but it will also expand the local range to
+          ;; incompass the new active range.
+          (gnus-agent-set-local group agent-min (1- active-min)))))))
 
 (defun gnus-agent-save-group-info (method group active)
+  "Update a single group's active range in the agent's copy of the server's active file."
   (when (gnus-agent-method-p method)
     (let* ((gnus-command-method method)
           (coding-system-for-write nnheader-file-coding-system)
@@ -1201,7 +1243,7 @@ This can be added to `gnus-select-article-hook' or
 
 (defun gnus-agent-covered-methods ()
   "Return the subset of methods that are covered by the agent."
-  (mapcar #'gnus-server-to-method gnus-agent-covered-methods))
+  (delq nil (mapcar #'gnus-server-to-method gnus-agent-covered-methods)))
 
 ;;; History functions
 
@@ -1435,7 +1477,7 @@ and that there are no duplicates."
              (gnus-message 1
                            "Overview buffer contains garbage '%s'."
                            (buffer-substring
-                            p (gnus-point-at-eol))))
+                            p (point-at-eol))))
             ((= cur prev-num)
              (or backed-up
                   (setq backed-up (gnus-agent-backup-overview-buffer)))
@@ -1689,53 +1731,55 @@ FILE and places the combined headers into `nntp-server-buffer'."
 (defun gnus-agent-read-agentview (file)
   "Load FILE and do a `read' there."
   (with-temp-buffer
-    (ignore-errors
-      (nnheader-insert-file-contents file)
-      (goto-char (point-min))
-      (let ((alist (read (current-buffer)))
-            (version (condition-case nil (read (current-buffer))
-                       (end-of-file 0)))
-            changed-version)
-
-        (cond
-        ((= version 0)
-         (let ((inhibit-quit t)
-               entry)
-           (gnus-agent-open-history)
-           (set-buffer (gnus-agent-history-buffer))
-           (goto-char (point-min))
-           (while (not (eobp))
-             (if (and (looking-at
-                       "[^\t\n]+\t\\([0-9]+\\)\t\\([^ \n]+\\) \\([0-9]+\\)")
-                      (string= (match-string 2)
-                               gnus-agent-read-agentview)
-                      (setq entry (assoc (string-to-number (match-string 3)) alist)))
-                 (setcdr entry (string-to-number (match-string 1))))
-             (forward-line 1))
-           (gnus-agent-close-history)
-           (setq changed-version t)))
-        ((= version 1)
-         (setq changed-version (not (= 1 gnus-agent-article-alist-save-format))))
-        ((= version 2)
-         (let (uncomp)
-           (mapcar
-            (lambda (comp-list)
-              (let ((state (car comp-list))
-                    (sequence (gnus-uncompress-sequence
-                               (cdr comp-list))))
-                (mapcar (lambda (article-id)
-                          (setq uncomp (cons (cons article-id state) uncomp)))
-                        sequence)))
-            alist)
-           (setq alist (sort uncomp
-                             (lambda (first second)
-                               (< (car first) (car second))))))))
-        (when changed-version
-          (let ((gnus-agent-article-alist alist))
-            (gnus-agent-save-alist gnus-agent-read-agentview)))
-        alist))))
-
-(defun gnus-agent-save-alist (group &optional articles state dir)
+    (condition-case nil
+      (progn
+        (nnheader-insert-file-contents file)
+        (goto-char (point-min))
+        (let ((alist (read (current-buffer)))
+              (version (condition-case nil (read (current-buffer))
+                         (end-of-file 0)))
+              changed-version)
+
+          (cond
+           ((< version 2)
+            (error "gnus-agent-read-agentview no longer supports version %d.  Stop gnus, manually evaluate gnus-agent-convert-to-compressed-agentview, then restart gnus."))
+           ((= version 0)
+            (let ((inhibit-quit t)
+                  entry)
+              (gnus-agent-open-history)
+              (set-buffer (gnus-agent-history-buffer))
+              (goto-char (point-min))
+              (while (not (eobp))
+                (if (and (looking-at
+                          "[^\t\n]+\t\\([0-9]+\\)\t\\([^ \n]+\\) \\([0-9]+\\)")
+                         (string= (match-string 2)
+                                  gnus-agent-read-agentview)
+                         (setq entry (assoc (string-to-number (match-string 3)) alist)))
+                    (setcdr entry (string-to-number (match-string 1))))
+                (forward-line 1))
+              (gnus-agent-close-history)
+              (setq changed-version t)))
+           ((= version 1)
+            (setq changed-version (not (= 1 gnus-agent-article-alist-save-format))))
+           ((= version 2)
+            (let (uncomp)
+              (mapcar
+               (lambda (comp-list)
+                 (let ((state (car comp-list))
+                       (sequence (gnus-uncompress-sequence
+                                  (cdr comp-list))))
+                   (mapcar (lambda (article-id)
+                             (setq uncomp (cons (cons article-id state) uncomp)))
+                           sequence)))
+               alist)
+              (setq alist (sort uncomp 'car-less-than-car)))))
+          (when changed-version
+            (let ((gnus-agent-article-alist alist))
+              (gnus-agent-save-alist gnus-agent-read-agentview)))
+          alist))
+      (file-error nil))))
+
+(defun gnus-agent-save-alist (group &optional articles state)
   "Save the article-state alist for GROUP."
   (let* ((file-name-coding-system nnmail-pathname-coding-system)
         (prev (cons nil gnus-agent-article-alist))
@@ -1754,12 +1798,13 @@ FILE and places the combined headers into `nntp-server-buffer'."
        (setcdr (cadr prev) state)))
       (setq prev (cdr prev)))
     (setq gnus-agent-article-alist (cdr all))
-    (if dir
-       (gnus-make-directory dir)
-      (gnus-make-directory (gnus-agent-article-name "" group)))
-    (with-temp-file (if dir
-                       (expand-file-name ".agentview" dir)
-                     (gnus-agent-article-name ".agentview" group))
+
+    (gnus-agent-set-local group 
+                          (caar gnus-agent-article-alist) 
+                          (caar (last gnus-agent-article-alist)))
+
+    (gnus-make-directory (gnus-agent-article-name "" group))
+    (with-temp-file (gnus-agent-article-name ".agentview" group)
       (cond ((eq gnus-agent-article-alist-save-format 1)
              (princ gnus-agent-article-alist (current-buffer)))
             ((eq gnus-agent-article-alist-save-format 2)
@@ -1785,6 +1830,141 @@ FILE and places the combined headers into `nntp-server-buffer'."
       (princ gnus-agent-article-alist-save-format (current-buffer))
       (insert "\n"))))
 
+(defvar gnus-agent-article-local nil)
+(defvar gnus-agent-file-loading-local nil)
+
+(defun gnus-agent-load-local (&optional method)
+  "Load the METHOD'S local file.  The local file contains min/max
+article counts for each of the method's subscribed groups."
+  (let ((gnus-command-method (or method gnus-command-method)))
+    (setq gnus-agent-article-local
+          (gnus-cache-file-contents
+           (gnus-agent-lib-file "local")
+           'gnus-agent-file-loading-local
+           'gnus-agent-read-and-cache-local))))
+
+(defun gnus-agent-read-and-cache-local (file)
+  "Load and read FILE then bind its contents to
+gnus-agent-article-local.  If that variable had `dirty' (also known as
+modified) original contents, they are first saved to their own file."
+
+  (if (and gnus-agent-article-local
+           (symbol-value (intern "+dirty" gnus-agent-article-local)))
+      (gnus-agent-save-local))
+  (gnus-agent-read-local file))
+
+(defun gnus-agent-read-local (file)
+  "Load FILE and do a `read' there."
+  (let ((my-obarray (gnus-make-hashtable (count-lines (point-min) 
+                                                      (point-max))))
+        (line 1))
+    (with-temp-buffer
+      (condition-case nil
+          (nnheader-insert-file-contents file)
+        (file-error))
+
+      (goto-char (point-min))
+      ;; Skip any comments at the beginning of the file (the only place where they may appear)
+      (while (= (following-char) ?\;)
+        (forward-line 1)
+        (setq line (1+ line)))
+
+      (while (not (eobp))
+        (condition-case err
+            (let (group 
+                  min
+                  max
+                  (cur (current-buffer)))
+              (setq group (read cur)
+                    min (read cur)
+                    max (read cur))
+
+              (when (stringp group)
+                (setq group (intern group my-obarray)))
+
+              ;; NOTE: The '+ 0' ensure that min and max are both numerics.
+              (set group (cons (+ 0 min) (+ 0 max))))
+          (error
+           (gnus-message 3 "Warning - invalid agent local: %s on line %d: "
+                         file line (error-message-string err))))
+        (forward-line 1)
+        (setq line (1+ line))))
+      
+    (set (intern "+dirty" my-obarray) nil)
+    (set (intern "+method" my-obarray) gnus-command-method)
+    my-obarray))
+
+(defun gnus-agent-save-local (&optional force)
+  "Save gnus-agent-article-local under it method's agent.lib directory."
+  (let ((my-obarray gnus-agent-article-local))
+    (when (and my-obarray
+               (or force (symbol-value (intern "+dirty" my-obarray))))
+      (let* ((gnus-command-method (symbol-value (intern "+method" my-obarray)))
+             ;; NOTE: gnus-command-method is used within gnus-agent-lib-file.
+             (dest (gnus-agent-lib-file "local")))
+        (gnus-make-directory (gnus-agent-lib-file ""))
+        (with-temp-file dest
+          (let ((gnus-command-method (symbol-value (intern "+method" my-obarray)))
+                (file-name-coding-system nnmail-pathname-coding-system)
+                (coding-system-for-write
+                 gnus-agent-file-coding-system)
+                print-level print-length item article
+                (standard-output (current-buffer)))
+            (mapatoms (lambda (symbol)
+                        (cond ((not (boundp symbol))
+                               nil)
+                              ((member (symbol-name symbol) '("+dirty" "+method"))
+                               nil)
+                              (t
+                               (prin1 symbol)
+                               (let ((range (symbol-value symbol)))
+                                 (princ " ")
+                                 (princ (car range))
+                                 (princ " ")
+                                 (princ (cdr range))
+                                 (princ "\n"))))) 
+                      my-obarray)))))))
+
+(defun gnus-agent-get-local (group)
+  (let* ((gmane (gnus-group-real-name group))
+         (gnus-command-method (gnus-find-method-for-group group))
+         (local (gnus-agent-load-local))
+         (symb (intern gmane local))
+         (minmax (and (boundp symb) (symbol-value symb))))
+    (unless minmax
+      ;; Bind these so that gnus-agent-load-alist doesn't change the
+      ;; current alist (i.e. gnus-agent-article-alist)
+      (let* ((gnus-agent-article-alist gnus-agent-article-alist)
+             (gnus-agent-file-loading-cache gnus-agent-file-loading-cache)
+             (alist (gnus-agent-load-alist group)))
+        (when alist
+          (setq minmax
+                (cons (caar alist)
+                      (caar (last alist))))
+          (gnus-agent-set-local group (car minmax) (cdr minmax) 
+                                gmane gnus-command-method local))))
+    minmax))
+
+(defun gnus-agent-set-local (group min max &optional gmane method local)
+  (let* ((gmane (or gmane (gnus-group-real-name group)))
+         (gnus-command-method (or method (gnus-find-method-for-group group)))
+         (local (or local (gnus-agent-load-local)))
+         (symb (intern gmane local))
+         (minmax (and (boundp symb) (symbol-value symb))))
+    
+    (if (cond ((and minmax
+                    (or (not (eq min (car minmax)))
+                        (not (eq max (cdr minmax)))))
+               (setcar minmax min)
+               (setcdr minmax max)
+               t)
+              (minmax
+               nil)
+              ((and min max)
+               (set symb (cons min max))
+               t))
+        (set (intern "+dirty" local) t))))
+
 (defun gnus-agent-article-name (article group)
   (expand-file-name article
                    (file-name-as-directory
@@ -2187,7 +2367,7 @@ The following commands are available:
     (gnus-category-position-point)))
 
 (defun gnus-category-name ()
-  (or (intern (get-text-property (gnus-point-at-bol) 'gnus-category))
+  (or (intern (get-text-property (point-at-bol) 'gnus-category))
       (error "No category on the current line")))
 
 (defun gnus-category-read ()
@@ -2432,22 +2612,58 @@ The following commands are available:
 (defun gnus-predicate-implies-unread (predicate)
   "Say whether PREDICATE implies unread articles only.
 It is okay to miss some cases, but there must be no false positives.
-That is, if this function returns true, then indeed the predicate must
+That is, if this predicate returns true, then indeed the predicate must
 return only unread articles."
-  (gnus-function-implies-unread-1 (gnus-category-make-function predicate)))
+  (eq t (gnus-function-implies-unread-1 
+         (gnus-category-make-function-1 predicate))))
 
 (defun gnus-function-implies-unread-1 (function)
-  (cond ((eq function (symbol-function 'gnus-agent-read-p))
-         nil)
-        ((not function)
-         nil)
-        ((functionp function)
-         'ignore)
-        ((memq (car function) '(or and not))
-         (apply (car function)
-                (mapcar 'gnus-function-implies-unread-1 (cdr function))))
-        (t
-         (error "Unknown function: %s" function))))
+  "Recursively evaluate a predicate function to determine whether it can select
+any read articles.  Returns t if the function is known to never
+return read articles, nil when it is known to always return read
+articles, and t_nil when the function may return both read and unread
+articles."
+  (let ((func (car function))
+        (args (mapcar 'gnus-function-implies-unread-1 (cdr function))))
+    (cond ((eq func 'and)
+           (cond ((memq t args) ; if any argument returns only unread articles
+                  ;; then that argument constrains the result to only unread articles.
+                  t)
+                 ((memq 't_nil args) ; if any argument is indeterminate
+                  ;; then the result is indeterminate
+                  't_nil)))
+          ((eq func 'or)
+           (cond ((memq nil args) ; if any argument returns read articles
+                  ;; then that argument ensures that the results includes read articles.
+                  nil)
+                 ((memq 't_nil args) ; if any argument is indeterminate
+                  ;; then that argument ensures that the results are indeterminate
+                  't_nil)
+                 (t ; if all arguments return only unread articles
+                  ;; then the result returns only unread articles
+                  t)))
+          ((eq func 'not)
+           (cond ((eq (car args) 't_nil) ; if the argument is indeterminate
+                  ; then the result is indeterminate
+                  (car args))
+                 (t ; otherwise
+                  ; toggle the result to be the opposite of the argument
+                  (not (car args)))))
+          ((eq func 'gnus-agent-read-p)
+           nil) ; The read predicate NEVER returns unread articles
+          ((eq func 'gnus-agent-false)
+           t) ; The false predicate returns t as the empty set excludes all read articles
+          ((eq func 'gnus-agent-true)
+           nil) ; The true predicate ALWAYS returns read articles
+          ((catch 'found-match
+             (let ((alist gnus-category-predicate-alist))
+               (while alist
+                 (if (eq func (cdar alist))
+                     (throw 'found-match t)
+                   (setq alist (cdr alist))))))
+           't_nil) ; All other predicates return read and unread articles
+          (t
+           (error "Unknown predicate function: %s" function)))))
 
 (defun gnus-group-category (group)
   "Return the category GROUP belongs to."
@@ -2508,8 +2724,7 @@ FORCE is equivalent to setting the expiration predicates to true."
                     (save-excursion
                       (gnus-agent-expire-group-1
                        group overview (gnus-gethash-safe group orig)
-                       articles force))
-                    (gnus-agent-write-active active-file orig t)))
+                       articles force))))
               (kill-buffer overview))))
       (gnus-message 4 (gnus-agent-expire-done-message)))))
 
@@ -2713,7 +2928,8 @@ line." (point) nov-file)))
           (while dlist
             (let ((new-completed (truncate (* 100.0
                                               (/ (setq cnt (1+ cnt))
-                                                 len)))))
+                                                 len))))
+                 message-log-max)
               (when (> new-completed completed)
                 (setq completed new-completed)
                 (gnus-message 7 "%3d%% completed..."  completed)))
@@ -2727,16 +2943,16 @@ line." (point) nov-file)))
                ;; Kept articles are unread, marked, or special.
                (keep
                 (gnus-agent-message 10
-                                    "gnus-agent-expire: Article %d: Kept %s article%s."
-                                    article-number keep (if fetch-date " and file" ""))
+                                    "gnus-agent-expire: %s:%d: Kept %s article%s."
+                                    group article-number keep (if fetch-date " and file" ""))
                 (when fetch-date
                   (unless (file-exists-p
                            (concat dir (number-to-string
                                         article-number)))
                     (setf (nth 1 entry) nil)
                     (gnus-agent-message 3 "gnus-agent-expire cleared \
-download flag on article %d as the cached article file is missing."
-                                        (caar dlist)))
+download flag on %s:%d as the cached article file is missing."
+                                        group (caar dlist)))
                   (unless marker
                     (gnus-message 1 "gnus-agent-expire detected a \
 missing NOV entry.  Run gnus-agent-regenerate-group to restore it.")))
@@ -2787,7 +3003,7 @@ missing NOV entry.  Run gnus-agent-regenerate-group to restore it.")))
 
                     (incf (nth 0 stats))
 
-                    (let ((from (gnus-point-at-bol))
+                    (let ((from (point-at-bol))
                           (to (progn (forward-line 1) (point))))
                       (incf (nth 2 stats) (- to from))
                       (delete-region from to)))
@@ -2804,13 +3020,14 @@ missing NOV entry.  Run gnus-agent-regenerate-group to restore it.")))
                     (push (format "Removed %s article number from \
 article alist" type) actions))
 
-                  (gnus-agent-message 8 "gnus-agent-expire: Article %d: %s"
-                                      article-number
-                                      (mapconcat 'identity actions ", "))))
+                 (when actions
+                   (gnus-agent-message 8 "gnus-agent-expire: %s:%d: %s"
+                                       group article-number
+                                       (mapconcat 'identity actions ", ")))))
                (t
                 (gnus-agent-message
-                 10 "gnus-agent-expire: Article %d: Article kept as \
-expiration tests failed." article-number)
+                 10 "gnus-agent-expire: %s:%d: Article kept as \
+expiration tests failed." group article-number)
                 (gnus-agent-append-to-list
                  tail-alist (cons article-number fetch-date)))
                )
@@ -2827,12 +3044,7 @@ expiration tests failed." article-number)
           (let ((inhibit-quit t))
             (unless (equal alist gnus-agent-article-alist)
               (setq gnus-agent-article-alist alist)
-              (gnus-agent-save-alist group)
-
-              ;; The active list changed, set the agent's active range
-              ;; to match the beginning of the list.
-              (if alist
-                  (setcar active (caar alist))))
+              (gnus-agent-save-alist group))
 
             (when (buffer-modified-p)
               (let ((coding-system-for-write
@@ -2892,8 +3104,7 @@ articles in every agentized group."))
                         (when active
                           (save-excursion
                             (gnus-agent-expire-group-1
-                             expiring-group overview active articles force)))))
-                    (gnus-agent-write-active active-file orig t))))
+                             expiring-group overview active articles force))))))))
             (kill-buffer overview))
           (gnus-agent-expire-unagentized-dirs)
           (gnus-message 4 (gnus-agent-expire-done-message))))))
@@ -3223,6 +3434,9 @@ has been fetched."
 (defun gnus-agent-regenerate-group (group &optional reread)
   "Regenerate GROUP.
 If REREAD is t, all articles in the .overview are marked as unread.
+If REREAD is a list, the specified articles will be marked as unread.
+In addition, their NOV entries in .overview will be refreshed using
+the articles' current headers.
 If REREAD is not nil, downloaded articles are marked as unread."
   (interactive
    (list (let ((def (or (gnus-group-group-name)
@@ -3236,245 +3450,224 @@ If REREAD is not nil, downloaded articles are marked as unread."
                  def
                select)))
          (catch 'mark
-           (while (let ((c (read-char-exclusive 
-                            "Mark as unread: (n)one / (a)ll / all (d)ownloaded articles? (n)"
-                            )))
+           (while (let (c
+                        (cursor-in-echo-area t)
+                        (echo-keystrokes 0))
+                    (message "Mark as unread: (n)one / (a)ll / all (d)ownloaded articles? (n) ")
+                    (setq c (read-char-exclusive))
+
                     (cond ((or (eq c ?\r) (eq c ?n) (eq c ?N))
                            (throw 'mark nil))
                           ((or (eq c ?a) (eq c ?A))
                            (throw 'mark t))
                           ((or (eq c ?d) (eq c ?D))
                            (throw 'mark 'some)))
-                    (message "Ignoring unexpected input")
+                    (gnus-message 3 "Ignoring unexpected input")
                     (sit-for 1)
                     t)))))
-  (gnus-message 5 "Regenerating in %s" group)
-  (let* ((gnus-command-method (or gnus-command-method
-                                  (gnus-find-method-for-group group)))
-         (file (gnus-agent-article-name ".overview" group))
-         (dir (file-name-directory file))
-         point
-        (downloaded (if (file-exists-p dir)
-                        (sort (mapcar (lambda (name) (string-to-int name))
-                                      (directory-files dir nil "^[0-9]+$" t))
-                              '>)
-                      (progn (gnus-make-directory dir) nil)))
-         dl nov-arts
-         alist header
-         regenerated)
-
-    (mm-with-unibyte-buffer
-     (if (file-exists-p file)
-         (let ((nnheader-file-coding-system
-                gnus-agent-file-coding-system))
-           (nnheader-insert-file-contents file)))
-     (set-buffer-modified-p nil)
-
-     ;; Load the article IDs found in the overview file.  As a
-     ;; side-effect, validate the file contents.
-     (let ((load t))
-       (while load
-         (setq load nil)
-         (goto-char (point-min))
-         (while (< (point) (point-max))
-          (cond ((and (looking-at "[0-9]+\t")
-                       (<= (- (match-end 0) (match-beginning 0)) 9))
-                  (push (read (current-buffer)) nov-arts)
-                  (forward-line 1)
-                  (let ((l1 (car nov-arts))
-                        (l2 (cadr nov-arts)))
-                    (cond ((not l2)
-                           nil)
-                          ((< l1 l2)
-                          (gnus-message 3 "gnus-agent-regenerate-group: NOV\
+  (when group
+      (gnus-message 5 "Regenerating in %s" group)
+      (let* ((gnus-command-method (or gnus-command-method
+                                      (gnus-find-method-for-group group)))
+             (file (gnus-agent-article-name ".overview" group))
+             (dir (file-name-directory file))
+             point
+             (downloaded (if (file-exists-p dir)
+                             (sort (mapcar (lambda (name) (string-to-int name))
+                                           (directory-files dir nil "^[0-9]+$" t))
+                                   '>)
+                           (progn (gnus-make-directory dir) nil)))
+             dl nov-arts
+             alist header
+             regenerated)
+
+        (mm-with-unibyte-buffer
+          (if (file-exists-p file)
+              (let ((nnheader-file-coding-system
+                     gnus-agent-file-coding-system))
+                (nnheader-insert-file-contents file)))
+          (set-buffer-modified-p nil)
+
+          ;; Load the article IDs found in the overview file.  As a
+          ;; side-effect, validate the file contents.
+          (let ((load t))
+            (while load
+              (setq load nil)
+              (goto-char (point-min))
+              (while (< (point) (point-max))
+                (cond ((and (looking-at "[0-9]+\t")
+                            (<= (- (match-end 0) (match-beginning 0)) 9))
+                       (push (read (current-buffer)) nov-arts)
+                       (forward-line 1)
+                       (let ((l1 (car nov-arts))
+                             (l2 (cadr nov-arts)))
+                         (cond ((and (listp reread) (memq l1 reread))
+                                (gnus-delete-line)
+                                (setq nov-arts (cdr nov-arts))
+                                (gnus-message 4 "gnus-agent-regenerate-group: NOV\
+entry of article %s deleted." l1))
+                               ((not l2)
+                                nil)
+                               ((< l1 l2)
+                                (gnus-message 3 "gnus-agent-regenerate-group: NOV\
  entries are NOT in ascending order.")
-                           ;; Don't sort now as I haven't verified
-                           ;; that every line begins with a number
-                           (setq load t))
-                          ((= l1 l2)
-                           (forward-line -1)
-                          (gnus-message 4 "gnus-agent-regenerate-group: NOV\
+                                ;; Don't sort now as I haven't verified
+                                ;; that every line begins with a number
+                                (setq load t))
+                               ((= l1 l2)
+                                (forward-line -1)
+                                (gnus-message 4 "gnus-agent-regenerate-group: NOV\
  entries contained duplicate of article %s.     Duplicate deleted." l1)
-                           (gnus-delete-line)
-                           (setq nov-arts (cdr nov-arts))))))
-                 (t
-                 (gnus-message 1 "gnus-agent-regenerate-group: NOV\
+                                (gnus-delete-line)
+                                (setq nov-arts (cdr nov-arts))))))
+                      (t
+                       (gnus-message 1 "gnus-agent-regenerate-group: NOV\
  entries contained line that did not begin with an article number.  Deleted\
  line.")
-                  (gnus-delete-line))))
-         (if load
-            (progn
-              (gnus-message 5 "gnus-agent-regenerate-group: Sorting NOV\
+                       (gnus-delete-line))))
+              (when load
+               (gnus-message 5 "gnus-agent-regenerate-group: Sorting NOV\
  entries into ascending order.")
-              (sort-numeric-fields 1 (point-min) (point-max))
-                    (setq nov-arts nil)))))
-     (gnus-agent-check-overview-buffer)
-
-     ;; Construct a new article alist whose nodes match every header
-     ;; in the .overview file.  As a side-effect, missing headers are
-     ;; reconstructed from the downloaded article file.
-     (while (or downloaded nov-arts)
-       (cond ((and downloaded
-                   (or (not nov-arts)
-                       (> (car downloaded) (car nov-arts))))
-              ;; This entry is missing from the overview file
-             (gnus-message 3 "Regenerating NOV %s %d..." group
-                            (car downloaded))
-              (let ((file (concat dir (number-to-string (car downloaded)))))
-                (mm-with-unibyte-buffer
-                 (nnheader-insert-file-contents file)
-                 (nnheader-remove-body)
-                 (setq header (nnheader-parse-naked-head)))
-                (mail-header-set-number header (car downloaded))
-                (if nov-arts
-                    (let ((key (concat "^" (int-to-string (car nov-arts))
-                                       "\t")))
-                      (or (re-search-backward key nil t)
-                          (re-search-forward key))
-                      (forward-line 1))
-                  (goto-char (point-min)))
-                (nnheader-insert-nov header))
-              (setq nov-arts (cons (car downloaded) nov-arts)))
-             ((eq (car downloaded) (car nov-arts))
-              ;; This entry in the overview has been downloaded
-              (push (cons (car downloaded)
-                          (time-to-days
-                           (nth 5 (file-attributes
-                                   (concat dir (number-to-string
-                                                (car downloaded))))))) alist)
-              (setq downloaded (cdr downloaded))
-              (setq nov-arts (cdr nov-arts)))
-             (t
-              ;; This entry in the overview has not been downloaded
-              (push (cons (car nov-arts) nil) alist)
-              (setq nov-arts (cdr nov-arts)))))
-
-     ;; When gnus-agent-consider-all-articles is set,
-     ;; gnus-agent-regenerate-group should NOT remove article IDs from
-     ;; the alist.  Those IDs serve as markers to indicate that an
-     ;; attempt has been made to fetch that article's header.
-
-     ;; When gnus-agent-consider-all-articles is NOT set,
-     ;; gnus-agent-regenerate-group can remove the article ID of every
-     ;; article (with the exception of the last ID in the list - it's
-     ;; special) that no longer appears in the overview.  In this
-     ;; situtation, the last article ID in the list implies that it,
-     ;; and every article ID preceeding it, have been fetched from the
-     ;; server.
-     (if gnus-agent-consider-all-articles
-         ;; Restore all article IDs that were not found in the overview file.
-         (let* ((n (cons nil alist))
-                (merged n)
-                (o (gnus-agent-load-alist group)))
-           (while o
-             (let ((nID (caadr n))
-                   (oID (caar o)))
-               (cond ((not nID)
-                      (setq n (setcdr n (list (list oID))))
-                      (setq o (cdr o)))
-                     ((< oID nID)
-                      (setcdr n (cons (list oID) (cdr n)))
-                      (setq o (cdr o)))
-                     ((= oID nID)
-                      (setq o (cdr o))
-                      (setq n (cdr n)))
-                     (t
-                      (setq n (cdr n))))))
-           (setq alist (cdr merged)))
-       ;; Restore the last article ID if it is not already in the new alist
-       (let ((n (last alist))
-             (o (last (gnus-agent-load-alist group))))
-         (cond ((not o)
-                nil)
-               ((not n)
-                (push (cons (caar o) nil) alist))
-               ((< (caar n) (caar o))
-                (setcdr n (list (car o)))))))
-
-     (let ((inhibit-quit t))
-     (if (setq regenerated (buffer-modified-p))
-         (let ((coding-system-for-write gnus-agent-file-coding-system))
-           (write-region (point-min) (point-max) file nil 'silent)))
-
-    (setq regenerated (or regenerated
-                          (and reread gnus-agent-article-alist)
-                          (not (equal alist gnus-agent-article-alist)))
-          )
-
-    (setq gnus-agent-article-alist alist)
-
-    (when regenerated
-        (gnus-agent-save-alist group)))
-     )
-
-    (when (and reread gnus-agent-article-alist)
-      (gnus-make-ascending-articles-unread
-       group
-       (delq nil (mapcar (function (lambda (c)
-                                     (cond ((eq reread t)
-                                            (car c))
-                                           ((cdr c)
-                                            (car c)))))
-                         gnus-agent-article-alist)))
-
-      (when (gnus-buffer-live-p gnus-group-buffer)
-        (gnus-group-update-group group t)
-        (sit-for 0))
-      )
-
-    (gnus-message 5 nil)
-    regenerated))
+               (sort-numeric-fields 1 (point-min) (point-max))
+               (setq nov-arts nil))))
+          (gnus-agent-check-overview-buffer)
+
+          ;; Construct a new article alist whose nodes match every header
+          ;; in the .overview file.  As a side-effect, missing headers are
+          ;; reconstructed from the downloaded article file.
+          (while (or downloaded nov-arts)
+            (cond ((and downloaded
+                        (or (not nov-arts)
+                            (> (car downloaded) (car nov-arts))))
+                   ;; This entry is missing from the overview file
+                   (gnus-message 3 "Regenerating NOV %s %d..." group
+                                 (car downloaded))
+                   (let ((file (concat dir (number-to-string (car downloaded)))))
+                     (mm-with-unibyte-buffer
+                       (nnheader-insert-file-contents file)
+                       (nnheader-remove-body)
+                       (setq header (nnheader-parse-naked-head)))
+                     (mail-header-set-number header (car downloaded))
+                     (if nov-arts
+                         (let ((key (concat "^" (int-to-string (car nov-arts))
+                                            "\t")))
+                           (or (re-search-backward key nil t)
+                               (re-search-forward key))
+                           (forward-line 1))
+                       (goto-char (point-min)))
+                     (nnheader-insert-nov header))
+                   (setq nov-arts (cons (car downloaded) nov-arts)))
+                  ((eq (car downloaded) (car nov-arts))
+                   ;; This entry in the overview has been downloaded
+                   (push (cons (car downloaded)
+                               (time-to-days
+                                (nth 5 (file-attributes
+                                        (concat dir (number-to-string
+                                                     (car downloaded))))))) alist)
+                   (setq downloaded (cdr downloaded))
+                   (setq nov-arts (cdr nov-arts)))
+                  (t
+                   ;; This entry in the overview has not been downloaded
+                   (push (cons (car nov-arts) nil) alist)
+                   (setq nov-arts (cdr nov-arts)))))
+
+          ;; When gnus-agent-consider-all-articles is set,
+          ;; gnus-agent-regenerate-group should NOT remove article IDs from
+          ;; the alist.  Those IDs serve as markers to indicate that an
+          ;; attempt has been made to fetch that article's header.
+
+          ;; When gnus-agent-consider-all-articles is NOT set,
+          ;; gnus-agent-regenerate-group can remove the article ID of every
+          ;; article (with the exception of the last ID in the list - it's
+          ;; special) that no longer appears in the overview.  In this
+          ;; situtation, the last article ID in the list implies that it,
+          ;; and every article ID preceeding it, have been fetched from the
+          ;; server.
+
+          (if gnus-agent-consider-all-articles
+              ;; Restore all article IDs that were not found in the overview file.
+              (let* ((n (cons nil alist))
+                     (merged n)
+                     (o (gnus-agent-load-alist group)))
+                (while o
+                  (let ((nID (caadr n))
+                        (oID (caar o)))
+                    (cond ((not nID)
+                           (setq n (setcdr n (list (list oID))))
+                           (setq o (cdr o)))
+                          ((< oID nID)
+                           (setcdr n (cons (list oID) (cdr n)))
+                           (setq o (cdr o)))
+                          ((= oID nID)
+                           (setq o (cdr o))
+                           (setq n (cdr n)))
+                          (t
+                           (setq n (cdr n))))))
+                (setq alist (cdr merged)))
+            ;; Restore the last article ID if it is not already in the new alist
+            (let ((n (last alist))
+                  (o (last (gnus-agent-load-alist group))))
+              (cond ((not o)
+                     nil)
+                    ((not n)
+                     (push (cons (caar o) nil) alist))
+                    ((< (caar n) (caar o))
+                     (setcdr n (list (car o)))))))
+
+          (let ((inhibit-quit t))
+            (if (setq regenerated (buffer-modified-p))
+                (let ((coding-system-for-write gnus-agent-file-coding-system))
+                  (write-region (point-min) (point-max) file nil 'silent)))
+
+            (setq regenerated (or regenerated
+                                  (and reread gnus-agent-article-alist)
+                                  (not (equal alist gnus-agent-article-alist))))
+
+            (setq gnus-agent-article-alist alist)
+
+            (when regenerated
+              (gnus-agent-save-alist group)
+       
+              ;; I have to alter the group's active range NOW as
+              ;; gnus-make-ascending-articles-unread will use it to
+              ;; recalculate the number of unread articles in the group
+
+              (let ((group (gnus-group-real-name group))
+                    (group-active (gnus-active group)))
+                (gnus-agent-possibly-alter-active group group-active)))))
+
+        (when (and reread gnus-agent-article-alist)
+          (gnus-make-ascending-articles-unread
+           group
+           (if (listp reread)
+               reread
+             (delq nil (mapcar (function (lambda (c)
+                                           (cond ((eq reread t)
+                                                  (car c))
+                                                 ((cdr c)
+                                                  (car c)))))
+                               gnus-agent-article-alist))))
+
+          (when (gnus-buffer-live-p gnus-group-buffer)
+            (gnus-group-update-group group t)
+            (sit-for 0)))
+
+        (gnus-message 5 nil)
+        regenerated)))
 
 ;;;###autoload
 (defun gnus-agent-regenerate (&optional clean reread)
   "Regenerate all agent covered files.
-If CLEAN, don't read existing active files."
+If CLEAN, obsolete (ignore)."
   (interactive "P")
   (let (regenerated)
     (gnus-message 4 "Regenerating Gnus agent files...")
     (dolist (gnus-command-method (gnus-agent-covered-methods))
-      (let ((active-file (gnus-agent-lib-file "active"))
-            active-hashtb active-changed
-            point)
-        (gnus-make-directory (file-name-directory active-file))
-        (if clean
-            (setq active-hashtb (gnus-make-hashtable 1000))
-          (mm-with-unibyte-buffer
-           (if (file-exists-p active-file)
-               (let ((nnheader-file-coding-system
-                      gnus-agent-file-coding-system))
-                 (nnheader-insert-file-contents active-file))
-             (setq active-changed t))
-           (gnus-active-to-gnus-format
-            nil (setq active-hashtb
-                      (gnus-make-hashtable
-                       (count-lines (point-min) (point-max)))))))
         (dolist (group (gnus-groups-from-server gnus-command-method))
           (setq regenerated (or (gnus-agent-regenerate-group group reread)
-                                regenerated))
-          (let ((min (or (caar gnus-agent-article-alist) 1))
-                (max (or (caar (last gnus-agent-article-alist)) 0))
-                (active (gnus-gethash-safe (gnus-group-real-name group)
-                                           active-hashtb))
-                (read (gnus-info-read (gnus-get-info group))))
-            (if (not active)
-                (progn
-                  (setq active (cons min max)
-                        active-changed t)
-                  (gnus-sethash group active active-hashtb))
-              (when (> (car active) min)
-                (setcar active min)
-                (setq active-changed t))
-              (when (< (cdr active) max)
-                (setcdr active max)
-                (setq active-changed t)))))
-        (when active-changed
-          (setq regenerated t)
-          (gnus-message 4 "Regenerate %s" active-file)
-          (let ((nnmail-active-file-coding-system
-                 gnus-agent-file-coding-system))
-            (gnus-write-active-file active-file active-hashtb)))))
+                                regenerated))))
     (gnus-message 4 "Regenerating Gnus agent files...done")
+
     regenerated))
 
 (defun gnus-agent-go-online (&optional force)
@@ -3505,49 +3698,6 @@ If CLEAN, don't read existing active files."
 (defun gnus-agent-group-covered-p (group)
   (gnus-agent-method-p (gnus-group-method group)))
 
-(add-hook 'gnus-group-prepare-hook
-          (lambda ()
-            'gnus-agent-do-once
-
-            (when (listp gnus-agent-expire-days)
-              (beep)
-              (beep)
-              (gnus-message 1 "WARNING: gnus-agent-expire-days no longer\
- supports being set to a list.")(sleep-for 3)
-              (gnus-message 1 "Change your configuration to set it to an\
- integer.")(sleep-for 3)
-              (gnus-message 1 "I am now setting group parameters on each\
- group to match the configuration that the list offered.")
-
-              (save-excursion
-                (let ((groups (gnus-group-listed-groups)))
-                  (while groups
-                    (let* ((group (pop groups))
-                           (days gnus-agent-expire-days)
-                           (day (catch 'found
-                                  (while days
-                                    (when (eq 0 (string-match
-                                                 (caar days)
-                                                 group))
-                                      (throw 'found (cadar days)))
-                                    (setq days (cdr days)))
-                                  nil)))
-                      (when day
-                        (gnus-group-set-parameter group 'agent-days-until-old
-                                                  day))))))
-
-              (let ((h gnus-group-prepare-hook))
-                (while h
-                  (let ((func (pop h)))
-                    (when (and (listp func)
-                               (eq (cadr (caddr func)) 'gnus-agent-do-once))
-                      (remove-hook 'gnus-group-prepare-hook func)
-                      (setq h nil)))))
-
-              (gnus-message 1 "I have finished setting group parameters on\
- each group. You may now customize your groups and/or topics to control the\
- agent."))))
-
 (provide 'gnus-agent)
 
 ;;; gnus-agent.el ends here