2009-12-13 Reiner Steib <Reiner.Steib@gmx.de>
[gnus] / lisp / gnus-agent.el
index 12427f7..362f64b 100644 (file)
@@ -1,24 +1,23 @@
 ;;; gnus-agent.el --- unplugged support for Gnus
-;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
-;;        Free Software Foundation, Inc.
+
+;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+;;   2006, 2007, 2008, 2009  Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
     (require 'timer))
   (require 'cl))
 
-(eval-and-compile
-  (autoload 'gnus-server-update-server "gnus-srvr")
-  (autoload 'gnus-agent-customize-category "gnus-cus")
-)
+(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."
@@ -60,7 +57,7 @@
 
 (defcustom gnus-agent-fetched-hook nil
   "Hook run when finished fetching articles."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-agent
   :type 'hook)
 
@@ -117,6 +114,8 @@ If nil, only read articles will be expired."
 (defcustom gnus-agent-synchronize-flags nil
   "Indicate if flags are synchronized when you plug in.
 If this is `ask' the hook will query the user."
+  ;; If the default switches to something else than nil, then the function
+  ;; should be fixed not be exceedingly slow.  See 2005-09-20 ChangeLog entry.
   :version "21.1"
   :type '(choice (const :tag "Always" t)
                 (const :tag "Never" nil)
@@ -152,7 +151,7 @@ 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"
+  :version "22.1"
   :type 'boolean
   :group 'gnus-agent)
 
@@ -160,6 +159,7 @@ read articles as they would just be downloaded again."
   "Chunk size for `gnus-agent-fetch-session'.
 The function will split its article fetches into chunks smaller than
 this limit."
+  :version "22.1"
   :group 'gnus-agent
   :type 'integer)
 
@@ -170,6 +170,7 @@ 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."
+  :version "22.1"
   :group 'gnus-agent
   :type '(radio (const :format "Enable " ENABLE)
                 (const :format "Disable " DISABLE)))
@@ -179,7 +180,7 @@ enable expiration per categories, topics, and groups."
 Have gnus-agent-expire scan the directories under
 \(gnus-agent-directory) for groups that are no longer agentized.
 When found, offer to remove them."
-  :version "21.4"
+  :version "22.1"
   :type 'boolean
   :group 'gnus-agent)
 
@@ -187,7 +188,7 @@ When found, offer to remove them."
   "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'."
-  :version "21.4"
+  :version "22.1"
   :type '(repeat symbol)
   :group 'gnus-agent)
 
@@ -195,29 +196,43 @@ See Info node `(gnus)Server Buffer'."
   "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."
+  :version "22.1"
   :group 'gnus-agent
   :type '(radio (const :format "Always" always)
                (const :format "Never" nil)
-               (const :format "When plugged" t)))
+               (const :format "When unplugged" t)))
 
 (defcustom gnus-agent-prompt-send-queue nil
   "If non-nil, `gnus-group-send-queue' will prompt if called when
 unplugged."
+  :version "22.1"
   :group 'gnus-agent
   :type 'boolean)
 
+(defcustom gnus-agent-article-alist-save-format 1
+  "Indicates whether to use compression(2), versus no
+compression(1), when writing agentview files.  The compressed
+files do save space but load times are 6-7 times higher.  A group
+must be opened then closed for the agentview to be updated using
+the new format."
+  ;; Wouldn't symbols instead numbers be nicer?  --rsteib
+  :version "22.1"
+  :group 'gnus-agent
+  :type '(radio (const :format "Compressed" 2)
+               (const :format "Uncompressed" 1)))
+
 ;;; 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.  
+  "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 
+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.")
@@ -240,6 +255,16 @@ NOTES:
 (defvar gnus-headers)
 (defvar gnus-score)
 
+;; Added to support XEmacs
+(eval-and-compile
+  (unless (fboundp 'directory-files-and-attributes)
+    (defun directory-files-and-attributes (directory
+                                          &optional full match nosort)
+      (let (result)
+       (dolist (file (directory-files directory full match nosort))
+         (push (cons file (file-attributes file)) result))
+       (nreverse result)))))
+
 ;;;
 ;;; Setup
 ;;;
@@ -340,8 +365,8 @@ manipulated as follows:
               (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
+                      (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)
@@ -364,17 +389,17 @@ manipulated as follows:
 (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-length-when-long           agent-long-article)
 (gnus-agent-cat-defaccessor
- gnus-agent-cat-length-when-short          agent-length-when-short)
+ gnus-agent-cat-length-when-short          agent-short-article)
 (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-score-file                 agent-score)
 (gnus-agent-cat-defaccessor
- gnus-agent-cat-enable-undownloaded-faces agent-enable-undownloaded-faces)
+ gnus-agent-cat-enable-undownloaded-faces  agent-enable-undownloaded-faces)
 
 
 ;; This form is equivalent to defsetf except that it calls make-symbol
@@ -430,6 +455,16 @@ manipulated as follows:
 (defsubst gnus-agent-cat-make (name &optional default-agent-predicate)
   (list name `(agent-predicate . ,(or default-agent-predicate 'false))))
 
+(defun gnus-agent-read-group ()
+  "Read a group name in the minibuffer, with completion."
+  (let ((def (or (gnus-group-group-name) gnus-newsgroup-name)))
+    (when def
+      (setq def (gnus-group-decoded-name def)))
+    (gnus-group-completing-read (if def
+                                   (concat "Group Name (" def "): ")
+                                 "Group Name: ")
+                               nil nil t nil nil def)))
+
 ;;; Fetching setup functions.
 
 (defun gnus-agent-start-fetch ()
@@ -571,7 +606,18 @@ manipulated as follows:
   (if (and (fboundp 'propertize)
           (fboundp 'make-mode-line-mouse-map))
       (propertize string 'local-map
-                 (make-mode-line-mouse-map mouse-button mouse-func))
+                 (make-mode-line-mouse-map mouse-button mouse-func)
+                 'mouse-face
+                 (cond ((and (featurep 'xemacs)
+                             ;; XEmacs' `facep' only checks for a face
+                             ;; object, not for a face name, so it's useless
+                             ;; to check with `facep'.
+                             (find-face 'modeline))
+                        'modeline)
+                       ((facep 'mode-line-highlight) ;; Emacs 22
+                        'mode-line-highlight)
+                       ((facep 'mode-line) ;; Emacs 21
+                        'mode-line)) )
     string))
 
 (defun gnus-agent-toggle-plugged (set-to)
@@ -586,8 +632,7 @@ manipulated as follows:
                  (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))
+         (gnus-agent-go-online gnus-agent-go-online))
         (t
          (gnus-agent-close-connections)
          (setq gnus-plugged set-to)
@@ -818,8 +863,7 @@ be a select method."
   (interactive)
   (save-excursion
     (dolist (gnus-command-method (gnus-agent-covered-methods))
-      (when (and (file-exists-p (gnus-agent-lib-file "flags"))
-                (not (eq (gnus-server-status gnus-command-method) 'offline)))
+      (when (eq (gnus-server-status gnus-command-method) 'ok)
        (gnus-agent-possibly-synchronize-flags-server gnus-command-method)))))
 
 (defun gnus-agent-synchronize-flags-server (method)
@@ -831,11 +875,11 @@ be a select method."
       (erase-buffer)
       (nnheader-insert-file-contents (gnus-agent-lib-file "flags"))
       (cond ((null gnus-plugged)
-            (gnus-message 
-             1 "You must be plugged to synchronize flags with server %s" 
+            (gnus-message
+             1 "You must be plugged to synchronize flags with server %s"
              (nth 1 gnus-command-method)))
            ((null (gnus-check-server gnus-command-method))
-            (gnus-message 
+            (gnus-message
              1 "Couldn't open server %s" (nth 1 gnus-command-method)))
            (t
             (condition-case err
@@ -855,18 +899,22 @@ be a select method."
 
 (defun gnus-agent-possibly-synchronize-flags-server (method)
   "Synchronize flags for server according to `gnus-agent-synchronize-flags'."
-  (when (or (and gnus-agent-synchronize-flags
-                (not (eq gnus-agent-synchronize-flags 'ask)))
-           (and (eq gnus-agent-synchronize-flags 'ask)
-                (gnus-y-or-n-p (format "Synchronize flags on server `%s'? "
-                                       (cadr method)))))
+  (when (and (file-exists-p (gnus-agent-lib-file "flags"))
+            (or (and gnus-agent-synchronize-flags
+                     (not (eq gnus-agent-synchronize-flags 'ask)))
+                (and (eq gnus-agent-synchronize-flags 'ask)
+                     (gnus-y-or-n-p
+                      (format "Synchronize flags on server `%s'? "
+                              (cadr method))))))
     (gnus-agent-synchronize-flags-server method)))
 
 ;;;###autoload
 (defun gnus-agent-rename-group (old-group new-group)
-  "Rename fully-qualified OLD-GROUP as NEW-GROUP.  Always updates the agent, even when
-disabled, as the old agent files would corrupt gnus when the agent was
-next enabled. Depends upon the caller to determine whether group renaming is supported."
+  "Rename fully-qualified OLD-GROUP as NEW-GROUP.
+Always updates the agent, even when disabled, as the old agent
+files would corrupt gnus when the agent was next enabled.
+Depends upon the caller to determine whether group renaming is
+supported."
   (let* ((old-command-method (gnus-find-method-for-group old-group))
         (old-path           (directory-file-name
                              (let (gnus-command-method old-command-method)
@@ -874,7 +922,8 @@ next enabled. Depends upon the caller to determine whether group renaming is sup
         (new-command-method (gnus-find-method-for-group new-group))
         (new-path           (directory-file-name
                              (let (gnus-command-method new-command-method)
-                               (gnus-agent-group-pathname new-group)))))
+                               (gnus-agent-group-pathname new-group))))
+        (file-name-coding-system nnmail-pathname-coding-system))
     (gnus-rename-file old-path new-path t)
 
     (let* ((old-real-group (gnus-group-real-name old-group))
@@ -883,7 +932,7 @@ next enabled. Depends upon the caller to determine whether group renaming is sup
       (gnus-agent-save-group-info old-command-method old-real-group nil)
       (gnus-agent-save-group-info new-command-method new-real-group old-active)
 
-      (let ((old-local (gnus-agent-get-local old-group 
+      (let ((old-local (gnus-agent-get-local old-group
                                             old-real-group old-command-method)))
        (gnus-agent-set-local old-group
                              nil nil
@@ -894,19 +943,22 @@ next enabled. Depends upon the caller to determine whether group renaming is sup
 
 ;;;###autoload
 (defun gnus-agent-delete-group (group)
-  "Delete fully-qualified GROUP.  Always updates the agent, even when
-disabled, as the old agent files would corrupt gnus when the agent was
-next enabled. Depends upon the caller to determine whether group deletion is supported."
+  "Delete fully-qualified GROUP.
+Always updates the agent, even when disabled, as the old agent
+files would corrupt gnus when the agent was next enabled.
+Depends upon the caller to determine whether group deletion is
+supported."
   (let* ((command-method (gnus-find-method-for-group group))
         (path           (directory-file-name
                          (let (gnus-command-method command-method)
-                           (gnus-agent-group-pathname group)))))
-    (gnus-delete-file path)
+                           (gnus-agent-group-pathname group))))
+        (file-name-coding-system nnmail-pathname-coding-system))
+    (gnus-delete-directory path)
 
     (let* ((real-group (gnus-group-real-name group)))
       (gnus-agent-save-group-info command-method real-group nil)
 
-      (let ((local (gnus-agent-get-local group 
+      (let ((local (gnus-agent-get-local group
                                         real-group command-method)))
        (gnus-agent-set-local group
                              nil nil
@@ -947,7 +999,7 @@ next enabled. Depends upon the caller to determine whether group deletion is sup
     (unless (member named-server gnus-agent-covered-methods)
       (error "Server not in the agent program"))
 
-    (setq gnus-agent-covered-methods 
+    (setq gnus-agent-covered-methods
           (delete named-server gnus-agent-covered-methods)
           gnus-agent-method-p-cache nil)
 
@@ -957,7 +1009,7 @@ next enabled. Depends upon the caller to determine whether group deletion is sup
 
 (defun gnus-agent-read-servers ()
   "Read the alist of covered servers."
-  (setq gnus-agent-covered-methods 
+  (setq gnus-agent-covered-methods
         (gnus-agent-read-file
          (nnheader-concat gnus-agent-directory "lib/servers"))
         gnus-agent-method-p-cache nil)
@@ -1089,7 +1141,7 @@ article's mark is toggled."
                    ;; 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))) 
+                   (setq headers (cdr headers)))
                  ((cdar alist)
                   (setq alist (cdr alist))
                   (setq headers (cdr headers))
@@ -1098,7 +1150,7 @@ article's mark is toggled."
                  (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.
@@ -1140,20 +1192,22 @@ downloadable."
   (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.
+                (processable (sort (gnus-copy-sequence gnus-newsgroup-processable) '<))
+                 (gnus-newsgroup-downloadable processable))
+           (gnus-agent-summary-fetch-group)
 
-            ;; 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)))))
+            ;; For each article that I processed that is no longer
+            ;; undownloaded, remove its processable mark.
+
+           (mapc #'gnus-summary-remove-process-mark
+                 (gnus-sorted-ndifference gnus-newsgroup-processable gnus-newsgroup-undownloaded))
+
+            ;; The preceeding call to (gnus-agent-summary-fetch-group)
+            ;; updated the temporary gnus-newsgroup-downloadable to
+            ;; remove each article successfully fetched.  Now, I
+            ;; update the real gnus-newsgroup-downloadable to only
+            ;; include undownloaded articles.
+           (gnus-sorted-ndifference dl (gnus-sorted-ndifference processable gnus-newsgroup-undownloaded))))))
 
 (defun gnus-agent-summary-fetch-group (&optional all)
   "Fetch the downloadable articles in the group.
@@ -1176,7 +1230,7 @@ Optional arg ALL, if non-nil, means to fetch all articles."
                       gnus-newsgroup-name articles)))))
       (save-excursion
         (dolist (article articles)
-          (let ((was-marked-downloadable 
+          (let ((was-marked-downloadable
                  (memq article gnus-newsgroup-downloadable)))
             (cond (gnus-agent-mark-unread-after-downloaded
                    (setq gnus-newsgroup-downloadable
@@ -1216,8 +1270,8 @@ This can be added to `gnus-select-article-hook' or
          ;; trying to call gnus-request-set-mark, I have to
          ;; reconstruct the original group name.
          (or (gnus-get-info group)
-             (gnus-get-info 
-              (setq group (gnus-group-full-name 
+             (gnus-get-info
+              (setq group (gnus-group-full-name
                            group gnus-command-method))))))
     (gnus-request-set-mark group actions)
 
@@ -1228,14 +1282,14 @@ This can be added to `gnus-select-article-hook' or
              (marks (nth 2 action)))
          (dolist (mark marks)
            (cond ((eq mark 'read)
-                  (gnus-info-set-read 
+                  (gnus-info-set-read
                    info
                    (funcall (if (eq what 'add)
                                 'gnus-range-add
                               'gnus-remove-from-range)
                             (gnus-info-read info)
                             range))
-                  (gnus-get-unread-articles-in-group 
+                  (gnus-get-unread-articles-in-group
                    info
                    (gnus-active (gnus-info-group info))))
                  ((memq mark '(tick))
@@ -1246,7 +1300,13 @@ This can be added to `gnus-select-article-hook' or
                                  'gnus-range-add
                                'gnus-remove-from-range)
                              (cdr info-marks)
-                             range)))))))))
+                             range))))))))
+
+      ;;Marks can be synchronized at any time by simply toggling from
+      ;;unplugged to plugged.  If that is what is happening right now, make
+      ;;sure that the group buffer is up to date.
+          (when (gnus-buffer-live-p gnus-group-buffer)
+            (gnus-group-update-group group t)))
     nil))
 
 (defun gnus-agent-save-active (method)
@@ -1257,7 +1317,8 @@ This can be added to `gnus-select-article-hook' or
       (gnus-active-to-gnus-format nil new)
       (gnus-agent-write-active file new)
       (erase-buffer)
-      (nnheader-insert-file-contents file))))
+      (let ((nnheader-file-coding-system gnus-agent-file-coding-system))
+       (nnheader-insert-file-contents file)))))
 
 (defun gnus-agent-write-active (file new)
     (gnus-make-directory (file-name-directory file))
@@ -1303,11 +1364,11 @@ downloaded into the agent."
           ;; file.
 
           (let ((read (gnus-info-read info)))
-            (gnus-info-set-read 
-             info 
-             (gnus-range-add 
-              read 
-              (list (cons (1+ agent-max) 
+            (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
@@ -1370,6 +1431,18 @@ downloaded into the agent."
                     oactive-min (read (current-buffer))) ;; min
              (cons oactive-min oactive-max))))))))
 
+(defvar gnus-agent-decoded-group-names nil
+  "Alist of non-ASCII group names and decoded ones.")
+
+(defun gnus-agent-decoded-group-name (group)
+  "Return a decoded group name of GROUP."
+  (or (cdr (assoc group gnus-agent-decoded-group-names))
+      (if (string-match "[^\000-\177]" group)
+         (let ((decoded (gnus-group-decoded-name group)))
+           (push (cons group decoded) gnus-agent-decoded-group-names)
+           decoded)
+       group)))
+
 (defun gnus-agent-group-path (group)
   "Translate GROUP into a file name."
 
@@ -1380,25 +1453,26 @@ downloaded into the agent."
   (setq group
         (nnheader-translate-file-chars
          (nnheader-replace-duplicate-chars-in-string
-          (nnheader-replace-chars-in-string 
-           (gnus-group-real-name group)
+          (nnheader-replace-chars-in-string
+           (gnus-group-real-name (gnus-agent-decoded-group-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)))
+    (nnheader-replace-chars-in-string group ?. ?/)))
 
 (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))))
+  (nnmail-group-pathname
+   (gnus-group-real-name (gnus-agent-decoded-group-name group))
+   (if gnus-command-method
+       (gnus-agent-directory)
+     (let ((gnus-command-method (gnus-find-method-for-group group)))
+       (gnus-agent-directory)))))
 
 (defun gnus-agent-get-function (method)
   (if (gnus-online method)
@@ -1461,7 +1535,7 @@ downloaded into the agent."
         (unless (and (eq article (caar alist))
                      (cdar alist))
           ;; Skip headers preceeding this article
-          (while (> article 
+          (while (> article
                     (setq header-number
                           (let* ((header (car headers)))
                             (if header
@@ -1502,7 +1576,8 @@ downloaded into the agent."
                (dir (gnus-agent-group-pathname group))
                (date (time-to-days (current-time)))
                (case-fold-search t)
-               pos crosses id)
+               pos crosses id
+              (file-name-coding-system nnmail-pathname-coding-system))
 
           (setcar selected-sets (nreverse (car selected-sets)))
           (setq selected-sets (nreverse selected-sets))
@@ -1547,7 +1622,7 @@ downloaded into the agent."
                           (while (looking-at "\\([^: \n]+\\):\\([0-9]+\\) *")
                             (push (cons (buffer-substring (match-beginning 1)
                                                           (match-end 1))
-                                        (string-to-int
+                                        (string-to-number
                                         (buffer-substring (match-beginning 2)
                                                           (match-end 2))))
                                   crosses)
@@ -1579,7 +1654,7 @@ downloaded into the agent."
 (defun gnus-agent-unfetch-articles (group articles)
   "Delete ARTICLES that were fetched from GROUP into the agent."
   (when articles
-    (gnus-agent-with-refreshed-group 
+    (gnus-agent-with-refreshed-group
      group
      (gnus-agent-load-alist group)
      (let* ((alist (cons nil gnus-agent-article-alist))
@@ -1588,22 +1663,27 @@ downloaded into the agent."
            (delete-this (pop articles)))
        (while (and (cdr next-possibility) delete-this)
         (let ((have-this (caar (cdr next-possibility))))
-          (cond ((< delete-this have-this)
-                 (setq delete-this (pop articles)))
-                ((= delete-this have-this)
-                 (let ((timestamp (cdar (cdr next-possibility))))
-                   (when timestamp
-                     (let* ((file-name (concat (gnus-agent-group-pathname group)
-                                               (number-to-string have-this)))
-                            (size-file (float (or (and gnus-agent-total-fetched-hashtb
-                                                       (nth 7 (file-attributes file-name)))
-                                                  0))))
-                       (delete-file file-name)
-                       (gnus-agent-update-files-total-fetched-for group (- size-file)))))
-
-                 (setcdr next-possibility (cddr next-possibility)))
-                (t
-                 (setq next-possibility (cdr next-possibility))))))
+          (cond
+           ((< delete-this have-this)
+            (setq delete-this (pop articles)))
+           ((= delete-this have-this)
+            (let ((timestamp (cdar (cdr next-possibility))))
+              (when timestamp
+                (let* ((file-name (concat (gnus-agent-group-pathname group)
+                                          (number-to-string have-this)))
+                       (size-file
+                        (float (or (and gnus-agent-total-fetched-hashtb
+                                        (nth 7 (file-attributes file-name)))
+                                   0)))
+                       (file-name-coding-system
+                        nnmail-pathname-coding-system))
+                  (delete-file file-name)
+                  (gnus-agent-update-files-total-fetched-for
+                   group (- size-file)))))
+
+            (setcdr next-possibility (cddr next-possibility)))
+           (t
+            (setq next-possibility (cdr next-possibility))))))
        (setq gnus-agent-article-alist (cdr alist))
        (gnus-agent-save-alist group)))))
 
@@ -1629,8 +1709,9 @@ downloaded into the agent."
        (when (= (point-max) (point-min))
          (push (cons group (current-buffer)) gnus-agent-buffer-alist)
          (ignore-errors
-           (nnheader-insert-file-contents
-            (gnus-agent-article-name ".overview" group))))
+          (let ((file-name-coding-system nnmail-pathname-coding-system))
+            (nnheader-insert-file-contents
+             (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)
@@ -1641,7 +1722,8 @@ downloaded into the agent."
   (when gnus-newsgroup-name
     (let ((root (gnus-agent-article-name ".overview" gnus-newsgroup-name))
           (cnt 0)
-          name)
+          name
+         (file-name-coding-system nnmail-pathname-coding-system))
       (while (file-exists-p
              (setq name (concat root "~"
                                 (int-to-string (setq cnt (1+ cnt))) "~"))))
@@ -1693,25 +1775,71 @@ and that there are no duplicates."
              (setq prev-num cur)))
            (forward-line 1)))))))
 
+(defun gnus-agent-flush-server (&optional server-or-method)
+  "Flush all agent index files for every subscribed group within
+  the given SERVER-OR-METHOD.  When called with nil, the current
+  value of gnus-command-method identifies the server."
+  (let* ((gnus-command-method (if server-or-method
+                                 (gnus-server-to-method server-or-method)
+                               gnus-command-method))
+        (alist gnus-newsrc-alist))
+    (while alist
+      (let ((entry (pop alist)))
+       (when (gnus-methods-equal-p gnus-command-method (gnus-info-method entry))
+         (gnus-agent-flush-group (gnus-info-group entry))))))) 
+
+(defun gnus-agent-flush-group (group)
+  "Flush the agent's index files such that the GROUP no longer
+appears to have any local content.  The actual content, the
+article files, may then be deleted using gnus-agent-expire-group.
+If flushing was a mistake, the gnus-agent-regenerate-group method
+provides an undo mechanism by reconstructing the index files from
+the article files."
+  (interactive (list (gnus-agent-read-group)))
+
+  (let* ((gnus-command-method (or gnus-command-method
+                                 (gnus-find-method-for-group group)))
+        (overview (gnus-agent-article-name ".overview" group))
+        (agentview (gnus-agent-article-name ".agentview" group))
+        (file-name-coding-system nnmail-pathname-coding-system))
+
+    (if (file-exists-p overview)
+       (delete-file overview))
+    (if (file-exists-p agentview)
+       (delete-file agentview))
+
+    (gnus-agent-update-view-total-fetched-for group nil gnus-command-method)
+    (gnus-agent-update-view-total-fetched-for group t   gnus-command-method)
+
+    ;(gnus-agent-set-local group nil nil)
+    ;(gnus-agent-save-local t)
+    (gnus-agent-save-group-info nil group nil)))
+
 (defun gnus-agent-flush-cache ()
+  "Flush the agent's index files such that the group no longer
+appears to have any local content.  The actual content, the
+article files, is then deleted using gnus-agent-expire-group. The
+gnus-agent-regenerate-group method provides an undo mechanism by
+reconstructing the index files from the article files."
+  (interactive)
   (save-excursion
-    (while gnus-agent-buffer-alist
-      (set-buffer (cdar gnus-agent-buffer-alist))
-      (let ((coding-system-for-write
-            gnus-agent-file-coding-system))
-       (write-region (point-min) (point-max)
-                     (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)))))
+    (let ((file-name-coding-system nnmail-pathname-coding-system))
+      (while gnus-agent-buffer-alist
+       (set-buffer (cdar gnus-agent-buffer-alist))
+       (let ((coding-system-for-write gnus-agent-file-coding-system))
+         (write-region (point-min) (point-max)
+                       (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))))))
 
 ;;;###autoload
 (defun gnus-agent-find-parameter (group symbol)
@@ -1743,10 +1871,20 @@ article numbers will be returned."
                                (gnus-agent-find-parameter group
                                                           'agent-predicate)))))
          (articles (if fetch-all
-                       (gnus-uncompress-range (gnus-active group))
+                      (if gnus-newsgroup-maximum-articles
+                          (let ((active (gnus-active group)))
+                            (gnus-uncompress-range
+                             (cons (max (car active)
+                                        (- (cdr active)
+                                           gnus-newsgroup-maximum-articles
+                                           -1))
+                                   (cdr active))))
+                        (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)))
+        (gnus-decode-encoded-address-function 'identity)
+         (file (gnus-agent-article-name ".overview" group))
+        (file-name-coding-system nnmail-pathname-coding-system))
 
     (unless fetch-all
       ;; Add articles with marks to the list of article headers we want to
@@ -1837,7 +1975,7 @@ article numbers will be returned."
 (defsubst gnus-agent-read-article-number ()
   "Reads the article number at point.  Returns nil when a valid article number can not be read."
 
-  ;; It is unfortunite but the read function quietly overflows
+  ;; It is unfortunate but the read function quietly overflows
   ;; integer.  As a result, I have to use string operations to test
   ;; for overflow BEFORE calling read.
   (when (looking-at "[0-9]+\t")
@@ -1896,21 +2034,21 @@ doesn't exist, to valid the overview buffer."
       (gnus-agent-copy-nov-line (pop articles))
 
       (ignore-errors
-       (while articles
-        (while (let ((art (read (current-buffer))))
-                 (cond ((< art (car articles))
-                        (forward-line 1)
-