* nnrss.el (nnrss-decode-entities-unibyte-string): Use `buffer-string'.
[gnus] / lisp / gnus-art.el
index 3e67c59..1af0325 100644 (file)
@@ -185,6 +185,8 @@ Possible values in this list are:
   'empty       Headers with no content.
   'newsgroups  Newsgroup identical to Gnus group.
   'to-address  To identical to To-address.
+  'to-list     To identical to To-list.
+  'cc-list     CC identical to To-list.
   'followup-to Followup-to identical to Newsgroups.
   'reply-to    Reply-to identical to From.
   'date        Date less than four days old.
@@ -193,6 +195,8 @@ Possible values in this list are:
   :type '(set (const :tag "Headers with no content." empty)
              (const :tag "Newsgroups identical to Gnus group." newsgroups)
              (const :tag "To identical to To-address." to-address)
+             (const :tag "To identical to To-list." to-list)
+             (const :tag "CC identical to To-list." cc-list)
              (const :tag "Followup-to identical to Newsgroups." followup-to)
              (const :tag "Reply-to identical to From." reply-to)
              (const :tag "Date less than four days old." date)
@@ -200,6 +204,15 @@ Possible values in this list are:
              (const :tag "Multiple To and/or Cc headers." many-to))
   :group 'gnus-article-hiding)
 
+(defcustom gnus-article-skip-boring nil
+  "Skip over text that is not worth reading.
+By default, if you set this t, then Gnus will display citations and
+signatures, but will never scroll down to show you a page consisting
+only of boring text.  Boring text is controlled by
+`gnus-article-boring-faces'."
+  :type 'boolean
+  :group 'gnus-article-hiding)
+
 (defcustom gnus-signature-separator '("^-- $" "^-- *$")
   "Regexp matching signature separator.
 This can also be a list of regexps.  In that case, it will be checked
@@ -544,10 +557,9 @@ The following additional specs are available:
   :type 'hook
   :group 'gnus-article-various)
 
-(defcustom gnus-article-hide-pgp-hook nil
-  "*A hook called after successfully hiding a PGP signature."
-  :type 'hook
-  :group 'gnus-article-various)
+(defvar gnus-article-hide-pgp-hook nil)
+(make-obsolete-variable 'gnus-article-hide-pgp-hook 
+                       "This variable is obsolete in Gnus 5.10.")
 
 (defcustom gnus-article-button-face 'bold
   "Face used for highlighting buttons in the article buffer.
@@ -792,7 +804,7 @@ This is meant for people who want to view first matched part.
 For `undisplayed-alternative' (default), the first undisplayed
 part or alternative part is used.  For `undisplayed', the first
 undisplayed part is used.  For a function, the first part which
-the function return `t' is used.  For `nil', the first part is
+the function return t is used.  For nil, the first part is
 used."
   :version "21.1"
   :group 'gnus-article-mime
@@ -966,13 +978,8 @@ See Info node `(gnus)Customizing Articles' for details."
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
 
-(defcustom gnus-treat-strip-pgp t
-  "Strip PGP signatures.
-Valid values are nil, t, `head', `last', an integer or a predicate.
-See Info node `(gnus)Customizing Articles' for details."
-  :group 'gnus-article-treat
-  :link '(custom-manual "(gnus)Customizing Articles")
-  :type gnus-article-treat-custom)
+(make-obsolete-variable 'gnus-treat-strip-pgp 
+                       "This option is obsolete in Gnus 5.10.")
 
 (defcustom gnus-treat-strip-pem nil
   "Strip PEM signatures.
@@ -1170,17 +1177,6 @@ See Info node `(gnus)Customizing Articles' and Info node
   :type gnus-article-treat-head-custom)
 (put 'gnus-treat-display-xface 'highlight t)
 
-(defcustom gnus-treat-display-grey-xface
-  (and (not noninteractive)
-       (string-match "^0x" (shell-command-to-string "uncompface"))
-       t)
-  "Display grey X-Face headers.
-Valid values are nil, t."
-  :group 'gnus-article-treat
-  :version "21.3"
-  :type 'boolean)
-(put 'gnus-treat-display-grey-xface 'highlight t)
-
 (defcustom gnus-treat-display-smileys
   (if (or (and (featurep 'xemacs)
               (featurep 'xpm))
@@ -1359,7 +1355,6 @@ It is a string, such as \"PGP\". If nil, ask user."
     (gnus-treat-hide-signature gnus-article-hide-signature)
     (gnus-treat-strip-list-identifiers gnus-article-hide-list-identifiers)
     (gnus-treat-leading-whitespace gnus-article-remove-leading-whitespace)
-    (gnus-treat-strip-pgp gnus-article-hide-pgp)
     (gnus-treat-strip-pem gnus-article-hide-pem)
     (gnus-treat-from-picon gnus-treat-from-picon)
     (gnus-treat-mail-picon gnus-treat-mail-picon)
@@ -1593,7 +1588,7 @@ always hide."
              (while (re-search-forward "^[^: \t]+:[ \t]*\n[^ \t]" nil t)
                (forward-line -1)
                (gnus-article-hide-text-type
-                (progn (beginning-of-line) (point))
+                (gnus-point-at-bol)
                 (progn
                   (end-of-line)
                   (if (re-search-forward "^[^ \t]" nil t)
@@ -1622,6 +1617,32 @@ always hide."
                              (nth 1 (mail-extract-address-components to))
                              to-address)))
                  (gnus-article-hide-header "to"))))
+            ((eq elem 'to-list)
+             (let ((to (message-fetch-field "to"))
+                   (to-list
+                    (gnus-parameter-to-list
+                     (if (boundp 'gnus-newsgroup-name)
+                         gnus-newsgroup-name ""))))
+               (when (and to to-list
+                          (ignore-errors
+                            (gnus-string-equal
+                             ;; only one address in To
+                             (nth 1 (mail-extract-address-components to))
+                             to-list)))
+                 (gnus-article-hide-header "to"))))
+            ((eq elem 'cc-list)
+             (let ((cc (message-fetch-field "cc"))
+                   (to-list
+                    (gnus-parameter-to-list
+                     (if (boundp 'gnus-newsgroup-name)
+                         gnus-newsgroup-name ""))))
+               (when (and cc to-list
+                          (ignore-errors
+                            (gnus-string-equal
+                             ;; only one address in CC
+                             (nth 1 (mail-extract-address-components cc))
+                             to-list)))
+                 (gnus-article-hide-header "cc"))))
             ((eq elem 'followup-to)
              (when (gnus-string-equal
                     (message-fetch-field "followup-to")
@@ -1683,7 +1704,7 @@ always hide."
     (goto-char (point-min))
     (when (re-search-forward (concat "^" header ":") nil t)
       (gnus-article-hide-text-type
-       (progn (beginning-of-line) (point))
+       (gnus-point-at-bol)
        (progn
         (end-of-line)
         (if (re-search-forward "^[^ \t]" nil t)
@@ -1799,7 +1820,7 @@ unfolded."
       (while (not (eobp))
        (save-restriction
          (mail-header-narrow-to-field)
-         (let ((header (buffer-substring (point-min) (point-max))))
+         (let ((header (buffer-string)))
            (with-temp-buffer
              (insert header)
              (goto-char (point-min))
@@ -1935,11 +1956,7 @@ unfolded."
   "Display any Face headers in the header."
   (interactive)
   (gnus-with-article-headers
-    (let ((face nil))
-      (save-excursion
-       (when (gnus-buffer-live-p gnus-original-article-buffer)
-         (set-buffer gnus-original-article-buffer)
-         (setq face (message-fetch-field "face"))))
+    (let ((face (message-fetch-field "face")))
       (when face
        (let ((png (gnus-convert-face-to-png face))
              image)
@@ -1966,7 +1983,7 @@ unfolded."
          ;; instead.
          (gnus-delete-images 'xface)
        ;; Display X-Faces.
-       (let (x-faces from face grey)
+       (let (x-faces from face)
          (save-excursion
            (when (and wash-face-p
                       (progn
@@ -1980,67 +1997,39 @@ unfolded."
              (set-buffer gnus-original-article-buffer))
            (save-restriction
              (mail-narrow-to-head)
-             (if gnus-treat-display-grey-xface
-                 (progn
-                   (while (gnus-article-goto-header "X-Face\\(-[0-9]+\\)?")
-                     (if (match-beginning 2)
-                         (progn
-                           (setq grey t)
-                           (push (cons (- (string-to-number (match-string 2)))
-                                       (mail-header-field-value))
-                                 x-faces))
-                       (push (cons 0 (mail-header-field-value)) x-faces)))
-                   (dolist (x-face (prog1
-                                       (if grey
-                                           (sort x-faces 'car-less-than-car)
-                                         (nreverse x-faces))
-                                     (setq x-faces nil)))
-                     (push (cdr x-face) x-faces)))
-               (while (gnus-article-goto-header "X-Face")
-                 (push (mail-header-field-value) x-faces)))
+             (while (gnus-article-goto-header "X-Face")
+               (push (mail-header-field-value) x-faces))
              (setq from (message-fetch-field "from"))))
-         (if grey
-             (let ((xpm (gnus-convert-gray-x-face-to-xpm x-faces))
-                   image)
-               (when xpm
-                 (setq image (gnus-create-image xpm 'xpm t))
-                 (gnus-article-goto-header "from")
-                 (when (bobp)
-                   (insert "From: [no `from' set]\n")
-                   (forward-char -17))
-                 (gnus-add-wash-type 'xface)
-                 (gnus-add-image 'xface image)
-                 (gnus-put-image image)))
-           ;; Sending multiple EOFs to xv doesn't work, so we only do a
-           ;; single external face.
-           (when (stringp gnus-article-x-face-command)
-             (setq x-faces (list (car x-faces))))
-           (while (and (setq face (pop x-faces))
-                       gnus-article-x-face-command
-                       (or force
-                           ;; Check whether this face is censored.
-                           (not gnus-article-x-face-too-ugly)
-                           (and gnus-article-x-face-too-ugly from
-                                (not (string-match gnus-article-x-face-too-ugly
-                                                   from)))))
-             ;; We display the face.
-             (if (symbolp gnus-article-x-face-command)
-                 ;; The command is a lisp function, so we call it.
-                 (if (gnus-functionp gnus-article-x-face-command)
-                     (funcall gnus-article-x-face-command face)
-                   (error "%s is not a function" gnus-article-x-face-command))
-               ;; The command is a string, so we interpret the command
-               ;; as a, well, command, and fork it off.
-               (let ((process-connection-type nil))
-                 (process-kill-without-query
-                  (start-process
-                   "article-x-face" nil shell-file-name shell-command-switch
-                   gnus-article-x-face-command))
-                 (with-temp-buffer
-                   (insert face)
-                   (process-send-region "article-x-face"
-                                        (point-min) (point-max)))
-                 (process-send-eof "article-x-face"))))))))))
+         ;; Sending multiple EOFs to xv doesn't work, so we only do a
+         ;; single external face.
+         (when (stringp gnus-article-x-face-command)
+           (setq x-faces (list (car x-faces))))
+         (while (and (setq face (pop x-faces))
+                     gnus-article-x-face-command
+                     (or force
+                         ;; Check whether this face is censored.
+                         (not gnus-article-x-face-too-ugly)
+                         (and gnus-article-x-face-too-ugly from
+                              (not (string-match gnus-article-x-face-too-ugly
+                                                 from)))))
+           ;; We display the face.
+           (if (symbolp gnus-article-x-face-command)
+               ;; The command is a lisp function, so we call it.
+               (if (gnus-functionp gnus-article-x-face-command)
+                   (funcall gnus-article-x-face-command face)
+                 (error "%s is not a function" gnus-article-x-face-command))
+             ;; The command is a string, so we interpret the command
+             ;; as a, well, command, and fork it off.
+             (let ((process-connection-type nil))
+               (process-kill-without-query
+                (start-process
+                 "article-x-face" nil shell-file-name shell-command-switch
+                 gnus-article-x-face-command))
+               (with-temp-buffer
+                 (insert face)
+                 (process-send-region "article-x-face"
+                                      (point-min) (point-max)))
+               (process-send-eof "article-x-face")))))))))
 
 (defun article-decode-mime-words ()
   "Decode all MIME-encoded words in the article."
@@ -2312,42 +2301,6 @@ The `gnus-list-identifiers' variable specifies what to do."
                 "^Subject: +\\(\\(R[Ee]: +\\)+\\)R[Ee]: +" nil t)
            (delete-region (match-beginning 1) (match-end 1))))))))
 
-(defun article-hide-pgp ()
-  "Remove any PGP headers and signatures in the current article."
-  (interactive)
-  (save-excursion
-    (save-restriction
-      (let ((inhibit-point-motion-hooks t)
-           buffer-read-only beg end)
-       (article-goto-body)
-       ;; Hide the "header".
-       (when (re-search-forward "^-----BEGIN PGP SIGNED MESSAGE-----\n" nil t)
-         (gnus-add-wash-type 'pgp)
-         (delete-region (match-beginning 0) (match-end 0))
-         ;; Remove armor headers (rfc2440 6.2)
-         (delete-region (point) (or (re-search-forward "^[ \t]*\n" nil t)
-                                    (point)))
-         (setq beg (point))
-         ;; Hide the actual signature.
-         (and (search-forward "\n-----BEGIN PGP SIGNATURE-----\n" nil t)
-              (setq end (1+ (match-beginning 0)))
-              (delete-region
-               end
-               (if (search-forward "\n-----END PGP SIGNATURE-----\n" nil t)
-                   (match-end 0)
-                 ;; Perhaps we shouldn't hide to the end of the buffer
-                 ;; if there is no end to the signature?
-                 (point-max))))
-         ;; Hide "- " PGP quotation markers.
-         (when (and beg end)
-           (narrow-to-region beg end)
-           (goto-char (point-min))
-           (while (re-search-forward "^- " nil t)
-             (delete-region
-              (match-beginning 0) (match-end 0)))
-           (widen))
-         (gnus-run-hooks 'gnus-article-hide-pgp-hook))))))
-
 (defun article-hide-pem (&optional arg)
   "Toggle hiding of any PEM headers and signatures in the current article.
 If given a negative prefix, always show; if given a positive prefix,
@@ -2376,43 +2329,50 @@ always hide."
             (match-beginning 0) (match-end 0) 'pem)))))))
 
 (defun article-strip-banner ()
-  "Strip the banner specified by the `banner' group parameter."
+  "Strip the banners specified by the `banner' group parameter and by
+`gnus-article-address-banner-alist'."
   (interactive)
+  (save-excursion
+    (save-restriction
+      (let ((inhibit-point-motion-hooks t))
+       (when (gnus-parameter-banner gnus-newsgroup-name)
+         (article-really-strip-banner
+          (gnus-parameter-banner gnus-newsgroup-name)))
+       (when gnus-article-address-banner-alist
+         (article-really-strip-banner
+          (let ((from (save-restriction
+                        (widen)
+                        (article-narrow-to-head)
+                        (mail-fetch-field "from"))))
+            (when (and from
+                       (setq from
+                             (caar (mail-header-parse-addresses from))))
+              (catch 'found
+                (dolist (pair gnus-article-address-banner-alist)
+                  (when (string-match (car pair) from)
+                    (throw 'found (cdr pair)))))))))))))
+
+(defun article-really-strip-banner (banner)
+  "Strip the banner specified by the argument."
   (save-excursion
     (save-restriction
       (let ((inhibit-point-motion-hooks t)
-           (banner (gnus-parameter-banner gnus-newsgroup-name))
            (gnus-signature-limit nil)
-           buffer-read-only beg end)
-       (when (and gnus-article-address-banner-alist
-                  (not banner))
-         (setq banner
-               (let ((from (save-restriction
-                             (widen)
-                             (article-narrow-to-head)
-                             (mail-fetch-field "from"))))
-                 (when (and from
-                            (setq from
-                                  (caar (mail-header-parse-addresses from))))
-                   (catch 'found
-                     (dolist (pair gnus-article-address-banner-alist)
-                       (when (string-match (car pair) from)
-                         (throw 'found (cdr pair)))))))))
-       (when banner
-         (article-goto-body)
-         (cond
-          ((eq banner 'signature)
-           (when (gnus-article-narrow-to-signature)
-             (widen)
-             (forward-line -1)
-             (delete-region (point) (point-max))))
-          ((symbolp banner)
-           (if (setq banner (cdr (assq banner gnus-article-banner-alist)))
-               (while (re-search-forward banner nil t)
-                 (delete-region (match-beginning 0) (match-end 0)))))
-          ((stringp banner)
-           (while (re-search-forward banner nil t)
-             (delete-region (match-beginning 0) (match-end 0))))))))))
+           buffer-read-only)
+       (article-goto-body)
+       (cond
+        ((eq banner 'signature)
+         (when (gnus-article-narrow-to-signature)
+           (widen)
+           (forward-line -1)
+           (delete-region (point) (point-max))))
+        ((symbolp banner)
+         (if (setq banner (cdr (assq banner gnus-article-banner-alist)))
+             (while (re-search-forward banner nil t)
+               (delete-region (match-beginning 0) (match-end 0)))))
+        ((stringp banner)
+         (while (re-search-forward banner nil t)
+           (delete-region (match-beginning 0) (match-end 0)))))))))
 
 (defun article-babel ()
   "Translate article using an online translation service."
@@ -3133,6 +3093,7 @@ Directory to save to is default to `gnus-article-save-directory'."
       (save-restriction
        (widen)
        (if (and (file-readable-p filename)
+                (file-regular-p filename)
                 (mail-file-babyl-p filename))
            (rmail-output-to-rmail-file filename t)
          (gnus-output-to-mail filename)))))
@@ -3394,7 +3355,6 @@ If variable `gnus-use-long-file-name' is non-nil, it is
      article-wash-html
      article-unsplit-urls
      article-hide-list-identifiers
-     article-hide-pgp
      article-strip-banner
      article-babel
      article-hide-pem
@@ -3497,9 +3457,6 @@ If variable `gnus-use-long-file-name' is non-nil, it is
 
     (gnus-run-hooks 'gnus-article-menu-hook)))
 
-;; Fixme: do something for the Emacs tool bar in Article mode a la
-;; Summary.
-
 (defun gnus-article-mode ()
   "Major mode for displaying an article.
 
@@ -3522,7 +3479,9 @@ commands:
   (make-local-variable 'minor-mode-alist)
   (use-local-map gnus-article-mode-map)
   (when (gnus-visual-p 'article-menu 'menu)
-    (gnus-article-make-menu-bar))
+    (gnus-article-make-menu-bar)
+    (when gnus-summary-tool-bar-map
+      (set (make-local-variable 'tool-bar-map) gnus-summary-tool-bar-map)))
   (gnus-update-format-specifications nil 'article-mode)
   (set (make-local-variable 'page-delimiter) gnus-page-delimiter)
   (make-local-variable 'gnus-page-broken)
@@ -3583,6 +3542,8 @@ commands:
          (setq gnus-article-mime-handle-alist nil)
          (buffer-disable-undo)
          (setq buffer-read-only t)
+         ;; This list just keeps growing if we don't reset it.
+         (setq gnus-button-marker-list nil)
          (unless (eq major-mode 'gnus-article-mode)
            (gnus-article-mode))
          (current-buffer))
@@ -3641,7 +3602,9 @@ If ALL-HEADERS is non-nil, no headers are hidden."
                      (cons gnus-newsgroup-name article))
                (set-buffer gnus-summary-buffer)
                (setq gnus-current-article article)
-               (if (memq article gnus-newsgroup-undownloaded)
+               (if (and (memq article gnus-newsgroup-undownloaded)
+                        (not (gnus-online (gnus-find-method-for-group
+                                           gnus-newsgroup-name))))
                    (progn
                      (gnus-summary-set-agent-mark article)
                      (message "Message marked for downloading"))
@@ -3777,7 +3740,7 @@ General format specifiers can also be used.  See Info node
     (gnus-mime-view-part-externally "e" "View Externally")
     (gnus-mime-print-part "p" "Print")
     (gnus-mime-pipe-part "|" "Pipe To Command...")
-    (gnus-mime-action-on-part "." "Take action on the part")))
+    (gnus-mime-action-on-part "." "Take action on the part...")))
 
 (defun gnus-article-mime-part-status ()
   (if gnus-article-mime-handle-alist-1
@@ -3797,21 +3760,36 @@ General format specifiers can also be used.  See Info node
       (define-key map (cadr c) (car c)))
     map))
 
-(defun gnus-mime-button-menu (event)
-  "Construct a context-sensitive menu of MIME commands."
-  (interactive "e")
-  (save-window-excursion
-    (let ((pos (event-start event)))
-      (select-window (posn-window pos))
-      (goto-char (posn-point pos))
-      (gnus-article-check-buffer)
-      (let ((response (x-popup-menu
-                      t `("MIME Part"
-                          ("" ,@(mapcar (lambda (c)
-                                          (cons (caddr c) (car c)))
-                                        gnus-mime-button-commands))))))
-       (if response
-           (call-interactively response))))))
+(easy-menu-define gnus-mime-button-menu gnus-mime-button-map "MIME button menu."
+  `("MIME Part"
+    ,@(mapcar (lambda (c)
+               (vector (caddr c) (car c) :enable t)) gnus-mime-button-commands)))
+
+(eval-when-compile
+  (define-compiler-macro popup-menu (&whole form
+                                           menu &optional position prefix)
+    (if (and (fboundp 'popup-menu)
+            (not (memq 'popup-menu (assoc "lmenu" load-history))))
+       form
+      ;; Gnus is probably running under Emacs 20.
+      `(let* ((menu (cdr ,menu))
+             (response (x-popup-menu
+                        t (list (car menu)
+                                (cons "" (mapcar (lambda (c)
+                                                   (cons (caddr c) (car c)))
+                                                 (cdr menu)))))))
+        (if response
+            (call-interactively (nth 3 (assq response menu))))))))
+
+(defun gnus-mime-button-menu (event prefix)
+ "Construct a context-sensitive menu of MIME commands."
+ (interactive "e\nP")
+ (save-window-excursion
+   (let ((pos (event-start event)))
+     (select-window (posn-window pos))
+     (goto-char (posn-point pos))
+     (gnus-article-check-buffer)
+     (popup-menu gnus-mime-button-menu nil prefix))))
 
 (defun gnus-mime-view-all-parts (&optional handles)
   "View all the MIME parts."
@@ -4118,7 +4096,8 @@ If no internal viewer is available, use an external viewer."
         (mail-parse-charset gnus-newsgroup-charset)
         (mail-parse-ignored-charsets
          (save-excursion (set-buffer gnus-summary-buffer)
-                         gnus-newsgroup-ignored-charsets)))
+                         gnus-newsgroup-ignored-charsets))
+        buffer-read-only)
     (when handle
       (if (mm-handle-undisplayer handle)
          (mm-remove-part handle)
@@ -4127,7 +4106,7 @@ If no internal viewer is available, use an external viewer."
 (defun gnus-mime-action-on-part (&optional action)
   "Do something with the MIME attachment at \(point\)."
   (interactive
-   (list (completing-read "Action: " gnus-mime-action-alist)))
+   (list (completing-read "Action: " gnus-mime-action-alist nil t)))
   (gnus-article-check-buffer)
   (let ((action-pair (assoc action gnus-mime-action-alist)))
     (if action-pair
@@ -4260,16 +4239,14 @@ If no internal viewer is available, use an external viewer."
              (if (window-live-p window)
                  (select-window window)))))
       (goto-char point)
-      (delete-region (gnus-point-at-bol) (progn (forward-line 1) (point)))
+      (gnus-delete-line)
       (gnus-insert-mime-button
        handle id (list (mm-handle-displayed-p handle)))
       (goto-char point))))
 
 (defun gnus-article-goto-part (n)
   "Go to MIME part N."
-  (let ((point (text-property-any (point-min) (point-max) 'gnus-part n)))
-    (when point
-      (goto-char point))))
+  (gnus-goto-char (text-property-any (point-min) (point-max) 'gnus-part n)))
 
 (defun gnus-insert-mime-button (handle gnus-tmp-id &optional displayed)
   (let ((gnus-tmp-name
@@ -4761,15 +4738,14 @@ If given a numerical ARG, move forward ARG pages."
 (defun gnus-article-goto-next-page ()
   "Show the next page of the article."
   (interactive)
-  (when (gnus-article-next-page)
-    (goto-char (point-min))
-    (gnus-article-read-summary-keys nil (gnus-character-to-event ?n))))
+  (gnus-eval-in-buffer-window gnus-summary-buffer
+    (gnus-summary-next-page)))
 
 (defun gnus-article-goto-prev-page ()
   "Show the next page of the article."
   (interactive)
-  (if (bobp) (gnus-article-read-summary-keys nil (gnus-character-to-event ?p))
-    (gnus-article-prev-page nil)))
+  (gnus-eval-in-buffer-window gnus-summary-buffer
+    (gnus-summary-prev-page)))
 
 (defun gnus-article-next-page (&optional lines)
   "Show the next page of the current article.
@@ -4819,17 +4795,33 @@ Argument LINES specifies lines to be scrolled down."
             (goto-char (point-min))))
        (move-to-window-line 0)))))
 
+(defun gnus-article-only-boring-p ()
+  "Decide whether there is only boring text remaining in the article.
+Something \"interesting\" is a word of at least two letters that does
+not have a face in `gnus-article-boring-faces'."
+  (when (and gnus-article-skip-boring
+            (boundp 'gnus-article-boring-faces)
+            (symbol-value 'gnus-article-boring-faces))
+    (save-excursion
+      (catch 'only-boring
+       (while (re-search-forward "\\b\\w\\w" nil t)
+         (forward-char -1)
+         (when (not (gnus-intersection
+                     (gnus-faces-at (point))
+                     (symbol-value 'gnus-article-boring-faces)))
+           (throw 'only-boring nil)))
+       (throw 'only-boring t)))))
+
 (defun gnus-article-refer-article ()
   "Read article specified by message-id around point."
   (interactive)
-  (let ((point (point)))
-    (search-forward ">" nil t)         ;Move point to end of "<....>".
-    (if (re-search-backward "\\(<[^<> \t\n]+>\\)" nil t)
-       (let ((message-id (match-string 1)))
-         (goto-char point)
+  (save-excursion
+    (re-search-backward "[ \t]\\|^" (gnus-point-at-bol) t)
+    (re-search-forward "<?news:<?\\|<" (gnus-point-at-eol) t)
+    (if (re-search-forward "[^@ ]+@[^ \t>]+" (gnus-point-at-eol) t)
+       (let ((msg-id (concat "<" (match-string 0) ">")))
          (set-buffer gnus-summary-buffer)
-         (gnus-summary-refer-article message-id))
-      (goto-char (point))
+         (gnus-summary-refer-article msg-id))
       (error "No references around point"))))
 
 (defun gnus-article-show-summary ()
@@ -5032,13 +5024,12 @@ the entire article will be yanked."
 
 (defun gnus-article-hide (&optional arg force)
   "Hide all the gruft in the current article.
-This means that PGP stuff, signatures, cited text and (some)
-headers will be hidden.
+This means that signatures, cited text and (some) headers will be
+hidden.
 If given a prefix, show the hidden text instead."
   (interactive (append (gnus-article-hidden-arg) (list 'force)))
   (gnus-article-hide-headers arg)
   (gnus-article-hide-list-identifiers arg)
-  (gnus-article-hide-pgp arg)
   (gnus-article-hide-citation-maybe arg force)
   (gnus-article-hide-signature arg))
 
@@ -5149,9 +5140,7 @@ If given a prefix, show the hidden text instead."
                 (gnus-cache-request-article article group))
            'article)
           ;; Check the agent cache.
-          ((and gnus-agent gnus-agent-cache gnus-plugged
-                (numberp article)
-                (gnus-agent-request-article article group))
+          ((gnus-agent-request-article article group)
            'article)
           ;; Get the article and put into the article buffer.
           ((or (stringp article)
@@ -5432,8 +5421,8 @@ groups."
 
 (defcustom gnus-button-url-regexp
   (if (string-match "[[:digit:]]" "1") ;; support POSIX?
-      "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)\\(//[-a-z0-9_.]+:[0-9]*\\)?[-a-z0-9_=!?#$@~`%&*+|\\/:;.,[:word:]]+[-a-z0-9_=#$@~`%&*+|\\/[:word:]]\\)"
-    "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)\\(//[-a-z0-9_.]+:[0-9]*\\)?\\([-a-z0-9_=!?#$@~`%&*+|\\/:;.,]\\|\\w\\)+\\([-a-z0-9_=#$@~`%&*+|\\/]\\|\\w\\)\\)")
+      "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)\\(//[-a-z0-9_.]+:[0-9]*\\)?[-a-z0-9_=!?#$@~%&*+\\/:;.,[:word:]]+[-a-z0-9_=#$@~%&*+\\/[:word:]]\\)"
+    "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)\\(//[-a-z0-9_.]+:[0-9]*\\)?\\([-a-z0-9_=!?#$@~%&*+\\/:;.,]\\|\\w\\)+\\([-a-z0-9_=#$@~%&*+\\/]\\|\\w\\)\\)")
   "Regular expression that matches URLs."
   :group 'gnus-article-buttons
   :type 'regexp)
@@ -5492,57 +5481,173 @@ The function must take one argument, the string naming the URL."
   :group 'gnus-article-buttons
   :type 'regexp)
 
-(defcustom gnus-button-prefer-mid-or-mail 'guess
-  "What to do when the button on a string as \"foo123@bar.com\" is pushed.
-Strings like this can be either a message ID or a mail address.  If the
-variable is set to the symbol `ask', query the user what do do.  If it is the
-symbol `guess', Gnus will do a guess and query the user what do do if it is
-ambiguous.  See the variable `gnus-button-guessed-mid-regexp' for details
-concerning the guessing.  If it is one of the sybols `mid' or `mail', Gnus
-will always assume that the string is a message ID or a mail address,
-respectivly."
-  ;; FIXME: doc-string could/should be improved.
+(defcustom gnus-button-prefer-mid-or-mail 'gnus-button-mid-or-mail-heuristic
+  "What to do when the button on a string as \"foo123@bar.invalid\" is pushed.
+Strings like this can be either a message ID or a mail address.  If it is one
+of the symbols `mid' or `mail', Gnus will always assume that the string is a
+message ID or a mail address, respectivly.  If this variable is set to the
+symbol `ask', always query the user what do do.  If it is a function, this
+function will be called with the string as it's only argument.  The function
+must return `mid', `mail', `invalid' or `ask'."
   :group 'gnus-article-buttons
-  :type '(choice (const ask)
-                (const guess)
+  :type '(choice (function-item :tag "Heuristic function"
+                               gnus-button-mid-or-mail-heuristic)
+                (const ask)
                 (const mid)
                 (const mail)))
 
-(defcustom gnus-button-guessed-mid-regexp
-  (concat
-   "^<?\\(slrn\\|Pine\\.\\)"
-   "\\|\\.fsf@\\|\\.fsf_-_@\\|\\.ln@"
-   "\\|@4ax\\.com\\|@ID-[0-9]+\\.[a-zA-Z]+\\.dfncis\\.de"
-         "\\|^<?.*[0-9].*[0-9].*[0-9].*[0-9].*[0-9].*[0-9].*@")
-  "Regular expression that matches message IDs and not mail addresses."
-  ;; TODO: Incorporate more matches from
-  ;; <URL:http://piology.org/perl/id-or-mail.pl.html>. I.e. translate the
-  ;; Perl-REs to Elisp-REs.
+(defcustom gnus-button-mid-or-mail-heuristic-alist
+  '((-10.0 . ".+\\$.+@")
+    (-10.0 . "#")
+    (-10.0 . "\\*")
+    (-5.0  . "\\+[^+]*\\+.*@") ;; # two plus signs
+    (-5.0  . "@[Nn][Ee][Ww][Ss]") ;; /\@news/i
+    (-5.0  . "@.*[Dd][Ii][Aa][Ll][Uu][Pp]") ;; /\@.*dialup/i;
+    (-1.0  . "^[^a-z]+@")
+   
+    (-5.0  . "\\.[0-9][0-9]+.*@") ;; "\.[0-9]{2,}.*\@"
+    (-5.0  . "[a-z].*[A-Z].*[a-z].*[A-Z].*@") ;; "([a-z].*[A-Z].*){2,}\@"
+    (-3.0  . "[A-Z][A-Z][a-z][a-z].*@")
+    (-5.0  . "\\...?.?@") ;; (-5.0 . "\..{1,3}\@")
+   
+    (-2.0  . "^[0-9]")
+    (-1.0  . "^[0-9][0-9]")
+    ;;
+    ;; -3.0 /^[0-9][0-9a-fA-F]{2,2}/;
+    (-3.0  . "^[0-9][0-9a-fA-F][0-9a-fA-F][^0-9a-fA-F]")
+    ;; -5.0 /^[0-9][0-9a-fA-F]{3,3}/;
+    (-5.0  . "^[0-9][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][^0-9a-fA-F]")
+    ;;
+    (-3.0  .  "[0-9][0-9][0-9][0-9][0-9][^0-9].*@") ;; "[0-9]{5,}.*\@"
+    (-3.0  .  "[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][^0-9].*@")
+    ;;       "[0-9]{8,}.*\@"
+    (-3.0
+     . "[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].*@")
+    ;; "[0-9]{12,}.*\@"
+    ;; compensation for TDMA dated mail addresses:
+    (25.0  . "-dated-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]+.*@")
+    ;;
+    (-20.0 . "\\.fsf@")        ;; Gnus
+    (-20.0 . "^slrn")
+    (-20.0 . "^Pine")
+    (-20.0 . "_-_") ;; Subject change in thread
+    ;;
+    (-20.0 . "\\.ln@") ;; leafnode
+    (-30.0 . "@ID-[0-9]+\\.[a-zA-Z]+\\.dfncis\\.de")
+    (-30.0 . "@4[Aa][Xx]\\.com") ;; Forte Agent
+    ;;
+    ;; (5.0 . "") ;; $local_part_len <= 7
+    (10.0  . "^[^0-9]+@")
+    (3.0   . "^[^0-9]+[0-9][0-9]?[0-9]?@")
+    ;;      ^[^0-9]+[0-9]{1,3}\@ digits only at end of local part
+    (3.0   . "\@stud")
+    ;;
+    (2.0   . "[a-z][a-z][._-][A-Z][a-z].*@")
+    ;;
+    (0.5   . "^[A-Z][a-z]")
+    (0.5   . "^[A-Z][a-z][a-z]")
+    (1.5   . "^[A-Z][a-z][A-Z][a-z][^a-z]") ;; ^[A-Z][a-z]{3,3}
+    (2.0   . "^[A-Z][a-z][A-Z][a-z][a-z][^a-z]")) ;; ^[A-Z][a-z]{4,4}
+  "An alist of \(RATE . REGEXP\) pairs for `gnus-button-mid-or-mail-heuristic'.
+
+A negative RATE indicates a message IDs, whereas a positive indicates a mail
+address.  The REGEXP is processed with `case-fold-search' set to `nil'."
   :group 'gnus-article-buttons
-  :type 'regexp)
+  :type '(repeat (cons (number :tag "Rate")
+                      (regexp :tag "Regexp"))))
+
+(defun gnus-button-mid-or-mail-heuristic (mid-or-mail)
+  "Guess whether MID-OR-MAIL is a message ID or a mail address.
+Returns `mid' if MID-OR-MAIL is a message IDs, `mail' if it's a mail
+address, `ask' if unsure and `invalid' if the string is invalid."
+  (let ((case-fold-search nil)
+       (list gnus-button-mid-or-mail-heuristic-alist)
+       (result 0) rate regexp lpartlen elem)
+    (setq lpartlen
+         (length (gnus-replace-in-string mid-or-mail "^\\(.*\\)@.*$" "\\1")))
+    (gnus-message 8 "`%s', length of local part=`%s'." mid-or-mail lpartlen)
+    ;; Certain special cases...
+    (when (string-match
+          (concat
+           "^0[0-9]+-[0-9][0-9][0-9][0-9]@t-online\\.de$" "\\|"
+           "^[0-9]+\.[0-9]+\@compuserve")
+          mid-or-mail)
+      (gnus-message 8 "`%s' is a known mail address.")
+      (setq result 'mail))
+    (when (string-match "@.*@\\| " mid-or-mail)
+      (gnus-message 8 "`%s' is invalid.")
+      (setq result 'invalid))
+    ;; Nothing more to do, if result is not a number here...
+    (when (numberp result)
+      (while list
+       (setq elem (car list)
+             rate (car elem)
+             regexp (cdr elem)
+             list (cdr list))
+       (when (string-match regexp mid-or-mail)
+         (setq result (+ result rate))
+         (gnus-message
+          9 "`%s' matched `%s', rate `%s', result `%s'."
+          mid-or-mail regexp rate result)))
+      (when (<= lpartlen 7)
+       (setq result (+ result 5.0))
+       (gnus-message 9 "`%s' matched (<= lpartlen 7), result `%s'."
+                     mid-or-mail result))
+      (when (>= lpartlen 12)
+       (gnus-message 9 "`%s' matched (>= lpartlen 12)" mid-or-mail)
+       (cond
+        ((string-match "[0-9][^0-9]+[0-9].*@" mid-or-mail)
+         ;; Long local part should contain realname if e-mail address,
+         ;; too many digits: message-id.
+         ;; $score -= 5.0 + 0.1 * $local_part_len;
+         (setq rate (* -1.0 (+ 5.0 (* 0.1 lpartlen))))
+         (setq result (+ result rate))
+         (gnus-message
+          9 "Many digits in `%s', rate `%s', result `%s'."
+          mid-or-mail rate result))
+        ((string-match "[^aeiouy][^aeiouy][^aeiouy][^aeiouy]+.*\@"
+                       mid-or-mail)
+         ;; Too few vowels [^aeiouy]{4,}.*\@
+         (setq result (+ result -5.0))
+         (gnus-message
+          9 "Few vowels in `%s', rate `%s', result `%s'."
+          mid-or-mail -5.0 result))
+        (t
+         (setq result (+ result 5.0))
+         (gnus-message
+          9 "`%s', rate `%s', result `%s'." mid-or-mail 5.0 result)))))
+    (gnus-message 8 "`%s': Final rate is `%s'." mid-or-mail result)
+    (cond
+     ;; Maybe we should make this a customizable alist: (condition . 'result)
+     ((< result -10.0) 'mid)
+     ((> result  10.0) 'mail)
+     (t 'ask))))
 
 (defun gnus-button-handle-mid-or-mail (mid-or-mail)
-  (let* ((pref gnus-button-prefer-mid-or-mail)
+  (let* ((pref gnus-button-prefer-mid-or-mail) guessed
         (url-mid (concat "news" ":" mid-or-mail))
         (url-mailto (concat "mailto" ":" mid-or-mail)))
     (gnus-message 9 "mid-or-mail=%s" mid-or-mail)
-    ;; If it looks like a MID (well known readers or servers) use 'mid,
-    ;; otherwise 'ask the user.
-    (if (eq pref 'guess)
-       (if (string-match gnus-button-guessed-mid-regexp mid-or-mail)
-           (setq pref 'mid)
-         (setq pref 'ask)))
+    (when (fboundp pref)
+      (setq guessed
+           ;; get rid of surrounding angles...
+           (funcall pref
+                    (gnus-replace-in-string mid-or-mail "^<\\|>$" "")))
+      (if (or (eq 'mid guessed) (eq 'mail guessed))
+         (setq pref guessed)
+       (setq pref 'ask)))
     (if (eq pref 'ask)
        (save-window-excursion
          (if (y-or-n-p (concat "Is <" mid-or-mail "> a mail address? "))
              (setq pref 'mail)
            (setq pref 'mid))))
     (cond ((eq pref 'mid)
-          (gnus-message 9 "calling `gnus-button-handle-news' %s" url-mid)
+          (gnus-message 8 "calling `gnus-button-handle-news' %s" url-mid)
           (gnus-button-handle-news url-mid))
          ((eq pref 'mail)
-          (gnus-message 9 "calling `gnus-url-mailto'  %s" url-mailto)
-          (gnus-url-mailto url-mailto)))))
+          (gnus-message 8 "calling `gnus-url-mailto'  %s" url-mailto)
+          (gnus-url-mailto url-mailto))
+         (t (gnus-message 3 "Invalid string.")))))
 
 (defun gnus-button-handle-custom (url)
   "Follow a Custom URL."
@@ -5551,40 +5656,43 @@ respectivly."
 (defvar gnus-button-handle-describe-prefix "^\\(C-h\\|<?[Ff]1>?\\)")
 
 (defun gnus-button-handle-describe-function (url)
-  "Call describe-function when pushing the corresponding URL button."
+  "Call `describe-function' when pushing the corresponding URL button."
   (describe-function
    (intern
     (gnus-replace-in-string url gnus-button-handle-describe-prefix ""))))
 
 (defun gnus-button-handle-describe-variable (url)
-  "Call describe-variable when pushing the corresponding URL button."
+  "Call `describe-variable' when pushing the corresponding URL button."
   (describe-variable
    (intern
     (gnus-replace-in-string url gnus-button-handle-describe-prefix ""))))
 
-;; FIXME: Is is possible to implement this?  Else it should be removed here
-;; and in `gnus-button-alist'.
 (defun gnus-button-handle-describe-key (url)
-  "Call describe-key when pushing the corresponding URL button."
-  (error "not implemented"))
+  "Call `describe-key' when pushing the corresponding URL button."
+  (let* ((key-string
+         (gnus-replace-in-string url gnus-button-handle-describe-prefix ""))
+        (keys (ignore-errors (eval `(kbd ,key-string)))))
+    (if keys
+       (describe-key keys)
+      (gnus-message 3 "Invalid key sequence in button: %s" key-string))))
 
 (defun gnus-button-handle-apropos (url)
-  "Call apropos when pushing the corresponding URL button."
+  "Call `apropos' when pushing the corresponding URL button."
   (apropos (gnus-replace-in-string url gnus-button-handle-describe-prefix "")))
 
 (defun gnus-button-handle-apropos-command (url)
-  "Call apropos when pushing the corresponding URL button."
+  "Call `apropos' when pushing the corresponding URL button."
   (apropos-command
    (gnus-replace-in-string url gnus-button-handle-describe-prefix "")))
 
 (defun gnus-button-handle-apropos-variable (url)
-  "Call apropos when pushing the corresponding URL button."
+  "Call `apropos' when pushing the corresponding URL button."
   (funcall
    (if (fboundp 'apropos-variable) 'apropos-variable 'apropos)
    (gnus-replace-in-string url gnus-button-handle-describe-prefix "")))
 
 (defun gnus-button-handle-apropos-documentation (url)
-  "Call apropos when pushing the corresponding URL button."
+  "Call `apropos' when pushing the corresponding URL button."
   (funcall
    (if (fboundp 'apropos-documentation) 'apropos-documentation 'apropos)
    (gnus-replace-in-string url gnus-button-handle-describe-prefix "")))
@@ -5676,9 +5784,10 @@ positives are possible."
      0 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-function 2)
     ("\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+v[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET"
      0 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-variable 2)
-    ("\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+k[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+" 0
-     ;; this regexp needs to be fixed!
-     (>= gnus-button-emacs-level 9) gnus-button-handle-describe-key 2)
+    ("`\\(\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+k[ \t\n]+\\([^']+\\)\\)'" 1
+     ;; Unlike the other regexps we really have to require quoting
+     ;; here to determine where it ends.
+     (>= gnus-button-emacs-level 1) gnus-button-handle-describe-key 3)
     ;; This is how URLs _should_ be embedded in text...
     ("<URL: *\\([^<>]*\\)>" 1 t gnus-button-embedded-url 1)
     ;; Raw URLs.
@@ -5783,8 +5892,8 @@ call it with the value of the `gnus-data' text property."
 If the text at point has a `gnus-callback' property,
 call it with the value of the `gnus-data' text property."
   (interactive)
-  (let* ((data (get-text-property (point) 'gnus-data))
-        (fun (get-text-property (point) 'gnus-callback)))
+  (let ((data (get-text-property (point) 'gnus-data))
+       (fun (get-text-property (point) 'gnus-callback)))
     (when fun
       (funcall fun data))))
 
@@ -6407,7 +6516,7 @@ For example:
                                   (search-forward field nil t))
                                 (prog2
                                     (message-narrow-to-field)
-                                    (buffer-substring (point-min) (point-max))
+                                    (buffer-string)
                                   (delete-region (point-min) (point-max))
                                   (widen))))
                          '("Content-Type:" "Content-Transfer-Encoding:"
@@ -6501,42 +6610,45 @@ For example:
 
 (defun gnus-mime-security-show-details (handle)
   (let ((details (mm-handle-multipart-ctl-parameter handle 'gnus-details)))
-    (if details
-       (if gnus-mime-security-show-details-inline
-           (let ((gnus-mime-security-button-pressed t)
-                 (gnus-mime-security-button-line-format
-                  (get-text-property (point) 'gnus-line-format))
+    (if (not details)
+       (gnus-message 5 "No details.")
+      (if gnus-mime-security-show-details-inline
+         (let ((gnus-mime-security-button-pressed
+                (not (get-text-property (point) 'gnus-mime-details)))
+               (gnus-mime-security-button-line-format
+                (get-text-property (point) 'gnus-line-format))
                buffer-read-only)
-             (forward-char -1)
-             (while (eq (get-text-property (point) 'gnus-line-format)
-                        gnus-mime-security-button-line-format)
-               (forward-char -1))
-             (forward-char)
-             (save-restriction
-               (narrow-to-region (point) (point))
-               (gnus-insert-mime-security-button handle))
-             (delete-region (point)
-                            (or (text-property-not-all
-                                 (point) (point-max)
-                                 'gnus-line-format
-                                 gnus-mime-security-button-line-format)
-                                (point-max))))
-         (if (gnus-buffer-live-p gnus-mime-security-details-buffer)
-             (with-current-buffer gnus-mime-security-details-buffer
-               (erase-buffer)
-               t)
-           (setq gnus-mime-security-details-buffer
-                 (gnus-get-buffer-create "*MIME Security Details*")))
-         (with-current-buffer gnus-mime-security-details-buffer
-           (insert details)
-           (goto-char (point-min)))
-         (pop-to-buffer gnus-mime-security-details-buffer))
-      (gnus-message 5 "No details."))))
+           (forward-char -1)
+           (while (eq (get-text-property (point) 'gnus-line-format)
+                      gnus-mime-security-button-line-format)
+             (forward-char -1))
+           (forward-char)
+           (save-restriction
+             (narrow-to-region (point) (point))
+             (gnus-insert-mime-security-button handle))
+           (delete-region (point)
+                          (or (text-property-not-all
+                               (point) (point-max)
+                               'gnus-line-format
+                               gnus-mime-security-button-line-format)
+                              (point-max))))
+       ;; Not inlined.
+       (if (gnus-buffer-live-p gnus-mime-security-details-buffer)
+           (with-current-buffer gnus-mime-security-details-buffer
+             (erase-buffer)
+             t)
+         (setq gnus-mime-security-details-buffer
+               (gnus-get-buffer-create "*MIME Security Details*")))
+       (with-current-buffer gnus-mime-security-details-buffer
+         (insert details)
+         (goto-char (point-min)))
+       (pop-to-buffer gnus-mime-security-details-buffer)))))
 
 (defun gnus-mime-security-press-button (handle)
-  (if (mm-handle-multipart-ctl-parameter handle 'gnus-info)
-      (gnus-mime-security-show-details handle)
-    (gnus-mime-security-verify-or-decrypt handle)))
+  (save-excursion
+    (if (mm-handle-multipart-ctl-parameter handle 'gnus-info)
+       (gnus-mime-security-show-details handle)
+      (gnus-mime-security-verify-or-decrypt handle))))
 
 (defun gnus-insert-mime-security-button (handle &optional displayed)
   (let* ((protocol (mm-handle-multipart-ctl-parameter handle 'protocol))
@@ -6557,7 +6669,8 @@ For example:
         b e)
     (setq gnus-tmp-details
          (if gnus-tmp-details
-             (concat "\n" gnus-tmp-details) ""))
+             (concat "\n" gnus-tmp-details)
+           ""))
     (setq gnus-tmp-pressed-details
          (if gnus-mime-security-button-pressed gnus-tmp-details ""))
     (unless (bolp)
@@ -6569,6 +6682,7 @@ For example:
      `(,@(gnus-local-map-property gnus-mime-security-button-map)
         gnus-callback gnus-mime-security-press-button
         gnus-line-format ,gnus-mime-security-button-line-format
+        gnus-mime-details ,gnus-mime-security-button-pressed
         article-type annotation
         gnus-data ,handle))
     (setq e (point))
@@ -6581,8 +6695,8 @@ For example:
      (lambda (widget/window &optional overlay pos)
        ;; Needed to properly clear the message due to a bug in
        ;; wid-edit (XEmacs only).
-       (if (boundp 'help-echo-owns-message)
-          (setq help-echo-owns-message t))
+       (when (boundp 'help-echo-owns-message)
+        (setq help-echo-owns-message t))
        (format
        "%S: show detail"
        (aref gnus-mouse-2 0))))))