emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] Changes to emacs/lisp/mh-e/mh-comp.el [gnus-5_10-branch]


From: Miles Bader
Subject: [Emacs-diffs] Changes to emacs/lisp/mh-e/mh-comp.el [gnus-5_10-branch]
Date: Sat, 04 Sep 2004 08:25:47 -0400

Index: emacs/lisp/mh-e/mh-comp.el
diff -c /dev/null emacs/lisp/mh-e/mh-comp.el:1.6.2.1
*** /dev/null   Sat Sep  4 12:01:50 2004
--- emacs/lisp/mh-e/mh-comp.el  Sat Sep  4 12:01:04 2004
***************
*** 0 ****
--- 1,1979 ----
+ ;;; mh-comp.el --- MH-E functions for composing messages
+ 
+ ;; Copyright (C) 1993, 95, 1997,
+ ;;  2000, 01, 02, 03, 2004 Free Software Foundation, Inc.
+ 
+ ;; Author: Bill Wohler <address@hidden>
+ ;; Maintainer: Bill Wohler <address@hidden>
+ ;; Keywords: mail
+ ;; See: mh-e.el
+ 
+ ;; This file is part of GNU Emacs.
+ 
+ ;; GNU Emacs is free software; you can redistribute it and/or modify
+ ;; it under the terms of the GNU General Public License as published by
+ ;; the Free Software Foundation; either version 2, or (at your option)
+ ;; any later version.
+ 
+ ;; GNU Emacs is distributed in the hope that it will be useful,
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ ;; GNU General Public License for more details.
+ 
+ ;; You should have received a copy of the GNU General Public License
+ ;; along with GNU Emacs; see the file COPYING.  If not, write to the
+ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ ;; Boston, MA 02111-1307, USA.
+ 
+ ;;; Commentary:
+ 
+ ;; Internal support for MH-E package.
+ 
+ ;;; Change Log:
+ 
+ ;;; Code:
+ 
+ (eval-when-compile (require 'mh-acros))
+ (mh-require-cl)
+ (require 'mh-e)
+ (require 'gnus-util)
+ (require 'easymenu)
+ (require 'mh-gnus)
+ (eval-when (compile load eval)
+   (ignore-errors (require 'mailabbrev)))
+ 
+ ;; Shush the byte-compiler
+ (defvar adaptive-fill-first-line-regexp)
+ (defvar font-lock-defaults)
+ (defvar mark-active)
+ (defvar sendmail-coding-system)
+ (defvar mh-identity-list)
+ (defvar mh-identity-default)
+ (defvar mh-mml-mode-default)
+ (defvar mh-identity-menu)
+ 
+ ;;; Autoloads
+ (autoload 'Info-goto-node "info")
+ (autoload 'mail-mode-fill-paragraph "sendmail")
+ (autoload 'mm-handle-displayed-p "mm-decode")
+ 
+ (autoload 'sc-cite-original "sc"
+   "Workhorse citing function which performs the initial citation.
+ This is callable from the various mail and news readers' reply
+ function according to the agreed upon standard.  See `sc-describe'
+ for more details.  `sc-cite-original' does not do any yanking of the
+ original message but it does require a few things:
+ 
+      1) The reply buffer is the current buffer.
+ 
+      2) The original message has been yanked and inserted into the
+         reply buffer.
+ 
+      3) Verbose mail headers from the original message have been
+         inserted into the reply buffer directly before the text of the
+         original message.
+ 
+      4) Point is at the beginning of the verbose headers.
+ 
+      5) Mark is at the end of the body of text to be cited.
+ 
+ For Emacs 19's, the region need not be active (and typically isn't
+ when this function is called.  Also, the hook `sc-pre-hook' is run
+ before, and `sc-post-hook' is run after the guts of this function.")
+ 
+ ;;; Site customization (see also mh-utils.el):
+ 
+ (defvar mh-send-prog "send"
+   "Name of the MH send program.
+ Some sites need to change this because of a name conflict.")
+ 
+ (defvar mh-redist-full-contents nil
+   "Non-nil if the `dist' command needs whole letter for redistribution.
+ This is the case only when `send' is compiled with the BERK option.
+ If MH will not allow you to redist a previously redist'd msg, set to nil.")
+ 
+ (defvar mh-redist-background nil
+   "If non-nil redist will be done in background like send.
+ This allows transaction log to be visible if -watch, -verbose or -snoop are
+ used.")
+ 
+ ;;; Scan Line Formats
+ 
+ (defvar mh-note-repl ?-
+   "Messages that have been replied to are marked by this character.")
+ 
+ (defvar mh-note-forw ?F
+   "Messages that have been forwarded are marked by this character.")
+ 
+ (defvar mh-note-dist ?R
+   "Messages that have been redistributed are marked by this character.")
+ 
+ (defvar mh-yank-hooks nil
+   "Obsolete hook for modifying a citation just inserted in the mail buffer.
+ Each hook function can find the citation between point and mark.
+ And each hook function should leave point and mark around the citation
+ text as modified.
+ 
+ This is a normal hook, misnamed for historical reasons.
+ It is semi-obsolete and is only used if `mail-citation-hook' is nil.")
+ 
+ (defvar mh-comp-formfile "components"
+   "Name of file to be used as a skeleton for composing messages.
+ Default is \"components\".  If not an absolute file name, the file
+ is searched for first in the user's MH directory, then in the
+ system MH lib directory.")
+ 
+ (defvar mh-repl-formfile "replcomps"
+   "Name of file to be used as a skeleton for replying to messages.
+ Default is \"replcomps\".  If not an absolute file name, the file
+ is searched for first in the user's MH directory, then in the
+ system MH lib directory.")
+ 
+ (defvar mh-repl-group-formfile "replgroupcomps"
+   "Name of file to be used as a skeleton for replying to messages.
+ This file is used to form replies to the sender and all recipients of a
+ message. Only used if `(mh-variant-p 'nmh)' is non-nil.
+ Default is \"replgroupcomps\".
+ If not an absolute file name, the file is searched for first in the user's MH
+ directory, then in the system MH lib directory.")
+ 
+ (defvar mh-rejected-letter-start
+   (format "^%s$"
+           (regexp-opt
+            '("Content-Type: message/rfc822" ;MIME MDN
+              "------ This is a copy of the message, including all the 
headers. ------";from exim
+            "--- Below this line is a copy of the message."; from qmail
+              "   ----- Unsent message follows -----" ;from sendmail V5
+              " --------Unsent Message below:" ; from sendmail at BU
+              "   ----- Original message follows -----" ;from sendmail V8
+              "------- Unsent Draft"     ;from MH itself
+              "----------  Original Message  ----------" ;from zmailer
+              "  --- The unsent message follows ---" ;from AIX mail system
+              "    Your message follows:" ;from MMDF-II
+              "Content-Description: Returned Content" ;1993 KJ sendmail
+              ))))
+ 
+ (defvar mh-new-draft-cleaned-headers
+   
"^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Sender:\\|^Errors-To:\\|^Delivery-Date:\\|^Return-Path:"
+   "Regexp of header lines to remove before offering a message as a new draft.
+ Used by the \\<mh-folder-mode-map>`\\[mh-edit-again]' and 
`\\[mh-extract-rejected-mail]' commands.")
+ 
+ (defvar mh-to-field-choices '(("t" . "To:") ("s" . "Subject:") ("c" . "Cc:")
+                               ("b" . "Bcc:") ("f" . "Fcc:") ("r" . "From:")
+                               ("d" . "Dcc:"))
+   "Alist of (final-character . field-name) choices for `mh-to-field'.")
+ 
+ (defvar mh-letter-mode-map (copy-keymap text-mode-map)
+   "Keymap for composing mail.")
+ 
+ (defvar mh-letter-mode-syntax-table nil
+   "Syntax table used by MH-E while in MH-Letter mode.")
+ 
+ (if mh-letter-mode-syntax-table
+     ()
+   (setq mh-letter-mode-syntax-table
+         (make-syntax-table text-mode-syntax-table))
+   (modify-syntax-entry ?% "." mh-letter-mode-syntax-table))
+ 
+ (defvar mh-sent-from-folder nil
+   "Folder of msg assoc with this letter.")
+ 
+ (defvar mh-sent-from-msg nil
+   "Number of msg assoc with this letter.")
+ 
+ (defvar mh-send-args nil
+   "Extra args to pass to \"send\" command.")
+ 
+ (defvar mh-annotate-char nil
+   "Character to use to annotate `mh-sent-from-msg'.")
+ 
+ (defvar mh-annotate-field nil
+   "Field name for message annotation.")
+ 
+ (defvar mh-insert-auto-fields-done-local nil
+   "Buffer-local variable set when `mh-insert-auto-fields' called 
successfully.")
+ (make-variable-buffer-local 'mh-insert-auto-fields-done-local)
+ 
+ ;;;###autoload
+ (defun mh-smail ()
+   "Compose and send mail with the MH mail system.
+ This function is an entry point to MH-E, the Emacs interface to the MH mail
+ system.
+ 
+ See `mh-send' for more details on composing mail."
+   (interactive)
+   (mh-find-path)
+   (call-interactively 'mh-send))
+ 
+ (defvar mh-error-if-no-draft nil)       ;raise error over using old draft
+ 
+ ;;;###autoload
+ (defun mh-smail-batch (&optional to subject other-headers &rest ignored)
+   "Set up a mail composition draft with the MH mail system.
+ This function is an entry point to MH-E, the Emacs interface to the MH mail
+ system. This function does not prompt the user for any header fields, and thus
+ is suitable for use by programs that want to create a mail buffer. Users
+ should use `mh-smail' to compose mail.
+ 
+ Optional arguments for setting certain fields include TO, SUBJECT, and
+ OTHER-HEADERS. Additional arguments are IGNORED."
+   (mh-find-path)
+   (let ((mh-error-if-no-draft t))
+     (mh-send (or to "") "" (or subject ""))))
+ 
+ ;; XEmacs needs this:
+ ;;;###autoload
+ (defun mh-user-agent-compose (&optional to subject other-headers continue
+                                         switch-function yank-action
+                                         send-actions)
+   "Set up mail composition draft with the MH mail system.
+ This is `mail-user-agent' entry point to MH-E.
+ 
+ The optional arguments TO and SUBJECT specify recipients and the
+ initial Subject field, respectively.
+ 
+ OTHER-HEADERS is an alist specifying additional
+ header fields.  Elements look like (HEADER . VALUE) where both
+ HEADER and VALUE are strings.
+ 
+ CONTINUE, SWITCH-FUNCTION, YANK-ACTION and SEND-ACTIONS are ignored."
+   (mh-find-path)
+   (let ((mh-error-if-no-draft t))
+     (mh-send to "" subject)
+     (while other-headers
+       (mh-insert-fields (concat (car (car other-headers)) ":")
+                         (cdr (car other-headers)))
+       (setq other-headers (cdr other-headers)))))
+ 
+ ;;;###mh-autoload
+ (defun mh-edit-again (msg)
+   "Clean up a draft or a message MSG previously sent and make it resendable.
+ Default is the current message.
+ The variable `mh-new-draft-cleaned-headers' specifies the headers to remove.
+ 
+ See also `mh-send'."
+   (interactive (list (mh-get-msg-num t)))
+   (let* ((from-folder mh-current-folder)
+          (config (current-window-configuration))
+          (draft
+           (cond ((and mh-draft-folder (equal from-folder mh-draft-folder))
+                  (pop-to-buffer (find-file-noselect (mh-msg-filename msg)) t)
+                  (rename-buffer (format "draft-%d" msg))
+                  ;; Make buffer writable...
+                  (setq buffer-read-only nil)
+                  ;; If buffer was being used to display the message reinsert
+                  ;; from file...
+                  (when (eq major-mode 'mh-show-mode)
+                    (erase-buffer)
+                    (insert-file-contents buffer-file-name))
+                  (buffer-name))
+                 (t
+                  (mh-read-draft "clean-up" (mh-msg-filename msg) nil)))))
+     (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil)
+     (mh-insert-header-separator)
+     (goto-char (point-min))
+     (save-buffer)
+     (mh-compose-and-send-mail draft "" from-folder nil nil nil nil nil nil
+                               config)
+     (mh-letter-mode-message)
+     (mh-letter-adjust-point)))
+ 
+ ;;;###mh-autoload
+ (defun mh-extract-rejected-mail (msg)
+   "Extract message MSG returned by the mail system and make it resendable.
+ Default is the current message.  The variable `mh-new-draft-cleaned-headers'
+ gives the headers to clean out of the original message.
+ 
+ See also `mh-send'."
+   (interactive (list (mh-get-msg-num t)))
+   (let ((from-folder mh-current-folder)
+         (config (current-window-configuration))
+         (draft (mh-read-draft "extraction" (mh-msg-filename msg) nil)))
+     (goto-char (point-min))
+     (cond ((re-search-forward mh-rejected-letter-start nil t)
+            (skip-chars-forward " \t\n")
+            (delete-region (point-min) (point))
+            (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil))
+           (t
+            (message "Does not appear to be a rejected letter")))
+     (mh-insert-header-separator)
+     (goto-char (point-min))
+     (save-buffer)
+     (mh-compose-and-send-mail draft "" from-folder msg
+                               (mh-get-header-field "To:")
+                               (mh-get-header-field "From:")
+                               (mh-get-header-field "Cc:")
+                               nil nil config)
+     (mh-letter-mode-message)))
+ 
+ ;;;###mh-autoload
+ (defun mh-forward (to cc &optional range)
+   "Forward messages to the recipients TO and CC.
+ Use optional RANGE argument to specify a message or sequence to forward.
+ Default is the displayed message.
+ 
+ Check the documentation of `mh-interactive-range' to see how RANGE is read in
+ interactive use.
+ 
+ See also `mh-send'."
+   (interactive (list (mh-interactive-read-address "To: ")
+                      (mh-interactive-read-address "Cc: ")
+                      (mh-interactive-range "Forward")))
+   (let* ((folder mh-current-folder)
+          (msgs (mh-range-to-msg-list range))
+          (config (current-window-configuration))
+          (fwd-msg-file (mh-msg-filename (car msgs) folder))
+          ;; forw always leaves file in "draft" since it doesn't have -draft
+          (draft-name (expand-file-name "draft" mh-user-path))
+          (draft (cond ((or (not (file-exists-p draft-name))
+                            (y-or-n-p "The file 'draft' exists.  Discard it? 
"))
+                        (mh-exec-cmd "forw" "-build"
+                                     (if (and (mh-variant-p 'nmh)
+                                              mh-compose-forward-as-mime-flag)
+                                         "-mime")
+                                     mh-current-folder
+                                     (mh-coalesce-msg-list msgs))
+                        (prog1
+                            (mh-read-draft "" draft-name t)
+                          (mh-insert-fields "To:" to "Cc:" cc)
+                          (save-buffer)))
+                       (t
+                        (mh-read-draft "" draft-name nil)))))
+     (let (orig-from
+           orig-subject)
+       (save-excursion
+         (set-buffer (get-buffer-create mh-temp-buffer))
+         (erase-buffer)
+         (insert-file-contents fwd-msg-file)
+         (setq orig-from (mh-get-header-field "From:"))
+         (setq orig-subject (mh-get-header-field "Subject:")))
+       (let ((forw-subject
+              (mh-forwarded-letter-subject orig-from orig-subject)))
+         (mh-insert-fields "Subject:" forw-subject)
+         (goto-char (point-min))
+         ;; If using MML, translate mhn
+         (if (equal mh-compose-insertion 'gnus)
+             (save-excursion
+               (goto-char (mh-mail-header-end))
+               (while
+                   (re-search-forward
+                    "^#forw \\[\\([^]]+\\)\\] \\(+\\S-+\\) \\(.*\\)$"
+                    (point-max) t)
+                 (let ((description (if (equal (match-string 1)
+                                               "forwarded messages")
+                                        "forwarded message %d"
+                                      (match-string 1)))
+                       (msgs (split-string (match-string 3)))
+                       (i 0))
+                   (beginning-of-line)
+                   (delete-region (point) (progn (forward-line 1) (point)))
+                   (dolist (msg msgs)
+                     (setq i (1+ i))
+                     (mh-mml-forward-message (format description i)
+                                             folder msg))))))
+         ;; Postition just before forwarded message
+         (if (re-search-forward "^------- Forwarded Message" nil t)
+             (forward-line -1)
+           (goto-char (mh-mail-header-end))
+           (forward-line 1))
+         (delete-other-windows)
+         (mh-add-msgs-to-seq msgs 'forwarded t)
+         (mh-compose-and-send-mail draft "" folder msgs
+                                   to forw-subject cc
+                                   mh-note-forw "Forwarded:"
+                                   config)
+         (mh-letter-mode-message)
+         (mh-letter-adjust-point)
+         (run-hooks 'mh-forward-hook)))))
+ 
+ (defun mh-forwarded-letter-subject (from subject)
+   "Return a Subject suitable for a forwarded message.
+ Original message has headers FROM and SUBJECT."
+   (let ((addr-start (string-match "<" from))
+         (comment (string-match "(" from)))
+     (cond ((and addr-start (> addr-start 0))
+            ;; Full Name <address@hidden>
+            (setq from (substring from 0 (1- addr-start))))
+           (comment
+            ;; address@hidden (Full Name)
+            (setq from (substring from (1+ comment) (1- (length from)))))))
+   (format mh-forward-subject-format from subject))
+ 
+ ;;;###autoload
+ (defun mh-smail-other-window ()
+   "Compose and send mail in other window with the MH mail system.
+ This function is an entry point to MH-E, the Emacs interface to the MH mail
+ system.
+ 
+ See `mh-send' for more details on composing mail."
+   (interactive)
+   (mh-find-path)
+   (call-interactively 'mh-send-other-window))
+ 
+ ;;;###mh-autoload
+ (defun mh-redistribute (to cc &optional msg)
+   "Redistribute displayed message to recipients TO and CC.
+ Use optional argument MSG to redistribute another message.
+ Depending on how your copy of MH was compiled, you may need to change the
+ setting of the variable `mh-redist-full-contents'.  See its documentation."
+   (interactive (list (mh-read-address "Redist-To: ")
+                      (mh-read-address "Redist-Cc: ")
+                      (mh-get-msg-num t)))
+   (or msg
+       (setq msg (mh-get-msg-num t)))
+   (save-window-excursion
+     (let ((folder mh-current-folder)
+           (draft (mh-read-draft "redistribution"
+                                 (if mh-redist-full-contents
+                                     (mh-msg-filename msg)
+                                   nil)
+                                 nil)))
+       (mh-goto-header-end 0)
+       (insert "Resent-To: " to "\n")
+       (if (not (equal cc "")) (insert "Resent-cc: " cc "\n"))
+       (mh-clean-msg-header
+        (point-min)
+        
"^Message-Id:\\|^Received:\\|^Return-Path:\\|^Sender:\\|^Date:\\|^From:"
+        nil)
+       (save-buffer)
+       (message "Redistributing...")
+       (let ((env "mhdist=1"))
+         ;; Setup environment...
+         (setq env (concat env " mhaltmsg=" (if mh-redist-full-contents
+                                                buffer-file-name
+                                              (mh-msg-filename msg folder))))
+         (unless mh-redist-full-contents
+           (setq env (concat env " mhannotate=1")))
+         ;; Redistribute...
+         (if mh-redist-background
+             (mh-exec-cmd-env-daemon env mh-send-prog nil buffer-file-name)
+           (mh-exec-cmd-error env mh-send-prog "-push" buffer-file-name))
+         ;; Annotate...
+         (mh-annotate-msg msg folder mh-note-dist
+                          "-component" "Resent:"
+                          "-text" (format "\"%s %s\"" to cc)))
+       (kill-buffer draft)
+       (message "Redistributing...done"))))
+ 
+ (defun mh-show-buffer-message-number (&optional buffer)
+   "Message number of displayed message in corresponding show buffer.
+ Return nil if show buffer not displayed.
+ If in `mh-letter-mode', don't display the message number being replied to,
+ but rather the message number of the show buffer associated with our
+ originating folder buffer.
+ Optional argument BUFFER can be used to specify the buffer."
+   (save-excursion
+     (if buffer
+         (set-buffer buffer))
+     (cond ((eq major-mode 'mh-show-mode)
+            (let ((number-start (mh-search-from-end ?/ buffer-file-name)))
+              (car (read-from-string (substring buffer-file-name
+                                                (1+ number-start))))))
+           ((and (eq major-mode 'mh-folder-mode)
+                 mh-show-buffer
+                 (get-buffer mh-show-buffer))
+            (mh-show-buffer-message-number mh-show-buffer))
+           ((and (eq major-mode 'mh-letter-mode)
+                 mh-sent-from-folder
+                 (get-buffer mh-sent-from-folder))
+            (mh-show-buffer-message-number mh-sent-from-folder))
+           (t
+            nil))))
+ 
+ ;;;###mh-autoload
+ (defun mh-reply (message &optional reply-to includep)
+   "Reply to MESSAGE.
+ Default is the displayed message.
+ If the optional argument REPLY-TO is not given, prompts for type of addresses
+ to reply to:
+    from    sender only,
+    to      sender and primary recipients,
+    cc/all  sender and all recipients.
+ If optional prefix argument INCLUDEP provided, then include the message
+ in the reply using filter `mhl.reply' in your MH directory.
+ If the file named by `mh-repl-formfile' exists, it is used as a skeleton
+ for the reply.
+ 
+ See also `mh-send'."
+   (interactive (list
+                 (mh-get-msg-num t)
+                 (let ((minibuffer-help-form
+                        "from => Sender only\nto => Sender and primary 
recipients\ncc or all => Sender and all recipients"))
+                   (or mh-reply-default-reply-to
+                       (completing-read "Reply to whom: [from] "
+                                        '(("from") ("to") ("cc") ("all"))
+                                        nil
+                                        t)))
+                 current-prefix-arg))
+   (let* ((folder mh-current-folder)
+          (show-buffer mh-show-buffer)
+          (config (current-window-configuration))
+          (group-reply (or (equal reply-to "cc") (equal reply-to "all")))
+          (form-file (cond ((and (mh-variant-p 'nmh 'mu-mh) group-reply
+                                 (stringp mh-repl-group-formfile))
+                            mh-repl-group-formfile)
+                           ((stringp mh-repl-formfile) mh-repl-formfile)
+                           (t nil))))
+     (message "Composing a reply...")
+     (mh-exec-cmd "repl" "-build" "-noquery" "-nodraftfolder"
+                  (if form-file
+                      (list "-form" form-file))
+                  mh-current-folder message
+                  (cond ((or (equal reply-to "from") (equal reply-to ""))
+                         '("-nocc" "all"))
+                        ((equal reply-to "to")
+                         '("-cc" "to"))
+                        (group-reply (if (mh-variant-p 'nmh 'mu-mh)
+                                         '("-group" "-nocc" "me")
+                                       '("-cc" "all" "-nocc" "me"))))
+                  (cond ((or (eq mh-yank-from-start-of-msg 'autosupercite)
+                             (eq mh-yank-from-start-of-msg 'autoattrib))
+                         '("-noformat"))
+                        (includep '("-filter" "mhl.reply"))
+                        (t '())))
+     (let ((draft (mh-read-draft "reply"
+                                 (expand-file-name "reply" mh-user-path)
+                                 t)))
+       (delete-other-windows)
+       (save-buffer)
+ 
+       (let ((to (mh-get-header-field "To:"))
+             (subject (mh-get-header-field "Subject:"))
+             (cc (mh-get-header-field "Cc:")))
+         (goto-char (point-min))
+         (mh-goto-header-end 1)
+         (or includep
+             (not mh-reply-show-message-flag)
+             (mh-in-show-buffer (show-buffer)
+               (mh-display-msg message folder)))
+         (mh-add-msgs-to-seq message 'answered t)
+         (message "Composing a reply...done")
+         (mh-compose-and-send-mail draft "" folder message to subject cc
+                                   mh-note-repl "Replied:" config))
+       (when (and (or (eq 'autosupercite mh-yank-from-start-of-msg)
+                      (eq 'autoattrib mh-yank-from-start-of-msg))
+                  (eq (mh-show-buffer-message-number) mh-sent-from-msg))
+         (undo-boundary)
+         (mh-yank-cur-msg))
+       (mh-letter-mode-message))))
+ 
+ ;;;###mh-autoload
+ (defun mh-send (to cc subject)
+   "Compose and send a letter.
+ Do not call this function from outside MH-E; use \\[mh-smail] instead.
+ 
+ The file named by `mh-comp-formfile' will be used as the form.
+ The letter is composed in `mh-letter-mode'; see its documentation for more
+ details.
+ If `mh-compose-letter-function' is defined, it is called on the draft and
+ passed three arguments: TO, CC, and SUBJECT."
+   (interactive (list
+                 (mh-interactive-read-address "To: ")
+                 (mh-interactive-read-address "Cc: ")
+                 (mh-interactive-read-string "Subject: ")))
+   (let ((config (current-window-configuration)))
+     (delete-other-windows)
+     (mh-send-sub to cc subject config)))
+ 
+ ;;;###mh-autoload
+ (defun mh-send-other-window (to cc subject)
+   "Compose and send a letter in another window.
+ Do not call this function from outside MH-E; use \\[mh-smail-other-window]
+ instead.
+ 
+ The file named by `mh-comp-formfile' will be used as the form.
+ The letter is composed in `mh-letter-mode'; see its documentation for more
+ details.
+ If `mh-compose-letter-function' is defined, it is called on the draft and
+ passed three arguments: TO, CC, and SUBJECT."
+   (interactive (list
+                 (mh-interactive-read-address "To: ")
+                 (mh-interactive-read-address "Cc: ")
+                 (mh-interactive-read-string "Subject: ")))
+   (let ((pop-up-windows t))
+     (mh-send-sub to cc subject (current-window-configuration))))
+ 
+ (defun mh-send-sub (to cc subject config)
+   "Do the real work of composing and sending a letter.
+ Expects the TO, CC, and SUBJECT fields as arguments.
+ CONFIG is the window configuration before sending mail."
+   (let ((folder mh-current-folder)
+         (msg-num (mh-get-msg-num nil)))
+     (message "Composing a message...")
+     (let ((draft (mh-read-draft
+                   "message"
+                   (let (components)
+                     (cond
+                      ((file-exists-p
+                        (setq components
+                              (expand-file-name mh-comp-formfile 
mh-user-path)))
+                       components)
+                      ((file-exists-p
+                        (setq components
+                              (expand-file-name mh-comp-formfile mh-lib)))
+                       components)
+                      ((file-exists-p
+                        (setq components
+                              (expand-file-name mh-comp-formfile
+                                                ;; What is this mh-etc ??  -sm
+                                                ;; This is dead code, so
+                                                ;; remove it.
+                                         ;(and (boundp 'mh-etc) mh-etc)
+                                                )))
+                       components)
+                      (t
+                       (error (format "Can't find components file \"%s\""
+                                      components)))))
+                   nil)))
+       (mh-insert-fields "To:" to "Subject:" subject "Cc:" cc)
+       (goto-char (point-max))
+       (mh-compose-and-send-mail draft "" folder msg-num
+                                 to subject cc
+                                 nil nil config)
+       (mh-letter-mode-message)
+       (mh-letter-adjust-point))))
+ 
+ (defun mh-read-draft (use initial-contents delete-contents-file)
+   "Read draft file into a draft buffer and make that buffer the current one.
+ USE is a message used for prompting about the intended use of the message.
+ INITIAL-CONTENTS is filename that is read into an empty buffer, or nil
+ if buffer should not be modified.  Delete the initial-contents file if
+ DELETE-CONTENTS-FILE flag is set.
+ Returns the draft folder's name.
+ If the draft folder facility is enabled in ~/.mh_profile, a new buffer is
+ used each time and saved in the draft folder.  The draft file can then be
+ reused."
+   (cond (mh-draft-folder
+          (let ((orig-default-dir default-directory)
+                (draft-file-name (mh-new-draft-name)))
+            (pop-to-buffer (generate-new-buffer
+                            (format "draft-%s"
+                                    (file-name-nondirectory draft-file-name))))
+            (condition-case ()
+                (insert-file-contents draft-file-name t)
+              (file-error))
+            (setq default-directory orig-default-dir)))
+         (t
+          (let ((draft-name (expand-file-name "draft" mh-user-path)))
+            (pop-to-buffer "draft")      ; Create if necessary
+            (if (buffer-modified-p)
+                (if (y-or-n-p "Draft has been modified; kill anyway? ")
+                    (set-buffer-modified-p nil)
+                  (error "Draft preserved")))
+            (setq buffer-file-name draft-name)
+            (clear-visited-file-modtime)
+            (unlock-buffer)
+            (cond ((and (file-exists-p draft-name)
+                        (not (equal draft-name initial-contents)))
+                   (insert-file-contents draft-name)
+                   (delete-file draft-name))))))
+   (cond ((and initial-contents
+               (or (zerop (buffer-size))
+                   (if (y-or-n-p
+                        (format "A draft exists.  Use for %s? " use))
+                       (if mh-error-if-no-draft
+                           (error "A prior draft exists"))
+                     t)))
+          (erase-buffer)
+          (insert-file-contents initial-contents)
+          (if delete-contents-file (delete-file initial-contents))))
+   (auto-save-mode 1)
+   (if mh-draft-folder
+       (save-buffer))                    ; Do not reuse draft name
+   (buffer-name))
+ 
+ (defun mh-new-draft-name ()
+   "Return the pathname of folder for draft messages."
+   (save-excursion
+     (mh-exec-cmd-quiet t "mhpath" mh-draft-folder "new")
+     (buffer-substring (point-min) (1- (point-max)))))
+ 
+ (defun mh-annotate-msg (msg buffer note &rest args)
+   "Mark MSG in BUFFER with character NOTE and annotate message with ARGS.
+ MSG can be a message number, a list of message numbers, or a sequence."
+   (apply 'mh-exec-cmd "anno" buffer
+          (if (listp msg) (append msg args) (cons msg args)))
+   (save-excursion
+     (cond ((get-buffer buffer)          ; Buffer may be deleted
+            (set-buffer buffer)
+            (mh-iterate-on-range nil msg
+              (mh-notate nil note (1+ mh-cmd-note)))))))
+ 
+ (defun mh-insert-fields (&rest name-values)
+   "Insert the NAME-VALUES pairs in the current buffer.
+ If the field exists, append the value to it.
+ Do not insert any pairs whose value is the empty string."
+   (let ((case-fold-search t))
+     (while name-values
+       (let ((field-name (car name-values))
+             (value (car (cdr name-values))))
+         (if (not (string-match "^.*:$" field-name))
+             (setq field-name (concat field-name ":")))
+         (cond ((equal value "")
+                nil)
+               ((mh-position-on-field field-name)
+                (insert " " (or value "")))
+               (t
+                (insert field-name " " value "\n")))
+         (setq name-values (cdr (cdr name-values)))))))
+ 
+ (defun mh-position-on-field (field &optional ignored)
+   "Move to the end of the FIELD in the header.
+ Move to end of entire header if FIELD not found.
+ Returns non-nil iff FIELD was found.
+ The optional second arg is for pre-version 4 compatibility and is IGNORED."
+   (cond ((mh-goto-header-field field)
+          (mh-header-field-end)
+          t)
+         ((mh-goto-header-end 0)
+          nil)))
+ 
+ ;;;###mh-autoload
+ (defun mh-get-header-field (field)
+   "Find and return the body of FIELD in the mail header.
+ Returns the empty string if the field is not in the header of the
+ current buffer."
+   (if (mh-goto-header-field field)
+       (progn
+         (skip-chars-forward " \t")      ;strip leading white space in body
+         (let ((start (point)))
+           (mh-header-field-end)
+           (buffer-substring-no-properties start (point))))
+     ""))
+ 
+ (fset 'mh-get-field 'mh-get-header-field) ;MH-E 4 compatibility
+ 
+ (defun mh-goto-header-field (field)
+   "Move to FIELD in the message header.
+ Move to the end of the FIELD name, which should end in a colon.
+ Returns t if found, nil if not."
+   (goto-char (point-min))
+   (let ((case-fold-search t)
+         (headers-end (save-excursion
+                        (mh-goto-header-end 0)
+                        (point))))
+     (re-search-forward (format "^%s" field) headers-end t)))
+ 
+ (defun mh-goto-header-end (arg)
+   "Move the cursor ARG lines after the header."
+   (if (re-search-forward "^-*$" nil nil)
+       (forward-line arg)))
+ 
+ (defun mh-extract-from-header-value ()
+   "Extract From: string from header."
+   (save-excursion
+     (if (not (mh-goto-header-field "From:"))
+         nil
+       (skip-chars-forward " \t")
+       (buffer-substring-no-properties
+        (point) (progn (mh-header-field-end)(point))))))
+ 
+ 
+ 
+ ;;; Mode for composing and sending a draft message.
+ 
+ (put 'mh-letter-mode 'mode-class 'special)
+ 
+ ;;; Menu extracted from mh-menubar.el V1.1 (31 July 2001)
+ (eval-when-compile (defvar mh-letter-menu nil))
+ (easy-menu-define
+   mh-letter-menu mh-letter-mode-map "Menu for MH-E letter mode."
+   '("Letter"
+     ["Send This Draft"          mh-send-letter t]
+     ["Split Current Line"       mh-open-line t]
+     ["Check Recipient"          mh-check-whom t]
+     ["Yank Current Message"     mh-yank-cur-msg t]
+     ["Insert a Message..."      mh-insert-letter t]
+     ["Insert Signature"         mh-insert-signature t]
+     ("Encrypt/Sign Message"
+      ["Sign Message"
+       mh-mml-secure-message-sign mh-gnus-pgp-support-flag]
+      ["Encrypt Message"
+       mh-mml-secure-message-encrypt mh-gnus-pgp-support-flag]
+      ["Sign+Encrypt Message"
+       mh-mml-secure-message-signencrypt mh-gnus-pgp-support-flag]
+      ["Disable Security"
+       mh-mml-unsecure-message mh-gnus-pgp-support-flag]
+      "--"
+      "Security Method"
+      ["PGP (MIME)" (setq mh-mml-method-default "pgpmime")
+       :style radio
+       :selected (equal mh-mml-method-default "pgpmime")]
+      ["PGP" (setq mh-mml-method-default "pgp")
+       :style radio
+       :selected (equal mh-mml-method-default "pgp")]
+      ["S/MIME" (setq mh-mml-method-default "smime")
+       :style radio
+       :selected (equal mh-mml-method-default "smime")]
+      "--"
+      ["Save Method as Default"
+       (customize-save-variable 'mh-mml-method-default mh-mml-method-default) 
t]
+      )
+     ["Compose Insertion (MIME)..."      mh-compose-insertion t]
+     ["Compose Compressed tar (MIME)..."
+      mh-mhn-compose-external-compressed-tar t]
+     ["Compose Get File (MIME)..."       mh-mhn-compose-anon-ftp t]
+     ["Compose Forward (MIME)..."        mh-compose-forward t]
+     ;; The next two will have to be merged. But I also need to make sure the
+     ;; user can't mix directives of both types.
+     ["Pull in All Compositions (mhn)"
+      mh-edit-mhn (mh-mhn-directive-present-p)]
+     ["Pull in All Compositions (gnus)"
+      mh-mml-to-mime (mh-mml-directive-present-p)]
+     ["Revert to Non-MIME Edit (mhn)"
+      mh-revert-mhn-edit (equal mh-compose-insertion 'mhn)]
+     ["Kill This Draft"          mh-fully-kill-draft t]))
+ 
+ ;;; Help Messages
+ ;;; Group messages logically, more or less.
+ (defvar mh-letter-mode-help-messages
+   '((nil
+      "Send letter:          \\[mh-send-letter]"
+      "\t\tOpen line:            \\[mh-open-line]\n"
+      "Kill letter:          \\[mh-fully-kill-draft]"
+      "\t\tInsert:\n"
+      "Check recipients:     \\[mh-check-whom]"
+      "\t\t  Current message:    \\[mh-yank-cur-msg]\n"
+      "\t\t  Attachment:             \\[mh-compose-insertion]\n"
+      "\t\t  Message to forward:     \\[mh-compose-forward]\n"
+      "                          "
+      "Security:"
+      "\t\t  Encrypt message:          \\[mh-mml-secure-message-encrypt]"
+      "\t\t  Sign+Encrypt message:     \\[mh-mml-secure-message-signencrypt]"
+      "\t\t  Sign message:             \\[mh-mml-secure-message-sign]\n"
+      "                          "
+      "\t\t  Signature:              \\[mh-insert-signature]"))
+   "Key binding cheat sheet.
+ 
+ This is an associative array which is used to show the most common commands.
+ The key is a prefix char. The value is one or more strings which are
+ concatenated together and displayed in the minibuffer if ? is pressed after
+ the prefix character. The special key nil is used to display the
+ non-prefixed commands.
+ 
+ The substitutions described in `substitute-command-keys' are performed as
+ well.")
+ 
+ ;;;###mh-autoload
+ (defun mh-fill-paragraph-function (arg)
+   "Fill paragraph at or after point.
+ Prefix ARG means justify as well. This function enables `fill-paragraph' to
+ work better in MH-Letter mode."
+   (interactive "P")
+   (let ((fill-paragraph-function) (fill-prefix))
+     (if (mh-in-header-p)
+         (mail-mode-fill-paragraph arg)
+       (fill-paragraph arg))))
+ 
+ ;; Avoid compiler warnings in XEmacs and Emacs 20
+ (eval-when-compile
+   (defvar tool-bar-mode)
+   (defvar tool-bar-map))
+ 
+ ;;;###autoload
+ (define-derived-mode mh-letter-mode text-mode "MH-Letter"
+   "Mode for composing letters in MH-E.\\<mh-letter-mode-map>
+ 
+ When you have finished composing, type \\[mh-send-letter] to send the message
+ using the MH mail handling system.
+ 
+ There are two types of MIME directives used by MH-E: Gnus and MH. The option
+ `mh-compose-insertion' controls what type of directives are inserted by MH-E
+ commands. These directives can be converted to MIME body parts by running
+ \\[mh-edit-mhn] for mhn directives or \\[mh-mml-to-mime] for Gnus directives.
+ This step is mandatory if these directives are added manually. If the
+ directives are inserted with MH-E commands such as \\[mh-compose-insertion],
+ the directives are expanded automatically when the letter is sent.
+ 
+ Options that control this mode can be changed with
+ \\[customize-group]; specify the \"mh-compose\" group.
+ 
+ When a message is composed, the hooks `text-mode-hook' and
+ `mh-letter-mode-hook' are run.
+ 
+ \\{mh-letter-mode-map}"
+   (mh-find-path)
+   (make-local-variable 'mh-send-args)
+   (make-local-variable 'mh-annotate-char)
+   (make-local-variable 'mh-annotate-field)
+   (make-local-variable 'mh-previous-window-config)
+   (make-local-variable 'mh-sent-from-folder)
+   (make-local-variable 'mh-sent-from-msg)
+   ;; Set the local value of mh-mail-header-separator according to what is
+   ;; present in the buffer...
+   (set (make-local-variable 'mh-mail-header-separator)
+        (save-excursion
+          (goto-char (mh-mail-header-end))
+          (buffer-substring-no-properties (point) (line-end-position))))
+   (make-local-variable 'mail-header-separator)
+   (setq mail-header-separator mh-mail-header-separator) ;override sendmail.el
+   (make-local-variable 'mh-help-messages)
+   (setq mh-help-messages mh-letter-mode-help-messages)
+   (setq buffer-invisibility-spec '((vanish . t) t))
+   (set (make-local-variable 'line-move-ignore-invisible) t)
+ 
+   ;; From sendmail.el for proper paragraph fill
+   ;; sendmail.el also sets a normal-auto-fill-function (not done here)
+   (make-local-variable 'paragraph-separate)
+   (make-local-variable 'paragraph-start)
+   (make-local-variable 'fill-paragraph-function)
+   (setq fill-paragraph-function 'mh-fill-paragraph-function)
+   (make-local-variable 'adaptive-fill-regexp)
+   (setq adaptive-fill-regexp
+         (concat adaptive-fill-regexp
+                 "\\|[ \t]*[-[:alnum:]]*>+[ \t]*"))
+   (make-local-variable 'adaptive-fill-first-line-regexp)
+   (setq adaptive-fill-first-line-regexp
+         (concat adaptive-fill-first-line-regexp
+                 "\\|[ \t]*[-[:alnum:]]*>+[ \t]*"))
+   ;; `-- ' 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*\\([-|#;>* ]\\|(?[0-9]+[.)]\\)+$"
+                                 "\\|[ \t]*[[:alnum:]]*>+[ \t]*$\\|[ \t]*$\\|"
+                                 "-- $\\|---+$\\|"
+                                 page-delimiter))
+   (setq paragraph-separate paragraph-start)
+   ;; --- End of code from sendmail.el ---
+ 
+   ;; Enable undo since a show-mode buffer might have been reused.
+   (buffer-enable-undo)
+   (set (make-local-variable 'tool-bar-map) mh-letter-tool-bar-map)
+   (mh-funcall-if-exists mh-toolbar-init :letter)
+   (make-local-variable 'font-lock-defaults)
+   (cond
+    ((or (equal mh-highlight-citation-p 'font-lock)
+         (equal mh-highlight-citation-p 'gnus))
+     ;; Let's use font-lock even if gnus is used in show-mode.  The reason
+     ;; is that gnus uses static text properties which are not appropriate
+     ;; for a buffer that will be edited.  So the choice here is either fontify
+     ;; the citations and header...
+     (setq font-lock-defaults '(mh-letter-font-lock-keywords t)))
+    (t
+     ;; ...or the header only
+     (setq font-lock-defaults '(mh-show-font-lock-keywords t))))
+   (easy-menu-add mh-letter-menu)
+   (setq fill-column mh-letter-fill-column)
+   ;; If text-mode-hook turned on auto-fill, tune it for messages
+   (when auto-fill-function
+     (make-local-variable 'auto-fill-function)
+     (setq auto-fill-function 'mh-auto-fill-for-letter)))
+ 
+ (defun mh-font-lock-field-data (limit)
+   "Find header field region between point and LIMIT."
+   (and (< (point) (mh-letter-header-end))
+        (< (point) limit)
+        (let ((end (min limit (mh-letter-header-end)))
+              (point (point))
+              data-end data-begin field)
+          (end-of-line)
+          (setq data-end (if (re-search-forward "^[^ \t]" end t)
+                             (match-beginning 0)
+                           end))
+          (goto-char (1- data-end))
+          (if (not (re-search-backward "\\(^[^ \t][^:]*\\):[ \t]*" nil t))
+              (setq data-begin (point-min))
+            (setq data-begin (match-end 0))
+            (setq field (match-string 1)))
+          (setq data-begin (max point data-begin))
+          (if (and field (mh-letter-skipped-header-field-p field))
+              (set-match-data nil)
+            (set-match-data (list data-begin data-end data-begin data-end)))
+          (goto-char (if (equal point data-end) (1+ data-end) data-end))
+          t)))
+ 
+ (defun mh-letter-header-end ()
+   "Find the end of the message header.
+ This function is to be used only for font locking. It works by searching for
+ `mh-mail-header-separator' in the buffer."
+   (save-excursion
+     (goto-char (point-min))
+     (cond ((equal mh-mail-header-separator "") (point-min))
+           ((search-forward (format "\n%s\n" mh-mail-header-separator) nil t)
+            (line-beginning-position 0))
+           (t (point-min)))))
+ 
+ (defun mh-auto-fill-for-letter ()
+   "Perform auto-fill for message.
+ Header is treated specially by inserting a tab before continuation lines."
+   (if (mh-in-header-p)
+       (let ((fill-prefix "\t"))
+         (do-auto-fill))
+     (do-auto-fill)))
+ 
+ (defun mh-insert-header-separator ()
+   "Insert `mh-mail-header-separator', if absent."
+   (save-excursion
+     (goto-char (point-min))
+     (rfc822-goto-eoh)
+     (if (looking-at "$")
+         (insert mh-mail-header-separator))))
+ 
+ ;;;###mh-autoload
+ (defun mh-to-field ()
+   "Move point to the end of a specified header field.
+ The field is indicated by the previous keystroke (the last keystroke
+ of the command) according to the list in the variable `mh-to-field-choices'.
+ Create the field if it does not exist.  Set the mark to point before moving."
+   (interactive)
+   (expand-abbrev)
+   (let ((target (cdr (or (assoc (char-to-string (logior last-input-char ?`))
+                                 mh-to-field-choices)
+                          ;; also look for a char for version 4 compat
+                          (assoc (logior last-input-char ?`)
+                                 mh-to-field-choices))))
+         (case-fold-search t))
+     (push-mark)
+     (cond ((mh-position-on-field target)
+            (let ((eol (point)))
+              (skip-chars-backward " \t")
+              (delete-region (point) eol))
+            (if (and (not (eq (logior last-input-char ?`) ?s))
+                     (save-excursion
+                       (backward-char 1)
+                       (not (looking-at "[:,]"))))
+                (insert ", ")
+              (insert " ")))
+           (t
+            (if (mh-position-on-field "To:")
+                (forward-line 1))
+            (insert (format "%s \n" target))
+            (backward-char 1)))))
+ 
+ ;;;###mh-autoload
+ (defun mh-to-fcc (&optional folder)
+   "Insert an Fcc: FOLDER field in the current message.
+ Prompt for the field name with a completion list of the current folders."
+   (interactive)
+   (or folder
+       (setq folder (mh-prompt-for-folder
+                     "Fcc"
+                     (or (and mh-default-folder-for-message-function
+                              (save-excursion
+                                (goto-char (point-min))
+                                (funcall
+                                 mh-default-folder-for-message-function)))
+                         "")
+                     t)))
+   (let ((last-input-char ?\C-f))
+     (expand-abbrev)
+     (save-excursion
+       (mh-to-field)
+       (insert (if (mh-folder-name-p folder)
+                   (substring folder 1)
+                 folder)))))
+ 
+ (defun mh-file-is-vcard-p (file)
+   "Return t if FILE is a .vcf vcard."
+   (let ((case-fold-search t))
+     (and (stringp file)
+          (file-exists-p file)
+          (or (and (not (mh-have-file-command))
+                   (not (null (string-match "\.vcf$" file))))
+              (and (mh-have-file-command)
+                   (string-equal "text/x-vcard" (mh-file-mime-type file)))))))
+ 
+ ;;;###mh-autoload
+ (defun mh-insert-signature (&optional file)
+   "Insert the signature specified by `mh-signature-file-name' or FILE at 
point.
+ A signature separator (`-- ') will be added if the signature block does not
+ contain one and `mh-signature-separator-flag' is on.
+ The value of `mh-letter-insert-signature-hook' is a list of functions to be
+ called, with no arguments, after the signature is inserted.
+ The signature can also be inserted with `mh-identity-list'."
+ (interactive)
+   (save-excursion
+     (insert "\n")
+     (let ((mh-signature-file-name (or file mh-signature-file-name))
+           (mh-mhn-p (mh-mhn-directive-present-p))
+           (mh-mml-p (mh-mml-directive-present-p)))
+       (save-restriction
+         (narrow-to-region (point) (point))
+         (cond
+          ((mh-file-is-vcard-p mh-signature-file-name)
+           (if (equal mh-compose-insertion 'gnus)
+               (insert "<#part type=\"text/x-vcard\" filename=\""
+                       mh-signature-file-name
+                       "\" disposition=inline description=VCard>\n<#/part>")
+             (insert "#text/x-vcard; name=\""
+                     (file-name-nondirectory mh-signature-file-name)
+                     "\" [VCard] " (expand-file-name mh-signature-file-name))))
+          (t
+           (cond
+            (mh-mhn-p
+             (insert "#\n" "Content-Description: Signature\n"))
+            (mh-mml-p
+             (mml-insert-tag 'part 'type "text/plain" 'disposition "inline"
+                             'description "Signature")))
+           (cond ((null mh-signature-file-name))
+                 ((and (stringp mh-signature-file-name)
+                       (file-readable-p mh-signature-file-name))
+                  (insert-file-contents mh-signature-file-name))
+                 ((functionp mh-signature-file-name)
+                  (funcall mh-signature-file-name)))))
+         (save-restriction
+           (widen)
+           (run-hooks 'mh-letter-insert-signature-hook))
+         (goto-char (point-min))
+         (when (and (not (mh-file-is-vcard-p mh-signature-file-name))
+                    mh-signature-separator-flag
+                    (> (point-max) (point-min))
+                    (not (mh-signature-separator-p)))
+           (cond (mh-mhn-p
+                  (forward-line 2))
+                 (mh-mml-p
+                  (forward-line 1)))
+           (insert mh-signature-separator))
+         (if (not (> (point-max) (point-min)))
+             (message "No signature found")))))
+   (force-mode-line-update))
+ 
+ ;;;###mh-autoload
+ (defun mh-check-whom ()
+   "Verify recipients of the current letter, showing expansion of any aliases."
+   (interactive)
+   (let ((file-name buffer-file-name))
+     (save-buffer)
+     (message "Checking recipients...")
+     (mh-in-show-buffer (mh-recipients-buffer)
+       (bury-buffer (current-buffer))
+       (erase-buffer)
+       (mh-exec-cmd-output "whom" t file-name))
+     (message "Checking recipients...done")))
+ 
+ (defun mh-tidy-draft-buffer ()
+   "Run when a draft buffer is destroyed."
+   (let ((buffer (get-buffer mh-recipients-buffer)))
+     (if buffer
+       (kill-buffer buffer))))
+ 
+ 
+ 
+ ;;; Routines to compose and send a letter.
+ 
+ (defun mh-insert-x-face ()
+   "Append X-Face, Face or X-Image-URL field to header.
+ If the field already exists, this function does nothing."
+   (when (and (file-exists-p mh-x-face-file)
+              (file-readable-p mh-x-face-file))
+     (save-excursion
+       (unless (or (mh-position-on-field "X-Face")
+                   (mh-position-on-field "Face")
+                   (mh-position-on-field "X-Image-URL"))
+         (save-excursion
+           (goto-char (+ (point) (cadr (insert-file-contents mh-x-face-file))))
+           (if (not (looking-at "^"))
+               (insert "\n")))
+         (unless (looking-at "\\(X-Face\\|Face\\|X-Image-URL\\): ")
+           (insert "X-Face: "))))))
+ 
+ (defvar mh-x-mailer-string nil
+   "*String containing the contents of the X-Mailer header field.
+ If nil, this variable is initialized to show the version of MH-E, Emacs, and
+ MH the first time a message is composed.")
+ 
+ (defun mh-insert-x-mailer ()
+   "Append an X-Mailer field to the header.
+ The versions of MH-E, Emacs, and MH are shown."
+   ;; Lazily initialize mh-x-mailer-string.
+   (when (and mh-insert-x-mailer-flag (null mh-x-mailer-string))
+     (setq mh-x-mailer-string
+           (format "MH-E %s; %s; %sEmacs %s"
+                   mh-version mh-variant-in-use
+                   (if mh-xemacs-flag "X" "GNU ")
+                   (cond ((not mh-xemacs-flag) emacs-version)
+                         ((string-match "[0-9.]*\\( +\([ a-z]+[0-9]+\)\\)?"
+                                        emacs-version)
+                          (match-string 0 emacs-version))
+                         (t (format "%s.%s" emacs-major-version
+                                    emacs-minor-version))))))
+   ;; Insert X-Mailer, but only if it doesn't already exist.
+   (save-excursion
+     (when (and mh-insert-x-mailer-flag
+                (null (mh-goto-header-field "X-Mailer")))
+       (mh-insert-fields "X-Mailer:" mh-x-mailer-string))))
+ 
+ (defun mh-regexp-in-field-p (regexp &rest fields)
+   "Non-nil means REGEXP was found in FIELDS."
+   (save-excursion
+     (let ((search-result nil)
+           (field))
+       (while fields
+         (setq field (car fields))
+         (if (and (mh-goto-header-field field)
+                  (re-search-forward
+                   regexp (save-excursion (mh-header-field-end)(point)) t))
+             (setq fields nil
+                   search-result t)
+           (setq fields (cdr fields))))
+       search-result)))
+ 
+ ;;;###mh-autoload
+ (defun mh-insert-auto-fields (&optional non-interactive)
+   "Insert custom fields if To or Cc match `mh-auto-fields-list'.
+ Sets buffer-local `mh-insert-auto-fields-done-local' when done and inserted
+ something.  If NON-INTERACTIVE is non-nil, do not be verbose and only
+ attempt matches if `mh-insert-auto-fields-done-local' is nil.
+ 
+ An `identity' entry is skipped if one was already entered manually.
+ 
+ Return t if fields added; otherwise return nil."
+   (interactive)
+   (when (or (not non-interactive)
+             (not mh-insert-auto-fields-done-local))
+     (save-excursion
+       (when (and (or (mh-goto-header-field "To:")
+                      (mh-goto-header-field "cc:")))
+         (let ((list mh-auto-fields-list)
+               (fields-inserted nil))
+           (while list
+             (let ((regexp (nth 0 (car list)))
+                   (entries (nth 1 (car list))))
+               (when (mh-regexp-in-field-p regexp "To:" "cc:")
+                 (setq mh-insert-auto-fields-done-local t)
+                 (setq fields-inserted t)
+                 (if (not non-interactive)
+                     (message "Fields for %s added" regexp))
+                 (let ((entry-list entries))
+                   (while entry-list
+                     (let ((field (caar entry-list))
+                           (value (cdar entry-list)))
+                       (cond
+                        ((equal ":identity" field)
+                         (when (and (not mh-identity-local)
+                                    (assoc value mh-identity-list))
+                           (mh-insert-identity value)))
+                        (t
+                         (mh-modify-header-field field value
+                                                 (equal field "From")))))
+                     (setq entry-list (cdr entry-list))))))
+             (setq list (cdr list)))
+           fields-inserted)))))
+ 
+ (defun mh-modify-header-field (field value &optional overwrite-flag)
+   "To header FIELD add VALUE.
+ If OVERWRITE-FLAG is non-nil then the old value, if present, is discarded."
+   (cond ((and overwrite-flag
+               (mh-goto-header-field (concat field ":")))
+          (insert " " value)
+          (delete-region (point) (line-end-position)))
+         ((and (not overwrite-flag)
+               (mh-regexp-in-field-p (concat "\\b" value "\\b") field))
+          ;; Already there, do nothing.
+          )
+         ((and (not overwrite-flag)
+               (mh-goto-header-field (concat field ":")))
+          (insert " " value ","))
+         (t
+          (mh-goto-header-end 0)
+          (insert field ": " value "\n"))))
+ 
+ (defun mh-compose-and-send-mail (draft send-args
+                                        sent-from-folder sent-from-msg
+                                        to subject cc
+                                        annotate-char annotate-field
+                                        config)
+   "Edit and compose a draft message in buffer DRAFT and send or save it.
+ SEND-ARGS is the argument passed to the send command.
+ SENT-FROM-FOLDER is buffer containing scan listing of current folder, or
+ nil if none exists.
+ SENT-FROM-MSG is the message number or sequence name or nil.
+ The TO, SUBJECT, and CC fields are passed to the
+ `mh-compose-letter-function'.
+ If ANNOTATE-CHAR is non-null, it is used to notate the scan listing of the
+ message.  In that case, the ANNOTATE-FIELD is used to build a string
+ for `mh-annotate-msg'.
+ CONFIG is the window configuration to restore after sending the letter."
+   (pop-to-buffer draft)
+   (mh-letter-mode)
+ 
+   ;; Insert identity.
+   (if (and (boundp 'mh-identity-default)
+            mh-identity-default
+            (not mh-identity-local))
+       (mh-insert-identity mh-identity-default))
+   (mh-identity-make-menu)
+   (easy-menu-add mh-identity-menu)
+ 
+   ;; Insert extra fields.
+   (mh-insert-x-mailer)
+   (mh-insert-x-face)
+ 
+   (mh-letter-hide-all-skipped-fields)
+ 
+   (setq mh-sent-from-folder sent-from-folder)
+   (setq mh-sent-from-msg sent-from-msg)
+   (setq mh-send-args send-args)
+   (setq mh-annotate-char annotate-char)
+   (setq mh-annotate-field annotate-field)
+   (setq mh-previous-window-config config)
+   (setq mode-line-buffer-identification (list "    {%b}"))
+   (mh-logo-display)
+   (mh-make-local-hook 'kill-buffer-hook)
+   (add-hook 'kill-buffer-hook 'mh-tidy-draft-buffer nil t)
+   (if (and (boundp 'mh-compose-letter-function)
+            mh-compose-letter-function)
+       ;; run-hooks will not pass arguments.
+       (let ((value mh-compose-letter-function))
+         (if (and (listp value) (not (eq (car value) 'lambda)))
+             (while value
+               (funcall (car value) to subject cc)
+               (setq value (cdr value)))
+           (funcall mh-compose-letter-function to subject cc)))))
+ 
+ (defun mh-letter-mode-message ()
+   "Display a help message for users of `mh-letter-mode'.
+ This should be the last function called when composing the draft."
+   (message "%s" (substitute-command-keys
+                  (concat "Type \\[mh-send-letter] to send message, "
+                          "\\[mh-help] for help"))))
+ 
+ (defun mh-ascii-buffer-p ()
+   "Check if current buffer is entirely composed of ASCII.
+ The function doesn't work for XEmacs since `find-charset-region' doesn't exist
+ there."
+   (loop for charset in (mh-funcall-if-exists
+                         find-charset-region (point-min) (point-max))
+         unless (eq charset 'ascii) return nil
+         finally return t))
+ 
+ ;;;###mh-autoload
+ (defun mh-send-letter (&optional arg)
+   "Send the draft letter in the current buffer.
+ If optional prefix argument ARG is provided, monitor delivery.
+ The value of `mh-before-send-letter-hook' is a list of functions to be called,
+ with no arguments, before doing anything.
+ Run `\\[mh-edit-mhn]' if mhn directives are present; otherwise
+ run `\\[mh-mml-to-mime]' if mml directives are present."
+   (interactive "P")
+   (run-hooks 'mh-before-send-letter-hook)
+   (if (and (mh-insert-auto-fields t)
+            mh-auto-fields-prompt-flag
+            (goto-char (point-min)))
+       (if (not (y-or-n-p "Auto fields inserted, send? "))
+           (error "Send aborted")))
+   (cond ((mh-mhn-directive-present-p)
+          (mh-edit-mhn))
+         ((or (mh-mml-directive-present-p) (not (mh-ascii-buffer-p)))
+          (mh-mml-to-mime)))
+   (save-buffer)
+   (message "Sending...")
+   (let ((draft-buffer (current-buffer))
+         (file-name buffer-file-name)
+         (config mh-previous-window-config)
+         (coding-system-for-write
+          (if (and (local-variable-p 'buffer-file-coding-system
+                                     (current-buffer)) ;XEmacs needs two args
+                   ;; We're not sure why, but buffer-file-coding-system
+                   ;; tends to get set to undecided-unix.
+                   (not (memq buffer-file-coding-system
+                              '(undecided undecided-unix undecided-dos))))
+              buffer-file-coding-system
+            (or (and (boundp 'sendmail-coding-system) sendmail-coding-system)
+                (and (boundp 'default-buffer-file-coding-system )
+                     default-buffer-file-coding-system)
+                'iso-latin-1))))
+     ;; The default BCC encapsulation will make a MIME message unreadable.
+     ;; With nmh use the -mime arg to prevent this.
+     (if (and (mh-variant-p 'nmh)
+              (mh-goto-header-field "Bcc:")
+              (mh-goto-header-field "Content-Type:"))
+         (setq mh-send-args (format "-mime %s" mh-send-args)))
+     (cond (arg
+            (pop-to-buffer mh-mail-delivery-buffer)
+            (erase-buffer)
+            (mh-exec-cmd-output mh-send-prog t "-watch" "-nopush"
+                                "-nodraftfolder" mh-send-args file-name)
+            (goto-char (point-max))      ; show the interesting part
+            (recenter -1)
+            (set-buffer draft-buffer))   ; for annotation below
+           (t
+            (mh-exec-cmd-daemon mh-send-prog nil "-nodraftfolder" "-noverbose"
+                                mh-send-args file-name)))
+     (if mh-annotate-char
+         (mh-annotate-msg mh-sent-from-msg
+                          mh-sent-from-folder
+                          mh-annotate-char
+                          "-component" mh-annotate-field
+                          "-text" (format "\"%s %s\""
+                                          (mh-get-header-field "To:")
+                                          (mh-get-header-field "Cc:"))))
+ 
+     (cond ((or (not arg)
+                (y-or-n-p "Kill draft buffer? "))
+            (kill-buffer draft-buffer)
+            (if config
+                (set-window-configuration config))))
+     (if arg
+         (message "Sending...done")
+       (message "Sending...backgrounded"))))
+ 
+ ;;;###mh-autoload
+ (defun mh-insert-letter (folder message verbatim)
+   "Insert a message into the current letter.
+ Removes the header fields according to the variable
+ `mh-invisible-header-fields-compiled'.
+ Prefixes each non-blank line with `mh-ins-buf-prefix', unless
+ `mh-yank-from-start-of-msg' is set for supercite in which case supercite is
+ used to format the message.
+ Prompts for FOLDER and MESSAGE.  If prefix argument VERBATIM provided, do
+ not indent and do not delete headers.  Leaves the mark before the letter
+ and point after it."
+   (interactive
+    (list (mh-prompt-for-folder "Message from" mh-sent-from-folder nil)
+          (read-input (format "Message number%s: "
+                              (if (numberp mh-sent-from-msg)
+                                  (format " [%d]" mh-sent-from-msg)
+                                "")))
+          current-prefix-arg))
+   (save-restriction
+     (narrow-to-region (point) (point))
+     (let ((start (point-min)))
+       (if (and (equal message "") (numberp mh-sent-from-msg))
+           (setq message (int-to-string mh-sent-from-msg)))
+       (insert-file-contents
+        (expand-file-name message (mh-expand-file-name folder)))
+       (when (not verbatim)
+         (mh-clean-msg-header start mh-invisible-header-fields-compiled nil)
+         (goto-char (point-max))         ;Needed for sc-cite-original
+         (push-mark)                     ;Needed for sc-cite-original
+         (goto-char (point-min))         ;Needed for sc-cite-original
+         (mh-insert-prefix-string mh-ins-buf-prefix)))))
+ 
+ (defun mh-extract-from-attribution ()
+   "Extract phrase or comment from From header field."
+   (save-excursion
+     (if (not (mh-goto-header-field "From: "))
+         nil
+       (skip-chars-forward " ")
+       (cond
+        ((looking-at "\"\\([^\"\n]+\\)\" \\(<.+>\\)")
+         (format "%s %s " (match-string 1)(match-string 2)))
+        ((looking-at "\\([^<\n]+<.+>\\)$")
+         (format "%s " (match-string 1)))
+        ((looking-at "\\([^ address@hidden ]+\\) +(\\(.+\\))$")
+         (format "%s <%s> " (match-string 2)(match-string 1)))
+        ((looking-at " *\\(.+\\)$")
+         (format "%s " (match-string 1)))))))
+ 
+ ;;;###mh-autoload
+ (defun mh-yank-cur-msg ()
+   "Insert the current message into the draft buffer.
+ Prefix each non-blank line in the message with the string in
+ `mh-ins-buf-prefix'.  If a region is set in the message's buffer, then
+ only the region will be inserted.  Otherwise, the entire message will
+ be inserted if `mh-yank-from-start-of-msg' is non-nil.  If this variable
+ is nil, the portion of the message following the point will be yanked.
+ If `mh-delete-yanked-msg-window-flag' is non-nil, any window displaying the
+ yanked message will be deleted."
+   (interactive)
+   (if (and mh-sent-from-folder
+            (save-excursion (set-buffer mh-sent-from-folder) mh-show-buffer)
+            (save-excursion (set-buffer mh-sent-from-folder)
+                            (get-buffer mh-show-buffer))
+            mh-sent-from-msg)
+       (let ((to-point (point))
+             (to-buffer (current-buffer)))
+         (set-buffer mh-sent-from-folder)
+         (if mh-delete-yanked-msg-window-flag
+             (delete-windows-on mh-show-buffer))
+         (set-buffer mh-show-buffer)     ; Find displayed message
+         (let* ((from-attr (mh-extract-from-attribution))
+                (yank-region (mh-mark-active-p nil))
+                (mh-ins-str
+                 (cond ((and yank-region
+                             (or (eq 'supercite mh-yank-from-start-of-msg)
+                                 (eq 'autosupercite mh-yank-from-start-of-msg)
+                                 (eq t mh-yank-from-start-of-msg)))
+                        ;; supercite needs the full header
+                        (concat
+                         (buffer-substring (point-min) (mh-mail-header-end))
+                         "\n"
+                         (buffer-substring (region-beginning) (region-end))))
+                       (yank-region
+                        (buffer-substring (region-beginning) (region-end)))
+                       ((or (eq 'body mh-yank-from-start-of-msg)
+                            (eq 'attribution
+                                mh-yank-from-start-of-msg)
+                            (eq 'autoattrib
+                                mh-yank-from-start-of-msg))
+                        (buffer-substring
+                         (save-excursion
+                           (goto-char (point-min))
+                           (mh-goto-header-end 1)
+                           (point))
+                         (point-max)))
+                       ((or (eq 'supercite mh-yank-from-start-of-msg)
+                            (eq 'autosupercite mh-yank-from-start-of-msg)
+                            (eq t mh-yank-from-start-of-msg))
+                        (buffer-substring (point-min) (point-max)))
+                       (t
+                        (buffer-substring (point) (point-max))))))
+           (set-buffer to-buffer)
+           (save-restriction
+             (narrow-to-region to-point to-point)
+             (insert (mh-filter-out-non-text mh-ins-str))
+             (goto-char (point-max))     ;Needed for sc-cite-original
+             (push-mark)                 ;Needed for sc-cite-original
+             (goto-char (point-min))     ;Needed for sc-cite-original
+             (mh-insert-prefix-string mh-ins-buf-prefix)
+             (when (or (eq 'attribution mh-yank-from-start-of-msg)
+                       (eq 'autoattrib mh-yank-from-start-of-msg))
+               (insert from-attr)
+               (mh-identity-insert-attribution-verb nil)
+               (insert "\n\n"))
+             ;; If the user has selected a region, he has already "edited" the
+             ;; text, so leave the cursor at the end of the yanked text. In
+             ;; either case, leave a mark at the opposite end of the included
+             ;; text to make it easy to jump or delete to the other end of the
+             ;; text.
+             (push-mark)
+             (goto-char (point-max))
+             (if (null yank-region)
+                 (mh-exchange-point-and-mark-preserving-active-mark)))))
+     (error "There is no current message")))
+ 
+ (defun mh-filter-out-non-text (string)
+   "Return STRING but without adornments such as MIME buttons and smileys."
+   (with-temp-buffer
+     ;; Insert the string to filter
+     (insert string)
+     (goto-char (point-min))
+ 
+     ;; Remove the MIME buttons
+     (let ((can-move-forward t)
+           (in-button nil))
+       (while can-move-forward
+         (cond ((and (not (get-text-property (point) 'mh-data))
+                     in-button)
+                (delete-region (1- (point)) (point))
+                (setq in-button nil))
+               ((get-text-property (point) 'mh-data)
+                (delete-region (point)
+                               (save-excursion (forward-line) (point)))
+                (setq in-button t))
+               (t (setq can-move-forward (= (forward-line) 0))))))
+ 
+     ;; Return the contents without properties... This gets rid of emphasis
+     ;; and smileys
+     (buffer-substring-no-properties (point-min) (point-max))))
+ 
+ (defun mh-insert-prefix-string (mh-ins-string)
+   "Insert prefix string before each line in buffer.
+ The inserted letter is cited using `sc-cite-original' if
+ `mh-yank-from-start-of-msg' is one of 'supercite or 'autosupercite. Otherwise,
+ simply insert MH-INS-STRING before each line."
+   (goto-char (point-min))
+   (cond ((or (eq mh-yank-from-start-of-msg 'supercite)
+              (eq mh-yank-from-start-of-msg 'autosupercite))
+          (sc-cite-original))
+         (mail-citation-hook
+          (run-hooks 'mail-citation-hook))
+         (mh-yank-hooks                  ;old hook name
+          (run-hooks 'mh-yank-hooks))
+         (t
+          (or (bolp) (forward-line 1))
+          (while (< (point) (point-max))
+            (insert mh-ins-string)
+            (forward-line 1))
+          (goto-char (point-min)))))     ;leave point like sc-cite-original
+ 
+ ;;;###mh-autoload
+ (defun mh-fully-kill-draft ()
+   "Kill the draft message file and the draft message buffer.
+ Use \\[kill-buffer] if you don't want to delete the draft message file."
+   (interactive)
+   (if (y-or-n-p "Kill draft message? ")
+       (let ((config mh-previous-window-config))
+         (if (file-exists-p buffer-file-name)
+             (delete-file buffer-file-name))
+         (set-buffer-modified-p nil)
+         (kill-buffer (buffer-name))
+         (message "")
+         (if config
+             (set-window-configuration config)))
+     (error "Message not killed")))
+ 
+ (defun mh-current-fill-prefix ()
+   "Return the `fill-prefix' on the current line as a string."
+   (save-excursion
+     (beginning-of-line)
+     ;; This assumes that the major-mode sets up adaptive-fill-regexp
+     ;; correctly such as mh-letter-mode or sendmail.el's mail-mode.  But
+     ;; perhaps I should use the variable and simply inserts its value here,
+     ;; and set it locally in a let scope.  --psg
+     (if (re-search-forward adaptive-fill-regexp nil t)
+         (match-string 0)
+       "")))
+ 
+ ;;;###mh-autoload
+ (defun mh-open-line ()
+   "Insert a newline and leave point after it.
+ In addition, insert newline and quoting characters before text after point.
+ This is useful in breaking up paragraphs in replies."
+   (interactive)
+   (let ((column (current-column))
+         (prefix (mh-current-fill-prefix)))
+     (if (> (length prefix) column)
+         (message "Sorry, point seems to be within the line prefix")
+       (newline 2)
+       (insert prefix)
+       (while (> column (current-column))
+         (insert " "))
+       (forward-line -1))))
+ 
+ (mh-do-in-xemacs (defvar mail-abbrevs))
+ 
+ ;;;###mh-autoload
+ (defun mh-complete-word (word choices begin end)
+   "Complete WORD at from CHOICES.
+ Any match found replaces the text from BEGIN to END."
+   (let ((completion (try-completion word choices)))
+     (cond ((eq completion t)
+            (message "Completed: %s" word))
+           ((null completion)
+            (message "No completion for `%s'" word))
+           ((stringp completion)
+            (if (equal word completion)
+                (with-output-to-temp-buffer "*Completions*"
+                  (display-completion-list (all-completions word choices)))
+              (delete-region begin end)
+              (insert completion))))))
+ 
+ ;;;###mh-autoload
+ (defun mh-beginning-of-word (&optional n)
+   "Return position of the N th word backwards."
+   (unless n (setq n 1))
+   (let ((syntax-table (syntax-table)))
+     (unwind-protect
+         (save-excursion
+           (mh-mail-abbrev-make-syntax-table)
+           (set-syntax-table mail-abbrev-syntax-table)
+           (backward-word n)
+           (point))
+       (set-syntax-table syntax-table))))
+ 
+ (defun mh-folder-expand-at-point ()
+   "Do folder name completion in Fcc header field."
+   (let* ((end (point))
+          (beg (mh-beginning-of-word))
+          (folder (buffer-substring beg end))
+          (leading-plus (and (> (length folder) 0) (equal (aref folder 0) ?+)))
+          (last-slash (mh-search-from-end ?/ folder))
+          (prefix (and last-slash (substring folder 0 last-slash)))
+          (choices (mapcar #'(lambda (x)
+                               (list (cond (prefix (format "%s/%s" prefix x))
+                                           (leading-plus (format "+%s" x))
+                                           (t x))))
+                           (mh-folder-completion-function folder nil t))))
+     (mh-complete-word folder choices beg end)))
+ 
+ (defvar mh-letter-complete-function-alist
+   '((cc . mh-alias-letter-expand-alias)
+     (bcc . mh-alias-letter-expand-alias)
+     (dcc . mh-alias-letter-expand-alias)
+     (fcc . mh-folder-expand-at-point)
+     (from . mh-alias-letter-expand-alias)
+     (mail-followup-to . mh-alias-letter-expand-alias)
+     (reply-to . mh-alias-letter-expand-alias)
+     (to . mh-alias-letter-expand-alias))
+   "Alist of header fields and completion functions to use.")
+ 
+ (defun mh-letter-complete (arg)
+   "Perform completion on header field or word preceding point.
+ If the field contains addresses (for example, `To:' or `Cc:') or folders (for
+ example, `Fcc:') then this function will provide alias completion. Elsewhere,
+ this function runs `mh-letter-complete-function' instead and passes the prefix
+ ARG, if present."
+   (interactive "P")
+   (let ((func nil))
+     (cond ((not (mh-in-header-p))
+            (funcall mh-letter-complete-function arg))
+           ((setq func (cdr (assoc (mh-letter-header-field-at-point)
+                                   mh-letter-complete-function-alist)))
+            (funcall func))
+           (t (funcall mh-letter-complete-function arg)))))
+ 
+ (defun mh-letter-complete-or-space (arg)
+   "Perform completion or insert space.
+ If `mh-compose-space-does-completion-flag' is nil (the default) a space is
+ inserted.
+ 
+ Otherwise, if point is in the message header and the preceding character is
+ not whitespace then do completion. Otherwise insert a space character.
+ 
+ ARG is the number of spaces inserted."
+   (interactive "p")
+   (let ((func nil)
+         (end-of-prev (save-excursion
+                        (goto-char (mh-beginning-of-word))
+                        (mh-beginning-of-word -1))))
+     (cond ((not mh-compose-space-does-completion-flag)
+            (self-insert-command arg))
+           ((not (mh-in-header-p)) (self-insert-command arg))
+           ((> (point) end-of-prev) (self-insert-command arg))
+           ((setq func (cdr (assoc (mh-letter-header-field-at-point)
+                                   mh-letter-complete-function-alist)))
+            (funcall func))
+           (t (self-insert-command arg)))))
+ 
+ (defun mh-letter-confirm-address ()
+   "Flash alias expansion if `mh-alias-flash-on-comma' is non-nil."
+   (interactive)
+   (cond ((not (mh-in-header-p)) (self-insert-command 1))
+         ((eq (cdr (assoc (mh-letter-header-field-at-point)
+                          mh-letter-complete-function-alist))
+              'mh-alias-letter-expand-alias)
+          (mh-alias-reload-maybe)
+          (mh-alias-minibuffer-confirm-address))
+         (t (self-insert-command 1))))
+ 
+ (defvar mh-letter-header-field-regexp "^\\([A-Za-z][A-Za-z0-9-]*\\):")
+ 
+ (defun mh-letter-header-field-at-point ()
+   "Return the header field name at point.
+ A symbol is returned whose name is the string obtained by downcasing the field
+ name."
+   (save-excursion
+     (end-of-line)
+     (and (re-search-backward mh-letter-header-field-regexp nil t)
+          (intern (downcase (match-string 1))))))
+ 
+ ;;;###mh-autoload
+ (defun mh-letter-next-header-field-or-indent (arg)
+   "Move to next field or indent depending on point.
+ In the message header, go to the next field. Elsewhere call
+ `indent-relative' as usual with optional prefix ARG."
+   (interactive "P")
+   (let ((header-end (save-excursion
+                       (goto-char (mh-mail-header-end))
+                       (forward-line)
+                       (point))))
+     (if (> (point) header-end)
+         (indent-relative arg)
+       (mh-letter-next-header-field))))
+ 
+ (defun mh-letter-next-header-field ()
+   "Cycle to the next header field.
+ If we are at the last header field go to the start of the message body."
+   (let ((header-end (mh-mail-header-end)))
+     (cond ((>= (point) header-end) (goto-char (point-min)))
+           ((< (point) (progn
+                         (beginning-of-line)
+                         (re-search-forward mh-letter-header-field-regexp
+                                            (line-end-position) t)
+                         (point)))
+            (beginning-of-line))
+           (t (end-of-line)))
+     (cond ((re-search-forward mh-letter-header-field-regexp header-end t)
+            (if (mh-letter-skipped-header-field-p (match-string 1))
+                (mh-letter-next-header-field)
+              (mh-letter-skip-leading-whitespace-in-header-field)))
+           (t (goto-char header-end)
+              (forward-line)))))
+ 
+ ;;;###mh-autoload
+ (defun mh-letter-previous-header-field ()
+   "Cycle to the previous header field.
+ If we are at the first header field go to the start of the message body."
+   (interactive)
+   (let ((header-end (mh-mail-header-end)))
+     (if (>= (point) header-end)
+         (goto-char header-end)
+       (mh-header-field-beginning))
+     (cond ((re-search-backward mh-letter-header-field-regexp nil t)
+            (if (mh-letter-skipped-header-field-p (match-string 1))
+                (mh-letter-previous-header-field)
+            (goto-char (match-end 0))
+            (mh-letter-skip-leading-whitespace-in-header-field)))
+           (t (goto-char header-end)
+              (forward-line)))))
+ 
+ (defun mh-letter-skipped-header-field-p (field)
+   "Check if FIELD is to be skipped."
+   (let ((field (downcase field)))
+     (loop for x in mh-compose-skipped-header-fields
+           when (equal (downcase x) field) return t
+           finally return nil)))
+ 
+ (defun mh-letter-skip-leading-whitespace-in-header-field ()
+   "Skip leading whitespace in a header field.
+ If the header field doesn't have at least one space after the colon then a
+ space character is added."
+   (let ((need-space t))
+     (while (memq (char-after) '(?\t ?\ ))
+       (forward-char)
+       (setq need-space nil))
+     (when need-space (insert " "))))
+ 
+ (defvar mh-hidden-header-keymap
+   (let ((map (make-sparse-keymap)))
+     (mh-do-in-gnu-emacs
+       (define-key map [mouse-2] 
'mh-letter-toggle-header-field-display-button))
+     (mh-do-in-xemacs
+       (define-key map '(button2)
+         'mh-letter-toggle-header-field-display-button))
+     map))
+ 
+ (defun mh-letter-toggle-header-field-display-button (event)
+   "Toggle header field display at location of EVENT.
+ This function does the same thing as `mh-letter-toggle-header-field-display'
+ except that it is callable from a mouse button."
+   (interactive "e")
+   (mh-do-at-event-location event
+     (mh-letter-toggle-header-field-display nil)))
+ 
+ (defun mh-letter-toggle-header-field-display (arg)
+   "Toggle display of header field at point.
+ If the header is long or spread over multiple lines then hiding it will show
+ the first few characters and replace the rest with an ellipsis.
+ 
+ If ARG is negative then header is hidden, if positive it is displayed. If ARG
+ is the symbol `long' then keep at most the first 4 lines."
+   (interactive (list nil))
+   (when (and (mh-in-header-p)
+              (progn
+                (end-of-line)
+                (re-search-backward mh-letter-header-field-regexp nil t)))
+     (let ((buffer-read-only nil)
+           (modified-flag (buffer-modified-p))
+           (begin (point))
+           end)
+       (end-of-line)
+       (setq end (1- (if (re-search-forward "^[^ \t]" nil t)
+                         (match-beginning 0)
+                       (point-max))))
+       (goto-char begin)
+       ;; Make it clickable...
+       (add-text-properties begin end `(keymap ,mh-hidden-header-keymap
+                                        mouse-face highlight))
+       (unwind-protect
+           (cond ((or (and (not arg)
+                           (text-property-any begin end 'invisible 'vanish))
+                      (and (numberp arg) (>= arg 0))
+                      (and (eq arg 'long) (> (line-beginning-position 5) end)))
+                  (remove-text-properties begin end '(invisible nil))
+                  (search-forward ":" (line-end-position) t)
+                  (mh-letter-skip-leading-whitespace-in-header-field))
+                 ((eq arg 'long)
+                  (end-of-line 4)
+                  (mh-letter-truncate-header-field end)
+                  (beginning-of-line))
+                 (t (end-of-line)
+                    (mh-letter-truncate-header-field end)
+                    (beginning-of-line)))
+         (set-buffer-modified-p modified-flag)))))
+ 
+ (defun mh-letter-truncate-header-field (end)
+   "Replace text from current line till END with an ellipsis.
+ If the current line is too long truncate a part of it as well."
+   (let ((max-len (min (window-width) 62)))
+     (when (> (+ (current-column) 4) max-len)
+       (backward-char (- (+ (current-column) 5) max-len)))
+     (when (> end (point))
+       (add-text-properties (point) end '(invisible vanish)))))
+ 
+ (defun mh-letter-hide-all-skipped-fields ()
+   "Hide all skipped fields."
+   (save-excursion
+     (goto-char (point-min))
+     (save-restriction
+       (narrow-to-region (point) (mh-mail-header-end))
+       (while (re-search-forward mh-letter-header-field-regexp nil t)
+         (if (mh-letter-skipped-header-field-p (match-string 1))
+             (mh-letter-toggle-header-field-display -1)
+           (mh-letter-toggle-header-field-display 'long))
+         (beginning-of-line 2)))))
+ 
+ (defun mh-interactive-read-address (prompt)
+   "Read an address.
+ If `mh-compose-prompt-flag' is non-nil, then read an address with PROMPT.
+ Otherwise return the empty string."
+   (if mh-compose-prompt-flag (mh-read-address prompt) ""))
+ 
+ (defun mh-interactive-read-string (prompt)
+   "Read a string.
+ If `mh-compose-prompt-flag' is non-nil, then read a string with PROMPT.
+ Otherwise return the empty string."
+   (if mh-compose-prompt-flag (read-string prompt) ""))
+ 
+ (defun mh-letter-adjust-point ()
+   "Move cursor to first header field if are using the no prompt mode."
+   (unless mh-compose-prompt-flag
+     (goto-char (point-max))
+     (mh-letter-next-header-field)))
+ 
+ ;;; Build the letter-mode keymap:
+ ;;; If this changes, modify mh-letter-mode-help-messages accordingly, above.
+ (gnus-define-keys  mh-letter-mode-map
+   " "                   mh-letter-complete-or-space
+   ","                   mh-letter-confirm-address
+   "\C-c?"               mh-help
+   "\C-c\C-\\"           mh-fully-kill-draft ;if no C-q
+   "\C-c\C-^"            mh-insert-signature ;if no C-s
+   "\C-c\C-c"            mh-send-letter
+   "\C-c\C-d"            mh-insert-identity
+   "\C-c\C-e"            mh-edit-mhn
+   "\C-c\C-f\C-b"        mh-to-field
+   "\C-c\C-f\C-c"        mh-to-field
+   "\C-c\C-f\C-d"        mh-to-field
+   "\C-c\C-f\C-f"        mh-to-fcc
+   "\C-c\C-f\C-r"        mh-to-field
+   "\C-c\C-f\C-s"        mh-to-field
+   "\C-c\C-f\C-t"        mh-to-field
+   "\C-c\C-fb"           mh-to-field
+   "\C-c\C-fc"           mh-to-field
+   "\C-c\C-fd"           mh-to-field
+   "\C-c\C-ff"           mh-to-fcc
+   "\C-c\C-fr"           mh-to-field
+   "\C-c\C-fs"           mh-to-field
+   "\C-c\C-ft"           mh-to-field
+   "\C-c\C-i"            mh-insert-letter
+   "\C-c\C-m\C-e"        mh-mml-secure-message-encrypt
+   "\C-c\C-m\C-f"        mh-compose-forward
+   "\C-c\C-m\C-g"        mh-mhn-compose-anon-ftp
+   "\C-c\C-m\C-i"        mh-compose-insertion
+   "\C-c\C-m\C-m"        mh-mml-to-mime
+   "\C-c\C-m\C-n"        mh-mml-unsecure-message
+   "\C-c\C-m\C-s"        mh-mml-secure-message-sign
+   "\C-c\C-m\C-t"        mh-mhn-compose-external-compressed-tar
+   "\C-c\C-m\C-u"        mh-revert-mhn-edit
+   "\C-c\C-m\C-x"        mh-mhn-compose-external-type
+   "\C-c\C-mee"          mh-mml-secure-message-encrypt
+   "\C-c\C-mes"          mh-mml-secure-message-signencrypt
+   "\C-c\C-mf"           mh-compose-forward
+   "\C-c\C-mg"           mh-mhn-compose-anon-ftp
+   "\C-c\C-mi"           mh-compose-insertion
+   "\C-c\C-mm"           mh-mml-to-mime
+   "\C-c\C-mn"           mh-mml-unsecure-message
+   "\C-c\C-mse"          mh-mml-secure-message-signencrypt
+   "\C-c\C-mss"          mh-mml-secure-message-sign
+   "\C-c\C-mt"           mh-mhn-compose-external-compressed-tar
+   "\C-c\C-mu"           mh-revert-mhn-edit
+   "\C-c\C-mx"           mh-mhn-compose-external-type
+   "\C-c\C-o"            mh-open-line
+   "\C-c\C-q"            mh-fully-kill-draft
+   "\C-c\C-s"            mh-insert-signature
+   "\C-c\C-t"            mh-letter-toggle-header-field-display
+   "\C-c\C-w"            mh-check-whom
+   "\C-c\C-y"            mh-yank-cur-msg
+   "\C-c\M-d"            mh-insert-auto-fields
+   "\M-\t"               mh-letter-complete
+   "\t"                  mh-letter-next-header-field-or-indent
+   [backtab]             mh-letter-previous-header-field)
+ 
+ ;; "C-c /" prefix is used in mh-letter-mode by pgp.el and mailcrypt.el.
+ 
+ ;;;###autoload(add-to-list 'auto-mode-alist '("/drafts/[0-9]+\\'" . 
mh-letter-mode))
+ 
+ (provide 'mh-comp)
+ 
+ ;;; Local Variables:
+ ;;; indent-tabs-mode: nil
+ ;;; sentence-end-double-space: nil
+ ;;; End:
+ 
+ ;;; arch-tag: 62865511-e610-4923-b0b5-f45a8ab70a34
+ ;;; mh-comp.el ends here




reply via email to

[Prev in Thread] Current Thread [Next in Thread]