Importing Pterodactyl Gnus v0.68.
[elisp/gnus.git-] / lisp / message.el
index c88a1f5..fb5e183 100644 (file)
@@ -251,7 +251,7 @@ should return the new buffer name."
   :group 'message-buffers
   :type '(choice (const :tag "off" nil)
                 (const :tag "unique" unique)
-                (const :tag "unsuniqueent" unsent)
+                (const :tag "unsent" unsent)
                 (function fun)))
 
 (defcustom message-kill-buffer-on-exit nil
@@ -322,7 +322,7 @@ The provided functions are:
   :group 'message-forwarding
   :type 'boolean)
 
-(defcustom message-ignored-resent-headers "^Return-receipt\\|^X-Gnus"
+(defcustom message-ignored-resent-headers "^Return-receipt\\|^X-Gnus\\|^Gnus-Warning:"
   "*All headers that match this regexp will be deleted when resending a message."
   :group 'message-interface
   :type 'regexp)
@@ -448,6 +448,11 @@ The function `message-setup' runs this hook."
   :group 'message-various
   :type 'hook)
 
+(defcustom message-cancel-hook nil
+  "Hook run when cancelling articles."
+  :group 'message-various
+  :type 'hook)
+
 (defcustom message-signature-setup-hook nil
   "Normal hook, run each time a new outgoing message is initialized.
 It is run after the headers have been inserted and before
@@ -832,7 +837,7 @@ Defaults to `text-mode-abbrev-table'.")
                "\\([" cite-prefix "]+[" cite-suffix "]*\\)?"
                "[:>|}].*")
        (0 'message-cited-text-face))
-      ("<#/?\\(multi\\)part.*>"
+      ("<#/?\\(multipart\\|part\\|external\\).*>"
        (0 'message-mml-face))))
   "Additional expressions to highlight in Message mode.")
 
@@ -874,13 +879,20 @@ The cdr of ech entry is a function for applying the face to a region.")
   "Coding system to encode outgoing mail.")
 
 (defvar message-draft-coding-system 
-  (if (string-match "XEmacs\\|Lucid" emacs-version)
-      'escape-quoted 'emacs-mule)
+  (cond 
+   ((not (fboundp 'coding-system-p)) nil)
+   ((coding-system-p 'emacs-mule) 'emacs-mule)
+   ((coding-system-p 'escape-quoted) 'escape-quoted)
+   ((coding-system-p 'no-conversion) 'no-conversion)
+   (t nil))
   "Coding system to compose mail.")
 
+(defvar message-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.")
+
 ;;; Internal variables.
 
-(defvar message-default-charset nil)
 (defvar message-buffer-list nil)
 (defvar message-this-is-news nil)
 (defvar message-this-is-mail nil)
@@ -1055,7 +1067,8 @@ The cdr of ech entry is a function for applying the face to a region.")
     (when value
       (while (string-match "\n[\t ]+" value)
        (setq value (replace-match " " t t value)))
-      value)))
+      ;; We remove all text props.delete-region
+      (format "%s" value))))
 
 (defun message-narrow-to-field ()
   "Narrow the buffer to the header on the current line."
@@ -1147,6 +1160,18 @@ Return the number of headers removed."
          (goto-char (point-max)))))
     number))
 
+(defun message-remove-first-header (header)
+  "Remove the first instance of HEADER if there is more than one."
+  (let ((count 0)
+       (regexp (concat "^" (regexp-quote header) ":")))
+    (save-excursion
+      (goto-char (point-min))
+      (while (re-search-forward regexp nil t)
+       (incf count)))
+    (while (> count 1)
+      (message-remove-header header nil t)
+      (decf count))))
+
 (defun message-narrow-to-headers ()
   "Narrow the buffer to the head of the message."
   (widen)
@@ -1282,6 +1307,7 @@ Point is left at the beginning of the narrowed-to region."
   (define-key message-mode-map "\C-c\C-y" 'message-yank-original)
   (define-key message-mode-map "\C-c\C-q" 'message-fill-yanked-message)
   (define-key message-mode-map "\C-c\C-w" 'message-insert-signature)
+  (define-key message-mode-map "\C-c\M-h" 'message-insert-headers)
   (define-key message-mode-map "\C-c\C-r" 'message-caesar-buffer-body)
   (define-key message-mode-map "\C-c\C-o" 'message-sort-headers)
   (define-key message-mode-map "\C-c\M-r" 'message-rename-buffer)
@@ -1296,8 +1322,11 @@ Point is left at the beginning of the narrowed-to region."
   (define-key message-mode-map "\C-c\C-z" 'message-kill-to-signature)
   (define-key message-mode-map "\M-\r" 'message-newline-and-reformat)
 
-  (define-key message-mode-map "\C-c\C-a" 'message-insert-mime-part)
-
+  (define-key message-mode-map "\C-c\C-a" 'message-mime-attach-file)
+  (define-key message-mode-map "\C-c\C-m\C-a" 'message-mime-attach-file)
+  (define-key message-mode-map "\C-c\C-m\C-e" 'message-mime-insert-external)
+  (define-key message-mode-map "\C-c\C-m\C-q" 'mml-quote-region)
+  
   (define-key message-mode-map "\t" 'message-tab))
 
 (easy-menu-define
@@ -1831,11 +1860,7 @@ prefix, and don't delete any headers."
           (if (listp message-indent-citation-function)
               message-indent-citation-function
             (list message-indent-citation-function)))))
-    (goto-char start)
-    ;; Quote parts.
-    (while (re-search-forward "<#/?!*\\(multi\\|part\\)>" end t)
-      (goto-char (match-beginning 1))
-      (insert "!"))
+    (mml-quote-region start end)
     (goto-char end)
     (when (re-search-backward "^-- $" start t)
       ;; Also peel off any blank lines before the signature.
@@ -1865,11 +1890,7 @@ prefix, and don't delete any headers."
             (if (listp message-indent-citation-function)
                 message-indent-citation-function
               (list message-indent-citation-function)))))
-      (goto-char start)
-      ;; Quote parts.
-      (while (re-search-forward "<#/?!*\\(multi\\|part\\)>" end t)
-       (goto-char (match-beginning 1))
-       (insert "!"))
+      (mml-quote-region start end)
       (goto-char start)
       (while functions
        (funcall (pop functions)))
@@ -2015,7 +2036,8 @@ the user from the mailer."
       (message-do-fcc)
       ;;(when (fboundp 'mail-hist-put-headers-into-history)
       ;; (mail-hist-put-headers-into-history))
-      (run-hooks 'message-sent-hook)
+      (save-excursion
+       (run-hooks 'message-sent-hook))
       (message "Sending...done")
       ;; Mark the buffer as unmodified and delete auto-save.
       (set-buffer-modified-p nil)
@@ -2084,7 +2106,6 @@ the user from the mailer."
        (case-fold-search nil)
        (news (message-news-p))
        (mailbuf (current-buffer)))
-    (message-encode-message-body)
     (save-restriction
       (message-narrow-to-headers)
       ;; Insert some headers.
@@ -2094,6 +2115,7 @@ the user from the mailer."
       (mail-encode-encoded-word-buffer)
       ;; Let the user do all of the above.
       (run-hooks 'message-header-hook))
+    (message-encode-message-body)
     (unwind-protect
        (save-excursion
          (set-buffer tembuf)
@@ -2260,7 +2282,6 @@ to find out how to use this."
        result)
     (if (not (message-check-news-body-syntax))
        nil
-      (message-encode-message-body)
       (save-restriction
        (message-narrow-to-headers)
        ;; Insert some headers.
@@ -2268,6 +2289,7 @@ to find out how to use this."
        (mail-encode-encoded-word-buffer)
        ;; Let the user do all of the above.
        (run-hooks 'message-header-hook))
+      (message-encode-message-body)
       (message-cleanup-headers)
       (if (not (message-check-news-syntax))
          nil
@@ -3177,10 +3199,6 @@ Headers already prepared in the buffer are not modified."
 (defun message-buffer-name (type &optional to group)
   "Return a new (unique) buffer name based on TYPE and TO."
   (cond
-   ;; Check whether `message-generate-new-buffers' is a function,
-   ;; and if so, call it.
-   ((message-functionp message-generate-new-buffers)
-    (funcall message-generate-new-buffers type to group))
    ;; Generate a new buffer name The Message Way.
    ((eq message-generate-new-buffers 'unique)
     (generate-new-buffer-name
@@ -3192,6 +3210,10 @@ Headers already prepared in the buffer are not modified."
               "")
             (if (and group (not (string= group ""))) (concat " on " group) "")
             "*")))
+   ;; Check whether `message-generate-new-buffers' is a function,
+   ;; and if so, call it.
+   ((message-functionp message-generate-new-buffers)
+    (funcall message-generate-new-buffers type to group))
    ((eq message-generate-new-buffers 'unsent)
     (generate-new-buffer-name
      (concat "*unsent " type
@@ -3324,6 +3346,23 @@ Headers already prepared in the buffer are not modified."
     (nndraft-request-expire-articles
      (list message-draft-article) "drafts" nil t)))
 
+(defun message-insert-headers ()
+  "Generate the headers for the article."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-headers)
+      (when (message-news-p)
+       (message-generate-headers
+        (delq 'Lines
+              (delq 'Subject
+                    (copy-sequence message-required-news-headers)))))
+      (when (message-mail-p)
+       (message-generate-headers
+        (delq 'Lines
+              (delq 'Subject
+                    (copy-sequence message-required-mail-headers))))))))
+
 \f
 
 ;;;
@@ -3620,6 +3659,7 @@ responses here are directed to other newsgroups."))
                  "")
                mail-header-separator "\n"
                message-cancel-message)
+       (run-hooks 'message-cancel-hook)
        (message "Canceling your article...")
        (if (let ((message-syntax-checks
                   'dont-check-for-anything-just-trust-me))
@@ -4107,10 +4147,55 @@ regexp varstr."
 ;;; MIME functions
 ;;;
 
-(defun message-insert-mime-part (file type)
-  "Insert a multipart/alternative part into the buffer."
+
+;; I really think this function should be renamed.  It is only useful
+;; for inserting file attachments.
+
+(defun message-mime-attach-file (file type description)
+  "Attach a file to the outgoing MIME message.
+The file is not inserted or encoded until you send the message with
+`\\[message-send-and-exit]' or `\\[message-send]'.
+
+FILE is the name of the file to attach.  TYPE is its content-type, a
+string of the form \"type/subtype\".  DESCRIPTION is a one-line
+description of the attachment."
   (interactive
-   (let* ((file (read-file-name "Insert file: " nil nil t))
+   (let* ((file (read-file-name "Attach file: " nil nil t))
+         (type (completing-read
+                (format "Content type (default %s): "
+                        (or (mm-default-file-encoding file)
+                            ;; Perhaps here we should check
+                            ;; what the file looks like, and
+                            ;; offer text/plain if it looks
+                            ;; like text/plain.
+                            "application/octet-stream"))
+                (delete-duplicates
+                 (mapcar (lambda (m) (list (cdr m))) mailcap-mime-extensions)
+                 :test 'equal)))
+         (description (read-string "One line description: ")))
+     (list file type description)))
+  (when (string-match "\\`[ \t]*\\'" description)
+    (setq description nil))
+  (when (string-match "\\`[ \t]*\\'" type)
+    (setq type (mm-default-file-encoding file))) nil
+  ;; Prevent some common errors.  This is inspired by similar code in
+  ;; VM.
+  (when (file-directory-p file)
+    (error "%s is a directory, cannot attach" file))
+  (unless (file-exists-p file)
+    (error "No such file: %s" file))
+  (unless (file-readable-p file)
+    (error "Permission denied: %s" file))
+  (insert (format "<#part type=%s filename=%s%s><#/part>\n"
+                 type (prin1-to-string file)
+                 (if description
+                     (format " description=%s" (prin1-to-string description))
+                   ""))))
+
+(defun message-mime-insert-external (file type)
+  "Insert a message/external-body part into the buffer."
+  (interactive
+   (let* ((file (read-file-name "Insert file: "))
          (type (mm-default-file-encoding file)))
      (list file
           (completing-read
@@ -4118,23 +4203,25 @@ regexp varstr."
            (delete-duplicates
             (mapcar (lambda (m) (list (cdr m))) mailcap-mime-extensions))
            nil nil type))))
-  (insert (format "<#part type=%s filename=\"%s\"><#/part>\n"
+  (insert (format "<#external type=%s name=\"%s\"><#/external>\n"
                  type file)))
 
 (defun message-encode-message-body ()
-  (let (lines multipart-p)
+  (let ((mm-default-charset message-default-charset)
+       lines multipart-p)
     (message-goto-body)
     (save-restriction
       (narrow-to-region (point) (point-max))
       (let ((new (mml-generate-mime)))
-       (delete-region (point-min) (point-max))
-       (insert new)
-       (goto-char (point-min))
-       (if (eq (aref new 0) ?\n)
-           (delete-char 1)
-         (search-forward "\n\n")
-         (setq lines (buffer-substring (point-min) (1- (point))))
-         (delete-region (point-min)  (point)))))
+       (when new
+         (delete-region (point-min) (point-max))
+         (insert new)
+         (goto-char (point-min))
+         (if (eq (aref new 0) ?\n)
+             (delete-char 1)
+           (search-forward "\n\n")
+           (setq lines (buffer-substring (point-min) (1- (point))))
+           (delete-region (point-min)  (point))))))
     (save-restriction
       (message-narrow-to-headers-or-head)
       (message-remove-header "Mime-Version")
@@ -4145,6 +4232,10 @@ regexp varstr."
       (setq multipart-p 
            (re-search-backward "^Content-Type: multipart/" nil t)))
     (when multipart-p
+      (save-restriction
+       (message-narrow-to-headers-or-head)
+       (message-remove-first-header "Content-Type")
+       (message-remove-first-header "Content-Transfer-Encoding"))
       (message-goto-body)
       (insert "This is a MIME multipart message.  If you are reading\n")
       (insert "this, you shouldn't.\n"))))