* gnus-msg.el (gnus-inews-yank-articles): Don't delete newlines.
[elisp/gnus.git-] / lisp / message.el
index 7a32809..8f67848 100644 (file)
@@ -1,5 +1,5 @@
 ;;; message.el --- composing mail and news messages
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -170,7 +170,7 @@ If the string contains the format spec \"%s\", the Newsgroups
 the article has been posted to will be inserted there.
 If this variable is nil, no such courtesy message will be added."
   :group 'message-sending
-  :type '(radio (string :format "%t: %v\n" :size 0) (const nil)))
+  :type '(radio string (const nil)))
 
 (defcustom message-ignored-bounced-headers
   "^\\(Received\\|Return-Path\\|Delivered-To\\):"
@@ -266,8 +266,7 @@ Archives \(such as groups.google.com\) respect this header."
   "Note to insert why you wouldn't want this posting archived.
 If nil, don't insert any text in the body."
   :version "21.4"
-  :type '(radio (string :format "%t: %v\n" :size 0)
-               (const nil))
+  :type '(radio string (const nil))
   :link '(custom-manual "(message)Header Commands")
   :group 'message-various)
 
@@ -419,7 +418,12 @@ included.  Organization and User-Agent are optional."
   :group 'message-news
   :group 'message-headers
   :link '(custom-manual "(message)Message Headers")
-  :type 'regexp)
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
+                regexp))
 
 (defcustom message-ignored-mail-headers
   "^[GF]cc:\\|^Resent-Fcc:\\|^Xref:\\|^X-Draft-From:\\|^X-Gnus-Agent-Meta-Information:"
@@ -435,7 +439,12 @@ It's best to delete old Path and Date headers before posting to avoid
 any confusion."
   :group 'message-interface
   :link '(custom-manual "(message)Superseding")
-  :type 'regexp)
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
+                regexp))
 
 (defcustom message-supersede-setup-function
   'message-supersede-setup-for-mime-edit
@@ -652,13 +661,22 @@ Done before generating the new subject of a forward."
   "*All headers that match this regexp will be deleted when resending a message."
   :group 'message-interface
   :link '(custom-manual "(message)Resending")
-  :type 'regexp)
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
+                regexp))
 
 (defcustom message-forward-ignored-headers "^Content-Transfer-Encoding:\\|^X-Gnus"
   "*All headers that match this regexp will be deleted when forwarding a message."
   :version "21.1"
   :group 'message-forwarding
-  :type '(choice (const :tag "None" nil)
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
                 regexp))
 
 (defcustom message-ignored-cited-headers "."
@@ -684,6 +702,7 @@ Done before generating the new subject of a forward."
                non-word-constituents
                "]\\)+>+\\|[ \t]*[]>|}+]\\)+"))))
   "*Regexp matching the longest possible citation prefix on a line."
+  :version "21.4"
   :group 'message-insertion
   :link '(custom-manual "(message)Insertion Variables")
   :type 'regexp)
@@ -753,6 +772,12 @@ and respond with new To and Cc headers."
   :link '(custom-manual "(message)Followup")
   :type '(choice function (const nil)))
 
+(defcustom message-extra-wide-headers nil
+  "If non-nil, a list of additional address headers.
+These are used when composing a wide reply."
+  :group 'message-sending
+  :type '(repeat string))
+
 (defcustom message-use-followup-to 'ask
   "*Specifies what to do with Followup-To header.
 If nil, always ignore the header.  If it is t, use its value, but
@@ -824,8 +849,7 @@ non-nil, each line of this file should be a mailing list address."
   :version "21.4"
   :group 'message-interface
   :link '(custom-manual "(message)Mailing Lists")
-  :type '(radio (file :format "%t: %v\n" :size 0)
-               (const nil)))
+  :type '(radio file (const nil)))
 
 (defcustom message-subscribed-addresses nil
   "*Specifies a list of addresses the user is subscribed to.
@@ -870,6 +894,7 @@ Doing so would be even more evil than leaving it out."
   "*Envelope-from when sending mail with sendmail.
 If this is nil, use `user-mail-address'.  If it is the symbol
 `header', use the From: header of the message."
+  :version "21.4"
   :type '(choice (string :tag "From name")
                 (const :tag "Use From: header from message" header)
                 (const :tag "Use `user-mail-address'" nil))
@@ -989,7 +1014,8 @@ The function `message-supersede' runs this hook."
   (let ((map (make-sparse-keymap 'message-minibuffer-local-map)))
     (set-keymap-parent map minibuffer-local-map)
     map)
-  "Keymap for `message-read-from-minibuffer'.")
+  "Keymap for `message-read-from-minibuffer'."
+  :version "21.4")
 
 ;;;###autoload
 (defcustom message-citation-line-function 'message-insert-citation-line
@@ -1284,14 +1310,22 @@ candidates:
   (or (not (listp message-shoot-gnksa-feet))
       (memq feature message-shoot-gnksa-feet)))
 
-(defcustom message-hidden-headers nil
+(defcustom message-hidden-headers "^References:"
   "Regexp of headers to be hidden when composing new messages.
 This can also be a list of regexps to match headers.  Or a list
 starting with `not' and followed by regexps."
   :version "21.4"
   :group 'message
   :link '(custom-manual "(message)Message Headers")
-  :type '(repeat regexp))
+  :type '(choice
+         :format "%{%t%}: %[Value Type%] %v"
+         (regexp :menu-tag "regexp" :format "regexp\n%t: %v")
+         (repeat :menu-tag "(regexp ...)" :format "(regexp ...)\n%v%i"
+                 (regexp :format "%t: %v"))
+         (cons :menu-tag "(not regexp ...)" :format "(not regexp ...)\n%v"
+               (const not)
+               (repeat :format "%v%i"
+                       (regexp :format "%t: %v")))))
 
 (defcustom message-cite-articles-with-x-no-archive t
   "If non-nil, cite text from articles that has X-No-Archive set."
@@ -1619,10 +1653,11 @@ no, only reply back to the author."
 
 (defcustom message-user-fqdn nil
   "*Domain part of Messsage-Ids."
+  :version "21.4"
   :group 'message-headers
   :link '(custom-manual "(message)News Headers")
   :type '(radio (const :format "%v  " nil)
-               (string :format "FQDN: %v\n" :size 0)))
+               (string :format "FQDN: %v")))
 
 (defcustom message-use-idna (and (condition-case nil (require 'idna)
                                   (file-error))
@@ -1733,7 +1768,8 @@ You must have the \"hashcash\" binary installed, see `hashcash-path'."
   "Alist of header names/filler functions.")
 
 (defvar message-header-format-alist
-  `((Newsgroups)
+  `((From)
+    (Newsgroups)
     (To)
     (Cc)
     (Subject)
@@ -1852,11 +1888,11 @@ is used by default."
   (if (not header)
       nil
     (let ((regexp (format "[%s]+" (or separator ",")))
-         (beg (point-min))
          (first t)
-         quoted elems paren)
+         beg quoted elems paren)
       (with-temp-buffer
        (set-buffer-multibyte t)
+       (setq beg (point-min))
        (insert header)
        (goto-char (point-min))
        (while (not (eobp))
@@ -2630,7 +2666,7 @@ message composition doesn't break too bad."
   ;; fontified: is used by font-lock.
   ;; syntax-table, local-map: I dunno.
   ;; We need to add XEmacs names to the list.
-  "Property list of with properties.forbidden in message buffers.
+  "Property list of with properties forbidden in message buffers.
 The values of the properties are ignored, only the property names are used.")
 
 (defun message-tamago-not-in-use-p (pos)
@@ -2655,10 +2691,9 @@ See also `message-forbidden-properties'."
             (message-tamago-not-in-use-p begin)
             ;; Check whether the invisible MIME part is not inserted.
             (not (text-property-any begin end 'mime-edit-invisible t)))
-    (dolist (from-to (message-text-with-property 'message-hidden
-                                                begin end t))
-      (remove-text-properties (car from-to) (cdr from-to)
-                             message-forbidden-properties))))
+    (let ((buffer-read-only nil)
+         (inhibit-read-only t))
+      (remove-text-properties begin end message-forbidden-properties))))
 
 ;;;###autoload
 (define-derived-mode message-mode text-mode "Message"
@@ -3534,9 +3569,9 @@ be added to the \"References\" field."
                (mail-header-format
                 (list (or (assq 'References message-header-format-alist)
                           '(References . message-fill-references)))
-                (list (cons 'References (mapconcat 'identity
-                                                   (nreverse newrefs) " "))))
-               (backward-delete-char 1))))))
+                (list (cons 'References
+                            (mapconcat 'identity
+                                       (nreverse newrefs) " ")))))))))
       (unless arg
        (if (and message-suspend-font-lock-when-citing
                 (boundp 'font-lock-mode)
@@ -3819,8 +3854,7 @@ Instead, just auto-save the buffer and then bury it."
   "Bury this mail BUFFER."
   (let ((newbuf (other-buffer buffer)))
     (bury-buffer buffer)
-    (if (and (fboundp 'frame-parameters)
-            (cdr (assq 'dedicated (frame-parameters)))
+    (if (and (window-dedicated-p (selected-window))
             (not (null (delq (selected-frame) (visible-frame-list)))))
        (delete-frame (selected-frame))
       (switch-to-buffer newbuf))))
@@ -3932,24 +3966,25 @@ It should typically alter the sending method in some way or other."
 (put 'message-check 'edebug-form-spec '(form body))
 
 ;; Advise the function `invisible-region'.
-(let (current-load-list)
-  (eval
-   `(defadvice invisible-region (around add-mime-edit-invisible (start end)
-                                       activate)
-      "Advised by T-gnus Message.
+(unless noninteractive
+  (let (current-load-list)
+    (eval
+     `(defadvice invisible-region (around add-mime-edit-invisible (start end)
+                                         activate)
+       "Advised by T-gnus Message.
 Add the text property `mime-edit-invisible' to an invisible text when
 the buffer's major mode is `message-mode'.  The added property will be
 used to distinguish whether the invisible text is a MIME part or not."
-      ,(if (featurep 'xemacs)
-          '(if (eq ?\n (char-after start))
-               (setq start (1+ start)))
-        '(if (eq ?\n (char-after (1- end)))
-             (setq end (1- end))))
-      (setq ad-return-value
-           (if (eq 'message-mode major-mode)
-               (add-text-properties start end
-                                    '(invisible t mime-edit-invisible t))
-             (put-text-property start end 'invisible t))))))
+       ,(if (featurep 'xemacs)
+            '(if (eq ?\n (char-after start))
+                 (setq start (1+ start)))
+          '(if (eq ?\n (char-after (1- end)))
+               (setq end (1- end))))
+       (setq ad-return-value
+             (if (eq 'message-mode major-mode)
+                 (add-text-properties start end
+                                      '(invisible t mime-edit-invisible t))
+               (put-text-property start end 'invisible t)))))))
 
 (defun message-text-with-property (prop &optional start end reverse)
   "Return a list of start and end positions where the text has PROP.
@@ -3985,9 +4020,9 @@ not have PROP."
   (unless (bolp)
     (insert "\n"))
   ;; Make the hidden headers visible.
-  (dolist (from-to (message-text-with-property 'message-hidden))
-    (add-text-properties (car from-to) (cdr from-to)
-                        '(invisible nil intangible nil)))
+  (widen)
+  ;; Sort headers before sending the message.
+  (message-sort-headers)
   ;; Make invisible text visible except for mime parts which may be
   ;; inserted by the MIME-Edit.
   ;; It doesn't seem as if this is useful, since the invisible property
@@ -4228,10 +4263,11 @@ This sub function is for exclusive use of `message-send-mail'."
         (headers message-required-mail-headers)
         failure)
     (when message-generate-hashcash
-      (save-restriction
-       (message-narrow-to-headers)
-       (message-remove-header "X-Hashcash"))
       (message "Generating hashcash...")
+      ;; Wait for calculations already started to finish...
+      (hashcash-wait-async)
+      ;; ...and do calculations not already done.  mail-add-payment
+      ;; will leave existing X-Hashcash headers alone.
       (mail-add-payment)
       (message "Generating hashcash...done"))
     (save-restriction
@@ -5575,6 +5611,7 @@ See `message-idna-encode'."
        (message-narrow-to-head)
        (message-idna-to-ascii-rhs-1 "From")
        (message-idna-to-ascii-rhs-1 "To")
+       (message-idna-to-ascii-rhs-1 "Reply-To")
        (message-idna-to-ascii-rhs-1 "Cc")))))
 
 (defun message-generate-headers (headers)
@@ -5782,8 +5819,7 @@ Headers already prepared in the buffer are not modified."
   (insert (capitalize (symbol-name header))
          ": "
          (std11-fill-msg-id-list-string
-          (if (consp value) (car value) value))
-         "\n"))
+          (if (consp value) (car value) value))))
 
 (defun message-split-line ()
   "Split current line, moving portion beyond point vertically down.
@@ -5933,10 +5969,10 @@ outside the message header or if the option `message-beginning-of-line'
 is nil.
 
 If point is in the message header and on a (non-continued) header
-line, move point to the beginning of the header value.  If point
-is already there, move point to beginning of line.  Therefore,
-repeated calls will toggle point between beginning of field and
-beginning of line."
+line, move point to the beginning of the header value or the beginning of line,
+whichever is closer.  If point is already at beginning of line, move point to
+beginning of header value.  Therefore, repeated calls will toggle point
+between beginning of field and beginning of line."
   (interactive "p")
   (let ((zrs 'zmacs-region-stays))
     (when (and (interactive-p) (boundp zrs))
@@ -5947,9 +5983,9 @@ beginning of line."
             (bol (progn (beginning-of-line n) (point)))
             (eol (point-at-eol))
             (eoh (re-search-forward ": *" eol t)))
-       (if (or (not eoh) (equal here eoh))
-           (goto-char bol)
-         (goto-char eoh)))
+       (goto-char
+        (if (and eoh (or (< eoh here) (= bol here)))
+            eoh bol)))
     (beginning-of-line n)))
 
 (defun message-buffer-name (type &optional to group)
@@ -6177,6 +6213,9 @@ are not included."
     (run-hooks 'message-header-setup-hook))
   (set-buffer-modified-p nil)
   (setq buffer-undo-list nil)
+  (when message-generate-hashcash
+    ;; Generate hashcash headers for recipients already known
+    (mail-add-payment-async))
   (run-hooks 'message-setup-hook)
   (message-position-point)
   (undo-boundary))
@@ -6263,7 +6302,7 @@ OTHER-HEADERS is an alist of header/value pairs."
                     (Subject . ,(or subject ""))))))
 
 (defun message-get-reply-headers (wide &optional to-address address-headers)
-  (let (follow-to mct never-mct to cc author mft recipients)
+  (let (follow-to mct never-mct to cc author mft recipients extra)
     ;; Find all relevant headers we need.
     (save-restriction
       (message-narrow-to-headers-or-head)
@@ -6274,10 +6313,15 @@ OTHER-HEADERS is an alist of header/value pairs."
        ;; message-header-synonyms.
        (setq to (or (message-fetch-field "to")
                     (and (loop for synonym in message-header-synonyms
-                           when (memq 'Original-To synonym)
-                           return t)
+                               when (memq 'Original-To synonym)
+                               return t)
                          (message-fetch-field "original-to")))
              cc (message-fetch-field "cc")
+             extra (when message-extra-wide-headers
+                     (mapconcat 'identity
+                                (mapcar 'message-fetch-field
+                                        message-extra-wide-headers)
+                                ", "))
              mct (when message-use-mail-copies-to
                    (message-fetch-field "mail-copies-to"))
              author (or mrt
@@ -6364,8 +6408,9 @@ responses here are directed to other addresses.")))
        (if mct (setq recipients (concat recipients ", " mct))))
        (t
        (setq recipients (if never-mct "" (concat ", " author)))
-       (if to  (setq recipients (concat recipients ", " to)))
-       (if cc  (setq recipients (concat recipients ", " cc)))
+       (if to (setq recipients (concat recipients ", " to)))
+       (if cc (setq recipients (concat recipients ", " cc)))
+       (if extra (setq recipients (concat recipients ", " extra)))
        (if mct (setq recipients (concat recipients ", " mct)))))
       (if (>= (length recipients) 2)
          ;; Strip the leading ", ".
@@ -6921,8 +6966,7 @@ Optional NEWS will use news to forward instead of mail."
     (setq e (point))
     (insert
      "\n-------------------- End of forwarded message --------------------\n")
-    (when (and (not current-prefix-arg)
-              message-forward-ignored-headers)
+    (when message-forward-ignored-headers
       (save-restriction
        (narrow-to-region b e)
        (goto-char b)
@@ -6968,7 +7012,7 @@ Optional NEWS will use news to forward instead of mail."
        (goto-char (point-max))))
     (setq e (point))
     (insert "<#/mml>\n")
-    (when (and (not current-prefix-arg)
+    (when (and (not message-forward-decoded-p)
               message-forward-ignored-headers)
       (save-restriction
        (narrow-to-region b e)
@@ -7343,6 +7387,7 @@ which specify the range to operate on."
        '("^\\(Disposition-Notification-To\\|Return-Receipt-To\\):"
          . message-expand-name))
   "Alist of (RE . FUN).  Use FUN for completion on header lines matching RE."
+  :version "21.4"
   :group 'message
   :type '(alist :key-type regexp :value-type function))
 
@@ -7370,7 +7415,7 @@ This variable is semi-obsolete, set it as nil and use
                (function-item :format "eudc: %v\n" eudc-expand-inline)
                (function-item :format "bbdb: %v\n" bbdb-complete-name)
                (function-item :format "lsdb: %v\n" lsdb-complete-name)
-               (function :size 0 :value expand-abbrev)))
+               (function :value expand-abbrev)))
 
 (defcustom message-tab-body-function nil
   "*Function to execute when `message-tab' (TAB) is executed in the body.
@@ -7611,7 +7656,7 @@ regexp VARSTR."
 
 (defun message-use-alternative-email-as-from ()
   (require 'mail-utils)
-  (let* ((fields '("To" "Cc"))
+  (let* ((fields '("To" "Cc" "From"))
         (emails
          (split-string
           (mail-strip-quoted-names
@@ -7625,7 +7670,8 @@ regexp VARSTR."
       (pop emails))
     (unless (or (not email) (equal email user-mail-address))
       (goto-char (point-max))
-      (insert "From: " email "\n"))))
+      (insert "From: " (let ((user-mail-address email)) (message-make-from))
+             "\n"))))
 
 (defun message-options-get (symbol)
   (cdr (assq symbol message-options)))
@@ -7664,7 +7710,8 @@ regexp VARSTR."
                     (list message-hidden-headers)
                   message-hidden-headers))
        (inhibit-point-motion-hooks t)
-       (after-change-functions nil))
+       (after-change-functions nil)
+       (end-of-headers 0))
     (when regexps
       (save-excursion
        (save-restriction
@@ -7673,11 +7720,17 @@ regexp VARSTR."
          (while (not (eobp))
            (if (not (message-hide-header-p regexps))
                (message-next-header)
-             (let ((begin (point)))
+             (let ((begin (point))
+                   header header-len)
                (message-next-header)
-               (add-text-properties
-                begin (point)
-                '(invisible t message-hidden t))))))))))
+               (setq header (buffer-substring begin (point))
+                     header-len (- (point) begin))
+               (delete-region begin (point))
+               (goto-char (1+ end-of-headers))
+               (insert header)
+               (setq end-of-headers
+                     (+ end-of-headers header-len))))))))
+    (narrow-to-region (1+ end-of-headers) (point-max))))
 
 (defun message-hide-header-p (regexps)
   (let ((result nil)