X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/53b0a6f88893036a42db2abcfbc257b68906956e..3b7f63b13fde224c5b0cf76a9dea51e820f1d93e:/lisp/mh-e.el diff --git a/lisp/mh-e.el b/lisp/mh-e.el index 83ad285090..619556d260 100644 --- a/lisp/mh-e.el +++ b/lisp/mh-e.el @@ -1,15 +1,12 @@ -;;; mh-e.el --- GNU Emacs interface to the MH mailer +;;; mh-e.el --- GNU Emacs interface to the MH mail system -;;; (Version: 3.7 for GNU Emacs Version 18 and MH.5 and MH.6) +;;; Copyright (C) 1985, 86, 87, 88, 90, 92, 93 Free Software Foundation -(defvar mh-e-RCS-id) -(setq mh-e-RCS-id "$Header: /var/home/larus/lib/emacs/RCS/mh-e.el,v 3.1 90/09/28 15:47:58 larus Exp Locker: larus $") -;;; Copyright (C) 1985-89 Free Software Foundation -;;; Author: James Larus (larus@ginger.Berkeley.EDU or ucbvax!larus) -;;; Please send suggestions and corrections to the above address. -;;; -;;; This file contains mh-e, a GNU Emacs front end to the MH mail system. +(defconst mh-e-time-stamp "Time-stamp: <93/05/30 18:37:43 gildea>") +;; Maintainer: Stephen Gildea +;; Version: 3.8.2 +;; Keywords: mail ;; GNU Emacs is distributed in the hope that it will be useful, ;; but without any warranty. No author or distributor @@ -25,16 +22,35 @@ ;; It should be in a file named COPYING. Among other things, the ;; copyright notice and this notice must be preserved on all copies. +;;; Commentary: -;;; Original version for Gosling emacs by Brian Reid, Stanford, 1982. -;;; Modified by James Larus, BBN, July 1984 and UCB, 1984 & 1985. -;;; Rewritten for GNU Emacs, James Larus 1985. larus@ginger.berkeley.edu -;;; Modified by Stephen Gildea 1988. gildea@bbn.com +;;; mh-e works with Emacs 18 or 19, and MH 5 or 6. +;;; HOW TO USE: +;;; M-x mh-rmail to read mail. Type C-h m there for a list of commands. +;;; C-u M-x mh-rmail to visit any folder. +;;; M-x mh-smail to send mail. From within the mail reader, "m" works, too. +;;; Your .emacs might benefit from these bindings: +;;; (global-set-key "\C-xm" 'mh-smail) +;;; (global-set-key "\C-x4m" 'mh-smail-other-window) +;;; (global-set-key "\C-cr" 'mh-rmail) -;;; NB. MH must have been compiled with the MHE compiler flag or several -;;; features necessary mh-e will be missing from MH commands, specifically -;;; the -build switch to repl and forw. +;;; MH (Message Handler) is a powerful mail reader. The MH newsgroup +;;; is comp.mail.mh; the mailing list is mh-users@ics.uci.edu (send to +;;; mh-users-request to be added). See the monthly Frequently Asked +;;; Questions posting there for information on getting MH. + +;;; NB. MH must have been compiled with the MHE compiler flag or several +;;; features necessary mh-e will be missing from MH commands, specifically +;;; the -build switch to repl and forw. + +;;; Original version for Gosling emacs by Brian Reid, Stanford, 1982. +;;; Modified by James Larus, BBN, July 1984 and UCB, 1984 & 1985. +;;; Rewritten for GNU Emacs, James Larus 1985. larus@ginger.berkeley.edu +;;; Modified by Stephen Gildea 1988. gildea@bbn.com +(defconst mh-e-RCS-id "$Header: /home/fsf/rms/e19/lisp/RCS/mh-e.el,v 1.15 1993/07/20 04:35:00 rms Exp rms $") + +;;; Code: @@ -45,7 +61,7 @@ ;;;(defvar mh-progs "/usr/new/mh/" "Directory containing MH commands.") ;;;(defvar mh-lib "/usr/new/lib/mh/" "Directory of MH library.") -(defvar mh-redist-full-contents t +(defvar mh-redist-full-contents nil "Non-nil if the `dist' command needs whole letter for redistribution. This is the case when `send' is compiled with the BERK option.") @@ -68,8 +84,11 @@ It is passed three arguments: TO recipients, SUBJECT, and CC recipients.") (defvar mh-inc-folder-hook nil "Invoked after incorporating mail into a folder with \\[mh-inc-folder].") +(defvar mh-before-quit-hook nil + "Invoked by \\[mh-quit] before quitting mh-e. See also mh-quit-hook") + (defvar mh-quit-hook nil - "Invoked after quitting mh-e with \\[mh-quit].") + "Invoked after quitting mh-e by \\[mh-quit]. See also mh-before-quit-hook") (defvar mh-ins-string nil @@ -80,7 +99,7 @@ It is passed three arguments: TO recipients, SUBJECT, and CC recipients.") (save-excursion (goto-char (point)) (or (bolp) (forward-line 1)) - (while (< (point) (mark)) + (while (< (point) (mark t)) (insert mh-ins-string) (forward-line 1)))) "Hook to run citation function. @@ -116,12 +135,12 @@ WARNING: do not delete the messages until printing is finished; otherwise, your output may be truncated.") (defvar mh-summary-height 4 - "*Number of lines in summary window.") + "*Number of lines in summary window (including the mode line).") (defvar mh-recenter-summary-p nil "*Recenter summary window when the show window is toggled off if non-nil.") -(defvar mh-ins-buf-prefix ">> " +(defvar mh-ins-buf-prefix "> " "*String to put before each non-blank line of a yanked or inserted message. Used when the message is inserted in an outgoing letter.") @@ -139,7 +158,7 @@ windows displaying the message.") (defvar mh-yank-from-start-of-msg t "*Controls which part of a message is yanked by \\[mh-yank-cur-msg]. -If non-nil, include the entire message. If the symbol `body, then yank the +If non-nil, include the entire message. If the symbol `body', then yank the message minus the header. If nil, yank only the portion of the message following the point. If the show buffer has a region, this variable is ignored.") @@ -152,9 +171,16 @@ value and it should be one of \"from\", \"to\", or \"cc\".") (defvar mh-recursive-folders nil "*If non-nil, then commands which operate on folders do so recursively.") +(defvar mh-unshar-default-directory "" + "*Default for directory name prompted for by mh-unshar-msg.") + +(defvar mh-signature-file-name "~/.signature" + "*Name of file containing the user's signature. +Inserted into message by \\\\[mh-insert-signature].") + ;;; Parameterize mh-e to work with different scan formats. The defaults work -;;; the standard MH scan listings. +;;; with the standard MH scan listings. (defvar mh-cmd-note 4 "Offset to insert notation.") @@ -169,7 +195,7 @@ value and it should be one of \"from\", \"to\", or \"cc\".") "String whose first character is used to notate redistributed messages.") (defvar mh-good-msg-regexp "^....[^D^]" - "Regexp specifiying the scan lines that are 'good' messages.") + "Regexp specifying the scan lines that are 'good' messages.") (defvar mh-deleted-msg-regexp "^....D" "Regexp matching scan lines of deleted messages.") @@ -212,7 +238,10 @@ The string is displayed after the folder's name. NIL for no annotation.") If `mh-visible-headers' is non-nil, it is used instead to specify what to keep.") -(defvar mh-rejected-letter-start "^ ----- Unsent message follows -----$" +(defvar mh-rejected-letter-start + (concat "^ ----- Unsent message follows -----$" ;from mail system + "\\|^------- Unsent Draft$" ;from MH itself + "\\|^ --- The unsent message follows ---$") ;from AIX mail system "Regexp specifying the beginning of the wrapper around a returned letter. This wrapper is generated by the mail system when rejecting a letter.") @@ -238,6 +267,9 @@ This wrapper is generated by the mail system when rejecting a letter.") (defvar mh-pick-mode-map (make-sparse-keymap) "Keymap for searching folder.") +(defvar mh-searching-folder nil + "Folder this pick is searching.") + (defvar mh-letter-mode-syntax-table nil "Syntax table used while in mh-e letter mode.") @@ -264,9 +296,6 @@ NIL means do not use draft folder.") (defvar mh-previous-seq nil "Name of the sequence to which a message was last added.") -(defvar mh-signature-file-name "~/.signature" - "Name of file containing the user's signature.") - ;;; Macros and generic functions: @@ -411,13 +440,13 @@ from a sequence." (config (current-window-configuration)) (draft (cond ((and mh-draft-folder (equal from-folder mh-draft-folder)) - (find-file (mh-msg-filename msg)) + (pop-to-buffer (find-file-noselect (mh-msg-filename msg)) t) (rename-buffer (format "draft-%d" msg)) (buffer-name)) (t (mh-read-draft "clean-up" (mh-msg-filename msg) nil))))) (mh-clean-msg-header (point-min) - "^Date:\\|^Received:\\|^Message-Id:\\|^From:" + "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Delivery-Date:" nil) (goto-char (point-min)) (set-buffer-modified-p nil) @@ -448,7 +477,7 @@ Default is the displayed message." (forward-char 1) (delete-region (point-min) (point)) (mh-clean-msg-header (point-min) - "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Sender:" + "^Date:\\|^Received:\\|^Message-Id:\\|^From:\\|^Sender:\\|^Return-Path:" nil)) (t (message "Does not appear to be a rejected letter."))) @@ -515,7 +544,7 @@ If optional prefix argument provided, then prompt for the message sequence." Non-nil second argument means do not signal an error if message does not exist. Non-nil third argument means not to show the message. Return non-nil if cursor is at message." - (interactive "NMessage number? ") + (interactive "NGoto message: ") (let ((cur-msg (mh-get-msg-num nil)) (starting-place (point)) (msg-pattern (mh-msg-search-pat number))) @@ -542,7 +571,7 @@ Return non-nil if cursor is at message." (defun mh-inc-folder (&optional maildrop-name) "Inc(orporate) new mail into +inbox. Optional prefix argument specifies an alternate maildrop from the default. -If this is given, mail is incorporated into the current folder, rather +If this is given, incorporate mail into the current folder, rather than +inbox. Run `mh-inc-folder-hook' after incorporating new mail." (interactive (list (if current-prefix-arg (expand-file-name @@ -571,7 +600,8 @@ than +inbox. Run `mh-inc-folder-hook' after incorporating new mail." (mh-remove-folder-from-folder-list folder) (message "Folder %s removed" folder) (mh-set-folder-modified-p nil) ; so kill-buffer doesn't complain - (kill-buffer mh-show-buffer) + (if (get-buffer mh-show-buffer) + (kill-buffer mh-show-buffer)) (kill-buffer folder)) (message "Folder not removed"))) @@ -592,7 +622,9 @@ than +inbox. Run `mh-inc-folder-hook' after incorporating new mail." (switch-to-buffer " *mh-temp*") (erase-buffer) (message "Listing folders...") - (mh-exec-cmd-output "folders" t) + (mh-exec-cmd-output "folders" t (if mh-recursive-folders + "-recurse" + "-norecurse")) (goto-char (point-min)) (message "Listing folders...done")))) @@ -658,7 +690,7 @@ Otherwise just send the message's body." (interactive (list current-prefix-arg (read-string "Shell command on message: "))) (save-excursion - (set-buffer mh-show-buffer) + (mh-display-msg (mh-get-msg-num t) mh-current-folder) ;update show buffer (goto-char (point-min)) (if (not prefix-provided) (search-forward "\n\n")) (shell-command-on-region (point) (point-max) command nil))) @@ -719,7 +751,7 @@ using filter mhl.reply in your MH directory." (message "Composing a reply...") (cond ((or (equal reply-to "from") (equal reply-to "")) (apply 'mh-exec-cmd - "repl" "-build" + "repl" "-build" "-noquery" "-nodraftfolder" mh-current-folder msg "-nocc" "all" @@ -727,7 +759,7 @@ using filter mhl.reply in your MH directory." (list "-filter" "mhl.reply")))) ((equal reply-to "to") (apply 'mh-exec-cmd - "repl" "-build" + "repl" "-build" "-noquery" "-nodraftfolder" mh-current-folder msg "-cc" "to" @@ -735,7 +767,7 @@ using filter mhl.reply in your MH directory." (list "-filter" "mhl.reply")))) ((or (equal reply-to "cc") (equal reply-to "all")) (apply 'mh-exec-cmd - "repl" "-build" + "repl" "-build" "-noquery" "-nodraftfolder" mh-current-folder msg "-cc" "all" "-nocc" "me" @@ -762,9 +794,11 @@ using filter mhl.reply in your MH directory." (defun mh-quit () - "Restore the previous window configuration, if one exists. -Finish by running mh-quit-hook." + "Quit mh-e. +Start by running mh-before-quit-hook. Restore the previous window +configuration, if one exists. Finish by running mh-quit-hook." (interactive) + (run-hooks 'mh-before-quit-hook) (if mh-previous-window-config (set-window-configuration mh-previous-window-config)) (run-hooks 'mh-quit-hook)) @@ -901,7 +935,7 @@ If optional prefix argument provided, then prompt for the message sequence." (mh-add-msgs-to-seq from to)) -(defun mh-rescan-folder (range) +(defun mh-rescan-folder (&optional range) "Rescan a folder after optionally processing the outstanding commands. If optional prefix argument is provided, prompt for the range of messages to display. Otherwise show the entire folder." @@ -985,7 +1019,10 @@ setting of the variable mh-redist-full-contents. See its documentation." (defun mh-send (to cc subject) - "Compose and send a letter." + "Compose and send a letter. +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, subject, and cc." (interactive "sTo: \nsCc: \nsSubject: ") (let ((config (current-window-configuration))) (delete-other-windows) @@ -1040,14 +1077,15 @@ mh-summary-height) and the show buffer below it." (mh-show-message-in-other-window) (mh-display-msg msg folder)) (other-window -1) - (shrink-window (- (window-height) mh-summary-height)) + (if (not (= (1+ (window-height)) (screen-height))) ;not horizontally split + (shrink-window (- (window-height) mh-summary-height))) (mh-recenter nil) (if (not (memq msg mh-seen-list)) (mh-push msg mh-seen-list))) (defun mh-sort-folder () "Sort the messages in the current folder by date." - (interactive "") + (interactive) (mh-process-or-undo-commands mh-current-folder) (setq mh-next-direction 'forward) (mh-set-folder-modified-p t) ; lock folder while sorting @@ -1073,21 +1111,30 @@ provided, then prompt for the message sequence." (if current-prefix-arg (mh-read-seq-default "Undo" t) (mh-get-msg-num t)))) - (cond (prefix-provided (mh-mapc (function mh-undo-msg) (mh-seq-to-msgs msg-or-seq))) - ((or (looking-at mh-deleted-msg-regexp) - (looking-at mh-refiled-msg-regexp)) - (mh-undo-msg (mh-get-msg-num t))) (t - (error "Nothing to undo"))) + (let ((original-position (point))) + (beginning-of-line) + (while (not (or (looking-at mh-deleted-msg-regexp) + (looking-at mh-refiled-msg-regexp) + (and (eq mh-next-direction 'forward) (bobp)) + (and (eq mh-next-direction 'backward) + (save-excursion (forward-line) (eobp))))) + (forward-line (if (eq mh-next-direction 'forward) -1 1))) + (if (or (looking-at mh-deleted-msg-regexp) + (looking-at mh-refiled-msg-regexp)) + (progn + (mh-undo-msg (mh-get-msg-num t)) + (mh-maybe-show)) + (goto-char original-position) + (error "Nothing to undo"))))) ;; update the mh-refile-list so mh-outstanding-commands-p will work (mh-mapc (function (lambda (elt) (if (not (mh-seq-to-msgs elt)) (setq mh-refile-list (delq elt mh-refile-list))))) mh-refile-list) - (if (not (mh-outstanding-commands-p)) (mh-set-folder-modified-p nil))) @@ -1096,18 +1143,17 @@ provided, then prompt for the message sequence." ;; Undo the deletion or refile of one MESSAGE. (cond ((memq msg mh-delete-list) (setq mh-delete-list (delq msg mh-delete-list)) - (mh-remove-msg-from-seq msg 'deleted t) - (mh-notate msg ? mh-cmd-note)) + (mh-remove-msg-from-seq msg 'deleted t)) (t (mh-mapc (function (lambda (dest) (mh-remove-msg-from-seq msg dest t))) - mh-refile-list) - (mh-notate msg ? mh-cmd-note)))) + mh-refile-list))) + (mh-notate msg ? mh-cmd-note)) (defun mh-undo-folder (&rest ignore) "Undo all commands in current folder." - (interactive "") + (interactive) (cond ((or mh-do-not-confirm (yes-or-no-p "Undo all commands in folder? ")) (setq mh-delete-list nil @@ -1121,22 +1167,57 @@ provided, then prompt for the message sequence." (sit-for 2)))) +(defun mh-unshar-msg (dir) + "Unpack the shar file contained in the current message into directory DIR." + (interactive (list (read-file-name "Unshar message in directory: " + mh-unshar-default-directory + mh-unshar-default-directory nil))) + (mh-display-msg (mh-get-msg-num t) mh-current-folder) ;update show buffer + (mh-unshar-buffer dir)) + +(defun mh-unshar-buffer (dir) + ;; Unpack the shar file contained in the current buffer into directory DIR. + (goto-char (point-min)) + (if (or (re-search-forward "^#![ \t]*/bin/sh" nil t) + (and (re-search-forward "^[^a-z0-9\"]*cut here\b" nil t) + (forward-line 1)) + (re-search-forward "^#" nil t) + (re-search-forward "^: " nil t)) + (let ((default-directory (expand-file-name dir)) + (start (progn (beginning-of-line) (point))) + (log-buffer (get-buffer-create "*Unshar Output*"))) + (save-excursion + (set-buffer log-buffer) + (setq default-directory (expand-file-name dir)) + (erase-buffer) + (if (file-directory-p default-directory) + (insert "cd " dir "\n") + (insert "mkdir " dir "\n") + (call-process "mkdir" nil log-buffer t default-directory))) + (set-window-start (display-buffer log-buffer) 0) ;so can watch progress + (call-process-region start (point-max) "sh" nil log-buffer t)) + (error "Cannot find start of shar."))) + + (defun mh-visit-folder (folder &optional range) - "Visit FOLDER and display RANGE of messages." + "Visit FOLDER and display RANGE of messages. +Assumes mh-e has already been initialized." (interactive (list (mh-prompt-for-folder "Visit" "+inbox" t) (mh-read-msg-range "Range [all]? "))) (let ((config (current-window-configuration))) (mh-scan-folder folder (or range "all")) - (setq mh-previous-window-config config))) + (setq mh-previous-window-config config)) + nil) (defun mh-widen () "Remove restrictions from the current folder, thereby showing all messages." - (interactive "") - (with-mh-folder-updating (t) - (delete-region (point-min) (point-max)) - (widen) - (mh-make-folder-mode-line)) + (interactive) + (if mh-narrowed-to-seq + (with-mh-folder-updating (t) + (delete-region (point-min) (point-max)) + (widen) + (mh-make-folder-mode-line))) (setq mh-narrowed-to-seq nil)) @@ -1158,7 +1239,7 @@ provided, then prompt for the message sequence." (defun mh-refile-a-msg (msg destination) - ;; Refile MESSAGE in FOLDER. + ;; Refile MESSAGE in FOLDER. FOLDER is a symbol, not a string. (save-excursion (mh-goto-msg msg nil t) (cond ((looking-at mh-deleted-msg-regexp) @@ -1182,6 +1263,7 @@ provided, then prompt for the message sequence." (defun mh-display-msg (msg-num folder) ;; Display message NUMBER of FOLDER. + ;; Sets the current buffer to the show buffer. (set-buffer folder) ;; Bind variables in folder buffer in case they are local (let ((formfile mhl-formfile) @@ -1251,7 +1333,7 @@ provided, then prompt for the message sequence." (save-restriction (goto-char start) (if (search-forward "\n\n" nil t) - (backward-char 2)) + (backward-char 1)) (narrow-to-region start (point)) (goto-char (point-min)) (if visible-headers @@ -1291,7 +1373,7 @@ provided, then prompt for the message sequence." ;; reused. (cond (mh-draft-folder (let ((orig-default-dir default-directory)) - (pop-to-buffer (find-file-noselect (mh-new-draft-name) t)) + (pop-to-buffer (find-file-noselect (mh-new-draft-name)) t) (rename-buffer (format "draft-%s" (buffer-name))) (setq default-directory orig-default-dir))) (t @@ -1327,7 +1409,7 @@ provided, then prompt for the message sequence." (set-buffer (get-buffer-create " *mh-temp*")) (erase-buffer) (mh-exec-cmd-output "mhpath" nil mh-draft-folder "new") - (buffer-substring (point) (1- (mark))))) + (buffer-substring (point) (1- (mark t))))) (defun mh-next-msg () @@ -1364,7 +1446,7 @@ provided, then prompt for the message sequence." ;;; The folder data abstraction. (defvar mh-current-folder nil "Name of current folder, a string.") -(defvar mh-show-buffer nil "Buffer that displays mesage for this folder.") +(defvar mh-show-buffer nil "Buffer that displays message for this folder.") (defvar mh-folder-filename nil "Full path of directory for this folder.") (defvar mh-showing nil "If non-nil, show the message in a separate window.") (defvar mh-next-seq-num nil "Index of free sequence id.") @@ -1434,9 +1516,9 @@ Variables controlling mh-e operation are (defaults in parentheses): a messages is toggled off. mh-summary-height (4) - Number of lines in the summary window. + Number of lines in the summary window including the mode line. - mh-ins-buf-prefix (\">> \") + mh-ins-buf-prefix (\"> \") String to insert before each non-blank line of a message as it is inserted in a draft letter. @@ -1462,6 +1544,7 @@ The value of mh-folder-mode-hook is called when a new folder is set up." 'mh-first-msg-num nil ; Number of first msg in buffer 'mh-last-msg-num nil ; Number of last msg in buffer 'mh-previous-window-config nil) ; Previous window configuration + (setq truncate-lines t) (auto-save-mode -1) (setq buffer-offer-save t) (make-local-variable 'write-file-hooks) @@ -1694,7 +1777,7 @@ The value of mh-folder-mode-hook is called when a new folder is set up." (save-excursion (mh-first-msg) (while (and msgs (< (point) (point-max))) - (cond ((= (mh-get-msg-num nil) (car msgs)) + (cond ((equal (mh-get-msg-num nil) (car msgs)) (delete-region (point) (save-excursion (forward-line) (point))) (setq msgs (cdr msgs))) (t @@ -1745,6 +1828,9 @@ Variables controlling this mode (defaults in parentheses): If nil, only the portion of the message following the point will be yanked. If there is a region, this variable is ignored. + mh-signature-file-name (\"~/.signature\") + File to be inserted into message by \\[mh-insert-signature]. + Upon invoking mh-letter-mode, text-mode-hook and mh-letter-mode-hook are invoked with no args, if those values are non-nil. @@ -1767,7 +1853,10 @@ invoked with no args, if those values are non-nil. (mh-set-mode-name "mh-e letter") (set-syntax-table mh-letter-mode-syntax-table) (run-hooks 'text-mode-hook 'mh-letter-mode-hook) - (mh-when auto-fill-function + (mh-when (and (boundp 'auto-fill-hook) auto-fill-hook) ;emacs 18 + (make-local-variable 'auto-fill-hook) + (setq auto-fill-hook 'mh-auto-fill-for-letter)) + (mh-when (and (boundp 'auto-fill-function) auto-fill-function) ;emacs 19 (make-local-variable 'auto-fill-function) (setq auto-fill-function 'mh-auto-fill-for-letter))) @@ -1795,7 +1884,7 @@ invoked with no args, if those values are non-nil. "Move point to the end of a specified header field. The field is indicated by the previous keystroke. Create the field if it does not exist. Set the mark to point before moving." - (interactive "") + (interactive) (expand-abbrev) (let ((target (cdr (assoc (logior last-input-char ?`) mh-to-field-choices))) (case-fold-search t)) @@ -1803,9 +1892,10 @@ it does not exist. Set the mark to point before moving." (let ((eol (point))) (skip-chars-backward " \t") (delete-region (point) eol)) - (if (save-excursion - (backward-char 1) - (not (looking-at "[:,]"))) + (if (and (not (eq (logior last-input-char ?`) ?s)) + (save-excursion + (backward-char 1) + (not (looking-at "[:,]")))) (insert ", ") (insert " "))) (t @@ -1830,8 +1920,8 @@ Prompt for the field name with a completion list of the current folders." (defun mh-insert-signature () - "Insert the file ~/.signature at the current point." - (interactive "") + "Insert the file named by mh-signature-file-name at the current point." + (interactive) (insert-file-contents mh-signature-file-name) (set-buffer-modified-p (buffer-modified-p))) ; force mode line update @@ -1881,7 +1971,7 @@ Put messages found in a sequence named `search'." (interactive) (let ((pattern-buffer (buffer-name)) (searching-buffer mh-searching-folder) - (range) + range msgs (pattern nil) (new-buffer nil)) (save-excursion @@ -1995,7 +2085,7 @@ Run mh-before-send-letter-hook before doing anything." "-nodraftfolder" mh-send-args file-name) (mh-exec-cmd-output "send" t "-watch" "-nopush" "-nodraftfolder" file-name)) - (goto-char (point-max)) + (goto-char (point-max)) ; show the interesting part (recenter -1) (set-buffer draft-buffer)) ; for annotation below (mh-send-args @@ -2065,8 +2155,9 @@ yanked message will be deleted." (if mh-delete-yanked-msg-window (delete-windows-on mh-show-buffer)) (set-buffer mh-show-buffer) ; Find displayed message - (let ((mh-ins-str (cond ((mark) - (buffer-substring (point) (mark))) + (let ((mh-ins-str (cond (mark-active + (buffer-substring (region-beginning) + (region-end))) ((eq 'body mh-yank-from-start-of-msg) (buffer-substring (save-excursion @@ -2100,7 +2191,7 @@ yanked message will be deleted." (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 "") + (interactive) (if (y-or-n-p "Kill draft message? ") (let ((config mh-previous-window-config)) (if (file-exists-p (buffer-file-name)) @@ -2196,7 +2287,8 @@ Use \\[kill-buffer] if you don't want to delete the draft message file." (save-excursion (mh-exec-cmd-quiet " *mh-temp*" "mark" folder "-list") (goto-char (point-min)) - (while (re-search-forward "^[^:]+" nil t) + ;; look for name in line of form "cur: 4" or "myseq (private): 23" + (while (re-search-forward "^[^: ]+" nil t) (mh-push (mh-make-seq (intern (buffer-substring (match-beginning 0) (match-end 0))) (mh-read-msg-list)) @@ -2322,7 +2414,7 @@ Use \\[kill-buffer] if you don't want to delete the draft message file." (defun mh-folder-name-p (name) ;; Return non-NIL if NAME is possibly the name of a folder. - ;; A name can be a folder name if it begins with "+". + ;; A name (a string or symbol) can be a folder name if it begins with "+". (if (symbolp name) (eql (aref (symbol-name name) 0) ?+) (eql (aref name 0) ?+))) @@ -2456,10 +2548,11 @@ Use \\[kill-buffer] if you don't want to delete the draft message file." (save-excursion (set-buffer (get-buffer-create " *mh-temp*")) (erase-buffer)) - (let ((process (apply 'start-process - command nil - (expand-file-name command mh-progs) - (mh-list-to-string args)))) + (let* ((process-connection-type nil) + (process (apply 'start-process + command nil + (expand-file-name command mh-progs) + (mh-list-to-string args)))) (set-process-filter process 'mh-process-daemon))) @@ -2529,16 +2622,16 @@ Use \\[kill-buffer] if you don't want to delete the draft message file." ;;; User prompting commands. (defun mh-prompt-for-folder (prompt default can-create) - ;; Prompt for a folder name with PROMPT. Returns the folder's name. - ;; DEFAULT is used if the folder exists and the user types return. - ;; If the CAN-CREATE flag is t, then a non-existant folder is made. + ;; Prompt for a folder name with PROMPT. Returns the folder's name as a + ;; string. DEFAULT is used if the folder exists and the user types return. + ;; If the CAN-CREATE flag is t, then a non-existent folder is made. (let* ((prompt (format "%s folder%s" prompt (if (equal "" default) "? " (format " [%s]? " default)))) name) (if (null mh-folder-list) - (setq mh-folder-list (mh-make-folder-list))) + (mh-set-folder-list)) (while (and (setq name (completing-read prompt mh-folder-list nil nil "+")) (equal name "") @@ -2554,17 +2647,21 @@ Use \\[kill-buffer] if you don't want to delete the draft message file." (message "Creating %s" name) (call-process "mkdir" nil nil nil (mh-expand-file-name name)) (message "Creating %s...done" name) - (mh-push (list name) mh-folder-list) - (mh-push (list (substring name 1 nil)) mh-folder-list)) + (mh-push (list name) mh-folder-list)) (new-file-p (error "Folder %s is not created" name)) (t (mh-when (null (assoc name mh-folder-list)) - (mh-push (list name) mh-folder-list) - (mh-push (list (substring name 1 nil)) mh-folder-list))))) + (mh-push (list name) mh-folder-list))))) name)) +(defun mh-set-folder-list () + "Sets mh-folder-list correctly. +A useful function for the command line or for when you need to sync by hand." + (setq mh-folder-list (mh-make-folder-list))) + + (defun mh-make-folder-list () "Return a list of the user's folders. Result is in a form suitable for completing read." @@ -2685,21 +2782,15 @@ Assumes that any filename that starts with '+' is a folder name." ;; Returns the empty string if the field is not in the message. (let ((case-fold-search t)) (goto-char (point-min)) - (cond ((not (search-forward field nil t)) "") + (cond ((not (re-search-forward (format "^%s" field) nil t)) "") ((looking-at "[\t ]*$") "") (t (re-search-forward "[\t ]*\\([^\t \n].*\\)$" nil t) - (let ((field (buffer-substring (match-beginning 1) - (match-end 1))) - (end-of-match (point))) - (forward-line) - (while (looking-at "[ \t]") (forward-line 1)) - (backward-char 1) - (if (<= (point) end-of-match) - field - (format "%s%s" - field - (buffer-substring end-of-match (point))))))))) + (let ((start (match-beginning 1))) + (forward-line 1) + (while (looking-at "[ \t]") + (forward-line 1)) + (buffer-substring start (1- (point)))))))) (defun mh-insert-fields (&rest name-values) @@ -2723,6 +2814,7 @@ Assumes that any filename that starts with '+' is a folder name." (defun mh-position-on-field (field set-mark) ;; Set point to the end of the line beginning with FIELD. ;; Set the mark to the old value of point, if SET-MARK is non-nil. + ;; Returns non-nil iff the field was found. (let ((case-fold-search t)) (if set-mark (push-mark)) (goto-char (point-min)) @@ -2760,6 +2852,7 @@ Assumes that any filename that starts with '+' is a folder name." (define-key mh-folder-mode-map "\ef" 'mh-visit-folder) (define-key mh-folder-mode-map "\ek" 'mh-kill-folder) (define-key mh-folder-mode-map "\el" 'mh-list-folders) +(define-key mh-folder-mode-map "\en" 'mh-unshar-msg) (define-key mh-folder-mode-map "\eo" 'mh-write-msg-to-file) (define-key mh-folder-mode-map "\ep" 'mh-pack-folder) (define-key mh-folder-mode-map "\es" 'mh-search-folder) @@ -2777,6 +2870,7 @@ Assumes that any filename that starts with '+' is a folder name." (define-key mh-folder-mode-map "m" 'mh-send) (define-key mh-folder-mode-map "a" 'mh-reply) (define-key mh-folder-mode-map "j" 'mh-goto-msg) +(define-key mh-folder-mode-map "<" 'mh-first-msg) (define-key mh-folder-mode-map "g" 'mh-goto-msg) (define-key mh-folder-mode-map "\177" 'mh-previous-page) (define-key mh-folder-mode-map " " 'mh-page-msg) @@ -2830,8 +2924,8 @@ Assumes that any filename that starts with '+' is a folder name." ;;; For Gnu Emacs. ;;; Local Variables: *** -;;; eval: (put 'mh-when 'lisp-indent-function 1) *** -;;; eval: (put 'with-mh-folder-updating 'lisp-indent-function 1) *** +;;; eval: (put 'mh-when 'lisp-indent-hook 1) *** +;;; eval: (put 'with-mh-folder-updating 'lisp-indent-hook 1) *** ;;; End: *** (provide 'mh-e)