-;;; message.el --- composing mail and news messages
-;; Copyright (C) 1996-2000 Free Software Foundation, Inc.
+;;; message.el --- composing mail and news messages -*- coding: iso-latin-1 -*-
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: mail, news
;;; Code:
-(eval-when-compile (require 'cl))
+(eval-when-compile
+ (require 'cl)
+ (defvar gnus-list-identifiers)) ; gnus-sum is required where necessary
(require 'mailheader)
(require 'nnheader)
-(require 'easymenu)
-(if (string-match "XEmacs\\|Lucid" emacs-version)
- (require 'mail-abbrevs)
- (require 'mailabbrev))
+;; This is apparently necessary even though things are autoloaded:
+(if (featurep 'xemacs)
+ (require 'mail-abbrevs))
(require 'mail-parse)
-(require 'mm-bodies)
-(require 'mm-encode)
(require 'mml)
(defgroup message '((user-mail-address custom-variable)
Don't touch this variable unless you really know what you're doing.
Checks include subject-cmsg multiple-headers sendsys message-id from
-long-lines control-chars size new-text redirected-followup signature
-approved sender empty empty-headers message-id from subject
-shorten-followup-to existing-newsgroups buffer-file-name unchanged
-newsgroups."
- :group 'message-news)
+long-lines control-chars size new-text quoting-style
+redirected-followup signature approved sender empty empty-headers
+message-id from subject shorten-followup-to existing-newsgroups
+buffer-file-name unchanged newsgroups."
+ :group 'message-news
+ :type '(repeat sexp))
(defcustom message-required-news-headers
'(From Newsgroups Subject Date Message-ID
:group 'message-buffers
:type 'boolean)
-(defvar gnus-local-organization)
+(eval-when-compile
+ (defvar gnus-local-organization))
(defcustom message-user-organization
(or (and (boundp 'gnus-local-organization)
(stringp gnus-local-organization)
(defcustom message-forward-as-mime t
"*If non-nil, forward messages as an inline/rfc822 MIME section. Otherwise, directly inline the old message in the forwarded message."
+ :version "21.1"
+ :group 'message-forwarding
+ :type 'boolean)
+
+(defcustom message-forward-show-mml t
+ "*If non-nil, forward messages are shown as mml. Otherwise, forward messages are unchanged."
+ :version "21.1"
:group 'message-forwarding
:type 'boolean)
:group 'message-interface
:type 'regexp)
-(defcustom message-forward-ignored-headers "Content-Transfer-Encoding"
+(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)
regexp))
:group 'message-insertion
:type 'regexp)
+(defcustom message-cite-prefix-regexp
+ ;; ?-, ?_ or ?. MUST NOT be in syntax entry w.
+ "\\([ \t]*\\(\\w\\|[-_.]\\)+>+\\|[ \t]*[]>ยป|:}+]\\)+"
+ "*Regexp matching the longest possible citation prefix on a line."
+ :group 'message-insertion
+ :type 'regexp)
+
(defcustom message-cancel-message "I am canceling my own article.\n"
"Message to be inserted in the cancel message."
:group 'message-interface
Folding `References' makes ancient versions of INN create incorrect
NOV lines.")
-(defvar gnus-post-method)
-(defvar gnus-select-method)
+(eval-when-compile
+ (defvar gnus-post-method)
+ (defvar gnus-select-method))
(defcustom message-post-method
(cond ((and (boundp 'gnus-post-method)
(listp gnus-post-method)
;;;###autoload
(defcustom message-yank-prefix "> "
- "*Prefix inserted on the lines of yanked messages."
+ "*Prefix inserted on the lines of yanked messages.
+Fix `message-cite-prefix-regexp' if it is set to an abnormal value."
:type 'string
:group 'message-insertion)
(define-widget 'message-header-lines 'text
"All header lines must be LFD terminated."
- :format "%t:%n%v"
+ :format "%{%t%}:%n%v"
:valid-regexp "^\\'"
:error "All header lines must be newline terminated")
:group 'message-sending
:type 'sexp)
-;; Ignore errors in case this is used in Emacs 19.
-;; Don't use ignore-errors because this is copied into loaddefs.el.
;;;###autoload
-(ignore-errors
- (define-mail-user-agent 'message-user-agent
- 'message-mail 'message-send-and-exit
- 'message-kill-buffer 'message-send-hook))
+(define-mail-user-agent 'message-user-agent
+ 'message-mail 'message-send-and-exit
+ 'message-kill-buffer 'message-send-hook)
(defvar message-mh-deletable-headers '(Message-ID Date Lines Sender)
"If non-nil, delete the deletable headers before feeding to mh.")
PREDICATE returns non-nil. FUNCTION is called with one parameter --
the prefix.")
-(defvar message-mail-alias-type 'abbrev
+(defcustom message-mail-alias-type 'abbrev
"*What alias expansion type to use in Message buffers.
The default is `abbrev', which uses mailabbrev. nil switches
-mail aliases off.")
+mail aliases off."
+ :group 'message
+ :link '(custom-manual "(message)Mail Aliases")
+ :type '(choice (const :tag "Use Mailabbrev" abbrev)
+ (const :tag "No expansion" nil)))
(defcustom message-auto-save-directory
- (nnheader-concat message-directory "drafts/")
+ (file-name-as-directory (nnheader-concat message-directory "drafts"))
"*Directory where Message auto-saves buffers if Gnus isn't running.
If nil, Message won't auto-save."
:group 'message-buffers
(defcustom message-buffer-naming-style 'unique
"*The way new message buffers are named.
Valid valued are `unique' and `unsent'."
+ :version "21.1"
:group 'message-buffers
:type '(choice (const :tag "unique" unique)
(const :tag "unsent" unsent)))
-(defcustom message-default-charset nil
- "Default charset used in non-MULE XEmacsen."
+(defcustom message-default-charset
+ (and (not (mm-multibyte-p)) 'iso-8859-1)
+ "Default charset used in non-MULE Emacsen.
+If nil, you might be asked to input the charset."
+ :version "21.1"
:group 'message
:type 'symbol)
-(defcustom message-dont-reply-to-names rmail-dont-reply-to-names
+(defcustom message-dont-reply-to-names
+ (and (boundp 'rmail-dont-reply-to-names) rmail-dont-reply-to-names)
"*A regexp specifying names to prune when doing wide replies.
A value of nil means exclude your own name only."
+ :version "21.1"
:group 'message
:type '(choice (const :tag "Yourself" nil)
regexp))
+(defvar message-shoot-gnksa-feet nil
+ "*A list of GNKSA feet you are allowed to shoot.
+Gnus gives you all the opportunity you could possibly want for
+shooting yourself in the foot. Also, Gnus allows you to shoot the
+feet of Good Net-Keeping Seal of Approval. The following are foot
+candidates:
+`empty-article' Allow you to post an empty article;
+`quoted-text-only' Allow you to post quoted text only;
+`multiple-copies' Allow you to post multiple copies.")
+
+(defsubst message-gnksa-enable-p (feature)
+ (or (not (listp message-shoot-gnksa-feet))
+ (memq feature message-shoot-gnksa-feet)))
+
;;; Internal variables.
;;; Well, not really internal.
(defvar message-mode-abbrev-table text-mode-abbrev-table
"Abbrev table used in Message mode buffers.
Defaults to `text-mode-abbrev-table'.")
-(defgroup message-headers nil
- "Message headers."
- :link '(custom-manual "(message)Variables")
- :group 'message)
(defface message-header-to-face
'((((class color)
:group 'message-faces)
(defvar message-font-lock-keywords
- (let* ((cite-prefix "A-Za-z")
- (cite-suffix (concat cite-prefix "0-9_.@-"))
- (content "[ \t]*\\(.+\\(\n[ \t].*\\)*\\)"))
+ (let ((content "[ \t]*\\(.+\\(\n[ \t].*\\)*\\)\n?"))
`((,(concat "^\\([Tt]o:\\)" content)
(1 'message-header-name-face)
(2 'message-header-to-face nil t))
`((,(concat "^\\(" (regexp-quote mail-header-separator) "\\)$")
1 'message-separator-face))
nil)
- (,(concat "^[ \t]*"
- "\\([" cite-prefix "]+[" cite-suffix "]*\\)?"
- "[:>|}].*")
+ (,(concat "^\\(" message-cite-prefix-regexp "\\).*")
(0 'message-cited-text-face))
- ("<#/?\\(multipart\\|part\\|external\\).*>"
+ ("<#/?\\(multipart\\|part\\|external\\|mml\\).*>"
(0 'message-mml-face))))
"Additional expressions to highlight in Message mode.")
mm-auto-save-coding-system
"Coding system to compose mail.")
+(defcustom message-send-mail-partially-limit 1000000
+ "The limitation of messages sent as message/partial.
+The lower bound of message size in characters, beyond which the message
+should be sent in several parts. If it is nil, the size is unlimited."
+ :version "21.1"
+ :group 'message-buffers
+ :type '(choice (const :tag "unlimited" nil)
+ (integer 1000000)))
+
+(defcustom message-alternative-emails nil
+ "A regexp to match the alternative email addresses.
+The first matched address (not primary one) is used in the From field."
+ :group 'message-headers
+ :type '(choice (const :tag "Always use primary" nil)
+ regexp))
+
+(defcustom message-mail-user-agent nil
+ "Like `mail-user-agent'.
+Except if it is `nil', use Gnus native MUA; if it is t, use
+`mail-user-agent'."
+ :type '(radio (const :tag "Gnus native"
+ :format "%t\n"
+ nil)
+ (const :tag "`mail-user-agent'"
+ :format "%t\n"
+ t)
+ (function-item :tag "Default Emacs mail"
+ :format "%t\n"
+ sendmail-user-agent)
+ (function-item :tag "Emacs interface to MH"
+ :format "%t\n"
+ mh-e-user-agent)
+ (function :tag "Other"))
+ :version "21.1"
+ :group 'message)
+
;;; Internal variables.
+(defvar message-sending-message "Sending...")
(defvar message-buffer-list nil)
(defvar message-this-is-news nil)
(defvar message-this-is-mail nil)
(defvar message-posting-charset nil)
;; Byte-compiler warning
-(defvar gnus-active-hashtb)
-(defvar gnus-read-active-file)
+(eval-when-compile
+ (defvar gnus-active-hashtb)
+ (defvar gnus-read-active-file))
;;; Regexp matching the delimiter of messages in UNIX mail format
;;; (UNIX From lines), minus the initial ^. It should be a copy
(User-Agent))
"Alist used for formatting headers.")
+(defvar message-options nil
+ "Some saved answers when sending message.")
+
(eval-and-compile
(autoload 'message-setup-toolbar "messagexmas")
(autoload 'mh-new-draft-name "mh-comp")
(autoload 'mh-send-letter "mh-comp")
(autoload 'gnus-point-at-eol "gnus-util")
(autoload 'gnus-point-at-bol "gnus-util")
+ (autoload 'gnus-output-to-rmail "gnus-util")
(autoload 'gnus-output-to-mail "gnus-util")
(autoload 'mail-abbrev-in-expansion-header-p "mailabbrev")
(autoload 'nndraft-request-associate-buffer "nndraft")
(autoload 'gnus-open-server "gnus-int")
(autoload 'gnus-request-post "gnus-int")
(autoload 'gnus-alive-p "gnus-util")
+ (autoload 'gnus-group-name-charset "gnus-group")
(autoload 'rmail-output "rmail"))
\f
`(delete-region (progn (beginning-of-line) (point))
(progn (forward-line ,(or n 1)) (point))))
+(defun message-unquote-tokens (elems)
+ "Remove double quotes (\") from strings in list."
+ (mapcar (lambda (item)
+ (while (string-match "^\\(.*\\)\"\\(.*\\)$" item)
+ (setq item (concat (match-string 1 item)
+ (match-string 2 item))))
+ item)
+ elems))
+
(defun message-tokenize-header (header &optional separator)
"Split HEADER into a list of header elements.
-\",\" is used as the separator."
+SEPARATOR is a string of characters to be used as separators. \",\"
+is used by default."
(if (not header)
nil
(let ((regexp (format "[%s]+" (or separator ",")))
((and (eq (char-after) ?\))
(not quoted))
(setq paren nil))))
- (nreverse elems)))))
+ (nreverse elems)))))
(defun message-mail-file-mbox-p (file)
"Say whether FILE looks like a Unix mbox file."
(when value
(while (string-match "\n[\t ]+" value)
(setq value (replace-match " " t t value)))
- ;; We remove all text props.
- (format "%s" value))))
+ (set-text-properties 0 (length value) nil value)
+ value)))
(defun message-narrow-to-field ()
"Narrow the buffer to the header on the current line."
(and (listp form) (eq (car form) 'lambda))
(byte-code-function-p form)))
+(defun message-strip-list-identifiers (subject)
+ "Remove list identifiers in `gnus-list-identifiers'."
+ (require 'gnus-sum) ; for gnus-list-identifiers
+ (let ((regexp (if (stringp gnus-list-identifiers)
+ gnus-list-identifiers
+ (mapconcat 'identity gnus-list-identifiers " *\\|"))))
+ (if (string-match (concat "\\(\\(\\(Re: +\\)?\\(" regexp
+ " *\\)\\)+\\(Re: +\\)?\\)") subject)
+ (concat (substring subject 0 (match-beginning 1))
+ (or (match-string 3 subject)
+ (match-string 5 subject))
+ (substring subject
+ (match-end 1)))
+ subject)))
+
(defun message-strip-subject-re (subject)
"Remove \"Re:\" from subject lines."
(if (string-match message-subject-re-regexp subject)
(point-max)))
(goto-char (point-min)))
-(defun message-narrow-to-head ()
- "Narrow the buffer to the head of the message.
-Point is left at the beginning of the narrowed-to region."
- (widen)
+(defun message-narrow-to-head-1 ()
+ "Like `message-narrow-to-head'. Don't widen."
(narrow-to-region
(goto-char (point-min))
(if (search-forward "\n\n" nil 1)
(point-max)))
(goto-char (point-min)))
+(defun message-narrow-to-head ()
+ "Narrow the buffer to the head of the message.
+Point is left at the beginning of the narrowed-to region."
+ (widen)
+ (message-narrow-to-head-1))
+
(defun message-narrow-to-headers-or-head ()
"Narrow the buffer to the head of the message."
(widen)
(define-key message-mode-map "\C-c\C-v" 'message-delete-not-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 "\M-q" 'message-fill-paragraph)
(define-key message-mode-map "\C-c\C-a" 'mml-attach-file)
(easy-menu-define
message-mode-menu message-mode-map "Message Menu."
- '("Message"
+ `("Message"
["Sort Headers" message-sort-headers t]
["Yank Original" message-yank-original t]
["Fill Yanked Message" message-fill-yanked-message t]
["Kill To Signature" message-kill-to-signature t]
["Newline and Reformat" message-newline-and-reformat t]
["Rename buffer" message-rename-buffer t]
- ["Spellcheck" ispell-message t]
- ["Attach file as MIME" mml-attach-file t]
+ ["Spellcheck" ispell-message
+ ,@(if (featurep 'xemacs) nil
+ '(:help "Spellcheck this message"))]
+ ["Attach file as MIME" mml-attach-file
+ ,@(if (featurep 'xemacs) nil
+ '(:help "Attach a file at point"))]
"----"
- ["Send Message" message-send-and-exit t]
- ["Abort Message" message-dont-send t]
- ["Kill Message" message-kill-buffer t]))
+ ["Send Message" message-send-and-exit
+ ,@(if (featurep 'xemacs) nil
+ '(:help "Send this message"))]
+ ["Abort Message" message-dont-send
+ ,@(if (featurep 'xemacs) nil
+ '(:help "File this draft message and exit"))]
+ ["Kill Message" message-kill-buffer
+ ,@(if (featurep 'xemacs) nil
+ '(:help "Delete this message without sending"))]))
(easy-menu-define
message-mode-field-menu message-mode-map ""
["Body" message-goto-body t]
["Signature" message-goto-signature t]))
-(defvar facemenu-add-face-function)
-(defvar facemenu-remove-face-function)
+(defvar message-tool-bar-map nil)
+
+(eval-when-compile
+ (defvar facemenu-add-face-function)
+ (defvar facemenu-remove-face-function))
;;;###autoload
(defun message-mode ()
"Major mode for editing mail and news to be sent.
Like Text Mode but with these additional commands:
C-c C-s message-send (send the message) C-c C-c message-send-and-exit
-C-c C-d Pospone sending the message C-c C-k Kill the message
+C-c C-d Postpone sending the message C-c C-k Kill the message
C-c C-f move to a header field (and create it if there isn't):
C-c C-f C-t move to To C-c C-f C-s move to Subject
C-c C-f C-c move to Cc C-c C-f C-b move to Bcc
C-c C-a mml-attach-file (attach a file as MIME).
M-RET message-newline-and-reformat (break the line and reformat)."
(interactive)
+ (if (local-variable-p 'mml-buffer-list (current-buffer))
+ (mml-destroy-buffers))
(kill-all-local-variables)
(set (make-local-variable 'message-reply-buffer) nil)
(make-local-variable 'message-send-actions)
(error "Face %s not configured for %s mode" face mode-name)))
"")
facemenu-remove-face-function t)
- (make-local-variable 'paragraph-separate)
- (make-local-variable 'paragraph-start)
- ;; `-- ' precedes the signature. `-----' appears at the start of the
- ;; lines that delimit forwarded messages.
- ;; Lines containing just >= 3 dashes, perhaps after whitespace,
- ;; are also sometimes used and should be separators.
- (setq paragraph-start
- (concat (regexp-quote mail-header-separator)
- "$\\|[ \t]*[a-z0-9A-Z]*>+[ \t]*$\\|[ \t]*$\\|"
- "-- $\\|---+$\\|"
- page-delimiter
- ;;!!! Uhm... shurely this can't be right?
- "[> " (regexp-quote message-yank-prefix) "]+$"))
- (setq paragraph-separate paragraph-start)
(make-local-variable 'message-reply-headers)
(setq message-reply-headers nil)
(make-local-variable 'message-newsreader)
(set (make-local-variable 'message-sent-message-via) nil)
(set (make-local-variable 'message-checksum) nil)
(set (make-local-variable 'message-mime-part) 0)
+ (message-setup-fill-variables)
+ ;; Allow using comment commands to add/remove quoting.
+ (set (make-local-variable 'comment-start) message-yank-prefix)
;;(when (fboundp 'mail-hist-define-keys)
;; (mail-hist-define-keys))
- (when (string-match "XEmacs\\|Lucid" emacs-version)
- (message-setup-toolbar))
+ (if (featurep 'xemacs)
+ (message-setup-toolbar)
+ (set (make-local-variable 'font-lock-defaults)
+ '(message-font-lock-keywords t))
+ (if (boundp 'tool-bar-map)
+ (set (make-local-variable 'tool-bar-map) (message-tool-bar-map))))
(easy-menu-add message-mode-menu message-mode-map)
(easy-menu-add message-mode-field-menu message-mode-map)
;; Allow mail alias things.
(mail-abbrevs-setup)
(mail-aliases-setup)))
(message-set-auto-save-file-name)
- (unless (string-match "XEmacs" emacs-version)
- (set (make-local-variable 'font-lock-defaults)
- '(message-font-lock-keywords t)))
- (make-local-variable 'adaptive-fill-regexp)
- (setq adaptive-fill-regexp
- (concat "[ \t]*[-a-z0-9A-Z]*\\(>[ \t]*\\)+[ \t]*\\|" adaptive-fill-regexp))
- (unless (boundp 'adaptive-fill-first-line-regexp)
- (setq adaptive-fill-first-line-regexp nil))
- (make-local-variable 'adaptive-fill-first-line-regexp)
- (setq adaptive-fill-first-line-regexp
- (concat "[ \t]*[-a-z0-9A-Z]*\\(>[ \t]*\\)+[ \t]*\\|"
- adaptive-fill-first-line-regexp))
- (make-local-variable 'auto-fill-inhibit-regexp)
- (setq auto-fill-inhibit-regexp "^[A-Z][^: \n\t]+:")
(mm-enable-multibyte)
(make-local-variable 'indent-tabs-mode) ;Turn off tabs for indentation.
(setq indent-tabs-mode nil)
(mml-mode)
(run-hooks 'text-mode-hook 'message-mode-hook))
+(defun message-setup-fill-variables ()
+ "Setup message fill variables."
+ (make-local-variable 'paragraph-separate)
+ (make-local-variable 'paragraph-start)
+ (make-local-variable 'adaptive-fill-regexp)
+ (unless (boundp 'adaptive-fill-first-line-regexp)
+ (setq adaptive-fill-first-line-regexp nil))
+ (make-local-variable 'adaptive-fill-first-line-regexp)
+ (make-local-variable 'auto-fill-inhibit-regexp)
+ (let ((quote-prefix-regexp
+ ;; User should change message-cite-prefix-regexp if
+ ;; message-yank-prefix is set to an abnormal value.
+ (concat "\\(" message-cite-prefix-regexp "\\)[ \t]*")))
+ (setq paragraph-start
+ (concat
+ (regexp-quote mail-header-separator) "$\\|"
+ "[ \t]*$\\|" ; blank lines
+ "-- $\\|" ; signature delimiter
+ "---+$\\|" ; delimiters for forwarded messages
+ page-delimiter "$\\|" ; spoiler warnings
+ ".*wrote:$\\|" ; attribution lines
+ quote-prefix-regexp "$")) ; empty lines in quoted text
+ (setq paragraph-separate paragraph-start)
+ (setq adaptive-fill-regexp
+ (concat quote-prefix-regexp "\\|" adaptive-fill-regexp))
+ (setq adaptive-fill-first-line-regexp
+ (concat quote-prefix-regexp "\\|"
+ adaptive-fill-first-line-regexp))
+ (setq auto-fill-inhibit-regexp "^[A-Z][^: \n\t]+:")))
+
\f
;;;
(mail-fetch-field "to")
(not (string-match "\\` *\\'" (mail-fetch-field "to"))))
(insert ", "))
- (insert (or (message-fetch-reply-field "reply-to")
+ (insert (or (message-fetch-reply-field "mail-reply-to")
+ (message-fetch-reply-field "reply-to")
(message-fetch-reply-field "from") "")))
(defun message-widen-reply ()
(unless (bolp)
(insert "\n"))))
-(defun message-newline-and-reformat ()
+(defun message-newline-and-reformat (&optional not-break)
"Insert four newlines, and then reformat if inside quoted text."
(interactive)
- (let ((prefix "[]>ยป|:}+ \t]*")
- (supercite-thing "[-._a-zA-Z0-9]*[>]+[ \t]*")
- quoted point)
- (unless (bolp)
- (save-excursion
- (beginning-of-line)
- (when (looking-at (concat prefix
- supercite-thing))
- (setq quoted (match-string 0))))
- (insert "\n"))
+ (let (quoted point beg end leading-space)
(setq point (point))
- (insert "\n\n\n")
- (delete-region (point) (re-search-forward "[ \t]*"))
- (when quoted
- (insert quoted))
- (fill-paragraph nil)
+ (beginning-of-line)
+ (setq beg (point))
+ ;; Find first line of the paragraph.
+ (if not-break
+ (while (and (not (eobp))
+ (not (looking-at message-cite-prefix-regexp))
+ (looking-at paragraph-start))
+ (forward-line 1)))
+ ;; Find the prefix
+ (when (looking-at message-cite-prefix-regexp)
+ (setq quoted (match-string 0))
+ (goto-char (match-end 0))
+ (looking-at "[ \t]*")
+ (setq leading-space (match-string 0)))
+ (if (and quoted
+ (not not-break)
+ (< (- point beg) (length quoted)))
+ ;; break in the cite prefix.
+ (setq quoted nil
+ end nil))
+ (if quoted
+ (progn
+ (forward-line 1)
+ (while (and (not (eobp))
+ (not (looking-at paragraph-separate))
+ (looking-at message-cite-prefix-regexp)
+ (equal quoted (match-string 0)))
+ (goto-char (match-end 0))
+ (looking-at "[ \t]*")
+ (if (> (length leading-space) (length (match-string 0)))
+ (setq leading-space (match-string 0)))
+ (forward-line 1))
+ (setq end (point))
+ (goto-char beg)
+ (while (and (if (bobp) nil (forward-line -1) t)
+ (not (looking-at paragraph-start))
+ (looking-at message-cite-prefix-regexp)
+ (equal quoted (match-string 0)))
+ (setq beg (point))
+ (goto-char (match-end 0))
+ (looking-at "[ \t]*")
+ (if (> (length leading-space) (length (match-string 0)))
+ (setq leading-space (match-string 0)))))
+ (while (and (not (eobp))
+ (not (looking-at paragraph-separate))
+ (not (looking-at message-cite-prefix-regexp)))
+ (forward-line 1))
+ (setq end (point))
+ (goto-char beg)
+ (while (and (if (bobp) nil (forward-line -1) t)
+ (not (looking-at paragraph-start))
+ (not (looking-at message-cite-prefix-regexp)))
+ (setq beg (point))))
(goto-char point)
- (forward-line 1)))
+ (save-restriction
+ (narrow-to-region beg end)
+ (if not-break
+ (setq point nil)
+ (insert "\n\n")
+ (setq point (point))
+ (insert "\n\n")
+ (delete-region (point) (re-search-forward "[ \t]*"))
+ (when quoted
+ (insert quoted leading-space)))
+ (if quoted
+ (let* ((adaptive-fill-regexp
+ (regexp-quote (concat quoted leading-space)))
+ (adaptive-fill-first-line-regexp
+ adaptive-fill-regexp ))
+ (fill-paragraph nil))
+ (fill-paragraph nil))
+ (if point (goto-char point)))))
+
+(defun message-fill-paragraph ()
+ "Like `fill-paragraph'."
+ (interactive)
+ (message-newline-and-reformat t))
(defun message-insert-signature (&optional force)
"Insert a signature. See documentation for the `message-signature' variable."
(insert "\n"))
(funcall message-citation-line-function))))
-(defvar mail-citation-hook) ;Compiler directive
+(eval-when-compile (defvar mail-citation-hook)) ;Compiler directive
(defun message-cite-original ()
"Cite function in the standard Message manner."
(if (and (boundp 'mail-citation-hook)
(put-text-property (point-min) (point-max) 'read-only nil))
(message-fix-before-sending)
(run-hooks 'message-send-hook)
- (message "Sending...")
+ (message message-sending-message)
(let ((alist message-send-method-alist)
(success t)
- elem sent)
+ elem sent
+ (message-options message-options))
+ (message-options-set-recipient)
(while (and success
(setq elem (pop alist)))
- (when (or (not (funcall (cadr elem)))
- (and (or (not (memq (car elem)
- message-sent-message-via))
- (y-or-n-p
- (format
- "Already sent message via %s; resend? "
- (car elem))))
- (setq success (funcall (caddr elem) arg))))
- (setq sent t)))
+ (when (funcall (cadr elem))
+ (when (and (or (not (memq (car elem)
+ message-sent-message-via))
+ (if (or (message-gnksa-enable-p 'multiple-copies)
+ (not (eq (car elem) 'news)))
+ (y-or-n-p
+ (format
+ "Already sent message via %s; resend? "
+ (car elem)))
+ (error "Denied posting -- multiple copies.")))
+ (setq success (funcall (caddr elem) arg)))
+ (setq sent t))))
(unless (or sent (not success))
(error "No methods specified to send by"))
(when (and success sent)
(eval (car actions)))))
(pop actions)))
+(defun message-send-mail-partially ()
+ "Sendmail as message/partial."
+ ;; replace the header delimiter with a blank line
+ (goto-char (point-min))
+ (re-search-forward
+ (concat "^" (regexp-quote mail-header-separator) "\n"))
+ (replace-match "\n")
+ (run-hooks 'message-send-mail-hook)
+ (let ((p (goto-char (point-min)))
+ (tembuf (message-generate-new-buffer-clone-locals " message temp"))
+ (curbuf (current-buffer))
+ (id (message-make-message-id)) (n 1)
+ plist total header required-mail-headers)
+ (while (not (eobp))
+ (if (< (point-max) (+ p message-send-mail-partially-limit))
+ (goto-char (point-max))
+ (goto-char (+ p message-send-mail-partially-limit))
+ (beginning-of-line)
+ (if (<= (point) p) (forward-line 1))) ;; In case of bad message.
+ (push p plist)
+ (setq p (point)))
+ (setq total (length plist))
+ (push (point-max) plist)
+ (setq plist (nreverse plist))
+ (unwind-protect
+ (save-excursion
+ (setq p (pop plist))
+ (while plist
+ (set-buffer curbuf)
+ (copy-to-buffer tembuf p (car plist))
+ (set-buffer tembuf)
+ (goto-char (point-min))
+ (if header
+ (progn
+ (goto-char (point-min))
+ (narrow-to-region (point) (point))
+ (insert header))
+ (message-goto-eoh)
+ (setq header (buffer-substring (point-min) (point)))
+ (goto-char (point-min))
+ (narrow-to-region (point) (point))
+ (insert header)
+ (message-remove-header "Mime-Version")
+ (message-remove-header "Content-Type")
+ (message-remove-header "Content-Transfer-Encoding")
+ (message-remove-header "Message-ID")
+ (message-remove-header "Lines")
+ (goto-char (point-max))
+ (insert "Mime-Version: 1.0\n")
+ (setq header (buffer-substring (point-min) (point-max))))
+ (goto-char (point-max))
+ (insert (format "Content-Type: message/partial; id=\"%s\"; number=%d; total=%d\n"
+ id n total))
+ (let ((mail-header-separator ""))
+ (when (memq 'Message-ID message-required-mail-headers)
+ (insert "Message-ID: " (message-make-message-id) "\n"))
+ (when (memq 'Lines message-required-mail-headers)
+ (let ((mail-header-separator ""))
+ (insert "Lines: " (message-make-lines) "\n")))
+ (message-goto-subject)
+ (end-of-line)
+ (insert (format " (%d/%d)" n total))
+ (goto-char (point-max))
+ (insert "\n")
+ (widen)
+ (mm-with-unibyte-current-buffer
+ (funcall message-send-mail-function)))
+ (setq n (+ n 1))
+ (setq p (pop plist))
+ (erase-buffer)))
+ (kill-buffer tembuf))))
+
(defun message-send-mail (&optional arg)
(require 'mail-utils)
(let* ((tembuf (message-generate-new-buffer-clone-locals " message temp"))
(set-buffer tembuf)
(erase-buffer)
;; Avoid copying text props.
- (insert (format
- "%s" (save-excursion
- (set-buffer mailbuf)
- (buffer-string))))
+ (insert (with-current-buffer mailbuf
+ (buffer-substring-no-properties (point-min) (point-max))))
;; Remove some headers.
(message-encode-message-body)
(save-restriction
(message-generate-headers '(Lines)))
;; Remove some headers.
(message-remove-header message-ignored-mail-headers t)
- (mail-encode-encoded-word-buffer))
+ (let ((mail-parse-charset message-default-charset))
+ (mail-encode-encoded-word-buffer)))
(goto-char (point-max))
;; require one newline at the end.
(or (= (preceding-char) ?\n)
(insert ?\n))
- (when (and news
+ (when
+ (save-restriction
+ (message-narrow-to-headers)
+ (and news
(or (message-fetch-field "cc")
- (message-fetch-field "to")))
+ (message-fetch-field "to"))
+ (string= "text/plain"
+ (car
+ (mail-header-parse-content-type
+ (message-fetch-field "content-type"))))))
(message-insert-courtesy-copy))
- (funcall message-send-mail-function))
+ (if (or (not message-send-mail-partially-limit)
+ (< (point-max) message-send-mail-partially-limit)
+ (not (y-or-n-p "The message size is too large, should it be sent partially?")))
+ (mm-with-unibyte-current-buffer
+ (funcall message-send-mail-function))
+ (message-send-mail-partially)))
(kill-buffer tembuf))
(set-buffer mailbuf)
(push 'mail message-sent-message-via)))
(method (if (message-functionp message-post-method)
(funcall message-post-method arg)
message-post-method))
+ (group-name-charset (gnus-group-name-charset method ""))
+ (rfc2047-header-encoding-alist
+ (if group-name-charset
+ (cons (cons "Newsgroups" group-name-charset)
+ rfc2047-header-encoding-alist)
+ rfc2047-header-encoding-alist))
(messbuf (current-buffer))
(message-syntax-checks
(if arg
message-syntax-checks))
(message-this-is-news t)
(message-posting-charset (gnus-setup-posting-charset
- (message-fetch-field "Newsgroups")))
+ (save-restriction
+ (message-narrow-to-headers-or-head)
+ (message-fetch-field "Newsgroups"))))
result)
(if (not (message-check-news-body-syntax))
nil
(message-generate-headers message-required-news-headers)
;; Let the user do all of the above.
(run-hooks 'message-header-hook))
+ (if group-name-charset
+ (setq message-syntax-checks
+ (cons '(valid-newsgroups . disabled)
+ message-syntax-checks)))
(message-cleanup-headers)
(if (not (message-check-news-syntax))
nil
(buffer-disable-undo)
(erase-buffer)
;; Avoid copying text props.
- (insert (format
- "%s" (save-excursion
- (set-buffer messbuf)
- (buffer-string))))
+ (insert (with-current-buffer messbuf
+ (buffer-substring-no-properties
+ (point-min) (point-max))))
(message-encode-message-body)
;; Remove some headers.
(save-restriction
(message-generate-headers '(Lines)))
;; Remove some headers.
(message-remove-header message-ignored-news-headers t)
- (let ((mail-parse-charset (car message-posting-charset)))
+ (let ((mail-parse-charset message-default-charset))
(mail-encode-encoded-word-buffer)))
(goto-char (point-max))
;; require one newline at the end.
(re-search-backward message-signature-separator nil t)
(beginning-of-line)
(or (re-search-backward "[^ \n\t]" b t)
- (y-or-n-p "Empty article. Really post? "))))
+ (if (message-gnksa-enable-p 'empty-article)
+ (y-or-n-p "Empty article. Really post? ")
+ (message "Denied posting -- Empty article.")
+ nil))))
;; Check for control characters.
(message-check 'control-chars
(if (re-search-forward "[\000-\007\013\015-\032\034-\037\200-\237]" nil t)
(or
(not message-checksum)
(not (eq (message-checksum) message-checksum))
- (y-or-n-p
- "It looks like no new text has been added. Really post? ")))
+ (if (message-gnksa-enable-p 'quoted-text-only)
+ (y-or-n-p
+ "It looks like no new text has been added. Really post? ")
+ (message "Denied posting -- no new text has been added.")
+ nil)))
;; Check the length of the signature.
(message-check 'signature
(goto-char (point-max))
(format
"Your .sig is %d lines; it should be max 4. Really post? "
(1- (count-lines (point) (point-max)))))
- t))))
+ t))
+ ;; Ensure that text follows last quoted portion.
+ (message-check 'quoting-style
+ (goto-char (point-max))
+ (let ((no-problem t))
+ (when (search-backward-regexp "^>[^\n]*\n" nil t)
+ (setq no-problem (search-forward-regexp "^[ \t]*[^>\n]" nil t)))
+ (if no-problem
+ t
+ (if (message-gnksa-enable-p 'quoted-text-only)
+ (y-or-n-p "Your text should follow quoted text. Really post? ")
+ ;; Ensure that
+ (goto-char (point-min))
+ (re-search-forward
+ (concat "^" (regexp-quote mail-header-separator) "$"))
+ (if (search-forward-regexp "^[ \t]*[^>\n]" nil t)
+ (y-or-n-p "Your text should follow quoted text. Really post? ")
+ (message "Denied posting -- only quoted text.")
+ nil)))))))
(defun message-checksum ()
"Return a \"checksum\" for the current buffer."
(while (setq file (message-fetch-field "fcc"))
(push file list)
(message-remove-header "fcc" nil t)))
+ (message-encode-message-body)
+ (save-restriction
+ (message-narrow-to-headers)
+ (let ((mail-parse-charset message-default-charset)
+ (rfc2047-header-encoding-alist
+ (cons '("Newsgroups" . default)
+ rfc2047-header-encoding-alist)))
+ (mail-encode-encoded-word-buffer)))
(goto-char (point-min))
- (re-search-forward (concat "^" (regexp-quote mail-header-separator) "$"))
- (replace-match "" t t)
+ (when (re-search-forward
+ (concat "^" (regexp-quote mail-header-separator) "$")
+ nil t)
+ (replace-match "" t t ))
;; Process FCC operations.
(while list
(setq file (pop list))
(rmail-output file 1 nil t)
(let ((mail-use-rfc822 t))
(rmail-output file 1 t t))))))
-
(kill-buffer (current-buffer)))))
(defun message-output (filename)
"Append this article to Unix/babyl mail file.."
(if (and (file-readable-p filename)
(mail-file-babyl-p filename))
- (rmail-output-to-rmail-file filename t)
+ (gnus-output-to-rmail filename t)
(gnus-output-to-mail filename t)))
(defun message-cleanup-headers ()
(mail-header-references message-reply-headers)
(mail-header-subject message-reply-headers)
psubject
- (mail-header-subject message-reply-headers)
(not (string=
(message-strip-subject-re
(mail-header-subject message-reply-headers))
(defun message-make-in-reply-to ()
"Return the In-Reply-To header for this message."
(when message-reply-headers
- (let ((from (mail-header-from message-reply-headers))
- (date (mail-header-date message-reply-headers)))
- (when from
- (let ((stop-pos
- (string-match " *at \\| *@ \\| *(\\| *<" from)))
- (concat (if (and stop-pos
- (not (zerop stop-pos)))
- (substring from 0 stop-pos) from)
- "'s message of \""
- (if (or (not date) (string= date ""))
- "(unknown date)" date)
- "\""))))))
+ (mail-header-message-id message-reply-headers)))
(defun message-make-distribution ()
"Make a Distribution header."
(setq message-buffer-list
(nconc message-buffer-list (list (current-buffer))))))
-(defvar mc-modes-alist)
-(defun message-setup (headers &optional replybuffer actions)
- (when (and (boundp 'mc-modes-alist)
- (not (assq 'message-mode mc-modes-alist)))
- (push '(message-mode (encrypt . mc-encrypt-message)
- (sign . mc-sign-message))
- mc-modes-alist))
+(defun message-mail-user-agent ()
+ (let ((mua (cond
+ ((not message-mail-user-agent) nil)
+ ((eq message-mail-user-agent t) mail-user-agent)
+ (t message-mail-user-agent))))
+ (if (memq mua '(message-user-agent gnus-user-agent))
+ nil
+ mua)))
+
+(defun message-setup (headers &optional replybuffer actions switch-function)
+ (let ((mua (message-mail-user-agent))
+ subject to field yank-action)
+ (if (not (and message-this-is-mail mua))
+ (message-setup-1 headers replybuffer actions)
+ (if replybuffer
+ (setq yank-action (list 'insert-buffer replybuffer)))
+ (setq headers (copy-sequence headers))
+ (setq field (assq 'Subject headers))
+ (when field
+ (setq subject (cdr field))
+ (setq headers (delq field headers)))
+ (setq field (assq 'To headers))
+ (when field
+ (setq to (cdr field))
+ (setq headers (delq field headers)))
+ (let ((mail-user-agent mua))
+ (compose-mail to subject
+ (mapcar (lambda (item)
+ (cons
+ (format "%s" (car item))
+ (cdr item)))
+ headers)
+ nil switch-function yank-action actions)))))
+
+;;;(defvar mc-modes-alist)
+(defun message-setup-1 (headers &optional replybuffer actions)
+;;; (when (and (boundp 'mc-modes-alist)
+;;; (not (assq 'message-mode mc-modes-alist)))
+;;; (push '(message-mode (encrypt . mc-encrypt-message)
+;;; (sign . mc-sign-message))
+;;; mc-modes-alist))
(when actions
(setq message-send-actions actions))
(setq message-reply-buffer replybuffer)
(message-insert-signature)
(save-restriction
(message-narrow-to-headers)
+ (if message-alternative-emails
+ (message-use-alternative-email-as-from))
(run-hooks 'message-header-setup-hook))
(set-buffer-modified-p nil)
(setq buffer-undo-list nil)
(defun message-set-auto-save-file-name ()
"Associate the message buffer with a file in the drafts directory."
(when message-auto-save-directory
+ (unless (file-directory-p
+ (directory-file-name message-auto-save-directory))
+ (gnus-make-directory message-auto-save-directory))
(if (gnus-alive-p)
(setq message-draft-article
(nndraft-request-associate-buffer "drafts"))
OTHER-HEADERS is an alist of header/value pairs."
(interactive)
(let ((message-this-is-mail t))
- (message-pop-to-buffer (message-buffer-name "mail" to))
+ (unless (message-mail-user-agent)
+ (message-pop-to-buffer (message-buffer-name "mail" to)))
(message-setup
(nconc
`((To . ,(or to "")) (Subject . ,(or subject "")))
(Subject . ,(or subject ""))))))
(defun message-get-reply-headers (wide &optional to-address)
- (let (follow-to mct never-mct from to cc reply-to)
+ (let (follow-to mct never-mct from to cc reply-to mrt mft ccalist)
;; Find all relevant headers we need.
(setq from (message-fetch-field "from")
to (message-fetch-field "to")
cc (message-fetch-field "cc")
mct (message-fetch-field "mail-copies-to")
- reply-to (message-fetch-field "reply-to"))
+ reply-to (message-fetch-field "reply-to")
+ mrt (message-fetch-field "mail-reply-to")
+ mft (message-fetch-field "mail-followup-to"))
;; Handle special values of Mail-Copies-To.
(when mct
(setq mct nil))
((or (equal (downcase mct) "always")
(equal (downcase mct) "poster"))
- (setq mct (or reply-to from)))))
-
- (message-set-work-buffer)
- (unless never-mct
- (insert (or reply-to from "")))
- (insert (if to (concat (if (bolp) "" ", ") to "") ""))
- (insert (if mct (concat (if (bolp) "" ", ") mct) ""))
- (insert (if cc (concat (if (bolp) "" ", ") cc) ""))
- (goto-char (point-min))
- (while (re-search-forward "[ \t]+" nil t)
- (replace-match " " t t))
- ;; Remove addresses that match `rmail-dont-reply-to-names'.
- (let ((rmail-dont-reply-to-names message-dont-reply-to-names))
- (insert (prog1 (rmail-dont-reply-to (buffer-string))
- (erase-buffer))))
- (goto-char (point-min))
- ;; Perhaps "Mail-Copies-To: never" removed the only address?
- (when (eobp)
- (insert (or reply-to from "")))
- (setq ccalist
- (mapcar
- (lambda (addr)
- (cons (mail-strip-quoted-names addr) addr))
- (message-tokenize-header (buffer-string))))
- (let ((s ccalist))
- (while s
- (setq ccalist (delq (assoc (car (pop s)) s) ccalist))))
- (setq follow-to (list (cons 'To (cdr (pop ccalist)))))
- (when ccalist
- (let ((ccs (cons 'Cc (mapconcat
- (lambda (addr) (cdr addr)) ccalist ", "))))
- (when (string-match "^ +" (cdr ccs))
- (setcdr ccs (substring (cdr ccs) (match-end 0))))
- (push ccs follow-to)))))
+ (setq mct (or mrt reply-to from)))))
+
+ (if (or (not wide)
+ to-address)
+ (progn
+ (setq follow-to (list (cons 'To (or to-address mrt reply-to from))))
+ (when (and wide (or mft mct))
+ (push (cons 'Cc (or mft mct)) follow-to)))
+ (let (ccalist)
+ (save-excursion
+ (message-set-work-buffer)
+ (if (and mft
+ message-use-followup-to
+ (or (not (eq message-use-followup-to 'ask))
+ (message-y-or-n-p
+ (concat "Obey Mail-Followup-To? ") t "\
+You should normally obey the Mail-Followup-To: header. In this
+article, it has the value of
+
+" mft "
+
+which directs your response to " (if (string-match "," mft)
+ "the specified addresses"
+ "that address only") ".
+
+If a message is posted to several mailing lists, Mail-Followup-To is
+often used to direct the following discussion to one list only,
+because discussions that are spread over several lists tend to be
+fragmented and very difficult to follow.
+
+Also, some source/announcement lists are not indented for discussion;
+responses here are directed to other addresses.")))
+ (insert mft)
+ (unless never-mct
+ (insert (or mrt reply-to from "")))
+ (insert (if to (concat (if (bolp) "" ", ") to "") ""))
+ (insert (if mct (concat (if (bolp) "" ", ") mct) ""))
+ (insert (if cc (concat (if (bolp) "" ", ") cc) "")))
+ (goto-char (point-min))
+ (while (re-search-forward "[ \t]+" nil t)
+ (replace-match " " t t))
+ ;; Remove addresses that match `rmail-dont-reply-to-names'.
+ (let ((rmail-dont-reply-to-names message-dont-reply-to-names))
+ (insert (prog1 (rmail-dont-reply-to (buffer-string))
+ (erase-buffer))))
+ (goto-char (point-min))
+ ;; Perhaps "Mail-Copies-To: never" removed the only address?
+ (when (eobp)
+ (insert (or mrt reply-to from "")))
+ (setq ccalist
+ (mapcar
+ (lambda (addr)
+ (cons (mail-strip-quoted-names addr) addr))
+ (message-tokenize-header (buffer-string))))
+ (let ((s ccalist))
+ (while s
+ (setq ccalist (delq (assoc (car (pop s)) s) ccalist)))))
+ (setq follow-to (list (cons 'To (cdr (pop ccalist)))))
+ (when ccalist
+ (let ((ccs (cons 'Cc (mapconcat
+ (lambda (addr) (cdr addr)) ccalist ", "))))
+ (when (string-match "^ +" (cdr ccs))
+ (setcdr ccs (substring (cdr ccs) (match-end 0))))
+ (push ccs follow-to)))))
+ follow-to))
;;;###autoload
(defun message-reply (&optional to-address wide)
"Start editing a reply to the article in the current buffer."
(interactive)
+ (require 'gnus-sum) ; for gnus-list-identifiers
(let ((cur (current-buffer))
from subject date reply-to to cc
references message-id follow-to
(message-this-is-mail t)
gnus-warning)
(save-restriction
- (message-narrow-to-head)
+ (message-narrow-to-head-1)
;; Allow customizations to have their say.
(if (not wide)
;; This is a regular reply.
date (message-fetch-field "date")
from (message-fetch-field "from")
subject (or (message-fetch-field "subject") "none"))
- ;; Remove any (buggy) Re:'s that are present and make a
- ;; proper one.
- (when (string-match message-subject-re-regexp subject)
- (setq subject (substring subject (match-end 0))))
- (setq subject (concat "Re: " subject))
+ (if gnus-list-identifiers
+ (setq subject (message-strip-list-identifiers subject)))
+ (setq subject (concat "Re: " (message-strip-subject-re subject)))
(when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
(string-match "<[^>]+>" gnus-warning))
(unless follow-to
(setq follow-to (message-get-reply-headers wide to-address))))
- (message-pop-to-buffer
- (message-buffer-name
- (if wide "wide reply" "reply") from
- (if wide to-address nil)))
+ (unless (message-mail-user-agent)
+ (message-pop-to-buffer
+ (message-buffer-name
+ (if wide "wide reply" "reply") from
+ (if wide to-address nil))))
(setq message-reply-headers
(vector 0 subject from date message-id references 0 0 ""))
"Follow up to the message in the current buffer.
If TO-NEWSGROUPS, use that as the new Newsgroups line."
(interactive)
+ (require 'gnus-sum) ; for gnus-list-identifiers
(let ((cur (current-buffer))
- from subject date reply-to mct
+ from subject date reply-to mrt mct
references message-id follow-to
(inhibit-point-motion-hooks t)
(message-this-is-news t)
newsgroups (message-fetch-field "newsgroups")
posted-to (message-fetch-field "posted-to")
reply-to (message-fetch-field "reply-to")
+ mrt (message-fetch-field "mail-reply-to")
distribution (message-fetch-field "distribution")
mct (message-fetch-field "mail-copies-to"))
(when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
(let ((case-fold-search t))
(string-match "world" distribution)))
(setq distribution nil))
- ;; Remove any (buggy) Re:'s that are present and make a
- ;; proper one.
- (when (string-match message-subject-re-regexp subject)
- (setq subject (substring subject (match-end 0))))
- (setq subject (concat "Re: " subject))
+ (if gnus-list-identifiers
+ (setq subject (message-strip-list-identifiers subject)))
+ (setq subject (concat "Re: " (message-strip-subject-re subject)))
(widen))
(message-pop-to-buffer (message-buffer-name "followup" from newsgroups))
does not read the newsgroup, so he wouldn't see any replies sent to it."))
(progn
(setq message-this-is-news nil)
- (cons 'To (or reply-to from "")))
+ (cons 'To (or mrt reply-to from "")))
(cons 'Newsgroups newsgroups)))
(t
(if (or (equal followup-to newsgroups)
(equal (downcase mct) "nobody"))))
(list (cons 'Cc (if (or (equal (downcase mct) "always")
(equal (downcase mct) "poster"))
- (or reply-to from "")
+ (or mrt reply-to from "")
mct)))))
cur)
(save-excursion
;; Get header info from original article.
(save-restriction
- (message-narrow-to-head)
+ (message-narrow-to-head-1)
(setq from (message-fetch-field "from")
sender (message-fetch-field "sender")
newsgroups (message-fetch-field "newsgroups")
(setq buf (set-buffer (get-buffer-create " *message cancel*"))))
(erase-buffer)
(insert "Newsgroups: " newsgroups "\n"
- "From: " (message-make-from) "\n"
+ "From: " from "\n"
"Subject: cmsg cancel " message-id "\n"
"Control: cancel " message-id "\n"
(if distribution
;; Get a normal message buffer.
(message-pop-to-buffer (message-buffer-name "supersede"))
(insert-buffer-substring cur)
- (message-narrow-to-head)
+ (mime-to-mml)
+ (message-narrow-to-head-1)
;; Remove unwanted headers.
(when message-ignored-supersedes-headers
(message-remove-header message-ignored-supersedes-headers t))
"Return a Subject header suitable for the message in the current buffer."
(save-excursion
(save-restriction
- (current-buffer)
- (message-narrow-to-head)
+ (message-narrow-to-head-1)
(let ((funcs message-make-forward-subject-function)
- (subject (if message-wash-forwarded-subjects
- (message-wash-subject
- (or (message-fetch-field "Subject") ""))
- (or (message-fetch-field "Subject") ""))))
+ (subject (message-fetch-field "Subject")))
+ (setq subject
+ (if subject
+ (mail-decode-encoded-word-string subject)
+ ""))
+ (if message-wash-forwarded-subjects
+ (setq subject (message-wash-subject subject)))
;; Make sure funcs is a list.
(and funcs
(not (listp funcs))
subject))))
;;;###autoload
-(defun message-forward (&optional news)
+(defun message-forward (&optional news digest)
"Forward the current message via mail.
-Optional NEWS will use news to forward instead of mail."
+Optional NEWS will use news to forward instead of mail.
+Optional DIGEST will use digest to forward."
(interactive "P")
- (let ((cur (current-buffer))
- (subject (message-make-forward-subject))
- art-beg)
+ (let* ((cur (current-buffer))
+ (subject (message-make-forward-subject))
+ art-beg)
(if news
(message-news nil subject)
(message-mail nil subject))
(message-goto-body)
(goto-char (point-max)))
(if message-forward-as-mime
- (insert "\n\n<#part type=message/rfc822 disposition=inline>\n")
+ (if digest
+ (insert "\n<#multipart type=digest>\n")
+ (if message-forward-show-mml
+ (insert "\n\n<#mml type=message/rfc822 disposition=inline>\n")
+ (insert "\n\n<#part type=message/rfc822 disposition=inline raw=t>\n")))
(insert "\n-------------------- Start of forwarded message --------------------\n"))
- (let ((b (point))
- e)
- (mml-insert-buffer cur)
+ (let ((b (point)) e)
+ (if digest
+ (if message-forward-as-mime
+ (insert-buffer-substring cur)
+ (mml-insert-buffer cur))
+ (if message-forward-show-mml
+ (let ((target (current-buffer)) tmp)
+ (with-temp-buffer
+ (mm-disable-multibyte) ;; Must copy buffer in unibyte mode
+ (setq tmp (current-buffer))
+ (set-buffer cur)
+ (mm-with-unibyte-current-buffer
+ (set-buffer tmp)
+ (insert-buffer-substring cur)
+ (set-buffer cur))
+ (set-buffer tmp)
+ (mm-enable-multibyte)
+ (mime-to-mml)
+ (goto-char (point-min))
+ (when (looking-at "From ")
+ (replace-match "X-From-Line: "))
+ (set-buffer target)
+ (insert-buffer-substring tmp)
+ (set-buffer tmp)))
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (mml-insert-buffer cur)
+ (goto-char (point-min))
+ (when (looking-at "From ")
+ (replace-match "X-From-Line: "))
+ (goto-char (point-max)))))
(setq e (point))
(if message-forward-as-mime
- (insert "<#/part>\n")
+ (if digest
+ (insert "<#/multipart>\n")
+ (if message-forward-show-mml
+ (insert "<#/mml>\n")
+ (insert "<#/part>\n")))
(insert "\n-------------------- End of forwarded message --------------------\n"))
- (when (and (not current-prefix-arg)
- message-forward-ignored-headers)
- (save-restriction
- (narrow-to-region b e)
- (goto-char b)
- (narrow-to-region (point) (or (search-forward "\n\n" nil t) (point)))
- (message-remove-header message-forward-ignored-headers t))))
+ (if (and digest message-forward-as-mime)
+ (save-restriction
+ (narrow-to-region b e)
+ (goto-char b)
+ (narrow-to-region (point)
+ (or (search-forward "\n\n" nil t) (point)))
+ (delete-region (point-min) (point-max)))
+ (when (and (not current-prefix-arg)
+ message-forward-ignored-headers)
+ (save-restriction
+ (narrow-to-region b e)
+ (goto-char b)
+ (narrow-to-region (point)
+ (or (search-forward "\n\n" nil t) (point)))
+ (message-remove-header message-forward-ignored-headers t)))))
(message-position-point)))
;;;###autoload
(let ((cur (current-buffer))
beg)
;; We first set up a normal mail buffer.
- (set-buffer (get-buffer-create " *message resend*"))
- (erase-buffer)
- (message-setup `((To . ,address)))
+ (unless (message-mail-user-agent)
+ (set-buffer (get-buffer-create " *message resend*"))
+ (erase-buffer))
+ (let ((message-this-is-mail t))
+ (message-setup `((To . ,address))))
;; Insert our usual headers.
(message-generate-headers '(From Date To))
(message-narrow-to-headers)
;;;###autoload
(defun message-bounce ()
"Re-mail the current message.
-This only makes sense if the current message is a bounce message than
+This only makes sense if the current message is a bounce message that
contains some mail you have written which has been bounced back to
you."
(interactive)
(if (re-search-forward "^[^ \n\t]+:" nil t)
(match-beginning 0)
(point))))
+ (mm-enable-multibyte)
+ (mime-to-mml)
(save-restriction
- (message-narrow-to-head)
+ (message-narrow-to-head-1)
(message-remove-header message-ignored-bounced-headers t)
(goto-char (point-max))
(insert mail-header-separator))
(defun message-mail-other-window (&optional to subject)
"Like `message-mail' command, but display mail buffer in another window."
(interactive)
- (let ((pop-up-windows t)
- (special-display-buffer-names nil)
- (special-display-regexps nil)
- (same-window-buffer-names nil)
- (same-window-regexps nil))
- (message-pop-to-buffer (message-buffer-name "mail" to)))
+ (unless (message-mail-user-agent)
+ (let ((pop-up-windows t)
+ (special-display-buffer-names nil)
+ (special-display-regexps nil)
+ (same-window-buffer-names nil)
+ (same-window-regexps nil))
+ (message-pop-to-buffer (message-buffer-name "mail" to))))
(let ((message-this-is-mail t))
- (message-setup `((To . ,(or to "")) (Subject . ,(or subject ""))))))
+ (message-setup `((To . ,(or to "")) (Subject . ,(or subject "")))
+ nil nil 'switch-to-buffer-other-window)))
;;;###autoload
(defun message-mail-other-frame (&optional to subject)
"Like `message-mail' command, but display mail buffer in another frame."
(interactive)
- (let ((pop-up-frames t)
- (special-display-buffer-names nil)
- (special-display-regexps nil)
- (same-window-buffer-names nil)
- (same-window-regexps nil))
- (message-pop-to-buffer (message-buffer-name "mail" to)))
+ (unless (message-mail-user-agent)
+ (let ((pop-up-frames t)
+ (special-display-buffer-names nil)
+ (special-display-regexps nil)
+ (same-window-buffer-names nil)
+ (same-window-regexps nil))
+ (message-pop-to-buffer (message-buffer-name "mail" to))))
(let ((message-this-is-mail t))
- (message-setup `((To . ,(or to "")) (Subject . ,(or subject ""))))))
+ (message-setup `((To . ,(or to "")) (Subject . ,(or subject "")))
+ nil nil 'switch-to-buffer-other-frame)))
;;;###autoload
(defun message-news-other-window (&optional newsgroups subject)
(defalias 'message-exchange-point-and-mark 'exchange-point-and-mark)
;; Support for toolbar
-(when (string-match "XEmacs\\|Lucid" emacs-version)
- (require 'messagexmas))
+(if (featurep 'xemacs)
+ (require 'messagexmas))
+
+(eval-when-compile
+ (defvar tool-bar-map)
+ (defvar tool-bar-mode))
+
+(defun message-tool-bar-map ()
+ (or message-tool-bar-map
+ (setq message-tool-bar-map
+ (and (fboundp 'tool-bar-add-item-from-menu)
+ tool-bar-mode
+ (let ((tool-bar-map (copy-keymap tool-bar-map))
+ (load-path (mm-image-load-path)))
+ ;; Zap some items which aren't so relevant and take
+ ;; up space.
+ (dolist (key '(print-buffer kill-buffer save-buffer
+ write-file dired open-file))
+ (define-key tool-bar-map (vector key) nil))
+ (tool-bar-add-item-from-menu
+ 'message-send-and-exit "mail_send" message-mode-map)
+ (tool-bar-add-item-from-menu
+ 'message-kill-buffer "close" message-mode-map)
+ (tool-bar-add-item-from-menu
+ 'message-dont-send "cancel" message-mode-map)
+ (tool-bar-add-item-from-menu
+ 'mml-attach-file "attach" message-mode-map)
+ (tool-bar-add-item-from-menu
+ 'ispell-message "spell" message-mode-map)
+ tool-bar-map)))))
;;; Group name completion.
(message-expand-group)
(tab-to-tab-stop)))
-(defvar gnus-active-hashtb)
(defun message-expand-group ()
"Expand the group name under point."
(let* ((b (save-excursion
;;; Miscellaneous functions
-;; stolen (and renamed) from nnheader.el
-(defun message-replace-chars-in-string (string from to)
- "Replace characters in STRING from FROM to TO."
- (let ((string (substring string 0)) ;Copy string.
- (len (length string))
- (idx 0))
- ;; Replace all occurrences of FROM with TO.
- (while (< idx len)
- (when (= (aref string idx) from)
- (aset string idx to))
- (setq idx (1+ idx)))
- string))
+(defsubst message-replace-chars-in-string (string from to)
+ (mm-subst-char-in-string from to string))
;;;
;;; MIME functions
(if (fboundp 'mail-abbrevs-setup)
(let ((mail-abbrev-mode-regexp "")
(minibuffer-setup-hook 'mail-abbrevs-setup))
- (read-from-minibuffer prompt)))
- (let ((minibuffer-setup-hook 'mail-abbrev-minibuffer-setup-hook))
- (read-string prompt)))
+ (read-from-minibuffer prompt))
+ (let ((minibuffer-setup-hook 'mail-abbrev-minibuffer-setup-hook))
+ (read-string prompt))))
+
+(defun message-use-alternative-email-as-from ()
+ (require 'mail-utils)
+ (let* ((fields '("To" "Cc"))
+ (emails
+ (split-string
+ (mail-strip-quoted-names
+ (mapconcat 'message-fetch-reply-field fields ","))
+ "[ \f\t\n\r\v,]+"))
+ email)
+ (while emails
+ (if (string-match message-alternative-emails (car emails))
+ (setq email (car emails)
+ emails nil))
+ (pop emails))
+ (unless (or (not email) (equal email user-mail-address))
+ (goto-char (point-max))
+ (insert "From: " email "\n"))))
+
+(defun message-options-get (symbol)
+ (cdr (assq symbol message-options)))
+
+(defun message-options-set (symbol value)
+ (let ((the-cons (assq symbol message-options)))
+ (if the-cons
+ (if value
+ (setcdr the-cons value)
+ (setq message-options (delq the-cons message-options)))
+ (and value
+ (push (cons symbol value) message-options))))
+ value)
+
+(defun message-options-set-recipient ()
+ (save-restriction
+ (message-narrow-to-headers-or-head)
+ (message-options-set 'message-sender
+ (mail-strip-quoted-names
+ (message-fetch-field "from")))
+ (message-options-set 'message-recipients
+ (mail-strip-quoted-names
+ (message-fetch-field "to")))))
(provide 'message)