* gnus-art.el (gnus-mime-save-part-and-strip): Clarify prompt.
[gnus] / lisp / gnus-art.el
index 75de415..74821df 100644 (file)
@@ -1,6 +1,7 @@
 ;;; gnus-art.el --- article mode commands for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-;;        Free Software Foundation, Inc.
+
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+;;   2005 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -933,6 +934,19 @@ used."
   :type '(repeat (cons (string :tag "name")
                       (function))))
 
+(defcustom gnus-auto-select-part 1
+  "Advance to next MIME part when deleting or stripping parts.
+
+When 0, point will be placed on the same part as before.  When
+positive (negative), move point forward (backwards) this many
+parts.  When nil, redisplay article."
+  :version "23.0" ;; No Gnus
+  :group 'gnus-article-mime
+  :type '(choice (const nil :tag "Redisplay article.")
+                (const 1 :tag "Next part.")
+                (const 0 :tag "Current part.")
+                integer))
+
 ;;;
 ;;; The treatment variables
 ;;;
@@ -1510,10 +1524,10 @@ This requires GNU Libidn, and by default only enabled if it is found."
     (gnus-treat-date-ut gnus-article-date-ut)
     (gnus-treat-date-local gnus-article-date-local)
     (gnus-treat-date-english gnus-article-date-english)
-    (gnus-treat-date-lapsed gnus-article-date-lapsed)
     (gnus-treat-date-original gnus-article-date-original)
     (gnus-treat-date-user-defined gnus-article-date-user)
     (gnus-treat-date-iso8601 gnus-article-date-iso8601)
+    (gnus-treat-date-lapsed gnus-article-date-lapsed)
     (gnus-treat-display-x-face gnus-article-display-x-face)
     (gnus-treat-display-face gnus-article-display-face)
     (gnus-treat-hide-headers gnus-article-maybe-hide-headers)
@@ -4092,8 +4106,26 @@ General format specifiers can also be used.  See Info node
          (delete-region (point) (point-max))
          (mm-display-parts handles))))))
 
+(defun gnus-article-jump-to-part (n)
+  "Jump to MIME part N."
+  (interactive "P")
+  (pop-to-buffer gnus-article-buffer)
+  (let ((parts (length gnus-article-mime-handle-alist)))
+    (or n (setq n
+               (string-to-number
+                (read-string ;; Emacs 21 doesn't have `read-number'.
+                 (format "Jump to part (2..%s): " parts)))))
+    (unless (and (integerp n) (<= n parts) (>= n 1))
+      (setq n
+           (progn
+             (gnus-message 7 "Invalid part `%s', using %s instead."
+                           n parts)
+             parts)))
+    (gnus-message 9 "Jumping to part %s." n)
+    (gnus-article-goto-part n)))
+
 (eval-when-compile
-  (defsubst gnus-article-edit-part (handles)
+  (defsubst gnus-article-edit-part (handles &optional current-id)
     "Edit an article in order to delete a mime part.
 This function is exclusively used by `gnus-mime-save-part-and-strip'
 and `gnus-mime-delete-part', and not provided at run-time normally."
@@ -4132,10 +4164,14 @@ and `gnus-mime-delete-part', and not provided at run-time normally."
        (gnus-summary-edit-article-done
         ,(or (mail-header-references gnus-current-headers) "")
         ,(gnus-group-read-only-p)
-        ,gnus-summary-buffer no-highlight)))
+        ,gnus-summary-buffer no-highlight))
+     t)
     (gnus-article-edit-done)
     (gnus-summary-expand-window)
-    (gnus-summary-show-article)))
+    (gnus-summary-show-article)
+    (when (and current-id (integerp gnus-auto-select-part))
+      (gnus-article-jump-to-part
+       (+ current-id gnus-auto-select-part)))))
 
 (defun gnus-mime-save-part-and-strip ()
   "Save the MIME part under point then replace it with an external body."
@@ -4146,29 +4182,28 @@ and `gnus-mime-delete-part', and not provided at run-time normally."
   (when (mm-complicated-handles gnus-article-mime-handles)
     (error "\
 The current article has a complicated MIME structure, giving up..."))
-  (when (gnus-yes-or-no-p "\
-Deleting parts may malfunction or destroy the article; continue? ")
-    (let* ((data (get-text-property (point) 'gnus-data))
-          file param
-          (handles gnus-article-mime-handles))
-      (setq file (and data (mm-save-part data)))
-      (when file
-       (with-current-buffer (mm-handle-buffer data)
-         (erase-buffer)
-         (insert "Content-Type: " (mm-handle-media-type data))
-         (mml-insert-parameter-string (cdr (mm-handle-type data))
-                                      '(charset))
-         (insert "\n")
-         (insert "Content-ID: " (message-make-message-id) "\n")
-         (insert "Content-Transfer-Encoding: binary\n")
-         (insert "\n"))
-       (setcdr data
-               (cdr (mm-make-handle nil
-                                    `("message/external-body"
-                                      (access-type . "LOCAL-FILE")
-                                      (name . ,file)))))
-       (set-buffer gnus-summary-buffer)
-       (gnus-article-edit-part handles)))))
+  (let* ((data (get-text-property (point) 'gnus-data))
+        (id (get-text-property (point) 'gnus-part))
+        file param
+        (handles gnus-article-mime-handles))
+    (setq file (and data (mm-save-part data "Delete MIME part and save to: ")))
+    (when file
+      (with-current-buffer (mm-handle-buffer data)
+       (erase-buffer)
+       (insert "Content-Type: " (mm-handle-media-type data))
+       (mml-insert-parameter-string (cdr (mm-handle-type data))
+                                    '(charset))
+       (insert "\n")
+       (insert "Content-ID: " (message-make-message-id) "\n")
+       (insert "Content-Transfer-Encoding: binary\n")
+       (insert "\n"))
+      (setcdr data
+             (cdr (mm-make-handle nil
+                                  `("message/external-body"
+                                    (access-type . "LOCAL-FILE")
+                                    (name . ,file)))))
+      ;; (set-buffer gnus-summary-buffer)
+      (gnus-article-edit-part handles id))))
 
 (defun gnus-mime-delete-part ()
   "Delete the MIME part under point.
@@ -4180,9 +4215,11 @@ Replace it with some information about the removed part."
   (when (mm-complicated-handles gnus-article-mime-handles)
     (error "\
 The current article has a complicated MIME structure, giving up..."))
-  (when (gnus-yes-or-no-p "\
-Deleting parts may malfunction or destroy the article; continue? ")
+  (when (or gnus-expert-user
+           (gnus-yes-or-no-p "\
+Deleting parts may malfunction or destroy the article; continue? "))
     (let* ((data (get-text-property (point) 'gnus-data))
+          (id (get-text-property (point) 'gnus-part))
           (handles gnus-article-mime-handles)
           (none "(none)")
           (description
@@ -4213,8 +4250,8 @@ Deleting parts may malfunction or destroy the article; continue? ")
                        nil `("text/plain") nil nil
                        (list "attachment")
                        (format "Deleted attachment (%s bytes)" bsize))))))
-      (set-buffer gnus-summary-buffer)
-      (gnus-article-edit-part handles))))
+      ;; (set-buffer gnus-summary-buffer)
+      (gnus-article-edit-part handles id))))
 
 (defun gnus-mime-save-part ()
   "Save the MIME part under point."
@@ -4478,13 +4515,15 @@ If no internal viewer is available, use an external viewer."
     (if action-pair
        (funcall (cdr action-pair)))))
 
-(defun gnus-article-part-wrapper (n function)
+(defun gnus-article-part-wrapper (n function &optional no-handle)
   (with-current-buffer gnus-article-buffer
     (when (> n (length gnus-article-mime-handle-alist))
       (error "No such part"))
     (gnus-article-goto-part n)
-    (let ((handle (cdr (assq n gnus-article-mime-handle-alist))))
-      (funcall function handle))))
+    (if no-handle
+       (funcall function)
+      (let ((handle (cdr (assq n gnus-article-mime-handle-alist))))
+       (funcall function handle)))))
 
 (defun gnus-article-pipe-part (n)
   "Pipe MIME part N, which is the numerical prefix."
@@ -4522,6 +4561,18 @@ N is the numerical prefix."
   (interactive "p")
   (gnus-article-part-wrapper n 'gnus-mime-inline-part))
 
+(defun gnus-article-save-part-and-strip (n)
+  "Save MIME part N and replace it with an external body.
+N is the numerical prefix."
+  (interactive "p")
+  (gnus-article-part-wrapper n 'gnus-mime-save-part-and-strip t))
+
+(defun gnus-article-delete-part (n)
+  "Delete MIME part N and add some information about the removed part.
+N is the numerical prefix."
+  (interactive "p")
+  (gnus-article-part-wrapper n 'gnus-mime-delete-part t))
+
 (defun gnus-article-mime-match-handle-first (condition)
   (if condition
       (let (n)
@@ -5199,12 +5250,22 @@ specifies."
                     (if header-line-format 1 0)))))))
 
 (defun gnus-article-next-page-1 (lines)
-  (let ((scroll-in-place nil))
-    (condition-case ()
-       (scroll-up lines)
-      (end-of-buffer
-       ;; Long lines may cause an end-of-buffer error.
-       (goto-char (point-max)))))
+  (when (and (not (featurep 'xemacs))
+            (numberp lines)
+            (> lines 0)
+            (numberp (symbol-value 'scroll-margin))
+            (> (symbol-value 'scroll-margin) 0))
+    ;; Protect against the bug that Emacs 21.x hangs up when scrolling up for
+    ;; too many number of lines if `scroll-margin' is set as two or greater.
+    (setq lines (min lines
+                    (max 0 (- (count-lines (window-start) (point-max))
+                              (symbol-value 'scroll-margin))))))
+  (condition-case ()
+      (let ((scroll-in-place nil))
+       (scroll-up lines))
+    (end-of-buffer
+     ;; Long lines may cause an end-of-buffer error.
+     (goto-char (point-max))))
   (gnus-article-beginning-of-window))
 
 (defun gnus-article-prev-page (&optional lines)
@@ -5219,13 +5280,13 @@ Argument LINES specifies lines to be scrolled down."
        (gnus-narrow-to-page -1)        ;Go to previous page.
        (goto-char (point-max))
        (recenter -1))
-    (let ((scroll-in-place nil))
-      (prog1
-         (condition-case ()
-             (scroll-down lines)
-           (beginning-of-buffer
-            (goto-char (point-min))))
-       (gnus-article-beginning-of-window)))))
+    (prog1
+       (condition-case ()
+           (let ((scroll-in-place nil))
+             (scroll-down lines))
+         (beginning-of-buffer
+          (goto-char (point-min))))
+      (gnus-article-beginning-of-window))))
 
 (defun gnus-article-only-boring-p ()
   "Decide whether there is only boring text remaining in the article.
@@ -5773,7 +5834,7 @@ groups."
        ,(or (mail-header-references gnus-current-headers) "")
        ,(gnus-group-read-only-p) ,gnus-summary-buffer no-highlight))))
 
-(defun gnus-article-edit-article (start-func exit-func)
+(defun gnus-article-edit-article (start-func exit-func &optional quiet)
   "Start editing the contents of the current article buffer."
   (let ((winconf (current-window-configuration)))
     (set-buffer gnus-article-buffer)
@@ -5786,7 +5847,8 @@ groups."
     (gnus-configure-windows 'edit-article)
     (setq gnus-article-edit-done-function exit-func)
     (setq gnus-prev-winconf winconf)
-    (gnus-message 6 "C-c C-c to end edits")))
+    (unless quiet
+      (gnus-message 6 "C-c C-c to end edits"))))
 
 (defun gnus-article-edit-done (&optional arg)
   "Update the article edits and exit."
@@ -5875,6 +5937,14 @@ groups."
   :group 'gnus-article-buttons
   :type 'regexp)
 
+;; Regexp suggested by Felix Wiemann in <87oeuomcz9.fsf@news2.ososo.de>
+(defcustom gnus-button-valid-localpart-regexp
+  "[a-z0-9$%(*-=?[_][^<>\")!;:,{}\n\t ]*"
+  "Regular expression that matches a localpart of mail addresses or MIDs."
+  :version "22.1"
+  :group 'gnus-article-buttons
+  :type 'regexp)
+
 (defcustom gnus-button-man-handler 'manual-entry
   "Function to use for displaying man pages.
 The function must take at least one argument with a string naming the
@@ -5914,12 +5984,11 @@ The function must take one argument, the string naming the URL."
                 (regexp :tag "Other")))
 
 (defcustom gnus-button-ctan-directory-regexp
-  (concat
-   "\\(?:"
-   "biblio\\|digests\\|dviware\\|fonts\\|graphics\\|help\\|"
-   "indexing\\|info\\|language\\|macros\\|support\\|systems\\|"
-   "tds\\|tools\\|usergrps\\|web\\|nonfree\\|obsolete"
-   "\\)")
+  (regexp-opt
+   (list "archive-tools" "biblio" "bibliography" "digests" "documentation"
+        "dviware" "fonts" "graphics" "help" "indexing" "info" "language"
+        "languages" "macros" "nonfree" "obsolete" "support" "systems"
+        "tds" "tools" "usergrps" "web") t)
   "Regular expression for ctan directories.
 It should match all directories in the top level of `gnus-ctan-url'."
   :version "22.1"
@@ -5927,8 +5996,7 @@ It should match all directories in the top level of `gnus-ctan-url'."
   :type 'regexp)
 
 (defcustom gnus-button-mid-or-mail-regexp
-  (concat "\\b\\(<?[a-z0-9$%(*-=?[_][^<>\")!;:,{}\n\t ]*@"
-         ;; Felix Wiemann in <87oeuomcz9.fsf@news2.ososo.de>
+  (concat "\\b\\(<?" gnus-button-valid-localpart-regexp "@"
          gnus-button-valid-fqdn-regexp
          ">?\\)\\b")
   "Regular expression that matches a message ID or a mail address."
@@ -6243,8 +6311,9 @@ positives are possible."
 (defcustom gnus-button-alist
   '(("<\\(url:[>\n\t ]*?\\)?\\(nntp\\|news\\):[>\n\t ]*\\([^>\n\t ]*@[^>\n\t ]*\\)>"
      0 (>= gnus-button-message-level 0) gnus-button-handle-news 3)
-    ("\\b\\(nntp\\|news\\):\\([^>\n\t ]*@[^>)!;:,\n\t ]*\\)" 0 t
-     gnus-button-handle-news 2)
+    ((concat "\\b\\(nntp\\|news\\):\\("
+            gnus-button-valid-localpart-regexp "@[a-z0-9.-]+[a-z]\\)")
+     0 t gnus-button-handle-news 2)
     ("\\(\\b<\\(url:[>\n\t ]*\\)?\\(nntp\\|news\\):[>\n\t ]*\\(//\\)?\\([^>\n\t ]*\\)>\\)"
      1 (>= gnus-button-message-level 0) gnus-button-fetch-group 5)
     ("\\b\\(nntp\\|news\\):\\(//\\)?\\([^'\">\n\t ]+\\)"