Sync up with Pteroductyl Gnus 0.62
[elisp/gnus.git-] / lisp / gnus-sum.el
index cf346a1..2c051e2 100644 (file)
 (require 'gnus-util)
 (require 'mime-view)
 
+;; Avoid byte-compile warnings.
+(eval-when-compile
+  (defvar gnus-article-decoded-p)
+  (defvar gnus-decode-encoded-word-function)
+  )
+
 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
 (autoload 'gnus-set-summary-default-charset "gnus-i18n" nil t)
 
@@ -313,6 +319,7 @@ and non-`vertical', do both horizontal and vertical recentering."
   :group 'gnus-summary-maneuvering
   :type '(choice (const :tag "none" nil)
                 (const vertical)
+                (integer :tag "height")
                 (sexp :menu-tag "both" t)))
 
 (defcustom gnus-show-all-headers nil
@@ -484,6 +491,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
@@ -674,24 +694,7 @@ is not run if `gnus-visual' is nil."
   :group 'gnus-summary-visual
   :type 'hook)
 
-(defcustom gnus-structured-field-decoder
-  #'eword-decode-and-unfold-structured-field
-  "Function to decode non-ASCII characters in structured field for summary."
-  :group 'gnus-various
-  :type 'function)
-
-(defcustom gnus-unstructured-field-decoder
-  (function
-   (lambda (string)
-     (eword-decode-unstructured-field-body
-      (std11-unfold-string string) 'must-unfold)
-     ))
-  "Function to decode non-ASCII characters in unstructured field for summary."
-  :group 'gnus-various
-  :type 'function)
-
-(defcustom gnus-parse-headers-hook
-  '(gnus-set-summary-default-charset)
+(defcustom gnus-parse-headers-hook '(gnus-set-summary-default-charset)
   "*A hook called before parsing the headers."
   :group 'gnus-various
   :type 'hook)
@@ -796,10 +799,42 @@ mark:    The articles mark."
 The function is called with one parameter, the article header vector,
 which it may alter in any way.")
 
+(defcustom gnus-extra-headers nil
+  "*Extra headers to parse."
+  :group 'gnus-summary
+  :type '(repeat symbol))
+
+(defcustom gnus-ignored-from-addresses
+  (and user-mail-address (regexp-quote user-mail-address))
+  "*Regexp of From headers that may be suppressed in favor of To headers."
+  :group 'gnus-summary
+  :type 'regexp)
+
+(defcustom gnus-default-charset 'iso-8859-1
+  "Default charset assumed to be used when viewing non-ASCII characters.
+This variable is used only in non-Mule Emacsen.")
+
+(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-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)
@@ -829,9 +864,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)
@@ -854,6 +890,7 @@ which it may alter in any way.")
     (?l (bbb-grouplens-score gnus-tmp-header) ?s)
     (?V (gnus-thread-total-score (and (boundp 'thread) (car thread))) ?d)
     (?U gnus-tmp-unread ?c)
+    (?f (gnus-summary-from-or-to-or-newsgroups gnus-tmp-header) ?s)
     (?t (gnus-summary-number-of-articles-in-thread
         (and (boundp 'thread) (car thread)) gnus-tmp-level)
        ?d)
@@ -981,6 +1018,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
@@ -1011,31 +1051,13 @@ 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.
 (defvar gnus-article-mode-map)
 
-;; MIME stuff.
-
-(defvar gnus-encoded-word-method-alist
-  '(("chinese" mail-decode-encoded-word-string rfc1843-decode-string)
-    (".*" mail-decode-encoded-word-string))
-  "Alist of regexps (to match group names) and lists of functions to be applied.")
-
-(defun gnus-multi-decode-encoded-word-string (string)
-  "Apply the functions from `gnus-encoded-word-method-alist' that match."
-  (let ((alist gnus-encoded-word-method-alist)
-       elem)
-    (while (setq elem (pop alist))
-      (when (string-match (car elem) gnus-newsgroup-name)
-       (pop elem)
-       (while elem
-         (setq string (funcall (pop elem) string)))
-       (setq alist nil)))
-    string))
-
 ;; Subject simplification.
 
 (defun gnus-simplify-whitespace (str)
@@ -1265,6 +1287,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
@@ -1274,7 +1297,6 @@ 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
     
     "V" gnus-summary-score-map
     "X" gnus-uu-extract-map
@@ -1447,7 +1469,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
@@ -1481,7 +1504,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)
@@ -1545,7 +1578,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]
@@ -1773,6 +1807,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]
@@ -1803,6 +1838,7 @@ increase the score of each group you read."
                     ("article body" "body" string)
                     ("article head" "head" string)
                     ("xref" "xref" string)
+                    ("extra header" "extra" string)
                     ("lines" "lines" number)
                     ("followups to author" "followup" string)))
          (types '((number ("less than" <)
@@ -2265,7 +2301,7 @@ marks of articles."
     (while (setq point (pop config))
       (when (and (< point (point-max))
                 (goto-char point)
-                (= (following-char) ?\n))
+                (eq (char-after) ?\n))
        (subst-char-in-region point (1+ point) ?\n ?\r)))))
 
 ;; Various summary mode internalish functions.
@@ -2337,7 +2373,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
@@ -2350,7 +2388,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)
@@ -2369,7 +2409,7 @@ marks of articles."
 (defun gnus-summary-last-article-p (&optional article)
   "Return whether ARTICLE is the last article in the buffer."
   (if (not (setq article (or article (gnus-summary-article-number))))
-      t                ; All non-existent numbers are the last article.  :-)
+      t                                        ; All non-existent numbers are the last article.  :-)
     (not (cdr (gnus-data-find-list article)))))
 
 (defun gnus-make-thread-indent-array ()
@@ -2399,7 +2439,8 @@ marks of articles."
        (let ((gnus-summary-line-format-spec spec)
              (gnus-newsgroup-downloadable '((0 . t))))
          (gnus-summary-insert-line
-          [0 "" "" "" "" "" 0 0 ""]  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)))))
@@ -2423,6 +2464,31 @@ marks of articles."
    (point) (progn (eval gnus-summary-dummy-line-format-spec) (point))
    (list 'gnus-number gnus-tmp-number 'gnus-intangible gnus-tmp-number)))
 
+(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))))
+       (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
+          (string-match gnus-ignored-from-addresses
+                        (mail-header-from header)))
+      (concat "-> "
+             (or (car (funcall gnus-extract-address-components
+                               (funcall
+                                gnus-decode-encoded-word-function to)))
+                 (funcall gnus-decode-encoded-word-function to))))
+     ((and newsgroups
+          gnus-ignored-from-addresses
+          (string-match gnus-ignored-from-addresses
+                        (mail-header-from header)))
+      (concat "=> " newsgroups))
+     (t
+      (or (car (funcall gnus-extract-address-components
+                       (mail-header-from header)))
+         (mail-header-from header))))))
+
 (defun gnus-summary-insert-line (gnus-tmp-header
                                 gnus-tmp-level gnus-tmp-current
                                 gnus-tmp-unread gnus-tmp-replied
@@ -2469,7 +2535,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)
@@ -2570,7 +2636,7 @@ If NO-DISPLAY, don't generate a summary buffer."
                                   kill-buffer no-display
                                   select-articles)
                                  (setq show-all nil
-                                  select-articles nil)))))
+                                       select-articles nil)))))
                (eq gnus-auto-select-next 'quietly))
       (set-buffer gnus-group-buffer)
       ;; The entry function called above goes to the next
@@ -3069,12 +3135,9 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
             (setq heads nil)))))
      gnus-newsgroup-dependencies)))
 
-;; The following macros and functions were written by Felix Lee
-;; <flee@cse.psu.edu>.
-
 (defmacro gnus-nov-read-integer ()
   '(prog1
-       (if (= (following-char) ?\t)
+       (if (eq (char-after) ?\t)
           0
         (let ((num (ignore-errors (read buffer))))
           (if (numberp num) num 0)))
@@ -3087,12 +3150,22 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
 (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)
   (let ((eol (gnus-point-at-eol))
        (buffer (current-buffer))
-       header rawtext decoded)
+       header)
 
     ;; overview: [num subject from date id refs chars lines misc]
     (unwind-protect
@@ -3104,30 +3177,17 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
          (setq header
                (make-full-mail-header
                 number                 ; number
-                (progn
-                  (setq rawtext (gnus-nov-field) ; subject
-                        decoded (funcall
-                                 gnus-unstructured-field-decoder rawtext))
-                  (if (string= rawtext decoded)
-                      rawtext
-                    (put-text-property 0 (length decoded) 'raw-text rawtext decoded)
-                    decoded))
-                (progn
-                  (setq rawtext (gnus-nov-field) ; from
-                        decoded (funcall
-                                 gnus-structured-field-decoder rawtext))
-                  (if (string= rawtext decoded)
-                      rawtext
-                    (put-text-property 0 (length decoded) 'raw-text rawtext decoded)
-                    decoded))
+                (gnus-nov-field)       ; subject
+                (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 (= (following-char) ?\n)
-                  (gnus-nov-field))))) ; misc
+                (unless (eq (char-after) ?\n)
+                  (gnus-nov-field))    ; misc
+                (gnus-nov-parse-extra)))) ; extra
 
       (widen))
 
@@ -3515,14 +3575,15 @@ If LINE, insert the rebuilt thread starting on line LINE."
 (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."
@@ -3603,6 +3664,12 @@ Unscored articles will be counted as having a score of zero."
 (defvar gnus-tmp-root-expunged nil)
 (defvar gnus-tmp-dummy-line nil)
 
+(defvar gnus-tmp-header)
+(defun gnus-extra-header (type &optional header)
+  "Return the extra header of TYPE."
+  (or (cdr (assq type (mail-header-extra (or header gnus-tmp-header))))
+      ""))
+
 (defun gnus-summary-prepare-threads (threads)
   "Prepare summary buffer from THREADS and indentation LEVEL.
 THREADS is either a list of `(PARENT [(CHILD1 [(GRANDCHILD ...]...) ...])'
@@ -4164,7 +4231,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
   (let ((types gnus-article-mark-lists)
        (info (gnus-get-info gnus-newsgroup-name))
        (uncompressed '(score bookmark killed))
-       type list newmarked symbol)
+       type list newmarked symbol delta-marks)
     (when info
       ;; Add all marks lists that are non-nil to the list of marks lists.
       (while (setq type (pop types))
@@ -4213,7 +4280,9 @@ If SELECT-ARTICLES, only select those articles from GROUP."
   "This function sets the mode line of the article or summary buffers.
 If WHERE is `summary', the summary mode line format will be used."
   ;; Is this mode line one we keep updated?
-  (when (memq where gnus-updated-mode-lines)
+  (when (and (memq where gnus-updated-mode-lines)
+            (symbol-value
+             (intern (format "gnus-%s-mode-line-format-spec" where))))
     (let (mode-string)
       (save-excursion
        ;; We evaluate this in the summary buffer since these
@@ -4427,15 +4496,17 @@ 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.
       (subst-char-in-region (point-min) (point-max) ?\t ?  t)
+      (subst-char-in-region (point-min) (point-max) ?\r ?  t)
       (gnus-run-hooks 'gnus-parse-headers-hook)
       (let ((case-fold-search t)
-           rawtext decoded
-           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.
@@ -4450,7 +4521,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)
@@ -4464,33 +4535,20 @@ The resulting hash table is returned, or nil if no Xrefs were found."
            (progn
              (goto-char p)
              (if (search-forward "\nsubject: " nil t)
-                 (progn
-                   (setq rawtext (nnheader-header-value)
-                         decoded (funcall
-                                  gnus-unstructured-field-decoder rawtext))
-                   (if (string-equal rawtext decoded)
-                       rawtext
-                     (put-text-property 0 (length decoded) 'raw-text rawtext decoded)
-                     decoded))
+                 (buffer-substring (match-end 0) (std11-field-end))
                "(none)"))
            ;; From.
            (progn
              (goto-char p)
              (if (search-forward "\nfrom: " nil t)
-                 (progn
-                   (setq rawtext (nnheader-header-value)
-                         decoded (funcall
-                                  gnus-structured-field-decoder rawtext))
-                   (if (string-equal rawtext decoded)
-                       rawtext
-                     (put-text-property 0 (length decoded) 'raw-text rawtext decoded)
-                     decoded))
+                 (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)
@@ -4510,11 +4568,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
@@ -4524,7 +4582,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)
@@ -4554,7 +4614,27 @@ 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)
+                   out)
+               (while extra
+                 (goto-char p)
+                 (when (search-forward
+                        (concat "\n" (symbol-name (car extra)) ": ") nil t)
+                   (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))
 
@@ -4580,11 +4660,14 @@ 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
       (set-buffer nntp-server-buffer)
+      (subst-char-in-region (point-min) (point-max) ?\r ?  t)
       ;; Allow the user to mangle the headers before parsing them.
       (gnus-run-hooks 'gnus-parse-headers-hook)
       (goto-char (point-min))
@@ -4638,7 +4721,7 @@ This is meant to be called in `gnus-article-internal-prepare-hook'."
          (save-restriction
            (nnheader-narrow-to-headers)
            (goto-char (point-min))
-           (when (or (and (eq (downcase (following-char)) ?x)
+           (when (or (and (eq (downcase (char-after)) ?x)
                           (looking-at "Xref:"))
                      (search-forward "\nXref:" nil t))
              (goto-char (1+ (match-end 0)))
@@ -4653,14 +4736,14 @@ the subject line on."
   (let* ((line (and (numberp old-header) old-header))
         (old-header (and (vectorp old-header) old-header))
         (header (cond ((and old-header use-old-header)
-                      old-header)
-                     ((and (numberp id)
-                           (gnus-number-to-header id))
-                      (gnus-number-to-header id))
-                     (t
-                      (gnus-read-header id))))
-       (number (and (numberp id) id))
-       d)
+                       old-header)
+                      ((and (numberp id)
+                            (gnus-number-to-header id))
+                       (gnus-number-to-header id))
+                      (t
+                       (gnus-read-header id))))
+        (number (and (numberp id) id))
+        d)
     (when header
       ;; Rebuild the thread that this article is part of and go to the
       ;; article we have fetched.
@@ -4902,7 +4985,9 @@ displayed, no centering will be performed."
   ;; Recenter only when requested.  Suggested by popovich@park.cs.columbia.edu.
   (let* ((top (cond ((< (window-height) 4) 0)
                    ((< (window-height) 7) 1)
-                   (t 2)))
+                   (t (if (numberp gnus-auto-center-summary)
+                          gnus-auto-center-summary
+                        2))))
         (height (1- (window-height)))
         (bottom (save-excursion (goto-char (point-max))
                                 (forward-line (- height))
@@ -5202,7 +5287,8 @@ 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 'gnus-summary-prepare-exit-hook)
+      (gnus-run-hooks (delq 'gnus-summary-expire-articles
+                           (copy-list gnus-summary-prepare-exit-hook)))
       ;; If we have several article buffers, we kill them at exit.
       (unless gnus-single-article-buffer
        (gnus-kill-buffer gnus-article-buffer)
@@ -5897,9 +5983,9 @@ Return nil if there are no articles."
   (interactive)
   (prog1
       (when (gnus-summary-first-subject)
-      (gnus-summary-show-thread)
-      (gnus-summary-first-subject)
-      (gnus-summary-display-article (gnus-summary-article-number)))
+       (gnus-summary-show-thread)
+       (gnus-summary-first-subject)
+       (gnus-summary-display-article (gnus-summary-article-number)))
     (gnus-summary-position-point)))
 
 (defun gnus-summary-best-unread-article ()
@@ -6539,6 +6625,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
@@ -6683,6 +6774,7 @@ Optional argument BACKWARD means do search for backward.
   ;; 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)
   (let ((gnus-select-article-hook nil) ;Disable hook.
        (gnus-article-display-hook nil)
        (gnus-mark-article-hook nil)    ;Inhibit marking as read.
@@ -6860,6 +6952,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
@@ -6868,6 +6964,11 @@ article massaging functions being run."
          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))
@@ -7029,7 +7130,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)
@@ -7410,8 +7511,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))))
          (error "Couldn't replace article")
        ;; Update the summary buffer.
        (if (and references
@@ -7694,6 +7794,7 @@ If N is negative, mark backwards instead.  Mark with MARK, ?r by default.
 The difference between N and the actual number of articles marked is
 returned."
   (interactive "p")
+  (gnus-summary-show-thread)
   (let ((backward (< n 0))
        (gnus-summary-goto-unread
         (and gnus-summary-goto-unread
@@ -7731,11 +7832,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))
@@ -7786,25 +7883,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)
@@ -7856,19 +7949,19 @@ marked."
   (let ((forward (cdr (assq type gnus-summary-mark-positions)))
         (buffer-read-only nil))
     (re-search-backward "[\n\r]" (gnus-point-at-bol) 'move-to-limit)
-    (when (looking-at "\r")
-      (incf forward))
-    (when (and forward
-               (<= (+ forward (point)) (point-max)))
-      ;; Go to the right position on the line.
-      (goto-char (+ forward (point)))
-      ;; Replace the old mark with the new mark.
-      (subst-char-in-region (point) (1+ (point)) (following-char) mark)
-      ;; Optionally update the marks by some user rule.
-      (when (eq type 'unread)
-        (gnus-data-set-mark
-         (gnus-data-find (gnus-summary-article-number)) mark)
-        (gnus-summary-update-line (eq mark gnus-unread-mark))))))
+    (when forward
+      (when (looking-at "\r")
+       (incf forward))
+      (when (<= (+ forward (point)) (point-max))
+       ;; Go to the right position on the line.
+       (goto-char (+ forward (point)))
+       ;; Replace the old mark with the new mark.
+       (subst-char-in-region (point) (1+ (point)) (char-after) mark)
+       ;; Optionally update the marks by some user rule.
+       (when (eq type 'unread)
+         (gnus-data-set-mark
+          (gnus-data-find (gnus-summary-article-number)) mark)
+         (gnus-summary-update-line (eq mark gnus-unread-mark)))))))
 
 (defun gnus-mark-article-as-read (article &optional mark)
   "Enter ARTICLE in the pertinent lists and remove it from others."
@@ -7949,14 +8042,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.
@@ -8239,25 +8332,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)
@@ -8501,17 +8584,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.
@@ -8587,7 +8668,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)
@@ -8672,6 +8753,7 @@ save those articles instead."
 (defun gnus-valid-move-group-p (group)
   (and (boundp group)
        (symbol-name group)
+       (symbol-value group)
        (memq 'respool
             (assoc (symbol-name
                     (car (gnus-find-method-for-group
@@ -9006,8 +9088,9 @@ save those articles instead."
        (setq unread (cdr unread)))
       (when (<= prev (cdr active))
        (push (cons prev (cdr active)) read))
+      (setq read (if (> (length read) 1) (nreverse read) read))
       (if compute
-         (if (> (length read) 1) (nreverse read) read)
+         read
        (save-excursion
          (set-buffer gnus-group-buffer)
          (gnus-undo-register
@@ -9017,8 +9100,7 @@ save those articles instead."
               (gnus-get-unread-articles-in-group ',info (gnus-active ,group))
               (gnus-group-update-group ,group t))))
        ;; Enter this list into the group info.
-       (gnus-info-set-read
-        info (if (> (length read) 1) (nreverse read) read))
+       (gnus-info-set-read info read)
        ;; Set the number of unread articles in gnus-newsrc-hashtb.
        (gnus-get-unread-articles-in-group info (gnus-active group))
        t))))
@@ -9083,6 +9165,83 @@ save those articles instead."
 ;;; @ end
 ;;;
 
+(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 ()
+  "Display the current article buffer fully MIME-buttonized."
+  (interactive)
+  (require 'gnus-art)
+  (let ((gnus-unbuttonized-mime-types nil))
+    (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)