Sync up with Pterodactyl Gnus 0.84
[elisp/gnus.git-] / lisp / gnus-sum.el
index e8e5a56..4608511 100644 (file)
@@ -1,8 +1,10 @@
-;;; gnus-sum.el --- summary mode commands for Gnus
+;;; gnus-sum.el --- summary mode commands for Semi-gnus
 ;; Copyright (C) 1996,97,98,99 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
-;; Keywords: news
+;;         MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;;         Katsumi Yamaoka  <yamaoka@jpl.org>
+;; Keywords: mail, news, MIME
 
 ;; This file is part of GNU Emacs.
 
 (require 'gnus-int)
 (require 'gnus-undo)
 (require 'gnus-util)
-(require 'mm-decode)
+(require 'mime-view)
+
+(eval-when-compile
+  (require 'mime-play)
+  ;; Avoid byte-compile warnings.
+  (defvar gnus-article-decoded-p)
+  (defvar gnus-decode-encoded-word-function)
+  )
+
+(eval-and-compile
+  (autoload 'gnus-cache-articles-in-group "gnus-cache"))
+
 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
+(autoload 'gnus-set-summary-default-charset "gnus-i18n" nil t)
 
 (defcustom gnus-kill-summary-on-exit t
   "*If non-nil, kill the summary buffer when you exit from it.
@@ -337,6 +351,13 @@ variable."
   :group 'gnus-article-various
   :type 'boolean)
 
+(defcustom gnus-show-mime t
+  "*If non-nil, do mime processing of articles.
+The articles will simply be fed to the function given by
+`gnus-article-display-method-for-mime'."
+  :group 'gnus-article-mime
+  :type 'boolean)
+
 (defcustom gnus-move-split-methods nil
   "*Variable used to suggest where articles are to be moved to.
 It uses the same syntax as the `gnus-split-methods' variable."
@@ -606,7 +627,7 @@ See `gnus-thread-score-function' for en explanation of what a
 \"thread score\" is.
 
 This variable is local to the summary buffers."
-  :group 'gnus-treading
+  :group 'gnus-threading
   :group 'gnus-score-default
   :type '(choice (const :tag "off" nil)
                 integer))
@@ -678,7 +699,7 @@ is not run if `gnus-visual' is nil."
   :group 'gnus-summary-visual
   :type 'hook)
 
-(defcustom gnus-parse-headers-hook nil
+(defcustom gnus-parse-headers-hook '(gnus-set-summary-default-charset)
   "*A hook called before parsing the headers."
   :group 'gnus-various
   :type 'hook)
@@ -783,9 +804,6 @@ mark:    The articles mark."
 The function is called with one parameter, the article header vector,
 which it may alter in any way.")
 
-(defvar gnus-decode-encoded-word-function 'mail-decode-encoded-word-string
-  "Variable that says which function should be used to decode a string with encoded words.")
-
 (defcustom gnus-extra-headers nil
   "*Extra headers to parse."
   :group 'gnus-summary
@@ -802,16 +820,25 @@ which it may alter in any way.")
     ("^cn\\>\\|\\<chinese\\>" cn-gb-2312)
     ("^fj\\>\\|^japan\\>" iso-2022-jp-2)
     ("^relcom\\>" koi8-r)
+    ("^\\(cz\\|hun\\|pl\\|sk\\|hr\\)\\>" iso-8859-2)
+    ("^israel\\>" iso-8859-1)
+    ("^han\\>" euc-kr)
+    ("^\\(comp\\|rec\\|alt\\|sci\\|soc\\|news\\|gnu\\|bofh\\)\\>" iso-8859-1)
     (".*" iso-8859-1))
-  "Alist of regexps (to match group names) and default charsets to be used."
+  "Alist of regexps (to match group names) and default charsets to be used when reading."
   :type '(repeat (list (regexp :tag "Group")
                       (symbol :tag "Charset")))
   :group 'gnus-charset)
 
+(defcustom gnus-newsgroup-ignored-charsets '(unknown-8bit)
+  "List of charsets that should be ignored.
+When these charsets are used in the \"charset\" parameter, the
+default charset will be used instead."
+  :type '(repeat symbol)
+  :group 'gnus-charset)
+
 ;;; 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)
@@ -844,9 +871,10 @@ which it may alter in any way.")
     (?S ,(macroexpand '(mail-header-subject gnus-tmp-header)) ?s)
     (?s gnus-tmp-subject-or-nil ?s)
     (?n gnus-tmp-name ?s)
-    (?A (car (cdr (funcall gnus-extract-address-components gnus-tmp-from)))
-       ?s)
-    (?a (or (car (funcall gnus-extract-address-components gnus-tmp-from))
+    (?A (std11-address-string
+        (car (mime-read-field 'From gnus-tmp-header))) ?s)
+    (?a (or (std11-full-name-string
+            (car (mime-read-field 'From gnus-tmp-header)))
            gnus-tmp-from) ?s)
     (?F gnus-tmp-from ?s)
     (?x ,(macroexpand '(mail-header-xref gnus-tmp-header)) ?s)
@@ -1018,7 +1046,8 @@ variable (string, integer, character, etc).")
     gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay
     gnus-newsgroup-scored gnus-newsgroup-kill-headers
     gnus-thread-expunge-below
-    gnus-score-alist gnus-current-score-file gnus-summary-expunge-below
+    gnus-score-alist gnus-current-score-file
+    (gnus-summary-expunge-below . global)
     (gnus-summary-mark-below . global)
     gnus-newsgroup-active gnus-scores-exclude-files
     gnus-newsgroup-history gnus-newsgroup-ancient
@@ -1035,45 +1064,6 @@ variable (string, integer, character, etc).")
 ;; Byte-compiler warning.
 (defvar gnus-article-mode-map)
 
-;; MIME stuff.
-
-(defvar gnus-decode-encoded-word-methods
-  '(mail-decode-encoded-word-string)
-  "List of methods used to decode encoded words.
-
-This variable is a list of FUNCTION or (REGEXP . FUNCTION). If item is
-FUNCTION, FUNCTION will be apply to all newsgroups. If item is a
-(REGEXP . FUNCTION), FUNCTION will be only apply to thes newsgroups
-whose names match REGEXP.
-
-For example:
-((\"chinese\" . gnus-decode-encoded-word-string-by-guess)
- mail-decode-encoded-word-string
- (\"chinese\" . rfc1843-decode-string))
-")
-
-(defvar gnus-decode-encoded-word-methods-cache nil)
-
-(defun gnus-multi-decode-encoded-word-string (string)
-  "Apply the functions from `gnus-encoded-word-methods' that match."
-  (unless (and gnus-decode-encoded-word-methods-cache
-              (eq gnus-newsgroup-name
-                  (car gnus-decode-encoded-word-methods-cache)))
-    (setq gnus-decode-encoded-word-methods-cache (list gnus-newsgroup-name))
-    (mapc '(lambda (x)
-            (if (symbolp x)
-                (nconc gnus-decode-encoded-word-methods-cache (list x))
-              (if (and gnus-newsgroup-name
-                       (string-match (car x) gnus-newsgroup-name))
-                  (nconc gnus-decode-encoded-word-methods-cache
-                         (list (cdr x))))))
-         gnus-decode-encoded-word-methods))
-  (let ((xlist gnus-decode-encoded-word-methods-cache))
-    (pop xlist)
-    (while xlist
-      (setq string (funcall (pop xlist) string))))
-  string)
-
 ;; Subject simplification.
 
 (defun gnus-simplify-whitespace (str)
@@ -1264,6 +1254,7 @@ increase the score of each group you read."
     "\C-c\M-\C-s" gnus-summary-limit-include-expunged
     "\C-c\C-s\C-n" gnus-summary-sort-by-number
     "\C-c\C-s\C-l" gnus-summary-sort-by-lines
+    "\C-c\C-s\C-c" gnus-summary-sort-by-chars
     "\C-c\C-s\C-a" gnus-summary-sort-by-author
     "\C-c\C-s\C-s" gnus-summary-sort-by-subject
     "\C-c\C-s\C-d" gnus-summary-sort-by-date
@@ -1273,6 +1264,7 @@ increase the score of each group you read."
     "\M-g" gnus-summary-rescan-group
     "w" gnus-summary-stop-page-breaking
     "\C-c\C-r" gnus-summary-caesar-message
+    "\M-t" gnus-summary-toggle-mime
     "f" gnus-summary-followup
     "F" gnus-summary-followup-with-original
     "C" gnus-summary-cancel-article
@@ -1297,6 +1289,7 @@ increase the score of each group you read."
     "t" gnus-article-hide-headers
     "g" gnus-summary-show-article
     "l" gnus-summary-goto-last-article
+    "v" gnus-summary-preview-mime-message
     "\C-c\C-v\C-v" gnus-uu-decode-uu-view
     "\C-d" gnus-summary-enter-digest-group
     "\M-\C-d" gnus-summary-read-document
@@ -1312,9 +1305,6 @@ increase the score of each group you read."
     "\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
     "S" gnus-summary-send-map)
@@ -1356,6 +1346,7 @@ increase the score of each group you read."
     "a" gnus-summary-limit-to-author
     "u" gnus-summary-limit-to-unread
     "m" gnus-summary-limit-to-marks
+    "M" gnus-summary-limit-exclude-marks
     "v" gnus-summary-limit-to-score
     "*" gnus-summary-limit-include-cached
     "D" gnus-summary-limit-include-dormant
@@ -1432,6 +1423,7 @@ increase the score of each group you read."
     "e" gnus-summary-end-of-article
     "^" gnus-summary-refer-parent-article
     "r" gnus-summary-refer-parent-article
+    "D" gnus-summary-enter-digest-group
     "R" gnus-summary-refer-references
     "T" gnus-summary-refer-thread
     "g" gnus-summary-show-article
@@ -1444,14 +1436,17 @@ increase the score of each group you read."
     "o" gnus-article-treat-overstrike
     "e" gnus-article-emphasize
     "w" gnus-article-fill-cited-article
+    "Q" gnus-article-fill-long-lines
+    "C" gnus-article-capitalize-sentences
     "c" gnus-article-remove-cr
-    "q" gnus-article-de-quoted-unreadable
     "f" gnus-article-display-x-face
     "l" gnus-summary-stop-page-breaking
     "r" gnus-summary-caesar-message
     "t" gnus-article-hide-headers
     "v" gnus-summary-verbose-headers
+    "m" gnus-summary-toggle-mime
     "h" gnus-article-treat-html
+    "H" gnus-article-strip-headers-in-body
     "d" gnus-article-treat-dumbquotes)
 
   (gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map)
@@ -1462,6 +1457,7 @@ increase the score of each group you read."
     "c" gnus-article-hide-citation
     "C" gnus-article-hide-citation-in-followups
     "p" gnus-article-hide-pgp
+    "B" gnus-article-strip-banner
     "P" gnus-article-hide-pem
     "\C-c" gnus-article-hide-citation-maybe)
 
@@ -1471,12 +1467,6 @@ increase the score of each group you read."
     "c" gnus-article-highlight-citation
     "s" gnus-article-highlight-signature)
 
-  (gnus-define-keys (gnus-summary-wash-mime-map "M" gnus-summary-wash-map)
-    "w" gnus-article-decode-mime-words
-    "c" gnus-article-decode-charset
-    "v" gnus-mime-view-all-parts
-    "b" gnus-article-view-part)
-
   (gnus-define-keys (gnus-summary-wash-time-map "T" gnus-summary-wash-map)
     "z" gnus-article-date-ut
     "u" gnus-article-date-ut
@@ -1536,6 +1526,7 @@ increase the score of each group you read."
     "o" gnus-article-save-part
     "c" gnus-article-copy-part
     "e" gnus-article-externalize-part
+    "i" gnus-article-inline-part
     "|" gnus-article-pipe-part)
   )
 
@@ -1581,17 +1572,13 @@ increase the score of each group you read."
               ["Signature" gnus-article-hide-signature t]
               ["Citation" gnus-article-hide-citation t]
               ["PGP" gnus-article-hide-pgp t]
+             ["Banner" gnus-article-strip-banner t]
               ["Boring headers" gnus-article-hide-boring-headers t])
              ("Highlight"
               ["All" gnus-article-highlight t]
               ["Headers" gnus-article-highlight-headers t]
               ["Signature" gnus-article-highlight-signature t]
               ["Citation" gnus-article-highlight-citation t])
-            ("MIME"
-             ["Words" gnus-article-decode-mime-words t]
-             ["Charset" gnus-article-decode-charset t]
-             ["QP" gnus-article-de-quoted-unreadable t]
-             ["View all" gnus-mime-view-all-parts t])
              ("Date"
               ["Local" gnus-article-date-local t]
               ["ISO8601" gnus-article-date-iso8601 t]
@@ -1612,15 +1599,17 @@ increase the score of each group you read."
               ["Dumb quotes" gnus-article-treat-dumbquotes t]
               ["Emphasis" gnus-article-emphasize t]
               ["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]
               ["Show X-Face" gnus-article-display-x-face t]
-              ["Quoted-Printable" gnus-article-de-quoted-unreadable t]
               ["UnHTMLize" gnus-article-treat-html t]
               ["Rot 13" gnus-summary-caesar-message t]
               ["Unix pipe" gnus-summary-pipe-message t]
               ["Add buttons" gnus-article-add-buttons t]
               ["Add buttons to head" gnus-article-add-buttons-to-head t]
               ["Stop page breaking" gnus-summary-stop-page-breaking t]
+              ["Toggle MIME" gnus-summary-toggle-mime t]
               ["Verbose header" gnus-summary-verbose-headers t]
               ["Toggle header" gnus-summary-toggle-header t])
              ("Output"
@@ -1717,8 +1706,8 @@ increase the score of each group you read."
        ["Wide reply and yank" gnus-summary-wide-reply-with-original t]
        ["Mail forward" gnus-summary-mail-forward t]
        ["Post forward" gnus-summary-post-forward t]
-       ["Digest and mail" gnus-uu-digest-mail-forward t]
-       ["Digest and post" gnus-uu-digest-post-forward t]
+       ["Digest and mail" gnus-summary-mail-digest t]
+       ["Digest and post" gnus-summary-post-digest t]
        ["Resend message" gnus-summary-resend-message t]
        ["Send bounced mail" gnus-summary-resend-bounced-mail t]
        ["Send a mail" gnus-summary-mail-other-window t]
@@ -1765,6 +1754,7 @@ increase the score of each group you read."
        ["Hide childless dormant"
         gnus-summary-limit-exclude-childless-dormant t]
        ;;["Hide thread" gnus-summary-limit-exclude-thread t]
+       ["Hide marked" gnus-summary-limit-exclude-marks t]
        ["Show expunged" gnus-summary-show-all-expunged t])
        ("Process Mark"
        ["Set mark" gnus-summary-mark-as-processable t]
@@ -1811,7 +1801,8 @@ increase the score of each group you read."
        ["Sort by subject" gnus-summary-sort-by-subject t]
        ["Sort by date" gnus-summary-sort-by-date t]
        ["Sort by score" gnus-summary-sort-by-score t]
-       ["Sort by lines" gnus-summary-sort-by-lines t])
+       ["Sort by lines" gnus-summary-sort-by-lines t]
+       ["Sort by characters" gnus-summary-sort-by-chars t])
        ("Help"
        ["Fetch group FAQ" gnus-summary-fetch-faq t]
        ["Describe group" gnus-summary-describe-group t]
@@ -1981,20 +1972,16 @@ 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 'post-command-hook)
-  (add-hook 'post-command-hook 'gnus-clear-inboxes-moved nil t)
   (make-local-hook 'pre-command-hook)
   (add-hook 'pre-command-hook 'gnus-set-global-variables nil t)
   (gnus-run-hooks 'gnus-summary-mode-hook)
-  (mm-enable-multibyte)
   (gnus-update-format-specifications nil 'summary 'summary-mode 'summary-dummy)
   (gnus-update-summary-mark-positions))
 
 (defun gnus-summary-make-local-variables ()
   "Make all the local summary buffer variables."
-  (let ((locals gnus-summary-local-variables)
-       global local)
-    (while (setq local (pop locals))
+  (let (global)
+    (dolist (local gnus-summary-local-variables)
       (if (consp local)
          (progn
            (if (eq (cdr local) 'global)
@@ -2002,11 +1989,9 @@ The following commands are available:
                (setq global (symbol-value (car local)))
              ;; Use the value from the list.
              (setq global (eval (cdr local))))
-           (make-local-variable (car local))
-           (set (car local) global))
+           (set (make-local-variable (car local)) global))
        ;; Simple nil-valued local variable.
-       (make-local-variable local)
-       (set local nil)))))
+       (set (make-local-variable local) nil)))))
 
 (defun gnus-summary-clear-local-variables ()
   (let ((locals gnus-summary-local-variables))
@@ -2467,7 +2452,8 @@ marks of articles."
        (let ((gnus-summary-line-format-spec spec)
              (gnus-newsgroup-downloadable '((0 . t))))
          (gnus-summary-insert-line
-          [0 "" "" "" "" "" 0 0 "" nil]  0 nil 128 t nil "" nil 1)
+          (make-full-mail-header 0 "" "" "" "" "" 0 0 "" nil)
+          0 nil 128 t nil "" nil 1)
          (goto-char (point-min))
          (setq pos (list (cons 'unread (and (search-forward "\200" nil t)
                                             (- (point) 2)))))
@@ -2561,7 +2547,7 @@ marks of articles."
       (setq gnus-tmp-name gnus-tmp-from))
     (unless (numberp gnus-tmp-lines)
       (setq gnus-tmp-lines 0))
-    (gnus-put-text-property
+    (gnus-put-text-property-excluding-characters-with-faces
      (point)
      (progn (eval gnus-summary-line-format-spec) (point))
      'gnus-number gnus-tmp-number)
@@ -3161,31 +3147,6 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
             (setq heads nil)))))
      gnus-newsgroup-dependencies)))
 
-(defmacro gnus-nov-read-integer ()
-  '(prog1
-       (if (eq (char-after) ?\t)
-          0
-        (let ((num (ignore-errors (read buffer))))
-          (if (numberp num) num 0)))
-     (unless (eobp)
-       (search-forward "\t" eol 'move))))
-
-(defmacro gnus-nov-skip-field ()
-  '(search-forward "\t" eol 'move))
-
-(defmacro gnus-nov-field ()
-  '(buffer-substring (point) (if (gnus-nov-skip-field) (1- (point)) eol)))
-
-(defmacro gnus-nov-parse-extra ()
-  '(let (out string)
-     (while (not (memq (char-after) '(?\n nil)))
-       (setq string (gnus-nov-field))
-       (when (string-match "^\\([^ :]+\\): " string)
-        (push (cons (intern (match-string 1 string))
-                    (substring string (match-end 0)))
-              out)))
-     out))
-
 ;; This function has to be called with point after the article number
 ;; on the beginning of the line.
 (defsubst gnus-nov-parse-line (number dependencies &optional force-new)
@@ -3194,30 +3155,22 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
        header)
 
     ;; overview: [num subject from date id refs chars lines misc]
-    (unwind-protect
-       (progn
-         (narrow-to-region (point) eol)
-         (unless (eobp)
-           (forward-char))
-
-         (setq header
-               (make-full-mail-header
-                number                 ; number
-                (funcall gnus-decode-encoded-word-function
-                         (gnus-nov-field)) ; subject
-                (funcall gnus-decode-encoded-word-function
-                         (gnus-nov-field)) ; from
-                (gnus-nov-field)       ; date
-                (or (gnus-nov-field)
-                    (nnheader-generate-fake-message-id)) ; id
-                (gnus-nov-field)       ; refs
-                (gnus-nov-read-integer) ; chars
-                (gnus-nov-read-integer) ; lines
-                (unless (eq (char-after) ?\n)
-                  (gnus-nov-field))    ; misc
-                (gnus-nov-parse-extra)))) ; extra
-
-      (widen))
+    (unless (eobp)
+      (forward-char))
+
+    (setq header
+         (make-full-mail-header
+          number                               ; number
+          (nnheader-nov-field)                 ; subject
+          (nnheader-nov-field)                 ; from
+          (nnheader-nov-field)                 ; date
+          (nnheader-nov-read-message-id)       ; id
+          (nnheader-nov-field)                 ; refs
+          (nnheader-nov-read-integer)          ; chars
+          (nnheader-nov-read-integer)          ; lines
+          (unless (eobp)
+            (nnheader-nov-field))              ; misc
+          (nnheader-nov-parse-extra)))         ; extra
 
     (when gnus-alter-header-function
       (funcall gnus-alter-header-function header))
@@ -3600,17 +3553,28 @@ If LINE, insert the rebuilt thread starting on line LINE."
   (gnus-article-sort-by-lines
    (gnus-thread-header h1) (gnus-thread-header h2)))
 
+(defsubst gnus-article-sort-by-chars (h1 h2)
+  "Sort articles by octet length."
+  (< (mail-header-chars h1)
+     (mail-header-chars h2)))
+
+(defun gnus-thread-sort-by-chars (h1 h2)
+  "Sort threads by root article octet length."
+  (gnus-article-sort-by-chars
+   (gnus-thread-header h1) (gnus-thread-header h2)))
+
 (defsubst gnus-article-sort-by-author (h1 h2)
   "Sort articles by root author."
   (string-lessp
-   (let ((extract (funcall
-                  gnus-extract-address-components
-                  (mail-header-from h1))))
-     (or (car extract) (cadr extract) ""))
-   (let ((extract (funcall
-                  gnus-extract-address-components
-                  (mail-header-from h2))))
-     (or (car extract) (cadr extract) ""))))
+   (let ((addr (mime-read-field 'From h1)))
+     (or (std11-full-name-string addr)
+        (std11-address-string addr)
+        ""))
+   (let ((addr (mime-read-field 'From h2)))
+     (or (std11-full-name-string addr)
+        (std11-address-string addr)
+        ""))
+   ))
 
 (defun gnus-thread-sort-by-author (h1 h2)
   "Sort threads by root author."
@@ -4020,8 +3984,10 @@ If SELECT-ARTICLES, only select those articles from GROUP."
       (gnus-adjust-marked-articles info))
 
     ;; Kludge to avoid having cached articles nixed out in virtual groups.
-    (when (gnus-virtual-group-p group)
-      (setq cached gnus-newsgroup-cached))
+    (setq cached
+         (if (gnus-virtual-group-p group)
+             gnus-newsgroup-cached
+           (gnus-cache-articles-in-group group)))
 
     (setq gnus-newsgroup-unreads
          (gnus-set-difference
@@ -4052,26 +4018,16 @@ If SELECT-ARTICLES, only select those articles from GROUP."
       ;; Retrieve the headers and read them in.
       (gnus-message 5 "Fetching headers for %s..." gnus-newsgroup-name)
       (setq gnus-newsgroup-headers
-           (if (eq 'nov
-                   (setq gnus-headers-retrieved-by
-                         (gnus-retrieve-headers
-                          articles gnus-newsgroup-name
-                          ;; We might want to fetch old headers, but
-                          ;; not if there is only 1 article.
-                          (and (or (and
-                                    (not (eq gnus-fetch-old-headers 'some))
-                                    (not (numberp gnus-fetch-old-headers)))
-                                   (> (length articles) 1))
-                               gnus-fetch-old-headers))))
-               (gnus-get-newsgroup-headers-xover
-                articles nil nil gnus-newsgroup-name t)
-             (gnus-get-newsgroup-headers)))
+           (gnus-retrieve-parsed-headers
+            articles gnus-newsgroup-name
+            ;; We might want to fetch old headers, but
+            ;; not if there is only 1 article.
+            (and (or (and (not (eq gnus-fetch-old-headers 'some))
+                          (not (numberp gnus-fetch-old-headers)))
+                     (> (length articles) 1))
+                 gnus-fetch-old-headers)))
       (gnus-message 5 "Fetching headers for %s...done" gnus-newsgroup-name)
 
-      ;; Kludge to avoid having cached articles nixed out in virtual groups.
-      (when cached
-       (setq gnus-newsgroup-cached cached))
-
       ;; Suppress duplicates?
       (when gnus-suppress-duplicates
        (gnus-dup-suppress-articles))
@@ -4088,6 +4044,11 @@ If SELECT-ARTICLES, only select those articles from GROUP."
       ;; Removed marked articles that do not exist.
       (gnus-update-missing-marks
        (gnus-sorted-complement fetched-articles articles))
+
+      ;; Kludge to avoid having cached articles nixed out in virtual groups.
+      (when cached
+       (setq gnus-newsgroup-cached cached))
+
       ;; We might want to build some more threads first.
       (when (and gnus-fetch-old-headers
                 (eq gnus-headers-retrieved-by 'nov))
@@ -4140,15 +4101,20 @@ If SELECT-ARTICLES, only select those articles from GROUP."
            (condition-case ()
                (cond
                 ((and (or (<= scored marked) (= scored number))
-                      (numberp gnus-large-newsgroup)
+                      (natnump gnus-large-newsgroup)
                       (> number gnus-large-newsgroup))
-                 (let ((input
-                        (read-string
-                         (format
-                          "How many articles from %s (default %d): "
-                          (gnus-limit-string gnus-newsgroup-name 35)
-                          number))))
-                   (if (string-match "^[ \t]*$" input) number input)))
+                 (let* ((minibuffer-setup-hook (append
+                                                minibuffer-setup-hook
+                                                '(beginning-of-line)))
+                        (input (read-string
+                                (format
+                                 "How many articles from %s (max %d): "
+                                 (gnus-limit-string gnus-newsgroup-name 35)
+                                 number)
+                                (number-to-string gnus-large-newsgroup))))
+                   (if (string-match "^[ \t]*$" input)
+                       number
+                     input)))
                 ((and (> scored marked) (< scored number)
                       (> (- scored number) 20))
                  (let ((input
@@ -4261,13 +4227,14 @@ If SELECT-ARTICLES, only select those articles from GROUP."
        (uncompressed '(score bookmark killed))
        type list newmarked symbol delta-marks)
     (when info
-      ;; Add all marks lists that are non-nil to the list of marks lists.
+      ;; Add all marks lists to the list of marks lists.
       (while (setq type (pop types))
-       (when (setq list (symbol-value
+       (setq list (symbol-value
                          (setq symbol
                                (intern (format "gnus-newsgroup-%s"
                                                (car type))))))
 
+       (when list
          ;; Get rid of the entries of the articles that have the
          ;; default score.
          (when (and (eq (cdr type) 'score)
@@ -4282,30 +4249,35 @@ If SELECT-ARTICLES, only select those articles from GROUP."
                    (setcdr prev (cdr arts))
                  (setq prev arts))
                (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)))))
-
+             (setq list (cdr all)))))
+
+         (when (gnus-check-backend-function 'request-set-mark
+                                            gnus-newsgroup-name)
+           ;; uncompressed:s are not proper flags (they are cons cells)
+           ;; cache is a internal gnus flag
+           (unless (memq (cdr type) (cons 'cache uncompressed))
+             (let* ((old (cdr (assq (cdr type) (gnus-info-marks info))))
+                    (list (gnus-compress-sequence (sort list '<)))
+                    (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)))))
+         
+       (when list
          (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))
-
+      (when delta-marks
+       (unless (gnus-check-group gnus-newsgroup-name)
+         (error "Can't open server for %s" gnus-newsgroup-name))
+       (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)
@@ -4376,7 +4348,7 @@ If WHERE is `summary', the summary mode line format will be used."
          ;; We might have to chop a bit of the string off...
          (when (> (length mode-string) max-len)
            (setq mode-string
-                 (concat (truncate-string-to-width mode-string (- max-len 3))
+                 (concat (gnus-truncate-string mode-string (- max-len 3))
                          "...")))
          ;; Pad the mode string a bit.
          (setq mode-string (format (format "%%-%ds" max-len) mode-string))))
@@ -4523,15 +4495,6 @@ The resulting hash table is returned, or nil if no Xrefs were found."
        ;; Update the group buffer.
        (gnus-group-update-group group t)))))
 
-(defun gnus-methods-equal-p (m1 m2)
-  (let ((m1 (or m1 gnus-select-method))
-       (m2 (or m2 gnus-select-method)))
-    (or (equal m1 m2)
-       (and (eq (car m1) (car m2))
-            (or (not (memq 'address (assoc (symbol-name (car m1))
-                                           gnus-valid-select-methods)))
-                (equal (nth 1 m1) (nth 1 m2)))))))
-
 (defvar gnus-newsgroup-none-id 0)
 
 (defun gnus-get-newsgroup-headers (&optional dependencies force-new)
@@ -4549,7 +4512,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
       (subst-char-in-region (point-min) (point-max) ?\r ?  t)
       (gnus-run-hooks 'gnus-parse-headers-hook)
       (let ((case-fold-search t)
-           in-reply-to header p lines chars)
+           in-reply-to header p lines chars ctype)
        (goto-char (point-min))
        ;; Search to the beginning of the next header.  Error messages
        ;; do not begin with 2 or 3.
@@ -4564,7 +4527,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
          ;; doesn't always go hand in hand.
          (setq
           header
-          (vector
+          (make-full-mail-header
            ;; Number.
            (prog1
                (read cur)
@@ -4578,21 +4541,20 @@ The resulting hash table is returned, or nil if no Xrefs were found."
            (progn
              (goto-char p)
              (if (search-forward "\nsubject: " nil t)
-                 (funcall gnus-decode-encoded-word-function
-                          (nnheader-header-value))
+                 (buffer-substring (match-end 0) (std11-field-end))
                "(none)"))
            ;; From.
            (progn
              (goto-char p)
              (if (search-forward "\nfrom: " nil t)
-                 (funcall gnus-decode-encoded-word-function
-                          (nnheader-header-value))
+                 (buffer-substring (match-end 0) (std11-field-end))
                "(nobody)"))
            ;; Date.
            (progn
              (goto-char p)
              (if (search-forward "\ndate: " nil t)
-                 (nnheader-header-value) ""))
+                 (buffer-substring (match-end 0) (std11-field-end))
+               ""))
            ;; Message-ID.
            (progn
              (goto-char p)
@@ -4612,11 +4574,11 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                  (progn
                    (setq end (point))
                    (prog1
-                       (nnheader-header-value)
+                       (buffer-substring (match-end 0) (std11-field-end))
                      (setq ref
                            (buffer-substring
                             (progn
-                              (end-of-line)
+                               ;; (end-of-line)
                               (search-backward ">" end t)
                               (1+ (point)))
                             (progn
@@ -4626,7 +4588,9 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                ;; were no references and the in-reply-to header looks
                ;; promising.
                (if (and (search-forward "\nin-reply-to: " nil t)
-                        (setq in-reply-to (nnheader-header-value))
+                        (setq in-reply-to
+                              (buffer-substring (match-end 0)
+                                                (std11-field-end)))
                         (string-match "<[^>]+>" in-reply-to))
                    (let (ref2)
                      (setq ref (substring in-reply-to (match-beginning 0)
@@ -4656,7 +4620,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
            (progn
              (goto-char p)
              (and (search-forward "\nxref: " nil t)
-                  (nnheader-header-value)))
+                  (buffer-substring (match-end 0) (std11-field-end))))
            ;; Extra.
            (when gnus-extra-headers
              (let ((extra gnus-extra-headers)
@@ -4665,10 +4629,18 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                  (goto-char p)
                  (when (search-forward
                         (concat "\n" (symbol-name (car extra)) ": ") nil t)
-                   (push (cons (car extra) (nnheader-header-value))
+                   (push (cons (car extra)
+                               (buffer-substring (match-end 0)
+                                                 (std11-field-end)))
                          out))
                  (pop extra))
                out))))
+         (goto-char p)
+         (if (and (search-forward "\ncontent-type: " nil t)
+                  (setq ctype
+                        (buffer-substring (match-end 0) (std11-field-end))))
+             (mime-entity-set-content-type-internal
+              header (mime-parse-Content-Type ctype)))
          (when (equal id ref)
            (setq ref nil))
 
@@ -4737,8 +4709,8 @@ list of headers that match SEQUENCE (see `nntp-retrieve-headers')."
        (let ((gnus-nov-is-evil t))
          (nconc
           (nreverse headers)
-          (when (gnus-retrieve-headers sequence group)
-            (gnus-get-newsgroup-headers))))))))
+          (gnus-retrieve-parsed-headers sequence group)
+          ))))))
 
 (defun gnus-article-get-xrefs ()
   "Fill in the Xref value in `gnus-current-headers', if necessary.
@@ -4846,7 +4818,7 @@ current article will be taken into consideration."
       (let ((max (max (point) (mark)))
            articles article)
        (save-excursion
-         (goto-char (min (min (point) (mark))))
+         (goto-char (min (point) (mark)))
          (while
              (and
               (push (setq article (gnus-summary-article-number)) articles)
@@ -5232,10 +5204,6 @@ 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)
@@ -5328,10 +5296,6 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
       (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)
-         (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)
@@ -5393,6 +5357,14 @@ The state which existed when entering the ephemeral is reset."
       (gnus-summary-recenter)
       (gnus-summary-position-point))))
 
+(defun gnus-summary-preview-mime-message ()
+  "MIME decode and play this message."
+  (interactive)
+  (let ((gnus-break-pages nil)
+       (gnus-show-mime t))
+    (gnus-summary-select-article gnus-show-all-headers t))
+  (select-window (get-buffer-window gnus-article-buffer)))
+
 ;;; Dead summaries.
 
 (defvar gnus-dead-summary-mode-map nil)
@@ -5720,7 +5692,9 @@ be displayed."
              ;; The requested article is different from the current article.
              (prog1
                  (gnus-summary-display-article article all-headers)
-               (setq did article))
+               (setq did article)
+               (when (or all-headers gnus-show-all-headers)
+                 (gnus-article-show-all-headers)))
            (when (or all-headers gnus-show-all-headers)
              (gnus-article-show-all-headers))
            'old))
@@ -6807,12 +6781,12 @@ Optional argument BACKWARD means do search for backward.
   (require 'gnus-async)
   (require 'gnus-art)
   (let ((gnus-select-article-hook nil) ;Disable hook.
+       (gnus-article-display-hook nil)
        (gnus-mark-article-hook nil)    ;Inhibit marking as read.
        (gnus-use-article-prefetch nil)
        (gnus-xmas-force-redisplay nil) ;Inhibit XEmacs redisplay.
        (gnus-use-trees nil)            ;Inhibit updating tree buffer.
        (sum (current-buffer))
-       (gnus-display-mime-function nil)
        (found nil)
        point)
     (gnus-save-hidden-threads
@@ -6944,7 +6918,7 @@ article.  If BACKWARD (the prefix) is non-nil, search backward instead."
 If N is negative, print the N previous articles.  If N is nil and articles
 have been marked with the process mark, print these instead.
 
-If the optional second argument FILENAME is nil, send the image to the
+If the optional first argument FILENAME is nil, send the image to the
 printer.  If FILENAME is a string, save the PostScript image in a file with
 that name.  If FILENAME is a number, prompt the user for the name of the file
 to save in."
@@ -6989,16 +6963,12 @@ article massaging functions being run."
     (require 'gnus-art)
     ;; Bind the article treatment functions to nil.
     (let ((gnus-have-all-headers t)
+         gnus-article-display-hook
          gnus-article-prepare-hook
          gnus-article-decode-hook
-         gnus-display-mime-function
          gnus-break-pages
+         gnus-show-mime
          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))
@@ -7023,33 +6993,47 @@ If ARG is a negative number, hide the unwanted header lines."
   (interactive "P")
   (save-excursion
     (set-buffer gnus-article-buffer)
-    (let* ((buffer-read-only nil)
-          (inhibit-point-motion-hooks t)
-          (hidden (text-property-any
-                   (goto-char (point-min)) (search-forward "\n\n")
-                   'invisible t))
-          e)
-      (goto-char (point-min))
-      (when (search-forward "\n\n" nil t)
-       (delete-region (point-min) (1- (point))))
-      (goto-char (point-min))
-      (save-excursion
-       (set-buffer gnus-original-article-buffer)
+    (save-restriction
+      (let* ((buffer-read-only nil)
+            (inhibit-point-motion-hooks t)
+            hidden e)
+       (save-restriction 
+         (article-narrow-to-head)
+         (setq hidden (gnus-article-hidden-text-p 'headers)))
+       (goto-char (point-min))
+       (when (search-forward "\n\n" nil t)
+         (delete-region (point-min) (1- (point))))
        (goto-char (point-min))
-       (setq e (1- (or (search-forward "\n\n" nil t) (point-max)))))
-      (insert-buffer-substring gnus-original-article-buffer 1 e)
-      (narrow-to-region (point-min) (point))
-      (if (or (not hidden) (and (numberp arg) (< arg 0)))
-         (let ((gnus-treat-hide-headers nil)
-               (gnus-treat-hide-boring-headers nil))
-           (gnus-treat-article 'head))
-       (gnus-treat-article 'head)))))
+       (save-excursion
+         (set-buffer gnus-original-article-buffer)
+         (goto-char (point-min))
+         (setq e (1- (or (search-forward "\n\n" nil t) (point-max)))))
+       (insert-buffer-substring gnus-original-article-buffer 1 e)
+       (save-restriction
+         (narrow-to-region (point-min) (point))
+         (article-decode-encoded-words)
+         (if (or hidden
+                 (and (numberp arg) (< arg 0)))
+             (let ((gnus-treat-hide-headers nil)
+                   (gnus-treat-hide-boring-headers nil))
+               (gnus-treat-article 'head))
+           (gnus-treat-article 'head)))))))
 
 (defun gnus-summary-show-all-headers ()
   "Make all header lines visible."
   (interactive)
   (gnus-article-show-all-headers))
 
+(defun gnus-summary-toggle-mime (&optional arg)
+  "Toggle MIME processing.
+If ARG is a positive number, turn MIME processing on."
+  (interactive "P")
+  (setq gnus-show-mime
+       (if (null arg)
+           (not gnus-show-mime)
+         (> (prefix-numeric-value arg) 0)))
+  (gnus-summary-select-article t 'force))
+
 (defun gnus-summary-caesar-message (&optional arg)
   "Caesar rotate the current article by 13.
 The numerical prefix specifies how many places to rotate each letter
@@ -7114,6 +7098,9 @@ and `request-accept' functions."
                 (crosspost "Crosspost" "Crossposting")))
        (copy-buf (save-excursion
                    (nnheader-set-temp-buffer " *copy article*")))
+       (default-marks gnus-article-mark-lists)
+       (no-expire-marks (delete '(expirable . expire)
+                                (copy-sequence gnus-article-mark-lists)))
        art-group to-method new-xref article to-groups)
     (unless (assq action names)
       (error "Unknown action %s" action))
@@ -7219,7 +7206,9 @@ and `request-accept' functions."
                                       (list (cdr art-group)))))
 
            ;; Copy any marks over to the new group.
-           (let ((marks gnus-article-mark-lists)
+           (let ((marks (if (gnus-group-auto-expirable-p to-group)
+                            default-marks
+                          no-expire-marks))
                  (to-article (cdr art-group)))
 
              ;; See whether the article is to be put in the cache.
@@ -7370,7 +7359,7 @@ latter case, they will be copied into the relevant groups."
     (save-excursion
       (set-buffer (gnus-get-buffer-create " *import file*"))
       (erase-buffer)
-      (insert-file-contents file)
+      (nnheader-insert-file-contents file)
       (goto-char (point-min))
       (unless (nnheader-article-p)
        ;; This doesn't look like an article, so we fudge some headers.
@@ -7425,6 +7414,8 @@ This will be the case if the article has both been mailed and posted."
        ;; There are expirable articles in this group, so we run them
        ;; through the expiry process.
        (gnus-message 6 "Expiring articles...")
+       (unless (gnus-check-group gnus-newsgroup-name)
+         (error "Can't open server for %s" gnus-newsgroup-name))
        ;; The list of articles that weren't expired is returned.
        (save-excursion
          (if expiry-wait
@@ -7504,22 +7495,21 @@ This will have permanent effect only in mail groups.
 If FORCE is non-nil, allow editing of articles even in read-only
 groups."
   (interactive "P")
-  (save-excursion
-    (set-buffer gnus-summary-buffer)
-    (gnus-set-global-variables)
-    (when (and (not force)
-              (gnus-group-read-only-p))
-      (error "The current newsgroup does not support article editing"))
-    ;; Select article if needed.
-    (unless (eq (gnus-summary-article-number)
-               gnus-current-article)
-      (gnus-summary-select-article t))
-    (gnus-article-date-original)
-    (gnus-article-edit-article
-     `(lambda (no-highlight)
-       (gnus-summary-edit-article-done
-        ,(or (mail-header-references gnus-current-headers) "")
-        ,(gnus-group-read-only-p) ,gnus-summary-buffer no-highlight)))))
+  (let ((mail-parse-charset gnus-newsgroup-charset))
+    (save-excursion
+      (set-buffer gnus-summary-buffer)
+      (gnus-set-global-variables)
+      (when (and (not force)
+                (gnus-group-read-only-p))
+       (error "The current newsgroup does not support article editing"))
+      (gnus-summary-show-article t)
+      (gnus-article-edit-article
+       'ignore
+       `(lambda (no-highlight)
+         (let ((mail-parse-charset ',gnus-newsgroup-charset))
+           (gnus-summary-edit-article-done
+            ,(or (mail-header-references gnus-current-headers) "")
+            ,(gnus-group-read-only-p) ,gnus-summary-buffer no-highlight)))))))
 
 (defalias 'gnus-summary-edit-article-postpone 'gnus-article-edit-exit)
 
@@ -7534,8 +7524,7 @@ groups."
       (if (and (not read-only)
               (not (gnus-request-replace-article
                     (cdr gnus-article-current) (car gnus-article-current)
-                    (current-buffer)
-                    (not gnus-article-decoded-p))))
+                    (current-buffer) t)))
          (error "Couldn't replace article")
        ;; Update the summary buffer.
        (if (and references
@@ -8600,11 +8589,17 @@ Argument REVERSE means reverse order."
   (gnus-summary-sort 'score reverse))
 
 (defun gnus-summary-sort-by-lines (&optional reverse)
-  "Sort the summary buffer by article length.
+  "Sort the summary buffer by the number of lines.
 Argument REVERSE means reverse order."
   (interactive "P")
   (gnus-summary-sort 'lines reverse))
 
+(defun gnus-summary-sort-by-chars (&optional reverse)
+  "Sort the summary buffer by article length.
+Argument REVERSE means reverse order."
+  (interactive "P")
+  (gnus-summary-sort 'chars reverse))  
+
 (defun gnus-summary-sort (predicate reverse)
   "Sort summary buffer by PREDICATE.  REVERSE means reverse order."
   (let* ((thread (intern (format "gnus-thread-sort-by-%s" predicate)))
@@ -8641,10 +8636,9 @@ The variable `gnus-default-article-saver' specifies the saver function."
         (save-buffer (save-excursion
                        (nnheader-set-temp-buffer " *Gnus Save*")))
         (num (length articles))
-        header article file)
-    (while articles
-      (setq header (gnus-summary-article-header
-                   (setq article (pop articles))))
+        header file)
+    (dolist (article articles)
+      (setq header (gnus-summary-article-header article))
       (if (not (vectorp header))
          ;; This is a pseudo-article.
          (if (assq 'name header)
@@ -8694,7 +8688,7 @@ If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 save those articles instead."
   (interactive "P")
-  (let ((gnus-default-article-saver 'rmail-output-to-rmail-file))
+  (let ((gnus-default-article-saver 'gnus-summary-save-in-rmail))
     (gnus-summary-save-article arg)))
 
 (defun gnus-summary-save-article-file (&optional arg)
@@ -8774,7 +8768,7 @@ save those articles instead."
                           split-name))
                    ((consp result)
                     (setq split-name (append result split-name)))))))))
-    split-name))
+    (nreverse split-name)))
 
 (defun gnus-valid-move-group-p (group)
   (and (boundp group)
@@ -8870,7 +8864,7 @@ save those articles instead."
                                (lambda (f)
                                  (if (equal f " ")
                                      f
-                                   (mm-quote-arg f)))
+                                   (gnus-quote-arg-for-sh-or-csh f)))
                                files " ")))))
          (setq ps (cdr ps)))))
     (if (and gnus-view-pseudos (not not-view))
@@ -9130,6 +9124,8 @@ save those articles instead."
            (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)
+              (unless (gnus-check-group group)
+                (error "Can't open server for %s" group))
                (gnus-request-set-mark
                 group (delq nil (list (if add (list add 'add '(read)))
                                       (if del (list del 'del '(read)))))))))
@@ -9167,13 +9163,140 @@ save those articles instead."
           (gnus-summary-exit))
         buffers)))))
 
+
+;;; @ for mime-partial
+;;;
+
+(defun gnus-request-partial-message ()
+  (save-excursion
+    (let ((number (gnus-summary-article-number))
+         (group gnus-newsgroup-name)
+         (mother gnus-article-buffer))
+      (set-buffer (get-buffer-create " *Partial Article*"))
+      (erase-buffer)
+      (setq mime-preview-buffer mother)
+      (gnus-request-article-this-buffer number group)
+      (mime-parse-buffer)
+      )))
+
+(autoload 'mime-combine-message/partial-pieces-automatically
+  "mime-partial"
+  "Internal method to combine message/partial messages automatically.")
+
+(mime-add-condition
+ 'action '((type . message)(subtype . partial)
+          (major-mode . gnus-original-article-mode)
+          (method . mime-combine-message/partial-pieces-automatically)
+          (summary-buffer-exp . gnus-summary-buffer)
+          (request-partial-message-method . gnus-request-partial-message)
+          ))
+
+
+;;; @ for message/rfc822
+;;;
+
+(defun gnus-mime-extract-message/rfc822 (entity situation)
+  (let (group article num cwin swin cur)
+    (with-current-buffer (mime-entity-buffer entity)
+      (save-restriction
+       (narrow-to-region (mime-entity-body-start entity)
+                         (mime-entity-body-end entity))
+       (setq group (or (cdr (assq 'group situation))
+                       (completing-read "Group: "
+                                        gnus-active-hashtb
+                                        nil
+                                        (gnus-read-active-file-p)
+                                        gnus-newsgroup-name))
+             article (gnus-request-accept-article group)
+             )
+       ))
+    (when (and (consp article)
+              (numberp (setq article (cdr article))))
+      (setq num (1+ (or (cdr (assq 'number situation)) 0))
+           cwin (get-buffer-window (current-buffer) t)
+           )
+      (save-window-excursion
+       (if (setq swin (get-buffer-window gnus-summary-buffer t))
+           (select-window swin)
+         (set-buffer gnus-summary-buffer)
+         )
+       (setq cur gnus-current-article)
+       (forward-line num)
+       (let (gnus-show-threads)
+         (gnus-summary-goto-subject article t)
+         )
+       (gnus-summary-clear-mark-forward 1)
+       (gnus-summary-goto-subject cur)
+       )
+      (when (and cwin (window-frame cwin))
+       (select-frame (window-frame cwin))
+       )
+      (when (boundp 'mime-acting-situation-to-override)
+       (set-alist 'mime-acting-situation-to-override
+                  'group
+                  group)
+       (set-alist 'mime-acting-situation-to-override
+                  'after-method
+                  `(progn
+                     (save-current-buffer
+                       (set-buffer gnus-group-buffer)
+                       (gnus-activate-group ,group)
+                       )
+                     (gnus-summary-goto-article ,cur
+                                                gnus-show-all-headers)
+                     ))
+       (set-alist 'mime-acting-situation-to-override
+                  'number num)
+       )
+      )))
+
+(mime-add-condition
+ 'action '((type . message)(subtype . rfc822)
+          (major-mode . gnus-original-article-mode)
+          (method . gnus-mime-extract-message/rfc822)
+          (mode . "extract")
+          ))
+
+(mime-add-condition
+ 'action '((type . message)(subtype . news)
+          (major-mode . gnus-original-article-mode)
+          (method . gnus-mime-extract-message/rfc822)
+          (mode . "extract")
+          ))
+
+(defun gnus-mime-extract-multipart (entity situation)
+  (let ((children (mime-entity-children entity))
+       mime-acting-situation-to-override
+       f)
+    (while children
+      (mime-play-entity (car children)
+                       (cons (assq 'mode situation)
+                             mime-acting-situation-to-override))
+      (setq children (cdr children)))
+    (if (setq f (cdr (assq 'after-method
+                          mime-acting-situation-to-override)))
+       (eval f)
+      )))  
+
+(mime-add-condition
+ 'action '((type . multipart)
+          (method . gnus-mime-extract-multipart)
+          (mode . "extract")
+          )
+ 'with-default)
+
+
+;;; @ end
+;;;
+
 (defun gnus-summary-setup-default-charset ()
   "Setup newsgroup default charset."
   (let ((name (and gnus-newsgroup-name
                   (gnus-group-real-name gnus-newsgroup-name))))
     (setq gnus-newsgroup-charset
          (or (and gnus-newsgroup-name
-                  (or (gnus-group-find-parameter gnus-newsgroup-name 'charset)
+                  (or (gnus-group-find-parameter gnus-newsgroup-name
+                                                 'charset)
                       (let ((alist gnus-group-charset-alist)
                             elem (charset nil))
                         (while (setq elem (pop alist))
@@ -9228,6 +9351,115 @@ treated as multipart/mixed."
        (gnus-summary-show-article))
     (gnus-summary-show-article)))
 
+;;;
+;;; with article
+;;;
+
+(defmacro gnus-with-article (article &rest forms)
+  "Select ARTICLE and perform FORMS in the original article buffer.
+Then replace the article with the result."
+  `(progn
+     ;; We don't want the article to be marked as read.
+     (let (gnus-mark-article-hook)
+       (gnus-summary-select-article t t nil ,article))
+     (set-buffer gnus-original-article-buffer)
+     ,@forms
+     (if (not (gnus-check-backend-function
+              'request-replace-article (car gnus-article-current)))
+        (gnus-message 5 "Read-only group; not replacing")
+       (unless (gnus-request-replace-article
+               ,article (car gnus-article-current)
+               (current-buffer) t)
+        (error "Couldn't replace article")))
+     ;; The cache and backlog have to be flushed somewhat.
+     (when gnus-keep-backlog
+       (gnus-backlog-remove-article
+       (car gnus-article-current) (cdr gnus-article-current)))
+     (when gnus-use-cache
+       (gnus-cache-update-article
+       (car gnus-article-current) (cdr gnus-article-current)))))
+
+(put 'gnus-with-article 'lisp-indent-function 1)
+(put 'gnus-with-article 'edebug-form-spec '(form body))
+
+;;;
+;;; Generic summary marking commands
+;;;
+
+(defvar gnus-summary-marking-alist
+  '((read gnus-del-mark "d")
+    (unread gnus-unread-mark "u")
+    (ticked gnus-ticked-mark "!")
+    (dormant gnus-dormant-mark "?")
+    (expirable gnus-expirable-mark "e"))
+  "An alist of names/marks/keystrokes.")
+
+(defvar gnus-summary-generic-mark-map (make-sparse-keymap))
+(defvar gnus-summary-mark-map)
+
+(defun gnus-summary-make-all-marking-commands ()
+  (define-key gnus-summary-mark-map "M" gnus-summary-generic-mark-map)
+  (dolist (elem gnus-summary-marking-alist)
+    (apply 'gnus-summary-make-marking-command elem)))
+
+(defun gnus-summary-make-marking-command (name mark keystroke)
+  (let ((map (make-sparse-keymap)))
+    (define-key gnus-summary-generic-mark-map keystroke map)
+    (dolist (lway `((next "next" next nil "n")
+                   (next-unread "next unread" next t "N")
+                   (prev "previous" prev nil "p")
+                   (prev-unread "previous unread" prev t "P")
+                   (nomove "" nil nil ,keystroke)))
+      (let ((func (gnus-summary-make-marking-command-1
+                  mark (car lway) lway name)))
+       (setq func (eval func))
+       (define-key map (nth 4 lway) func)))))
+      
+(defun gnus-summary-make-marking-command-1 (mark way lway name)      
+  `(defun ,(intern
+           (format "gnus-summary-put-mark-as-%s%s"
+                   name (if (eq way 'nomove)
+                            ""
+                          (concat "-" (symbol-name way)))))
+     (n)
+     ,(format
+       "Mark the current article as %s%s.
+If N, the prefix, then repeat N times.
+If N is negative, move in reverse order.
+The difference between N and the actual number of articles marked is
+returned."
+       name (cadr lway))
+     (interactive "p")
+     (gnus-summary-generic-mark n ,mark ',(nth 2 lway) ,(nth 3 lway))))
+    
+(defun gnus-summary-generic-mark (n mark move unread)
+  "Mark N articles with MARK."
+  (unless (eq major-mode 'gnus-summary-mode)
+    (error "This command can only be used in the summary buffer"))
+  (gnus-summary-show-thread)
+  (let ((nummove
+        (cond
+         ((eq move 'next) 1)
+         ((eq move 'prev) -1)
+         (t 0))))
+    (if (zerop nummove)
+       (setq n 1)
+      (when (< n 0)
+       (setq n (abs n)
+             nummove (* -1 nummove))))
+    (while (and (> n 0)
+               (gnus-summary-mark-article nil mark)
+               (zerop (gnus-summary-next-subject nummove unread t)))
+      (setq n (1- n)))
+    (when (/= 0 n)
+      (gnus-message 7 "No more %sarticles" (if mark "" "unread ")))
+    (gnus-summary-recenter)
+    (gnus-summary-position-point)
+    (gnus-set-mode-line 'summary)
+    n))
+
+(gnus-summary-make-all-marking-commands)
+
 (gnus-ems-redefine)
 
 (provide 'gnus-sum)