(gnus-point-at-bol, gnus-point-at-eol): Remove.
[gnus] / lisp / gnus-sum.el
index 10e2bb9..3379a64 100644 (file)
@@ -1,5 +1,5 @@
 ;;; gnus-sum.el --- summary mode commands for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -26,7 +26,9 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(eval-when-compile
+  (require 'cl)
+  (defvar tool-bar-map))
 
 (require 'gnus)
 (require 'gnus-group)
@@ -251,7 +253,12 @@ If threads are hidden, you have to run the command
 `gnus-summary-show-thread' by hand or use `gnus-select-article-hook'
 to expose hidden threads."
   :group 'gnus-thread
-  :type 'boolean)
+  :type '(radio (sexp :format "Non-nil\n"
+                     :match (lambda (widget value)
+                              (not (or (consp value) (functionp value))))
+                     :value t)
+               (const nil)
+               (sexp :tag "Predicate specifier" :size 0)))
 
 (defcustom gnus-thread-hide-killed t
   "*If non-nil, hide killed threads automatically."
@@ -321,13 +328,13 @@ place point on some subject line."
 (defcustom gnus-auto-select-next t
   "*If non-nil, offer to go to the next group from the end of the previous.
 If the value is t and the next newsgroup is empty, Gnus will exit
-summary mode and go back to group mode.         If the value is neither nil
-nor t, Gnus will select the following unread newsgroup.         In
+summary mode and go back to group mode.  If the value is neither nil
+nor t, Gnus will select the following unread newsgroup.  In
 particular, if the value is the symbol `quietly', the next unread
 newsgroup will be selected without any confirmation, and if it is
 `almost-quietly', the next group will be selected without any
 confirmation if you are located on the last article in the group.
-Finally, if this variable is `slightly-quietly', the `Z n' command
+Finally, if this variable is `slightly-quietly', the `\\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]' command
 will go to the next group without confirmation."
   :group 'gnus-summary-maneuvering
   :type '(choice (const :tag "off" nil)
@@ -343,6 +350,23 @@ the first unread article."
   :group 'gnus-summary-maneuvering
   :type 'boolean)
 
+(defcustom gnus-auto-goto-ignores 'unfetched
+  "*Says how to handle unfetched articles when maneuvering.
+
+This variable can either be the symbols nil (maneuver to any
+article), `undownloaded' (maneuvering while unplugged ignores articles
+that have not been fetched), `always-undownloaded' (maneuvering always
+ignores articles that have not been fetched), `unfetched' (maneuvering
+ignores articles whose headers have not been fetched).
+
+NOTE: The list of unfetched articles will always be nil when plugged
+and, when unplugged, a subset of the undownloaded article list."
+  :group 'gnus-summary-maneuvering
+  :type '(choice (const :tag "None" nil)
+                 (const :tag "Undownloaded when unplugged" undownloaded)
+                 (const :tag "Undownloaded" always-undownloaded)
+                 (const :tag "Unfetched" unfetched)))
+
 (defcustom gnus-summary-check-current nil
   "*If non-nil, consider the current article when moving.
 The \"unread\" movement commands will stay on the same line if the
@@ -360,6 +384,9 @@ and non-`vertical', do both horizontal and vertical recentering."
                 (integer :tag "height")
                 (sexp :menu-tag "both" t)))
 
+(defvar gnus-auto-center-group t
+  "*If non-nil, always center the group buffer.")
+
 (defcustom gnus-show-all-headers nil
   "*If non-nil, don't hide any headers."
   :group 'gnus-article-hiding
@@ -847,6 +874,21 @@ automatically when it is selected."
   :group 'gnus-summary
   :type 'hook)
 
+(defcustom gnus-summary-article-move-hook nil
+  "*A hook called after an article is moved, copied, respooled, or crossposted."
+  :group 'gnus-summary
+  :type 'hook)
+
+(defcustom gnus-summary-article-delete-hook nil
+  "*A hook called after an article is deleted."
+  :group 'gnus-summary
+  :type 'hook)
+
+(defcustom gnus-summary-article-expire-hook nil
+  "*A hook called after an article is expired."
+  :group 'gnus-summary
+  :type 'hook)
+
 (defcustom gnus-summary-display-arrow
   (and (fboundp 'display-graphic-p)
        (display-graphic-p))
@@ -914,7 +956,8 @@ default:      The default article score.
 default-high: The default score for high scored articles.
 default-low:  The default score for low scored articles.
 below:        The score below which articles are automatically marked as read.
-mark:         The articles mark."
+mark:         The article's mark.
+uncached:     Non-nil if the article is uncached."
   :group 'gnus-summary-visual
   :type '(repeat (cons (sexp :tag "Form" nil)
                       face)))
@@ -1016,15 +1059,16 @@ For example: ((1 . cn-gb-2312) (2 . big5))."
                 integer))
 
 (defcustom gnus-summary-save-parts-default-mime "image/.*"
-  "*A regexp to match MIME parts when saving multiple parts of a message
-with gnus-summary-save-parts (X m). This regexp will be used by default
-when prompting the user for which type of files to save."
+  "*A regexp to match MIME parts when saving multiple parts of a
+message with `gnus-summary-save-parts' (\\<gnus-summary-mode-map>\\[gnus-summary-save-parts]).
+This regexp will be used by default when prompting the user for which
+type of files to save."
   :group 'gnus-summary
   :type 'regexp)
 
 (defcustom gnus-read-all-available-headers nil
   "Whether Gnus should parse all headers made available to it.
-This is mostly relevant for slow backends where the user may
+This is mostly relevant for slow back ends where the user may
 wish to widen the summary buffer to include all headers
 that were fetched.  Say, for nnultimate groups."
   :group 'gnus-summary
@@ -1044,7 +1088,7 @@ Set it to non-nil, Gnus will treat some articles as MIME even if
 the MIME-Version header is missed."
   :version "21.3"
   :type 'boolean
-  :group 'gnus-article)
+  :group 'gnus-article-mime)
 
 (defcustom gnus-article-emulate-mime t
   "If non-nil, use MIME emulation for uuencode and the like.
@@ -1052,7 +1096,7 @@ This means that Gnus will search message bodies for text that look
 like uuencoded bits, yEncoded bits, and so on, and present that using
 the normal Gnus MIME machinery."
   :type 'boolean
-  :group 'gnus-article)
+  :group 'gnus-article-mime)
 
 ;;; Internal variables
 
@@ -1074,7 +1118,7 @@ the normal Gnus MIME machinery."
   "Function called to sort the articles within a thread after it has been gathered together.")
 
 (defvar gnus-summary-save-parts-type-history nil)
-(defvar gnus-summary-save-parts-last-directory nil)
+(defvar gnus-summary-save-parts-last-directory mm-default-directory)
 
 ;; Avoid highlighting in kill files.
 (defvar gnus-summary-inhibit-highlight nil)
@@ -1187,6 +1231,7 @@ the type of the variable (string, integer, character, etc).")
 (defvar gnus-newsgroup-data-reverse nil)
 (defvar gnus-newsgroup-limit nil)
 (defvar gnus-newsgroup-limits nil)
+(defvar gnus-summary-use-undownloaded-faces nil)
 
 (defvar gnus-newsgroup-unreads nil
   "Sorted list of unread articles in the current newsgroup.")
@@ -1235,10 +1280,13 @@ the type of the variable (string, integer, character, etc).")
   "Sorted list of articles in the current newsgroup that can be processed.")
 
 (defvar gnus-newsgroup-unfetched nil
-  "Sorted list of articles in the current newsgroup whose headers have not been fetched into the agent.")
+  "Sorted list of articles in the current newsgroup whose headers have
+not been fetched into the agent.
+
+This list will always be a subset of gnus-newsgroup-undownloaded.")
 
 (defvar gnus-newsgroup-undownloaded nil
-  "List of articles in the current newsgroup that haven't been downloaded..")
+  "List of articles in the current newsgroup that haven't been downloaded.")
 
 (defvar gnus-newsgroup-unsendable nil
   "List of articles in the current newsgroup that won't be sent.")
@@ -1286,7 +1334,7 @@ the type of the variable (string, integer, character, etc).")
 
 (defvar gnus-article-before-search nil)
 
-(defconst gnus-summary-local-variables
+(defvar gnus-summary-local-variables
   '(gnus-newsgroup-name
     gnus-newsgroup-begin gnus-newsgroup-end
     gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
@@ -1324,7 +1372,8 @@ the type of the variable (string, integer, character, etc).")
     gnus-cache-removable-articles gnus-newsgroup-cached
     gnus-newsgroup-data gnus-newsgroup-data-reverse
     gnus-newsgroup-limit gnus-newsgroup-limits
-    gnus-newsgroup-charset gnus-newsgroup-display)
+    gnus-newsgroup-charset gnus-newsgroup-display
+    gnus-summary-use-undownloaded-faces)
   "Variables that are buffer-local to the summary buffers.")
 
 (defvar gnus-newsgroup-variables nil
@@ -1343,9 +1392,18 @@ buffers. For example:
 ")
 
 ;; Byte-compiler warning.
-;(eval-when-compile (defvar gnus-article-mode-map))
 (eval-when-compile
+  ;; Bind features so that require will believe that gnus-sum has
+  ;; already been loaded (avoids infinite recursion)
   (let ((features (cons 'gnus-sum features)))
+    ;; Several of the declarations in gnus-sum are needed to load the
+    ;; following files. Right now, these definitions have been
+    ;; compiled but not defined (evaluated).  We could either do a
+    ;; eval-and-compile about all of the declarations or evaluate the
+    ;; source file.
+    (if (boundp 'gnus-newsgroup-variables)
+        nil
+      (load "gnus-sum.el" t t t))
     (require 'gnus)
     (require 'gnus-agent)
     (require 'gnus-art)))
@@ -1392,26 +1450,24 @@ For example:
 
 (defun gnus-simplify-whitespace (str)
   "Remove excessive whitespace from STR."
-  (let ((mystr str))
-    ;; Multiple spaces.
-    (while (string-match "[ \t][ \t]+" mystr)
-      (setq mystr (concat (substring mystr 0 (match-beginning 0))
-                         " "
-                         (substring mystr (match-end 0)))))
-    ;; Leading spaces.
-    (when (string-match "^[ \t]+" mystr)
-      (setq mystr (substring mystr (match-end 0))))
-    ;; Trailing spaces.
-    (when (string-match "[ \t]+$" mystr)
-      (setq mystr (substring mystr 0 (match-beginning 0))))
-    mystr))
+  ;; Multiple spaces.
+  (while (string-match "[ \t][ \t]+" str)
+    (setq str (concat (substring str 0 (match-beginning 0))
+                       " "
+                       (substring str (match-end 0)))))
+  ;; Leading spaces.
+  (when (string-match "^[ \t]+" str)
+    (setq str (substring str (match-end 0))))
+  ;; Trailing spaces.
+  (when (string-match "[ \t]+$" str)
+    (setq str (substring str 0 (match-beginning 0))))
+  str)
 
 (defun gnus-simplify-all-whitespace (str)
   "Remove all whitespace from STR."
-  (let ((mystr str))
-    (while (string-match "[ \t\n]+" mystr)
-      (setq mystr (replace-match "" nil nil mystr)))
-    mystr))
+  (while (string-match "[ \t\n]+" str)
+    (setq str (replace-match "" nil nil str)))
+  str)
 
 (defsubst gnus-simplify-subject-re (subject)
   "Remove \"Re:\" from subject lines."
@@ -1489,7 +1545,7 @@ See `gnus-simplify-buffer-fuzzy' for details."
       (buffer-string))))
 
 (defsubst gnus-simplify-subject-fully (subject)
-  "Simplify a subject string according to gnus-summary-gather-subject-limit."
+  "Simplify a subject string according to `gnus-summary-gather-subject-limit'."
   (cond
    (gnus-simplify-subject-functions
     (gnus-map-function gnus-simplify-subject-functions subject))
@@ -1505,7 +1561,7 @@ See `gnus-simplify-buffer-fuzzy' for details."
 
 (defsubst gnus-subject-equal (s1 s2 &optional simple-first)
   "Check whether two subjects are equal.
-If optional argument simple-first is t, first argument is already
+If optional argument SIMPLE-FIRST is t, first argument is already
 simplified."
   (cond
    ((null simple-first)
@@ -2049,8 +2105,24 @@ increase the score of each group you read."
              ["View MIME buttons" gnus-summary-display-buttonized t]
              ["View all" gnus-mime-view-all-parts t]
              ["Verify and Decrypt" gnus-summary-force-verify-and-decrypt t]
-             ["Encrypt body" gnus-article-encrypt-body t]
-             ["Extract all parts" gnus-summary-save-parts t])
+             ["Encrypt body" gnus-article-encrypt-body
+              :active (not (gnus-group-read-only-p))
+              ,@(if (featurep 'xemacs) nil
+                  '(:help "Encrypt the message body on disk"))]
+             ["Extract all parts..." gnus-summary-save-parts t]
+             ("Multipart"
+              ["Repair multipart" gnus-summary-repair-multipart t]
+              ["Pipe part..." gnus-article-pipe-part t]
+              ["Inline part" gnus-article-inline-part t]
+              ["Encrypt body" gnus-article-encrypt-body
+               :active (not (gnus-group-read-only-p))
+              ,@(if (featurep 'xemacs) nil
+                  '(:help "Encrypt the message body on disk"))]
+              ["View part externally" gnus-article-view-part-externally t]
+              ["View part with charset..." gnus-article-view-part-as-charset t]
+              ["Copy part" gnus-article-copy-part t]
+              ["Save part..." gnus-article-save-part t]
+              ["View part" gnus-article-view-part t]))
             ("Date"
              ["Local" gnus-article-date-local t]
              ["ISO8601" gnus-article-date-iso8601 t]
@@ -2069,9 +2141,9 @@ increase the score of each group you read."
               ,@(gnus-summary-menu-split
                  (mapcar
                   (lambda (cs)
-                    ;; Since easymenu under FSF Emacs doesn't allow lambda
-                    ;; forms for menu commands, we should provide intern'ed
-                    ;; function symbols.
+                    ;; Since easymenu under Emacs doesn't allow
+                    ;; lambda forms for menu commands, we should
+                    ;; provide intern'ed function symbols.
                     (let ((command (intern (format "\
 gnus-summary-show-article-from-menu-as-charset-%s" cs))))
                       (fset command
@@ -2102,7 +2174,7 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
              ["Word wrap" gnus-article-fill-cited-article t]
              ["Fill long lines" gnus-article-fill-long-lines t]
              ["Capitalize sentences" gnus-article-capitalize-sentences t]
-             ["CR" gnus-article-remove-cr t]
+             ["Remove CR" gnus-article-remove-cr t]
              ["Quoted-Printable" gnus-article-de-quoted-unreadable t]
              ["Base64" gnus-article-de-base64-unreadable t]
              ["Rot 13" gnus-summary-caesar-message
@@ -2118,9 +2190,9 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
              ["Unfold headers" gnus-article-treat-unfold-headers t]
              ["Fold newsgroups" gnus-article-treat-fold-newsgroups t]
              ["Html" gnus-article-wash-html t]
-             ["URLs" gnus-article-unsplit-urls t]
+             ["Unsplit URLs" gnus-article-unsplit-urls t]
              ["Verify X-PGP-Sig" gnus-article-verify-x-pgp-sig t]
-             ["HZ" gnus-article-decode-HZ t]
+             ["Decode HZ" gnus-article-decode-HZ t]
              ("(Outlook) Deuglify"
               ["Unwrap lines" gnus-article-outlook-unwrap-lines t]
               ["Repair attribution" gnus-article-outlook-repair-attribution t]
@@ -2129,20 +2201,20 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
                gnus-article-outlook-deuglify-article t])
              )
             ("Output"
-             ["Save in default format" gnus-summary-save-article
+             ["Save in default format..." gnus-summary-save-article
               ,@(if (featurep 'xemacs) '(t)
                   '(:help "Save article using default method"))]
-             ["Save in file" gnus-summary-save-article-file
+             ["Save in file..." gnus-summary-save-article-file
               ,@(if (featurep 'xemacs) '(t)
                   '(:help "Save article in file"))]
-             ["Save in Unix mail format" gnus-summary-save-article-mail t]
-             ["Save in MH folder" gnus-summary-save-article-folder t]
-             ["Save in VM folder" gnus-summary-save-article-vm t]
-             ["Save in RMAIL mbox" gnus-summary-save-article-rmail t]
-             ["Save body in file" gnus-summary-save-article-body-file t]
-             ["Pipe through a filter" gnus-summary-pipe-output t]
+             ["Save in Unix mail format..." gnus-summary-save-article-mail t]
+             ["Save in MH folder..." gnus-summary-save-article-folder t]
+             ["Save in VM folder..." gnus-summary-save-article-vm t]
+             ["Save in RMAIL mbox..." gnus-summary-save-article-rmail t]
+             ["Save body in file..." gnus-summary-save-article-body-file t]
+             ["Pipe through a filter..." gnus-summary-pipe-output t]
              ["Add to SOUP packet" gnus-soup-add-article t]
-             ["Print with Muttprint" gnus-summary-muttprint t]
+             ["Print with Muttprint..." gnus-summary-muttprint t]
              ["Print" gnus-summary-print-article t])
             ("Backend"
              ["Respool article..." gnus-summary-respool-article t]
@@ -2153,8 +2225,12 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
              ["Crosspost article..." gnus-summary-crosspost-article
               (gnus-check-backend-function
                'request-replace-article gnus-newsgroup-name)]
-             ["Import file..." gnus-summary-import-article t]
-             ["Create article..." gnus-summary-create-article t]
+             ["Import file..." gnus-summary-import-article
+              (gnus-check-backend-function
+               'request-accept-article gnus-newsgroup-name)]
+             ["Create article..." gnus-summary-create-article
+              (gnus-check-backend-function
+               'request-accept-article gnus-newsgroup-name)]
              ["Check if posted" gnus-summary-article-posted-p t]
              ["Edit article" gnus-summary-edit-article
               (not (gnus-group-read-only-p))]
@@ -2296,7 +2372,7 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
         ["Catchup all" gnus-summary-catchup-all t]
         ["Catchup to here" gnus-summary-catchup-to-here t]
         ["Catchup from here" gnus-summary-catchup-from-here t]
-        ["Catchup region" gnus-summary-mark-region-as-read 
+        ["Catchup region" gnus-summary-mark-region-as-read
          (gnus-mark-active-p)]
         ["Mark excluded" gnus-summary-limit-mark-excluded-as-read t])
        ("Mark Various"
@@ -2344,7 +2420,8 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
          ["Kill" gnus-summary-kill-process-mark t]
          ["Yank" gnus-summary-yank-process-mark
           gnus-newsgroup-process-stack]
-         ["Save" gnus-summary-save-process-mark t]))
+         ["Save" gnus-summary-save-process-mark t]
+         ["Run command on marked..." gnus-summary-universal-argument t]))
        ("Scroll article"
         ["Page forward" gnus-summary-next-page
          ,@(if (featurep 'xemacs) '(t)
@@ -2399,7 +2476,7 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
        ["See old articles" gnus-summary-insert-old-articles t]
        ["See new articles" gnus-summary-insert-new-articles t]
        ["Filter articles..." gnus-summary-execute-command t]
-       ["Run command on subjects..." gnus-summary-universal-argument t]
+       ["Run command on articles..." gnus-summary-universal-argument t]
        ["Search articles forward..." gnus-summary-search-article-forward t]
        ["Search articles backward..." gnus-summary-search-article-backward t]
        ["Toggle line truncation" gnus-summary-toggle-truncation t]
@@ -2572,7 +2649,7 @@ and backwards while displaying articles, type `\\[gnus-summary-next-unread-artic
 respectively.
 
 You can also post articles and send mail from this buffer.  To
-follow up an article, type `\\[gnus-summary-followup]'.         To mail a reply to the author
+follow up an article, type `\\[gnus-summary-followup]'.  To mail a reply to the author
 of an article, type `\\[gnus-summary-reply]'.
 
 There are approx. one gazillion commands you can execute in this
@@ -2608,7 +2685,7 @@ The following commands are available:
   (make-local-variable 'gnus-summary-dummy-line-format)
   (make-local-variable 'gnus-summary-dummy-line-format-spec)
   (make-local-variable 'gnus-summary-mark-positions)
-  (make-local-hook 'pre-command-hook)
+  (gnus-make-local-hook 'pre-command-hook)
   (add-hook 'pre-command-hook 'gnus-set-global-variables nil t)
   (gnus-run-hooks 'gnus-summary-mode-hook)
   (turn-on-gnus-mailing-list-mode)
@@ -3007,10 +3084,6 @@ display only a single character."
                                               (point)
                                               (current-buffer))))))
 
-(defun gnus-summary-buffer-name (group)
-  "Return the summary buffer name of GROUP."
-  (concat "*Summary " (gnus-group-decoded-name group) "*"))
-
 (defun gnus-summary-setup-buffer (group)
   "Initialize summary buffer."
   (let ((buffer (gnus-summary-buffer-name group))
@@ -3221,7 +3294,7 @@ buffer that was in action when the last article was fetched."
                 gnus-unseen-mark)
                (t gnus-no-mark)))
         (gnus-tmp-downloaded
-         (cond (undownloaded 
+         (cond (undownloaded
                  gnus-undownloaded-mark)
                 (gnus-newsgroup-agentized
                  gnus-downloaded-mark)
@@ -3249,7 +3322,7 @@ buffer that was in action when the last article was fetched."
       (setq gnus-tmp-lines -1))
     (if (= gnus-tmp-lines -1)
        (setq gnus-tmp-lines "?")
-      (setq gnus-tmp-lines (number-to-string gnus-tmp-lines))) 
+      (setq gnus-tmp-lines (number-to-string gnus-tmp-lines)))
       (gnus-put-text-property
      (point)
      (progn (eval gnus-summary-line-format-spec) (point))
@@ -3323,7 +3396,7 @@ the thread are to be displayed."
 (defsubst gnus-summary-line-message-size (head)
   "Return pretty-printed version of message size.
 This function is intended to be used in
-`gnus-summary-line-format-alist', which see."
+`gnus-summary-line-format-alist'."
   (let ((c (or (mail-header-chars head) -1)))
     (cond ((< c 0) "n/a")              ; chars not available
          ((< c (* 1000 10)) (format "%1.1fk" (/ c 1024.0)))
@@ -3519,7 +3592,8 @@ If NO-DISPLAY, don't generate a summary buffer."
          (gnus-summary-position-point)
          (gnus-configure-windows 'summary 'force)
          (gnus-set-mode-line 'summary))
-       (when (get-buffer-window gnus-group-buffer t)
+       (when (and gnus-auto-center-group
+                  (get-buffer-window gnus-group-buffer t))
          ;; Gotta use windows, because recenter does weird stuff if
          ;; the current buffer ain't the displayed window.
          (let ((owin (selected-window)))
@@ -3549,7 +3623,7 @@ If NO-DISPLAY, don't generate a summary buffer."
    ((eq gnus-auto-select-subject 'first)
     ;; Do nothing.
     )
-   ((gnus-functionp gnus-auto-select-subject)
+   ((functionp gnus-auto-select-subject)
     (funcall gnus-auto-select-subject))))
 
 (defun gnus-summary-prepare ()
@@ -3576,7 +3650,7 @@ If NO-DISPLAY, don't generate a summary buffer."
     (gnus-run-hooks 'gnus-summary-prepare-hook)))
 
 (defsubst gnus-general-simplify-subject (subject)
-  "Simply subject by the same rules as gnus-gather-threads-by-subject."