2006-07-10 Daiki Ueno <ueno@unixuser.org>
[gnus] / lisp / gnus-sum.el
index 995bf42..25fef12 100644 (file)
@@ -87,7 +87,7 @@ locally cached header entries."
                 number
                 (sexp :menu-tag "other" t)))
 
-(defcustom gnus-refer-thread-limit 200
+(defcustom gnus-refer-thread-limit 500
   "*The number of old headers to fetch when doing \\<gnus-summary-mode-map>\\[gnus-summary-refer-thread].
 If t, fetch all the available old headers."
   :group 'gnus-thread
@@ -1322,6 +1322,7 @@ the type of the variable (string, integer, character, etc).")
 (defvar gnus-newsgroup-last-mail nil)
 (defvar gnus-newsgroup-last-folder nil)
 (defvar gnus-newsgroup-last-file nil)
+(defvar gnus-newsgroup-last-directory nil)
 (defvar gnus-newsgroup-auto-expire nil)
 (defvar gnus-newsgroup-active nil)
 
@@ -1437,6 +1438,7 @@ This list will always be a subset of gnus-newsgroup-undownloaded.")
     gnus-newsgroup-begin gnus-newsgroup-end
     gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
     gnus-newsgroup-last-folder gnus-newsgroup-last-file
+    gnus-newsgroup-last-directory
     gnus-newsgroup-auto-expire gnus-newsgroup-unreads
     gnus-newsgroup-unselected gnus-newsgroup-marked
     gnus-newsgroup-spam-marked
@@ -1712,6 +1714,8 @@ increase the score of each group you read."
   "," gnus-summary-best-unread-article
   "\M-s" gnus-summary-search-article-forward
   "\M-r" gnus-summary-search-article-backward
+  "\M-S" gnus-summary-repeat-search-article-forward
+  "\M-R" gnus-summary-repeat-search-article-backward
   "<" gnus-summary-beginning-of-article
   ">" gnus-summary-end-of-article
   "j" gnus-summary-goto-article
@@ -1843,6 +1847,7 @@ increase the score of each group you read."
 (gnus-define-keys (gnus-summary-limit-map "/" gnus-summary-mode-map)
   "/" gnus-summary-limit-to-subject
   "n" gnus-summary-limit-to-articles
+  "b" gnus-summary-limit-to-bodies
   "w" gnus-summary-pop-limit
   "s" gnus-summary-limit-to-subject
   "a" gnus-summary-limit-to-author
@@ -1889,6 +1894,7 @@ increase the score of each group you read."
   "T" gnus-summary-toggle-threads
   "t" gnus-summary-rethread-current
   "^" gnus-summary-reparent-thread
+  "\M-^" gnus-summary-reparent-children
   "s" gnus-summary-show-thread
   "S" gnus-summary-show-all-threads
   "h" gnus-summary-hide-thread
@@ -1950,6 +1956,7 @@ increase the score of each group you read."
   "e" gnus-article-emphasize
   "w" gnus-article-fill-cited-article
   "Q" gnus-article-fill-long-lines
+  "L" gnus-article-toggle-truncate-lines
   "C" gnus-article-capitalize-sentences
   "c" gnus-article-remove-cr
   "q" gnus-article-de-quoted-unreadable
@@ -2069,6 +2076,7 @@ increase the score of each group you read."
   "r" gnus-summary-save-article-rmail
   "f" gnus-summary-save-article-file
   "b" gnus-summary-save-article-body-file
+  "B" gnus-summary-write-article-body-file
   "h" gnus-summary-save-article-folder
   "v" gnus-summary-save-article-vm
   "p" gnus-summary-pipe-output
@@ -2083,10 +2091,12 @@ increase the score of each group you read."
   "O" gnus-article-save-part-and-strip
   "r" gnus-article-replace-part
   "d" gnus-article-delete-part
+  "t" gnus-article-view-part-as-type
   "j" gnus-article-jump-to-part
   "c" gnus-article-copy-part
   "C" gnus-article-view-part-as-charset
   "e" gnus-article-view-part-externally
+  "H" gnus-article-browse-html-article
   "E" gnus-article-encrypt-body
   "i" gnus-article-inline-part
   "|" gnus-article-pipe-part)
@@ -2230,11 +2240,13 @@ increase the score of each group you read."
               ["Repair multipart" gnus-summary-repair-multipart t]
               ["Pipe part..." gnus-article-pipe-part t]
               ["Inline part" gnus-article-inline-part t]
+              ["View part as type..." gnus-article-view-part-as-type t]
               ["Encrypt body" gnus-article-encrypt-body
                :active (not (gnus-group-read-only-p))
               ,@(if (featurep 'xemacs) nil
                   '(:help "Encrypt the message body on disk"))]
               ["View part externally" gnus-article-view-part-externally t]
+              ["View HTML parts in browser" gnus-article-browse-html-article t]
               ["View part with charset..." gnus-article-view-part-as-charset t]
               ["Copy part" gnus-article-copy-part t]
               ["Save part..." gnus-article-save-part t]
@@ -2289,6 +2301,7 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
              ["Emphasis" gnus-article-emphasize t]
              ["Word wrap" gnus-article-fill-cited-article t]
              ["Fill long lines" gnus-article-fill-long-lines t]
+             ["Toggle truncate long lines" gnus-article-toggle-truncate-lines t]
              ["Capitalize sentences" gnus-article-capitalize-sentences t]
              ["Remove CR" gnus-article-remove-cr t]
              ["Quoted-Printable" gnus-article-de-quoted-unreadable t]
@@ -2672,15 +2685,16 @@ Pre-defined symbols include `gnus-summary-tool-bar-gnome' and
 
 (defcustom gnus-summary-tool-bar-gnome
   '((gnus-summary-post-news "mail/compose" nil)
-    (gnus-summary-insert-new-articles "mail/inbox")
-    ;;
+    (gnus-summary-insert-new-articles "mail/inbox" nil
+                                     :visible (or (not gnus-agent)
+                                                  gnus-plugged))
     (gnus-summary-reply-with-original "mail/reply")
     (gnus-summary-reply "mail/reply" nil :visible nil)
     (gnus-summary-followup-with-original "mail/reply-all")
     (gnus-summary-followup "mail/reply-all" nil :visible nil)
     (gnus-summary-mail-forward "mail/forward")
     (gnus-summary-save-article "mail/save")
-    (gnus-summary-search-article-forward "search")
+    (gnus-summary-search-article-forward "search" nil :visible nil)
     (gnus-summary-print-article "print")
     (gnus-summary-tick-article-forward "flag-followup" nil :visible nil)
     ;; Some new commands that may need more suitable icons:
@@ -2699,10 +2713,14 @@ Pre-defined symbols include `gnus-summary-tool-bar-gnome' and
      :visible (gnus-check-backend-function 'request-expire-articles
                                           gnus-newsgroup-name))
     (gnus-summary-mark-as-spam
-     "mail/spam" t :visible (spam-group-ham-contents-p gnus-newsgroup-name)
+     "mail/spam" t
+     :visible (and (fboundp 'spam-group-ham-contents-p)
+                  (spam-group-ham-contents-p gnus-newsgroup-name))
      :help "Mark as spam")
     (gnus-summary-mark-as-read-forward
-     "mail/not-spam" nil :visible (spam-group-spam-contents-p gnus-newsgroup-name))
+     "mail/not-spam" nil
+     :visible (and (fboundp 'spam-group-spam-contents-p)
+                  (spam-group-spam-contents-p gnus-newsgroup-name)))
     ;;
     (gnus-summary-exit "exit")
     (gmm-customize-mode "preferences" t :help "Edit mode preferences")
@@ -2762,6 +2780,8 @@ See `gmm-tool-bar-from-list' for the format of the list."
   :set 'gnus-summary-tool-bar-update
   :group 'gnus-summary)
 
+(defvar image-load-path)
+
 (defun gnus-summary-make-tool-bar (&optional force)
   "Make a summary mode tool bar from `gnus-summary-tool-bar'.
 When FORCE, rebuild the tool bar."
@@ -2770,9 +2790,12 @@ When FORCE, rebuild the tool bar."
             tool-bar-mode
             (or (not gnus-summary-tool-bar-map) force))
     (let* ((load-path
-           (gmm-image-load-path "gnus" "mail/save.xpm" 'load-path))
-          (image-load-path
-           (gmm-image-load-path "gnus" "mail/save.xpm" 'image-load-path))
+           (gmm-image-load-path-for-library "gnus"
+                                            "mail/save.xpm"
+                                            nil t))
+           (image-load-path (cons (car load-path)
+                                  (when (boundp 'image-load-path)
+                                    image-load-path)))
           (map (gmm-tool-bar-from-list gnus-summary-tool-bar
                                        gnus-summary-tool-bar-zap-list
                                        'gnus-summary-mode-map)))
@@ -3292,8 +3315,11 @@ display only a single character."
     (aset table ?\r nil)
     ;; We keep TAB as well.
     (aset table ?\t nil)
-    ;; We nix out any glyphs over 126 that are not set already.
-    (let ((i 256))
+    ;; We nix out any glyphs 127 through 255, or 127 through 159 in
+    ;; Emacs 23 (unicode), that are not set already.
+    (let ((i (if (ignore-errors (= (make-char 'latin-iso8859-1 160) 160))
+                160
+              256)))
       (while (>= (setq i (1- i)) 127)
        ;; Only modify if the entry is nil.
        (unless (aref table i)
@@ -3333,10 +3359,11 @@ display only a single character."
       (gnus-summary-mode group)
       (when gnus-carpal
        (gnus-carpal-setup-buffer 'summary))
-      (unless gnus-single-article-buffer
-       (make-local-variable 'gnus-article-buffer)
-       (make-local-variable 'gnus-article-current)
-       (make-local-variable 'gnus-original-article-buffer))
+      (when (gnus-group-quit-config group)
+       (set (make-local-variable 'gnus-single-article-buffer) nil))
+      (make-local-variable 'gnus-article-buffer)
+      (make-local-variable 'gnus-article-current)
+      (make-local-variable 'gnus-original-article-buffer)
       (setq gnus-newsgroup-name group)
       ;; Set any local variables in the group parameters.
       (gnus-summary-set-local-parameters gnus-newsgroup-name)
@@ -3509,7 +3536,14 @@ buffer that was in action when the last article was fetched."
                      (inline
                        (gnus-summary-extract-address-component
                         (funcall gnus-decode-encoded-word-function to)))))
-            ((setq newsgroups (cdr (assq 'Newsgroups extra-headers)))
+            ((setq newsgroups
+                   (or
+                    (cdr (assq 'Newsgroups extra-headers))
+                    (and
+                     (memq 'Newsgroups gnus-extra-headers)
+                      (eq (car (gnus-find-method-for-group
+                                gnus-newsgroup-name)) 'nntp)
+                     (gnus-group-real-name gnus-newsgroup-name))))
              (concat gnus-summary-newsgroup-prefix newsgroups)))))
      (inline (gnus-summary-extract-address-component gnus-tmp-from)))))
 
@@ -6157,7 +6191,8 @@ Return a list of headers that match SEQUENCE (see
        (allp (cond
               ((eq gnus-read-all-available-headers t)
                t)
-              ((stringp gnus-read-all-available-headers)
+              ((and (stringp gnus-read-all-available-headers)
+                    group)
                (string-match gnus-read-all-available-headers group))
               (t
                nil)))
@@ -6816,6 +6851,7 @@ If FORCE (the prefix), also save the .newsrc file(s)."
     (gnus-run-hooks '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)
       (gnus-kill-buffer gnus-original-article-buffer)
       (setq gnus-article-current nil))
     (when gnus-use-cache
@@ -6954,19 +6990,11 @@ The state which existed when entering the ephemeral is reset."
             (gnus-set-global-variables))))
     (if (or (eq (cdr quit-config) 'article)
            (eq (cdr quit-config) 'pick))
-       (progn
-         ;; The current article may be from the ephemeral group
-         ;; thus it is best that we reload this article
-         ;;
-         ;; If we're exiting from a large digest, this can be
-         ;; extremely slow.  So, it's better not to reload it. -- jh.
-         ;;(gnus-summary-show-article)
-         (if (and (boundp 'gnus-pick-mode) (symbol-value 'gnus-pick-mode))
-             (gnus-configure-windows 'pick 'force)
-           (gnus-configure-windows (cdr quit-config) 'force)))
+       (if (and (boundp 'gnus-pick-mode) (symbol-value 'gnus-pick-mode))
+           (gnus-configure-windows 'pick 'force)
+         (gnus-configure-windows (cdr quit-config) 'force))
       (gnus-configure-windows (cdr quit-config) 'force))
     (when (eq major-mode 'gnus-summary-mode)
-      (gnus-summary-next-subject 1 nil t)
       (gnus-summary-recenter)
       (gnus-summary-position-point))))
 
@@ -7979,6 +8007,38 @@ If ALL is non-nil, limit strictly to unread articles."
           gnus-duplicate-mark gnus-souped-mark)
      'reverse)))
 
+(defun gnus-summary-limit-to-bodies (match &optional reverse)
+  "Limit the summary buffer to articles that have bodies that match MATCH.
+If REVERSE (the prefix), limit to articles that don't match."
+  (interactive "sMatch body (regexp): \nP")
+  (let ((articles nil)
+       (gnus-select-article-hook nil)  ;Disable hook.
+       (gnus-article-prepare-hook nil)
+       (gnus-use-article-prefetch nil)
+       (gnus-keep-backlog nil)
+       (gnus-break-pages nil)
+       (gnus-summary-display-arrow nil)
+       (gnus-updated-mode-lines nil)
+       (gnus-auto-center-summary nil)
+       (gnus-display-mime-function nil))
+    (dolist (data gnus-newsgroup-data)
+      (let (gnus-mark-article-hook)
+       (gnus-summary-select-article t t nil (gnus-data-number data)))
+      (save-excursion
+       (set-buffer gnus-article-buffer)
+       (article-goto-body)
+       (let* ((case-fold-search t)
+              (found (re-search-forward match nil t)))
+         (when (or (and found
+                        (not reverse))
+                   (and (not found)
+                        reverse))
+           (push (gnus-data-number data) articles)))))
+    (if (not articles)
+       (message "No messages matched")
+      (gnus-summary-limit articles)))
+  (gnus-summary-position-point))
+
 (defun gnus-summary-limit-to-replied (&optional unreplied)
   "Limit the summary buffer to replied articles.
 If UNREPLIED (the prefix), limit to unreplied articles."
@@ -8663,6 +8723,20 @@ If REGEXP-P (the prefix) is non-nil, do regexp isearch."
       (widen)
       (isearch-forward regexp-p))))
 
+(defun gnus-summary-repeat-search-article-forward ()
+  "Repeat the previous search forwards."
+  (interactive)
+  (unless gnus-last-search-regexp
+    (error "No previous search"))
+  (gnus-summary-search-article-forward gnus-last-search-regexp))
+
+(defun gnus-summary-repeat-search-article-backward ()
+  "Repeat the previous search backwards."
+  (interactive)
+  (unless gnus-last-search-regexp
+    (error "No previous search"))
+  (gnus-summary-search-article-forward gnus-last-search-regexp t))
+
 (defun gnus-summary-search-article-forward (regexp &optional backward)
   "Search for an article containing REGEXP forward.
 If BACKWARD, search backward instead."
@@ -9130,10 +9204,6 @@ installed for this command to work."
              (replace-match (idna-to-unicode (match-string 1))))
            (set-window-start (get-buffer-window (current-buffer)) start)))))))
 
-(autoload 'unmorse-region "morse"
-  "Convert morse coded text in region to ordinary ASCII text."
-  t)
-
 (defun gnus-summary-morse-message (&optional arg)
   "Morse decode the current article."
   (interactive "P")
@@ -9657,7 +9727,7 @@ deleted forever, right now."
   (interactive)
   (or gnus-expert-user
       (gnus-yes-or-no-p
-       "Are you really, really, really sure you want to delete all these messages? ")
+       "Are you really, really sure you want to delete all expirable messages? ")
       (error "Phew!"))
   (gnus-summary-expire-articles t))
 
@@ -10801,41 +10871,51 @@ is non-nil or the Subject: of both articles are the same."
     (error "The current newsgroup does not support article editing"))
   (unless (<= (length gnus-newsgroup-processable) 1)
     (error "No more than one article may be marked"))
-  (save-window-excursion
-    (let ((gnus-article-buffer " *reparent*")
-         (current-article (gnus-summary-article-number))
-         ;; First grab the marked article, otherwise one line up.
-         (parent-article (if (not (null gnus-newsgroup-processable))
-                             (car gnus-newsgroup-processable)
-                           (save-excursion
-                             (if (eq (forward-line -1) 0)
-                                 (gnus-summary-article-number)
-                               (error "Beginning of summary buffer"))))))
-      (unless (not (eq current-article parent-article))
-       (error "An article may not be self-referential"))
-      (let ((message-id (mail-header-id
-                        (gnus-summary-article-header parent-article))))
-       (unless (and message-id (not (equal message-id "")))
-         (error "No message-id in desired parent"))
-       (gnus-with-article current-article
-         (save-restriction
-           (goto-char (point-min))
-           (message-narrow-to-head)
-           (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)
-       (if (gnus-summary-goto-subject (cdr gnus-article-current) nil t)
+  (let ((child (gnus-summary-article-number))
+       ;; First grab the marked article, otherwise one line up.
+       (parent (if (not (null gnus-newsgroup-processable))
+                   (car gnus-newsgroup-processable)
+                 (save-excursion
+                   (if (eq (forward-line -1) 0)
+                       (gnus-summary-article-number)
+                     (error "Beginning of summary buffer"))))))
+    (gnus-summary-reparent-children parent (list child))))
+
+(defun gnus-summary-reparent-children (parent children)
+  "Make PARENT the parent of CHILDREN.
+When called interactively, PARENT is is current article and
+CHILDREN are the process-marked articles."
+  (interactive
+   (list (gnus-summary-article-number)
+        (gnus-summary-work-articles nil)))
+  (dolist (child children)
+    (save-window-excursion
+      (let ((gnus-article-buffer " *reparent*"))
+       (unless (not (eq parent child))
+         (error "An article may not be self-referential"))
+       (let ((message-id (mail-header-id
+                          (gnus-summary-article-header parent))))
+         (unless (and message-id (not (equal message-id "")))
+           (error "No message-id in desired parent"))
+         (gnus-with-article child
+           (save-restriction
+             (goto-char (point-min))
+             (message-narrow-to-head)
+             (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 child)
+         (when (gnus-summary-goto-subject (cdr gnus-article-current) nil t)
            (gnus-summary-update-secondary-mark (cdr gnus-article-current)))
-       (gnus-summary-rethread-current)
-       (gnus-message 3 "Article %d is now the child of article %d"
-                     current-article parent-article)))))
+         (gnus-summary-rethread-current)
+         (gnus-message 3 "Article %d is now the child of article %d"
+                       child parent))))))
 
 (defun gnus-summary-toggle-threads (&optional arg)
   "Toggle showing conversation threads.
@@ -10895,7 +10975,9 @@ Returns nil if no thread was there to be shown."
 (defun gnus-map-articles (predicate articles)
   "Map PREDICATE over ARTICLES and return non-nil if any predicate is non-nil."
   (apply 'gnus-or (mapcar predicate
-                         (mapcar 'gnus-summary-article-header articles))))
+                         (mapcar (lambda (number)
+                                   (gnus-summary-article-header number))
+                                 articles))))
 
 (defun gnus-summary-hide-all-threads (&optional predicate)
   "Hide all thread subtrees.
@@ -11158,12 +11240,26 @@ If N is a positive number, save the N next articles.
 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.
-The variable `gnus-default-article-saver' specifies the saver function."
+The variable `gnus-default-article-saver' specifies the saver function.
+
+If the optional second argument NOT-SAVED is non-nil, articles saved
+will not be marked as saved."
   (interactive "P")
+  (require 'gnus-art)
   (let* ((articles (gnus-summary-work-articles n))
         (save-buffer (save-excursion
                        (nnheader-set-temp-buffer " *Gnus Save*")))
         (num (length articles))
+        ;; Whether to save decoded articles or raw articles.
+        (decode (when gnus-article-save-coding-system
+                  (get gnus-default-article-saver :decode)))
+        ;; When saving many articles in a single file, use the other
+        ;; function to save articles other than the first one.
+        (saver2 (get gnus-default-article-saver :function))
+        (gnus-prompt-before-saving (if saver2
+                                       t
+                                     gnus-prompt-before-saving))
+        (gnus-default-article-saver gnus-default-article-saver)
         header file)
     (dolist (article articles)
       (setq header (gnus-summary-article-header article))
@@ -11174,17 +11270,25 @@ The variable `gnus-default-article-saver' specifies the saver function."
            (gnus-message 1 "Article %d is unsaveable" article))
        ;; This is a real article.
        (save-window-excursion
-         (let ((gnus-display-mime-function nil)
-               (gnus-article-prepare-hook nil))
-           (gnus-summary-select-article t nil nil article)))
+         (let ((gnus-display-mime-function (when decode
+                                             gnus-display-mime-function))
+               (gnus-article-prepare-hook (when decode
+                                            gnus-article-prepare-hook)))
+           (gnus-summary-select-article t nil nil article)
+           (gnus-summary-goto-subject article)))
        (save-excursion
          (set-buffer save-buffer)
          (erase-buffer)
-         (insert-buffer-substring gnus-original-article-buffer))
+         (insert-buffer-substring (if decode
+                                      gnus-article-buffer
+                                    gnus-original-article-buffer)))
        (setq file (gnus-article-save save-buffer file num))
        (gnus-summary-remove-process-mark article)
        (unless not-saved
-         (gnus-summary-set-saved-mark article))))
+         (gnus-summary-set-saved-mark article)))
+      (when saver2
+       (setq gnus-default-article-saver saver2
+             saver2 nil)))
     (gnus-kill-buffer save-buffer)
     (gnus-summary-position-point)
     (gnus-set-mode-line 'summary)
@@ -11208,7 +11312,7 @@ If HEADERS (the symbolic prefix), include the headers, too."
       (gnus-configure-windows 'pipe))))
 
 (defun gnus-summary-save-article-mail (&optional arg)
-  "Append the current article to an mail file.
+  "Append the current article to a Unix mail box file.
 If N is a positive number, save the N next articles.
 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,
@@ -11262,6 +11366,17 @@ save those articles instead."
   (let ((gnus-default-article-saver 'gnus-summary-save-body-in-file))
     (gnus-summary-save-article arg)))
 
+(defun gnus-summary-write-article-body-file (&optional arg)
+  "Write the current article body to a file, deleting the previous file.
+If N is a positive number, save the N next articles.
+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")
+  (require 'gnus-art)
+  (let ((gnus-default-article-saver 'gnus-summary-write-body-to-file))
+    (gnus-summary-save-article arg)))
+
 (defun gnus-summary-muttprint (&optional arg)
   "Print the current article using Muttprint.
 If N is a positive number, save the N next articles.
@@ -11380,6 +11495,8 @@ save those articles instead."
          (error "No such group: %s" to-newsgroup)))
     to-newsgroup))
 
+(defvar gnus-summary-save-parts-counter)
+
 (defun gnus-summary-save-parts (type dir n &optional reverse)
   "Save parts matching TYPE to DIR.
 If REVERSE, save parts that do not match TYPE."
@@ -11402,7 +11519,8 @@ If REVERSE, save parts that do not match TYPE."
       (let ((handles (or gnus-article-mime-handles
                         (mm-dissect-buffer nil gnus-article-loose-mime)
                         (and gnus-article-emulate-mime
-                             (mm-uu-dissect)))))
+                             (mm-uu-dissect))))
+           (gnus-summary-save-parts-counter 1))
        (when handles
          (gnus-summary-save-parts-1 type dir handles reverse)
          (unless gnus-article-mime-handles ;; Don't destroy this case.
@@ -11424,10 +11542,11 @@ If REVERSE, save parts that do not match TYPE."
                       (mm-handle-disposition handle) 'filename)
                      (mail-content-type-get
                       (mm-handle-type handle) 'name)
-                     (concat gnus-newsgroup-name
-                             "." (number-to-string
-                                  (cdr gnus-article-current))))))
+                     (format "%s.%d.%d" gnus-newsgroup-name
+                             (cdr gnus-article-current)
+                             gnus-summary-save-parts-counter))))
                   dir)))
+       (incf gnus-summary-save-parts-counter)
        (unless (file-exists-p file)
          (mm-save-part-to-file handle file))))))
 
@@ -11582,11 +11701,14 @@ If REVERSE, save parts that do not match TYPE."
            ()                          ; Malformed head.
          (unless (gnus-summary-article-sparse-p (mail-header-number header))
            (when (and (stringp id)
-                      (not (string= (gnus-group-real-name group)
-                                    (car where))))
-             ;; If we fetched by Message-ID and the article came
-             ;; from a different group, we fudge some bogus article
-             ;; numbers for this article.
+                      (or
+                       (not (string= (gnus-group-real-name group)
+                                     (car where)))
+                       (not (gnus-server-equal gnus-override-method
+                                               (gnus-group-method group)))))
+             ;; If we fetched by Message-ID and the article came from
+             ;; a different group (or server), we fudge some bogus
+             ;; article numbers for this article.
              (mail-header-set-number header gnus-reffed-article-number))
            (save-excursion
              (set-buffer gnus-summary-buffer)