Importing pgnus-0.70
[elisp/gnus.git-] / lisp / gnus-sum.el
index 8485f0e..c754177 100644 (file)
@@ -1,5 +1,5 @@
 ;;; gnus-sum.el --- summary mode commands for Gnus
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996,97,98,99 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -475,6 +475,19 @@ It uses the same syntax as the `gnus-split-methods' variable."
   :group 'gnus-extract-view
   :type 'boolean)
 
+(defcustom gnus-auto-expirable-marks
+  (list gnus-killed-mark gnus-del-mark gnus-catchup-mark
+       gnus-low-score-mark gnus-ancient-mark gnus-read-mark
+       gnus-souped-mark gnus-duplicate-mark)
+  "*The list of marks converted into expiration if a group is auto-expirable."
+  :group 'gnus-summary
+  :type '(repeat character))
+
+(defcustom gnus-inhibit-user-auto-expire t
+  "*If non-nil, user marking commands will not mark an article as expirable, even if the group has auto-expire turned on."
+  :group 'gnus-summary
+  :type 'boolean)
+
 (defcustom gnus-view-pseudos nil
   "*If `automatic', pseudo-articles will be viewed automatically.
 If `not-confirm', pseudos will be viewed automatically, and the user
@@ -784,12 +797,32 @@ which it may alter in any way.")
   :group 'gnus-summary
   :type 'regexp)
 
+(defcustom gnus-default-charset 'iso-8859-1
+  "Default charset assumed to be used when viewing non-ASCII characters.")
+
+(defcustom gnus-newsgroup-default-charset-alist 
+  '(("^hk\\>\\|^tw\\>\\|\\<big5\\>" . cn-big5)
+    ("^cn\\>\\|\\<chinese\\>" . cn-gb-2312)
+    ("^fj\\>\\|^japan\\>" . iso-2022-jp-2)
+    ("^relcom\\>" . koi8-r))
+  "Alist of Regexps (to match group names) and default charsets to be applied."
+  :type '(repeat (cons (regexp :tag "Group")
+                      (symbol :tag "Charset")))
+  :group 'gnus)
+
+(defcustom gnus-newsgroup-iso-8859-1-forced-regexp 
+  "^tw\\>\\|^hk\\>\\|^cn\\>\\|\\<chinese\\>"
+  "Regexp of newsgroup in which ISO-8859-1 is forced to other charset."
+  :type 'regexp
+  :group 'gnus)
+
 ;;; Internal variables
 
 (defvar gnus-article-mime-handles nil)
 (defvar gnus-article-decoded-p nil)
 (defvar gnus-scores-exclude-files nil)
 (defvar gnus-page-broken nil)
+(defvar gnus-inhibit-mime-unbuttonizing nil)
 
 (defvar gnus-original-article nil)
 (defvar gnus-article-internal-prepare-hook nil)
@@ -972,6 +1005,9 @@ variable (string, integer, character, etc).")
 (defvar gnus-last-article nil)
 (defvar gnus-newsgroup-history nil)
 
+(defvar gnus-newsgroup-default-charset gnus-default-charset)
+(defvar gnus-newsgroup-iso-8859-1-forced nil)
+
 (defconst gnus-summary-local-variables
   '(gnus-newsgroup-name
     gnus-newsgroup-begin gnus-newsgroup-end
@@ -1002,7 +1038,8 @@ variable (string, integer, character, etc).")
     (gnus-newsgroup-expunged-tally . 0)
     gnus-cache-removable-articles gnus-newsgroup-cached
     gnus-newsgroup-data gnus-newsgroup-data-reverse
-    gnus-newsgroup-limit gnus-newsgroup-limits)
+    gnus-newsgroup-limit gnus-newsgroup-limits
+    gnus-newsgroup-default-charset gnus-newsgroup-iso-8859-1-forced)
   "Variables that are buffer-local to the summary buffers.")
 
 ;; Byte-compiler warning.
@@ -1274,6 +1311,7 @@ increase the score of each group you read."
     "\C-d" gnus-summary-enter-digest-group
     "\M-\C-d" gnus-summary-read-document
     "\M-\C-e" gnus-summary-edit-parameters
+    "\M-\C-g" gnus-summary-customize-parameters
     "\C-c\C-b" gnus-bug
     "*" gnus-cache-enter-article
     "\M-*" gnus-cache-remove-article
@@ -1283,7 +1321,9 @@ increase the score of each group you read."
     "L" gnus-summary-lower-score
     "\M-i" gnus-symbolic-argument
     "h" gnus-summary-select-article-buffer
+
     "b" gnus-article-view-part
+    "\M-t" gnus-summary-toggle-display-buttonized
     
     "V" gnus-summary-score-map
     "X" gnus-uu-extract-map
@@ -1462,7 +1502,8 @@ increase the score of each group you read."
     "m" gnus-article-strip-multiple-blank-lines
     "a" gnus-article-strip-blank-lines
     "A" gnus-article-strip-all-blank-lines
-    "s" gnus-article-strip-leading-space)
+    "s" gnus-article-strip-leading-space
+    "e" gnus-article-strip-trailing-space)
 
   (gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
     "v" gnus-version
@@ -1496,7 +1537,17 @@ increase the score of each group you read."
     "h" gnus-summary-save-article-folder
     "v" gnus-summary-save-article-vm
     "p" gnus-summary-pipe-output
-    "s" gnus-soup-add-article))
+    "s" gnus-soup-add-article)
+
+  (gnus-define-keys (gnus-summary-mime-map "K" gnus-summary-mode-map)
+    "b" gnus-summary-display-buttonized
+    "m" gnus-summary-repair-multipart
+    "v" gnus-article-view-part
+    "o" gnus-article-save-part
+    "c" gnus-article-copy-part
+    "e" gnus-article-externalize-part
+    "|" gnus-article-pipe-part)
+  )
 
 (defun gnus-summary-make-menu-bar ()
   (gnus-turn-off-edit-menu 'summary)
@@ -1565,7 +1616,8 @@ increase the score of each group you read."
                ["Trailing" gnus-article-remove-trailing-blank-lines t]
                ["All of the above" gnus-article-strip-blank-lines t]
                ["All" gnus-article-strip-all-blank-lines t]
-               ["Leading space" gnus-article-strip-leading-space t])
+               ["Leading space" gnus-article-strip-leading-space t]
+              ["Trailing space" gnus-article-strip-trailing-space t])
               ["Overstrike" gnus-article-treat-overstrike t]
               ["Dumb quotes" gnus-article-treat-dumbquotes t]
               ["Emphasis" gnus-article-emphasize t]
@@ -1793,6 +1845,7 @@ increase the score of each group you read."
        ["Edit local kill file" gnus-summary-edit-local-kill t]
        ["Edit main kill file" gnus-summary-edit-global-kill t]
        ["Edit group parameters" gnus-summary-edit-parameters t]
+       ["Customize group parameters" gnus-summary-customize-parameters t]
        ["Send a bug report" gnus-bug t]
        ("Exit"
        ["Catchup and exit" gnus-summary-catchup-and-exit t]
@@ -2359,7 +2412,9 @@ marks of articles."
          (original gnus-original-article-buffer)
          (gac gnus-article-current)
          (reffed gnus-reffed-article-number)
-         (score-file gnus-current-score-file))
+         (score-file gnus-current-score-file)
+         (default-charset gnus-newsgroup-default-charset)
+         (iso-8859-1-forced gnus-newsgroup-iso-8859-1-forced))
       (save-excursion
        (set-buffer gnus-group-buffer)
        (setq gnus-newsgroup-name name
@@ -2372,7 +2427,9 @@ marks of articles."
              gnus-article-buffer article-buffer
              gnus-original-article-buffer original
              gnus-reffed-article-number reffed
-             gnus-current-score-file score-file)
+             gnus-current-score-file score-file
+             gnus-newsgroup-default-charset default-charset
+             gnus-newsgroup-iso-8859-1-forced iso-8859-1-forced)
        ;; The article buffer also has local variables.
        (when (gnus-buffer-live-p gnus-article-buffer)
          (set-buffer gnus-article-buffer)
@@ -2447,7 +2504,9 @@ marks of articles."
 
 (defun gnus-summary-from-or-to-or-newsgroups (header)
   (let ((to (cdr (assq 'To (mail-header-extra header))))
-       (newsgroups (cdr (assq 'Newsgroups (mail-header-extra header)))))
+       (newsgroups (cdr (assq 'Newsgroups (mail-header-extra header))))
+       (rfc2047-default-charset gnus-newsgroup-default-charset)
+       (mm-charset-iso-8859-1-forced gnus-newsgroup-iso-8859-1-forced))
     (cond
      ((and to
           gnus-ignored-from-addresses
@@ -3966,6 +4025,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
     (setq gnus-newsgroup-name group)
     (setq gnus-newsgroup-unselected nil)
     (setq gnus-newsgroup-unreads (gnus-list-of-unread-articles group))
+    (gnus-newsgroup-setup-default-charset)
 
     ;; Adjust and set lists of article marks.
     (when info
@@ -4236,12 +4296,28 @@ If SELECT-ARTICLES, only select those articles from GROUP."
                (setq arts (cdr arts)))
              (setq list (cdr all))))
 
+         (when (gnus-check-backend-function 'request-set-mark 
+                                            gnus-newsgroup-name)
+           ;; score & bookmark are not proper flags (they are cons cells)
+           ;; cache is a internal gnus flag
+           (unless (memq (cdr type) '(cache score bookmark))
+             (let* ((old (cdr (assq (cdr type) (gnus-info-marks info))))
+                    (del (gnus-remove-from-range old list))
+                    (add (gnus-remove-from-range list old)))
+               (if add
+                   (push (list add 'add (list (cdr type))) delta-marks))
+               (if del
+                   (push (list del 'del (list (cdr type))) delta-marks)))))
+         
          (push (cons (cdr type)
                      (if (memq (cdr type) uncompressed) list
                        (gnus-compress-sequence
                         (set symbol (sort list '<)) t)))
                newmarked)))
 
+      (if delta-marks
+         (gnus-request-set-mark gnus-newsgroup-name delta-marks))
+
       ;; Enter these new marks into the info of the group.
       (if (nthcdr 3 info)
          (setcar (nthcdr 3 info) newmarked)
@@ -4476,7 +4552,9 @@ The resulting hash table is returned, or nil if no Xrefs were found."
         (or dependencies
             (save-excursion (set-buffer gnus-summary-buffer)
                             gnus-newsgroup-dependencies)))
-       headers id end ref)
+       headers id end ref
+       (rfc2047-default-charset gnus-newsgroup-default-charset)
+       (mm-charset-iso-8859-1-forced gnus-newsgroup-iso-8859-1-forced))
     (save-excursion
       (set-buffer nntp-server-buffer)
       ;; Translate all TAB characters into SPACE characters.
@@ -4629,7 +4707,9 @@ list of headers that match SEQUENCE (see `nntp-retrieve-headers')."
   ;; Get the Xref when the users reads the articles since most/some
   ;; NNTP servers do not include Xrefs when using XOVER.
   (setq gnus-article-internal-prepare-hook '(gnus-article-get-xrefs))
-  (let ((cur nntp-server-buffer)
+  (let ((rfc2047-default-charset gnus-newsgroup-default-charset)
+       (mm-charset-iso-8859-1-forced gnus-newsgroup-iso-8859-1-forced)
+       (cur nntp-server-buffer)
        (dependencies (or dependencies gnus-newsgroup-dependencies))
        number headers header)
     (save-excursion
@@ -5166,6 +5246,10 @@ If FORCE (the prefix), also save the .newsrc file(s)."
 gnus-exit-group-hook is called with no arguments if that value is non-nil."
   (interactive)
   (gnus-set-global-variables)
+  (when (gnus-buffer-live-p gnus-article-buffer)
+    (save-excursion
+      (set-buffer gnus-article-buffer)
+      (mm-destroy-parts gnus-article-mime-handles)))
   (gnus-kill-save-kill-buffer)
   (gnus-async-halt-prefetch)
   (let* ((group gnus-newsgroup-name)
@@ -5173,6 +5257,12 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
         (mode major-mode)
          (group-point nil)
         (buf (current-buffer)))
+    (unless quit-config
+      ;; Do adaptive scoring, and possibly save score files.
+      (when gnus-newsgroup-adaptive
+       (gnus-score-adaptive))
+      (when gnus-use-scoring
+       (gnus-score-save)))
     (gnus-run-hooks 'gnus-summary-prepare-exit-hook)
     ;; If we have several article buffers, we kill them at exit.
     (unless gnus-single-article-buffer
@@ -5191,12 +5281,7 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
     ;; Make all changes in this group permanent.
     (unless quit-config
       (gnus-run-hooks 'gnus-exit-group-hook)
-      (gnus-summary-update-info)
-      ;; Do adaptive scoring, and possibly save score files.
-      (when gnus-newsgroup-adaptive
-       (gnus-score-adaptive))
-      (when gnus-use-scoring
-       (gnus-score-save)))
+      (gnus-summary-update-info))
     (gnus-close-group group)
     ;; Make sure where we were, and go to next newsgroup.
     (set-buffer gnus-group-buffer)
@@ -5211,10 +5296,6 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
     (setq group-point (point))
     (if temporary
        nil                             ;Nothing to do.
-      (when (gnus-buffer-live-p gnus-article-buffer)
-       (save-excursion
-         (set-buffer gnus-article-buffer)
-         (mm-destroy-parts gnus-article-mime-handles)))
       ;; If we have several article buffers, we kill them at exit.
       (unless gnus-single-article-buffer
        (gnus-kill-buffer gnus-article-buffer)
@@ -5258,8 +5339,9 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
              gnus-expert-user
              (gnus-y-or-n-p "Discard changes to this group and exit? "))
       (gnus-async-halt-prefetch)
-      (gnus-run-hooks (delq 'gnus-summary-expire-articles 
-                           (copy-list gnus-summary-prepare-exit-hook)))
+      (mapcar 'funcall
+             (delq 'gnus-summary-expire-articles 
+                   (copy-list gnus-summary-prepare-exit-hook)))
       (when (gnus-buffer-live-p gnus-article-buffer)
        (save-excursion
          (set-buffer gnus-article-buffer)
@@ -6589,6 +6671,11 @@ or `gnus-select-method', no matter what backend the article comes from."
   (interactive)
   (gnus-group-edit-group gnus-newsgroup-name 'params))
 
+(defun gnus-summary-customize-parameters ()
+  "Customize the group parameters of the current group."
+  (interactive)
+  (gnus-group-customize gnus-newsgroup-name))
+
 (defun gnus-summary-enter-digest-group (&optional force)
   "Enter an nndoc group based on the current article.
 If FORCE, force a digest interpretation.  If not, try
@@ -6912,6 +6999,10 @@ article massaging functions being run."
   (if (not arg)
       ;; Select the article the normal way.
       (gnus-summary-select-article nil 'force)
+    ;; We have to require this here to make sure that the following
+    ;; dynamic binding isn't shadowed by autoloading.
+    (require 'gnus-async)
+    (require 'gnus-art)
     ;; Bind the article treatment functions to nil.
     (let ((gnus-have-all-headers t)
          gnus-article-display-hook
@@ -6920,6 +7011,11 @@ article massaging functions being run."
          gnus-display-mime-function
          gnus-break-pages
          gnus-visual)
+      ;; Destroy any MIME parts.
+      (when (gnus-buffer-live-p gnus-article-buffer)
+       (save-excursion
+         (set-buffer gnus-article-buffer)
+         (mm-destroy-parts gnus-article-mime-handles)))
       (gnus-summary-select-article nil 'force)))
   (gnus-summary-goto-subject gnus-current-article)
   (gnus-summary-position-point))
@@ -7072,7 +7168,7 @@ and `request-accept' functions."
                  gnus-newsgroup-name)) ; Server
          (list 'gnus-request-accept-article
                to-newsgroup (list 'quote select-method)
-               (not articles))         ; Accept form
+               (not articles) t)               ; Accept form
          (not articles)))              ; Only save nov last time
        ;; Copy the article.
        ((eq action 'copy)
@@ -7775,11 +7871,7 @@ returned."
     (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
     ;; Check for auto-expiry.
     (when (and gnus-newsgroup-auto-expire
-              (or (= mark gnus-killed-mark) (= mark gnus-del-mark)
-                  (= mark gnus-catchup-mark) (= mark gnus-low-score-mark)
-                  (= mark gnus-ancient-mark)
-                  (= mark gnus-read-mark) (= mark gnus-souped-mark)
-                  (= mark gnus-duplicate-mark)))
+              (memq mark gnus-auto-expirable-marks))
       (setq mark gnus-expirable-mark)
       ;; Let the backend know about the mark change.
       (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
@@ -7830,25 +7922,21 @@ returned."
   "Mark ARTICLE with MARK.  MARK can be any character.
 Four MARK strings are reserved: `? ' (unread), `?!' (ticked),
 `??' (dormant) and `?E' (expirable).
-If MARK is nil, then the default character `?D' is used.
+If MARK is nil, then the default character `?r' is used.
 If ARTICLE is nil, then the article on the current line will be
 marked."
   ;; The mark might be a string.
   (when (stringp mark)
     (setq mark (aref mark 0)))
   ;; If no mark is given, then we check auto-expiring.
-  (and (not no-expire)
-       gnus-newsgroup-auto-expire
-       (or (not mark)
-          (and (gnus-characterp mark)
-               (or (= mark gnus-killed-mark) (= mark gnus-del-mark)
-                   (= mark gnus-catchup-mark) (= mark gnus-low-score-mark)
-                   (= mark gnus-read-mark) (= mark gnus-souped-mark)
-                   (= mark gnus-duplicate-mark))))
-       (setq mark gnus-expirable-mark))
-  (let* ((mark (or mark gnus-del-mark))
-        (article (or article (gnus-summary-article-number)))
-        (old-mark (gnus-summary-article-mark article)))
+  (when (null mark)
+    (setq mark gnus-del-mark))
+  (when (and (not no-expire)
+            gnus-newsgroup-auto-expire
+            (memq mark gnus-auto-expirable-marks))
+    (setq mark gnus-expirable-mark))
+  (let ((article (or article (gnus-summary-article-number)))
+       (old-mark (gnus-summary-article-mark article)))
     ;; Allow the backend to change the mark.
     (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
     (if (eq mark old-mark)
@@ -7993,14 +8081,14 @@ If N is negative, mark backwards instead.
 The difference between N and the actual number of articles marked is
 returned."
   (interactive "p")
-  (gnus-summary-mark-forward n gnus-del-mark t))
+  (gnus-summary-mark-forward n gnus-del-mark gnus-inhibit-user-auto-expire))
 
 (defun gnus-summary-mark-as-read-backward (n)
   "Mark the N articles as read backwards.
 The difference between N and the actual number of articles marked is
 returned."
   (interactive "p")
-  (gnus-summary-mark-forward (- n) gnus-del-mark t))
+  (gnus-summary-mark-forward (- n) gnus-del-mark gnus-inhibit-user-auto-expire))
 
 (defun gnus-summary-mark-as-read (&optional article mark)
   "Mark current article as read.
@@ -8283,25 +8371,15 @@ is non-nil or the Subject: of both articles are the same."
                         (gnus-summary-article-header parent-article))))
        (unless (and message-id (not (equal message-id "")))
          (error "No message-id in desired parent"))
-       ;; We don't want the article to be marked as read.
-       (let (gnus-mark-article-hook)
-         (gnus-summary-select-article t t nil current-article))
-       (set-buffer gnus-original-article-buffer)
-       (let ((buf (format "%s" (buffer-string))))
-         (with-temp-buffer
-           (insert buf)
-           (goto-char (point-min))
-           (if (re-search-forward "^References: " nil t)
-               (progn
-                 (re-search-forward "^[^ \t]" nil t)
-                 (forward-line -1)
-                 (end-of-line)
-                 (insert " " message-id))
-             (insert "References: " message-id "\n"))
-           (unless (gnus-request-replace-article
-                    current-article (car gnus-article-current)
-                    (current-buffer))
-             (error "Couldn't replace article"))))
+       (gnus-with-article current-article
+         (goto-char (point-min))
+         (if (re-search-forward "^References: " nil t)
+             (progn
+               (re-search-forward "^[^ \t]" nil t)
+               (forward-line -1)
+               (end-of-line)
+               (insert " " message-id))
+           (insert "References: " message-id "\n")))
        (set-buffer gnus-summary-buffer)
        (gnus-summary-unmark-all-processable)
        (gnus-summary-update-article current-article)
@@ -8545,17 +8623,15 @@ Argument REVERSE means reverse order."
   (let* ((thread (intern (format "gnus-thread-sort-by-%s" predicate)))
         (article (intern (format "gnus-article-sort-by-%s" predicate)))
         (gnus-thread-sort-functions
-         (list
-          (if (not reverse)
-              thread
-            `(lambda (t1 t2)
-               (,thread t2 t1)))))
+         (if (not reverse)
+             thread
+           `(lambda (t1 t2)
+              (,thread t2 t1))))
         (gnus-article-sort-functions
-         (list
-          (if (not reverse)
-              article
-            `(lambda (t1 t2)
-               (,article t2 t1)))))
+         (if (not reverse)
+             article
+           `(lambda (t1 t2)
+              (,article t2 t1))))
         (buffer-read-only)
         (gnus-summary-prepare-hook nil))
     ;; We do the sorting by regenerating the threads.
@@ -9062,6 +9138,14 @@ save those articles instead."
               (gnus-info-set-read ',info ',(gnus-info-read info))
               (gnus-get-unread-articles-in-group ',info (gnus-active ,group))
               (gnus-group-update-group ,group t))))
+       ;; Propagate the read marks to the backend.
+       (if (gnus-check-backend-function 'request-set-mark group)
+           (let ((del (gnus-remove-from-range (gnus-info-read info) read))
+                 (add (gnus-remove-from-range read (gnus-info-read info))))
+             (when (or add del)
+               (gnus-request-set-mark
+                group (delq nil (list (if add (list add 'add '(read)))
+                                      (if del (list del 'del '(read)))))))))
        ;; Enter this list into the group info.
        (gnus-info-set-read info read)
        ;; Set the number of unread articles in gnus-newsrc-hashtb.
@@ -9096,6 +9180,86 @@ save those articles instead."
           (gnus-summary-exit))
         buffers)))))
 
+(defun gnus-newsgroup-setup-default-charset ()
+  "Setup newsgroup default charset."
+  (let ((name (and gnus-newsgroup-name 
+                  (string-match "[^:]+$" gnus-newsgroup-name)
+                  (match-string 0 gnus-newsgroup-name))))
+    (setq gnus-newsgroup-default-charset
+         (or (and gnus-newsgroup-name
+                  (or (gnus-group-find-parameter 
+                       gnus-newsgroup-name 'charset)
+                      (let ((alist gnus-newsgroup-default-charset-alist) 
+                            elem (charset nil))
+                        (while alist
+                          (if (and name
+                                   (string-match 
+                                    (car (setq elem (pop alist)))
+                                    name))
+                              (setq alist nil
+                                    charset (cdr elem))))
+                        charset)))
+             gnus-default-charset))
+    (setq gnus-newsgroup-iso-8859-1-forced 
+         (and gnus-newsgroup-name
+              (or (gnus-group-find-parameter
+                   gnus-newsgroup-name 'iso-8859-1-forced)
+                  (and name
+                       (string-match  gnus-newsgroup-iso-8859-1-forced-regexp 
+                                      name))))))
+  (if (stringp gnus-newsgroup-default-charset)
+      (setq gnus-newsgroup-default-charset
+           (intern (downcase gnus-newsgroup-default-charset))))
+  (setq gnus-newsgroup-iso-8859-1-forced
+       (if (stringp gnus-newsgroup-iso-8859-1-forced)
+           (intern (downcase gnus-newsgroup-iso-8859-1-forced))
+         (and gnus-newsgroup-iso-8859-1-forced
+              gnus-newsgroup-default-charset))))
+  
+;;;
+;;; MIME Commands
+;;;
+
+(defun gnus-summary-display-buttonized (&optional show-all-parts)
+  "Display the current article buffer fully MIME-buttonized.  
+If SHOW-ALL-PARTS (the prefix) is non-nil, all multipart/* parts are
+treated as multipart/mixed."
+  (interactive "P")
+  (require 'gnus-art)
+  (let ((gnus-unbuttonized-mime-types nil)
+       (gnus-mime-display-multipart-as-mixed show-all-parts))
+    (gnus-summary-show-article)))
+
+(defun gnus-summary-repair-multipart (article)
+  "Add a Content-Type header to a multipart article without one."
+  (interactive (list (gnus-summary-article-number)))
+  (gnus-with-article article
+    (message-narrow-to-head)
+    (goto-char (point-max))
+    (widen)
+    (when (search-forward "\n--" nil t)
+      (let ((separator (buffer-substring (point) (gnus-point-at-eol))))
+       (message-narrow-to-head)
+       (message-remove-header "Mime-Version")
+       (message-remove-header "Content-Type")
+       (goto-char (point-max))
+       (insert (format "Content-Type: multipart/mixed; boundary=\"%s\"\n"
+                       separator))
+       (insert "Mime-Version: 1.0\n")
+       (widen))))
+  (let (gnus-mark-article-hook)
+    (gnus-summary-select-article t t nil article)))
+
+(defun gnus-summary-toggle-display-buttonized ()
+  "Toggle the buttonizing of the article buffer."
+  (interactive)
+  (require 'gnus-art)
+  (if (setq gnus-inhibit-mime-unbuttonizing
+           (not gnus-inhibit-mime-unbuttonizing))
+      (let ((gnus-unbuttonized-mime-types nil))
+       (gnus-summary-show-article))
+    (gnus-summary-show-article)))
+    
 (gnus-ems-redefine)
 
 (provide 'gnus-sum)