emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] Changes to emacs/lisp/gnus/gnus-agent.el


From: Miles Bader
Subject: [Emacs-diffs] Changes to emacs/lisp/gnus/gnus-agent.el
Date: Sat, 04 Sep 2004 09:48:34 -0400

Index: emacs/lisp/gnus/gnus-agent.el
diff -c emacs/lisp/gnus/gnus-agent.el:1.8 emacs/lisp/gnus/gnus-agent.el:1.9
*** emacs/lisp/gnus/gnus-agent.el:1.8   Mon Sep  1 15:45:23 2003
--- emacs/lisp/gnus/gnus-agent.el       Sat Sep  4 13:13:43 2004
***************
*** 1,5 ****
  ;;; gnus-agent.el --- unplugged support for Gnus
! ;; Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
  
  ;; Author: Lars Magne Ingebrigtsen <address@hidden>
  ;; This file is part of GNU Emacs.
--- 1,6 ----
  ;;; gnus-agent.el --- unplugged support for Gnus
! ;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
! ;;        Free Software Foundation, Inc.
  
  ;; Author: Lars Magne Ingebrigtsen <address@hidden>
  ;; This file is part of GNU Emacs.
***************
*** 25,39 ****
--- 26,48 ----
  
  (require 'gnus)
  (require 'gnus-cache)
+ (require 'nnmail)
  (require 'nnvirtual)
  (require 'gnus-sum)
  (require 'gnus-score)
+ (require 'gnus-srvr)
+ (require 'gnus-util)
  (eval-when-compile
    (if (featurep 'xemacs)
        (require 'itimer)
      (require 'timer))
    (require 'cl))
  
+ (eval-and-compile
+   (autoload 'gnus-server-update-server "gnus-srvr")
+   (autoload 'gnus-agent-customize-category "gnus-cus")
+ )
+ 
  (defcustom gnus-agent-directory (nnheader-concat gnus-directory "agent/")
    "Where the Gnus agent will store its files."
    :group 'gnus-agent
***************
*** 49,63 ****
    :group 'gnus-agent
    :type 'hook)
  
  (defcustom gnus-agent-handle-level gnus-level-subscribed
    "Groups on levels higher than this variable will be ignored by the Agent."
    :group 'gnus-agent
    :type 'integer)
  
  (defcustom gnus-agent-expire-days 7
!   "Read articles older than this will be expired."
    :group 'gnus-agent
!   :type 'integer)
  
  (defcustom gnus-agent-expire-all nil
    "If non-nil, also expire unread, ticked and dormant articles.
--- 58,78 ----
    :group 'gnus-agent
    :type 'hook)
  
+ (defcustom gnus-agent-fetched-hook nil
+   "Hook run when finished fetching articles."
+   :group 'gnus-agent
+   :type 'hook)
+ 
  (defcustom gnus-agent-handle-level gnus-level-subscribed
    "Groups on levels higher than this variable will be ignored by the Agent."
    :group 'gnus-agent
    :type 'integer)
  
  (defcustom gnus-agent-expire-days 7
!   "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"))
  
  (defcustom gnus-agent-expire-all nil
    "If non-nil, also expire unread, ticked and dormant articles.
***************
*** 70,85 ****
--- 85,112 ----
    :group 'gnus-agent
    :type 'hook)
  
+ ;; Extracted from gnus-xmas-redefine in order to preserve user settings
+ (when (featurep 'xemacs)
+   (add-hook 'gnus-agent-group-mode-hook 'gnus-xmas-agent-group-menu-add))
+ 
  (defcustom gnus-agent-summary-mode-hook nil
    "Hook run in Agent summary minor modes."
    :group 'gnus-agent
    :type 'hook)
  
+ ;; Extracted from gnus-xmas-redefine in order to preserve user settings
+ (when (featurep 'xemacs)
+   (add-hook 'gnus-agent-summary-mode-hook 'gnus-xmas-agent-summary-menu-add))
+ 
  (defcustom gnus-agent-server-mode-hook nil
    "Hook run in Agent summary minor modes."
    :group 'gnus-agent
    :type 'hook)
  
+ ;; Extracted from gnus-xmas-redefine in order to preserve user settings
+ (when (featurep 'xemacs)
+   (add-hook 'gnus-agent-server-mode-hook 'gnus-xmas-agent-server-menu-add))
+ 
  (defcustom gnus-agent-confirmation-function 'y-or-n-p
    "Function to confirm when error happens."
    :version "21.1"
***************
*** 95,107 ****
                 (const :tag "Ask" ask))
    :group 'gnus-agent)
  
  ;;; Internal variables
  
  (defvar gnus-agent-history-buffers nil)
  (defvar gnus-agent-buffer-alist nil)
! (defvar gnus-agent-article-alist nil)
  (defvar gnus-agent-group-alist nil)
- (defvar gnus-agent-covered-methods nil)
  (defvar gnus-category-alist nil)
  (defvar gnus-agent-current-history nil)
  (defvar gnus-agent-overview-buffer nil)
--- 122,224 ----
                 (const :tag "Ask" ask))
    :group 'gnus-agent)
  
+ (defcustom gnus-agent-go-online 'ask
+   "Indicate if offline servers go online when you plug in.
+ If this is `ask' the hook will query the user."
+   :version "21.1"
+   :type '(choice (const :tag "Always" t)
+                (const :tag "Never" nil)
+                (const :tag "Ask" ask))
+   :group 'gnus-agent)
+ 
+ (defcustom gnus-agent-mark-unread-after-downloaded t
+   "Indicate whether to mark articles unread after downloaded."
+   :version "21.1"
+   :type 'boolean
+   :group 'gnus-agent)
+ 
+ (defcustom gnus-agent-download-marks '(download)
+   "Marks for downloading."
+   :version "21.1"
+   :type '(repeat (symbol :tag "Mark"))
+   :group 'gnus-agent)
+ 
+ (defcustom gnus-agent-consider-all-articles nil
+   "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)
+ 
+ (defcustom gnus-agent-max-fetch-size 10000000 ;; 10 Mb
+   "Chunk size for `gnus-agent-fetch-session'.
+ The function will split its article fetches into chunks smaller than
+ this limit."
+   :group 'gnus-agent
+   :type 'integer)
+ 
+ (defcustom gnus-agent-enable-expiration 'ENABLE
+   "The default expiration state for each group.
+ When set to ENABLE, the default, `gnus-agent-expire' will expire old
+ contents from a group's local storage.  This value may be overridden
+ to disable expiration in specific categories, topics, and groups.  Of
+ course, you could change gnus-agent-enable-expiration to DISABLE then
+ enable expiration per categories, topics, and groups."
+   :group 'gnus-agent
+   :type '(radio (const :format "Enable " ENABLE)
+                 (const :format "Disable " DISABLE)))
+ 
+ (defcustom gnus-agent-expire-unagentized-dirs t
+   "*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
  
  (defvar gnus-agent-history-buffers nil)
  (defvar gnus-agent-buffer-alist nil)
! (defvar gnus-agent-article-alist nil
!   "An assoc list identifying the articles whose headers have been fetched.  
! If successfully fetched, these headers will be stored in the group's overview
! file.  The key of each assoc pair is the article ID, the value of each assoc
! pair is a flag indicating whether the identified article has been downloaded
! \(gnus-agent-fetch-articles sets the value to the day of the download).
! NOTES:
! 1) The last element of this list can not be expired as some 
!    routines (for example, get-agent-fetch-headers) use the last
!    value to track which articles have had their headers retrieved.
! 2) The function `gnus-agent-regenerate' may destructively modify the value.")
  (defvar gnus-agent-group-alist nil)
  (defvar gnus-category-alist nil)
  (defvar gnus-agent-current-history nil)
  (defvar gnus-agent-overview-buffer nil)
***************
*** 111,116 ****
--- 228,234 ----
  (defvar gnus-agent-file-name nil)
  (defvar gnus-agent-send-mail-function nil)
  (defvar gnus-agent-file-coding-system 'raw-text)
+ (defvar gnus-agent-file-loading-cache nil)
  
  ;; Dynamic variables
  (defvar gnus-headers)
***************
*** 141,148 ****
  (gnus-add-shutdown 'gnus-close-agent 'gnus)
  
  (defun gnus-close-agent ()
!   (setq gnus-agent-covered-methods nil
!       gnus-category-predicate-cache nil
        gnus-category-group-cache nil
        gnus-agent-spam-hashtb nil)
    (gnus-kill-buffer gnus-agent-overview-buffer))
--- 259,265 ----
  (gnus-add-shutdown 'gnus-close-agent 'gnus)
  
  (defun gnus-close-agent ()
!   (setq gnus-category-predicate-cache nil
        gnus-category-group-cache nil
        gnus-agent-spam-hashtb nil)
    (gnus-kill-buffer gnus-agent-overview-buffer))
***************
*** 176,193 ****
                    (file-name-as-directory
                     (expand-file-name "agent.lib" (gnus-agent-directory)))))
  
  ;;; Fetching setup functions.
  
  (defun gnus-agent-start-fetch ()
    "Initialize data structures for efficient fetching."
-   (gnus-agent-open-history)
-   (setq gnus-agent-current-history (gnus-agent-history-buffer))
    (gnus-agent-create-buffer))
  
  (defun gnus-agent-stop-fetch ()
    "Save all data structures and clean up."
-   (gnus-agent-save-history)
-   (gnus-agent-close-history)
    (setq gnus-agent-spam-hashtb nil)
    (save-excursion
      (set-buffer nntp-server-buffer)
--- 293,412 ----
                    (file-name-as-directory
                     (expand-file-name "agent.lib" (gnus-agent-directory)))))
  
+ (defun gnus-agent-cat-set-property (category property value)
+   (if value
+       (setcdr (or (assq property category)
+               (let ((cell (cons property nil)))
+                     (setcdr category (cons cell (cdr category)))
+                     cell)) value)
+     (let ((category category))
+       (while (cond ((eq property (caadr category))
+                     (setcdr category (cddr category))
+                     nil)
+                    (t
+                     (setq category (cdr category)))))))
+   category)
+ 
+ (eval-when-compile
+   (defmacro gnus-agent-cat-defaccessor (name prop-name)
+     "Define accessor and setter methods for manipulating a list of the form
+ \(NAME (PROPERTY1 VALUE1) ... (PROPERTY_N VALUE_N)).
+ Given the call (gnus-agent-cat-defaccessor func PROPERTY1), the list may be
+ manipulated as follows:
+   (func LIST): Returns VALUE1
+   (setf (func LIST) NEW_VALUE1): Replaces VALUE1 with NEW_VALUE1."
+     `(progn (defmacro ,name (category)
+               (list (quote cdr) (list (quote assq)
+                                       (quote (quote ,prop-name)) category)))
+ 
+             (define-setf-method ,name (category)
+               (let* ((--category--temp-- (make-symbol "--category--"))
+                      (--value--temp-- (make-symbol "--value--")))
+                 (list (list --category--temp--) ; temporary-variables
+                       (list category)   ; value-forms
+                       (list --value--temp--) ; store-variables
+                       (let* ((category --category--temp--) ; store-form
+                              (value --value--temp--))
+                         (list (quote gnus-agent-cat-set-property)
+                               category
+                               (quote (quote ,prop-name))
+                               value))
+                       (list (quote ,name) --category--temp--) ; access-form
+                       )))))
+   )
+ 
+ (defmacro gnus-agent-cat-name (category)
+   `(car ,category))
+ 
+ (gnus-agent-cat-defaccessor
+  gnus-agent-cat-days-until-old             agent-days-until-old)
+ (gnus-agent-cat-defaccessor
+  gnus-agent-cat-enable-expiration          agent-enable-expiration)
+ (gnus-agent-cat-defaccessor
+  gnus-agent-cat-groups                     agent-groups)
+ (gnus-agent-cat-defaccessor
+  gnus-agent-cat-high-score                 agent-high-score)
+ (gnus-agent-cat-defaccessor
+  gnus-agent-cat-length-when-long           agent-length-when-long)
+ (gnus-agent-cat-defaccessor
+  gnus-agent-cat-length-when-short          agent-length-when-short)
+ (gnus-agent-cat-defaccessor
+  gnus-agent-cat-low-score                  agent-low-score)
+ (gnus-agent-cat-defaccessor
+  gnus-agent-cat-predicate                  agent-predicate)
+ (gnus-agent-cat-defaccessor
+  gnus-agent-cat-score-file                 agent-score-file)
+ (gnus-agent-cat-defaccessor
+  gnus-agent-cat-enable-undownloaded-faces agent-enable-undownloaded-faces)
+ 
+ (eval-and-compile
+   (defsetf gnus-agent-cat-groups (category) (groups)
+     (list 'gnus-agent-set-cat-groups category groups)))
+ 
+ (defun gnus-agent-set-cat-groups (category groups)
+   (unless (eq groups 'ignore)
+     (let ((new-g groups)
+           (old-g (gnus-agent-cat-groups category)))
+       (cond ((eq new-g old-g)
+              ;; gnus-agent-add-group is fiddling with the group
+              ;; list. Still, Im done.
+              nil
+              )
+             ((eq new-g (cdr old-g))
+              ;; gnus-agent-add-group is fiddling with the group list
+              (setcdr (or (assq 'agent-groups category)
+                          (let ((cell (cons 'agent-groups nil)))
+                            (setcdr category (cons cell (cdr category)))
+                            cell)) new-g))
+             (t
+              (let ((groups groups))
+                (while groups
+                  (let* ((group        (pop groups))
+                         (old-category (gnus-group-category group)))
+                    (if (eq category old-category)
+                        nil
+                      (setf (gnus-agent-cat-groups old-category)
+                            (delete group (gnus-agent-cat-groups
+                                           old-category))))))
+                ;; Purge cache as preceeding loop invalidated it.
+                (setq gnus-category-group-cache nil))
+ 
+              (setcdr (or (assq 'agent-groups category)
+                          (let ((cell (cons 'agent-groups nil)))
+                            (setcdr category (cons cell (cdr category)))
+                            cell)) groups))))))
+ 
+ (defsubst gnus-agent-cat-make (name &optional default-agent-predicate)
+   (list name `(agent-predicate . ,(or default-agent-predicate 'false))))
+ 
  ;;; Fetching setup functions.
  
  (defun gnus-agent-start-fetch ()
    "Initialize data structures for efficient fetching."
    (gnus-agent-create-buffer))
  
  (defun gnus-agent-stop-fetch ()
    "Save all data structures and clean up."
    (setq gnus-agent-spam-hashtb nil)
    (save-excursion
      (set-buffer nntp-server-buffer)
***************
*** 204,209 ****
--- 423,435 ----
  (put 'gnus-agent-with-fetch 'lisp-indent-function 0)
  (put 'gnus-agent-with-fetch 'edebug-form-spec '(body))
  
+ (defmacro gnus-agent-append-to-list (tail value)
+   `(setq ,tail (setcdr ,tail (cons ,value nil))))
+ 
+ (defmacro gnus-agent-message (level &rest args)
+   `(if (<= ,level gnus-verbose)
+        (message ,@args)))
+ 
  ;;;
  ;;; Mode infestation
  ;;;
***************
*** 233,239 ****
                                                     buffer))))
            minor-mode-map-alist))
      (when (eq major-mode 'gnus-group-mode)
!       (gnus-agent-toggle-plugged gnus-plugged))
      (gnus-run-hooks 'gnus-agent-mode-hook
                    (intern (format "gnus-agent-%s-mode-hook" buffer)))))
  
--- 459,471 ----
                                                     buffer))))
            minor-mode-map-alist))
      (when (eq major-mode 'gnus-group-mode)
!       (let ((init-plugged gnus-plugged)
!             (gnus-agent-go-online nil))
!         ;; g-a-t-p does nothing when gnus-plugged isn't changed.
!         ;; Therefore, make certain that the current value does not
!         ;; match the desired initial value.
!         (setq gnus-plugged :unknown)
!         (gnus-agent-toggle-plugged init-plugged)))
      (gnus-run-hooks 'gnus-agent-mode-hook
                    (intern (format "gnus-agent-%s-mode-hook" buffer)))))
  
***************
*** 244,252 ****
    "Jj" gnus-agent-toggle-plugged
    "Js" gnus-agent-fetch-session
    "JY" gnus-agent-synchronize-flags
!   "JS" gnus-group-send-drafts
    "Ja" gnus-agent-add-group
!   "Jr" gnus-agent-remove-group)
  
  (defun gnus-agent-group-make-menu-bar ()
    (unless (boundp 'gnus-agent-group-menu)
--- 476,485 ----
    "Jj" gnus-agent-toggle-plugged
    "Js" gnus-agent-fetch-session
    "JY" gnus-agent-synchronize-flags
!   "JS" gnus-group-send-queue
    "Ja" gnus-agent-add-group
!   "Jr" gnus-agent-remove-group
!   "Jo" gnus-agent-toggle-group-plugged)
  
  (defun gnus-agent-group-make-menu-bar ()
    (unless (boundp 'gnus-agent-group-menu)
***************
*** 254,268 ****
       gnus-agent-group-menu gnus-agent-group-mode-map ""
       '("Agent"
         ["Toggle plugged" gnus-agent-toggle-plugged t]
         ["List categories" gnus-enter-category-buffer t]
!        ["Send drafts" gnus-group-send-drafts gnus-plugged]
         ("Fetch"
        ["All" gnus-agent-fetch-session gnus-plugged]
!       ["Group" gnus-agent-fetch-group gnus-plugged])))))
  
  (defvar gnus-agent-summary-mode-map (make-sparse-keymap))
  (gnus-define-keys gnus-agent-summary-mode-map
    "Jj" gnus-agent-toggle-plugged
    "J#" gnus-agent-mark-article
    "J\M-#" gnus-agent-unmark-article
    "@" gnus-agent-toggle-mark
--- 487,509 ----
       gnus-agent-group-menu gnus-agent-group-mode-map ""
       '("Agent"
         ["Toggle plugged" gnus-agent-toggle-plugged t]
+        ["Toggle group plugged" gnus-agent-toggle-group-plugged t]
         ["List categories" gnus-enter-category-buffer t]
!        ["Add (current) group to category" gnus-agent-add-group t]
!        ["Remove (current) group from category" gnus-agent-remove-group t]
!        ["Send queue" gnus-group-send-queue gnus-plugged]
         ("Fetch"
        ["All" gnus-agent-fetch-session gnus-plugged]
!       ["Group" gnus-agent-fetch-group gnus-plugged])
!        ["Synchronize flags" gnus-agent-synchronize-flags t]
!        ))))
  
  (defvar gnus-agent-summary-mode-map (make-sparse-keymap))
  (gnus-define-keys gnus-agent-summary-mode-map
    "Jj" gnus-agent-toggle-plugged
+   "Ju" gnus-agent-summary-fetch-group
+   "JS" gnus-agent-fetch-group
+   "Js" gnus-agent-summary-fetch-series
    "J#" gnus-agent-mark-article
    "J\M-#" gnus-agent-unmark-article
    "@" gnus-agent-toggle-mark
***************
*** 277,282 ****
--- 518,524 ----
         ["Mark as downloadable" gnus-agent-mark-article t]
         ["Unmark as downloadable" gnus-agent-unmark-article t]
         ["Toggle mark" gnus-agent-toggle-mark t]
+        ["Fetch downloadable" gnus-agent-summary-fetch-group t]
         ["Catchup undownloaded" gnus-agent-catchup t]))))
  
  (defvar gnus-agent-server-mode-map (make-sparse-keymap))
***************
*** 294,317 ****
         ["Add" gnus-agent-add-server t]
         ["Remove" gnus-agent-remove-server t]))))
  
! (defun gnus-agent-toggle-plugged (plugged)
    "Toggle whether Gnus is unplugged or not."
    (interactive (list (not gnus-plugged)))
!   (if plugged
!       (progn
!       (setq gnus-plugged plugged)
!       (gnus-agent-possibly-synchronize-flags)
!       (gnus-run-hooks 'gnus-agent-plugged-hook)
!       (setcar (cdr gnus-agent-mode-status) " Plugged"))
!     (gnus-agent-close-connections)
!     (setq gnus-plugged plugged)
!     (gnus-run-hooks 'gnus-agent-unplugged-hook)
!     (setcar (cdr gnus-agent-mode-status) " Unplugged"))
    (set-buffer-modified-p t))
  
  (defun gnus-agent-close-connections ()
    "Close all methods covered by the Gnus agent."
!   (let ((methods gnus-agent-covered-methods))
      (while methods
        (gnus-close-server (pop methods)))))
  
--- 536,585 ----
         ["Add" gnus-agent-add-server t]
         ["Remove" gnus-agent-remove-server t]))))
  
! (defun gnus-agent-make-mode-line-string (string mouse-button mouse-func)
!   (if (and (fboundp 'propertize)
!          (fboundp 'make-mode-line-mouse-map))
!       (propertize string 'local-map
!                 (make-mode-line-mouse-map mouse-button mouse-func))
!     string))
! 
! (defun gnus-agent-toggle-plugged (set-to)
    "Toggle whether Gnus is unplugged or not."
    (interactive (list (not gnus-plugged)))
!   (cond ((eq set-to gnus-plugged)
!          nil)
!         (set-to
!          (setq gnus-plugged set-to)
!          (gnus-run-hooks 'gnus-agent-plugged-hook)
!          (setcar (cdr gnus-agent-mode-status)
!                  (gnus-agent-make-mode-line-string " Plugged"
!                                                    'mouse-2
!                                                    
'gnus-agent-toggle-plugged))
!          (gnus-agent-go-online gnus-agent-go-online)
!          (gnus-agent-possibly-synchronize-flags))
!         (t
!          (gnus-agent-close-connections)
!          (setq gnus-plugged set-to)
!          (gnus-run-hooks 'gnus-agent-unplugged-hook)
!          (setcar (cdr gnus-agent-mode-status)
!                  (gnus-agent-make-mode-line-string " Unplugged"
!                                                    'mouse-2
!                                                    
'gnus-agent-toggle-plugged))))
    (set-buffer-modified-p t))
  
+ (defmacro gnus-agent-while-plugged (&rest body)
+   `(let ((original-gnus-plugged gnus-plugged))
+     (unwind-protect
+         (progn (gnus-agent-toggle-plugged t)
+                ,@body)
+       (gnus-agent-toggle-plugged original-gnus-plugged))))
+ 
+ (put 'gnus-agent-while-plugged 'lisp-indent-function 0)
+ (put 'gnus-agent-while-plugged 'edebug-form-spec '(body))
+ 
  (defun gnus-agent-close-connections ()
    "Close all methods covered by the Gnus agent."
!   (let ((methods (gnus-agent-covered-methods)))
      (while methods
        (gnus-close-server (pop methods)))))
  
***************
*** 330,365 ****
    (gnus))
  
  ;;;###autoload
  (defun gnus-agentize ()
    "Allow Gnus to be an offline newsreader.
- The normal usage of this command is to put the following as the
- last form in your `.gnus.el' file:
- 
- \(gnus-agentize)
  
! This will modify the `gnus-before-startup-hook', `gnus-post-method',
! and `message-send-mail-function' variables, and install the Gnus
! agent minor mode in all Gnus buffers."
    (interactive)
    (gnus-open-agent)
    (add-hook 'gnus-setup-news-hook 'gnus-agent-queue-setup)
    (unless gnus-agent-send-mail-function
!     (setq gnus-agent-send-mail-function message-send-mail-function
!         message-send-mail-function 'gnus-agent-send-mail))
!   (unless gnus-agent-covered-methods
!     (setq gnus-agent-covered-methods (list gnus-select-method))))
! 
! (defun gnus-agent-queue-setup ()
!   "Make sure the queue group exists."
!   (unless (gnus-gethash "nndraft:queue" gnus-newsrc-hashtb)
!     (gnus-request-create-group "queue" '(nndraft ""))
      (let ((gnus-level-default-subscribed 1))
!       (gnus-subscribe-group "nndraft:queue" nil '(nndraft "")))
      (gnus-group-set-parameter
!      "nndraft:queue" 'gnus-dummy '((gnus-draft-mode)))))
  
  (defun gnus-agent-send-mail ()
!   (if gnus-plugged
        (funcall gnus-agent-send-mail-function)
      (goto-char (point-min))
      (re-search-forward
--- 598,661 ----
    (gnus))
  
  ;;;###autoload
+ (defun gnus-slave-unplugged (&optional arg)
+   "Read news as a slave unplugged."
+   (interactive "P")
+   (setq gnus-plugged nil)
+   (gnus arg nil 'slave))
+ 
+ ;;;###autoload
  (defun gnus-agentize ()
    "Allow Gnus to be an offline newsreader.
  
! The gnus-agentize function is now called internally by gnus when
! gnus-agent is set.  If you wish to avoid calling gnus-agentize,
! customize gnus-agent to nil.
! 
! This will modify the `gnus-setup-news-hook', and
! `message-send-mail-real-function' variables, and install the Gnus agent
! minor mode in all Gnus buffers."
    (interactive)
    (gnus-open-agent)
    (add-hook 'gnus-setup-news-hook 'gnus-agent-queue-setup)
    (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-real-function 'gnus-agent-send-mail))
! 
!   ;; 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))
!     (gnus-agent-write-servers)))
! 
! (defun gnus-agent-queue-setup (&optional group-name)
!   "Make sure the queue group exists.
! Optional arg GROUP-NAME allows to specify another group."
!   (unless (gnus-gethash (format "nndraft:%s" (or group-name "queue"))
!                       gnus-newsrc-hashtb)
!     (gnus-request-create-group (or group-name "queue") '(nndraft ""))
      (let ((gnus-level-default-subscribed 1))
!       (gnus-subscribe-group (format "nndraft:%s" (or group-name "queue"))
!                           nil '(nndraft "")))
      (gnus-group-set-parameter
!      (format "nndraft:%s" (or group-name "queue"))
!      'gnus-dummy '((gnus-draft-mode)))))
  
  (defun gnus-agent-send-mail ()
!   (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
***************
*** 370,376 ****
  
  (defun gnus-agent-insert-meta-information (type &optional method)
    "Insert meta-information into the message that says how it's to be posted.
! TYPE can be either `mail' or `news'.  If the latter METHOD can
  be a select method."
    (save-excursion
      (message-remove-header gnus-agent-meta-information-header)
--- 666,672 ----
  
  (defun gnus-agent-insert-meta-information (type &optional method)
    "Insert meta-information into the message that says how it's to be posted.
! TYPE can be either `mail' or `news'.  If the latter, then METHOD can
  be a select method."
    (save-excursion
      (message-remove-header gnus-agent-meta-information-header)
***************
*** 386,392 ****
    "Restore GCC field from saved header."
    (save-excursion
      (goto-char (point-min))
!     (while (re-search-forward (concat gnus-agent-gcc-header ":") nil t)
        (replace-match "Gcc:" 'fixedcase))))
  
  (defun gnus-agent-any-covered-gcc ()
--- 682,689 ----
    "Restore GCC field from saved header."
    (save-excursion
      (goto-char (point-min))
!     (while (re-search-forward
!           (concat "^" (regexp-quote gnus-agent-gcc-header) ":") nil t)
        (replace-match "Gcc:" 'fixedcase))))
  
  (defun gnus-agent-any-covered-gcc ()
***************
*** 400,410 ****
                                   gcc " ,")))))
           covered)
        (while (and (not covered) methods)
!       (setq covered
!             (member (car methods) gnus-agent-covered-methods)
              methods (cdr methods)))
        covered)))
  
  (defun gnus-agent-possibly-save-gcc ()
    "Save GCC if Gnus is unplugged."
    (when (and (not gnus-plugged) (gnus-agent-any-covered-gcc))
--- 697,707 ----
                                   gcc " ,")))))
           covered)
        (while (and (not covered) methods)
!       (setq covered (gnus-agent-method-p (car methods))
              methods (cdr methods)))
        covered)))
  
+ ;;;###autoload
  (defun gnus-agent-possibly-save-gcc ()
    "Save GCC if Gnus is unplugged."
    (when (and (not gnus-plugged) (gnus-agent-any-covered-gcc))
***************
*** 430,446 ****
      (error "Groups can't be fetched when Gnus is unplugged"))
    (gnus-group-iterate n 'gnus-agent-fetch-group))
  
! (defun gnus-agent-fetch-group (group)
    "Put all new articles in GROUP into the Agent."
    (interactive (list (gnus-group-group-name)))
!   (unless gnus-plugged
!     (error "Groups can't be fetched when Gnus is unplugged"))
    (unless group
      (error "No group on the current line"))
!   (let ((gnus-command-method (gnus-find-method-for-group group)))
!     (gnus-agent-with-fetch
!       (gnus-agent-fetch-group-1 group gnus-command-method)
!       (gnus-message 5 "Fetching %s...done" group))))
  
  (defun gnus-agent-add-group (category arg)
    "Add the current group to an agent category."
--- 727,744 ----
      (error "Groups can't be fetched when Gnus is unplugged"))
    (gnus-group-iterate n 'gnus-agent-fetch-group))
  
! (defun gnus-agent-fetch-group (&optional group)
    "Put all new articles in GROUP into the Agent."
    (interactive (list (gnus-group-group-name)))
!   (setq group (or group gnus-newsgroup-name))
    (unless group
      (error "No group on the current line"))
! 
!   (gnus-agent-while-plugged
!     (let ((gnus-command-method (gnus-find-method-for-group group)))
!       (gnus-agent-with-fetch
!         (gnus-agent-fetch-group-1 group gnus-command-method)
!         (gnus-message 5 "Fetching %s...done" group)))))
  
  (defun gnus-agent-add-group (category arg)
    "Add the current group to an agent category."
***************
*** 457,466 ****
        c groups)
      (gnus-group-iterate arg
        (lambda (group)
!       (when (cadddr (setq c (gnus-group-category group)))
!         (setf (cadddr c) (delete group (cadddr c))))
        (push group groups)))
!     (setf (cadddr cat) (nconc (cadddr cat) groups))
      (gnus-category-write)))
  
  (defun gnus-agent-remove-group (arg)
--- 755,766 ----
        c groups)
      (gnus-group-iterate arg
        (lambda (group)
!       (when (gnus-agent-cat-groups (setq c (gnus-group-category group)))
!         (setf (gnus-agent-cat-groups c)
!                 (delete group (gnus-agent-cat-groups c))))
        (push group groups)))
!     (setf (gnus-agent-cat-groups cat)
!           (nconc (gnus-agent-cat-groups cat) groups))
      (gnus-category-write)))
  
  (defun gnus-agent-remove-group (arg)
***************
*** 469,483 ****
    (let (c)
      (gnus-group-iterate arg
        (lambda (group)
!       (when (cadddr (setq c (gnus-group-category group)))
!         (setf (cadddr c) (delete group (cadddr c))))))
      (gnus-category-write)))
  
  (defun gnus-agent-synchronize-flags ()
    "Synchronize unplugged flags with servers."
    (interactive)
    (save-excursion
!     (dolist (gnus-command-method gnus-agent-covered-methods)
        (when (file-exists-p (gnus-agent-lib-file "flags"))
        (gnus-agent-synchronize-flags-server gnus-command-method)))))
  
--- 769,784 ----
    (let (c)
      (gnus-group-iterate arg
        (lambda (group)
!       (when (gnus-agent-cat-groups (setq c (gnus-group-category group)))
!         (setf (gnus-agent-cat-groups c)
!                 (delete group (gnus-agent-cat-groups c))))))
      (gnus-category-write)))
  
  (defun gnus-agent-synchronize-flags ()
    "Synchronize unplugged flags with servers."
    (interactive)
    (save-excursion
!     (dolist (gnus-command-method (gnus-agent-covered-methods))
        (when (file-exists-p (gnus-agent-lib-file "flags"))
        (gnus-agent-synchronize-flags-server gnus-command-method)))))
  
***************
*** 485,491 ****
    "Synchronize flags according to `gnus-agent-synchronize-flags'."
    (interactive)
    (save-excursion
!     (dolist (gnus-command-method gnus-agent-covered-methods)
        (when (file-exists-p (gnus-agent-lib-file "flags"))
        (gnus-agent-possibly-synchronize-flags-server gnus-command-method)))))
  
--- 786,792 ----
    "Synchronize flags according to `gnus-agent-synchronize-flags'."
    (interactive)
    (save-excursion
!     (dolist (gnus-command-method (gnus-agent-covered-methods))
        (when (file-exists-p (gnus-agent-lib-file "flags"))
        (gnus-agent-possibly-synchronize-flags-server gnus-command-method)))))
  
***************
*** 497,507 ****
        (erase-buffer)
        (nnheader-insert-file-contents (gnus-agent-lib-file "flags"))
        (if (null (gnus-check-server gnus-command-method))
!         (message "Couldn't open server %s" (nth 1 gnus-command-method))
        (while (not (eobp))
          (if (null (eval (read (current-buffer))))
!             (progn (forward-line)
!                    (kill-line -1))
            (write-file (gnus-agent-lib-file "flags"))
            (error "Couldn't set flags from file %s"
                   (gnus-agent-lib-file "flags"))))
--- 798,807 ----
        (erase-buffer)
        (nnheader-insert-file-contents (gnus-agent-lib-file "flags"))
        (if (null (gnus-check-server gnus-command-method))
!         (gnus-message 1 "Couldn't open server %s" (nth 1 gnus-command-method))
        (while (not (eobp))
          (if (null (eval (read (current-buffer))))
!             (gnus-delete-line)
            (write-file (gnus-agent-lib-file "flags"))
            (error "Couldn't set flags from file %s"
                   (gnus-agent-lib-file "flags"))))
***************
*** 521,556 ****
  ;;; Server mode commands
  ;;;
  
! (defun gnus-agent-add-server (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))))
!     (when (member method gnus-agent-covered-methods)
        (error "Server already in the agent program"))
!     (push method gnus-agent-covered-methods)
      (gnus-agent-write-servers)
!     (message "Entered %s into the Agent" server)))
  
! (defun gnus-agent-remove-server (server)
    "Remove SERVER from 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))))
!     (unless (member method gnus-agent-covered-methods)
        (error "Server not in the agent program"))
!     (setq gnus-agent-covered-methods
!         (delete method gnus-agent-covered-methods))
      (gnus-agent-write-servers)
!     (message "Removed %s from the agent" server)))
  
  (defun gnus-agent-read-servers ()
    "Read the alist of covered servers."
    (setq gnus-agent-covered-methods
!       (gnus-agent-read-file
!        (nnheader-concat gnus-agent-directory "lib/servers"))))
  
  (defun gnus-agent-write-servers ()
    "Write the alist of covered servers."
--- 821,900 ----
  ;;; Server mode commands
  ;;;
  
! (defun gnus-agent-add-server ()
    "Enroll SERVER in the agent program."
!   (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 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 ()
    "Remove SERVER from the agent program."
!   (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 named-server gnus-agent-covered-methods)
!           gnus-agent-method-p-cache nil)
! 
!     (gnus-server-update-server server)
      (gnus-agent-write-servers)
!     (gnus-message 1 "Removed %s from the agent" server)))
  
  (defun gnus-agent-read-servers ()
    "Read the alist of covered servers."
+   (setq gnus-agent-covered-methods 
+         (gnus-agent-read-file
+          (nnheader-concat gnus-agent-directory "lib/servers"))
+         gnus-agent-method-p-cache nil)
+ 
+   ;; I am called so early in start-up that I can not validate server
+   ;; names.  When that is the case, I skip the validation.  That is
+   ;; alright as the gnus startup code calls the validate methods
+   ;; directly.
+   (if gnus-server-alist
+       (gnus-agent-read-servers-validate)))
+ 
+ (defun gnus-agent-read-servers-validate ()
+   (mapcar (lambda (server-or-method)
+             (let* ((server (if (stringp server-or-method)
+                                server-or-method
+                              (gnus-method-to-server server-or-method)))
+                    (method (gnus-server-to-method server)))
+               (if method
+                   (unless (member server gnus-agent-covered-methods)
+                     (push server gnus-agent-covered-methods)
+                     (setq gnus-agent-method-p-cache nil))
+                 (gnus-message 1 "Ignoring disappeared server `%s'" server))))
+           (prog1 gnus-agent-covered-methods
+             (setq gnus-agent-covered-methods nil))))
+ 
+ (defun gnus-agent-read-servers-validate-native (native-method)
    (setq gnus-agent-covered-methods
!         (mapcar (lambda (method)
!                   (if (or (not method)
!                           (equal method native-method))
!                       "native"
!                     method)) gnus-agent-covered-methods)))
  
  (defun gnus-agent-write-servers ()
    "Write the alist of covered servers."
***************
*** 558,564 ****
    (let ((coding-system-for-write nnheader-file-coding-system)
        (file-name-coding-system nnmail-pathname-coding-system))
      (with-temp-file (nnheader-concat gnus-agent-directory "lib/servers")
!       (prin1 gnus-agent-covered-methods (current-buffer)))))
  
  ;;;
  ;;; Summary commands
--- 902,909 ----
    (let ((coding-system-for-write nnheader-file-coding-system)
        (file-name-coding-system nnmail-pathname-coding-system))
      (with-temp-file (nnheader-concat gnus-agent-directory "lib/servers")
!       (prin1 gnus-agent-covered-methods
!            (current-buffer)))))
  
  ;;;
  ;;; Summary commands
***************
*** 600,754 ****
    (gnus-agent-mark-article n 'toggle))
  
  (defun gnus-summary-set-agent-mark (article &optional unmark)
!   "Mark ARTICLE as downloadable."
!   (let ((unmark (if (and (not (null unmark)) (not (eq t unmark)))
!                   (memq article gnus-newsgroup-downloadable)
!                 unmark)))
!     (if unmark
!       (progn
!         (setq gnus-newsgroup-downloadable
!               (delq article gnus-newsgroup-downloadable))
!         (push article gnus-newsgroup-undownloaded))
!       (setq gnus-newsgroup-undownloaded
!           (delq article gnus-newsgroup-undownloaded))
!       (push article gnus-newsgroup-downloadable))
!     (gnus-summary-update-mark
!      (if unmark gnus-undownloaded-mark gnus-downloadable-mark)
!      'unread)))
  
  (defun gnus-agent-get-undownloaded-list ()
!   "Mark all unfetched articles as read."
    (let ((gnus-command-method (gnus-find-method-for-group 
gnus-newsgroup-name)))
!     (when (and (not gnus-plugged)
!              (gnus-agent-method-p gnus-command-method))
!       (gnus-agent-load-alist gnus-newsgroup-name)
!       ;; First mark all undownloaded articles as undownloaded.
!       (let ((articles (append gnus-newsgroup-unreads
!                             gnus-newsgroup-marked
!                             gnus-newsgroup-dormant))
!           article)
!       (while (setq article (pop articles))
!         (unless (or (cdr (assq article gnus-agent-article-alist))
!                     (memq article gnus-newsgroup-downloadable)
!                     (memq article gnus-newsgroup-cached))
!           (push article gnus-newsgroup-undownloaded))))
!       ;; Then mark downloaded downloadable as not-downloadable,
!       ;; if you get my drift.
!       (let ((articles gnus-newsgroup-downloadable)
!           article)
!       (while (setq article (pop articles))
!         (when (cdr (assq article gnus-agent-article-alist))
!           (setq gnus-newsgroup-downloadable
!                 (delq article gnus-newsgroup-downloadable))))))))
  
  (defun gnus-agent-catchup ()
!   "Mark all undownloaded articles as read."
    (interactive)
    (save-excursion
!     (while gnus-newsgroup-undownloaded
!       (gnus-summary-mark-article
!        (pop gnus-newsgroup-undownloaded) gnus-catchup-mark)))
!   (gnus-summary-position-point))
  
  ;;;
  ;;; Internal functions
  ;;;
  
  (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-agent-write-active file new)
        (erase-buffer)
        (nnheader-insert-file-contents file))))
  
  (defun gnus-agent-write-active (file new)
-   (let ((orig (gnus-make-hashtable (count-lines (point-min) (point-max))))
-       (file (gnus-agent-lib-file "active"))
-       elem osym)
-     (when (file-exists-p file)
-       (with-temp-buffer
-       (nnheader-insert-file-contents file)
-       (gnus-active-to-gnus-format nil orig))
-       (mapatoms
-        (lambda (sym)
-        (when (and sym (boundp sym))
-          (if (and (boundp (setq osym (intern (symbol-name sym) orig)))
-                   (setq elem (symbol-value osym)))
-              (setcdr elem (cdr (symbol-value sym)))
-            (set (intern (symbol-name sym) orig) (symbol-value sym)))))
-        new))
      (gnus-make-directory (file-name-directory file))
!     (let ((coding-system-for-write gnus-agent-file-coding-system))
!       ;; The hashtable contains real names of groups,  no more prefix
!       ;; removing, so set `full' to `t'.
!       (gnus-write-active-file file orig t))))
! 
! (defun gnus-agent-save-groups (method)
!   (gnus-agent-save-active-1 method 'gnus-groups-to-gnus-format))
  
  (defun gnus-agent-save-group-info (method group active)
    (when (gnus-agent-method-p method)
      (let* ((gnus-command-method method)
           (coding-system-for-write nnheader-file-coding-system)
           (file-name-coding-system nnmail-pathname-coding-system)
           (file (gnus-agent-lib-file "active"))
!          oactive)
        (gnus-make-directory (file-name-directory file))
        (with-temp-file file
        ;; Emacs got problem to match non-ASCII group in multibyte buffer.
        (mm-disable-multibyte)
        (when (file-exists-p file)
!         (nnheader-insert-file-contents file))
!       (goto-char (point-min))
!       (when (re-search-forward
!              (concat "^" (regexp-quote group) " ") nil t)
!         (save-excursion
!           (save-restriction
!             (narrow-to-region (match-beginning 0)
!                               (progn
!                                 (forward-line 1)
!                                 (point)))
!             (setq oactive (car (nnmail-parse-active)))))
!         (gnus-delete-line))
        (insert (format "%S %d %d y\n" (intern group)
!                       (cdr active)
!                       (or (car oactive) (car active))))
        (goto-char (point-max))
        (while (search-backward "\\." nil t)
          (delete-char 1))))))
  
  (defun gnus-agent-group-path (group)
    "Translate GROUP into a file name."
!   (if nnmail-use-long-file-names
!       (gnus-group-real-name group)
!     (nnheader-translate-file-chars
!      (nnheader-replace-chars-in-string
!       (nnheader-replace-duplicate-chars-in-string
!        (nnheader-replace-chars-in-string
!       (gnus-group-real-name group)
!       ?/ ?_)
!        ?. ?_)
!       ?. ?/))))
! 
! 
! 
! (defun gnus-agent-method-p (method)
!   "Say whether METHOD is covered by the agent."
!   (member method gnus-agent-covered-methods))
  
  (defun gnus-agent-get-function (method)
!   (if (and (not gnus-plugged)
!          (gnus-agent-method-p method))
!       (progn
!       (require 'nnagent)
!       'nnagent)
!     (car method)))
  
  ;;; History functions
  
--- 945,1250 ----
    (gnus-agent-mark-article n 'toggle))
  
  (defun gnus-summary-set-agent-mark (article &optional unmark)
!   "Mark ARTICLE as downloadable.  If UNMARK is nil, article is marked.
! When UNMARK is t, the article is unmarked.  For any other value, the
! article's mark is toggled."
!   (let ((unmark (cond ((eq nil unmark)
!                      nil)
!                     ((eq t unmark)
!                      t)
!                     (t
!                      (memq article gnus-newsgroup-downloadable)))))
!     (when (gnus-summary-goto-subject article nil t)
!       (gnus-summary-update-mark
!        (if unmark
!            (progn
!              (setq gnus-newsgroup-downloadable
!                    (delq article gnus-newsgroup-downloadable))
!              (gnus-article-mark article))
!        (setq gnus-newsgroup-downloadable
!              (gnus-add-to-sorted-list gnus-newsgroup-downloadable article))
!        gnus-downloadable-mark)
!        'unread))))
  
  (defun gnus-agent-get-undownloaded-list ()
!   "Construct list of articles that have not been downloaded."
    (let ((gnus-command-method (gnus-find-method-for-group 
gnus-newsgroup-name)))
!     (when (set (make-local-variable 'gnus-newsgroup-agentized)
!                (gnus-agent-method-p gnus-command-method))
!       (let* ((alist (gnus-agent-load-alist gnus-newsgroup-name))
!              (headers (sort (mapcar (lambda (h)
!                                       (mail-header-number h))
!                                     gnus-newsgroup-headers) '<))
!              (cached (and gnus-use-cache gnus-newsgroup-cached))
!              (undownloaded (list nil))
!              (tail-undownloaded undownloaded)
!              (unfetched (list nil))
!              (tail-unfetched unfetched))
!       (while (and alist headers)
!         (let ((a (caar alist))
!               (h (car headers)))
!           (cond ((< a h)
!                  ;; Ignore IDs in the alist that are not being
!                  ;; displayed in the summary.
!                  (setq alist (cdr alist)))
!                 ((> a h)
!                    ;; Headers that are not in the alist should be
!                    ;; fictious (see nnagent-retrieve-headers); they
!                    ;; imply that this article isn't in the agent.
!                  (gnus-agent-append-to-list tail-undownloaded h)
!                  (gnus-agent-append-to-list tail-unfetched    h)
!                    (setq headers (cdr headers))) 
!                 ((cdar alist)
!                  (setq alist (cdr alist))
!                  (setq headers (cdr headers))
!                  nil                  ; ignore already downloaded
!                  )
!                 (t
!                  (setq alist (cdr alist))
!                  (setq headers (cdr headers))
!                    
!                    ;; This article isn't in the agent.  Check to see
!                    ;; if it is in the cache.  If it is, it's been
!                    ;; downloaded.
!                    (while (and cached (< (car cached) a))
!                      (setq cached (cdr cached)))
!                    (unless (equal a (car cached))
!                      (gnus-agent-append-to-list tail-undownloaded a))))))
! 
!       (while headers
!           (let ((num (pop headers)))
!             (gnus-agent-append-to-list tail-undownloaded num)
!             (gnus-agent-append-to-list tail-unfetched    num)))
! 
!       (setq gnus-newsgroup-undownloaded (cdr undownloaded)
!               gnus-newsgroup-unfetched    (cdr unfetched))))))
  
  (defun gnus-agent-catchup ()
!   "Mark as read all unhandled articles.
! An article is unhandled if it is neither cached, nor downloaded, nor
! downloadable."
    (interactive)
    (save-excursion
!     (let ((articles gnus-newsgroup-undownloaded))
!       (when (or gnus-newsgroup-downloadable
!                 gnus-newsgroup-cached)
!         (setq articles (gnus-sorted-ndifference
!                       (gnus-sorted-ndifference
!                        (gnus-copy-sequence articles)
!                        gnus-newsgroup-downloadable)
!                       gnus-newsgroup-cached)))
! 
!       (while articles
!         (gnus-summary-mark-article
!          (pop articles) gnus-catchup-mark)))
!     (gnus-summary-position-point)))
! 
! (defun gnus-agent-summary-fetch-series ()
!   (interactive)
!   (when gnus-newsgroup-processable
!     (setq gnus-newsgroup-downloadable
!           (let* ((dl gnus-newsgroup-downloadable)
!                  (gnus-newsgroup-downloadable
!                 (sort (gnus-copy-sequence gnus-newsgroup-processable) '<))
!                  (fetched-articles (gnus-agent-summary-fetch-group)))
!             ;; The preceeding call to (gnus-agent-summary-fetch-group)
!             ;; updated gnus-newsgroup-downloadable to remove each
!             ;; article successfully fetched.
! 
!             ;; For each article that I processed, remove its
!             ;; processable mark IF the article is no longer
!             ;; downloadable (i.e. it's already downloaded)
!             (dolist (article gnus-newsgroup-processable)
!               (unless (memq article gnus-newsgroup-downloadable)
!                 (gnus-summary-remove-process-mark article)))
!             (gnus-sorted-ndifference dl fetched-articles)))))
! 
! (defun gnus-agent-summary-fetch-group (&optional all)
!   "Fetch the downloadable articles in the group.
! Optional arg ALL, if non-nil, means to fetch all articles."
!   (interactive "P")
!   (let ((articles
!        (if all gnus-newsgroup-articles
!          gnus-newsgroup-downloadable))
!       (gnus-command-method (gnus-find-method-for-group gnus-newsgroup-name))
!         fetched-articles)
!     (gnus-agent-while-plugged
!       (unless articles
!         (error "No articles to download"))
!       (gnus-agent-with-fetch
!         (setq gnus-newsgroup-undownloaded
!               (gnus-sorted-ndifference
!                gnus-newsgroup-undownloaded
!                (setq fetched-articles
!                      (gnus-agent-fetch-articles
!                       gnus-newsgroup-name articles)))))
!       (save-excursion
!         (dolist (article articles)
!           (let ((was-marked-downloadable 
!                  (memq article gnus-newsgroup-downloadable)))
!             (cond (gnus-agent-mark-unread-after-downloaded
!                    (setq gnus-newsgroup-downloadable
!                          (delq article gnus-newsgroup-downloadable))
! 
!                    (gnus-summary-mark-article article gnus-unread-mark))
!                   (was-marked-downloadable
!                    (gnus-summary-set-agent-mark article t)))
!             (when (gnus-summary-goto-subject article nil t)
!               (gnus-summary-update-download-mark article))))))
!     fetched-articles))
! 
! (defun gnus-agent-fetch-selected-article ()
!   "Fetch the current article as it is selected.
! This can be added to `gnus-select-article-hook' or
! `gnus-mark-article-hook'."
!   (let ((gnus-command-method gnus-current-select-method))
!     (when (and gnus-plugged (gnus-agent-method-p gnus-command-method))
!       (when (gnus-agent-fetch-articles
!              gnus-newsgroup-name
!            (list gnus-current-article))
!       (setq gnus-newsgroup-undownloaded
!             (delq gnus-current-article gnus-newsgroup-undownloaded))
!         (gnus-summary-update-download-mark gnus-current-article)))))
  
  ;;;
  ;;; Internal functions
  ;;;
  
  (defun gnus-agent-save-active (method)
    (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")))
!       (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)
      (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 new nil)))
! 
! (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)
           (file-name-coding-system nnmail-pathname-coding-system)
           (file (gnus-agent-lib-file "active"))
!          oactive-min oactive-max)
        (gnus-make-directory (file-name-directory file))
        (with-temp-file file
        ;; Emacs got problem to match non-ASCII group in multibyte buffer.
        (mm-disable-multibyte)
        (when (file-exists-p file)
!         (nnheader-insert-file-contents file)
! 
!           (goto-char (point-min))
!           (when (re-search-forward
!                  (concat "^" (regexp-quote group) " ") nil t)
!             (save-excursion
!               (setq oactive-max (read (current-buffer)) ;; max
!                     oactive-min (read (current-buffer)))) ;; min
!             (gnus-delete-line)))
        (insert (format "%S %d %d y\n" (intern group)
!                       (max (or oactive-max (cdr active)) (cdr active))
!                         (min (or oactive-min (car active)) (car active))))
        (goto-char (point-max))
        (while (search-backward "\\." nil t)
          (delete-char 1))))))
  
  (defun gnus-agent-group-path (group)
    "Translate GROUP into a file name."
! 
!   ;; NOTE: This is what nnmail-group-pathname does as of Apr 2003.
!   ;; The two methods must be kept synchronized, which is why
!   ;; gnus-agent-group-pathname was added.
! 
!   (setq group
!         (nnheader-translate-file-chars
!          (nnheader-replace-duplicate-chars-in-string
!           (nnheader-replace-chars-in-string 
!            (gnus-group-real-name group)
!            ?/ ?_)
!           ?. ?_)))
!   (if (or nnmail-use-long-file-names
!           (file-directory-p (expand-file-name group (gnus-agent-directory))))
!       group
!     (mm-encode-coding-string
!      (nnheader-replace-chars-in-string group ?. ?/)
!      nnmail-pathname-coding-system)))
! 
! (defun gnus-agent-group-pathname (group)
!   "Translate GROUP into a file name."
!   ;; nnagent uses nnmail-group-pathname to read articles while
!   ;; unplugged.  The agent must, therefore, use the same directory
!   ;; while plugged.
!   (let ((gnus-command-method (or gnus-command-method
!                                  (gnus-find-method-for-group group))))
!     (nnmail-group-pathname (gnus-group-real-name group) 
(gnus-agent-directory))))
  
  (defun gnus-agent-get-function (method)
!   (if (gnus-online method)
!       (car method)
!     (require 'nnagent)
!     'nnagent))
! 
! (defun gnus-agent-covered-methods ()
!   "Return the subset of methods that are covered by the agent."
!   (delq nil (mapcar #'gnus-server-to-method gnus-agent-covered-methods)))
  
  ;;; History functions
  
***************
*** 770,783 ****
        (nnheader-insert-file-contents file))
        (set (make-local-variable 'gnus-agent-file-name) file))))
  
- (defun gnus-agent-save-history ()
-   (save-excursion
-     (set-buffer gnus-agent-current-history)
-     (gnus-make-directory (file-name-directory gnus-agent-file-name))
-     (let ((coding-system-for-write gnus-agent-file-coding-system))
-       (write-region (1+ (point-min)) (point-max)
-                   gnus-agent-file-name nil 'silent))))
- 
  (defun gnus-agent-close-history ()
    (when (gnus-buffer-live-p gnus-agent-current-history)
      (kill-buffer gnus-agent-current-history)
--- 1266,1271 ----
***************
*** 785,821 ****
          (delq (assoc (gnus-agent-method) gnus-agent-history-buffers)
                gnus-agent-history-buffers))))
  
- (defun gnus-agent-enter-history (id group-arts date)
-   (save-excursion
-     (set-buffer gnus-agent-current-history)
-     (goto-char (point-max))
-     (let ((p (point)))
-       (insert id "\t" (number-to-string date) "\t")
-       (while group-arts
-       (insert (format "%S" (intern (caar group-arts)))
-               " " (number-to-string (cdr (pop group-arts)))
-               " "))
-       (insert "\n")
-       (while (search-backward "\\." p t)
-       (delete-char 1)))))
- 
- (defun gnus-agent-article-in-history-p (id)
-   (save-excursion
-     (set-buffer (gnus-agent-history-buffer))
-     (goto-char (point-min))
-     (search-forward (concat "\n" id "\t") nil t)))
- 
- (defun gnus-agent-history-path (id)
-   (save-excursion
-     (set-buffer (gnus-agent-history-buffer))
-     (goto-char (point-min))
-     (when (search-forward (concat "\n" id "\t") nil t)
-       (let ((method (gnus-agent-method)))
-       (let (paths group)
-         (while (not (numberp (setq group (read (current-buffer)))))
-           (push (concat method "/" group) paths))
-         (nreverse paths))))))
- 
  ;;;
  ;;; Fetching
  ;;;
--- 1273,1278 ----
***************
*** 823,899 ****
  (defun gnus-agent-fetch-articles (group articles)
    "Fetch ARTICLES from GROUP and put them into the Agent."
    (when articles
!     ;; Prune off articles that we have already fetched.
!     (while (and articles
!               (cdr (assq (car articles) gnus-agent-article-alist)))
!       (pop articles))
!     (let ((arts articles))
!       (while (cdr arts)
!       (if (cdr (assq (cadr arts) gnus-agent-article-alist))
!           (setcdr arts (cddr arts))
!         (setq arts (cdr arts)))))
!     (when articles
!       (let ((dir (concat
!                 (gnus-agent-directory)
!                 (gnus-agent-group-path group) "/"))
!           (date (time-to-days (current-time)))
!           (case-fold-search t)
!           pos crosses id elem)
!       (gnus-make-directory dir)
!       (gnus-message 7 "Fetching articles for %s..." group)
!       ;; Fetch the articles from the backend.
!       (if (gnus-check-backend-function 'retrieve-articles group)
!           (setq pos (gnus-retrieve-articles articles group))
!         (with-temp-buffer
!           (let (article)
!             (while (setq article (pop articles))
!               (when (or
!                      (gnus-backlog-request-article group article
!                                                    nntp-server-buffer)
!                      (gnus-request-article article group))
!                 (goto-char (point-max))
!                 (push (cons article (point)) pos)
!                 (insert-buffer-substring nntp-server-buffer)))
!             (copy-to-buffer nntp-server-buffer (point-min) (point-max))
!             (setq pos (nreverse pos)))))
!       ;; Then save these articles into the Agent.
!       (save-excursion
!         (set-buffer nntp-server-buffer)
!         (while pos
!           (narrow-to-region (cdar pos) (or (cdadr pos) (point-max)))
!           (goto-char (point-min))
!           (when (search-forward "\n\n" nil t)
!             (when (search-backward "\nXrefs: " nil t)
!               ;; Handle crossposting.
!               (skip-chars-forward "^ ")
!               (skip-chars-forward " ")
!               (setq crosses nil)
!               (while (looking-at "\\([^: \n]+\\):\\([0-9]+\\) +")
!                 (push (cons (buffer-substring (match-beginning 1)
!                                               (match-end 1))
!                             (buffer-substring (match-beginning 2)
!                                               (match-end 2)))
!                       crosses)
!                 (goto-char (match-end 0)))
!               (gnus-agent-crosspost crosses (caar pos))))
!           (goto-char (point-min))
!           (if (not (re-search-forward "^Message-ID: *<\\([^>\n]+\\)>" nil t))
!               (setq id "No-Message-ID-in-article")
!             (setq id (buffer-substring (match-beginning 1) (match-end 1))))
!           (let ((coding-system-for-write
!                  gnus-agent-file-coding-system))
!             (write-region (point-min) (point-max)
!                           (concat dir (number-to-string (caar pos)))
!                           nil 'silent))
!           (when (setq elem (assq (caar pos) gnus-agent-article-alist))
!             (setcdr elem t))
!           (gnus-agent-enter-history
!            id (or crosses (list (cons group (caar pos)))) date)
!           (widen)
!           (pop pos)))
!       (gnus-agent-save-alist group)))))
  
- (defun gnus-agent-crosspost (crosses article)
    (let (gnus-agent-article-alist group alist beg end)
      (save-excursion
        (set-buffer gnus-agent-overview-buffer)
--- 1280,1418 ----
  (defun gnus-agent-fetch-articles (group articles)
    "Fetch ARTICLES from GROUP and put them into the Agent."
    (when articles
!     (gnus-agent-load-alist group)
!     (let* ((alist   gnus-agent-article-alist)
!            (headers (if (< (length articles) 2) nil gnus-newsgroup-headers))
!            (selected-sets (list nil))
!            (current-set-size 0)
!            article
!            header-number)
!       ;; Check each article
!       (while (setq article (pop articles))
!         ;; Skip alist entries preceeding this article
!         (while (> article (or (caar alist) (1+ article)))
!           (setq alist (cdr alist)))
! 
!         ;; Prune off articles that we have already fetched.
!         (unless (and (eq article (caar alist))
!                      (cdar alist))
!           ;; Skip headers preceeding this article
!           (while (> article 
!                     (setq header-number
!                           (let* ((header (car headers)))
!                             (if header
!                                 (mail-header-number header)
!                               (1+ article)))))
!             (setq headers (cdr headers)))
! 
!           ;; Add this article to the current set
!           (setcar selected-sets (cons article (car selected-sets)))
! 
!           ;; Update the set size, when the set is too large start a
!           ;; new one.  I do this after adding the article as I want at
!           ;; least one article in each set.
!           (when (< gnus-agent-max-fetch-size
!                    (setq current-set-size
!                        (+ current-set-size
!                           (if (= header-number article)
!                                 (let ((char-size (mail-header-chars
!                                                   (car headers))))
!                                   (if (<= char-size 0)
!                                       ;; The char size was missing/invalid,
!                                       ;; assume a worst-case situation of
!                                       ;; 65 char/line.  If the line count
!                                       ;; is missing, arbitrarily assume a
!                                       ;; size of 1000 characters.
!                                     (max (* 65 (mail-header-lines
!                                                 (car headers)))
!                                          1000)
!                                     char-size))
!                             0))))
!             (setcar selected-sets (nreverse (car selected-sets)))
!             (setq selected-sets (cons nil selected-sets)
!                   current-set-size 0))))
! 
!       (when (or (cdr selected-sets) (car selected-sets))
!         (let* ((fetched-articles (list nil))
!                (tail-fetched-articles fetched-articles)
!                (dir (gnus-agent-group-pathname group))
!                (date (time-to-days (current-time)))
!                (case-fold-search t)
!                pos crosses id)
! 
!           (setcar selected-sets (nreverse (car selected-sets)))
!           (setq selected-sets (nreverse selected-sets))
! 
!           (gnus-make-directory dir)
!           (gnus-message 7 "Fetching articles for %s..." group)
! 
!           (unwind-protect
!               (while (setq articles (pop selected-sets))
!                 ;; Fetch the articles from the backend.
!                 (if (gnus-check-backend-function 'retrieve-articles group)
!                     (setq pos (gnus-retrieve-articles articles group))
!                   (with-temp-buffer
!                     (let (article)
!                       (while (setq article (pop articles))
!                         (gnus-message 10 "Fetching article %s for %s..."
!                                       article group)
!                         (when (or
!                                (gnus-backlog-request-article group article
!                                                              
nntp-server-buffer)
!                                (gnus-request-article article group))
!                           (goto-char (point-max))
!                           (push (cons article (point)) pos)
!                           (insert-buffer-substring nntp-server-buffer)))
!                       (copy-to-buffer
!                      nntp-server-buffer (point-min) (point-max))
!                       (setq pos (nreverse pos)))))
!                 ;; Then save these articles into the Agent.
!                 (save-excursion
!                   (set-buffer nntp-server-buffer)
!                   (while pos
!                     (narrow-to-region (cdar pos) (or (cdadr pos) (point-max)))
!                     (goto-char (point-min))
!                     (unless (eobp) ;; Don't save empty articles.
!                       (when (search-forward "\n\n" nil t)
!                         (when (search-backward "\nXrefs: " nil t)
!                           ;; Handle cross posting.
!                           (goto-char (match-end 0)) ; move to end of header 
name
!                           (skip-chars-forward "^ ") ; skip server name
!                           (skip-chars-forward " ")
!                           (setq crosses nil)
!                           (while (looking-at "\\([^: \n]+\\):\\([0-9]+\\) *")
!                             (push (cons (buffer-substring (match-beginning 1)
!                                                           (match-end 1))
!                                         (string-to-int
!                                        (buffer-substring (match-beginning 2)
!                                                          (match-end 2))))
!                                   crosses)
!                             (goto-char (match-end 0)))
!                           (gnus-agent-crosspost crosses (caar pos) date)))
!                       (goto-char (point-min))
!                       (if (not (re-search-forward
!                                 "^Message-ID: *<\\([^>\n]+\\)>" nil t))
!                           (setq id "No-Message-ID-in-article")
!                         (setq id (buffer-substring
!                                 (match-beginning 1) (match-end 1))))
!                       (let ((coding-system-for-write
!                              gnus-agent-file-coding-system))
!                         (write-region (point-min) (point-max)
!                                       (concat dir (number-to-string (caar 
pos)))
!                                       nil 'silent))
! 
!                       (gnus-agent-append-to-list
!                      tail-fetched-articles (caar pos)))
!                     (widen)
!                     (setq pos (cdr pos)))))
! 
!             (gnus-agent-save-alist group (cdr fetched-articles) date)
!             (gnus-message 7 ""))
!           (cdr fetched-articles))))))
! 
! (defun gnus-agent-crosspost (crosses article &optional date)
!   (setq date (or date t))
  
    (let (gnus-agent-article-alist group alist beg end)
      (save-excursion
        (set-buffer gnus-agent-overview-buffer)
***************
*** 906,912 ****
        (unless (setq alist (assoc group gnus-agent-group-alist))
        (push (setq alist (list group (gnus-agent-load-alist (caar crosses))))
              gnus-agent-group-alist))
!       (setcdr alist (cons (cons (cdar crosses) t) (cdr alist)))
        (save-excursion
        (set-buffer (gnus-get-buffer-create (format " *Gnus agent overview %s*"
                                                    group)))
--- 1425,1431 ----
        (unless (setq alist (assoc group gnus-agent-group-alist))
        (push (setq alist (list group (gnus-agent-load-alist (caar crosses))))
              gnus-agent-group-alist))
!       (setcdr alist (cons (cons (cdar crosses) date) (cdr alist)))
        (save-excursion
        (set-buffer (gnus-get-buffer-create (format " *Gnus agent overview %s*"
                                                    group)))
***************
*** 917,924 ****
             (gnus-agent-article-name ".overview" group))))
        (nnheader-find-nov-line (string-to-number (cdar crosses)))
        (insert (string-to-number (cdar crosses)))
!       (insert-buffer-substring gnus-agent-overview-buffer beg end))
!       (pop crosses))))
  
  (defun gnus-agent-flush-cache ()
    (save-excursion
--- 1436,1500 ----
             (gnus-agent-article-name ".overview" group))))
        (nnheader-find-nov-line (string-to-number (cdar crosses)))
        (insert (string-to-number (cdar crosses)))
!       (insert-buffer-substring gnus-agent-overview-buffer beg end)
!         (gnus-agent-check-overview-buffer))
!       (setq crosses (cdr crosses)))))
! 
! (defun gnus-agent-backup-overview-buffer ()
!   (when gnus-newsgroup-name
!     (let ((root (gnus-agent-article-name ".overview" gnus-newsgroup-name))
!           (cnt 0)
!           name)
!       (while (file-exists-p
!             (setq name (concat root "~"
!                                (int-to-string (setq cnt (1+ cnt))) "~"))))
!       (write-region (point-min) (point-max) name nil 'no-msg)
!       (gnus-message 1 "Created backup copy of overview in %s." name)))
!   t)
! 
! (defun gnus-agent-check-overview-buffer (&optional buffer)
!   "Check the overview file given for sanity.
! In particular, checks that the file is sorted by article number
! and that there are no duplicates."
!   (let ((prev-num -1)
!         (backed-up nil))
!     (save-excursion
!       (when buffer
!       (set-buffer buffer))
!       (save-restriction
!       (widen)
!       (goto-char (point-min))
! 
!       (while (< (point) (point-max))
!         (let ((p (point))
!               (cur (condition-case nil
!                        (read (current-buffer))
!                      (error nil))))
!           (cond
!            ((or (not (integerp cur))
!                 (not (eq (char-after) ?\t)))
!               (or backed-up
!                   (setq backed-up (gnus-agent-backup-overview-buffer)))
!             (gnus-message 1
!                           "Overview buffer contains garbage '%s'."
!                           (buffer-substring
!                            p (gnus-point-at-eol))))
!            ((= cur prev-num)
!             (or backed-up
!                   (setq backed-up (gnus-agent-backup-overview-buffer)))
!               (gnus-message 1
!                           "Duplicate overview line for %d" cur)
!             (delete-region (point) (progn (forward-line 1) (point))))
!            ((< cur prev-num)
!             (or backed-up
!                   (setq backed-up (gnus-agent-backup-overview-buffer)))
!               (gnus-message 1 "Overview buffer not sorted!")
!             (sort-numeric-fields 1 (point-min) (point-max))
!             (goto-char (point-min))
!             (setq prev-num -1))
!            (t
!             (setq prev-num cur)))
!           (forward-line 1)))))))
  
  (defun gnus-agent-flush-cache ()
    (save-excursion
***************
*** 930,1072 ****
                      (gnus-agent-article-name ".overview"
                                               (caar gnus-agent-buffer-alist))
                      nil 'silent))
!       (pop gnus-agent-buffer-alist))
      (while gnus-agent-group-alist
!       (with-temp-file (caar gnus-agent-group-alist)
        (princ (cdar gnus-agent-group-alist))
        (insert "\n"))
!       (pop gnus-agent-group-alist))))
  
! (if (fboundp 'union)
!     (defalias 'gnus-agent-union 'union)
!   (defun gnus-agent-union (l1 l2)
!     "Set union of lists L1 and L2."
!     (cond ((null l1) l2)
!         ((null l2) l1)
!         ((equal l1 l2) l1)
!         (t
!          (or (>= (length l1) (length l2))
!              (setq l1 (prog1 l2 (setq l2 l1))))
!          (while l2
!            (or (memq (car l2) l1)
!                (push (car l2) l1))
!            (pop l2))
!          l1))))
  
  (defun gnus-agent-fetch-headers (group &optional force)
!   (let ((articles (gnus-list-of-unread-articles group))
!       (gnus-decode-encoded-word-function 'identity)
!       (file (gnus-agent-article-name ".overview" group)))
!     ;; Add article with marks to list of article headers we want to fetch.
!     (dolist (arts (gnus-info-marks (gnus-get-info group)))
!       (setq articles (gnus-agent-union (gnus-uncompress-sequence (cdr arts))
!                           articles)))
!     (setq articles (sort articles '<))
!     ;; Remove known articles.
!     (when (gnus-agent-load-alist group)
!       (setq articles (gnus-sorted-intersection
!                     articles
!                     (gnus-uncompress-range
!                      (cons (1+ (caar (last gnus-agent-article-alist)))
!                            (cdr (gnus-active group)))))))
!     ;; Fetch them.
!     (gnus-make-directory (nnheader-translate-file-chars
!                         (file-name-directory file) t))
!     (when articles
!       (gnus-message 7 "Fetching headers for %s..." group)
        (save-excursion
!       (set-buffer nntp-server-buffer)
!       (unless (eq 'nov (gnus-retrieve-headers articles group))
!         (nnvirtual-convert-headers))
!       ;; Save these headers for later processing.
!       (copy-to-buffer gnus-agent-overview-buffer (point-min) (point-max))
!       (when (file-exists-p file)
!         (gnus-agent-braid-nov group articles file))
!       (let ((coding-system-for-write
!              gnus-agent-file-coding-system))
!         (write-region (point-min) (point-max) file nil 'silent))
!       (gnus-agent-save-alist group articles nil)
!       (gnus-agent-enter-history
!        "last-header-fetched-for-session"
!        (list (cons group (nth (- (length  articles) 1) articles)))
!        (time-to-days (current-time)))
!       articles))))
  
  (defsubst gnus-agent-copy-nov-line (article)
!   (let (b e)
      (set-buffer gnus-agent-overview-buffer)
!     (setq b (point))
!     (if (eq article (read (current-buffer)))
!       (setq e (progn (forward-line 1) (point)))
!       (progn
!       (beginning-of-line)
!       (setq e b)))
!     (set-buffer nntp-server-buffer)
!     (insert-buffer-substring gnus-agent-overview-buffer b e)))
  
  (defun gnus-agent-braid-nov (group articles file)
!   (set-buffer gnus-agent-overview-buffer)
!   (goto-char (point-min))
!   (set-buffer nntp-server-buffer)
!   (erase-buffer)
!   (nnheader-insert-file-contents file)
!   (goto-char (point-max))
!   (if (or (= (point-min) (point-max))
!         (progn
!           (forward-line -1)
!           (< (read (current-buffer)) (car articles))))
!       ;; We have only headers that are after the older headers,
!       ;; so we just append them.
!       (progn
!       (goto-char (point-max))
!       (insert-buffer-substring gnus-agent-overview-buffer))
!     ;; We do it the hard way.
!     (nnheader-find-nov-line (car articles))
!     (gnus-agent-copy-nov-line (car articles))
!     (pop articles)
!     (while (and articles
!               (not (eobp)))
!       (while (and (not (eobp))
!                 (< (read (current-buffer)) (car articles)))
!       (forward-line 1))
!       (beginning-of-line)
!       (unless (eobp)
!       (gnus-agent-copy-nov-line (car articles))
!       (setq articles (cdr articles))))
      (when articles
!       (let (b e)
        (set-buffer gnus-agent-overview-buffer)
!       (setq b (point)
!             e (point-max))
!       (set-buffer nntp-server-buffer)
!       (insert-buffer-substring gnus-agent-overview-buffer b e)))))
  
! (defun gnus-agent-load-alist (group &optional dir)
    "Load the article-state alist for GROUP."
!   (setq gnus-agent-article-alist
!       (gnus-agent-read-file
!        (if dir
!            (expand-file-name ".agentview" dir)
!          (gnus-agent-article-name ".agentview" group)))))
  
! (defun gnus-agent-save-alist (group &optional articles state dir)
    "Save the article-state alist for GROUP."
!   (let ((file-name-coding-system nnmail-pathname-coding-system))
!       (with-temp-file (if dir
!                         (expand-file-name ".agentview" dir)
!                       (gnus-agent-article-name ".agentview" group))
!       (princ (setq gnus-agent-article-alist
!                    (nconc gnus-agent-article-alist
!                           (mapcar (lambda (article) (cons article state))
!                                   articles)))
!              (current-buffer))
!       (insert "\n"))))
  
  (defun gnus-agent-article-name (article group)
!   (expand-file-name (if (stringp article) article (string-to-number article))
                    (file-name-as-directory
!                    (expand-file-name (gnus-agent-group-path group)
!                                      (gnus-agent-directory)))))
  
  (defun gnus-agent-batch-confirmation (msg)
    "Show error message and return t."
--- 1506,1971 ----
                      (gnus-agent-article-name ".overview"
                                               (caar gnus-agent-buffer-alist))
                      nil 'silent))
!       (setq gnus-agent-buffer-alist (cdr gnus-agent-buffer-alist)))
      (while gnus-agent-group-alist
!       (with-temp-file (gnus-agent-article-name
!                      ".agentview" (caar gnus-agent-group-alist))
        (princ (cdar gnus-agent-group-alist))
+       (insert "\n")
+         (princ 1 (current-buffer))
        (insert "\n"))
!       (setq gnus-agent-group-alist (cdr gnus-agent-group-alist)))))
  
! (defun gnus-agent-find-parameter (group symbol)
!   "Search for GROUPs SYMBOL in the group's parameters, the group's
! topic parameters, the group's category, or the customizable
! variables.  Returns the first non-nil value found."
!   (or (gnus-group-find-parameter group symbol t)
!       (gnus-group-parameter-value (cdr (gnus-group-category group)) symbol t)
!       (symbol-value
!        (cdr
!         (assq symbol
!               '((agent-short-article . gnus-agent-short-article)
!                 (agent-long-article . gnus-agent-long-article)
!                 (agent-low-score . gnus-agent-low-score)
!                 (agent-high-score . gnus-agent-high-score)
!                 (agent-days-until-old . gnus-agent-expire-days)
!                 (agent-enable-expiration
!                  . gnus-agent-enable-expiration)
!                 (agent-predicate . gnus-agent-predicate)))))))
  
  (defun gnus-agent-fetch-headers (group &optional force)
!   "Fetch interesting headers into the agent.  The group's overview
! file will be updated to include the headers while a list of available
! article numbers will be returned."
!   (let* ((fetch-all (and gnus-agent-consider-all-articles
!                          ;; Do not fetch all headers if the predicate
!                          ;; implies that we only consider unread articles.
!                          (not (gnus-predicate-implies-unread
!                                (gnus-agent-find-parameter group
!                                                           
'agent-predicate)))))
!          (articles (if fetch-all
!                        (gnus-uncompress-range (gnus-active group))
!                      (gnus-list-of-unread-articles group)))
!          (gnus-decode-encoded-word-function 'identity)
!          (file (gnus-agent-article-name ".overview" group)))
! 
!     (unless fetch-all
!       ;; Add articles with marks to the list of article headers we want to
!       ;; fetch.  Don't fetch articles solely on the basis of a recent or seen
!       ;; mark, but do fetch recent or seen articles if they have other, more
!       ;; interesting marks.  (We have to fetch articles with boring marks
!       ;; because otherwise the agent will remove their marks.)
!       (dolist (arts (gnus-info-marks (gnus-get-info group)))
!         (unless (memq (car arts) '(seen recent killed cache))
!           (setq articles (gnus-range-add articles (cdr arts)))))
!       (setq articles (sort (gnus-uncompress-sequence articles) '<)))
! 
!     ;; At this point, I have the list of articles to consider for
!     ;; fetching.  This is the list that I'll return to my caller. Some
!     ;; of these articles may have already been fetched.  That's OK as
!     ;; the fetch article code will filter those out.  Internally, I'll
!     ;; filter this list to just those articles whose headers need to
!     ;; be fetched.
!     (let ((articles articles))
!       ;; Remove known articles.
!       (when (and (or gnus-agent-cache
!                      (not gnus-plugged))
!                  (gnus-agent-load-alist group))
!         ;; Remove articles marked as downloaded.
!         (if fetch-all
!             ;; I want to fetch all headers in the active range.
!             ;; Therefore, exclude only those headers that are in the
!             ;; article alist.
!             ;; NOTE: This is probably NOT what I want to do after
!             ;; agent expiration in this group.
!             (setq articles (gnus-agent-uncached-articles articles group))
! 
!           ;; I want to only fetch those headers that have never been
!           ;; fetched.  Therefore, exclude all headers that are, or
!           ;; WERE, in the article alist.
!           (let ((low (1+ (caar (last gnus-agent-article-alist))))
!                 (high (cdr (gnus-active group))))
!             ;; Low can be greater than High when the same group is
!             ;; fetched twice in the same session {The first fetch will
!             ;; fill the article alist such that (last
!             ;; gnus-agent-article-alist) equals (cdr (gnus-active
!             ;; group))}.  The addition of one(the 1+ above) then
!             ;; forces Low to be greater than High.  When this happens,
!             ;; gnus-list-range-intersection returns nil which
!             ;; indicates that no headers need to be fetched. -- Kevin
!             (setq articles (gnus-list-range-intersection
!                             articles (list (cons low high)))))))
! 
!       (gnus-message
!        10 "gnus-agent-fetch-headers: undownloaded articles are '%s'"
!        (gnus-compress-sequence articles t))
! 
        (save-excursion
!         (set-buffer nntp-server-buffer)
! 
!         (if articles
!             (progn
!               (gnus-message 7 "Fetching headers for %s..." group)
! 
!               ;; Fetch them.
!               (gnus-make-directory (nnheader-translate-file-chars
!                                     (file-name-directory file) t))
! 
!               (unless (eq 'nov (gnus-retrieve-headers articles group))
!                 (nnvirtual-convert-headers))
!               (gnus-agent-check-overview-buffer)
!               ;; Move these headers to the overview buffer so that
!               ;; gnus-agent-braid-nov can merge them with the contents
!               ;; of FILE.
!               (copy-to-buffer
!              gnus-agent-overview-buffer (point-min) (point-max))
!               (when (file-exists-p file)
!                 (gnus-agent-braid-nov group articles file))
!               (let ((coding-system-for-write
!                      gnus-agent-file-coding-system))
!                 (gnus-agent-check-overview-buffer)
!                 (write-region (point-min) (point-max) file nil 'silent))
!               (gnus-agent-save-alist group articles nil)
!               articles)
!           (ignore-errors
!             (erase-buffer)
!             (nnheader-insert-file-contents file)))))
!     articles))
  
  (defsubst gnus-agent-copy-nov-line (article)
!   (let (art b e)
      (set-buffer gnus-agent-overview-buffer)
!     (while (and (not (eobp))
!               (< (setq art (read (current-buffer))) article))
!       (forward-line 1))
!     (beginning-of-line)
!     (if (or (eobp)
!           (not (eq article art)))
!       (set-buffer nntp-server-buffer)
!       (setq b (point))
!       (setq e (progn (forward-line 1) (point)))
!       (set-buffer nntp-server-buffer)
!       (insert-buffer-substring gnus-agent-overview-buffer b e))))
  
  (defun gnus-agent-braid-nov (group articles file)
!   "Merge agent overview data with given file.
! Takes headers for ARTICLES from `gnus-agent-overview-buffer' and the given
! FILE and places the combined headers into `nntp-server-buffer'."
!   (let (start last)
!     (set-buffer gnus-agent-overview-buffer)
!     (goto-char (point-min))
!     (set-buffer nntp-server-buffer)
!     (erase-buffer)
!     (nnheader-insert-file-contents file)
!     (goto-char (point-max))
!     (forward-line -1)
!     (unless (looking-at "[0-9]+\t")
!       ;; Remove corrupted lines
!       (gnus-message
!        1 "Overview %s is corrupted. Removing corrupted lines..." file)
!       (goto-char (point-min))
!       (while (not (eobp))
!       (if (looking-at "[0-9]+\t")
!           (forward-line 1)
!         (delete-region (point) (progn (forward-line 1) (point)))))
!       (forward-line -1))
!     (unless (or (= (point-min) (point-max))
!               (< (setq last (read (current-buffer))) (car articles)))
!       ;; We do it the hard way.
!       (when (nnheader-find-nov-line (car articles))
!         ;; Replacing existing NOV entry
!         (delete-region (point) (progn (forward-line 1) (point))))
!       (gnus-agent-copy-nov-line (pop articles))
! 
!       (ignore-errors
!         (while articles
!           (while (let ((art (read (current-buffer))))
!                    (cond ((< art (car articles))
!                           (forward-line 1)
!                           t)
!                          ((= art (car articles))
!                           (beginning-of-line)
!                           (delete-region
!                          (point) (progn (forward-line 1) (point)))
!                           nil)
!                          (t
!                           (beginning-of-line)
!                           nil))))
! 
!         (gnus-agent-copy-nov-line (pop articles)))))
! 
!     ;; Copy the rest lines
!     (set-buffer nntp-server-buffer)
!     (goto-char (point-max))
      (when articles
!       (when last
        (set-buffer gnus-agent-overview-buffer)
!       (ignore-errors
!           (while (<= (read (current-buffer)) last)
!             (forward-line 1)))
!       (beginning-of-line)
!       (setq start (point))
!       (set-buffer nntp-server-buffer))
!       (insert-buffer-substring gnus-agent-overview-buffer start))))
  
! ;; Keeps the compiler from warning about the free variable in
! ;; gnus-agent-read-agentview.
! (eval-when-compile
!   (defvar gnus-agent-read-agentview))
! 
! (defun gnus-agent-load-alist (group)
    "Load the article-state alist for GROUP."
!   ;; Bind free variable that's used in `gnus-agent-read-agentview'.
!   (let ((gnus-agent-read-agentview group))
!     (setq gnus-agent-article-alist
!           (gnus-cache-file-contents
!            (gnus-agent-article-name ".agentview" group)
!            'gnus-agent-file-loading-cache
!            'gnus-agent-read-agentview))))
! 
! ;; Save format may be either 1 or 2.  Two is the new, compressed
! ;; format that is still being tested.  Format 1 is uncompressed but
! ;; known to be reliable.
! (defconst gnus-agent-article-alist-save-format 2)
! 
! (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 'car-less-than-car)))))
!           (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)
    "Save the article-state alist for GROUP."
!   (let* ((file-name-coding-system nnmail-pathname-coding-system)
!        (prev (cons nil gnus-agent-article-alist))
!        (all prev)
!        print-level print-length item article)
!     (while (setq article (pop articles))
!       (while (and (cdr prev)
!                   (< (caadr prev) article))
!       (setq prev (cdr prev)))
!       (cond
!        ((not (cdr prev))
!       (setcdr prev (list (cons article state))))
!        ((> (caadr prev) article)
!       (setcdr prev (cons (cons article state) (cdr prev))))
!        ((= (caadr prev) article)
!       (setcdr (cadr prev) state)))
!       (setq prev (cdr prev)))
!     (setq gnus-agent-article-alist (cdr all))
! 
!     (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)
!              (let ((compressed nil))
!                (mapcar (lambda (pair)
!                          (let* ((article-id (car pair))
!                                 (day-of-download (cdr pair))
!                                 (comp-list (assq day-of-download compressed)))
!                            (if comp-list
!                                (setcdr comp-list
!                                      (cons article-id (cdr comp-list)))
!                              (setq compressed
!                                  (cons (list day-of-download article-id)
!                                        compressed)))
!                            nil)) gnus-agent-article-alist)
!                (mapcar (lambda (comp-list)
!                        (setcdr comp-list
!                                (gnus-compress-sequence
!                                 (nreverse (cdr comp-list)))))
!                      compressed)
!                (princ compressed (current-buffer)))))
!       (insert "\n")
!       (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
!                      (gnus-agent-group-pathname group))))
  
  (defun gnus-agent-batch-confirmation (msg)
    "Show error message and return t."
***************
*** 1089,1194 ****
      (error "No servers are covered by the Gnus agent"))
    (unless gnus-plugged
      (error "Can't fetch articles while Gnus is unplugged"))
!   (let ((methods gnus-agent-covered-methods)
        groups group gnus-command-method)
      (save-excursion
        (while methods
!       (condition-case err
!           (progn
!             (setq gnus-command-method (car methods))
!             (when (or (gnus-server-opened gnus-command-method)
!                       (gnus-open-server gnus-command-method))
!               (setq groups (gnus-groups-from-server (car methods)))
!               (gnus-agent-with-fetch
!                 (while (setq group (pop groups))
!                   (when (<= (gnus-group-level group) gnus-agent-handle-level)
!                     (gnus-agent-fetch-group-1 group gnus-command-method))))))
!         (error
!          (unless (funcall gnus-agent-confirmation-function
!                           (format "Error (%s).  Continue? " err))
!            (error "Cannot fetch articles into the Gnus agent")))
!         (quit
!          (unless (funcall gnus-agent-confirmation-function
!                           (format "Quit (%s).  Continue? " err))
!            (signal 'quit "Cannot fetch articles into the Gnus agent."))))
!       (pop methods))
        (gnus-message 6 "Finished fetching articles into the Gnus agent"))))
  
  (defun gnus-agent-fetch-group-1 (group method)
    "Fetch GROUP."
    (let ((gnus-command-method method)
        (gnus-newsgroup-name group)
!       gnus-newsgroup-dependencies gnus-newsgroup-headers
!       gnus-newsgroup-scored gnus-headers gnus-score
!       gnus-use-cache articles arts
!       category predicate info marks score-param
        (gnus-summary-expunge-below gnus-summary-expunge-below)
        (gnus-summary-mark-below gnus-summary-mark-below)
        (gnus-orphan-score gnus-orphan-score)
        ;; Maybe some other gnus-summary local variables should also
        ;; be put here.
        )
      (unless (gnus-check-group group)
        (error "Can't open server for %s" group))
      ;; Fetch headers.
!     (when (and (or (gnus-active group) (gnus-activate-group group))
!              (setq articles (gnus-agent-fetch-headers group))
!              (let ((nntp-server-buffer gnus-agent-overview-buffer))
!                ;; Parse them and see which articles we want to fetch.
!                (setq gnus-newsgroup-dependencies
!                      (make-vector (length articles) 0))
!                (setq gnus-newsgroup-headers
!                      (gnus-get-newsgroup-headers-xover articles nil nil
!                                                        group))
!                ;; `gnus-agent-overview-buffer' may be killed for
!                ;; timeout reason.  If so, recreate it.
!                (gnus-agent-create-buffer)))
!       (setq category (gnus-group-category group))
!       (setq predicate
!           (gnus-get-predicate
!            (or (gnus-group-find-parameter group 'agent-predicate t)
!                (cadr category))))
!       (if (memq (caaddr predicate) '(gnus-agent-true gnus-agent-false))
!         ;; Simple implementation
!         (setq arts
!               (and (eq (caaddr predicate) 'gnus-agent-true) articles))
!       (setq arts nil)
!       (setq score-param
!             (or (gnus-group-get-parameter group 'agent-score t)
!                 (caddr category)))
!       ;; Translate score-param into real one
!       (cond
!        ((not score-param))
!        ((eq score-param 'file)
!         (setq score-param (gnus-all-score-files group)))
!        ((stringp (car score-param)))
!        (t
!         (setq score-param (list (list score-param)))))
!       (when score-param
!         (gnus-score-headers score-param))
!       (while (setq gnus-headers (pop gnus-newsgroup-headers))
!         (setq gnus-score
!               (or (cdr (assq (mail-header-number gnus-headers)
!                              gnus-newsgroup-scored))
!                   gnus-summary-default-score))
!         (when (funcall predicate)
!           (push (mail-header-number gnus-headers)
!                 arts))))
!       ;; Fetch the articles.
!       (when arts
!       (gnus-agent-fetch-articles group arts)))
!     ;; Perhaps we have some additional articles to fetch.
!     (setq arts (assq 'download (gnus-info-marks
!                               (setq info (gnus-get-info group)))))
!     (when (cdr arts)
!       (gnus-agent-fetch-articles
!        group (gnus-uncompress-range (cdr arts)))
!       (setq marks (delq arts (gnus-info-marks info)))
!       (gnus-info-set-marks info marks)
!       (gnus-dribble-enter
!        (concat "(gnus-group-set-info '"
!              (gnus-prin1-to-string info)
!              ")")))))
  
  ;;;
  ;;; Agent Category Mode
--- 1988,2213 ----
      (error "No servers are covered by the Gnus agent"))
    (unless gnus-plugged
      (error "Can't fetch articles while Gnus is unplugged"))
!   (let ((methods (gnus-agent-covered-methods))
        groups group gnus-command-method)
      (save-excursion
        (while methods
!       (setq gnus-command-method (car methods))
!       (when (and (or (gnus-server-opened gnus-command-method)
!                      (gnus-open-server gnus-command-method))
!                  (gnus-online gnus-command-method))
!         (setq groups (gnus-groups-from-server (car methods)))
!         (gnus-agent-with-fetch
!           (while (setq group (pop groups))
!             (when (<= (gnus-group-level group)
!                       gnus-agent-handle-level)
!               (if (or debug-on-error debug-on-quit)
!                   (gnus-agent-fetch-group-1
!                    group gnus-command-method)
!                 (condition-case err
!                     (gnus-agent-fetch-group-1
!                      group gnus-command-method)
!                   (error
!                    (unless (funcall gnus-agent-confirmation-function
!                                     (format "Error %s.  Continue? "
!                                             (error-message-string err)))
!                      (error "Cannot fetch articles into the Gnus agent")))
!                   (quit
!                    (unless (funcall gnus-agent-confirmation-function
!                                     (format
!                                      "Quit fetching session %s.  Continue? "
!                                      (error-message-string err)))
!                      (signal 'quit
!                              "Cannot fetch articles into the Gnus 
agent")))))))))
!       (setq methods (cdr methods)))
!       (gnus-run-hooks 'gnus-agent-fetched-hook)
        (gnus-message 6 "Finished fetching articles into the Gnus agent"))))
  
  (defun gnus-agent-fetch-group-1 (group method)
    "Fetch GROUP."
    (let ((gnus-command-method method)
        (gnus-newsgroup-name group)
!       (gnus-newsgroup-dependencies gnus-newsgroup-dependencies)
!         (gnus-newsgroup-headers gnus-newsgroup-headers)
!       (gnus-newsgroup-scored gnus-newsgroup-scored)
!       (gnus-use-cache gnus-use-cache)
        (gnus-summary-expunge-below gnus-summary-expunge-below)
        (gnus-summary-mark-below gnus-summary-mark-below)
        (gnus-orphan-score gnus-orphan-score)
        ;; Maybe some other gnus-summary local variables should also
        ;; be put here.
+ 
+         gnus-headers
+         gnus-score
+         articles arts
+       category predicate info marks score-param
        )
      (unless (gnus-check-group group)
        (error "Can't open server for %s" group))
+ 
      ;; Fetch headers.
!     (when (or gnus-newsgroup-active
!               (gnus-active group)
!               (gnus-activate-group group))
!       (let ((marked-articles gnus-newsgroup-downloadable))
!         ;; Identify the articles marked for download
!         (unless gnus-newsgroup-active
!         ;; The variable gnus-newsgroup-active was selected as I need
!         ;; a gnus-summary local variable that is NOT bound to any
!         ;; value (its global value should default to nil).
!           (dolist (mark gnus-agent-download-marks)
!             (let ((arts (cdr (assq mark (gnus-info-marks
!                                          (setq info (gnus-get-info 
group)))))))
!               (when arts
!                 (setq marked-articles (nconc (gnus-uncompress-range arts)
!                                              marked-articles))
!                 ))))
!         (setq marked-articles (sort marked-articles '<))
! 
!         ;; Fetch any new articles from the server
!         (setq articles (gnus-agent-fetch-headers group))
! 
!         ;; Merge new articles with marked
!         (setq articles (sort (append marked-articles articles) '<))
! 
!         (when articles
!           ;; Parse them and see which articles we want to fetch.
!           (setq gnus-newsgroup-dependencies
!                 (or gnus-newsgroup-dependencies
!                     (make-vector (length articles) 0)))
!           (setq gnus-newsgroup-headers
!                 (or gnus-newsgroup-headers
!                     (gnus-get-newsgroup-headers-xover articles nil nil
!                                                       group)))
!           ;; `gnus-agent-overview-buffer' may be killed for
!           ;; timeout reason.  If so, recreate it.
!           (gnus-agent-create-buffer)
! 
!           ;; Figure out how to select articles in this group
!           (setq category (gnus-group-category group))
! 
!           (setq predicate
!                 (gnus-get-predicate
!                  (gnus-agent-find-parameter group 'agent-predicate)))
! 
!           ;; If the selection predicate requires scoring, score each header
!           (unless (memq predicate '(gnus-agent-true gnus-agent-false))
!             (let ((score-param
!                    (gnus-agent-find-parameter group 'agent-score-file)))
!               ;; Translate score-param into real one
!               (cond
!                ((not score-param))
!                ((eq score-param 'file)
!                 (setq score-param (gnus-all-score-files group)))
!                ((stringp (car score-param)))
!                (t
!                 (setq score-param (list (list score-param)))))
!               (when score-param
!                 (gnus-score-headers score-param))))
! 
!           (unless (and (eq predicate 'gnus-agent-false)
!                        (not marked-articles))
!             (let ((arts (list nil)))
!               (let ((arts-tail arts)
!                     (alist (gnus-agent-load-alist group))
!                     (marked-articles marked-articles)
!                     (gnus-newsgroup-headers gnus-newsgroup-headers))
!                 (while (setq gnus-headers (pop gnus-newsgroup-headers))
!                   (let ((num (mail-header-number gnus-headers)))
!                     ;; Determine if this article is already in the cache
!                     (while (and alist
!                                 (> num (caar alist)))
!                       (setq alist (cdr alist)))
! 
!                     (unless (and (eq num (caar alist))
!                                  (cdar alist))
! 
!                       ;; Determine if this article was marked for download.
!                       (while (and marked-articles
!                                   (> num (car marked-articles)))
!                         (setq marked-articles
!                               (cdr marked-articles)))
! 
!                       ;; When this article is marked, or selected by the
!                       ;; predicate, add it to the download list
!                       (when (or (eq num (car marked-articles))
!                                 (let ((gnus-score
!                                        (or (cdr
!                                           (assq num gnus-newsgroup-scored))
!                                            gnus-summary-default-score))
!                                       (gnus-agent-long-article
!                                        (gnus-agent-find-parameter
!                                         group 'agent-long-article))
!                                       (gnus-agent-short-article
!                                        (gnus-agent-find-parameter
!                                         group 'agent-short-article))
!                                       (gnus-agent-low-score
!                                        (gnus-agent-find-parameter
!                                         group 'agent-low-score))
!                                       (gnus-agent-high-score
!                                        (gnus-agent-find-parameter
!                                         group 'agent-high-score))
!                                       (gnus-agent-expire-days
!                                        (gnus-agent-find-parameter
!                                         group 'agent-days-until-old)))
!                                   (funcall predicate)))
!                         (gnus-agent-append-to-list arts-tail num))))))
! 
!               (let (fetched-articles)
!                 ;; Fetch all selected articles
!                 (setq gnus-newsgroup-undownloaded
!                       (gnus-sorted-ndifference
!                      gnus-newsgroup-undownloaded
!                      (setq fetched-articles
!                            (if (cdr arts)
!                                (gnus-agent-fetch-articles group (cdr arts))
!                              nil))))
! 
!                 (let ((unfetched-articles
!                      (gnus-sorted-ndifference (cdr arts) fetched-articles)))
!                   (if gnus-newsgroup-active
!                       ;; Update the summary buffer
!                       (progn
!                         (dolist (article marked-articles)
!                           (gnus-summary-set-agent-mark article t))
!                         (dolist (article fetched-articles)
!                           (if gnus-agent-mark-unread-after-downloaded
!                               (gnus-summary-mark-article
!                              article gnus-unread-mark))
!                           (when (gnus-summary-goto-subject article nil t)
!                             (gnus-summary-update-download-mark article)))
!                         (dolist (article unfetched-articles)
!                           (gnus-summary-mark-article
!                          article gnus-canceled-mark)))
! 
!                     ;; Update the group buffer.
! 
!                     ;; When some, or all, of the marked articles came
!                     ;; from the download mark.  Remove that mark.  I
!                     ;; didn't do this earlier as I only want to remove
!                     ;; the marks after the fetch is completed.
! 
!                     (dolist (mark gnus-agent-download-marks)
!                       (when (eq mark 'download)
!                         (let ((marked-arts
!                              (assq mark (gnus-info-marks
!                                          (setq info (gnus-get-info group))))))
!                           (when (cdr marked-arts)
!                             (setq marks
!                                 (delq marked-arts (gnus-info-marks info)))
!                             (gnus-info-set-marks info marks)))))
!                     (let ((read (gnus-info-read
!                                (or info (setq info (gnus-get-info group))))))
!                       (gnus-info-set-read
!                      info (gnus-add-to-range read unfetched-articles)))
! 
!                     (gnus-group-update-group group t)
!                     (sit-for 0)
! 
!                     (gnus-dribble-enter
!                      (concat "(gnus-group-set-info '"
!                              (gnus-prin1-to-string info)
!                              ")"))))))))))))
  
  ;;;
  ;;; Agent Category Mode
***************
*** 1198,1208 ****
    "Hook run in `gnus-category-mode' buffers.")
  
  (defvar gnus-category-line-format "     %(%20c%): %g\n"
!   "Format of category lines.")
  
  (defvar gnus-category-mode-line-format "Gnus: %%b"
    "The format specification for the category mode line.")
  
  (defvar gnus-agent-short-article 100
    "Articles that have fewer lines than this are short.")
  
--- 2217,2237 ----
    "Hook run in `gnus-category-mode' buffers.")
  
  (defvar gnus-category-line-format "     %(%20c%): %g\n"
!   "Format of category lines.
! 
! Valid specifiers include:
! %c  Topic name (string)
! %g  The number of groups in the topic (integer)
! 
! General format specifiers can also be used.  See Info node
! `(gnus)Formatting Variables'.")
  
  (defvar gnus-category-mode-line-format "Gnus: %%b"
    "The format specification for the category mode line.")
  
+ (defvar gnus-agent-predicate 'false
+   "The selection predicate used when no other source is available.")
+ 
  (defvar gnus-agent-short-article 100
    "Articles that have fewer lines than this are short.")
  
***************
*** 1242,1247 ****
--- 2271,2277 ----
      "k" gnus-category-kill
      "c" gnus-category-copy
      "a" gnus-category-add
+     "e" gnus-agent-customize-category
      "p" gnus-category-edit-predicate
      "g" gnus-category-edit-groups
      "s" gnus-category-edit-score
***************
*** 1262,1267 ****
--- 2292,2298 ----
         ["Add" gnus-category-add t]
         ["Kill" gnus-category-kill t]
         ["Copy" gnus-category-copy t]
+        ["Edit category" gnus-agent-customize-category t]
         ["Edit predicate" gnus-category-edit-predicate t]
         ["Edit score" gnus-category-edit-score t]
         ["Edit groups" gnus-category-edit-groups t]
***************
*** 1275,1281 ****
  All normal editing commands are switched off.
  \\<gnus-category-mode-map>
  For more in-depth information on this mode, read the manual
! (`\\[gnus-info-find-node]').
  
  The following commands are available:
  
--- 2306,2312 ----
  All normal editing commands are switched off.
  \\<gnus-category-mode-map>
  For more in-depth information on this mode, read the manual
! \(`\\[gnus-info-find-node]').
  
  The following commands are available:
  
***************
*** 1298,1305 ****
  (defalias 'gnus-category-position-point 'gnus-goto-colon)
  
  (defun gnus-category-insert-line (category)
!   (let* ((gnus-tmp-name (car category))
!        (gnus-tmp-groups (length (cadddr category))))
      (beginning-of-line)
      (gnus-add-text-properties
       (point)
--- 2329,2336 ----
  (defalias 'gnus-category-position-point 'gnus-goto-colon)
  
  (defun gnus-category-insert-line (category)
!   (let* ((gnus-tmp-name (format "%s" (car category)))
!        (gnus-tmp-groups (length (gnus-agent-cat-groups category))))
      (beginning-of-line)
      (gnus-add-text-properties
       (point)
***************
*** 1333,1347 ****
      (gnus-category-position-point)))
  
  (defun gnus-category-name ()
!   (or (get-text-property (gnus-point-at-bol) 'gnus-category)
        (error "No category on the current line")))
  
  (defun gnus-category-read ()
    "Read the category alist."
    (setq gnus-category-alist
!       (or (gnus-agent-read-file
!            (nnheader-concat gnus-agent-directory "lib/categories"))
!           (list (list 'default 'short nil nil)))))
  
  (defun gnus-category-write ()
    "Write the category alist."
--- 2364,2404 ----
      (gnus-category-position-point)))
  
  (defun gnus-category-name ()
!   (or (intern (get-text-property (gnus-point-at-bol) 'gnus-category))
        (error "No category on the current line")))
  
  (defun gnus-category-read ()
    "Read the category alist."
    (setq gnus-category-alist
!         (or
!          (with-temp-buffer
!            (ignore-errors
!             (nnheader-insert-file-contents (nnheader-concat 
gnus-agent-directory "lib/categories"))
!             (goto-char (point-min))
!             ;; This code isn't temp, it will be needed so long as
!             ;; anyone may be migrating from an older version.
! 
!             ;; Once we're certain that people will not revert to an
!             ;; earlier version, we can take out the old-list code in
!             ;; gnus-category-write.
!             (let* ((old-list (read (current-buffer)))
!                    (new-list (ignore-errors (read (current-buffer)))))
!               (if new-list
!                   new-list
!                 ;; Convert from a positional list to an alist.
!                 (mapcar
!                  (lambda (c)
!                    (setcdr c
!                            (delq nil
!                                  (gnus-mapcar
!                                   (lambda (valu symb)
!                                     (if valu
!                                         (cons symb valu)))
!                                   (cdr c)
!                                   '(agent-predicate agent-score-file 
agent-groups))))
!                    c)
!                  old-list)))))
!          (list (gnus-agent-cat-make 'default 'short)))))
  
  (defun gnus-category-write ()
    "Write the category alist."
***************
*** 1349,1354 ****
--- 2406,2421 ----
        gnus-category-group-cache nil)
    (gnus-make-directory (nnheader-concat gnus-agent-directory "lib"))
    (with-temp-file (nnheader-concat gnus-agent-directory "lib/categories")
+     ;; This prin1 is temporary.  It exists so that people can revert
+     ;; to an earlier version of gnus-agent.
+     (prin1 (mapcar (lambda (c)
+               (list (car c)
+                     (cdr (assoc 'agent-predicate c))
+                     (cdr (assoc 'agent-score-file c))
+                     (cdr (assoc 'agent-groups c))))
+                    gnus-category-alist)
+            (current-buffer))
+     (newline)
      (prin1 gnus-category-alist (current-buffer))))
  
  (defun gnus-category-edit-predicate (category)
***************
*** 1356,1364 ****
    (interactive (list (gnus-category-name)))
    (let ((info (assq category gnus-category-alist)))
      (gnus-edit-form
!      (cadr info) (format "Editing the predicate for category %s" category)
       `(lambda (predicate)
!       (setcar (cdr (assq ',category gnus-category-alist)) predicate)
        (gnus-category-write)
        (gnus-category-list)))))
  
--- 2423,2438 ----
    (interactive (list (gnus-category-name)))
    (let ((info (assq category gnus-category-alist)))
      (gnus-edit-form
!      (gnus-agent-cat-predicate info)
!      (format "Editing the select predicate for category %s" category)
       `(lambda (predicate)
!         ;; Avoid run-time execution of setf form
!         ;; (setf (gnus-agent-cat-predicate (assq ',category 
gnus-category-alist))
!         ;;       predicate)
!         ;; use its expansion instead:
!         (gnus-agent-cat-set-property (assq ',category gnus-category-alist)
!                                      'agent-predicate predicate)
! 
        (gnus-category-write)
        (gnus-category-list)))))
  
***************
*** 1367,1376 ****
    (interactive (list (gnus-category-name)))
    (let ((info (assq category gnus-category-alist)))
      (gnus-edit-form
!      (caddr info)
       (format "Editing the score expression for category %s" category)
!      `(lambda (groups)
!       (setcar (cddr (assq ',category gnus-category-alist)) groups)
        (gnus-category-write)
        (gnus-category-list)))))
  
--- 2441,2456 ----
    (interactive (list (gnus-category-name)))
    (let ((info (assq category gnus-category-alist)))
      (gnus-edit-form
!      (gnus-agent-cat-score-file info)
       (format "Editing the score expression for category %s" category)
!      `(lambda (score-file)
!         ;; Avoid run-time execution of setf form
!         ;; (setf (gnus-agent-cat-score-file (assq ',category 
gnus-category-alist))
!         ;;       score-file)
!         ;; use its expansion instead:
!         (gnus-agent-cat-set-property (assq ',category gnus-category-alist)
!                                      'agent-score-file score-file)
! 
        (gnus-category-write)
        (gnus-category-list)))))
  
***************
*** 1379,1387 ****
    (interactive (list (gnus-category-name)))
    (let ((info (assq category gnus-category-alist)))
      (gnus-edit-form
!      (cadddr info) (format "Editing the group list for category %s" category)
       `(lambda (groups)
!       (setcar (nthcdr 3 (assq ',category gnus-category-alist)) groups)
        (gnus-category-write)
        (gnus-category-list)))))
  
--- 2459,2474 ----
    (interactive (list (gnus-category-name)))
    (let ((info (assq category gnus-category-alist)))
      (gnus-edit-form
!      (gnus-agent-cat-groups info)
!      (format "Editing the group list for category %s" category)
       `(lambda (groups)
!         ;; Avoid run-time execution of setf form
!         ;; (setf (gnus-agent-cat-groups (assq ',category gnus-category-alist))
!         ;;       groups)
!         ;; use its expansion instead:
!         (gnus-agent-set-cat-groups (assq ',category gnus-category-alist)
!                                    groups)
! 
        (gnus-category-write)
        (gnus-category-list)))))
  
***************
*** 1398,1405 ****
    "Copy the current category."
    (interactive (list (gnus-category-name) (intern (read-string "New name: 
"))))
    (let ((info (assq category gnus-category-alist)))
!     (push (list to (gnus-copy-sequence (cadr info))
!               (gnus-copy-sequence (caddr info)) nil)
          gnus-category-alist)
      (gnus-category-write)
      (gnus-category-list)))
--- 2485,2494 ----
    "Copy the current category."
    (interactive (list (gnus-category-name) (intern (read-string "New name: 
"))))
    (let ((info (assq category gnus-category-alist)))
!     (push (let ((newcat (gnus-copy-sequence info)))
!             (setf (gnus-agent-cat-name newcat) to)
!             (setf (gnus-agent-cat-groups newcat) nil)
!             newcat)
          gnus-category-alist)
      (gnus-category-write)
      (gnus-category-list)))
***************
*** 1409,1415 ****
    (interactive "SCategory name: ")
    (when (assq category gnus-category-alist)
      (error "Category %s already exists" category))
!   (push (list category 'false nil nil)
        gnus-category-alist)
    (gnus-category-write)
    (gnus-category-list))
--- 2498,2504 ----
    (interactive "SCategory name: ")
    (when (assq category gnus-category-alist)
      (error "Category %s already exists" category))
!   (push (gnus-agent-cat-make category)
        gnus-category-alist)
    (gnus-category-write)
    (gnus-category-list))
***************
*** 1434,1439 ****
--- 2523,2529 ----
      (long . gnus-agent-long-p)
      (low . gnus-agent-low-scored-p)
      (high . gnus-agent-high-scored-p)
+     (read . gnus-agent-read-p)
      (true . gnus-agent-true)
      (false . gnus-agent-false))
    "Mapping from short score predicate symbols to predicate functions.")
***************
*** 1465,1473 ****
    "Say whether an article has a high score or not."
    (> gnus-score gnus-agent-high-score))
  
! (defun gnus-category-make-function (cat)
!   "Make a function from category CAT."
!   `(lambda () ,(gnus-category-make-function-1 cat)))
  
  (defun gnus-agent-true ()
    "Return t."
--- 2555,2572 ----
    "Say whether an article has a high score or not."
    (> gnus-score gnus-agent-high-score))
  
! (defun gnus-agent-read-p ()
!   "Say whether an article is read or not."
!   (gnus-member-of-range (mail-header-number gnus-headers)
!                       (gnus-info-read (gnus-get-info gnus-newsgroup-name))))
! 
! (defun gnus-category-make-function (predicate)
!   "Make a function from PREDICATE."
!   (let ((func (gnus-category-make-function-1 predicate)))
!     (if (and (= (length func) 1)
!            (symbolp (car func)))
!       (car func)
!       (gnus-byte-compile `(lambda () ,func)))))
  
  (defun gnus-agent-true ()
    "Return t."
***************
*** 1477,1509 ****
    "Return nil."
    nil)
  
! (defun gnus-category-make-function-1 (cat)
!   "Make a function from category CAT."
    (cond
     ;; Functions are just returned as is.
!    ((or (symbolp cat)
!       (gnus-functionp cat))
!     `(,(or (cdr (assq cat gnus-category-predicate-alist))
!          cat)))
!    ;; More complex category.
!    ((consp cat)
      `(,(cond
!       ((memq (car cat) '(& and))
         'and)
!       ((memq (car cat) '(| or))
         'or)
!       ((memq (car cat) gnus-category-not)
         'not))
!       ,@(mapcar 'gnus-category-make-function-1 (cdr cat))))
     (t
!     (error "Unknown category type: %s" cat))))
  
  (defun gnus-get-predicate (predicate)
!   "Return the predicate for CATEGORY."
    (or (cdr (assoc predicate gnus-category-predicate-cache))
!       (cdar (push (cons predicate
!                       (gnus-category-make-function predicate))
!                 gnus-category-predicate-cache))))
  
  (defun gnus-group-category (group)
    "Return the category GROUP belongs to."
--- 2576,2666 ----
    "Return nil."
    nil)
  
! (defun gnus-category-make-function-1 (predicate)
!   "Make a function from PREDICATE."
    (cond
     ;; Functions are just returned as is.
!    ((or (symbolp predicate)
!       (functionp predicate))
!     `(,(or (cdr (assq predicate gnus-category-predicate-alist))
!          predicate)))
!    ;; More complex predicate.
!    ((consp predicate)
      `(,(cond
!       ((memq (car predicate) '(& and))
         'and)
!       ((memq (car predicate) '(| or))
         'or)
!       ((memq (car predicate) gnus-category-not)
         'not))
!       ,@(mapcar 'gnus-category-make-function-1 (cdr predicate))))
     (t
!     (error "Unknown predicate type: %s" predicate))))
  
  (defun gnus-get-predicate (predicate)
!   "Return the function implementing PREDICATE."
    (or (cdr (assoc predicate gnus-category-predicate-cache))
!       (let ((func (gnus-category-make-function predicate)))
!       (setq gnus-category-predicate-cache
!             (nconc gnus-category-predicate-cache
!                    (list (cons predicate func))))
!       func)))
! 
! (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 predicate returns true, then indeed the predicate must
! return only unread articles."
!   (eq t (gnus-function-implies-unread-1 
!          (gnus-category-make-function-1 predicate))))
! 
! (defun gnus-function-implies-unread-1 (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."
***************
*** 1512,1699 ****
      (let ((cs gnus-category-alist)
          groups cat)
        (while (setq cat (pop cs))
!       (setq groups (cadddr cat))
        (while groups
          (gnus-sethash (pop groups) cat gnus-category-group-cache)))))
    (or (gnus-gethash group gnus-category-group-cache)
        (assq 'default gnus-category-alist)))
  
! (defun gnus-agent-expire ()
!   "Expire all old articles."
    (interactive)
!   (let ((methods gnus-agent-covered-methods)
!       (day (- (time-to-days (current-time)) gnus-agent-expire-days))
!       gnus-command-method sym group articles
!       history overview file histories elem art nov-file low info
!       unreads marked article orig lowest highest)
!     (save-excursion
!       (setq overview (gnus-get-buffer-create " *expire overview*"))
!       (while (setq gnus-command-method (pop methods))
!       (when (file-exists-p (gnus-agent-lib-file "active"))
!         (with-temp-buffer
!           (nnheader-insert-file-contents (gnus-agent-lib-file "active"))
!           (gnus-active-to-gnus-format
!            gnus-command-method
!            (setq orig (gnus-make-hashtable
!                        (count-lines (point-min) (point-max))))))
!         (let ((expiry-hashtb (gnus-make-hashtable 1023)))
!           (gnus-agent-open-history)
!           (set-buffer
!            (setq gnus-agent-current-history
!                  (setq history (gnus-agent-history-buffer))))
!           (goto-char (point-min))
!           (when (> (buffer-size) 1)
!             (goto-char (point-min))
!             (while (not (eobp))
!               (skip-chars-forward "^\t")
!               (if (> (read (current-buffer)) day)
!                   ;; New article; we don't expire it.
!                   (forward-line 1)
!                 ;; Old article.  Schedule it for possible nuking.
!                 (while (not (eolp))
!                   (setq sym (let ((obarray expiry-hashtb) s)
!                               (setq s (read (current-buffer)))
!                               (if (stringp s) (intern s) s)))
!                   (if (boundp sym)
!                       (set sym (cons (cons (read (current-buffer)) (point))
!                                      (symbol-value sym)))
!                     (set sym (list (cons (read (current-buffer)) (point)))))
!                   (skip-chars-forward " "))
!                 (forward-line 1)))
!             ;; We now have all articles that can possibly be expired.
!             (mapatoms
!              (lambda (sym)
!                (setq group (symbol-name sym)
!                      articles (sort (symbol-value sym) 'car-less-than-car)
!                      low (car (gnus-active group))
!                      info (gnus-get-info group)
!                      unreads (ignore-errors
!                                (gnus-list-of-unread-articles group))
!                      marked (nconc
!                              (gnus-uncompress-range
!                               (cdr (assq 'tick (gnus-info-marks info))))
!                              (gnus-uncompress-range
!                               (cdr (assq 'dormant
!                                          (gnus-info-marks info)))))
!                      nov-file (gnus-agent-article-name ".overview" group)
!                      lowest nil
!                      highest nil)
!                (gnus-agent-load-alist group)
!                (gnus-message 5 "Expiring articles in %s" group)
!                (set-buffer overview)
!                (erase-buffer)
!                (when (file-exists-p nov-file)
!                  (nnheader-insert-file-contents nov-file))
!                (goto-char (point-min))
!                (setq article 0)
!                (while (setq elem (pop articles))
!                  (setq article (car elem))
!                  (when (or (null low)
!                            (< article low)
!                            gnus-agent-expire-all
!                            (and (not (memq article unreads))
!                                 (not (memq article marked))))
!                    ;; Find and nuke the NOV line.
!                    (while (and (not (eobp))
!                                (or (not (numberp
!                                          (setq art (read (current-buffer)))))
!                                    (< art article)))
!                      (if (and (numberp art)
!                               (file-exists-p
!                                (gnus-agent-article-name
!                                 (number-to-string art) group)))
!                          (progn
!                            (unless lowest
!                              (setq lowest art))
!                            (setq highest art)
!                            (forward-line 1))
!                        ;; Remove old NOV lines that have no articles.
!                        (gnus-delete-line)))
!                    (if (or (eobp)
!                            (/= art article))
!                        (beginning-of-line)
!                      (gnus-delete-line))
!                    ;; Nuke the article.
!                    (when (file-exists-p
!                           (setq file (gnus-agent-article-name
!                                       (number-to-string article)
!                                       group)))
!                      (delete-file file))
!                    ;; Schedule the history line for nuking.
!                    (push (cdr elem) histories)))
!                (gnus-make-directory (file-name-directory nov-file))
!                (let ((coding-system-for-write
!                       gnus-agent-file-coding-system))
!                  (write-region (point-min) (point-max) nov-file nil 'silent))
!                ;; Delete the unwanted entries in the alist.
!                (setq gnus-agent-article-alist
!                      (sort gnus-agent-article-alist 'car-less-than-car))
!                (let* ((alist gnus-agent-article-alist)
!                       (prev (cons nil alist))
!                       (first prev)
!                       expired)
!                  (while (and alist
!                              (<= (caar alist) article))
!                    (if (or (not (cdar alist))
!                            (not (file-exists-p
!                                  (gnus-agent-article-name
!                                   (number-to-string
!                                    (caar alist))
!                                   group))))
!                        (progn
!                          (push (caar alist) expired)
!                          (setcdr prev (setq alist (cdr alist))))
!                      (setq prev alist
!                            alist (cdr alist))))
!                  (setq gnus-agent-article-alist (cdr first))
!                  (gnus-agent-save-alist group)
!                  ;; Mark all articles up to the first article
!                  ;; in `gnus-article-alist' as read.
!                  (when (and info (caar gnus-agent-article-alist))
!                    (setcar (nthcdr 2 info)
!                            (gnus-range-add
!                             (nth 2 info)
!                             (cons 1 (- (caar gnus-agent-article-alist) 1)))))
!                  ;; Maybe everything has been expired from 
`gnus-article-alist'
!                  ;; and so the above marking as read could not be conducted,
!                  ;; or there are expired article within the range of the 
alist.
!                  (when (and info
!                             expired
!                             (or (not (caar gnus-agent-article-alist))
!                                 (> (car expired)
!                                    (caar gnus-agent-article-alist))))
!                    (setcar (nthcdr 2 info)
!                            (gnus-add-to-range
!                             (nth 2 info)
!                             (nreverse expired))))
!                  (gnus-dribble-enter
!                   (concat "(gnus-group-set-info '"
!                           (gnus-prin1-to-string info)
!                           ")")))
!                (when lowest
!                  (if (gnus-gethash group orig)
!                      (setcar (gnus-gethash group orig) lowest)
!                    (gnus-sethash group (cons lowest highest) orig))))
!              expiry-hashtb)
!             (set-buffer history)
!             (setq histories (nreverse (sort histories '<)))
!             (while histories
!               (goto-char (pop histories))
!               (gnus-delete-line))
!             (gnus-agent-save-history)
!             (gnus-agent-close-history)
!             (gnus-write-active-file
!              (gnus-agent-lib-file "active") orig))
!           (gnus-message 4 "Expiry...done")))))))
  
  ;;;###autoload
  (defun gnus-agent-batch ()
    (interactive)
    (let ((init-file-user "")
        (gnus-always-read-dribble-file t))
      (gnus))
!   (gnus-group-send-drafts)
!   (gnus-agent-fetch-session))
  
  (provide 'gnus-agent)
  
--- 2669,3744 ----
      (let ((cs gnus-category-alist)
          groups cat)
        (while (setq cat (pop cs))
!       (setq groups (gnus-agent-cat-groups cat))
        (while groups
          (gnus-sethash (pop groups) cat gnus-category-group-cache)))))
    (or (gnus-gethash group gnus-category-group-cache)
        (assq 'default gnus-category-alist)))
  
! (defun gnus-agent-expire-group (group &optional articles force)
!   "Expire all old articles in GROUP.
! If you want to force expiring of certain articles, this function can
! take ARTICLES, and FORCE parameters as well.
! 
! The articles on which the expiration process runs are selected as follows:
!   if ARTICLES is null, all read and unmarked articles.
!   if ARTICLES is t, all articles.
!   if ARTICLES is a list, just those articles.
! FORCE is equivalent to setting the expiration predicates to true."
!   (interactive
!    (list (let ((def (or (gnus-group-group-name)
!                         gnus-newsgroup-name)))
!            (let ((select (read-string (if def
!                                           (concat "Group Name ("
!                                                   def "): ")
!                                         "Group Name: "))))
!              (if (and (equal "" select)
!                       def)
!                  def
!                select)))))
! 
!   (if (not group)
!       (gnus-agent-expire articles group force)
!     (let ( ;; Bind gnus-agent-expire-stats to enable tracking of
!          ;; expiration statistics of this single group
!           (gnus-agent-expire-stats (list 0 0 0.0)))
!       (if (or (not (eq articles t))
!               (yes-or-no-p
!                (concat "Are you sure that you want to "
!                        "expire all articles in " group ".")))
!           (let ((gnus-command-method (gnus-find-method-for-group group))
!                 (overview (gnus-get-buffer-create " *expire overview*"))
!                 orig)
!             (unwind-protect
!                 (let ((active-file (gnus-agent-lib-file "active")))
!                   (when (file-exists-p active-file)
!                     (with-temp-buffer
!                       (nnheader-insert-file-contents active-file)
!                       (gnus-active-to-gnus-format
!                        gnus-command-method
!                        (setq orig (gnus-make-hashtable
!                                    (count-lines (point-min) (point-max))))))
!                     (save-excursion
!                       (gnus-agent-expire-group-1
!                        group overview (gnus-gethash-safe group orig)
!                        articles force))))
!               (kill-buffer overview))))
!       (gnus-message 4 (gnus-agent-expire-done-message)))))
! 
! (defun gnus-agent-expire-group-1 (group overview active articles force)
!   ;; Internal function - requires caller to have set
!   ;; gnus-command-method, initialized overview buffer, and to have
!   ;; provided a non-nil active
! 
!   (let ((dir (gnus-agent-group-pathname group)))
!     (when (boundp 'gnus-agent-expire-current-dirs)
!       (set 'gnus-agent-expire-current-dirs 
!            (cons dir 
!                  (symbol-value 'gnus-agent-expire-current-dirs))))
! 
!     (if (and (not force)
!              (eq 'DISABLE (gnus-agent-find-parameter group 
!                                                      
'agent-enable-expiration)))
!         (gnus-message 5 "Expiry skipping over %s" group)
!       (gnus-message 5 "Expiring articles in %s" group)
!       (gnus-agent-load-alist group)
!       (let* ((stats (if (boundp 'gnus-agent-expire-stats)
!                         ;; Use the list provided by my caller
!                         (symbol-value 'gnus-agent-expire-stats)
!                       ;; otherwise use my own temporary list
!                       (list 0 0 0.0)))
!              (info (gnus-get-info group))
!              (alist gnus-agent-article-alist)
!              (day (- (time-to-days (current-time))
!                      (gnus-agent-find-parameter group 'agent-days-until-old)))
!              (specials (if (and alist
!                                 (not force))
!                            ;; This could be a bit of a problem.  I need to
!                            ;; keep the last article to avoid refetching
!                            ;; headers when using nntp in the backend.  At
!                            ;; the same time, if someone uses a backend
!                            ;; that supports article moving then I may have
!                            ;; to remove the last article to complete the
!                            ;; move.  Right now, I'm going to assume that
!                            ;; FORCE overrides specials.
!                            (list (caar (last alist)))))
!              (unreads ;; Articles that are excluded from the
!               ;; expiration process
!               (cond (gnus-agent-expire-all
!                      ;; All articles are marked read by global decree
!                      nil)
!                     ((eq articles t)
!                      ;; All articles are marked read by function
!                      ;; parameter
!                      nil)
!                     ((not articles)
!                      ;; Unread articles are marked protected from
!                      ;; expiration Don't call
!                      ;; gnus-list-of-unread-articles as it returns
!                      ;; articles that have not been fetched into the
!                      ;; agent.
!                      (ignore-errors
!                        (gnus-agent-unread-articles group)))
!                     (t
!                      ;; All articles EXCEPT those named by the caller
!                      ;; are protected from expiration
!                      (gnus-sorted-difference
!                       (gnus-uncompress-range
!                        (cons (caar alist)
!                              (caar (last alist))))
!                       (sort articles '<)))))
!              (marked ;; More articles that are excluded from the
!               ;; expiration process
!               (cond (gnus-agent-expire-all
!                      ;; All articles are unmarked by global decree
!                      nil)
!                     ((eq articles t)
!                      ;; All articles are unmarked by function
!                      ;; parameter
!                      nil)
!                     (articles
!                      ;; All articles may as well be unmarked as the
!                      ;; unreads list already names the articles we are
!                      ;; going to keep
!                      nil)
!                     (t
!                      ;; Ticked and/or dormant articles are excluded
!                      ;; from expiration
!                      (nconc
!                       (gnus-uncompress-range
!                        (cdr (assq 'tick (gnus-info-marks info))))
!                       (gnus-uncompress-range
!                        (cdr (assq 'dormant
!                                   (gnus-info-marks info))))))))
!              (nov-file (concat dir ".overview"))
!              (cnt 0)
!              (completed -1)
!              dlist
!              type)
! 
!         ;; The normal article alist contains elements that look like
!         ;; (article# .  fetch_date) I need to combine other
!         ;; information with this list.  For example, a flag indicating
!         ;; that a particular article MUST BE KEPT.  To do this, I'm
!         ;; going to transform the elements to look like (article#
!         ;; fetch_date keep_flag NOV_entry_marker) Later, I'll reverse
!         ;; the process to generate the expired article alist.
! 
!         ;; Convert the alist elements to (article# fetch_date nil
!         ;; nil).
!         (setq dlist (mapcar (lambda (e)
!                               (list (car e) (cdr e) nil nil)) alist))
! 
!         ;; Convert the keep lists to elements that look like (article#
!         ;; nil keep_flag nil) then append it to the expanded dlist
!         ;; These statements are sorted by ascending precidence of the
!         ;; keep_flag.
!         (setq dlist (nconc dlist
!                            (mapcar (lambda (e)
!                                      (list e nil 'unread  nil))
!                                    unreads)))
!         (setq dlist (nconc dlist
!                            (mapcar (lambda (e)
!                                      (list e nil 'marked  nil))
!                                    marked)))
!         (setq dlist (nconc dlist
!                            (mapcar (lambda (e)
!                                      (list e nil 'special nil))
!                                    specials)))
! 
!         (set-buffer overview)
!         (erase-buffer)
!         (buffer-disable-undo)
!         (when (file-exists-p nov-file)
!           (gnus-message 7 "gnus-agent-expire: Loading overview...")
!           (nnheader-insert-file-contents nov-file)
!           (goto-char (point-min))
! 
!           (let (p)
!             (while (< (setq p (point)) (point-max))
!               (condition-case nil
!                   ;; If I successfully read an integer (the plus zero
!                   ;; ensures a numeric type), prepend a marker entry
!                   ;; to the list
!                   (push (list (+ 0 (read (current-buffer))) nil nil
!                               (set-marker (make-marker) p))
!                         dlist)
!                 (error
!                  (gnus-message 1 "gnus-agent-expire: read error \
! occurred when reading expression at %s in %s.  Skipping to next \
! line." (point) nov-file)))
!               ;; Whether I succeeded, or failed, it doesn't matter.
!               ;; Move to the next line then try again.
!               (forward-line 1)))
! 
!           (gnus-message
!            7 "gnus-agent-expire: Loading overview... Done"))
!         (set-buffer-modified-p nil)
! 
!         ;; At this point, all of the information is in dlist.  The
!         ;; only problem is that much of it is spread across multiple
!         ;; entries.  Sort then MERGE!!
!         (gnus-message 7 "gnus-agent-expire: Sorting entries... ")
!         ;; If two entries have the same article-number then sort by
!         ;; ascending keep_flag.
!         (let ((special 0)
!               (marked 1)
!               (unread 2))
!           (setq dlist
!                 (sort dlist
!                       (lambda (a b)
!                         (cond ((< (nth 0 a) (nth 0 b))
!                                t)
!                               ((> (nth 0 a) (nth 0 b))
!                                nil)
!                               (t
!                                (let ((a (or (symbol-value (nth 2 a))
!                                             3))
!                                      (b (or (symbol-value (nth 2 b))
!                                             3)))
!                                  (<= a b))))))))
!         (gnus-message 7 "gnus-agent-expire: Sorting entries... Done")
!         (gnus-message 7 "gnus-agent-expire: Merging entries... ")
!         (let ((dlist dlist))
!           (while (cdr dlist)            ; I'm not at the end-of-list
!             (if (eq (caar dlist) (caadr dlist))
!                 (let ((first (cdr (car dlist)))
!                       (secnd (cdr (cadr dlist))))
!                   (setcar first (or (car first)
!                                     (car secnd))) ; fetch_date
!                   (setq first (cdr first)
!                         secnd (cdr secnd))
!                   (setcar first (or (car first)
!                                     (car secnd))) ; Keep_flag
!                   (setq first (cdr first)
!                         secnd (cdr secnd))
!                   (setcar first (or (car first)
!                                     (car secnd))) ; NOV_entry_marker
! 
!                   (setcdr dlist (cddr dlist)))
!               (setq dlist (cdr dlist)))))
!         (gnus-message 7 "gnus-agent-expire: Merging entries... Done")
! 
!         (let* ((len (float (length dlist)))
!                (alist (list nil))
!                (tail-alist alist))
!           (while dlist
!             (let ((new-completed (truncate (* 100.0
!                                               (/ (setq cnt (1+ cnt))
!                                                  len))))
!                 message-log-max)
!               (when (> new-completed completed)
!                 (setq completed new-completed)
!                 (gnus-message 7 "%3d%% completed..."  completed)))
!             (let* ((entry          (car dlist))
!                    (article-number (nth 0 entry))
!                    (fetch-date     (nth 1 entry))
!                    (keep           (nth 2 entry))
!                    (marker         (nth 3 entry)))
! 
!               (cond
!                ;; Kept articles are unread, marked, or special.
!                (keep
!                 (gnus-agent-message 10
!                                     "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 %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.")))
!                 (gnus-agent-append-to-list
!                  tail-alist
!                  (cons article-number fetch-date)))
! 
!                ;; The following articles are READ, UNMARKED, and
!                ;; ORDINARY.  See if they can be EXPIRED!!!
!                ((setq type
!                       (cond
!                        ((not (integerp fetch-date))
!                         'read) ;; never fetched article (may expire
!                        ;; right now)
!                        ((not (file-exists-p
!                               (concat dir (number-to-string
!                                            article-number))))
!                         (setf (nth 1 entry) nil)
!                         'externally-expired) ;; Can't find the cached
!                        ;; article.  Handle case
!                        ;; as though this article
!                        ;; was never fetched.
! 
!                        ;; We now have the arrival day, so we see
!                        ;; whether it's old enough to be expired.
!                        ((< fetch-date day)
!                         'expired)
!                        (force
!                         'forced)))
! 
!                 ;; I found some reason to expire this entry.
! 
!                 (let ((actions nil))
!                   (when (memq type '(forced expired))
!                     (ignore-errors      ; Just being paranoid.
!                       (let ((file-name (concat dir (number-to-string
!                                                 article-number))))
!                         (incf (nth 2 stats) (nth 7 (file-attributes 
file-name)))
!                         (incf (nth 1 stats))
!                         (delete-file file-name))
!                       (push "expired cached article" actions))
!                     (setf (nth 1 entry) nil)
!                     )
! 
!                   (when marker
!                     (push "NOV entry removed" actions)
!                     (goto-char marker)
! 
!                     (incf (nth 0 stats))
! 
!                     (let ((from (gnus-point-at-bol))
!                           (to (progn (forward-line 1) (point))))
!                       (incf (nth 2 stats) (- to from))
!                       (delete-region from to)))
! 
!                   ;; If considering all articles is set, I can only
!                   ;; expire article IDs that are no longer in the
!                   ;; active range (That is, articles that preceed the
!                   ;; first article in the new alist).
!                   (if (and gnus-agent-consider-all-articles
!                            (>= article-number (car active)))
!                       ;; I have to keep this ID in the alist
!                       (gnus-agent-append-to-list
!                        tail-alist (cons article-number fetch-date))
!                     (push (format "Removed %s article number from \
! article alist" type) 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: %s:%d: Article kept as \
! expiration tests failed." group article-number)
!                 (gnus-agent-append-to-list
!                  tail-alist (cons article-number fetch-date)))
!                )
! 
!               ;; Clean up markers as I want to recycle this buffer
!               ;; over several groups.
!               (when marker
!                 (set-marker marker nil))
! 
!               (setq dlist (cdr dlist))))
! 
!           (setq alist (cdr alist))
! 
!           (let ((inhibit-quit t))
!             (unless (equal alist gnus-agent-article-alist)
!               (setq gnus-agent-article-alist alist)
!               (gnus-agent-save-alist group))
! 
!             (when (buffer-modified-p)
!               (let ((coding-system-for-write
!                      gnus-agent-file-coding-system))
!                 (gnus-make-directory dir)
!                 (write-region (point-min) (point-max) nov-file nil
!                               'silent)
!                 ;; clear the modified flag as that I'm not confused by
!                 ;; its status on the next pass through this routine.
!                 (set-buffer-modified-p nil)))
! 
!             (when (eq articles t)
!               (gnus-summary-update-info))))))))
! 
! (defun gnus-agent-expire (&optional articles group force)
!   "Expire all old articles.
! If you want to force expiring of certain articles, this function can
! take ARTICLES, GROUP and FORCE parameters as well.
! 
! The articles on which the expiration process runs are selected as follows:
!   if ARTICLES is null, all read and unmarked articles.
!   if ARTICLES is t, all articles.
!   if ARTICLES is a list, just those articles.
! Setting GROUP will limit expiration to that group.
! FORCE is equivalent to setting the expiration predicates to true."
    (interactive)
!   
!   (if group
!       (gnus-agent-expire-group group articles force)
!     (if (or (not (eq articles t))
!             (yes-or-no-p "Are you sure that you want to expire all \
! articles in every agentized group."))
!         (let ((methods (gnus-agent-covered-methods))
!               ;; Bind gnus-agent-expire-current-dirs to enable tracking
!               ;; of agent directories.
!               (gnus-agent-expire-current-dirs nil)
!               ;; Bind gnus-agent-expire-stats to enable tracking of
!               ;; expiration statistics across all groups
!               (gnus-agent-expire-stats (list 0 0 0.0))
!               gnus-command-method overview orig)
!           (setq overview (gnus-get-buffer-create " *expire overview*"))
!           (unwind-protect
!               (while (setq gnus-command-method (pop methods))
!                 (let ((active-file (gnus-agent-lib-file "active")))
!                   (when (file-exists-p active-file)
!                     (with-temp-buffer
!                       (nnheader-insert-file-contents active-file)
!                       (gnus-active-to-gnus-format
!                        gnus-command-method
!                        (setq orig (gnus-make-hashtable
!                                    (count-lines (point-min) (point-max))))))
!                     (dolist (expiring-group (gnus-groups-from-server
!                                              gnus-command-method))
!                       (let* ((active
!                               (gnus-gethash-safe expiring-group orig)))
!                                         
!                         (when active
!                           (save-excursion
!                             (gnus-agent-expire-group-1
!                              expiring-group overview active articles 
force))))))))
!             (kill-buffer overview))
!           (gnus-agent-expire-unagentized-dirs)
!           (gnus-message 4 (gnus-agent-expire-done-message))))))
! 
! (defun gnus-agent-expire-done-message ()
!   (if (and (> gnus-verbose 4)
!            (boundp 'gnus-agent-expire-stats))
!       (let* ((stats (symbol-value 'gnus-agent-expire-stats))
!              (size (nth 2 stats))
!             (units '(B KB MB GB)))
!         (while (and (> size 1024.0)
!                     (cdr units))
!           (setq size (/ size 1024.0)
!                 units (cdr units)))
! 
!         (format "Expiry recovered %d NOV entries, deleted %d files,\
!  and freed %f %s." 
!                 (nth 0 stats) 
!                 (nth 1 stats) 
!                 size (car units)))
!     "Expiry...done"))
! 
! (defun gnus-agent-expire-unagentized-dirs ()
!   (when (and gnus-agent-expire-unagentized-dirs
!              (boundp 'gnus-agent-expire-current-dirs))
!     (let* ((keep (gnus-make-hashtable))
!          ;; Formally bind gnus-agent-expire-current-dirs so that the
!          ;; compiler will not complain about free references.
!          (gnus-agent-expire-current-dirs
!           (symbol-value 'gnus-agent-expire-current-dirs))
!            dir)
! 
!       (gnus-sethash gnus-agent-directory t keep)
!       (while gnus-agent-expire-current-dirs
!       (setq dir (pop gnus-agent-expire-current-dirs))
!       (when (and (stringp dir)
!                  (file-directory-p dir))
!         (while (not (gnus-gethash dir keep))
!           (gnus-sethash dir t keep)
!           (setq dir (file-name-directory (directory-file-name dir))))))
! 
!       (let* (to-remove
!              checker
!              (checker
!               (function
!                (lambda (d)
!                  "Given a directory, check it and its subdirectories for 
!               membership in the keep hash.  If it isn't found, add 
!               it to to-remove." 
!                  (let ((files (directory-files d))
!                        file)
!                    (while (setq file (pop files))
!                      (cond ((equal file ".") ; Ignore self
!                             nil)
!                            ((equal file "..") ; Ignore parent
!                             nil)
!                            ((equal file ".overview") 
!                             ;; Directory must contain .overview to be
!                             ;; agent's cache of a group.
!                             (let ((d (file-name-as-directory d))
!                                   r)
!                               ;; Search ancestor's for last directory NOT
!                               ;; found in keep hash.
!                               (while (not (gnus-gethash
!                                            (setq d (file-name-directory d)) 
keep))
!                                 (setq r d
!                                       d (directory-file-name d)))
!                               ;; if ANY ancestor was NOT in keep hash and
!                               ;; it it's already in to-remove, add it to
!                               ;; to-remove.                          
!                               (if (and r
!                                        (not (member r to-remove)))
!                                   (push r to-remove))))
!                            ((file-directory-p (setq file (nnheader-concat d 
file)))
!                             (funcall checker file)))))))))
!         (funcall checker (expand-file-name gnus-agent-directory))
! 
!         (when (and to-remove
!                    (or gnus-expert-user
!                        (gnus-y-or-n-p
!                         "gnus-agent-expire has identified local directories 
that are\
!  not currently required by any agentized group.        Do you wish to 
consider\
!  deleting them?")))
!           (while to-remove
!             (let ((dir (pop to-remove)))
!               (if (gnus-y-or-n-p (format "Delete %s? " dir))
!                   (let* (delete-recursive
!                          (delete-recursive
!                           (function
!                            (lambda (f-or-d)
!                              (ignore-errors
!                                (if (file-directory-p f-or-d)
!                                    (condition-case nil
!                                        (delete-directory f-or-d)
!                                      (file-error
!                                       (mapcar (lambda (f)
!                                                 (or (member f '("." ".."))
!                                                     (funcall delete-recursive
!                                                              (nnheader-concat
!                                                               f-or-d f))))
!                                               (directory-files f-or-d))
!                                       (delete-directory f-or-d)))
!                                  (delete-file f-or-d)))))))
!                     (funcall delete-recursive dir))))))))))
  
  ;;;###autoload
  (defun gnus-agent-batch ()
+   "Start Gnus, send queue and fetch session."
    (interactive)
    (let ((init-file-user "")
        (gnus-always-read-dribble-file t))
      (gnus))
!   (let ((gnus-agent-confirmation-function 'gnus-agent-batch-confirmation))
!     (gnus-group-send-queue)
!     (gnus-agent-fetch-session)))
! 
! (defun gnus-agent-unread-articles (group)
!   (let* ((read (gnus-info-read (gnus-get-info group)))
!        (known (gnus-agent-load-alist group))
!        (unread (list nil))
!        (tail-unread unread))
!     (while (and known read)
!       (let ((candidate (car (pop known))))
!       (while (let* ((range (car read))
!                     (min   (if (numberp range) range (car range)))
!                     (max   (if (numberp range) range (cdr range))))
!                (cond ((or (not min)
!                           (< candidate min))
!                       (gnus-agent-append-to-list tail-unread candidate)
!                       nil)
!                      ((> candidate max)
!                       (setq read (cdr read))
!                         ;; return t so that I always loop one more
!                         ;; time.  If I just iterated off the end of
!                         ;; read, min will become nil and the current
!                         ;; candidate will be added to the unread list.
!                         t))))))
!     (while known
!       (gnus-agent-append-to-list tail-unread (car (pop known))))
!     (cdr unread)))
! 
! (defun gnus-agent-uncached-articles (articles group &optional cached-header)
!   "Restrict ARTICLES to numbers already fetched.
! Returns a sublist of ARTICLES that excludes thos article ids in GROUP
! that have already been fetched.
! If CACHED-HEADER is nil, articles are only excluded if the article itself
! has been fetched."
! 
!   ;; Logically equivalent to: (gnus-sorted-difference articles (mapcar
!   ;; 'car gnus-agent-article-alist))
! 
!   ;; Functionally, I don't need to construct a temp list using mapcar.
! 
!   (if (and (or gnus-agent-cache (not gnus-plugged))
!            (gnus-agent-load-alist group))
!     (let* ((ref gnus-agent-article-alist)
!            (arts articles)
!            (uncached (list nil))
!            (tail-uncached uncached))
!       (while (and ref arts)
!         (let ((v1 (car arts))
!               (v2 (caar ref)))
!           (cond ((< v1 v2) ; v1 does not appear in the reference list
!                (gnus-agent-append-to-list tail-uncached v1)
!                  (setq arts (cdr arts)))
!                 ((= v1 v2)
!                  (unless (or cached-header (cdar ref)) ; v1 is already cached
!                  (gnus-agent-append-to-list tail-uncached v1))
!                  (setq arts (cdr arts))
!                  (setq ref (cdr ref)))
!                 (t ; reference article (v2) preceeds the list being filtered
!                  (setq ref (cdr ref))))))
!       (while arts
!       (gnus-agent-append-to-list tail-uncached (pop arts)))
!       (cdr uncached))
!     ;; if gnus-agent-load-alist fails, no articles are cached.
!     articles))
! 
! (defun gnus-agent-retrieve-headers (articles group &optional fetch-old)
!   (save-excursion
!     (gnus-agent-create-buffer)
!     (let ((gnus-decode-encoded-word-function 'identity)
!         (file (gnus-agent-article-name ".overview" group))
!         cached-articles uncached-articles)
!       (gnus-make-directory (nnheader-translate-file-chars
!                           (file-name-directory file) t))
! 
!       ;; Populate temp buffer with known headers
!       (when (file-exists-p file)
!       (with-current-buffer gnus-agent-overview-buffer
!         (erase-buffer)
!         (let ((nnheader-file-coding-system
!                gnus-agent-file-coding-system))
!           (nnheader-insert-nov-file file (car articles)))))
! 
!       (if (setq uncached-articles (gnus-agent-uncached-articles articles group
!                                                                 t))
!         (progn
!             ;; Populate nntp-server-buffer with uncached headers
!           (set-buffer nntp-server-buffer)
!           (erase-buffer)
!             (cond ((not (eq 'nov (let (gnus-agent) ; Turn off agent
!                                    (gnus-retrieve-headers
!                                     uncached-articles group fetch-old))))
!                    (nnvirtual-convert-headers))
!                   ((eq 'nntp (car gnus-current-select-method))
!                    ;; The author of gnus-get-newsgroup-headers-xover
!                    ;; reports that the XOVER command is commonly
!                    ;; unreliable. The problem is that recently
!                    ;; posted articles may not be entered into the
!                    ;; NOV database in time to respond to my XOVER
!                    ;; query.
!                    ;;
!                    ;; I'm going to use his assumption that the NOV
!                    ;; database is updated in order of ascending
!                    ;; article ID.  Therefore, a response containing
!                    ;; article ID N implies that all articles from 1
!                    ;; to N-1 are up-to-date.  Therefore, missing
!                    ;; articles in that range have expired.
! 
!                    (set-buffer nntp-server-buffer)
!                    (let* ((fetched-articles (list nil))
!                           (tail-fetched-articles fetched-articles)
!                           (min (cond ((numberp fetch-old)
!                                       (max 1 (- (car articles) fetch-old)))
!                                      (fetch-old
!                                       1)
!                                      (t
!                                       (car articles))))
!                           (max (car (last articles))))
! 
!                      ;; Get the list of articles that were fetched
!                      (goto-char (point-min))
!                      (let ((pm (point-max)))
!                        (while (< (point) pm)
!                          (when (looking-at "[0-9]+\t")
!                            (gnus-agent-append-to-list
!                             tail-fetched-articles
!                             (read (current-buffer))))
!                          (forward-line 1)))
! 
!                      ;; Clip this list to the headers that will
!                      ;; actually be returned
!                      (setq fetched-articles (gnus-list-range-intersection
!                                              (cdr fetched-articles)
!                                              (cons min max)))
! 
!                      ;; Clip the uncached articles list to exclude
!                      ;; IDs after the last FETCHED header.  The
!                      ;; excluded IDs may be fetchable using HEAD.
!                      (if (car tail-fetched-articles)
!                          (setq uncached-articles
!                                (gnus-list-range-intersection
!                                 uncached-articles
!                                 (cons (car uncached-articles)
!                                       (car tail-fetched-articles)))))
! 
!                      ;; Create the list of articles that were
!                      ;; "successfully" fetched.  Success, in this
!                      ;; case, means that the ID should not be
!                      ;; fetched again.  In the case of an expired
!                      ;; article, the header will not be fetched.
!                      (setq uncached-articles
!                            (gnus-sorted-nunion fetched-articles
!                                                uncached-articles))
!                      )))
! 
!             ;; Erase the temp buffer
!           (set-buffer gnus-agent-overview-buffer)
!           (erase-buffer)
! 
!             ;; Copy the nntp-server-buffer to the temp buffer
!           (set-buffer nntp-server-buffer)
!           (copy-to-buffer gnus-agent-overview-buffer (point-min) (point-max))
! 
!             ;; Merge the temp buffer with the known headers (found on
!             ;; disk in FILE) into the nntp-server-buffer
!           (when (and uncached-articles (file-exists-p file))
!             (gnus-agent-braid-nov group uncached-articles file))
! 
!             ;; Save the new set of known headers to FILE
!           (set-buffer nntp-server-buffer)
!           (let ((coding-system-for-write
!                  gnus-agent-file-coding-system))
!             (gnus-agent-check-overview-buffer)
!             (write-region (point-min) (point-max) file nil 'silent))
! 
!             ;; Update the group's article alist to include the newly
!             ;; fetched articles.
!           (gnus-agent-load-alist group)
!           (gnus-agent-save-alist group uncached-articles nil)
!             )
! 
!         ;; Copy the temp buffer to the nntp-server-buffer
!         (set-buffer nntp-server-buffer)
!       (erase-buffer)
!       (insert-buffer-substring gnus-agent-overview-buffer)))
! 
!     (if (and fetch-old
!            (not (numberp fetch-old)))
!       t                               ; Don't remove anything.
!       (nnheader-nov-delete-outside-range
!        (if fetch-old (max 1 (- (car articles) fetch-old))
!        (car articles))
!        (car (last articles)))
!       t)
! 
!     'nov))
! 
! (defun gnus-agent-request-article (article group)
!   "Retrieve ARTICLE in GROUP from the agent cache."
!   (when (and gnus-agent
!              (or gnus-agent-cache
!                  (not gnus-plugged))
!              (numberp article))
!     (let* ((gnus-command-method (gnus-find-method-for-group group))
!            (file (gnus-agent-article-name (number-to-string article) group))
!            (buffer-read-only nil))
!       (when (and (file-exists-p file)
!                  (> (nth 7 (file-attributes file)) 0))
!         (erase-buffer)
!         (gnus-kill-all-overlays)
!         (let ((coding-system-for-read gnus-cache-coding-system))
!           (insert-file-contents file))
!         t))))
! 
! (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)
!                         gnus-newsgroup-name)))
!            (let ((select (read-string (if def
!                                           (concat "Group Name ("
!                                                   def "): ")
!                                         "Group Name: "))))
!              (if (and (equal "" select)
!                       def)
!                  def
!                select)))
!          (catch 'mark
!            (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)))
!                     (gnus-message 3 "Ignoring unexpected input")
!                     (sit-for 1)
!                     t)))))
! 
!   (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\
!  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\
!  entries contained line that did not begin with an article number.  Deleted\
!  line.")
!                        (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)
!        
!               ;; 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 (or (gnus-active group)
!                                       (gnus-activate-group 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, obsolete (ignore)."
!   (interactive "P")
!   (let (regenerated)
!     (gnus-message 4 "Regenerating Gnus agent files...")
!     (dolist (gnus-command-method (gnus-agent-covered-methods))
!         (dolist (group (gnus-groups-from-server gnus-command-method))
!           (setq regenerated (or (gnus-agent-regenerate-group group reread)
!                                 regenerated))))
!     (gnus-message 4 "Regenerating Gnus agent files...done")
! 
!     regenerated))
! 
! (defun gnus-agent-go-online (&optional force)
!   "Switch servers into online status."
!   (interactive (list t))
!   (dolist (server gnus-opened-servers)
!     (when (eq (nth 1 server) 'offline)
!       (if (if (eq force 'ask)
!             (gnus-y-or-n-p
!              (format "Switch %s:%s into online status? "
!                      (caar server) (cadar server)))
!           force)
!         (setcar (nthcdr 1 server) 'close)))))
! 
! (defun gnus-agent-toggle-group-plugged (group)
!   "Toggle the status of the server of the current group."
!   (interactive (list (gnus-group-group-name)))
!   (let* ((method (gnus-find-method-for-group group))
!        (status (cadr (assoc method gnus-opened-servers))))
!     (if (eq status 'offline)
!       (gnus-server-set-status method 'closed)
!       (gnus-close-server method)
!       (gnus-server-set-status method 'offline))
!     (message "Turn %s:%s from %s to %s." (car method) (cadr method)
!            (if (eq status 'offline) 'offline 'online)
!            (if (eq status 'offline) 'online 'offline))))
! 
! (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)
  




reply via email to

[Prev in Thread] Current Thread [Next in Thread]