Mercurial > emacs
changeset 47730:2568d5a27317
Upgraded to mh-e version 6.1.1.
author | Bill Wohler <wohler@newt.com> |
---|---|
date | Tue, 01 Oct 2002 20:27:23 +0000 |
parents | 8dcdf2a8c1f8 |
children | 755c4233cfba |
files | etc/ChangeLog etc/MH-E-NEWS etc/MH-E-ONEWS etc/NEWS lisp/ChangeLog lisp/mail/mh-comp.el lisp/mail/mh-e.el lisp/mail/mh-funcs.el lisp/mail/mh-mime.el lisp/mail/mh-pick.el lisp/mail/mh-seq.el lisp/mail/mh-utils.el lisp/mail/mh-xemacs-compat.el lisp/mail/reply2.pbm lisp/mail/reply2.xpm lisp/toolbar/execute.pbm lisp/toolbar/execute.xpm lisp/toolbar/page-down.pbm lisp/toolbar/page-down.xpm lisp/toolbar/refile.pbm lisp/toolbar/refile.xpm lisp/toolbar/repack.pbm lisp/toolbar/repack.xpm lisp/toolbar/rescan.pbm lisp/toolbar/rescan.xpm lisp/toolbar/show.pbm lisp/toolbar/show.xpm lisp/toolbar/widen.pbm lisp/toolbar/widen.xpm |
diffstat | 29 files changed, 3194 insertions(+), 999 deletions(-) [+] |
line wrap: on
line diff
--- a/etc/ChangeLog Tue Oct 01 18:48:35 2002 +0000 +++ b/etc/ChangeLog Tue Oct 01 20:27:23 2002 +0000 @@ -1,3 +1,7 @@ +2002-10-01 Bill Wohler <wohler@newt.com> + + * MH-E-NEWS: Upgraded to mh-e version 6.1.1. + 2002-09-16 Jonathan Yavner <jyavner@engineer.com> * ses-example.ses: New file: example spreadsheet.
--- a/etc/MH-E-NEWS Tue Oct 01 18:48:35 2002 +0000 +++ b/etc/MH-E-NEWS Tue Oct 01 20:27:23 2002 +0000 @@ -1,144 +1,744 @@ -User-visible changes to mh-e in version 5.0 from 4.1. +* Changes in mh-e 6.1 + +This is a minor release which includes a few bug fixes. The +distribution now includes the ChangeLog. + +** New Features in mh-e 6.1 + +*** Fontification + +Unseen messages now displayed in bold. + +*** Viewing folders and sequences + +The folder and sequence listings that "F l (mh-list-folders)" and "S l +(mh-list-sequences)" create are now displayed in view mode. + +** Bug Fixes in mh-e 6.1 + +*** mh-folder-unseen-seq-name + +Byte compilation failed when initializing this variable when the +user's MH environment was not set up. This has been fixed (closes +Debian #140232 and Debian #140817). + +*** mh-forward + +When forwarding a sequence, the mode of the draft would not be set to +MH-Letter correctly. This has been fixed (closes SF #489448). + +*** mh-insert-prefix-string + +Fixed to work under XEmacs. Thanks to Will Partain +<partain at dcs.gla.ac.uk>. + +*** mh-quit + +mh-quit now cleans up the buffers named `mh-temp-buffer, +'mh-temp-folders-buffer' and 'mh-temp-sequences-buffer.' + + +* Changes in mh-e 6.0 + +mh-e is now maintained at SourceForge (see +http://mh-e.sourceforge.net/). This is where you need to go to obtain +new versions of mh-e, report bugs and receive support. + +The maintainers have moved much of their personal configurations into +the codebase, so you may find that you may be able to reduce your mh-e +customizations as well. + +There are several incompatibilities in this version from older +versions. Please read the following notes carefully for details. Pay +particular attention to the key binding changes in the MH-Folder +section. If you have customized your scan format, you will want to +read about the new variable `mh-scan-format-file'. + +The manual could not be updated in time for this release. It will be +updated in the near future. If the Preface in your manual indicates +the older version (version 1.3, for mh-e version 5.0.2), please check +the following page occasionally for an update: + + https://sourceforge.net/project/showfiles.php?group_id=13357 + + +** New Features in mh-e 6.0 + +*** Customization + +mh-e now uses the customize feature of Emacs. Use "M-x customize-group +mh RET" to customize mh-e. + +*** Menus + +All mh-e modes now provide menus that contain most mh-e functions. + +*** Toolbars + +All mh-e modes now have toolbar buttons for oft-used functions (Emacs 21). + +*** Fontification + +All mh-e buffers now have font-lock keywords. To use, either call +(turn-on-font-lock) from the appropriate hook, or set +`global-font-lock-mode' to t. To customize, use "M-x +customize-apropos-faces ^mh RET". + +If you have customized your scan lines, you will have to update your +scan regexps. The existing regexps were changed to extract a match so +you will have to add appropriate grouping constructs to take advantage +of the fontification. Your old settings will continue to work, but the +folder will not be fontified. For example: - Note: This being a major release, there are many internal changes. -This document lists only changes to the external interfaces of mh-e. + (setq mh-good-msg-regexp "^\\(.....\\)[^D^]") + +You will most likely have to update the new variable +`mh-scan-subject-regexp' as well. There is another new variable +`mh-scan-date-regexp' which you may also find useful. Run "M-x apropos +mh.*regexp" for a complete list. + +*** mail-user-agent support + +You can now set `mail-user-agent' to `mh-e-user-agent' so that packages +that need to send mail will use mh-e (closes SF #406883, SF #470024). + +*** replgroupcomps support + +If you reply to `cc' or `all' and you use nmh, the nmh repl option +-group will be used. This means that the file `replgroupcomps' will be +used. If you have customized `replcomps', you will definitely want to +either copy `$NMH_LIB/replgroupcomps' to your mail directory and modify +it the same way that you modified your `replcomps' file, or simply +copy your `replcomps' file to `replgroupcomps'. + +*** MH-Folder mode + +The variable `mh-summary-height' used to have a default of 4. It now +varies from 4 to 10 depending on the height of the frame. + +Clicking the mouse on a message shows that message. + +Delete, refile and undo now operate on a region (but only if +`transient-mark-mode' is non-nil). + +SPC (mh-page-msg) now displays the message if it is not already +visible. If the bottom of a message is showing, SPC (mh-page-msg) +moves to the next message (respecting the direction you are moving +through the folder). + +The threading commands "T u (mh-next-unseen-subject-thread)", +"T t (mh-toggle-subject-thread)", "T s (mh-narrow-to-subject-thread)", +and "T k (mh-delete-subject-thread)" have been added. These functions +do not offer threading in the true sense of the word, but do allow +some manipulation by subject. + +Major, major keymap changes. This was done to free up movement +commands in the buffer, and to provide for additional features, such +as the threading commands. At the same time, better and more +consistent mnemonics were realized that should make it easier to +remember key bindings. + +Added new sub-keymaps for folder commands, sequence commands, +extraction commands, and digest commands which begin with with F, S, +X, and D, respectively. These sub-keymaps allowed some consistency +(e.g., especially with l(ist) and k(ill)). + +Here are the actual changes and rationale: + +Old New Rationale + +e - Deleted. Already have x. Now used by mh-edit-again. +j - Deleted. Already have g. + +M-a e Better mnemonic. Matches rmail. Frees movement command. +M-e E Better mnemonic. Consistent with e. +- S Why not? mh-sort-folder. + +M-f Fv Frees movement command +M-f Ff Alias (keep?) +M-f Fo Alias (keep?) +M-k Fk No reason but to keep with folder commands +M-l Fl No reason but to keep with folder commands +M-p Fp No reason but to keep with folder commands +M-r Fr Frees movement command +M-s Fs No reason but to keep with folder commands +M-u Fu No reason but to keep with folder commands + +M-% Sd Better mnemonic +M-# Sk Better mnemonic +M-q Sl Better mnemonic +C-xn Sn Frees up standard key binding +% Sp Better mnemonic for putting a message in a sequence +? Ss Shows sequences that message is in +C-xw Sw Frees up standard key binding + +M-n Xs Better mnemonic (extract shar) +M-n Xu Better mnemonic (extract uuencode) + +M-SPC D SPC Frees mark command +M-\177 D \177 No reason but to keep with digest commands +M-b Db Frees movement command + +As the number of variables increases, it is becoming important to +organize the mh-e namespace. Several variables having to do with the +format of scan lines were renamed, as follows: + +Old New - When upgrading, you must either explicitly reload the new versions of -all mh-e files that are already loaded or restart your Emacs. +mh-good-msg-regexp mh-scan-good-msg-regexp +mh-deleted-msg-regexp mh-scan-deleted-msg-regexp +mh-refiled-msg-regexp mh-scan-refiled-msg-regexp +mh-valid-scan-line mh-scan-valid-regexp +mh-cur-scan-msg-regexp mh-scan-cur-msg-number-regexp +- mh-scan-cur-msg-regexp +- mh-scan-rcpt-regexp +- mh-scan-format-regexp +mh-msg-number-regexp mh-scan-msg-number-regexp +mh-msg-search-regexp mh-scan-msg-search-regexp + +*** MH-Show mode + +While the MIME support is not complete, quoted-printable body parts +are now decoded. + +Some MTAs quote From at the beginning of the line with a ">". The ">" +is now removed in the display, but not on disk. + +*** MH-Letter mode + +New function "C-c C-o (mh-split-line)" splits lines in a draft +preserving the fill prefix and indentation. This is useful when +responding to several sentences in a single paragraph separately. + +"M-q (fill-paragraph)" can now be used on the message that is being +replied to. The fill prefix such as "> " is preserved. + +You no longer have to run "C-c C-e (mh-edit-mhn)" manually as this is +now done automatically when the message is sent. + +The X-Mailer header field is now added to messages as they are sent. + +"C-c C-m C-i (mh-mhn-compose-insertion)" now makes a pretty good guess +at the type of file using the `file' command and no longer asks the +user for the media type. If the necessary version of `file' is not +available, the user is asked for the media type as before; however, +the list of media types is now taken from the system mailcap if +available. Failing that, the built-in list of types has been +supplemented so in most cases the type you need should be present +(closes SF #406883, #441179). + +** New Variables in mh-e 6.0 + +New variables not mentioned earlier include: + +*** mh-insert-x-mailer-p + +Default value of t means that an X-Mailer header field should be +added. + +*** mh-reply-show-message-p + +The setting of this variable determines whether the MH show-buffer is +displayed with the current message when using mh-reply without a prefix +argument. Set it to nil if you already include the message +automatically in your draft using "repl: -filter repl.filter" in +"~/.mh_profile." + +*** mh-scan-format-file + +Specifies the format file to pass to the scan program. If t, the +format string will be taken from the either `mh-scan-format-mh' or +`mh-scan-format-nmh' depending on whether MH or nmh is in use. If nil, +the default scan output will be used. + +If you customize the scan format, you may need to modify a few +variables containing regexps that mh-e uses to identify specific +portions of the output. Use `M-x apropos RET mh-scan.*regexp' to +obtain a list of these variables. + +*** mh-scan-format-mh + +Scan format string for MH, provided to the scan program via the +-format arg. This format is identical to the default except that +additional hints for fontification have been added to the sixth +column. + +*** mh-scan-format-nmh + +Scan format string for nmh, provided to the scan program via the +-format arg. This format is identical to the default except that +additional hints for fontification have been added to the sixth +column. + +*** mh-show-use-goto-addr + +Non-nil means URLs and e-mail addresses are highlighted using +goto-addr in MH-Show buffer. + +*** mh-letter-fill-column + +Fill column to use in `mh-letter-mode'. This is useful to make the +lines a bit shorter to allow for quoting in replies. + +*** mh-folder-updated-hook + +Invoked when the actions in a folder (such as moves and deletes) are +performed. Variables that are useful in this hook include +`mh-delete-list' and `mh-refile-list' which can be used to see which +changes are being made to current folder, `mh-current-folder'. + +*** mh-unseen-updated-hook - mh-e 5.0.1 contains minor changes from mh-e 5.0 to integrate it with -Emacs 19.29. +Invoked after the unseen sequence has been updated. The variable +`mh-seen-list' can be used to obtain the list of messages which will +be removed from the unseen sequence + +** Bug Fixes in mh-e 6.0 + +*** mh-edit-again and mh-extract-rejected-mail + +Now insert a header separator (--------) which packages such as +mailcrypt expect. + +*** mh-find-progs + +Now uses `mhparam' to set `mh-lib-progs' and `mh-lib'. Added more +directories to `mh-progs' so that mh-e can autoconfigure in more +environments. Chances are that you no longer have to set these +variables, and if you do, you will only have to set `mh-progs'. +Unless, of course, you are using an ancient version of MH that doesn't +have `mhparam'. + +*** mh-folder-mode-map + +The DEL/<delete>/<backspace> change in Emacs 21 broke +`mh-previous-page'. This has been fixed (closes SF #228907). + +*** mh-forward + +If you had "forw: -mime" to your .mh_profile, forwarding a message +resulted in: + + Search failed: "^------- Forwarded Message" + +In addition, the Subject field was not filled in. This has been fixed +(closes SF #223603). + +*** mh-kill-folder + +The user is now always prompted before this action; the variable +`mh-do-not-confirm' is no longer consulted here. Therefore users who +wanted to set `mh-do-not-confirm' but didn't because of the +`mh-kill-folder' dependency may now do so. + +*** mh-make-folder-mode-line + +Properly deals with folders that do not have any lines in them. Prints +"no msgs" instead of "0 msgs". Does not try to print a range when +there are no messages. + +*** mh-mhn-compose-insertion - mh-e 5.0.2 contains additional minor changes to integrate it with +Now gets the MIME type automatically (assuming the local file command +supports the -i and -b options). If this use of the file command is +not supported, the list of MIME types has been expanded to use the +system's mailcap file. + +*** mh-nmh-p + +This variable (t when nmh is in use rather than MH) assumed that the +string "nmh" is in `mh-lib-progs' or `mh-lib'. This has been fixed +(closes SF #441776). + +*** mh-refile-msg + +No longer lets you specify an empty folder (closes SF #476824). + +*** mh-regenerate-headers + +Now suppresses "scan: bad message list" messages. + +*** mh-print-msg + +This function was looking for `mhl' in the wrong place on nmh on +Redhat LINUX 7.0. This has been fixed (closes SF #481128). + +*** mh-show + +Now updates `cur' sequence after a message is shown (closes SF #481772). + +*** mh-showing + +Renamed variable and function to `mh-showing-mode' to conform with +minor mode conventions. Added optional arg to function so it would +behave like a normal minor mode: no or nil arg toggles mode, 0 arg +turns off, non-nil turns on. This fixed the error that occurred when +`desktop-create-buffer' recreated mh-e buffers because it was calling +`mh-showing' with an arg. + +*** mh-version + +Fixed for nmh. Now displays mh-e version correctly. Cleaned up output +and display `mh-progs', etc. + +*** mh-widen + +Now attempts to stay on the same message number (closes SF #480922). + +No longer wipes out pending deletes and refiles without warning +(closes SF #481036). + + +* Changes in mh-e 5.0.2 + +This version contains additional minor changes to integrate it with reporter.el (requires reporter.el version 3.1c or later) and Emacs 19.30. The mh-goto-msg function is much faster, which also speeds up several other operations. -Major Changes and New Features in mh-e -====================================== + +* Changes in mh-e 5.0.1 + +This version contains minor changes from mh-e 5.0 to integrate it with +Emacs 19.29. + + +* User-visible changes to mh-e 5.0 + +Note: This being a major release, there are many internal changes. +This document lists only changes to the external interfaces of mh-e. - The emphasis for this release has been on consistency and -documentation. Many documentation strings were enhanced. -Documentation strings were changed to comments for internal functions -and variables. +When upgrading, you must either explicitly reload the new versions of +all mh-e files that are already loaded or restart your Emacs. + + +** Major Changes and New Features in mh-e 5.0 - There is now proper documentation in the form of a 75-page users -manual. The Texinfo source is mh-e.texi; the formatted Info document +The emphasis for this release has been on consistency and +documentation. Many documentation strings were enhanced. Documentation +strings were changed to comments for internal functions and variables. + +*** There is now proper documentation in the form of a 75-page users +manual. The Texinfo source is mh-e.texi; the formatted Info document is mh-e.info. - There is a new command `mh-update-sequences', which updates MH's -idea of what messages are in the Unseen sequence and what is the current -folder and message. `mh-quit' calls it. While `mh-execute-commands' -has always done this updating as a side effect, the new function is -faster. +*** There is a new command `mh-update-sequences', which updates MH's +idea of what messages are in the Unseen sequence and what is the +current folder and message. `mh-quit' calls it. While +`mh-execute-commands' has always done this updating as a side effect, +the new function is faster. - The MH profile entry "Inbox:" is supported. +*** The MH profile entry "Inbox:" is supported. - If the show-buffer is modified, the user is queried before mh-e -reuses the buffer to show a different message. This buffer is also +*** If the show-buffer is modified, the user is queried before mh-e +reuses the buffer to show a different message. This buffer is also auto-saved and backed up correctly. - `mh-store-buffer' is significantly more robust. It now handles -messages created by a wide variety of packaging software. The status -message for `uudecode' includes the name of the file created. An error +*** `mh-store-buffer' is significantly more robust. It now handles +messages created by a wide variety of packaging software. The status +message for `uudecode' includes the name of the file created. An error is signaled if the subprocess exits with a non-zero status. - `mh-search-folder' behaves predictably, adding messages found to the -`search' sequence. It correctly handles the case of no messages found. - - `mh-burst-digest' (`M-b') now only rescans the part of the folder -affected by the burst. It is now much faster in a large folder. +*** `mh-search-folder' behaves predictably, adding messages found to +the `search' sequence. It correctly handles the case of no messages +found. -New mh-e Hooks and Customization Variables -========================================== +*** `mh-burst-digest' (`M-b') now only rescans the part of the folder +affected by the burst. It is now much faster in a large folder. + - `mh-default-folder-for-message-function': new name for the old -`mh-msg-folder-hook', which wasn't a hook. The old name was confusing, +** New Hooks and Customization Variables in mh-e 5.0 + +*** `mh-default-folder-for-message-function': new name for the old +`mh-msg-folder-hook', which wasn't a hook. The old name was confusing, leading people to think they could use `add-hook' with it, when actually `setq' is the correct way. - `mh-sortm-args': When this variable is used has changed. Now +*** `mh-sortm-args': When this variable is used has changed. Now `mh-sortm-args' is passed if there IS a prefix argument to -`mh-sort-folder'. The assumption is that for arguments you normally +`mh-sort-folder'. The assumption is that for arguments you normally want, you would specify them in an MH profile entry. - `mh-mhn-args': new hook, a list of additional arguments to pass to +*** `mh-mhn-args': new hook, a list of additional arguments to pass to the `mhn' program if `mh-edit-mhn' is given a prefix argument. - `mh-edit-mhn-hook': new hook called by `mh-edit-mhn', the function +*** `mh-edit-mhn-hook': new hook called by `mh-edit-mhn', the function that formats MIME messages. - `mh-folder-list-change-hook': new hook, called whenever the cached +*** `mh-folder-list-change-hook': new hook, called whenever the cached list of folders, `mh-folder-list', is changed. - `mh-find-path-hook': new hook, called when entering mh-e. +*** `mh-find-path-hook': new hook, called when entering mh-e. - `mh-repl-formfile': new variable, used to change the format file +*** `mh-repl-formfile': new variable, used to change the format file used by `mh-reply' from the default of "replcomps". - New variables to customize the scan format and notating: +*** New variables to customize the scan format and notating: `mh-note-deleted', `mh-note-refiled', `mh-note-seq', `mh-note-cur', `mh-note-copied', `mh-note-printed'. -Key Binding Changes in mh-e -=========================== - `RET' runs `mh-show' for consistency with the Finder and Info. The +** Key Binding Changes in mh-e 5.0 + +*** `RET' runs `mh-show' for consistency with the Finder and Info. The old binding `.' still works, but `RET' is now the standard binding. - `M-<' now runs `mh-first-msg' for consistency with `M->', which runs -`mh-last-msg'. +*** `M-<' now runs `mh-first-msg' for consistency with `M->', which +runs `mh-last-msg'. - `C-c C-f C-d' in MH-Letter mode moves to a Dcc: header field. +*** `C-c C-f C-d' in MH-Letter mode moves to a Dcc: header field. - `C-c C-f C-r' in MH-Letter mode moves to a From: header field. +*** `C-c C-f C-r' in MH-Letter mode moves to a From: header field. - `g' is now the standard binding for `mh-goto-msg'. The old binding +*** `g' is now the standard binding for `mh-goto-msg'. The old binding `j' still works. -Other Improvements and Changes to mh-e -====================================== + +** Other Improvements and Changes to mh-e 5.0 - `mh-lpr-command-format' no longer passes the "-p" argument to `lpr' -by default. The mail header typically has the date anyway. +*** `mh-lpr-command-format' no longer passes the "-p" argument to +`lpr' by default. The mail header typically has the date anyway. - When prompting for a sequence name, if no sequences have been used +*** When prompting for a sequence name, if no sequences have been used yet, mh-e will offer the first sequence the current message is in. - The patterns of more mailers are recognized by +*** The patterns of more mailers are recognized by `mh-extract-rejected-mail'. - `mh-insert-prefix-string' no longer wraps the call to the +*** `mh-insert-prefix-string' no longer wraps the call to the `mail-citation-hook' function in a `save-excursion' so the hook writer can choose whether to leave point at the beginning or the end of the yanked text. - `mh-write-msg-to-file': The prompt now refers to "message" or -"message body" depending on which will be written. (This is controlled -by a prefix argument.) The file defaults to the last-used file instead +*** `mh-write-msg-to-file': The prompt now refers to "message" or +"message body" depending on which will be written. (This is controlled +by a prefix argument.) The file defaults to the last-used file instead of supplying only the directory name. - mh-e uses message ranges when running MH commands. Thus "rmm 1 2 3 -4 6" is now "rmm 1-4 6". This change makes it less likely to overflow +*** mh-e uses message ranges when running MH commands. Thus "rmm 1 2 3 +4 6" is now "rmm 1-4 6". This change makes it less likely to overflow system argument list limits, and it might be faster, too. -Bug Fixes to mh-e -================= - mh-e's idea of the unseen sequence now stays in sync with MH's +** Bug Fixes to mh-e 5.0 + +*** mh-e's idea of the unseen sequence now stays in sync with MH's better. - Functions that are supposed to find fields in the message header no -longer look in the message body. +*** Functions that are supposed to find fields in the message header +no longer look in the message body. - mh-e would sometimes fail to remove the "%" from a scan line when the -message was removed from a sequence if the message was also in the +*** mh-e would sometimes fail to remove the "%" from a scan line when +the message was removed from a sequence if the message was also in the Previous sequence. - The variable `mh-inc-prog' is now correctly used in all places. +*** The variable `mh-inc-prog' is now correctly used in all places. - `mh-pipe-msg' runs the process in the correct directory. +*** `mh-pipe-msg' runs the process in the correct directory. - A partially scanned folder will no longer lose the "/select" +*** A partially scanned folder will no longer lose the "/select" annotation when you execute marked deletes and refiles with `x'. + +* Changes to mh-e 4.0 + +This file is automatically generated from news-mh-e.txinfo. Do not edit. + +[MH-E-ONEWS has been incorporated here and removed. news-mh-e.txinfo +is no longer available.] + +Note: there are many internal changes to mh-e in this release. If you +have the previous version loaded into your Emacs, you will probably not +be able to load this version on top of it. + +** New Features in mh-e 4.0 + +*** Background folder collection. The first time you are prompted for +a folder, you must wait while mh-e collects the names of all existing +folders. Now however, if you abort, collecting will continue in the +background, and you can do something else in Emacs until the +collection completes. Normally, mh-e will begin collecting folders +names in the background when you first load it; you can disable this +feature by setting `mh-auto-folder-collect' to nil. + +*** There is support for composing MIME messages using the `mhn' +program from MH 6.8. See the documentation string for mh-edit-mhn. +(While composing a letter, type `C-h k C-c C-e'.) See also mhn(1). +There is as yet no support for reading MIME messages. + +*** `mh-show', typically on `.', repositions to the start of the +message if the message is already visible. It used to do nothing in +this case. + +*** The function `mh-unshar-msg' is renamed `mh-store-msg'. It now +does uudecoding, too. Someday it should do MIME. It remembers the last +directory you used and offers it as the default for next time. + +*** New function `mh-header-display', on `,', displays the message +with all headers, including those normally not displayed. Type `.' to +display the message normally again. + +*** New function `mh-list-sequences' lists the sequences in use in the +current folder. + +*** New function `mh-version' displays version information about MH +and mh-e. Please use the output in bug reports. + +*** `mh-quit' now burys the folder buffer and show buffer. + + +** New hooks and customization variables in mh-e 4.0 + +*** `mh-pick-mode-hook': new hook called by new mode `mh-pick-mode'. +The pick buffer didn't used to have its own mode. Another advantage of +`mh-pick-mode' is that `C-h m' works in the pick buffer. + +*** `mail-citation-hook': new variable for supercite. + +*** `mh-refile-msg-hook': new hook called by `mh-refile-msg' (and +`mh-refile-or-write-again' when refiling). + +*** `mh-msg-folder-hook': new hook used by `mh-refile-msg' and +`mh-to-fcc' to provide a default folder for user prompt. + +*** `mh-show-hook': new hook called by `mh-show'. + +*** `mh-delete-msg-hook': new hook called by `mh-delete-msg'. + +*** `mh-show-mode-hook': new hook called by new mode `mh-show-mode' +for `show-' buffers. + +*** `mh-comp-formfile': new variable so can customize `components' +file. + +*** `mh-sortm-args': new variable, a list of extra arguments to be +passed to sortm by `mh-sort-folder'. Give an argument to +`mh-sort-folder' to suppress this behavior. + +*** `mh-send-prog': new variable so can customize name of `send' +program in case of name conflicts. + +*** `mh-scan-prog': new variable so can customize name of `scan' +program to generate custom effects. + +*** `mh-inc-prog': new variable so can customize name of `inc' program +to do fancy management of incoming messages. + +*** `mh-forwarded-letter-subject': new function used by `mh-forward' +to compute the Subject line of the new message. It is a small function +which can be replaced by the user for customization. Uses the new +variable `mh-forward-subject-format', which allows some simple +customizations without rewriting even `mh-forwarded-letter-subject'. + +*** `mh-new-draft-cleaned-headers': new variable, header lines removed +by `mh-edit-again' and `mh-extract-rejected-mail' before offering a +message as a new draft. + +*** `mh-signature-file-name': new variable used by +`mh-insert-signature' to so can customize name of the file to insert. + +*** `mh-read-address': new function called to read all To: and Cc: +addresses. + +*** `mh-msg-folder-hook': new hook used by `mh-refile-msg' and +`mh-to-fcc' to provide a default folder for user prompt. + + +** Key binding changes in mh-e 4.0 + +*** `,' runs new function `mh-header-display'. It is like `.' but it +displays *all* the headers. + +*** `M-#' runs the new function `mh-delete-seq'. One used to have to +type `C-u M-%' to delete a sequence. + +*** `<' no longer does `mh-first-msg', but `M->' now does +`mh-last-msg'. This allows first and last to be consistent (`>' was +taken) and is more likely to be discovered by chance anyway. + +*** `M-d' runs `mh-redistribute', `r' runs `mh-reply' (on the theory +that the more commonly used function should be easier to type, and the +obscure action of redistributing can be harder to type). + +*** `M-o' changed to `C-o' (`mh-write-msg-to-file'). It was +interfering with arrow keys for some people. + +*** `M-n' now runs `mh-store-msg' (formerly `mh-unshar-msg'). + +*** `b' no longer runs `mh-quit'; use `q' instead. `b' may be used in +a future version for something else. + + +** Minor improvements to mh-e 4.0 + +*** The mh-e code is now divided into multiple Emacs Lisp files, so it +starts up faster because Emacs doesn't have to load all of it at once. +(This change also makes it easier for the maintainer to manage +things.) + +*** When searching for the directory containing the MH programs, +search the user's PATH in addition to the built-in directories, to +increase the chance of finding the MH programs. + +*** The subject for a forwarded message no longer has ugly square +brackets around it. + +*** The name of the folder is no longer appears twice in the show +buffer mode line. + +*** When typing a folder name in the minibuffer, parent folders +complete to the trailing slash (/), for easier typing of subfolders. + +*** The folder buffer mode name changed from `mh-e scan' or `mh-e +show' to `MH-Folder', which makes the hook name easier to guess. Added +`mh-showing' to `minor-mode-alist' so there is still an indication in +the mode line of whether messages will be shown automatically. + +*** `mh-rename-seq' does completion on the old sequence name. + +*** If called by a user who has never used MH on this system before, +mh-e runs the MH program `install-mh' to get them set up. + +*** Undo history for previous messages is not kept to avoid wasting +memory. + +*** The internal temp buffer used by mh-e has `buffer-offer-save' +explicitly nil. This change benefits people who change the +`buffer-offer-save' default. + + +** Bug fixes to mh-e 4.0 + +*** `mh-to-field': don't bomb if no To: field. + +*** `mh-get-new-mail': restore annotations, e.g., cur, even if no new +mail. + +*** `mh-rename-seq': verify that the new seq name was accepted by +`mark' before updating state. + +*** `mh-internal-seq': the Previous sequence is not notated, since it +would notate everything scanned. + +*** `mh-read-draft': don't call `find-file-noselect' so an +`auto-mode-alist' doesn't trigger `mh-letter-mode-hook' twice. Faster, +too. + +*** `mh-show': If user moves onto a message that doesn't exist, don't +leave the cursor in the show pane. + +*** `mh-delete-scan-msgs': use `equal', not `=', on the result of +`mh-get-msg-num', since it may be nil. + +*** `mh-get-field': do anchored search so searching for `reply-to:' +doesn't find `in-reply-to:'. + +*** `mh-widen': do nothing if not narrowed. + +*** `mh-clean-message-header': find end of headers even if no body. + + +Local variables: +mode: outline +paragraph-separate: "[ ]*$" +end:
--- a/etc/MH-E-ONEWS Tue Oct 01 18:48:35 2002 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,194 +0,0 @@ -This file is automatically generated from news-mh-e.txinfo. Do not edit. - -User-visible changes to mh-e in version 4.0 from 3.8 - -Note: there are many internal changes to mh-e in this release. If you -have the previous version loaded into your Emacs, you will probably not -be able to load this version on top of it. - - -New Features in mh-e -==================== - -Background folder collection. The first time you are prompted for a -folder, you must wait while mh-e collects the names of all existing -folders. Now however, if you abort, collecting will continue in the -background, and you can do something else in Emacs until the collection -completes. Normally, mh-e will begin collecting folders names in the -background when you first load it; you can disable this feature by -setting `mh-auto-folder-collect' to nil. - -There is support for composing MIME messages using the `mhn' program -from MH 6.8. See the documentation string for mh-edit-mhn. (While -composing a letter, type `C-h k C-c C-e'.) See also mhn(1). There is -as yet no support for reading MIME messages. - -`mh-show', typically on `.', repositions to the start of the message if -the message is already visible. It used to do nothing in this case. - -The function `mh-unshar-msg' is renamed `mh-store-msg'. It now does -uudecoding, too. Someday it should do MIME. It remembers the last -directory you used and offers it as the default for next time. - -New function `mh-header-display', on `,', displays the message with all -headers, including those normally not displayed. Type `.' to display -the message normally again. - -New function `mh-list-sequences' lists the sequences in use in the -current folder. - -New function `mh-version' displays version information about MH and -mh-e. Please use the output in bug reports. - -`mh-quit' now burys the folder buffer and show buffer. - - -New mh-e hooks and customization variables -========================================== - -`mh-pick-mode-hook': new hook called by new mode `mh-pick-mode'. The -pick buffer didn't used to have its own mode. Another advantage of -`mh-pick-mode' is that `C-h m' works in the pick buffer. - -`mail-citation-hook': new variable for supercite. - -`mh-refile-msg-hook': new hook called by `mh-refile-msg' (and -`mh-refile-or-write-again' when refiling). - -`mh-msg-folder-hook': new hook used by `mh-refile-msg' and `mh-to-fcc' -to provide a default folder for user prompt. - -`mh-show-hook': new hook called by `mh-show'. - -`mh-delete-msg-hook': new hook called by `mh-delete-msg'. - -`mh-show-mode-hook': new hook called by new mode `mh-show-mode' for -`show-' buffers. - -`mh-comp-formfile': new variable so can customize `components' file. - -`mh-sortm-args': new variable, a list of extra arguments to be passed to -sortm by `mh-sort-folder'. Give an argument to `mh-sort-folder' to -suppress this behavior. - -`mh-send-prog': new variable so can customize name of `send' program in -case of name conflicts. - -`mh-scan-prog': new variable so can customize name of `scan' program to -generate custom effects. - -`mh-inc-prog': new variable so can customize name of `inc' program to do -fancy management of incoming messages. - -`mh-forwarded-letter-subject': new function used by `mh-forward' to -compute the Subject line of the new message. It is a small function -which can be replaced by the user for customization. Uses the new -variable `mh-forward-subject-format', which allows some simple -customizations without rewriting even `mh-forwarded-letter-subject'. - -`mh-new-draft-cleaned-headers': new variable, header lines removed by -`mh-edit-again' and `mh-extract-rejected-mail' before offering a message -as a new draft. - -`mh-signature-file-name': new variable used by `mh-insert-signature' to -so can customize name of the file to insert. - -`mh-read-address': new function called to read all To: and Cc: -addresses. - -`mh-msg-folder-hook': new hook used by `mh-refile-msg' and `mh-to-fcc' -to provide a default folder for user prompt. - - -Key binding changes in mh-e -=========================== - -`,' runs new function `mh-header-display'. It is like `.' but it -displays *all* the headers. - -`M-#' runs the new function `mh-delete-seq'. One used to have to type -`C-u M-%' to delete a sequence. - -`<' no longer does `mh-first-msg', but `M->' now does `mh-last-msg'. -This allows first and last to be consistent (`>' was taken) and is more -likely to be discovered by chance anyway. - -`M-d' runs `mh-redistribute', `r' runs `mh-reply' (on the theory that -the more commonly used function should be easier to type, and the -obscure action of redistributing can be harder to type). - -`M-o' changed to `C-o' (`mh-write-msg-to-file'). It was interfering -with arrow keys for some people. - -`M-n' now runs `mh-store-msg' (formerly `mh-unshar-msg'). - -`b' no longer runs `mh-quit'; use `q' instead. `b' may be used in a -future version for something else. - - -Minor improvements to mh-e -========================== - -The mh-e code is now divided into multiple Emacs Lisp files, so it -starts up faster because Emacs doesn't have to load all of it at once. -(This change also makes it easier for the maintainer to manage things.) - -When searching for the directory containing the MH programs, search the -user's PATH in addition to the built-in directories, to increase the -chance of finding the MH programs. - -The subject for a forwarded message no longer has ugly square brackets -around it. - -The name of the folder is no longer appears twice in the show buffer -mode line. - -When typing a folder name in the minibuffer, parent folders complete to -the trailing slash (/), for easier typing of subfolders. - -The folder buffer mode name changed from `mh-e scan' or `mh-e show' to -`MH-Folder', which makes the hook name easier to guess. Added -`mh-showing' to `minor-mode-alist' so there is still an indication in -the mode line of whether messages will be shown automatically. - -`mh-rename-seq' does completion on the old sequence name. - -If called by a user who has never used MH on this system before, mh-e -runs the MH program `install-mh' to get them set up. - -Undo history for previous messages is not kept to avoid wasting memory. - -The internal temp buffer used by mh-e has `buffer-offer-save' explicitly -nil. This change benefits people who change the `buffer-offer-save' -default. - - -Bug fixes to mh-e -================= - -`mh-to-field': don't bomb if no To: field. - -`mh-get-new-mail': restore annotations, e.g., cur, even if no new mail. - -`mh-rename-seq': verify that the new seq name was accepted by `mark' -before updating state. - -`mh-internal-seq': the Previous sequence is not notated, since it would -notate everything scanned. - -`mh-read-draft': don't call `find-file-noselect' so an `auto-mode-alist' -doesn't trigger `mh-letter-mode-hook' twice. Faster, too. - -`mh-show': If user moves onto a message that doesn't exist, don't leave -the cursor in the show pane. - -`mh-delete-scan-msgs': use `equal', not `=', on the result of -`mh-get-msg-num', since it may be nil. - -`mh-get-field': do anchored search so searching for `reply-to:' doesn't -find `in-reply-to:'. - -`mh-widen': do nothing if not narrowed. - -`mh-clean-message-header': find end of headers even if no body. -
--- a/etc/NEWS Tue Oct 01 18:48:35 2002 +0000 +++ b/etc/NEWS Tue Oct 01 20:27:23 2002 +0000 @@ -59,6 +59,11 @@ * Changes in Emacs 21.4 +** MH-E changes. + +Upgraded to mh-e version 6.1.1. There have been major changes since +version 5.0.2; see MH-E-NEWS for details. + +++ ** The `emacsclient' understand the options `--eval' and `--display' which tell Emacs resp. to evaluate the given elisp expressions and
--- a/lisp/ChangeLog Tue Oct 01 18:48:35 2002 +0000 +++ b/lisp/ChangeLog Tue Oct 01 20:27:23 2002 +0000 @@ -1,3 +1,19 @@ +2002-10-01 Bill Wohler <wohler@newt.com> + + * mail/mh-comp.el, mail/mh-e.el, mail/mh-funcs.el, + mail/mh-mime.el, mail/mh-pick.el, mail/mh-seq.el, + mail/mh-utils.el, mail/mh-xemacs-compat.el, mail/reply2.pbm, + mail/reply2.xpm, toolbar/execute.pbm, toolbar/execute.xpm, + toolbar/page-down.pbm, toolbar/page-down.xpm, toolbar/refile.pbm, + toolbar/refile.xpm, toolbar/repack.pbm, toolbar/repack.xpm, + toolbar/rescan.pbm, toolbar/rescan.xpm, toolbar/show.pbm, + toolbar/show.xpm, toolbar/widen.pbm, toolbar/widen.xpm: Upgraded + to mh-e version 6.1.1. Full ChangeLog available in + http://prdownloads.sourceforge.net/mh-e/mh-e-6.1.tgz?download . + There were no user-visible changes in 6.1.1 from 6.1--only the + section of the Makefile that installs the files into Emacs was + changed. + 2002-10-01 Juanma Barranquero <lektu@terra.es> * eshell/esh-module.el (eshell-load-defgroups): Add "no-byte-compile: t"
--- a/lisp/mail/mh-comp.el Tue Oct 01 18:48:35 2002 +0000 +++ b/lisp/mail/mh-comp.el Tue Oct 01 20:27:23 2002 +0000 @@ -1,11 +1,11 @@ ;;; mh-comp.el --- mh-e functions for composing messages -;; Time-stamp: <2001-12-20 18:55:07 pavel> -;; Copyright (C) 1993,1995,1997,2000 Free Software Foundation, Inc. +;; Copyright (C) 1993,1995,1997,2000,2001,2002 Free Software Foundation, Inc. +;; Author: Bill Wohler <wohler@newt.com> ;; Maintainer: Bill Wohler <wohler@newt.com> ;; Keywords: mail -;; Bug-reports: include `M-x mh-version' output in any correspondence +;; See: mh-e.el ;; This file is part of GNU Emacs. @@ -30,17 +30,69 @@ ;;; Change Log: -;; $Id: mh-comp.el,v 1.22 2001/07/15 19:53:53 pj Exp $ +;; $Id: mh-comp.el,v 1.56 2002/04/07 19:20:56 wohler Exp $ ;;; Code: (provide 'mh-comp) +(require 'mh-e) (require 'mh-utils) +(require 'gnus-util) +(require 'easymenu) + +;;; autoloads from mh-mime + +(autoload 'mh-mhn-compose-insertion "mh-mime" + "Add a directive to insert a MIME message part from a file. +This is the typical way to insert non-text parts in a message. +See also \\[mh-edit-mhn]." t) + +(autoload 'mh-mhn-compose-anon-ftp "mh-mime" + "Add a directive for a MIME anonymous ftp external body part. +This directive tells MH to include a reference to a +message/external-body part retrievable by anonymous FTP. +See also \\[mh-edit-mhn]." t) + +(autoload 'mh-mhn-compose-external-compressed-tar "mh-mime" + "Add a directive to include a MIME reference to a compressed tar file. +The file should be available via anonymous ftp. This directive +tells MH to include a reference to a message/external-body part. +See also \\[mh-edit-mhn]." t) + +(autoload 'mh-mhn-compose-forw "mh-mime" + "Add a forw directive to this message, to forward a message with MIME. +This directive tells MH to include another message in this one. +See also \\[mh-edit-mhn]." t) + +(autoload 'mh-edit-mhn "mh-mime" + "Format the current draft for MIME, expanding any mhn directives. +Process the current draft with the mhn program, which, +using directives already inserted in the draft, fills in +all the MIME components and header fields. +This step should be done last just before sending the message. +The mhn program is part of MH version 6.8 or later. +The \\[mh-revert-mhn-edit] command undoes this command. +For assistance with creating mhn directives to insert +various types of components in a message, see +\\[mh-mhn-compose-insertion] (generic insertion from a file), +\\[mh-mhn-compose-anon-ftp] (external reference to file via anonymous ftp), +\\[mh-mhn-compose-external-compressed-tar] \ +\(reference to compressed tar file via anonymous ftp), and +\\[mh-mhn-compose-forw] (forward message)." t) + +(autoload 'mh-revert-mhn-edit "mh-mime" + "Undoes the effect of \\[mh-edit-mhn] by reverting to the backup file. +Optional non-nil argument means don't ask for confirmation." t) + +;;; Other Autoloads. + +(autoload 'Info-goto-node "info") +(autoload 'mail-mode-fill-paragraph "sendmail") ;;; Site customization (see also mh-utils.el): (defgroup mh-compose nil - "Mh-e functions for composing messages" + "Mh-e functions for composing messages." :prefix "mh-" :group 'mh) @@ -54,6 +106,9 @@ 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.") (defvar mh-note-repl "-" "String whose first character is used to notate replied to messages.") @@ -85,11 +140,17 @@ See also the variable `mh-yank-from-start-of-msg', which controls how much of the message passed to the hook.") -;;; Copied from sendmail.el for Hyperbole -(defvar mail-header-separator "--------" - "*Line used by MH to separate headers from text in messages being composed.") +;;; Personal preferences: -;;; Personal preferences: +(defcustom mh-insert-x-mailer-p t + "*If t, append an X-Mailer field to the header." + :type 'boolean + :group 'mh-compose) + +(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.") (defcustom mh-delete-yanked-msg-window nil "*Controls window display when a message is yanked by \\<mh-letter-mode-map>\\[mh-yank-cur-msg]. @@ -152,11 +213,30 @@ system MH lib directory.") (defvar mh-repl-group-formfile "replgroupcomps" - "Name of file to be used as a skeleton for replying to the sender -and all recipients of a messages. Only used if mh-nmh-p 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.") + "Name of file to be used as a skeleton for replying to the sender and all recipients of a message. +Only used if `mh-nmh-p' 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.") + +(defcustom mh-reply-show-message-p t + "*Whether the show buffer is displayed using \\<mh-letter-mode-map>\\[mh-reply]. + +The setting of this variable determines whether the MH `show-buffer' is +displayed with the current message when using `mh-reply' without a prefix +argument. Set it to nil if you already include the message automatically +in your draft using + repl: -filter repl.filter +in your ~/.mh_profile file." + :type 'boolean + :group 'mh-compose) + +(defcustom mh-letter-fill-column 72 + "*Fill column to use in `mh-letter-mode'. +This is usually less than in other text modes because email messages get +quoted by some prefix (sometimes many times) when they are replied-to, +and it's best to avoid quoted lines that span more than 80 columns." + :type 'integer + :group 'mh-compose) ;;; Hooks: @@ -176,18 +256,17 @@ :type 'hook :group 'mh-compose) - (defvar mh-rejected-letter-start - (concat "^ ----- Unsent message follows -----$" ;from sendmail V5 - "\\|^ ----- 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 - ) - "Regexp specifying the beginning of the wrapper around a returned letter. -This wrapper is generated by the mail system when rejecting a letter.") + (regexp-opt + '("^Content-Type: message/rfc822$" ;MIME MDN + "^ ----- Unsent message follows -----$" ;from sendmail V5 + "^ ----- 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:" @@ -197,7 +276,7 @@ (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.") + "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.") @@ -234,16 +313,41 @@ 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." +Users should use `\\[mh-smail]' to compose mail. +Optional arguments for setting certain fields include TO, SUBJECT, and +OTHER-HEADERS." (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))))) (defun mh-edit-again (msg) - "Clean-up a draft or a message previously sent and make it resendable. + "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. +The variable `mh-new-draft-cleaned-headers' specifies the headers to remove. See also documentation for `\\[mh-send]' function." (interactive (list (mh-get-msg-num t))) (let* ((from-folder mh-current-folder) @@ -256,6 +360,7 @@ (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 @@ -263,7 +368,7 @@ (defun mh-extract-rejected-mail (msg) - "Extract a letter returned by the mail system and make it resendable. + "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 documentation for `\\[mh-send]' function." @@ -278,6 +383,7 @@ (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 @@ -288,9 +394,9 @@ (defun mh-forward (to cc &optional msg-or-seq) - "Forward a message or message sequence. Defaults to displayed message. -If optional prefix argument provided, then prompt for the message sequence. -See also documentation for `\\[mh-send]' function." + "Forward displayed message to recipients TO and CC. +If optional prefix argument MSG-OR-SEQ provided, then prompt for the message +sequence. See also documentation for `\\[mh-send]' function." (interactive (list (mh-read-address "To: ") (mh-read-address "Cc: ") (if current-prefix-arg @@ -300,6 +406,10 @@ (setq msg-or-seq (mh-get-msg-num t))) (let* ((folder mh-current-folder) (config (current-window-configuration)) + (fwd-msg-file (mh-msg-filename (if (numberp msg-or-seq) + msg-or-seq + (car (mh-seq-to-msgs msg-or-seq))) + 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)) @@ -311,11 +421,7 @@ (mh-insert-fields "To:" to "Cc:" cc) (save-buffer))) (t - (mh-read-draft "" draft-name nil)))) - (fwd-msg-file (mh-msg-filename (if (numberp msg-or-seq) - msg-or-seq - (car (mh-seq-to-msgs msg-or-seq))) - folder))) + (mh-read-draft "" draft-name nil))))) (let (orig-from orig-subject) (save-excursion @@ -325,12 +431,13 @@ (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-forwarded-letter-subject orig-from orig-subject)) + (mail-header-separator mh-mail-header-separator)) (mh-insert-fields "Subject:" forw-subject) (goto-char (point-min)) (if (re-search-forward "^------- Forwarded Message" nil t) (forward-line -1) - (re-search-forward "^--------") + (re-search-forward mail-header-separator) (forward-line 1)) (delete-other-windows) (if (numberp msg-or-seq) @@ -368,7 +475,8 @@ (defun mh-redistribute (to cc &optional msg) - "Redistribute a letter. + "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: ") @@ -391,20 +499,32 @@ nil) (save-buffer) (message "Redistributing...") - (if mh-redist-full-contents - (call-process "/bin/sh" nil 0 nil "-c" - (format "mhdist=1 mhaltmsg=%s %s -push %s" - buffer-file-name - (expand-file-name mh-send-prog mh-progs) - buffer-file-name)) - (call-process "/bin/sh" nil 0 nil "-c" - (format "mhdist=1 mhaltmsg=%s mhannotate=1 %s -push %s" - (mh-msg-filename msg folder) - (expand-file-name mh-send-prog mh-progs) - buffer-file-name))) + (if (not mh-redist-background) + (if mh-redist-full-contents + (call-process "/bin/sh" nil 0 nil "-c" + (format "mhdist=1 mhaltmsg=%s %s -push %s" + buffer-file-name + (expand-file-name mh-send-prog mh-progs) + buffer-file-name)) + (call-process "/bin/sh" nil 0 nil "-c" + (format "mhdist=1 mhaltmsg=%s mhannotate=1 %s -push %s" + (mh-msg-filename msg folder) + (expand-file-name mh-send-prog mh-progs) + buffer-file-name)))) (mh-annotate-msg msg folder mh-note-dist "-component" "Resent:" "-text" (format "\"%s %s\"" to cc)) + (if mh-redist-background + (mh-exec-cmd-daemon "/bin/sh" "-c" + (format "mhdist=1 mhaltmsg=%s %s %s %s" + (if mh-redist-full-contents + buffer-file-name + (mh-msg-filename msg folder)) + (if mh-redist-full-contents + "" + "mhannotate=1") + (mh-expand-file-name "send" mh-progs) + buffer-file-name))) (kill-buffer draft) (message "Redistributing...done")))) @@ -462,6 +582,7 @@ (goto-char (point-min)) (mh-goto-header-end 1) (or includep + (not mh-reply-show-message-p) (mh-in-show-buffer (show-buffer) (mh-display-msg message folder))) (mh-add-msgs-to-seq message 'answered t) @@ -472,12 +593,14 @@ (defun mh-send (to cc subject) "Compose and send a letter. -The file named by `mh-comp-formfile' will be used as the form. + Do not call this function from outside mh-e; use \\[mh-smail] instead. -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." +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-read-address "To: ") (mh-read-address "Cc: ") @@ -489,9 +612,15 @@ (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. -See also documentation for `\\[mh-send]' function." + +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-read-address "To: ") (mh-read-address "Cc: ") @@ -540,7 +669,7 @@ (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 + ;; 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. @@ -617,7 +746,7 @@ (cond ((equal value "") nil) ((mh-position-on-field field-name) - (insert " " value)) + (insert " " (or value ""))) (t (insert field-name " " value "\n"))) (setq name-values (cdr (cdr name-values))))))) @@ -628,10 +757,11 @@ ;; 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. - (if (mh-goto-header-field field) - (progn - (mh-header-field-end) - t))) + (cond ((mh-goto-header-field field) + (mh-header-field-end) + t) + ((mh-goto-header-end 0) + nil))) (defun mh-get-header-field (field) @@ -651,7 +781,7 @@ (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. + ;; Returns T if found, NIL if not. (goto-char (point-min)) (let ((case-fold-search t) (headers-end (save-excursion @@ -659,15 +789,6 @@ (point)))) (re-search-forward (format "^%s" field) headers-end t))) -(defun mh-header-field-end () - ;; Move to the end of the current header field. - ;; Handles RFC 822 continuation lines. - (forward-line 1) - (while (looking-at "^[ \t]") - (forward-line 1)) - (backward-char 1)) ;to end of previous line - - (defun mh-goto-header-end (arg) ;; Find the end of the message header in the current buffer and position ;; the cursor at the ARG'th newline after the header. @@ -699,39 +820,24 @@ ;;;###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. -See the documentation for \\[mh-edit-mhn] for information on composing MIME -messages. -\\{mh-letter-mode-map} - -Variables controlling this mode (defaults in parentheses): - - mh-delete-yanked-msg-window (nil) - If non-nil, \\[mh-yank-cur-msg] will delete any windows displaying - the yanked message. +If MH MIME directives are added manually, you must first run \\[mh-edit-mhn] +before sending the message. MIME directives that are added by mh-e commands +such as \\[mh-mhn-compose-insertion] are processed automatically when the +message is sent. - mh-yank-from-start-of-msg (t) - If non-nil, \\[mh-yank-cur-msg] will include the entire message. - If `body', just yank the body (no header). - If nil, only the portion of the message following the point will be yanked. - If there is a region, this variable is ignored. - - mh-ins-buf-prefix (\"> \") - String to insert before each non-blank line of a message as it is - inserted in a draft letter. +Options that control this mode can be changed with +\\[customize-group]; specify the \"mh-compose\" group. - mh-signature-file-name (\"~/.signature\") - File to be inserted into message by \\[mh-insert-signature]. +When a message is composed, the hooks `text-mode-hook' and +`mh-letter-mode-hook' are run. -This command runs the normal hooks `text-mode-hook' and `mh-letter-mode-hook'." +\\{mh-letter-mode-map}" + (or mh-user-path (mh-find-path)) - (make-local-variable 'paragraph-start) - (setq paragraph-start (concat "^[ \t]*[-_][-_][-_]+$\\|" paragraph-start)) - (make-local-variable 'paragraph-separate) - (setq paragraph-separate - (concat "^[ \t]*[-_][-_][-_]+$\\|" paragraph-separate)) (make-local-variable 'mh-send-args) (make-local-variable 'mh-annotate-char) (make-local-variable 'mh-annotate-field) @@ -739,7 +845,56 @@ (make-local-variable 'mh-sent-from-folder) (make-local-variable 'mh-sent-from-msg) (make-local-variable 'mail-header-separator) - (setq mail-header-separator "--------") ;for Hyperbole + (setq mail-header-separator mh-mail-header-separator) ;override sendmail.el + + ;; 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 'mail-mode-fill-paragraph) + (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 --- + + (if (and (boundp 'tool-bar-mode) tool-bar-mode) + (set (make-local-variable 'tool-bar-map) mh-letter-tool-bar-map)) + (make-local-variable 'font-lock-defaults) + (cond + ((equal mh-highlight-citation-p 'font-lock) + (setq font-lock-defaults '(mh-show-font-lock-keywords-with-cite t))) + ((equal mh-highlight-citation-p 'gnus) + (setq font-lock-defaults '(mh-show-font-lock-keywords t)) + (mh-gnus-article-highlight-citation)) + (t + (setq font-lock-defaults '(mh-show-font-lock-keywords t)))) + (easy-menu-add mh-letter-menu) + ;; See if a "forw: -mime" message containing a MIME composition. + ;; mode clears local vars, so can't do this in mh-forward. + (save-excursion + (goto-char (point-min)) + (when (and (re-search-forward mail-header-separator nil t) + (= 0 (forward-line 1)) + (looking-at "^#forw")) + (require 'mh-mime) ;Need mh-mhn-compose-insert-p local var + (setq mh-mhn-compose-insert-p t))) + (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) @@ -755,14 +910,13 @@ (do-auto-fill))) -(defun mh-in-header-p () - ;; Return non-nil if the point is in the header of a draft message. +(defun mh-insert-header-separator () + ;; Inserts `mh-mail-header-separator', if absent. (save-excursion - (let ((cur-point (point))) - (goto-char (point-min)) - (re-search-forward "^-*$" nil t) - (< cur-point (point))))) - + (goto-char (point-min)) + (rfc822-goto-eoh) + (if (looking-at "$") + (insert mh-mail-header-separator)))) (defun mh-to-field () "Move point to the end of a specified header field. @@ -839,6 +993,30 @@ ;;; Routines to compose and send a letter. +(defun mh-insert-x-mailer () + ;; Appends an X-Mailer field to the header. + ;; The versions of mh-e, Emacs, and MH are shown. + + ;; Lazily initialize mh-x-mailer-string. + (when (null mh-x-mailer-string) + (save-window-excursion + (mh-version) + (set-buffer mh-temp-buffer) + (if mh-nmh-p + (search-forward-regexp "^nmh-\\(\\S +\\)") + (search-forward-regexp "^MH \\(\\S +\\)" nil t)) + (let ((x-mailer-mh (buffer-substring (match-beginning 1) (match-end 1)))) + (setq mh-x-mailer-string + (format "mh-e %s; %s %s; Emacs %d.%d" + mh-version (if mh-nmh-p "nmh" "MH") x-mailer-mh + emacs-major-version emacs-minor-version))) + (kill-buffer mh-temp-buffer))) + ;; Insert X-Mailer, but only if it doesn't already exist. + (save-excursion + (when (null (mh-goto-header-field "X-Mailer")) + (mh-insert-fields "X-Mailer:" mh-x-mailer-string)))) + + (defun mh-compose-and-send-mail (draft send-args sent-from-folder sent-from-msg to subject cc @@ -877,24 +1055,31 @@ (defun mh-send-letter (&optional arg) "Send the draft letter in the current buffer. -If optional prefix argument is provided, monitor delivery. -Run `mh-before-send-letter-hook' before actually doing anything." +If optional prefix argument ARG is provided, monitor delivery. +Run `mh-before-send-letter-hook' before actually doing anything. +Run `\\[mh-edit-mhn]' if variable `mh-mhn-compose-insert-p' is set." (interactive "P") (run-hooks 'mh-before-send-letter-hook) + (if (and (boundp 'mh-mhn-compose-insert-p) + mh-mhn-compose-insert-p) + (mh-edit-mhn)) + (if mh-insert-x-mailer-p (mh-insert-x-mailer)) (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) + (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 sendmail-coding-system - default-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)))) (cond (arg (pop-to-buffer "MH mail delivery") @@ -1006,9 +1191,10 @@ (run-hooks 'mh-yank-hooks)) (t (or (bolp) (forward-line 1)) - (while (< (point) (mark)) - (insert mh-ins-string) - (forward-line 1))))) + (let ((zmacs-regions nil)) ;so "(mark)" works in XEmacs + (while (< (point) (mark)) + (insert mh-ins-string) + (forward-line 1)))))) (defun mh-fully-kill-draft () @@ -1027,81 +1213,122 @@ (error "Message not killed"))) -;;; Build the letter-mode keymap: +(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) + ""))) + -(define-key mh-letter-mode-map "\C-c\C-f\C-b" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-f\C-c" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-f\C-d" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-f\C-f" 'mh-to-fcc) -(define-key mh-letter-mode-map "\C-c\C-f\C-r" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-f\C-s" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-f\C-t" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-fb" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-fc" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-fd" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-ff" 'mh-to-fcc) -(define-key mh-letter-mode-map "\C-c\C-fr" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-fs" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-ft" 'mh-to-field) -(define-key mh-letter-mode-map "\C-c\C-i" 'mh-insert-letter) -(define-key mh-letter-mode-map "\C-c\C-q" 'mh-fully-kill-draft) -(define-key mh-letter-mode-map "\C-c\C-\\" 'mh-fully-kill-draft) ;if no C-q -(define-key mh-letter-mode-map "\C-c\C-s" 'mh-insert-signature) -(define-key mh-letter-mode-map "\C-c\C-^" 'mh-insert-signature) ;if no C-s -(define-key mh-letter-mode-map "\C-c\C-w" 'mh-check-whom) -(define-key mh-letter-mode-map "\C-c\C-y" 'mh-yank-cur-msg) -(define-key mh-letter-mode-map "\C-c\C-c" 'mh-send-letter) -(define-key mh-letter-mode-map "\C-c\C-m\C-f" 'mh-mhn-compose-forw) -(define-key mh-letter-mode-map "\C-c\C-m\C-e" 'mh-mhn-compose-anon-ftp) -(define-key mh-letter-mode-map "\C-c\C-m\C-t" 'mh-mhn-compose-external-compressed-tar) -(define-key mh-letter-mode-map "\C-c\C-m\C-i" 'mh-mhn-compose-insertion) -(define-key mh-letter-mode-map "\C-c\C-e" 'mh-edit-mhn) -(define-key mh-letter-mode-map "\C-c\C-m\C-u" 'mh-revert-mhn-edit) +(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)) + (point (point)) + (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)))) -;; "C-c /" prefix is used in mh-letter-mode by pgp.el - -;;; autoloads from mh-mime -(autoload 'mh-mhn-compose-insertion "mh-mime" - "Add a directive to insert a MIME message part from a file. -This is the typical way to insert non-text parts in a message. -See also \\[mh-edit-mhn]." t) +;;; Build the letter-mode keymap: +(gnus-define-keys mh-letter-mode-map + "\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-o" mh-open-line + "\C-c\C-q" mh-fully-kill-draft + "\C-c\C-\\" mh-fully-kill-draft ;if no C-q + "\C-c\C-s" mh-insert-signature + "\C-c\C-^" mh-insert-signature ;if no C-s + "\C-c\C-w" mh-check-whom + "\C-c\C-y" mh-yank-cur-msg + "\C-c\C-c" mh-send-letter + "\C-c\C-m\C-f" mh-mhn-compose-forw + "\C-c\C-m\C-e" mh-mhn-compose-anon-ftp + "\C-c\C-m\C-t" mh-mhn-compose-external-compressed-tar + "\C-c\C-m\C-i" mh-mhn-compose-insertion + "\C-c\C-e" mh-edit-mhn + "\C-c\C-m\C-u" mh-revert-mhn-edit) -(autoload 'mh-mhn-compose-anon-ftp "mh-mime" - "Add a directive for a MIME anonymous ftp external body part. -This directive tells MH to include a reference to a -message/external-body part retrievable by anonymous FTP. -See also \\[mh-edit-mhn]." t) - -(autoload 'mh-mhn-compose-external-compressed-tar "mh-mime" - "Add a directive to include a MIME reference to a compressed tar file. -The file should be available via anonymous ftp. This directive -tells MH to include a reference to a message/external-body part. -See also \\[mh-edit-mhn]." t) +;; "C-c /" prefix is used in mh-letter-mode by pgp.el and mailcrypt.el. -(autoload 'mh-mhn-compose-forw "mh-mime" - "Add a forw directive to this message, to forward a message with MIME. -This directive tells MH to include another message in this one. -See also \\[mh-edit-mhn]." t) +;;; Menu extracted from mh-menubar.el V1.1 (31 July 2001) +(cond + ((fboundp 'easy-menu-define) + (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] + ["Compose Insertion (MIME)..." mh-mhn-compose-insertion t] + ["Compose Compressed tar (MIME)..." mh-mhn-compose-external-compressed-tar t] + ["Compose Anon FTP (MIME)..." mh-mhn-compose-anon-ftp t] + ["Compose Forward (MIME)..." mh-mhn-compose-forw t] + ["Pull in All Compositions (MIME)" mh-edit-mhn t] + ["Revert to Non-MIME Edit" mh-revert-mhn-edit t] + ["Kill This Draft" mh-fully-kill-draft t])))) + +(defun mh-customize () + "Customize mh-e variables." + (interactive) + (customize-group 'mh)) -(autoload 'mh-edit-mhn "mh-mime" - "Format the current draft for MIME, expanding any mhn directives. -Process the current draft with the mhn program, which, -using directives already inserted in the draft, fills in -all the MIME components and header fields. -This step should be done last just before sending the message. -The mhn program is part of MH version 6.8 or later. -The \\[mh-revert-mhn-edit] command undoes this command. -For assistance with creating mhn directives to insert -various types of components in a message, see -\\[mh-mhn-compose-insertion] (generic insertion from a file), -\\[mh-mhn-compose-anon-ftp] (external reference to file via anonymous ftp), -\\[mh-mhn-compose-external-compressed-tar] \ -\(reference to compressed tar file via anonymous ftp), and -\\[mh-mhn-compose-forw] (forward message)." t) - -(autoload 'mh-revert-mhn-edit "mh-mime" - "Undoes the effect of \\[mh-edit-mhn] by reverting to the backup file. -Optional non-nil argument means don't ask for confirmation." t) +;;; Support for emacs21 toolbar using gnus/message.el icons (and code). +(eval-when-compile (defvar tool-bar-map)) +(when (and (fboundp 'tool-bar-add-item) + tool-bar-mode) + (defvar mh-letter-tool-bar-map + (let ((tool-bar-map (make-sparse-keymap))) + (tool-bar-add-item "mail_send" 'mh-send-letter 'mh-letter-send + :help "Send this letter") + (tool-bar-add-item "attach" 'mh-mhn-compose-insertion 'mh-letter-compose + :help "Insert attachment") + (tool-bar-add-item "spell" 'ispell-message 'mh-letter-ispell + :help "Check spelling") + (tool-bar-add-item-from-menu 'save-buffer "save") + (tool-bar-add-item-from-menu 'undo "undo") + (tool-bar-add-item-from-menu 'kill-region "cut") + (tool-bar-add-item-from-menu 'menu-bar-kill-ring-save "copy") + (tool-bar-add-item "close" 'mh-fully-kill-draft 'mh-letter-kill + :help "Kill this draft") + (tool-bar-add-item "preferences" (lambda () + (interactive) + (customize-group "mh-compose")) + 'mh-letter-customize + :help "mh-e composition preferences") + (tool-bar-add-item "help" (lambda () + (interactive) + (Info-goto-node "(mh-e)Draft Editing")) + 'mh-letter-help :help "Help") + tool-bar-map))) ;;; mh-comp.el ends here
--- a/lisp/mail/mh-e.el Tue Oct 01 18:48:35 2002 +0000 +++ b/lisp/mail/mh-e.el Tue Oct 01 20:27:23 2002 +0000 @@ -1,11 +1,11 @@ ;;; mh-e.el --- GNU Emacs interface to the MH mail system -;; Copyright (C) 1985,86,87,88,90,92,93,94,95,97,2000 Free Software Foundation, Inc. +;; Copyright (C) 1985,86,87,88,90,92,93,94,95,97,2000,2001,2002 Free Software Foundation, Inc. +;; Author: Bill Wohler <wohler@newt.com> ;; Maintainer: Bill Wohler <wohler@newt.com> -;; Version: 5.0.2 +;; Version: 6.1.1 ;; Keywords: mail -;; Bug-reports: include `M-x mh-version' output in any correspondence ;; This file is part of GNU Emacs. @@ -26,60 +26,89 @@ ;;; Commentary: -;; 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. - -;; 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 and mh-e. +;; 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. -;; mh-e is an Emacs interface to the MH mail system. -;; There is a mailing list for discussion of mh-e and -;; announcements of new versions. Send a "subscribe" message to -;; mh-e-request@gnu.org to be added. Do not report bugs here; mail -;; them directly to the maintainer (see top of mh-e.el source). -;; Include the output of M-x mh-version in any bug report. +;; Your .emacs might benefit from these bindings: +;; (global-set-key "\C-cr" 'mh-rmail) +;; (global-set-key "\C-xm" 'mh-smail) +;; (global-set-key "\C-x4m" 'mh-smail-other-window) + +;; MH (Message Handler) is a powerful mail reader. -;; mh-e works with GNU Emacs 18 or 19, and MH 6. +;; 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 and mh-e: +;; http://www.faqs.org/faqs/mail/mh-faq/part1/preamble.html -;; NB. MH must have been compiled with the MHE compiler flag or several +;; N.B. MH must have been compiled with the MHE compiler flag or several ;; features necessary for mh-e will be missing from MH commands, specifically ;; the -build switch to repl and forw. -;; Your .emacs might benefit from these bindings: -;; (global-set-key "\C-cr" 'mh-rmail) -;; (global-set-key "\C-xm" 'mh-smail) -;; (global-set-key "\C-x4m" 'mh-smail-other-window) +;; mh-e is an Emacs interface to the MH mail system. + +;; mh-e is supported in GNU Emacs 20 and 21, with MH 6.8.4 and nmh 1.0.4. + +;; Mailing Lists: +;; mh-e-users@lists.sourceforge.net +;; mh-e-announce@lists.sourceforge.net +;; mh-e-devel@lists.sourceforge.net +;; +;; Subscribe by sending a "subscribe" message to +;; <list>-request@lists.sourceforge.net, or by using the web interface at +;; https://sourceforge.net/mail/?group_id=13357 + +;; Bug Reports: +;; https://sourceforge.net/tracker/?group_id=13357&atid=113357 +;; Include the output of M-x mh-version in any bug report. + +;; Feature Requests: +;; https://sourceforge.net/tracker/?atid=363357&group_id=13357&func=browse + +;; Support: +;; https://sourceforge.net/tracker/?group_id=13357&atid=213357 ;;; Change Log: ;; 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@stop.mail-abuse.org -(defconst mh-e-RCS-id "$Id: mh-e.el,v 1.30 2001/09/23 17:38:22 eliz Exp $") +;; Modified by Stephen Gildea 1988. gildea@lcs.mit.edu +;; Maintenance picked up by Bill Wohler <wohler@newt.com> and the +;; SourceForge Crew <http://mh-e.sourceforge.net/>. 2001. + +;; $Id: mh-e.el,v 1.99.1.1 2002/10/01 19:41:43 wohler Exp $ ;;; Code: (provide 'mh-e) (require 'mh-utils) +(require 'gnus-util) +(require 'easymenu) +(if (save-match-data (string-match "XEmacs\\|Lucid" emacs-version)) + (require 'mh-xemacs-compat)) +(eval-when-compile (require 'cl)) + +(defconst mh-version "6.1.1" "Version number of mh-e.") + +;;; Initial Autoloads + +(autoload 'Info-goto-node "info") ;;; Hooks: (defgroup mh nil - "Emacs interface to the MH mail system" + "Emacs interface to the MH mail system." :group 'mail) (defgroup mh-hook nil - "Hooks to mh-e mode" + "Hooks to mh-e mode." :prefix "mh-" :group 'mh) - (defcustom mh-folder-mode-hook nil "Invoked in MH-Folder mode on a new folder." :type 'hook @@ -90,6 +119,14 @@ :type 'hook :group 'mh-hook) +(defcustom mh-folder-updated-hook nil + "Invoked when the folder actions (such as moves and deletes) are performed. +Variables that are useful in this hook include `mh-delete-list' and +`mh-refile-list' which can be used to see which changes are being made to +current folder, `mh-current-folder'." + :type 'hook + :group 'mh-hook) + (defcustom mh-show-hook nil "Invoked after \\<mh-folder-mode-map>`\\[mh-show]' shows a message." :type 'hook @@ -111,16 +148,23 @@ :group 'mh-hook) (defcustom mh-before-quit-hook nil - "Invoked by \\<mh-folder-mode-map>`\\[mh-quit]' before quitting mh-e. See also mh-quit-hook." + "Invoked by \\<mh-folder-mode-map>`\\[mh-quit]' before quitting mh-e. +See also `mh-quit-hook'." :type 'hook :group 'mh-hook) (defcustom mh-quit-hook nil - "Invoked after \\<mh-folder-mode-map>`\\[mh-quit]' quits mh-e. See also mh-before-quit-hook." + "Invoked after \\<mh-folder-mode-map>`\\[mh-quit]' quits mh-e. +See also `mh-before-quit-hook'." :type 'hook :group 'mh-hook) - +(defcustom mh-unseen-updated-hook nil + "Invoked after the unseen sequence has been updated. +The variable `mh-seen-list' can be used to obtain the list of messages which +will be removed from the unseen sequence." + :type 'hook + :group 'mh-hook) ;;; Personal preferences: @@ -135,8 +179,7 @@ (defcustom mh-scan-prog "scan" "*Program to run to generate one-line-per-message listing of a folder. Normally \"scan\" or a file name linked to scan. This file is searched -for relative to the mh-progs directory unless it is an absolute pathname. -Automatically becomes buffer-local when set in any fashion." +for relative to the mh-progs directory unless it is an absolute pathname." :type 'string :group 'mh) (make-variable-buffer-local 'mh-scan-prog) @@ -161,8 +204,11 @@ :group 'mh) (defcustom mh-do-not-confirm nil - "*Non-nil means do not prompt for confirmation before some mh-e commands. -Affects non-recoverable commands such as `mh-kill-folder' and `mh-undo-folder'." + "*Non-nil means do not prompt for confirmation. +Commands such as `mh-pack-folder' prompt to confirm whether to process +outstanding moves and deletes or not before continuing. A non-nil setting will +perform the action--which is usually desired but cannot be retracted--without +question." :type 'boolean :group 'mh) @@ -173,25 +219,6 @@ directory) :group 'mh) -;;; Parameterize mh-e to work with different scan formats. The defaults work -;;; with the standard MH scan listings, in which the first 4 characters on -;;; the line are the message number, followed by two places for notations. - -(defvar mh-good-msg-regexp "^....[^D^]" - "Regexp specifying the scan lines that are 'good' messages.") - -(defvar mh-deleted-msg-regexp "^....D" - "Regexp matching scan lines of deleted messages.") - -(defvar mh-refiled-msg-regexp "^....\\^" - "Regexp matching scan lines of refiled messages.") - -(defvar mh-valid-scan-line "^ *[0-9]" - "Regexp matching scan lines for messages (not error messages).") - -(defvar mh-cur-scan-msg-regexp "^....\\+" - "Regexp matching scan line for the cur message.") - (defvar mh-note-deleted "D" "String whose first character is used to notate deleted messages.") @@ -203,8 +230,358 @@ (defvar mh-partial-folder-mode-line-annotation "select" "Annotation when displaying part of a folder. -The string is displayed after the folder's name. nil for no annotation.") +The string is displayed after the folder's name. NIL for no annotation.") + +;;; Parameterize mh-e to work with different scan formats. The defaults work +;;; with the standard MH scan listings, in which the first 4 characters on +;;; the line are the message number, followed by two places for notations. + +(defcustom mh-scan-format-file t + "Specifies the format file to pass to the scan program. +If t, the format string will be taken from the either `mh-scan-format-mh' +or `mh-scan-format-nmh' depending on whether MH or nmh is in use. +If nil, the default scan output will be used. + +If you customize the scan format, you may need to modify a few variables +containing regexps that mh-e uses to identify specific portions of the output. +Use `M-x apropos RET mh-scan.*regexp' to obtain a list of these variables." + :type '(choice (const :tag "Use mh-e scan format" t) + (const :tag "Use default scan format" nil) + (file :tag "Specify a scan format file")) + :group 'mh) + +;; The following scan formats are passed to the scan program if the +;; setting of `mh-scan-format-file' above is nil. They are identical +;; except the later one makes use of the nmh `decode' function to +;; decode RFC 2047 encodings. + +(defvar mh-scan-format-mh + (concat + "%4(msg)" + "%<(cur)+%| %>" + "%<{replied}-" + "%?(nonnull(comp{to}))%<(mymbox{to})t%>" + "%?(nonnull(comp{cc}))%<(mymbox{cc})c%>" + "%?(nonnull(comp{bcc}))%<(mymbox{bcc})b%>" + "%?(nonnull(comp{newsgroups}))n%>" + "%<(zero) %>" + "%02(mon{date})/%02(mday{date})%<{date} %|*%>" + "%<(mymbox{from})%<{to}To:%14(friendly{to})%>%>" + "%<(zero)%17(friendly{from})%> " + "%{subject}%<{body}<<%{body}%>") + "*Scan format string for MH, provided to the scan program via the -format arg. +This format is identical to the default except that additional hints for +fontification have been added to the sixth column. + +The values of the sixth column, in priority order, are: `-' if the +message has been replied to, t if an address on the To: line matches +one of the mailboxes of the current user, `c' if the Cc: line matches, +`b' if the Bcc: line matches, and `n' if a non-empty Newsgroups: header +is present.") + +(defvar mh-scan-format-nmh + (concat + "%4(msg)" + "%<(cur)+%| %>" + "%<{replied}-" + "%?(nonnull(comp{to}))%<(mymbox{to})t%>" + "%?(nonnull(comp{cc}))%<(mymbox{cc})c%>" + "%?(nonnull(comp{bcc}))%<(mymbox{bcc})b%>" + "%?(nonnull(comp{newsgroups}))n%>" + "%<(zero) %>" + "%02(mon{date})/%02(mday{date})%<{date} %|*%>" + "%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>" + "%<(zero)%17(decode(friendly{from}))%> " + "%(decode{subject})%<{body}<<%{body}%>") + "*Scan format string for nmh, provided to the scan program via the -format arg. +This format is identical to the default except that additional hints for +fontification have been added to the sixth column. + +The values of the sixth column, in priority order, are: `-' if the +message has been replied to, t if an address on the To: line matches +one of the mailboxes of the current user, `c' if the Cc: line matches, +`b' if the Bcc: line matches, and `n' if a non-empty Newsgroups: header +is present.") + +(defvar mh-scan-good-msg-regexp "^\\(....\\)[^D^]" + "Regexp specifying the scan lines that are 'good' messages. +The default `mh-folder-font-lock-keywords' expects this expression to contain +at least one parenthesized expression which matches the message number.") + +(defvar mh-scan-deleted-msg-regexp "^\\(....\\)D" + "Regexp matching scan lines of deleted messages. +The default `mh-folder-font-lock-keywords' expects this expression to contain +at least one parenthesized expression which matches the message number.") + +(defvar mh-scan-refiled-msg-regexp "^\\(....\\)\\^" + "Regexp matching scan lines of refiled messages. +The default `mh-folder-font-lock-keywords' expects this expression to contain +at least one parenthesized expression which matches the message number.") + +(defvar mh-scan-valid-regexp "^ *[0-9]" + "Regexp matching scan lines for messages (not error messages).") + +(defvar mh-scan-cur-msg-number-regexp "^\\(....\\+\\).*" + "Regexp matching scan line for the current message. +The default `mh-folder-font-lock-keywords' expects this expression to contain +at least one parenthesized expression which matches the message number. +Don't disable this regexp as it's needed by non fontifying functions.") + +(defvar mh-scan-cur-msg-regexp "^\\(....\\+DISABLED.*\\)" + "Regexp matching scan line for the current message. +The default `mh-folder-font-lock-keywords' expects this expression to contain +at least one parenthesized expression which matches the whole line. +To enable this feature, remove the string DISABLED from the regexp.") + +(defvar mh-scan-date-regexp "\\([0-9][0-9]/[0-9][0-9]\\)" + "Regexp matching a valid date in scan lines. +The default `mh-folder-font-lock-keywords' expects this expression to contain +only one parenthesized expression which matches the date field +\(see `mh-scan-format-regexp').") + +(defvar mh-scan-rcpt-regexp "\\(To:\\)\\(..............\\)" + "Regexp specifying the recipient in scan lines for messages we sent. +The default `mh-folder-font-lock-keywords' expects this expression to contain +two parenthesized expressions. The first is expected to match the To: +that the default scan format file generates. The second is expected to match +the recipient's name.") + +(defvar mh-scan-body-regexp "\\(<<\\([^\n]+\\)?\\)" + "Regexp matching the message body beginning displayed in scan lines. +The default `mh-folder-font-lock-keywords' expects this expression to contain +at least one parenthesized expression which matches the body text.") + +(defvar mh-scan-subject-regexp + "^...............................\\([Rr][Ee]:\\s-*\\)*\\([^<\n]*\\)" + "*Regexp matching the subject string in MH folder mode. +The default `mh-folder-font-lock-keywords' expects this expression to contain +at least two parenthesized expressions. The first is expected to match the Re: +string, if any. The second is expected to match the subject line itself.") + +(defvar mh-scan-format-regexp + (concat "\\([bct]\\)" mh-scan-date-regexp " \\(..................\\)") + "Regexp matching the output of scan using `mh-scan-format-mh' or `mh-scan-format-nmh'. +The default `mh-folder-font-lock-keywords' expects this expression to contain +at least three parenthesized expressions. The first should match the +fontification hint, the second is found in `mh-scan-date-regexp', and the +third should match the user name.") + +(defvar mh-folder-followup-face 'mh-folder-followup-face + "Face for highlighting Re: (followup) subject text in MH-Folder buffers.") +(defface mh-folder-followup-face + '((((class color) (background light)) + (:foreground "blue3")) + (((class color) (background dark)) + (:foreground "LightGoldenRod")) + (t + (:bold t))) + "Face for highlighting Re: (followup) subject text in MH-Folder buffers." + :group 'mh) +(defvar mh-folder-address-face 'mh-folder-address-face + "Face for highlighting the address in MH-Folder buffers.") +(copy-face 'mh-folder-subject-face 'mh-folder-address-face) +(defvar mh-folder-scan-format-face 'mh-folder-scan-format-face + "Face for highlighting `mh-scan-format-regexp' matches in MH-Folder buffers.") +(copy-face 'mh-folder-followup-face 'mh-folder-scan-format-face) + +(defvar mh-folder-date-face 'mh-folder-date-face + "Face for highlighting the date in MH-Folder buffers.") +(defface mh-folder-date-face + '((((class color) (background light)) + (:foreground "snow4")) + (((class color) (background dark)) + (:foreground "snow3")) + (t + (:bold t))) + "Face for highlighting the date in MH-Folder buffers." + :group 'mh) +(defvar mh-folder-msg-number-face 'mh-folder-msg-number-face + "Face for highlighting the message number in MH-Folder buffers.") +(defface mh-folder-msg-number-face + '((((class color) (background light)) + (:foreground "snow4")) + (((class color) (background dark)) + (:foreground "snow3")) + (t + (:bold t))) + "Face for highlighting the message number in MH-Folder buffers." + :group 'mh) + +(defvar mh-folder-deleted-face 'mh-folder-deleted-face + "Face for highlighting deleted messages in MH-Folder buffers.") +(copy-face 'mh-folder-msg-number-face 'mh-folder-deleted-face) + +(defvar mh-folder-cur-msg-face 'mh-folder-cur-msg-face + "Face for the current message line in MH-Folder buffers.") +(defface mh-folder-cur-msg-face + '((((type tty pc) (class color)) + (:background "LightGreen")) + (((class color) (background light)) + (:background "LightGreen") ;Use this for solid background colour +;;; (:underline t) ;Use this for underlining + ) + (((class color) (background dark)) + (:background "DarkOliveGreen4")) + (t (:underline t))) + "Face for the current message line in MH-Folder buffers." + :group 'mh) + +;;mh-folder-subject-face is defined in mh-utils since it's needed there +;;for mh-show-subject-face. + +(eval-after-load "font-lock" + '(progn + (defvar mh-folder-refiled-face 'mh-folder-refiled-face + "Face for highlighting refiled messages in MH-Folder buffers.") + (copy-face 'font-lock-variable-name-face 'mh-folder-refiled-face) + (defvar mh-folder-cur-msg-number-face 'mh-folder-cur-msg-number-face + "Face for highlighting the current message in MH-Folder buffers.") + (copy-face 'font-lock-keyword-face 'mh-folder-cur-msg-number-face) + (defvar mh-folder-to-face 'mh-folder-to-face + "Face for highlighting the To: string in MH-Folder buffers.") + (copy-face 'font-lock-string-face 'mh-folder-to-face) + (defvar mh-folder-body-face 'mh-folder-body-face + "Face for highlighting body text in MH-Folder buffers.") + (copy-face 'font-lock-string-face 'mh-folder-body-face) + + (defvar mh-folder-font-lock-keywords + (list + ;; Marked for deletion + (list (concat mh-scan-deleted-msg-regexp ".*") + '(0 mh-folder-deleted-face)) + ;; Marked for refile + (list (concat mh-scan-refiled-msg-regexp ".*") + '(0 mh-folder-refiled-face)) + ;;after subj + (list mh-scan-body-regexp '(1 mh-folder-body-face nil t)) + '(mh-folder-font-lock-subject + (1 mh-folder-followup-face append t) + (2 mh-folder-subject-face append t)) + ;;current msg + (list mh-scan-cur-msg-number-regexp + '(1 mh-folder-cur-msg-number-face)) + (list mh-scan-good-msg-regexp + '(1 mh-folder-msg-number-face)) ;; Msg number + (list mh-scan-date-regexp '(1 mh-folder-date-face)) ;; Date + (list mh-scan-rcpt-regexp + '(1 mh-folder-to-face) ;; To: + '(2 mh-folder-address-face)) ;; address + ;; scan font-lock name + (list mh-scan-format-regexp + '(1 mh-folder-date-face) + '(3 mh-folder-scan-format-face)) + ;; Current message line + (list mh-scan-cur-msg-regexp + '(1 mh-folder-cur-msg-face prepend t)) + ;; Unseen messages in bold + '(mh-folder-font-lock-unseen (1 'bold append t)) + ) + "Regexp keywords used to fontify the MH-Folder buffer.") + )) + +(defun mh-folder-font-lock-subject (limit) + "Return mh-e scan subject strings to font-lock between point and LIMIT." + (if (not (re-search-forward mh-scan-subject-regexp limit t)) + nil + (if (match-beginning 1) + (set-match-data (list (match-beginning 1) (match-end 2) + (match-beginning 1) (match-end 2) nil nil)) + (set-match-data (list (match-beginning 2) (match-end 2) + nil nil (match-beginning 2) (match-end 2)))) + t)) + +;; Fontifify unseen mesages in bold. - Peter S Galbraith <psg@debian.org> +(defvar mh-folder-unseen-seq-name nil + "Name of unseen sequence. +The default for this is provided by the function `mh-folder-unseen-seq-name' +On nmh systems.") + +(defun mh-folder-unseen-seq-name () + "Provide name of unseen sequence from mhparam." + (or mh-progs (mh-find-path)) + (save-excursion + (let ((tmp-buffer (get-buffer-create mh-temp-buffer)) + (unseen-seq-name "unseen")) + (set-buffer tmp-buffer) + (unwind-protect + (progn + (call-process (expand-file-name "mhparam" mh-progs) + nil '(t t) nil "-component" "Unseen-Sequence") + (goto-char (point-min)) + (if (re-search-forward "Unseen-Sequence: \\(.*\\)$" nil t) + (setq unseen-seq-name (match-string 1)))) + (kill-buffer tmp-buffer)) + unseen-seq-name))) + +(defun mh-folder-unseen-seq-list () + "Return a list of unseen message numbers for current folder." + (if (not mh-folder-unseen-seq-name) + (setq mh-folder-unseen-seq-name (mh-folder-unseen-seq-name))) + (cond + ((not mh-folder-unseen-seq-name) + nil) + (t + (let ((folder mh-current-folder)) + (save-excursion + (let ((tmp-buffer (get-buffer-create mh-temp-buffer))) + (set-buffer tmp-buffer) + (unwind-protect + (progn + (call-process (expand-file-name "mark" mh-progs) + nil '(t t) nil + folder "-seq" mh-folder-unseen-seq-name + "-list") + (goto-char (point-min)) + (sort (mh-read-msg-list) '<)) + (kill-buffer tmp-buffer)))))))) + +(defvar mh-folder-unseen-seq-cache nil + "Internal cache variable used for font-lock in mh-e. +Should only be non-nil through font-lock stepping, and nil once font-lock +is done highlighting.") +(make-variable-buffer-local 'mh-folder-unseen-seq-cache) + +(defun mh-folder-font-lock-unseen (limit) + "Return unseen message lines to font-lock between point and LIMIT." + (if (not mh-folder-unseen-seq-cache) + (setq mh-folder-unseen-seq-cache (mh-folder-unseen-seq-list))) + (let ((cur-msg (mh-get-msg-num nil))) + (cond + ((not mh-folder-unseen-seq-cache) + nil) + ((not cur-msg) ;Presumably at end of buffer + (setq mh-folder-unseen-seq-cache nil) + nil) + ((member cur-msg mh-folder-unseen-seq-cache) + (let ((bpoint (progn (beginning-of-line)(point))) + (epoint (progn (forward-line 1)(point)))) + (if (<= limit (point)) + (setq mh-folder-unseen-seq-cache nil)) + (set-match-data (list bpoint epoint bpoint epoint)) + t)) + (t + ;; move forward one line at a time, checking each message number. + (while (and + (= 0 (forward-line 1)) + (> limit (point)) + (not (member (mh-get-msg-num nil) mh-folder-unseen-seq-cache)))) + ;; Examine how we must have exited the loop... + (let ((cur-msg (mh-get-msg-num nil))) + (cond + ((or (not cur-msg) + (<= limit (point)) + (not (member cur-msg mh-folder-unseen-seq-cache))) + (setq mh-folder-unseen-seq-cache nil) + nil) + ((member cur-msg mh-folder-unseen-seq-cache) + (let ((bpoint (progn (beginning-of-line)(point))) + (epoint (progn (forward-line 1)(point)))) + (if (<= limit (point)) + (setq mh-folder-unseen-seq-cache nil)) + (set-match-data (list bpoint epoint bpoint epoint)) + t)))))))) +;; fontifify unseen mesages in bold. - end ;;; Internal variables: @@ -225,7 +602,7 @@ (defvar mh-last-msg-num nil) ;Number of last msg in buffer. -(defvar mh-mode-line-annotation nil) ;Indiction this is not the full folder. +(defvar mh-mode-line-annotation nil) ;Message range displayed in buffer. ;;; Macros and generic functions: @@ -234,44 +611,40 @@ (funcall func (car list)) (setq list (cdr list)))) +(defun mh-scan-format () + "Generate arguments to the scan program to specify which format string should be used." + (if (equal mh-scan-format-file t) + (list "-format" (if mh-nmh-p + (list mh-scan-format-nmh) + (list mh-scan-format-mh))) + (if (not (equal mh-scan-format-file nil)) + (list "-form" mh-scan-format-file)))) + ;;; Entry points: ;;;###autoload (defun mh-rmail (&optional arg) - "Inc(orporate) new mail with MH, or, with arg, scan an MH mail folder. -This function is an entry point to mh-e, the Emacs front end -to the MH mail system." + "Inc(orporate) new mail with MH. +Scan an MH folder if ARG is non-nil. This function is an entry point to mh-e, +the Emacs front end to the MH mail system." (interactive "P") (mh-find-path) (if arg (call-interactively 'mh-visit-folder) (mh-inc-folder))) - -;;; mh-smail and mh-smail-other-window have been moved to the new file -;;; mh-comp.el, but Emacs 18 still looks for them here, so provide a -;;; definition here, too, for a while. - -(defun mh-smail () - "Compose and send mail with the MH mail system. -This function is an entry point to mh-e, the Emacs front end -to the MH mail system." - (interactive) - (mh-find-path) - (require 'mh-comp) - (call-interactively 'mh-send)) - - -(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 front end -to the MH mail system." - (interactive) - (mh-find-path) - (require 'mh-comp) - (call-interactively 'mh-send-other-window)) +;;;###autoload +(defun mh-nmail (&optional arg) + "Check for new mail in inbox folder. +Scan an MH folder if ARG is non-nil. This function is an entry point to mh-e, +the Emacs front end to the MH mail system." + (interactive "P") + (mh-find-path) ; init mh-inbox + (if arg + (call-interactively 'mh-visit-folder) + (mh-visit-folder mh-inbox))) @@ -279,18 +652,26 @@ (defun mh-delete-msg (msg-or-seq) - "Mark the specified MESSAGE(s) for subsequent deletion and move to the next. -Default is the displayed message. If optional prefix argument is -given then prompt for the message sequence." - (interactive (list (if current-prefix-arg - (mh-read-seq-default "Delete" t) - (mh-get-msg-num t)))) + "Mark the specified MSG-OR-SEQ for subsequent deletion and move to the next. + +Default is the displayed message. If optional prefix argument is given then +prompt for the message sequence. If variable `transient-mark-mode' is non-nil +and the mark is active, then the selected region is marked for deletion." + (interactive (list (cond + ((and (boundp 'transient-mark-mode) + transient-mark-mode mark-active) + (mh-region-to-sequence (region-beginning)(region-end)) + 'region) + (current-prefix-arg + (mh-read-seq-default "Delete" t)) + (t + (mh-get-msg-num t))))) (mh-delete-msg-no-motion msg-or-seq) (mh-next-msg)) (defun mh-delete-msg-no-motion (msg-or-seq) - "Mark the specified MESSAGE(s) for subsequent deletion. + "Mark the specified MSG-OR-SEQ for subsequent deletion. Default is the displayed message. If optional prefix argument is provided, then prompt for the message sequence." (interactive (list (if current-prefix-arg @@ -316,7 +697,7 @@ "Move to the first message." (interactive) (goto-char (point-min)) - (while (and (not (eobp)) (not (looking-at mh-valid-scan-line))) + (while (and (not (eobp)) (not (looking-at mh-scan-valid-regexp))) (forward-line 1))) @@ -341,8 +722,8 @@ (defun mh-inc-folder (&optional maildrop-name) "Inc(orporate)s new mail into the Inbox folder. -Optional prefix argument specifies an alternate maildrop from the default. -If the prefix argument is given, incorporates mail into the current +Optional argument MAILDROP-NAME specifies an alternate maildrop from the +default. If the prefix argument is given, incorporates mail into the current folder, otherwise uses the folder named by `mh-inbox'. Runs `mh-inc-folder-hook' after incorporating new mail. Do not call this function from outside mh-e; use \\[mh-rmail] instead." @@ -359,6 +740,7 @@ (switch-to-buffer mh-inbox) (setq mh-previous-window-config config))))) (mh-get-new-mail maildrop-name) + (if mh-showing-mode (mh-show)) (run-hooks 'mh-inc-folder-hook)) @@ -371,11 +753,11 @@ (defun mh-next-undeleted-msg (&optional arg) - "Move to the NTH next undeleted message in window." + "Move to the next undeleted message ARG in window." (interactive "p") (setq mh-next-direction 'forward) (forward-line 1) - (cond ((re-search-forward mh-good-msg-regexp nil 0 arg) + (cond ((re-search-forward mh-scan-good-msg-regexp nil 0 arg) (beginning-of-line) (mh-maybe-show)) (t @@ -385,12 +767,19 @@ (defun mh-refile-msg (msg-or-seq folder) - "Refile MESSAGE(s) (default: displayed message) into FOLDER. -If optional prefix argument provided, then prompt for message sequence." + "Refile MSG-OR-SEQ (default: displayed message) into FOLDER. +If optional prefix argument provided, then prompt for message sequence. +If variable `transient-mark-mode' is non-nil and the mark is active, then the +selected region is marked for refiling." (interactive - (list (if current-prefix-arg - (mh-read-seq-default "Refile" t) - (mh-get-msg-num t)) + (list (cond + ((and (boundp 'transient-mark-mode) transient-mark-mode mark-active) + (mh-region-to-sequence (region-beginning)(region-end)) + 'region) + (current-prefix-arg + (mh-read-seq-default "Refile" t)) + (t + (mh-get-msg-num t))) (intern (mh-prompt-for-folder "Destination" @@ -430,24 +819,48 @@ (defun mh-quit () "Quit the current mh-e folder. -Start by running mh-before-quit-hook. Restore the previous window -configuration, if one exists. Finish by running mh-quit-hook." +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) + (run-hooks 'mh-before-quit-hook) (mh-update-sequences) (mh-invalidate-show-buffer) (bury-buffer (current-buffer)) (if (get-buffer mh-show-buffer) (bury-buffer mh-show-buffer)) + (if (get-buffer mh-temp-buffer) + (kill-buffer mh-temp-buffer)) + (if (get-buffer mh-temp-folders-buffer) + (kill-buffer mh-temp-folders-buffer)) + (if (get-buffer mh-temp-sequences-buffer) + (kill-buffer mh-temp-sequences-buffer)) (if mh-previous-window-config (set-window-configuration mh-previous-window-config)) (run-hooks 'mh-quit-hook)) (defun mh-page-msg (&optional arg) "Page the displayed message forwards. -Scrolls ARG lines or a full screen if no argument is supplied." +Scrolls ARG lines or a full screen if no argument is supplied. Show buffer +first if not displayed. Show the next undeleted message if looking at the +bottom of the current message." (interactive "P") - (scroll-other-window arg)) + (if mh-showing-mode + (if mh-page-to-next-msg-p + (if (equal mh-next-direction 'backward) + (mh-previous-undeleted-msg) + (mh-next-undeleted-msg)) + (if (mh-in-show-buffer (mh-show-buffer) + (pos-visible-in-window-p (point-max))) + (progn + (message (format + "End of message (Type %s to read %s undeleted message)" + (single-key-description last-input-event) + (if (equal mh-next-direction 'backward) + "previous" + "next"))) + (setq mh-page-to-next-msg-p t)) + (scroll-other-window arg))) + (mh-show))) (defun mh-previous-page (&optional arg) @@ -459,11 +872,11 @@ (defun mh-previous-undeleted-msg (&optional arg) - "Move to the NTH previous undeleted message in window." + "Move to the previous undeleted message ARG in window." (interactive "p") (setq mh-next-direction 'backward) (beginning-of-line) - (cond ((re-search-backward mh-good-msg-regexp nil 0 arg) + (cond ((re-search-backward mh-scan-good-msg-regexp nil 0 arg) (mh-maybe-show)) (t (if (get-buffer mh-show-buffer) @@ -472,7 +885,7 @@ (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 +If optional prefix argument RANGE is provided, prompt for the range of messages to display. Otherwise show the entire folder." (interactive (list (if current-prefix-arg (mh-read-msg-range "Range to scan [all]? ") @@ -482,8 +895,8 @@ (defun mh-write-msg-to-file (msg file no-headers) - "Append MESSAGE to the end of a FILE. -If NO-HEADERS (prefix argument) is provided, write only the message body. + "Append MSG to the end of a FILE. +If prefix argument NO-HEADERS is provided, write only the message body. Otherwise send the entire message including the headers." (interactive (list (mh-get-msg-num t) @@ -512,29 +925,37 @@ (defun mh-toggle-showing () "Toggle the scanning mode/showing mode of displaying messages." (interactive) - (if mh-showing + (if mh-showing-mode (mh-set-scan-mode) - (mh-show))) + (mh-show))) (defun mh-undo (msg-or-seq) - "Undo the pending deletion or refile of the specified MESSAGE(s). + "Undo the pending deletion or refile of the specified MSG-OR-SEQ. Default is the displayed message. If optional prefix argument is -provided, then prompt for the message sequence." - (interactive (list (if current-prefix-arg - (mh-read-seq-default "Undo" t) - (mh-get-msg-num t)))) +provided, then prompt for the message sequence. +If variable `transient-mark-mode' is non-nil and the mark is active, then the +selected region is unmarked." + (interactive (list (cond + ((and (boundp 'transient-mark-mode) + transient-mark-mode mark-active) + (mh-region-to-sequence (region-beginning)(region-end)) + 'region) + (current-prefix-arg + (mh-read-seq-default "Undo" t)) + (t + (mh-get-msg-num t))))) (cond ((numberp msg-or-seq) (let ((original-position (point))) (beginning-of-line) - (while (not (or (looking-at mh-deleted-msg-regexp) - (looking-at mh-refiled-msg-regexp) + (while (not (or (looking-at mh-scan-deleted-msg-regexp) + (looking-at mh-scan-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)) + (if (or (looking-at mh-scan-deleted-msg-regexp) + (looking-at mh-scan-refiled-msg-regexp)) (progn (mh-undo-msg (mh-get-msg-num t)) (mh-maybe-show)) @@ -559,21 +980,27 @@ (mh-find-progs) (set-buffer (get-buffer-create mh-temp-buffer)) (erase-buffer) - (insert " mh-e info:\n\nversion: " mh-e-RCS-id - "\nEmacs: " emacs-version " on " (symbol-name system-type) " ") + ;; mh-e and Emacs versions. + (insert "mh-e " mh-version "\n\n" (emacs-version) "\n\n") + ;; MH version. + (let ((help-start (point))) + (condition-case err-data + (mh-exec-cmd-output "inc" nil (if mh-nmh-p "-version" "-help")) + (file-error (insert (mapconcat 'concat (cdr err-data) ": ") "\n"))) + (goto-char help-start) + (if mh-nmh-p + (search-forward "inc -- " nil t) + (search-forward "version: " nil t)) + (delete-region help-start (point))) + (goto-char (point-max)) + (insert "mh-progs:\t" mh-progs "\n" + "mh-lib:\t\t" mh-lib "\n" + "mh-lib-progs:\t" mh-lib-progs "\n\n") + ;; Linux version. (condition-case () (call-process "uname" nil t nil "-a") (file-error)) - (insert "\n\n MH info:\n\n" (expand-file-name "inc" mh-progs) ":\n") - (let ((help-start (point))) - (condition-case err-data - (mh-exec-cmd-output "inc" nil "-help") - (file-error (insert (mapconcat 'concat (cdr err-data) ": ")))) - (goto-char help-start) - (search-forward "version: " nil t) - (beginning-of-line) - (delete-region help-start (point)) - (goto-char (point-min))) + (goto-char (point-min)) (display-buffer mh-temp-buffer)) @@ -588,17 +1015,6 @@ nil) -(defun mh-compat-quit () - "The \"b\" key is obsolescent; will assume you want \"\\[mh-quit]\" ..." - ;; Was going to make it run mh-burst-digest, but got complaint that - ;; 'b' should mean 'back', as it does in info, less, and rn. - ;; This is a temporary compatibility function. - (interactive) - (message "%s" (documentation this-command)) - (sit-for 1) - (call-interactively 'mh-quit)) - - (defun mh-update-sequences () "Update MH's Unseen sequence and current folder and message. Flush mh-e's state out to MH. The message at the cursor becomes current." @@ -613,11 +1029,15 @@ (setcdr seq-entry (list new-cur)) ;delete-seq-locally, add-msgs-to-seq (mh-define-sequence 'cur (list new-cur)) (beginning-of-line) - (if (looking-at mh-good-msg-regexp) + (if (looking-at mh-scan-good-msg-regexp) (mh-notate nil mh-note-cur mh-cmd-note))) (or folder-set (save-excursion - (mh-exec-cmd-quiet t "folder" mh-current-folder "-fast")))))) + ;; psg - mh-current-folder is nil if mh-summary-height < 4 ! + ;; So I added this sanity check. + (if (stringp mh-current-folder) + (mh-exec-cmd-quiet t "folder" mh-current-folder "-fast") + (mh-exec-cmd-quiet t "folder" "-fast"))))))) @@ -628,9 +1048,9 @@ ;; Delete the MESSAGE. (save-excursion (mh-goto-msg msg nil t) - (if (looking-at mh-refiled-msg-regexp) + (if (looking-at mh-scan-refiled-msg-regexp) (error "Message %d is refiled. Undo refile before deleting" msg)) - (if (looking-at mh-deleted-msg-regexp) + (if (looking-at mh-scan-deleted-msg-regexp) nil (mh-set-folder-modified-p t) (setq mh-delete-list (cons msg mh-delete-list)) @@ -642,9 +1062,9 @@ ;; 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) + (cond ((looking-at mh-scan-deleted-msg-regexp) (error "Message %d is deleted. Undo delete before moving" msg)) - ((looking-at mh-refiled-msg-regexp) + ((looking-at mh-scan-refiled-msg-regexp) (if (y-or-n-p (format "Message %d already refiled. Copy to %s as well? " msg destination)) @@ -673,7 +1093,7 @@ ;; Display the scan listing buffer, but do not show a message. (if (get-buffer mh-show-buffer) (delete-windows-on mh-show-buffer)) - (setq mh-showing nil) + (mh-showing-mode 0) (force-mode-line-update) (if mh-recenter-summary-p (mh-recenter nil))) @@ -711,110 +1131,33 @@ ;;; Ensure new buffers won't get this mode if default-major-mode is nil. (put 'mh-folder-mode 'mode-class 'special) -(defun mh-folder-mode () +(define-derived-mode mh-folder-mode fundamental-mode "MH-Folder" "Major mh-e mode for \"editing\" an MH folder scan listing.\\<mh-folder-mode-map> + You can show the message the cursor is pointing to, and step through the messages. Messages can be marked for deletion or refiling into another folder; these commands are executed all at once with a separate command. A prefix argument (\\[universal-argument]) to delete, refile, list, or undo -applies the action to a message sequence. - -Here is a list of the standard keys for mh-e commands, grouped by function. -This list is purposefully not customized; mh-e has a long history, and many -alternate key bindings as a result. This list is to encourage users to use -standard keys so the other keys can perhaps someday be put to new uses. - -t toggle show or scan-only mode -RET show message, or back to top if already showing - -SPC page message forward -DEL page message back - -n next message -p previous message -g go to message by number - -d mark for deletion -o, ^ mark for output (refile) to another folder -? show folder of pending refile -u undo delete or refile marking +applies the action to a message sequence. If `transient-mark-mode', +is non-nil, the action is applied to the region. -x execute marked deletes and refiles -i incorporate new mail - -m mail a new message -r reply to a message -f forward a message - -q quit mh-e - -M-f visit new folder -M-r rescan this folder - -Here are all the commands with their current binding, listed in key order: -\\{mh-folder-mode-map} - -Variables controlling mh-e operation are (defaults in parentheses): - - `mh-recursive-folders' (nil) - Non-nil means commands which operate on folders do so recursively. - - `mh-bury-show-buffer' (t) - Non-nil means that the buffer used to display message is buried. - It will never be offered as the default other buffer. +Options that control this mode can be changed with \\[customize-group]; +specify the \"mh\" group. In particular, please see the `mh-scan-format-file' +option if you wish to modify scan's format. - `mh-clean-message-header' (nil) - Non-nil means remove header lines matching the regular expression - specified in mh-invisible-headers from messages. - - `mh-visible-headers' (nil) - If non-nil, it contains a regexp specifying the headers that are shown in - a message if mh-clean-message-header is non-nil. Setting this variable - overrides `mh-invisible-headers'. - - `mh-do-not-confirm' (nil) - Non-nil means do not prompt for confirmation before executing some - non-recoverable commands such as `mh-kill-folder' and `mh-undo-folder'. - - `mhl-formfile' (nil) - Name of format file to be used by mhl to show messages. - A value of t means use the default format file. - nil means don't use mhl to format messages. - - `mh-lpr-command-format' (\"lpr -p -J '%s'\") - Format for command used to print a message on a system printer. +When a folder is visited, the hook `mh-folder-mode-hook' is run. - `mh-scan-prog' (\"scan\") - Program to run to generate one-line-per-message listing of a folder. - Normally \"scan\" or a file name linked to scan. This file is searched - for relative to the mh-progs directory unless it is an absolute pathname. - Automatically becomes buffer-local when set in any fashion. - - `mh-print-background' (nil) - Print messages in the background if non-nil. - WARNING: do not delete the messages until printing is finished; - otherwise, your output may be truncated. +\\{mh-folder-mode-map}" - `mh-recenter-summary-p' (nil) - If non-nil, then the scan listing is recentered when the window displaying - a messages is toggled off. - - `mh-summary-height' (4) - Number of lines in the summary window including the mode line. - -The value of mh-folder-mode-hook is called when a new folder is set up." - - (kill-all-local-variables) - (use-local-map mh-folder-mode-map) - (setq major-mode 'mh-folder-mode) - (mh-set-mode-name "MH-Folder") + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(mh-folder-font-lock-keywords t)) (mh-make-local-vars 'mh-current-folder (buffer-name) ; Name of folder, a string 'mh-show-buffer (format "show-%s" (buffer-name)) ; Buffer that displays msgs 'mh-folder-filename ; e.g. "/usr/foobar/Mail/inbox/" (file-name-as-directory (mh-expand-file-name (buffer-name))) - 'mh-showing nil ; Show message also? + 'mh-showing-mode nil ; Show message also? 'mh-delete-list nil ; List of msgs nums to delete 'mh-refile-list nil ; List of folder names in mh-seq-list 'mh-seq-list nil ; Alist of (seq . msgs) nums @@ -834,11 +1177,18 @@ (make-local-variable 'write-file-hooks) (setq write-file-hooks '(mh-execute-commands))) ;Emacs 18 (make-local-variable 'revert-buffer-function) + (make-local-variable 'hl-line-mode) ; avoid pollution + (if (fboundp 'hl-line-mode) + (hl-line-mode 1)) (setq revert-buffer-function 'mh-undo-folder) - (or (assq 'mh-showing minor-mode-alist) + (or (assq 'mh-showing-mode minor-mode-alist) (setq minor-mode-alist - (cons '(mh-showing " Show") minor-mode-alist))) - (run-hooks 'mh-folder-mode-hook)) + (cons '(mh-showing-mode " Show") minor-mode-alist))) + (easy-menu-add mh-folder-sequence-menu) + (easy-menu-add mh-folder-message-menu) + (easy-menu-add mh-folder-folder-menu) + (if (and (boundp 'tool-bar-mode) tool-bar-mode) + (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map))) (defun mh-make-local-vars (&rest pairs) @@ -857,12 +1207,11 @@ (mh-process-or-undo-commands folder) (switch-to-buffer folder))) (mh-regenerate-headers range) - (cond ((zerop (buffer-size)) + (if (zerop (buffer-size)) (if (equal range "all") (message "Folder %s is empty" folder) (message "No messages in %s, range %s" folder range)) - (sit-for 5))) - (mh-goto-cur-msg)) + (mh-goto-cur-msg))) (defun mh-regenerate-headers (range &optional update) @@ -877,15 +1226,18 @@ (erase-buffer)) (setq scan-start (point)) (mh-exec-cmd-output mh-scan-prog nil + (mh-scan-format) "-noclear" "-noheader" "-width" (window-width) folder range) (goto-char scan-start) (cond ((looking-at "scan: no messages in") - (keep-lines mh-valid-scan-line)) ; Flush random scan lines + (keep-lines mh-scan-valid-regexp)) ; Flush random scan lines + ((looking-at "scan: bad message list ") + (keep-lines mh-scan-valid-regexp)) ((looking-at "scan: ")) ; Keep error messages (t - (keep-lines mh-valid-scan-line))) ; Flush random scan lines + (keep-lines mh-scan-valid-regexp))) ; Flush random scan lines (setq mh-seq-list (mh-read-folder-sequences folder nil)) (mh-notate-user-sequences) (or update @@ -914,10 +1266,12 @@ ;; I think MH 5 used "-ms-file" instead of "-file", ;; which would make inc'ing from maildrops fail. (mh-exec-cmd-output mh-inc-prog nil folder + (mh-scan-format) "-file" (expand-file-name maildrop-name) "-width" (window-width) "-truncate") (mh-exec-cmd-output mh-inc-prog nil + (mh-scan-format) "-width" (window-width))) (if maildrop-name (message "inc %s -file %s...done" folder maildrop-name) @@ -928,11 +1282,11 @@ (message "No new mail%s%s" (if maildrop-name " in " "") (if maildrop-name maildrop-name ""))) ((re-search-forward "^inc:" nil t) ; Error messages - (error "inc error")) + (error "Error incorporating mail")) (t (mh-remove-cur-notation) (setq new-mail-p t))) - (keep-lines mh-valid-scan-line) ; Flush random scan lines + (keep-lines mh-scan-valid-regexp) ; Flush random scan lines (setq mh-seq-list (mh-read-folder-sequences folder t)) (mh-notate-user-sequences) (if new-mail-p @@ -952,20 +1306,25 @@ (setq mh-first-msg-num (mh-get-msg-num nil)) (mh-last-msg) (setq mh-last-msg-num (mh-get-msg-num nil)) - (setq mh-msg-count (count-lines (point-min) (point-max))) + (setq mh-msg-count (if mh-first-msg-num + (count-lines (point-min) (point-max)) + 0)) (setq mode-line-buffer-identification - (list (format "{%%b%s} %d msg%s" + (list (format "{%%b%s} %s msg%s" (if mh-mode-line-annotation (format "/%s" mh-mode-line-annotation) "") - mh-msg-count + (if (zerop mh-msg-count) + "no" + (format "%d" mh-msg-count)) (if (zerop mh-msg-count) "s" - (if (> mh-msg-count 1) - (format "s (%d-%d)" mh-first-msg-num - mh-last-msg-num) - (format " (%d)" mh-first-msg-num)))))))) - + (cond ((> mh-msg-count 1) + (format "s (%d-%d)" mh-first-msg-num + mh-last-msg-num)) + (mh-first-msg-num + (format " (%d)" mh-first-msg-num)) + ("")))))))) (defun mh-unmark-all-headers (remove-all-flags) ;; Remove all '+' flags from the headers, and if called with a non-nil @@ -1002,7 +1361,7 @@ (save-excursion (and cur-msg (mh-goto-msg cur-msg t t) - (looking-at mh-cur-scan-msg-regexp) + (looking-at mh-scan-cur-msg-number-regexp) (mh-notate nil ? mh-cmd-note))))) (defun mh-goto-cur-msg () @@ -1025,9 +1384,9 @@ (if (mh-outstanding-commands-p) (if (or mh-do-not-confirm (y-or-n-p - "Process outstanding deletes and refiles (or lose them)? ")) + "Process outstanding deletes and refiles (or lose them)? ")) (mh-process-commands folder) - (mh-undo-folder))) + (mh-undo-folder))) (mh-update-unseen) (mh-invalidate-show-buffer)) @@ -1037,6 +1396,9 @@ (message "Processing deletes and refiles for %s..." folder) (set-buffer folder) (with-mh-folder-updating (nil) + ;; Run the hook while the lists are still valid + (run-hooks 'mh-folder-updated-hook) + ;; Update the unseen sequence if it exists (mh-update-unseen) @@ -1080,13 +1442,14 @@ (defun mh-update-unseen () ;; Flush updates to the Unseen sequence out to MH. - ;; Return non-nil iff set the MH folder. + ;; Return non-NIL iff set the MH folder. (if mh-seen-list (let* ((unseen-seq (mh-find-seq mh-unseen-seq)) (unseen-msgs (mh-seq-msgs unseen-seq))) (if unseen-msgs (progn (mh-undefine-sequence mh-unseen-seq mh-seen-list) + (run-hooks 'mh-unseen-updated-hook) (while mh-seen-list (setq unseen-msgs (delq (car mh-seen-list) unseen-msgs)) (setq mh-seen-list (cdr mh-seen-list))) @@ -1144,6 +1507,8 @@ nil (string-lessp msg2 msg1)))) +(defun mh-lessp (msg1 msg2) + (not (mh-greaterp msg1 msg2))) ;;; Basic sequence handling @@ -1211,7 +1576,7 @@ (defun mh-internal-seq (name) - ;; Return non-nil if NAME is the name of an internal mh-e sequence. + ;; Return non-NIL if NAME is the name of an internal mh-e sequence. (or (memq name '(answered cur deleted forwarded printed)) (eq name mh-unseen-seq) (eq name mh-previous-seq) @@ -1219,9 +1584,9 @@ (defun mh-delete-msg-from-seq (message sequence &optional internal-flag) - "Delete MESSAGE from SEQUENCE. MESSAGE defaults to displayed message. -From Lisp, optional third arg INTERNAL-FLAG non-nil means do not -inform MH of the change." + "Delete MESSAGE from SEQUENCE. +MESSAGE defaults to displayed message. From Lisp, optional third arg +INTERNAL-FLAG non-nil means do not inform MH of the change." (interactive (list (mh-get-msg-num t) (mh-read-seq-default "Delete from" t) nil)) @@ -1305,65 +1670,220 @@ ;;; Build the folder-mode keymap: (suppress-keymap mh-folder-mode-map) -(define-key mh-folder-mode-map "q" 'mh-quit) -(define-key mh-folder-mode-map "b" 'mh-compat-quit) -(define-key mh-folder-mode-map "?" 'mh-msg-is-in-seq) -(define-key mh-folder-mode-map "%" 'mh-put-msg-in-seq) -(define-key mh-folder-mode-map "|" 'mh-pipe-msg) -(define-key mh-folder-mode-map "\ea" 'mh-edit-again) -(define-key mh-folder-mode-map "\e%" 'mh-delete-msg-from-seq) -(define-key mh-folder-mode-map "\e#" 'mh-delete-seq) -(define-key mh-folder-mode-map "\C-xn" 'mh-narrow-to-seq) -(define-key mh-folder-mode-map "\C-xw" 'mh-widen) -(define-key mh-folder-mode-map "\eb" 'mh-burst-digest) -(define-key mh-folder-mode-map "\eu" 'mh-undo-folder) -(define-key mh-folder-mode-map "\e " 'mh-page-digest) -(define-key mh-folder-mode-map "\e\177" 'mh-page-digest-backwards) -(define-key mh-folder-mode-map "\ed" 'mh-redistribute) -(define-key mh-folder-mode-map "\ee" 'mh-extract-rejected-mail) -(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-store-msg) -(define-key mh-folder-mode-map "\ep" 'mh-pack-folder) -(define-key mh-folder-mode-map "\eq" 'mh-list-sequences) -(define-key mh-folder-mode-map "\es" 'mh-search-folder) -(define-key mh-folder-mode-map "\er" 'mh-rescan-folder) -(define-key mh-folder-mode-map "l" 'mh-print-msg) -(define-key mh-folder-mode-map "t" 'mh-toggle-showing) -(define-key mh-folder-mode-map "c" 'mh-copy-msg) -(define-key mh-folder-mode-map "i" 'mh-inc-folder) -(define-key mh-folder-mode-map "x" 'mh-execute-commands) -(define-key mh-folder-mode-map "e" 'mh-execute-commands) -(define-key mh-folder-mode-map "f" 'mh-forward) -(define-key mh-folder-mode-map "m" 'mh-send) -(define-key mh-folder-mode-map "s" 'mh-send) -(define-key mh-folder-mode-map "r" 'mh-reply) -(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 "g" 'mh-goto-msg) -(define-key mh-folder-mode-map "\e<" 'mh-first-msg) -(define-key mh-folder-mode-map "\e>" 'mh-last-msg) -(define-key mh-folder-mode-map "\177" 'mh-previous-page) -(define-key mh-folder-mode-map " " 'mh-page-msg) -(define-key mh-folder-mode-map "\r" 'mh-show) -(define-key mh-folder-mode-map "." 'mh-show) -(define-key mh-folder-mode-map "," 'mh-header-display) -(define-key mh-folder-mode-map "u" 'mh-undo) -(define-key mh-folder-mode-map "d" 'mh-delete-msg) -(define-key mh-folder-mode-map "\C-d" 'mh-delete-msg-no-motion) -(define-key mh-folder-mode-map "p" 'mh-previous-undeleted-msg) -(define-key mh-folder-mode-map "n" 'mh-next-undeleted-msg) -(define-key mh-folder-mode-map "o" 'mh-refile-msg) -(define-key mh-folder-mode-map "^" 'mh-refile-msg) -(define-key mh-folder-mode-map "\C-o" 'mh-write-msg-to-file) -(define-key mh-folder-mode-map ">" 'mh-write-msg-to-file) -(define-key mh-folder-mode-map "!" 'mh-refile-or-write-again) + +;; Save the `b' binding for a future `back'. Maybe? +(gnus-define-keys mh-folder-mode-map + " " mh-page-msg + "!" mh-refile-or-write-again + "," mh-header-display + "." mh-show ;alias + ">" mh-write-msg-to-file + "E" mh-extract-rejected-mail + "\177" mh-previous-page + "\C-d" mh-delete-msg-no-motion + "\e<" mh-first-msg + "\e>" mh-last-msg + "\ed" mh-redistribute + "\r" mh-show + "^" mh-refile-msg ;alias + "c" mh-copy-msg + "d" mh-delete-msg + "e" mh-edit-again + "f" mh-forward + "g" mh-goto-msg + "i" mh-inc-folder + "k" mh-delete-subject-thread + "l" mh-print-msg + "m" mh-send ;alias + "n" mh-next-undeleted-msg + "o" mh-refile-msg + "p" mh-previous-undeleted-msg + "q" mh-quit + "r" mh-reply + "s" mh-send + "t" mh-toggle-showing + "u" mh-undo + "x" mh-execute-commands + "|" mh-pipe-msg) + +(gnus-define-keys (mh-folder-map "F" mh-folder-mode-map) + "S" mh-sort-folder + "f" mh-visit-folder ;alias + "k" mh-kill-folder + "l" mh-list-folders + "o" mh-visit-folder ;alias + "p" mh-pack-folder + "r" mh-rescan-folder + "s" mh-search-folder + "u" mh-undo-folder + "v" mh-visit-folder) + +(gnus-define-keys (mh-sequence-map "S" mh-folder-mode-map) + "d" mh-delete-msg-from-seq + "k" mh-delete-seq + "l" mh-list-sequences + "n" mh-narrow-to-seq + "p" mh-put-msg-in-seq + "s" mh-msg-is-in-seq + "w" mh-widen) + +(gnus-define-keys (mh-thread-map "T" mh-folder-mode-map) + "d" mh-delete-subject-thread + "k" mh-delete-subject-thread + "s" mh-narrow-to-subject-thread + "t" mh-toggle-subject-thread + "u" mh-next-unseen-subject-thread) + +(gnus-define-keys (mh-extract-map "X" mh-folder-mode-map) + "s" mh-store-msg ;shar + "u" mh-store-msg) ;uuencode + +(gnus-define-keys (mh-digest-map "D" mh-folder-mode-map) + " " mh-page-digest + "\177" mh-page-digest-backwards + "b" mh-burst-digest) + +(cond + ((not (null (save-match-data (string-match "XEmacs\\|Lucid" emacs-version)))) + (define-key mh-folder-mode-map [button2] 'mh-show-mouse)) + (t + (define-key mh-folder-mode-map [mouse-2] 'mh-show-mouse))) ;; "C-c /" prefix is used in mh-folder-mode by pgp.el and mailcrypt +;;; Menu extracted from mh-menubar.el V1.1 (31 July 2001) +;;; Menus for folder mode: folder, message, sequence (in that order) +;;; folder-mode "Sequence" menu +(easy-menu-define + mh-folder-sequence-menu mh-folder-mode-map "Menu for mh-e folder-sequence." + '("Sequence" + ["Add Msg to Seq..." mh-put-msg-in-seq (mh-get-msg-num nil)] + ["List Seq's for Msg" mh-msg-is-in-seq (mh-get-msg-num nil)] + ["Delete Msg from Seq..." mh-delete-msg-from-seq (mh-get-msg-num nil)] + ["List Seq's in Folder..." mh-list-sequences t] + ["Delete Seq..." mh-delete-seq t] + ["Show Only Msgs in Seq..." mh-narrow-to-seq t] + ["Show All Msgs in Folder" mh-widen mh-narrowed-to-seq] + "--" + ["Toggle Subject Thread" mh-toggle-subject-thread t] + ["Narrow to Subject Thread" mh-narrow-to-subject-thread t] + ["Delete Rest of Subject Thread" mh-delete-subject-thread t] + ["Next Unseen Subject Thread" mh-next-unseen-subject-thread t] + "--" + ["Push State Out to MH" mh-update-sequences t])) + +;;; folder-mode "Message" menu +(easy-menu-define + mh-folder-message-menu mh-folder-mode-map "Menu for mh-e folder-message." + '("Message" + ["Show Msg" mh-show (mh-get-msg-num nil)] + ["Next Msg" mh-next-undeleted-msg t] + ["Previous Msg" mh-previous-undeleted-msg t] + ["Go to First Msg" mh-first-msg t] + ["Go to Last Msg" mh-last-msg t] + ["Go to Msg by Number..." mh-goto-msg t] + ["Delete Msg" mh-delete-msg (mh-get-msg-num nil)] + ["Refile Msg" mh-refile-msg (mh-get-msg-num nil)] + ["Undo Delete/Refile" mh-undo t] + ["Process Delete/Refile" mh-execute-commands + (or mh-refile-list mh-delete-list)] + "--" + ["Compose a New Msg" mh-send t] + ["Reply to Msg..." mh-reply (mh-get-msg-num nil)] + ["Forward Msg..." mh-forward (mh-get-msg-num nil)] + ["Redistribute Msg..." mh-redistribute (mh-get-msg-num nil)] + ["Edit Msg Again" mh-edit-again (mh-get-msg-num nil)] + ["Re-edit a Bounced Msg" mh-extract-rejected-mail t] + "--" + ["Refile Msg in Folder..." mh-refile-msg (mh-get-msg-num nil)] + ["Copy Msg to Folder..." mh-copy-msg (mh-get-msg-num nil)] + ["Print Msg" mh-print-msg (mh-get-msg-num nil)] + ["Write Msg to File..." mh-write-msg-to-file (mh-get-msg-num nil)] + ["Pipe Msg to Command..." mh-pipe-msg (mh-get-msg-num nil)] + ["Unpack Uuencoded Msg..." mh-store-msg (mh-get-msg-num nil)] + ["Show Msg with Header" mh-header-display (mh-get-msg-num nil)] + ["Burst Digest Msg" mh-burst-digest (mh-get-msg-num nil)])) + +;;; folder-mode "Folder" menu +(easy-menu-define + mh-folder-folder-menu mh-folder-mode-map "Menu for mh-e folder." + '("Folder" + ["Incorporate New Mail" mh-inc-folder t] + ["Toggle Show/Folder" mh-toggle-showing t] + ["Execute Delete/Refile" mh-execute-commands + (or mh-refile-list mh-delete-list)] + ["Rescan Folder" mh-rescan-folder t] + ["Pack Folder" mh-pack-folder t] + ["Sort Folder" mh-sort-folder t] + "--" + ["Search a Folder..." mh-search-folder t] + ["Visit a Folder..." mh-visit-folder t] + ["List Folders" mh-list-folders t] + ["Quit MH-E" mh-quit t])) +;;; Support for emacs21 toolbar using gnus/message.el icons (and code). +(eval-when-compile (defvar tool-bar-map)) +(when (and (fboundp 'tool-bar-add-item) + tool-bar-mode) + (defvar mh-folder-tool-bar-map + (let ((tool-bar-map (make-sparse-keymap))) + (tool-bar-add-item "mail" 'mh-inc-folder 'mh-folder-inc-folder + :help "Incorporate new mail in Inbox") + + (tool-bar-add-item "left_arrow" 'mh-previous-undeleted-msg + 'mh-folder-prev :help "Previous message") + (tool-bar-add-item "page-down" 'mh-page-msg 'mh-folder-page + :help "Page this message") + (tool-bar-add-item "right_arrow" 'mh-next-undeleted-msg 'mh-folder-next + :help "Next message") + + (tool-bar-add-item "close" 'mh-delete-msg 'mh-folder-delete + :help "Mark for deletion") + (tool-bar-add-item "refile" 'mh-refile-msg 'mh-folder-refile + :help "Refile this message") + (tool-bar-add-item "undo" 'mh-undo 'mh-folder-undo + :help "Undo this mark") + (tool-bar-add-item "execute" 'mh-execute-commands 'mh-folder-exec + :help "Perform moves and deletes") + + (tool-bar-add-item "show" 'mh-toggle-showing 'mh-folder-toggle-show + :help "Toggle showing message") + + (tool-bar-add-item "mail/reply2" 'mh-reply 'mh-folder-reply + :help "Reply to this message") + (tool-bar-add-item "mail_compose" 'mh-send 'mh-folder-compose + :help "Compose new message") + + (tool-bar-add-item "rescan" 'mh-rescan-folder 'mh-folder-rescan + :help "Rescan this folder") + (tool-bar-add-item "repack" 'mh-pack-folder 'mh-folder-pack + :help "Repack this folder") + + (tool-bar-add-item "search" 'mh-search-folder 'mh-folder-search + :help "Search this folder") + (tool-bar-add-item "fld_open" 'mh-visit-folder 'mh-folder-visit + :help "Visit other folder") + + (tool-bar-add-item "preferences" (lambda () + (interactive) + (customize-group "mh")) + 'mh-folder-customize + :help "mh-e preferences") + (tool-bar-add-item "help" (lambda () + (interactive) + (Info-goto-node "(mh-e)Top")) + 'mh-folder-help :help "Help") + tool-bar-map)) + + (defvar mh-folder-seq-tool-bar-map + (let ((tool-bar-map (copy-keymap mh-folder-tool-bar-map))) + (tool-bar-add-item "widen" 'mh-widen 'mh-folder-widen + :help "Widen from this sequence") + tool-bar-map) + "Tool-bar to use when narrowed to a sequence in MH-Folder buffers.") + ) + ;;;autoload the other mh-e parts ;;; mh-comp @@ -1503,6 +2023,8 @@ ;;; mh-seq +(autoload 'mh-region-to-sequence "mh-seq" + "Define sequence 'region as the messages in selected region." t) (autoload 'mh-delete-seq "mh-seq" "Delete the SEQUENCE." t) (autoload 'mh-list-sequences "mh-seq" @@ -1519,6 +2041,16 @@ "Remove restrictions from current folder, thereby showing all messages." t) (autoload 'mh-rename-seq "mh-seq" "Rename SEQUENCE to have NEW-NAME." t) +(autoload 'mh-narrow-to-subject-thread "mh-seq" + "Narrow to a sequence containing all following messages with same subject." + t) +(autoload 'mh-toggle-subject-thread "mh-seq" + "Narrow to or widen from a sequence containing current subject sequence." t) +(autoload 'mh-delete-subject-thread "mh-seq" + "Mark all following messages with same subject to be deleted." t) +(autoload 'mh-next-unseen-subject-thread "mh-seq" + "Get the next unseen subject thread." t) + (dolist (mess '("^Cursor not pointing to message$" "^There is no other window$"))
--- a/lisp/mail/mh-funcs.el Tue Oct 01 18:48:35 2002 +0000 +++ b/lisp/mail/mh-funcs.el Tue Oct 01 20:27:23 2002 +0000 @@ -1,7 +1,11 @@ ;;; mh-funcs.el --- mh-e functions not everyone will use right away -;; Time-stamp: <2001-07-14 13:08:45 pavel> + +;; Copyright (C) 1993, 1995, 2001, 2002 Free Software Foundation, Inc. -;; Copyright (C) 1993, 1995 Free Software Foundation, Inc. +;; Author: Bill Wohler <wohler@newt.com> +;; Maintainer: Bill Wohler <wohler@newt.com> +;; Keywords: mail +;; See: mh-e.el ;; This file is part of GNU Emacs. @@ -28,7 +32,7 @@ ;;; Change Log: -;; $Id: mh-funcs.el,v 1.5 1996/01/14 07:34:30 erik Exp $ +;; $Id: mh-funcs.el,v 1.12 2002/04/07 19:20:56 wohler Exp $ ;;; Code: @@ -71,7 +75,7 @@ (defun mh-copy-msg (msg-or-seq folder) - "Copy the specified MESSAGE(s) to another FOLDER without deleting them. + "Copy the specified MSG-OR-SEQ to another FOLDER without deleting them. Default is the displayed message. If optional prefix argument is provided, then prompt for the message sequence." (interactive (list (if current-prefix-arg @@ -84,10 +88,12 @@ (mh-notate-seq msg-or-seq mh-note-copied mh-cmd-note))) (defun mh-kill-folder () - "Remove the current folder." + "Remove the current folder and all included messages. +Removes all of the messages (files) within the specified current folder, +and then removes the folder (directory) itself." (interactive) - (if (or mh-do-not-confirm - (yes-or-no-p (format "Remove folder %s? " mh-current-folder))) + (if (yes-or-no-p (format "Remove folder %s (and all included messages)?" + mh-current-folder)) (let ((folder mh-current-folder)) (if (null mh-folder-list) (mh-set-folder-list)) @@ -100,23 +106,27 @@ (mh-set-folder-modified-p nil) ; so kill-buffer doesn't complain (if (get-buffer mh-show-buffer) (kill-buffer mh-show-buffer)) - (kill-buffer folder)) + (if (get-buffer folder) + (kill-buffer folder))) (message "Folder not removed"))) (defun mh-list-folders () "List mail folders." (interactive) - (with-output-to-temp-buffer mh-temp-buffer - (save-excursion - (switch-to-buffer mh-temp-buffer) - (erase-buffer) - (message "Listing folders...") - (mh-exec-cmd-output "folders" t (if mh-recursive-folders - "-recurse" + (let ((temp-buffer mh-temp-folders-buffer)) + (with-output-to-temp-buffer temp-buffer + (save-excursion + (set-buffer temp-buffer) + (erase-buffer) + (message "Listing folders...") + (mh-exec-cmd-output "folders" t (if mh-recursive-folders + "-recurse" "-norecurse")) - (goto-char (point-min)) - (message "Listing folders...done")))) + (goto-char (point-min)) + (view-mode 1) + (setq view-exit-action 'kill-buffer) + (message "Listing folders...done"))))) (defun mh-pack-folder (range) @@ -197,10 +207,10 @@ (defun mh-print-msg (msg-or-seq) - "Print MESSAGE(s) (default: displayed message) on printer. + "Print MSG-OR-SEQ (default: displayed message) on printer. If optional prefix argument provided, then prompt for the message sequence. -The variable mh-lpr-command-format is used to generate the print command. -The messages are formatted by mhl. See the variable mhl-formfile." +The variable `mh-lpr-command-format' is used to generate the print command. +The messages are formatted by mhl. See the variable `mhl-formfile'." (interactive (list (if current-prefix-arg (reverse (mh-seq-to-msgs (mh-read-seq-default "Print" t))) @@ -211,7 +221,7 @@ (let ((print-command (if (numberp msg-or-seq) (format "%s -nobell -clear %s %s | %s" - (expand-file-name "mhl" mh-lib) + (expand-file-name "mhl" mh-lib-progs) (mh-msg-filename msg-or-seq) (if (stringp mhl-formfile) (format "-form %s" mhl-formfile) @@ -223,7 +233,7 @@ (format "Sequence from %s" mh-current-folder)))) (format "(scan -clear %s ; %s -nobell -clear %s %s) | %s" (mapconcat (function (lambda (msg) msg)) msg-or-seq " ") - (expand-file-name "mhl" mh-lib) + (expand-file-name "mhl" mh-lib-progs) (if (stringp mhl-formfile) (format "-form %s" mhl-formfile) "") @@ -254,8 +264,8 @@ (defun mh-sort-folder (&optional extra-args) "Sort the messages in the current folder by date. Calls the MH program sortm to do the work. -The arguments in the list mh-sortm-args are passed to sortm -if this function is passed an argument." +The arguments in the list `mh-sortm-args' are passed to sortm +if the optional argument EXTRA-ARGS is given." (interactive "P") (mh-process-or-undo-commands mh-current-folder) (setq mh-next-direction 'forward) @@ -267,7 +277,8 @@ (defun mh-undo-folder (&rest ignore) - "Undo all pending deletes and refiles in current folder." + "Undo all pending deletes and refiles in current folder. +Argument IGNORE is deprecated." (interactive) (cond ((or mh-do-not-confirm (yes-or-no-p "Undo all commands in folder? ")) @@ -286,7 +297,7 @@ "Store the file(s) contained in the current message into DIRECTORY. The message can contain a shar file or uuencoded file. Default directory is the last directory used, or initially the value of -mh-store-default-directory or the current directory." +`mh-store-default-directory' or the current directory." (interactive (list (let ((udir (or mh-store-default-directory default-directory))) (read-file-name "Store message in directory: " udir udir nil))))
--- a/lisp/mail/mh-mime.el Tue Oct 01 18:48:35 2002 +0000 +++ b/lisp/mail/mh-mime.el Tue Oct 01 20:27:23 2002 +0000 @@ -1,7 +1,11 @@ ;;; mh-mime.el --- mh-e support for composing MIME messages -;; Time-stamp: <2001-07-15 09:52:45 pavel> + +;; Copyright (C) 1993, 1995, 2001, 2002 Free Software Foundation, Inc. -;; Copyright (C) 1993, 1995 Free Software Foundation, Inc. +;; Author: Bill Wohler <wohler@newt.com> +;; Maintainer: Bill Wohler <wohler@newt.com> +;; Keywords: mail +;; See: mh-e.el ;; This file is part of GNU Emacs. @@ -28,14 +32,13 @@ ;;; Change Log: -;; $Id: mh-mime.el,v 1.8 1998/09/23 21:51:50 kwzh Exp $ +;; $Id: mh-mime.el,v 1.26 2002/04/07 19:20:56 wohler Exp $ ;;; Code: (provide 'mh-mime) (require 'mh-comp) - ;; To do: ;; paragraph code should not fill # lines if MIME enabled. ;; implement mh-auto-edit-mhn (if non-nil, \\[mh-send-letter] @@ -54,31 +57,96 @@ (defvar mh-edit-mhn-hook nil "Invoked on the formatted letter by \\<mh-letter-mode-map>\\[mh-edit-mhn].") -;;;###autoload +(defun mh-have-file-command () + "Return t if 'file' command is on the system. +'file -i' is used to get MIME type of composition insertion." + (when (not (boundp 'mh-have-file-command)) + (load "executable" t t) ; executable-find not autoloaded in emacs20 + (setq mh-have-file-command + (and (fboundp 'executable-find) + (executable-find "file") ; file command exists + ; and accepts -i and -b args. + (zerop (call-process "file" nil nil nil "-i" "-b" + (expand-file-name "inc" mh-progs)))))) + mh-have-file-command) + +(defun mh-file-mime-type (filename) + "Return MIME type of FILENAME from file command. +Returns nil if file command not on system." + (cond + ((not (mh-have-file-command)) + nil) ;No file command, exit now. + ((not (and (file-exists-p filename)(file-readable-p filename))) + nil) + (t + (save-excursion + (let ((tmp-buffer (get-buffer-create mh-temp-buffer))) + (set-buffer tmp-buffer) + (unwind-protect + (progn + (call-process "file" nil '(t nil) nil "-b" "-i" + (expand-file-name filename)) + (goto-char (point-min)) + (if (not (re-search-forward mh-media-type-regexp nil t)) + nil + (match-string 0))) + (kill-buffer tmp-buffer))))))) + +(defvar mh-mhn-compose-insert-p nil + "Buffer-local variable to know whether MIME insertion was done. +Triggers an automatic call to `mh-edit-mhn' in `mh-send-letter'.") +(make-variable-buffer-local 'mh-mhn-compose-insert-p) + +;;; This is needed for Emacs20 which doesn't have mailcap-mime-types. (defvar mh-mime-content-types - '(("text/plain") ("text/richtext") - ("multipart/mixed") ("multipart/alternative") ("multipart/digest") - ("multipart/parallel") - ("message/rfc822") ("message/partial") ("message/external-body") - ("application/octet-stream") ("application/postscript") - ("image/jpeg") ("image/gif") - ("audio/basic") - ("video/mpeg")) - "Legal MIME content types. See documentation for \\[mh-edit-mhn].") + '(("application/mac-binhex40") ("application/msword") + ("application/octet-stream") ("application/pdf") ("application/pgp-keys") + ("application/pgp-signature") ("application/pkcs7-signature") + ("application/postscript") ("application/rtf") + ("application/vnd.ms-excel") ("application/vnd.ms-powerpoint") + ("application/vnd.ms-project") ("application/vnd.ms-tnef") + ("application/wordperfect5.1") ("application/wordperfect6.0") + ("application/zip") + + ("audio/basic") ("audio/mpeg") + + ("image/gif") ("image/jpeg") ("image/png") + + ("message/delivery-status") + ("message/external-body") ("message/partial") ("message/rfc822") + + ("text/enriched") ("text/html") ("text/plain") ("text/rfc822-headers") + ("text/richtext") ("text/xml") + + ("video/mpeg") ("video/quicktime")) + "Legal MIME content types. +See documentation for \\[mh-edit-mhn].") + +(defvar mh-media-type-regexp + (concat (regexp-opt '("text" "image" "audio" "video" "application" + "multipart" "message") t) + "/[-.+a-zA-Z0-9]+") + "Regexp matching valid media types used in MIME attachment compositions.") (defun mh-mhn-compose-insertion (filename type description attributes) "Add a directive to insert a MIME message part from a file. -This is the typical way to insert non-text parts in a message. -Arguments are FILENAME, which tells where to find the file, TYPE, the -MIME content type, and DESCRIPTION, a line of text for the -Content-description header. See also \\[mh-edit-mhn]." - (interactive (let ((filename (read-file-name "Insert contents of: "))) +This is the typical way to insert non-text parts in a message. Arguments are +FILENAME, which tells where to find the file, TYPE, the MIME content type, +DESCRIPTION, a line of text for the Content-Description field. ATTRIBUTES is a +comma separated list of name=value pairs that is appended to the Content-Type +field of the attachment. +See also \\[mh-edit-mhn]." + (interactive (let ((filename (read-file-name "Insert contents of: "))) (list filename - (completing-read "Content-type: " - mh-mime-content-types nil nil nil) - (read-string "Content-description: ") - (read-string "Content-Attributes: " + (or (mh-file-mime-type filename) + (completing-read "Content-Type: " + (if (and (require 'mailcap nil t) + (fboundp 'mailcap-mime-types)) + (mapcar 'list (mailcap-mime-types)) + mh-mime-content-types))) + (read-string "Content-Description: ") + (read-string "Content-Attributes: " (concat "name=\"" (file-name-nondirectory filename) "\""))))) @@ -86,6 +154,7 @@ (defun mh-mhn-compose-type (filename type &optional description attributes comment) + (setq mh-mhn-compose-insert-p t) (beginning-of-line) (insert "#" type) (and attributes @@ -109,9 +178,12 @@ (interactive (list (read-string "Remote host: ") (read-string "Remote filename: ") - (completing-read "External Content-type: " - mh-mime-content-types nil nil nil) - (read-string "External Content-description: "))) + (completing-read "External Content-Type: " + (if (and (require 'mailcap nil t) + (fboundp 'mailcap-mime-types)) + (mapcar 'list (mailcap-mime-types)) + mh-mime-content-types)) + (read-string "External Content-Description: "))) (mh-mhn-compose-external-type "anon-ftp" host filename type description)) @@ -136,6 +208,7 @@ (defun mh-mhn-compose-external-type (access-type host filename type &optional description attributes extra-params comment) + (setq mh-mhn-compose-insert-p t) (beginning-of-line) (insert "#@" type) (and attributes @@ -167,6 +240,7 @@ (if mh-sent-from-msg (format " [%d]" mh-sent-from-msg) ""))))) + (setq mh-mhn-compose-insert-p t) (beginning-of-line) (insert "#forw [") (and description @@ -187,35 +261,45 @@ (defun mh-edit-mhn (&optional extra-args) "Format the current draft for MIME, expanding any mhn directives. -Process the current draft with the mhn program, which, -using directives already inserted in the draft, fills in -all the MIME components and header fields. + +Process the current draft with the mhn program, which, using directives +already inserted in the draft, fills in all the MIME components and header +fields. + This step should be done last just before sending the message. -The mhn program is part of MH version 6.8 or later. -The `\\[mh-revert-mhn-edit]' command undoes this command. -The arguments in the list `mh-mhn-args' are passed to mhn -if this function is passed an argument. + +The `\\[mh-revert-mhn-edit]' command undoes this command. The arguments in the +list `mh-mhn-args' are passed to mhn if this function is passed an optional +prefix argument EXTRA-ARGS. -For assistance with creating mhn directives to insert -various types of components in a message, see -\\[mh-mhn-compose-insertion] (generic insertion from a file), -\\[mh-mhn-compose-anon-ftp] (external reference to file via anonymous ftp), -\\[mh-mhn-compose-external-compressed-tar] \ -\(reference to compressed tar file via anonymous ftp), and -\\[mh-mhn-compose-forw] (forward message)." +For assistance with creating mhn directives to insert various types of +components in a message, see \\[mh-mhn-compose-insertion] (generic insertion +from a file), \\[mh-mhn-compose-anon-ftp] (external reference to file via +anonymous ftp), \\[mh-mhn-compose-external-compressed-tar] \ \(reference to +compressed tar file via anonymous ftp), and \\[mh-mhn-compose-forw] (forward +message). If these helper functions are used, `mh-edit-mhn' is run +automatically when the draft is sent. + +The mhn program is part of MH version 6.8 or later." (interactive "*P") (save-buffer) (message "mhn editing...") - (mh-exec-cmd-error (format "mhdraft=%s" buffer-file-name) - "mhn" (if extra-args mh-mhn-args) buffer-file-name) + (cond + (mh-nmh-p + (mh-exec-cmd-error nil + "mhbuild" (if extra-args mh-mhn-args) buffer-file-name)) + (t + (mh-exec-cmd-error (format "mhdraft=%s" buffer-file-name) + "mhn" (if extra-args mh-mhn-args) buffer-file-name))) + (setq mh-mhn-compose-insert-p nil) (revert-buffer t t) (message "mhn editing...done") (run-hooks 'mh-edit-mhn-hook)) (defun mh-revert-mhn-edit (noconfirm) - "Undoes the effect of \\[mh-edit-mhn] by reverting to the backup file. -Optional non-nil argument means don't ask for confirmation." + "Undo the effect of \\[mh-edit-mhn] by reverting to the backup file. +Optional non-nil argument NOCONFIRM means don't ask for confirmation." (interactive "*P") (if (null buffer-file-name) (error "Buffer does not seem to be associated with any file")) @@ -230,11 +314,11 @@ ".orig"))))) (setq backup-strings (cdr backup-strings))) (or backup-strings - (error "mhn backup file for %s no longer exists!" buffer-file-name)) + (error "Backup file for %s no longer exists!" buffer-file-name)) (or noconfirm (yes-or-no-p (format "Revert buffer from file %s? " backup-file)) - (error "mhn edit revert not confirmed")) + (error "Revert not confirmed")) (let ((buffer-read-only nil)) (erase-buffer) (insert-file-contents backup-file))
--- a/lisp/mail/mh-pick.el Tue Oct 01 18:48:35 2002 +0000 +++ b/lisp/mail/mh-pick.el Tue Oct 01 20:27:23 2002 +0000 @@ -1,7 +1,11 @@ ;;; mh-pick.el --- make a search pattern and search for a message in mh-e -;; Time-stamp: <2001-12-20 18:55:31 pavel> + +;; Copyright (C) 1993, 1995, 2001 Free Software Foundation, Inc. -;; Copyright (C) 1993, 1995 Free Software Foundation, Inc. +;; Author: Bill Wohler <wohler@newt.com> +;; Maintainer: Bill Wohler <wohler@newt.com> +;; Keywords: mail +;; See: mh-e.el ;; This file is part of GNU Emacs. @@ -26,12 +30,14 @@ ;;; Change Log: -;; $Id: mh-pick.el,v 1.6 2001/07/15 19:53:53 pj Exp $ +;; $Id: mh-pick.el,v 1.11 2001/12/29 00:10:41 wohler Exp $ ;;; Code: (provide 'mh-pick) (require 'mh-e) +(require 'easymenu) +(require 'gnus-util) (defvar mh-pick-mode-hook nil "Invoked in `mh-pick-mode' on a new pattern.") @@ -71,29 +77,27 @@ (put 'mh-pick-mode 'mode-class 'special) -(defun mh-pick-mode () +(define-derived-mode mh-pick-mode fundamental-mode "MH-Pick" "Mode for creating search templates in mh-e.\\<mh-pick-mode-map> + After each field name, enter the pattern to search for. If a field's value does not matter for the search, leave it empty. To search the entire message, supply the pattern in the \"body\" of the template. Each non-empty field must be matched for a message to be selected. To effect a logical \"or\", use \\[mh-search-folder] multiple times. When you have finished, type \\[mh-do-pick-search] to do the search. -\\{mh-pick-mode-map} -Turning on mh-pick-mode calls the value of the variable mh-pick-mode-hook -if that value is non-nil." - (interactive) - (kill-all-local-variables) + +This mode runs the hook `mh-pick-mode-hook'. + +\\{mh-pick-mode-map}" + (make-local-variable 'mh-searching-folder) - (use-local-map mh-pick-mode-map) - (setq major-mode 'mh-pick-mode) - (mh-set-mode-name "MH-Pick") - (run-hooks 'mh-pick-mode-hook)) + (easy-menu-add mh-pick-menu)) (defun mh-do-pick-search () "Find messages that match the qualifications in the current pattern buffer. -Messages are searched for in the folder named in mh-searching-folder. +Messages are searched for in the folder named in `mh-searching-folder'. Add the messages found to the sequence named `search'." (interactive) (let ((pattern-buffer (buffer-name)) @@ -154,7 +158,7 @@ ;; Return the next piece of a pick argument that can be extracted from the ;; BUFFER. ;; Return a list like ("--fieldname" "pattern") or ("-search" "bodypat") - ;; or nil if no pieces remain. + ;; or NIL if no pieces remain. (set-buffer buffer) (let ((case-fold-search t)) (cond ((eobp) @@ -177,21 +181,27 @@ nil)))) ;;; Build the pick-mode keymap: +(gnus-define-keys mh-pick-mode-map + "\C-c\C-c" mh-do-pick-search + "\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-field + "\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-field + "\C-c\C-fr" mh-to-field + "\C-c\C-fs" mh-to-field + "\C-c\C-ft" mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-c" 'mh-do-pick-search) -(define-key mh-pick-mode-map "\C-c\C-f\C-b" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-f\C-c" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-f\C-d" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-f\C-f" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-f\C-r" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-f\C-s" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-f\C-t" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-fb" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-fc" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-fd" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-ff" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-fr" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-fs" 'mh-to-field) -(define-key mh-pick-mode-map "\C-c\C-ft" 'mh-to-field) +;;; Menu extracted from mh-menubar.el V1.1 (31 July 2001) +(easy-menu-define + mh-pick-menu mh-pick-mode-map "Menu for mh-e pick-mode" + '("Pick" + ["Execute the Search" mh-do-pick-search t])) ;;; mh-pick.el ends here
--- a/lisp/mail/mh-seq.el Tue Oct 01 18:48:35 2002 +0000 +++ b/lisp/mail/mh-seq.el Tue Oct 01 20:27:23 2002 +0000 @@ -1,7 +1,11 @@ ;;; mh-seq.el --- mh-e sequences support -;; Time-stamp: <2001-07-14 13:10:33 pavel> + +;; Copyright (C) 1993, 1995, 2001, 2002 Free Software Foundation, Inc. -;; Copyright (C) 1993, 1995 Free Software Foundation, Inc. +;; Author: Bill Wohler <wohler@newt.com> +;; Maintainer: Bill Wohler <wohler@newt.com> +;; Keywords: mail +;; See: mh-e.el ;; This file is part of GNU Emacs. @@ -26,7 +30,7 @@ ;;; Change Log: -;; $Id: mh-seq.el,v 1.6 1996/01/29 23:16:57 kwzh Exp $ +;; $Id: mh-seq.el,v 1.14 2002/04/07 19:20:56 wohler Exp $ ;;; Code: @@ -53,7 +57,7 @@ "List the sequences defined in FOLDER." (interactive (list (mh-prompt-for-folder "List sequences in" mh-current-folder t))) - (let ((temp-buffer mh-temp-buffer) + (let ((temp-buffer mh-temp-sequences-buffer) (seq-list mh-seq-list)) (with-output-to-temp-buffer temp-buffer (save-excursion @@ -78,6 +82,8 @@ (insert "\n")) (setq seq-list (cdr seq-list))) (goto-char (point-min)) + (view-mode 1) + (setq view-exit-action 'kill-buffer) (message "Listing sequences...done"))))) @@ -106,13 +112,16 @@ (setq mh-mode-line-annotation (symbol-name sequence)) (mh-make-folder-mode-line) (mh-recenter nil) + (if (and (boundp 'tool-bar-mode) tool-bar-mode) + (set (make-local-variable 'tool-bar-map) + mh-folder-seq-tool-bar-map)) (setq mh-narrowed-to-seq sequence))) (t (error "No messages in sequence `%s'" (symbol-name sequence)))))) (defun mh-put-msg-in-seq (msg-or-seq sequence) - "Add MESSAGE(s) (default: displayed message) to SEQUENCE. + "Add MSG-OR-SEQ (default: displayed message) to SEQUENCE. If optional prefix argument provided, then prompt for the message sequence." (interactive (list (if current-prefix-arg (mh-read-seq-default "Add messages from" t) @@ -129,14 +138,42 @@ (defun mh-widen () "Remove restrictions from current folder, thereby showing all messages." (interactive) - (if mh-narrowed-to-seq + (let ((msg (mh-get-msg-num nil))) + (when mh-narrowed-to-seq (with-mh-folder-updating (t) - (delete-region (point-min) (point-max)) - (widen) - (setq mh-mode-line-annotation mh-non-seq-mode-line-annotation) - (mh-make-folder-mode-line))) + (delete-region (point-min) (point-max)) + (widen) + (setq mh-mode-line-annotation mh-non-seq-mode-line-annotation) + (mh-make-folder-mode-line)) + (if msg + (mh-goto-msg msg t nil)))) + (mh-notate-deleted-and-refiled) + (if (and (boundp 'tool-bar-mode) tool-bar-mode) + (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map)) (setq mh-narrowed-to-seq nil)) + +;; FIXME? We may want to clear all notations and add one for current-message +;; and process user sequences. +(defun mh-notate-deleted-and-refiled () + ;; notate the sequence 'deleted as well as all the sequences in + ;; mh-refile-list. + ;; + ;; First, the 'deleted sequence is straightforward + (mh-notate-seq 'deleted mh-note-deleted mh-cmd-note) + ;; Second, refiles are stored in multiple sequences, one for each folder + ;; name to refile to. This list of buffer names is stored in + ;; mh-refile-list + (mh-mapc + (function + (lambda (dest) + ;; foreach folder name, get the keyed sequence from mh-seq-list + (let ((msg-list (cdr (assoc dest mh-seq-list)))) + (mapcar (lambda (msg) + ;; foreach msg in a sequence, do the mh-notate + (mh-notate msg mh-note-refiled mh-cmd-note)) + msg-list)))) + mh-refile-list)) ;;; Commands to manipulate sequences. Sequences are stored in an alist @@ -235,4 +272,118 @@ (goto-char location) (insert-buffer-substring (current-buffer) beginning-of-line end)))) +(defun mh-region-to-sequence (begin end) + "Define sequence 'region as the messages between point and mark. +When called programmatically, use arguments BEGIN and END to define region." + (interactive "r") + (mh-delete-seq-locally 'region) + (save-excursion + (goto-char begin) + (while (<= (point) end) + (mh-add-msgs-to-seq (mh-get-msg-num t) 'region t) + (forward-line 1)))) + + +;;; Commands to handle new 'subject sequence. +;;; Or "Poor man's threading" by psg. +(defun mh-subject-thread-to-sequence (all) + "Put all following messages with same subject in sequence 'subject. +If arg ALL is t, move to beginning of folder buffer to collect all messages. +If arg ALL is nil, collect only messages fron current one on forward. +Return number of messages put in the sequence: + nil -> there was no subject line. + 0 -> there were no later messages with the same subject (sequence not made) + >1 -> the total number of messages including current one." + (if (not (eq major-mode 'mh-folder-mode)) + (error "Not in a folder buffer")) + (save-excursion + (beginning-of-line) + (if (or (not (looking-at mh-scan-subject-regexp)) + (not (match-string 2)) + (string-equal "" (match-string 2))) + (progn (message "No subject line.") + nil) + (let ((subject (match-string-no-properties 2)) + (end (point-max)) + (list)) + (if (> (length subject) 41) + (setq subject (substring subject 0 41))) + (save-excursion + (if all + (goto-char (point-min))) + (while (re-search-forward mh-scan-subject-regexp nil t) + (let ((this-subject (match-string-no-properties 2))) + (if (> (length this-subject) 41) + (setq this-subject (substring this-subject 0 41))) + (if (string-equal this-subject subject) + (setq list (cons (mh-get-msg-num t) list)))))) + (cond + (list + ;; If we created a new sequence, add the initial message to it too. + (if (not (member (mh-get-msg-num t) list)) + (setq list (cons (mh-get-msg-num t) list))) + (mh-delete-seq-locally 'subject) + ;; sort the result into a sequence + (let ((sorted-list (sort (copy-sequence list) 'mh-lessp)) + (msg)) + (while sorted-list + (mh-add-msgs-to-seq (car sorted-list) 'subject t) + (setq sorted-list (cdr sorted-list))) + (safe-length list))) + (t + 0)))))) + +(defun mh-narrow-to-subject-thread () + "Narrow to a sequence containing all following messages with same subject." + (interactive) + (let ((num (mh-get-msg-num nil)) + (count (mh-subject-thread-to-sequence t))) + (cond + ((not count) ; No subject line, delete msg anyway + nil) + ((= 0 count) ; No other msgs, delete msg anyway. + (message "No other messages with same Subject following this one.") + nil) + (t ; We have a subject sequence. + (message "Found %d messages for subject sequence." count) + (mh-narrow-to-seq 'subject) + (if (numberp num) + (mh-goto-msg num t t)))))) + +(defun mh-toggle-subject-thread () + "Narrow to or widen from a sequence containing current subject sequence." + (interactive) + (if (and (stringp mh-mode-line-annotation) + (string-equal mh-mode-line-annotation "subject")) + (progn + (goto-char (point-min)) + (mh-widen)) + (mh-narrow-to-subject-thread))) + +(defun mh-delete-subject-thread () + "Mark all following messages with same subject to be deleted." + (interactive) + (let ((count (mh-subject-thread-to-sequence nil))) + (cond + ((not count) ; No subject line, delete msg anyway + (mh-delete-msg (mh-get-msg-num t))) + ((= 0 count) ; No other msgs, delete msg anyway. + (message "No other messages with same Subject following this one.") + (mh-delete-msg (mh-get-msg-num t))) + (t ; We have a subject sequence. + (message "Marked %d messages for deletion" count) + (mh-delete-msg 'subject))))) + +(defun mh-next-unseen-subject-thread () + "Get the next unseen subject thread." + (interactive) + (if (and mh-mode-line-annotation + (string-equal mh-mode-line-annotation "subject")) + (goto-char (point-min))) + (if (or (not mh-mode-line-annotation) + (not (string-equal mh-mode-line-annotation "unseen"))) + (mh-narrow-to-seq 'unseen)) + (mh-next-undeleted-msg) + (mh-narrow-to-subject-thread)) + ;;; mh-seq.el ends here
--- a/lisp/mail/mh-utils.el Tue Oct 01 18:48:35 2002 +0000 +++ b/lisp/mail/mh-utils.el Tue Oct 01 20:27:23 2002 +0000 @@ -1,6 +1,11 @@ ;;; mh-utils.el --- mh-e code needed for both sending and reading -;; Copyright (C) 1993, 1995, 1997, 2000, 2001 Free Software Foundation, Inc. +;; Copyright (C) 1993, 1995, 1997, 2000, 2001, 2002 Free Software Foundation, Inc. + +;; Author: Bill Wohler <wohler@newt.com> +;; Maintainer: Bill Wohler <wohler@newt.com> +;; Keywords: mail +;; See: mh-e.el ;; This file is part of GNU Emacs. @@ -23,8 +28,26 @@ ;; Internal support for mh-e package. +;;; Change Log: + +;; $Id: mh-utils.el,v 1.79 2002/04/07 19:20:56 wohler Exp $ + ;;; Code: +(load "executable" t t) ; Non-fatal dependency on + ; executable-find + +;;; Autoload mh-seq + +(autoload 'mh-add-to-sequence "mh-seq") +(autoload 'mh-notate-seq "mh-seq") +(autoload 'mh-read-seq-default "mh-seq") +(autoload 'mh-map-to-seq-msgs "mh-seq") + +;;; Other Autoloads + +(autoload 'mail-header-end "sendmail") + ;;; Set for local environment: ;;; mh-progs and mh-lib used to be set in paths.el, which tried to ;;; figure out at build time which of several possible directories MH @@ -41,11 +64,11 @@ (defvar mh-lib-progs nil "Directory containing MH helper programs. -This directory contains, among other things, +This directory contains, among other things, the mhl program.") (defvar mh-nmh-p nil - "Non-nil if nmh is installed on this system instead of MH") + "Non-nil if nmh is installed on this system instead of MH.") ;;;###autoload (put 'mh-progs 'risky-local-variable t) @@ -76,7 +99,7 @@ :type 'boolean :group 'mh) -(defcustom mh-clean-message-header nil +(defcustom mh-clean-message-header t "*Non-nil means clean headers of messages that are displayed or inserted. The variables `mh-visible-headers' and `mh-invisible-headers' control what is removed." @@ -91,33 +114,108 @@ :group 'mh-buffer) (defvar mh-invisible-headers - "^Received: \\|^Message-Id: \\|^Remailed-\\|^Via: \\|^Mail-from: \\|^Return-Path: \\|^Delivery-Date: \\|^In-Reply-To: \\|^Resent-" - "Regexp matching lines in a message header that are not to be shown. + (concat + "^" + (let ((max-specpdl-size 1000)) ;workaround for insufficient default + (regexp-opt + '( ;; RFC 822 + "Received: " "Message-Id: " "Return-Path: " + ;; RFC 2045 + "Mime-Version" "Content-" + ;; sendmail + "X-Authentication-Warning: " "X-MIME-Autoconverted: " "From " + "Status: " + ;; X400 + "X400-" "P1-Message-Id: " "Original-Encoded-Information-Types: " + "P1-Recipient: " "P1-Content-Type: " "Ua-Content-Id: " + ;; MH + "Resent" "Prev-Resent" "Forwarded: " "Replied: " "Delivery-Date: " + "In-Reply-To: " "Remailed-" "Via: " "Mail-from: " + ;; gnus + "X-Gnus-Mail-Source: " + ;; MS Outlook + "X-Priority: " "X-Msmail-" "X-MimeOLE: " "X-Apparently-From: " + "Importance: " "Sensitivity: " "X-MS-TNEF-Correlator: " + ;; Juno + "X-Juno-" + ;; Hotmail + "X-OriginalArrivalTime: " "X-Originating-IP: " + ;; Netscape/Mozilla + "X-Accept-Language: " "X-Mozilla-Status: " + ;; NTMail + "X-Info: " "X-VSMLoop: " + ;; News + "NNTP-" "X-News: " + ;; Mailman mailing list manager + "List-" "X-Beenthere: " "X-Mailman-Version: " + ;; Egroups/yahoogroups mailing list manager + "X-eGroups-" "X-Apparently-To: " "Mailing-List: " "Delivered-To: " + ;; SourceForge mailing list manager + "X-Original-Date: " + ;; Unknown mailing list managers + "X-Mailing-List: " "X-Loop: " + "List-Subscribe: " "List-Unsubscribe: " + "X-List-Subscribe: " "X-List-Unsubscribe: " + "X-Listserver: " "List-" "X-List-Host: " + ;; Sieve filtering + "X-Sieve: " + ;; Worldtalk gateways + "X-Wss-Id: " + ;; User added + "X-Face: " "X-Qotd-" + ;; Miscellaneous + "X-Sender: " "X-Ack: " "Errors-To: " "Precedence: " "X-Message-Id" + "X-From-Line" "X-Cron-Env: " "Delivery: " "X-Delivered" + "X-Received: " "X-Vms-To: " "Xref: " "X-Request-" "X-UIDL: " + "X-Orcl-Content-Type: " "X-Server-Uuid: " "X-Envelope-Sender: " + "X-Envelope-To: " "Encoding: " "Old-Return-Path: " "Path: " + "References: " "Lines: " "Autoforwarded: " "Bestservhost: " + "X-pgp: " "X-Accept-Language: " "Priority: " "User-Agent: " + "X-MIMETrack: " "X-Abuse-Info: " "X-Complaints-To: " + "X-No-Archive: " "X-Original-Complaints-To: " + "X-Original-Trace: " "X-Received-Date: " "X-Server-Date: " + "X-Trace: " "X-UserInfo1: " "X-submission-address: ") + t))) + "*Regexp matching lines in a message header that are not to be shown. If `mh-visible-headers' is non-nil, it is used instead to specify what to keep.") +;;; Additional header fields that might someday be added: +;;; "Sender: " "Reply-to: " + (defcustom mh-bury-show-buffer t "*Non-nil means that the displayed show buffer for a folder is buried." :type 'boolean :group 'mh-buffer) -(defcustom mh-summary-height 4 +(defcustom mh-summary-height (or (and (fboundp 'frame-height) + (> (frame-height) 24) + (min 10 (/ (frame-height) 6))) + 4) "*Number of lines in MH-Folder window (including the mode line)." :type 'integer :group 'mh-buffer) -(defvar mh-msg-number-regexp "^ *\\([0-9]+\\)" +;; Use goto-addr if it was already loaded (which probably sets this +;; variable to t), or if this variable is otherwise set to t. +(defcustom mh-show-use-goto-addr (and (boundp 'goto-address-highlight-p) + goto-address-highlight-p) + "*Non-nil means URLs and e-mail addresses are highlighted using goto-addr while in mh-show-mode." + :type 'boolean + :group 'mh-buffer) + +(defvar mh-scan-msg-number-regexp "^ *\\([0-9]+\\)" "Regexp to find the number of a message in a scan line. The message's number must be surrounded with \\( \\)") -(defvar mh-msg-search-regexp "^[^0-9]*%d[^0-9]" +(defvar mh-scan-msg-search-regexp "^[^0-9]*%d[^0-9]" "Format string containing a regexp matching the scan listing for a message. The desired message's number will be an argument to format.") (defcustom mhl-formfile nil "*Name of format file to be used by mhl to show and print messages. -A value of t means use the default format file. -nil means don't use mhl to format messages when showing; mhl is still used, +A value of T means use the default format file. +Nil means don't use mhl to format messages when showing; mhl is still used, with the default format file, to format messages when printing them. The format used should specify a non-zero value for overflowoffset so the message continues to conform to RFC 822 and mh-e can parse the headers." @@ -125,20 +223,55 @@ :group 'mh) (put 'mhl-formfile 'info-file "mh-e") +(defvar mh-decode-quoted-printable-have-mimedecode + (not (null (and (fboundp 'executable-find)(executable-find "mimedecode")))) + "Whether the mimedecode command is installed on the system. +This sets the default value of variable `mh-decode-quoted-printable' to +determine whether quoted-printable MIME parts are decode when viewed in +`mh-show'. The source code for mimedecode can be obtained from +http://www.freesoft.org/CIE/FAQ/mimedeco.c") + +(defcustom mh-decode-quoted-printable + mh-decode-quoted-printable-have-mimedecode + "Whether to decode quoted-printable MIME parts in `mh-show'. +This can only be done if the 'mimedecode' command is available in the +executable path on the system (the mh-decode-quoted-printable-have-mimedecode +variable is set if the command was found). That program is used as a helper +program to achieve this. The source code for mimedecode can usually be +obtained from http://www.freesoft.org/CIE/FAQ/mimedeco.c" + :type 'boolean + :group 'mh-buffer) + +(defcustom mh-update-sequences-after-mh-show t + "Whether to call `mh-update-sequence' in `mh-show-mode'. +If set, `mh-update-sequence' is run every time a message is shown, telling +MH or nmh that this is your current message. It's useful, for example, to +display MIME content using \"M-! mhshow RET\"" + :type 'boolean + :group 'mh-buffer) + +(defcustom mh-highlight-citation-p 'gnus + "How to highlight citations in show buffers. +The gnus method uses a different color for each indentation." + :type '(choice (const :tag "Use gnus" gnus) + (const :tag "Use font-lock" font-lock) + (const :tag "Don't fontify" nil)) + :group 'mh-buffer) + (defvar mh-default-folder-for-message-function nil "Function to select a default folder for refiling or Fcc. If set to a function, that function is called with no arguments by `\\[mh-refile-msg]' and `\\[mh-to-fcc]' to get a default when prompting the user for a folder. The function is called from within a -save-excursion, with point at the start of the message. It should +`save-excursion', with point at the start of the message. It should return the folder to offer as the refile or Fcc folder, as a string with a leading `+' sign. It can also return an empty string to use no -default, or nil to calculate the default the usual way. +default, or NIL to calculate the default the usual way. NOTE: This variable is not an ordinary hook; It may not be a list of functions.") (defvar mh-find-path-hook nil - "Invoked by mh-find-path while reading the user's MH profile.") + "Invoked by `mh-find-path' while reading the user's MH profile.") (defvar mh-folder-list-change-hook nil "Invoked whenever the cached folder list `mh-folder-list' is changed.") @@ -153,58 +286,257 @@ (defvar mh-note-seq "%" "String whose first character is used to notate messages in a sequence.") +(defvar mh-mail-header-separator "--------" + "*Line used by MH to separate headers from text in messages being composed. +This variable should not be used directly in programs. Programs should use +`mail-header-separator' instead. `mail-header-separator' is initialized to +`mh-mail-header-separator' in `mh-letter-mode'; in other contexts, you may +have to perform this initialization yourself. + +Do not make this a regexp as it may be the argument to `insert' and it is +passed through `regexp-quote' before being used by functions like +`re-search-forward'.") + +(defun mh-in-header-p () + ;; Return non-nil if the point is in the header of a draft message. + (< (point) (mail-header-end))) + +(defun mh-header-field-end () + ;; Move to the end of the current header field. + ;; Handles RFC 822 continuation lines. + (forward-line 1) + (while (looking-at "^[ \t]") + (forward-line 1)) + (backward-char 1)) ;to end of previous line + +(defun mh-letter-header-font-lock (limit) + "Return the entire mail header to font-lock. +Argument LIMIT limits search." + (if (= (point) limit) + nil + (let* ((mail-header-end (save-match-data (mail-header-end))) + (lesser-limit (if (< mail-header-end limit) mail-header-end limit))) + (when (mh-in-header-p) + (set-match-data (list 1 lesser-limit)) + (goto-char lesser-limit) + t)))) + +(defun mh-header-field-font-lock (field limit) + "Return the value of a header field FIELD to font-lock. +Argument LIMIT limits search." + (if (= (point) limit) + nil + (let* ((mail-header-end (mail-header-end)) + (lesser-limit (if (< mail-header-end limit) mail-header-end limit)) + (case-fold-search t)) + (when (and (< (point) mail-header-end) ;Only within header + (re-search-forward (format "^%s" field) lesser-limit t)) + (let ((match-one-b (match-beginning 0)) + (match-one-e (match-end 0))) + (mh-header-field-end) + (if (> (point) limit) ;Don't search for end beyond limit + (goto-char limit)) + (set-match-data (list match-one-b match-one-e + (1+ match-one-e) (point))) + t))))) + +(defun mh-header-to-font-lock (limit) + (mh-header-field-font-lock "To:" limit)) + +(defun mh-header-cc-font-lock (limit) + (mh-header-field-font-lock "cc:" limit)) + +(defun mh-header-subject-font-lock (limit) + (mh-header-field-font-lock "Subject:" limit)) + +(defvar mh-show-to-face 'mh-show-to-face + "Face for highlighting the To: header field.") +(if (boundp 'facemenu-unlisted-faces) + (add-to-list 'facemenu-unlisted-faces "^mh-show")) +(defface mh-show-to-face + '((((class grayscale) (background light)) + (:foreground "DimGray" :underline t)) + (((class grayscale) (background dark)) + (:foreground "LightGray" :underline t)) + (((class color) (background light)) (:foreground "SaddleBrown")) + (((class color) (background dark)) (:foreground "burlywood")) + (t (:underline t))) + "Face for highlighting the To: header field." + :group 'mh-buffer) + +(defvar mh-show-from-face 'mh-show-from-face + "Face for highlighting the From: header field.") +(defface mh-show-from-face + '((((class color) (background light)) + (:foreground "red3")) + (((class color) (background dark)) + (:foreground "cyan")) + (t + (:bold t))) + "Face for highlighting the From: header field." + :group 'mh-buffer) + +(defvar mh-folder-subject-face 'mh-folder-subject-face + "Face for highlighting subject text in MH-Folder buffers.") +(if (boundp 'facemenu-unlisted-faces) + (add-to-list 'facemenu-unlisted-faces "^mh-folder")) +(defface mh-folder-subject-face + '((((class color) (background light)) + (:foreground "blue4")) + (((class color) (background dark)) + (:foreground "yellow")) + (t + (:bold t))) + "Face for highlighting subject text in MH-Folder buffers." + :group 'mh) +(defvar mh-show-subject-face 'mh-show-subject-face + "Face for highlighting the Subject header field.") +(copy-face 'mh-folder-subject-face 'mh-show-subject-face) + +(eval-after-load "font-lock" + '(progn + (defvar mh-show-cc-face 'mh-show-cc-face + "Face for highlighting cc header fields.") + (copy-face 'font-lock-variable-name-face 'mh-show-cc-face) + (defvar mh-show-date-face 'mh-show-date-face + "Face for highlighting the Date header field.") + (copy-face 'font-lock-type-face 'mh-show-date-face) + (defvar mh-show-header-face 'mh-show-header-face + "Face used to deemphasize unspecified header fields.") + (copy-face 'font-lock-string-face 'mh-show-header-face) + + (defvar mh-show-font-lock-keywords + '(("^\\(From:\\|Sender:\\)\\(.*\\)" + (1 'default) (2 mh-show-from-face)) + (mh-header-to-font-lock + (0 'default) (1 mh-show-to-face)) + (mh-header-cc-font-lock + (0 'default) (1 mh-show-cc-face)) + ("^\\(Reply-To:\\|Return-Path:\\)\\(.*\\)$" + (1 'default) (2 mh-show-from-face)) + (mh-header-subject-font-lock + (0 'default) (1 mh-show-subject-face)) + ("^\\(Apparently-To:\\|Newsgroups:\\)\\(.*\\)" + (1 'default) (2 mh-show-cc-face)) + ("^\\(In-reply-to\\|Date\\):\\(.*\\)$" + (1 'default) (2 mh-show-date-face)) + (mh-letter-header-font-lock (0 mh-show-header-face append t))) + "Additional expressions to highlight in MH-show mode.") + + (defvar mh-show-font-lock-keywords-with-cite + (eval-when-compile + (let* ((cite-chars "[>|}]") + (cite-prefix "A-Za-z") + (cite-suffix (concat cite-prefix "0-9_.@-`'\""))) + (append + mh-show-font-lock-keywords + (list + ;; Use MATCH-ANCHORED to effectively anchor the regexp left side. + `(,cite-chars + (,(concat "\\=[ \t]*" + "\\(\\([" cite-prefix "]+[" cite-suffix "]*\\)?" + "\\(" cite-chars "[ \t]*\\)\\)+" + "\\(.*\\)") + (beginning-of-line) (end-of-line) + (2 font-lock-constant-face nil t) + (4 font-lock-comment-face nil t))))))) + "Additional expressions to highlight in MH-show mode.") + )) + +(defun mh-gnus-article-highlight-citation () + "Highlight cited text in current buffer using gnus." + (interactive) + (require 'gnus-cite) + (let ((modified (buffer-modified-p)) + (gnus-article-buffer (buffer-name)) + (gnus-cite-face-list + '(gnus-cite-face-2 gnus-cite-face-3 gnus-cite-face-4 gnus-cite-face-5 + gnus-cite-face-6 gnus-cite-face-7 gnus-cite-face-8 gnus-cite-face-9 + gnus-cite-face-10 gnus-cite-face-11 gnus-cite-face-1))) + (gnus-article-highlight-citation t) + (set-buffer-modified-p modified))) + ;;; Internal bookkeeping variables: ;; The value of `mh-folder-list-change-hook' is called whenever ;; mh-folder-list variable is set. -(defvar mh-folder-list nil) ;List of folder names for completion. +;; List of folder names for completion. +(defvar mh-folder-list nil) ;; Cached value of the `Path:' component in the user's MH profile. -(defvar mh-user-path nil) ;User's mail folder directory. +;; User's mail folder directory. +(defvar mh-user-path nil) -;; An mh-draft-folder of nil means do not use a draft folder. +;; An mh-draft-folder of NIL means do not use a draft folder. ;; Cached value of the `Draft-Folder:' component in the user's MH profile. -(defvar mh-draft-folder nil) ;Name of folder containing draft messages. +;; Name of folder containing draft messages. +(defvar mh-draft-folder nil) ;; Cached value of the `Unseen-Sequence:' component in the user's MH profile. -(defvar mh-unseen-seq nil) ;Name of the Unseen sequence. +;; Name of the Unseen sequence. +(defvar mh-unseen-seq nil) -;; Cached value of the `Previous-Sequence:' component in the user's MH profile. -(defvar mh-previous-seq nil) ;Name of the Previous sequence. +;; Cached value of the `Previous-Sequence:' component in the user's MH +;; profile. +;; Name of the Previous sequence. +(defvar mh-previous-seq nil) ;; Cached value of the `Inbox:' component in the user's MH profile, ;; or "+inbox" if no such component. -(defvar mh-inbox nil) ;Name of the Inbox folder. +;; Name of the Inbox folder. +(defvar mh-inbox nil) + +;; Name of mh-e scratch buffer. +(defconst mh-temp-buffer " *mh-temp*") + +;; Name of the mh-e folder list buffer. +(defconst mh-temp-folders-buffer "*Folders*") -(defconst mh-temp-buffer " *mh-temp*") ;Name of mh-e scratch buffer. +;; Name of the mh-e sequences list buffer. +(defconst mh-temp-sequences-buffer "*Sequences*") -(defvar mh-previous-window-config nil) ;Window configuration before mh-e command. +;; Window configuration before mh-e command. +(defvar mh-previous-window-config nil) + +;;Non-nil means next SPC or whatever goes to next undeleted message. +(defvar mh-page-to-next-msg-p nil) ;;; Internal variables local to a folder. -(defvar mh-current-folder nil) ;Name of current folder, a string. +;; Name of current folder, a string. +(defvar mh-current-folder nil) -(defvar mh-show-buffer nil) ;Buffer that displays message for this folder. +;; Buffer that displays message for this folder. +(defvar mh-show-buffer nil) -(defvar mh-folder-filename nil) ;Full path of directory for this folder. +;; Full path of directory for this folder. +(defvar mh-folder-filename nil) -(defvar mh-msg-count nil) ;Number of msgs in buffer. +;;Number of msgs in buffer. +(defvar mh-msg-count nil) -(defvar mh-showing nil) ;If non-nil, show the message in a separate window. +;; If non-nil, show the message in a separate window. +(defvar mh-showing-mode nil) ;;; This holds a documentation string used by describe-mode. -(defun mh-showing () - "When moving to a new message in the Folder window, -also show it in a separate Show window." - nil) +(defun mh-showing-mode (&optional arg) + "Change whether messages should be displayed. +With arg, display messages iff ARG is positive." + (setq mh-showing-mode + (if (null arg) + (not mh-showing-mode) + (> (prefix-numeric-value arg) 0)))) -(defvar mh-seq-list nil) ;The sequences of this folder. An alist of (seq . msgs). +;; The sequences of this folder. An alist of (seq . msgs). +(defvar mh-seq-list nil) -(defvar mh-seen-list nil) ;List of displayed messages to be removed from the Unseen sequence. +;; List of displayed messages to be removed from the Unseen sequence. +(defvar mh-seen-list nil) ;; If non-nil, show buffer contains message with all headers. ;; If nil, show buffer contains message processed normally. -(defvar mh-showing-with-headers nil) ;Showing message with headers or normally. +;; Showing message with headers or normally. +(defvar mh-showing-with-headers nil) ;;; mh-e macros @@ -254,23 +586,35 @@ ;;; Ensure new buffers won't get this mode if default-major-mode is nil. (put 'mh-show-mode 'mode-class 'special) -(defun mh-show-mode () +(define-derived-mode mh-show-mode text-mode "MH-Show" "Major mode for showing messages in mh-e. -The value of mh-show-mode-hook is called when a new message is displayed." - (kill-all-local-variables) - (setq major-mode 'mh-show-mode) - (mh-set-mode-name "MH-Show") - (run-hooks 'mh-show-mode-hook)) - +The value of `mh-show-mode-hook' is called when a new message is displayed." + (set (make-local-variable 'mail-header-separator) mh-mail-header-separator) + (mh-show-unquote-From) + (when mh-show-use-goto-addr + (if (not (featurep 'goto-addr)) + (load "goto-addr" t t)) + (if (fboundp 'goto-address) + (goto-address))) + (make-local-variable 'font-lock-defaults) + (set (make-local-variable 'font-lock-support-mode) nil) + (cond + ((equal mh-highlight-citation-p 'font-lock) + (setq font-lock-defaults '(mh-show-font-lock-keywords-with-cite t))) + ((equal mh-highlight-citation-p 'gnus) + (setq font-lock-defaults '(mh-show-font-lock-keywords t)) + (mh-gnus-article-highlight-citation)) + (t + (setq font-lock-defaults '(mh-show-font-lock-keywords t))))) (defun mh-maybe-show (&optional msg) ;; If in showing mode, then display the message pointed to by the cursor. - (if mh-showing (mh-show msg))) + (if mh-showing-mode (mh-show msg))) (defun mh-show (&optional message) "Show MESSAGE (default: message at cursor). Force a two-window display with the folder window on top (size -mh-summary-height) and the show buffer below it. +`mh-summary-height') and the show buffer below it. If the message is already visible, display the start of the message. Display of the message is controlled by setting the variables @@ -283,11 +627,17 @@ (mh-invalidate-show-buffer)) (mh-show-msg message)) +(defun mh-show-mouse (EVENT) + "Move point to mouse EVENT and show message." + (interactive "e") + (mouse-set-point EVENT) + (mh-show)) (defun mh-show-msg (msg) (if (not msg) (setq msg (mh-get-msg-num t))) - (setq mh-showing t) + (mh-showing-mode t) + (setq mh-page-to-next-msg-p nil) (let ((folder mh-current-folder) (clean-message-header mh-clean-message-header) (show-window (get-buffer-window mh-show-buffer))) @@ -305,9 +655,39 @@ (shrink-window (- (window-height) mh-summary-height))) (mh-recenter nil) (if (not (memq msg mh-seen-list)) (setq mh-seen-list (cons msg mh-seen-list))) + (when mh-update-sequences-after-mh-show + (mh-update-sequences)) (run-hooks 'mh-show-hook)) +(defun mh-decode-quoted-printable () + ;; Run mimedecode commmand on current buffer, replacing it contents. + (let ((case-fold-search t)) + (goto-char (point-min)) + (when (and (re-search-forward + "^content-transfer-encoding:[ \t]*quoted-printable" + nil t) + (search-forward "\n\n" nil t)) + (message "Converting quoted-printable characters...") + (let ((modified (buffer-modified-p)) + (command "mimedecode")) + (shell-command-on-region (point-min) (point-max) command t t) + (if (fboundp 'deactivate-mark) + (deactivate-mark)) + (set-buffer-modified-p modified)) + (message "Converting quoted-printable characters... done.")))) + + +(defun mh-show-unquote-From () + ;; Decode >From at beginning of lines for mh-show-mode + (save-excursion + (let ((modified (buffer-modified-p)) + (case-fold-search nil)) + (goto-char (mail-header-end)) + (while (re-search-forward "^>From" nil t) + (replace-match "From")) + (set-buffer-modified-p modified)))) + (defun mh-display-msg (msg-num folder) ;; Display message NUMBER of FOLDER. ;; Sets the current buffer to the show buffer. @@ -335,6 +715,8 @@ (list "-form" formfile)) msg-filename) (insert-file-contents msg-filename)) + (if mh-decode-quoted-printable + (mh-decode-quoted-printable)) (goto-char (point-min)) (cond (clean-message-header (mh-clean-msg-header (point-min) @@ -395,7 +777,7 @@ ;; pointing to a message. (save-excursion (beginning-of-line) - (cond ((looking-at mh-msg-number-regexp) + (cond ((looking-at mh-scan-msg-number-regexp) (string-to-int (buffer-substring (match-beginning 1) (match-end 1)))) (error-if-no-message @@ -417,7 +799,9 @@ ;; regular expression specifying the lines to display, otherwise ;; INVISIBLE-HEADERS contains a regular expression specifying lines to ;; delete from the header. - (let ((case-fold-search t)) + (let ((case-fold-search t) + (after-change-functions nil)) ;Work around emacs-20 font-lock bug + ;causing an endless loop. (save-restriction (goto-char start) (if (search-forward "\n\n" nil 'move) @@ -442,11 +826,13 @@ (defun mh-recenter (arg) - ;; Like recenter but with two improvements: nil arg means recenter, - ;; and only does anything if the current buffer is in the selected - ;; window. (Commands like save-some-buffers can make this false.) + ;; Like recenter but with two improvements: + ;; - only does anything if the current buffer is in the selected + ;; window. (Commands like save-some-buffers can make this false.) + ;; - nil arg means recenter as with C-u prefix (if (eq (get-buffer-window (current-buffer)) (selected-window)) + ;; '(4) is the same as C-u prefix argument. (recenter (if arg arg '(4))))) @@ -454,7 +840,6 @@ ;; Delete version of kill-line. (delete-region (point) (progn (forward-line lines) (point)))) - (defun mh-notate (msg notation offset) ;; Marks MESSAGE with the character NOTATION at position OFFSET. ;; Null MESSAGE means the message that the cursor points to. @@ -489,10 +874,10 @@ (defun mh-goto-msg (number &optional no-error-if-no-message dont-show) "Position the cursor at message NUMBER. -Optional non-nil second argument means return nil instead of -signaling an error if message does not exist; in this case, -the cursor is positioned near where the message would have been. -Non-nil third argument means not to show the message." +Optional non-nil second argument NO-ERROR-IF-NO-MESSAGE means return nil +instead of signaling an error if message does not exist; in this case, the +cursor is positioned near where the message would have been. +Non-nil third argument DONT-SHOW means not to show the message." (interactive "NGo to message: ") (setq number (prefix-numeric-value number)) ;Emacs 19 ;; This basic routine tries to be as fast as possible, @@ -524,12 +909,12 @@ (defun mh-msg-search-pat (n) ;; Return a search pattern for message N in the scan listing. - (format mh-msg-search-regexp n)) + (format mh-scan-msg-search-regexp n)) (defun mh-get-profile-field (field) ;; Find and return the value of FIELD in the current buffer. - ;; Returns nil if the field is not in the buffer. + ;; Returns NIL if the field is not in the buffer. (let ((case-fold-search t)) (goto-char (point-min)) (cond ((not (re-search-forward (format "^%s" field) nil t)) nil) @@ -604,13 +989,12 @@ (and (file-regular-p file) (file-executable-p file))) (defun mh-find-progs () - "Find the `inc' and `mhl' programs of MH. + "Find the directories for the installed MH/nmh binaries and config files. Set the `mh-progs' and `mh-lib', and `mh-lib-progs' variables to the -directory names." - (or (and mh-progs (mh-file-command-p (expand-file-name "inc" mh-progs))) - (setq mh-progs - (or (mh-path-search exec-path "inc") - (mh-path-search '("/usr/local/bin/mh/" +directory names and set `mh-nmh-p' if we detect nmh instead of MH." + (let ((path (or (mh-path-search exec-path "mhparam") + (mh-path-search '("/usr/local/nmh/bin" ; nmh default + "/usr/local/bin/mh/" "/usr/local/mh/" "/usr/bin/mh/" ;Ultrix 4.2 "/usr/new/mh/" ;Ultrix <4.2 @@ -618,41 +1002,28 @@ "/usr/pkg/bin/" ; NetBSD "/usr/local/bin/" ) - "inc")))) - (or (null mh-progs) - (let ((mh-base mh-progs)) - (while (let ((dir-name (file-name-nondirectory - (directory-file-name mh-base)))) - (or (string= "mh" dir-name) - (string= "bin" dir-name))) - (setq mh-base - (file-name-directory (directory-file-name mh-base)))) - (or (and mh-lib - (file-exists-p (expand-file-name "components" mh-lib))) - (setq mh-lib - ;; Look for a lib directory roughly parallel to the bin - ;; directory: Strip any trailing `mh' or `bin' path - ;; components, then look for lib/mh or mh/lib. - (or (mh-path-search - (mapcar (lambda (p) (expand-file-name p mh-base)) - '("lib/mh" "etc/nmh" "/etc/nmh" "mh/lib" "etc" "lib")) - "components" - 'file-exists-p)))) - (or (and mh-lib-progs - (mh-file-command-p (expand-file-name "mhl" mh-lib-progs))) - (setq mh-lib-progs - (or (mh-path-search - (mapcar (lambda (p) (expand-file-name p mh-base)) - '("lib/mh" "libexec/nmh" "lib/nmh" "mh/lib" "lib")) - "mhl") - (mh-path-search '("/usr/local/bin/mh/") "mhl") - (mh-path-search exec-path "mhl") ;unlikely - ))))) - (unless (and mh-progs mh-lib mh-lib-progs) - (error "Cannot find the commands `inc' and `mhl' and the file `components'")) - (setq mh-nmh-p (not (null - (or (string-match "nmh" mh-lib-progs) - (string-match "nmh" mh-lib)))))) + "mhparam")))) + (if (not path) + (error "Unable to find the `mhparam' command")) + (save-excursion + (let ((tmp-buffer (get-buffer-create mh-temp-buffer))) + (set-buffer tmp-buffer) + (unwind-protect + (progn + (call-process (expand-file-name "mhparam" path) + nil '(t nil) nil "libdir" "etcdir") + (goto-char (point-min)) + (if (search-forward-regexp "^libdir:\\s-\\(\\S-+\\)\\s-*$" nil t) + (setq mh-lib-progs (match-string 1) + mh-lib mh-lib-progs + mh-progs path)) + (goto-char (point-min)) + (if (search-forward-regexp "^etcdir:\\s-\\(\\S-+\\)\\s-*$" nil t) + (setq mh-lib (match-string 1) + mh-nmh-p t))) + (kill-buffer tmp-buffer)))) + (unless (and mh-progs mh-lib mh-lib-progs) + (error "Unable to determine paths from `mhparam' command")))) (defun mh-path-search (path file &optional func-p) ;; Search PATH, a list of directory names, for FILE. @@ -713,17 +1084,6 @@ (mh-add-to-sequence seq msgs) (mh-notate-seq seq mh-note-seq (1+ mh-cmd-note)))))) -(autoload 'mh-add-to-sequence "mh-seq") -(autoload 'mh-notate-seq "mh-seq") -(autoload 'mh-read-seq-default "mh-seq") -(autoload 'mh-map-to-seq-msgs "mh-seq") - - -(defun mh-set-mode-name (mode-name-string) - ;; Set the mode-name and ensure that the mode line is updated. - (setq mode-name mode-name-string) - (force-mode-line-update t)) - (defvar mh-folder-hist nil) (defun mh-prompt-for-folder (prompt default can-create) @@ -747,6 +1107,8 @@ (setq read-name default)) ((not (mh-folder-name-p read-name)) (setq read-name (format "+%s" read-name)))) + (if (or (not read-name) (equal "" read-name)) + (error "No folder specified")) (setq folder-name read-name) (cond ((and (> (length folder-name) 0) (eq (aref folder-name (1- (length folder-name))) ?/)) @@ -848,7 +1210,7 @@ (defun mh-folder-name-p (name) - ;; Return non-nil if NAME is possibly the name of a folder. + ;; Return non-NIL if NAME is possibly the name of a folder. ;; A name (a string or symbol) can be a folder name if it begins with "+". (if (symbolp name) (eq (aref (symbol-name name) 0) ?+) @@ -888,7 +1250,7 @@ ;; the shell hacks necessary here shows just how broken Unix is (apply 'call-process "/bin/sh" nil t nil "-c" (format "%s %s ${1+\"$@\"}" - env + env (expand-file-name command mh-progs)) command (mh-list-to-string args))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/mail/mh-xemacs-compat.el Tue Oct 01 20:27:23 2002 +0000 @@ -0,0 +1,103 @@ +;;; mh-xemacs-compat.el --- GNU Emacs Functions needed by XEmacs + +;; Copyright (C) 2001, 2002 Free Software Foundation, Inc. + +;; Author: FSF +;; Maintainer: Bill Wohler <wohler@newt.com> +;; 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: + +;;; Change Log: + +;; $Id: mh-xemacs-compat.el,v 1.7 2002/04/07 19:20:55 wohler Exp $ + +;;; Code: + +;;; Simple compatibility: + +(unless (fboundp 'match-string-no-properties) + (defalias 'match-string-no-properties 'match-string)) + +;;; Functions from simple.el of Emacs-21.1 +;;; simple.el --- basic editing commands for Emacs + +;; Copyright (C) 1985, 86, 87, 93, 94, 95, 96, 97, 98, 99, 2000, 2001 +;; Free Software Foundation, Inc. + +(defun rfc822-goto-eoh () + ;; Go to header delimiter line in a mail message, following RFC822 rules + (goto-char (point-min)) + (while (looking-at "^[^: \n]+:\\|^[ \t]") + (forward-line 1)) + (point)) + +;;; Functions from sendmail.el of Emacs-21.1 +;;; sendmail.el --- mail sending commands for Emacs. + +;; Copyright (C) 1985, 86, 92, 93, 94, 95, 96, 98, 2000, 2001 +;; Free Software Foundation, Inc. + +(defun mail-header-end () + "Return the buffer location of the end of headers, as a number." + (save-restriction + (widen) + (save-excursion + (rfc822-goto-eoh) + (point)))) + +(defun mail-mode-fill-paragraph (arg) + ;; Do something special only if within the headers. + (if (< (point) (mail-header-end)) + (let (beg end fieldname) + (when (prog1 (re-search-backward "^[-a-zA-Z]+:" nil 'yes) + (setq beg (point))) + (setq fieldname + (downcase (buffer-substring beg (1- (match-end 0)))))) + (forward-line 1) + ;; Find continuation lines and get rid of their continuation markers. + (while (looking-at "[ \t]") + (delete-horizontal-space) + (forward-line 1)) + (setq end (point-marker)) + (goto-char beg) + ;; If this field contains addresses, + ;; make sure we can fill after each address. + (if (member fieldname + '("to" "cc" "bcc" "from" "reply-to" + "resent-to" "resent-cc" "resent-bcc" + "resent-from" "resent-reply-to")) + (while (search-forward "," end t) + (or (looking-at "[ \t]") + (insert " ")))) + (fill-region-as-paragraph beg end) + ;; Mark all lines except the first as continuations. + (goto-char beg) + (forward-line 1) + (while (< (point) end) + (insert " ") + (forward-line 1)) + (move-marker end nil) + t))) + +(provide 'mh-xemacs-compat) + +;;; mh-xemacs-compat.el ends here
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/mail/reply2.xpm Tue Oct 01 20:27:23 2002 +0000 @@ -0,0 +1,38 @@ +/* XPM */ +static char * mail_reply_xpm[] = { +/* columns rows colors chars-per-pixel */ +"24 24 9 1", +" c None", +". c black", +"X c #673e666663d4", +"o c #eb46ea1de471", +"O c #a852a7bea3d2", +"+ c #ae51c17b9b26", +"@ c #8d4d97577838", +"# c #7c7c8b8b6e6e", +"$ c #5e0868be52d3", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" .... ", +" .....XooO. ", +" .....XOooooooO. ", +" .XOooooooooooXOO. ", +" .oXXooooooooOXOo. ", +" .OoOXXooooooXOoo. ", +" .oooOOXOooXXXooO. ", +" ........XXOoOXOo. ", +" ..++++@.ooooooXO. ", +" ..+@@@.oooooooXO. ", +" ..+@@@#.oooooooO.. ", +" ..++@@@#$.ooooO... ", +" .++++@@#.$.oO... ", +" .+@@@#.o.... ", +" .+@#$... ", +" .#$. ", +" .$. ", +" . ", +" "};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/toolbar/execute.pbm Tue Oct 01 20:27:23 2002 +0000 @@ -0,0 +1,3 @@ +P4 +24 24 +ÿÿÿÿÿÿÿÿÿÿÿÿÿùÿÿ™ÿù™ÿù™ÿù™ÿù™ÿù™ÿù™ÿù™ÿù™ÿùŸÿùûÿÿùÿÿ™ÿùŸÿùÿÿÿÿÿÿÿÿÿÿÿÿÿÿ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/toolbar/execute.xpm Tue Oct 01 20:27:23 2002 +0000 @@ -0,0 +1,35 @@ +/* XPM */ +static char * mail_exec_xpm[] = { +/* columns rows colors chars-per-pixel */ +"24 24 6 1", +" c None", +". c black", +"X c #a5d8a5d89550", +"o c #d305d305bc3c", +"O c #ea03ea03d271", +"+ c white", +/* pixels */ +" ", +" ", +" ", +" .. ", +" XX .. ", +" oo XX .. ", +" OO oo XX .. ", +" OO oo XX .. ", +" OO oo XX .. ", +" OO oo XX .. ", +" OO oo XX .. ", +" OO oo XX .. ", +" OO oo XX .. ", +" OO oo XX ", +" OO oo ", +" OO + .. ", +" XX .. ", +" oo XX ", +" OO oo ", +" OO ", +" ", +" ", +" ", +" "};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/toolbar/page-down.xpm Tue Oct 01 20:27:23 2002 +0000 @@ -0,0 +1,34 @@ +/* XPM */ +static char * mail_page_xpm[] = { +/* columns rows colors chars-per-pixel */ +"24 24 5 1", +" c None", +". c black", +"X c #ea03ea03d271", +"o c #a5d8a5d89550", +"O c #d305d305bc3c", +/* pixels */ +" ", +" ", +" .................. ", +" .XXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XoooooooooooooXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .Xoooooooooo..oXX. ", +" .XXXXXXXXXXX..XXX. ", +" .XXXXXXXXXXX..XXX. ", +" .XooooooXXXX..XXX. ", +" .XXXXXXXXXXX..XXX. ", +" .XXXXXXXXX.O..O.X. ", +" .Xoooooooo.....XX. ", +" .XXXXXXXXXX....XX. ", +" .XXXXXXXXXXX..XXX. ", +" .XXXXXXXXXXXooXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .................. ", +" ", +" ", +" "};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/toolbar/refile.xpm Tue Oct 01 20:27:23 2002 +0000 @@ -0,0 +1,36 @@ +/* XPM */ +static char * refile_xpm[] = { +/* columns rows colors chars-per-pixel */ +"24 24 7 1", +" c None", +". c black", +"X c #a5d8a5d89550", +"o c #d305d305bc3c", +"O c #ea03ea03d271", +"+ c #828282827474", +"@ c #61b761b7600a", +/* pixels */ +" . ", +" ..X. ", +" ..XoO.... ", +" ..XooooO.+. ", +" ..XooooooOX.. .. ", +" .@@ooooooOOO@. ... ", +" .O@oooooOOOOO..@@. ", +" .OO@oooOOOOOO..@@. ", +" ...OO@XooOOOOO...@@. ", +" ..+.O@XooOOOO..@@@@@. ", +" .++..XooOOOO..@@@@@@. ", +" .++.@oooOO...@@@@@@@. ", +" ..+.XooOOO..@@@@@@@. ", +" .++.OOOO.@@@@@@@@. ", +" .+.oOO..@@@@@@@. ", +" .++.OO.@@@@@@@. ", +" .++.O.@@@@@.. ", +" ..+.O.@@@@@. ", +" .++..@@@@. ", +" ..++.@@@. ", +" .+.@@. ", +" ...@. ", +" ... ", +" . "};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/toolbar/repack.xpm Tue Oct 01 20:27:23 2002 +0000 @@ -0,0 +1,35 @@ +/* XPM */ +static char * mail_repack_xpm[] = { +/* columns rows colors chars-per-pixel */ +"24 24 6 1", +" c None", +". c black", +"X c #a5d8a5d89550", +"o c #d305d305bc3c", +"O c #ea03ea03d271", +"+ c #828282827474", +/* pixels */ +" ", +" ", +" .............. ", +" .XXXXXXXXXXXX.. ", +" .XXXXXXXXXXXX.X. ", +" .XXXXXXXXXXXX.oo. ", +" ..............ooo. ", +" .OOOOOOOOOOOO.oo. ", +" .O++++++++++O.oo. ", +" .O+XXXXXXXX+O.o. ", +" .+XXXXXXXX+.o.. ", +" .+XX...XXX+.... ", +" ....o.......oo. ", +" ....o.....Oooo. ", +" .OOO...OOOO.oooo. ", +" .++++++++++.oooo. ", +" .+XXXXXXXX+.oooo. ", +" .O+XXXXXXXX+O.ooX. ", +" .O+XXXXXXXX+O.oo.. ", +" .O++++++++++O.o.. ", +" ..OOOOOOOOOOOO... ", +" ................ ", +" ", +" "};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/toolbar/rescan.xpm Tue Oct 01 20:27:23 2002 +0000 @@ -0,0 +1,35 @@ +/* XPM */ +static char * mail_rescan_xpm[] = { +/* columns rows colors chars-per-pixel */ +"24 24 6 1", +" c None", +". c black", +"X c #a5d8a5d89550", +"o c #d305d305bc3c", +"O c #ea03ea03d271", +"+ c #828282827474", +/* pixels */ +" ", +" ", +" .............. ", +" .XXXXXXXXXXXX.. ", +" .XXXXXXXXXXXX.X. ", +" .XXXXXXXXXXXX.oo. ", +" ..............ooo. ", +" .OOOOOOOOOOOO.ooo. ", +" .O++++++++++O.ooo. ", +" .O+XXXXXXXX+O.ooo. ", +" .O+XXXXXXXX+O.ooo. ", +" .O+XXXXXXXX+O.ooo. ", +" .O+XXXXXXXX+O.ooo. ", +" .O++++++++++O.ooo. ", +" .OOOOOOOOOOOO.ooo. ", +" .O++++++++++O.ooo. ", +" .O+XXXXXXXX+O.ooo. ", +" .O+XXXXXXXX+O.ooX. ", +" .O+XXXXXXXX+O.oo.. ", +" .O++++++++++O.o.. ", +" ..OOOOOOOOOOOO... ", +" ................ ", +" ", +" "};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/toolbar/show.xpm Tue Oct 01 20:27:23 2002 +0000 @@ -0,0 +1,33 @@ +/* XPM */ +static char * mail_show_xpm[] = { +/* columns rows colors chars-per-pixel */ +"24 24 4 1", +" c None", +". c black", +"X c #ea03ea03d271", +"o c #a5d8a5d89550", +/* pixels */ +" ", +" ", +" .................. ", +" .XXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XoooooooooooooXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XoooooooooooooXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XooooooXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XoooooooooXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXX. ", +" .................. ", +" ", +" ", +" "};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/toolbar/widen.pbm Tue Oct 01 20:27:23 2002 +0000 @@ -0,0 +1,3 @@ +P4 +24 24 +ÿÿÿÿÿÿÿÿÿßÿûßÿûßÿûßÿûßÿûßÿûßÿûßÿûßÿûßÿûßÿûßÿûßÿûßÿûßÿûßÿûßÿûßÿûÿÿÿÿÿÿÿÿÿ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/toolbar/widen.xpm Tue Oct 01 20:27:23 2002 +0000 @@ -0,0 +1,32 @@ +/* XPM */ +static char * widen_xpm[] = { +/* columns rows colors chars-per-pixel */ +"24 24 3 1", +" c None", +". c #8d4d97577838", +"X c black", +/* pixels */ +" ", +" ", +" ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . XX XX . ", +" . XX XX . ", +" . XX XX . ", +" .XXXXXXXX XXXXXXXX. ", +" .XXXXXXXX XXXXXXXX. ", +" . XX XX . ", +" . XX XX . ", +" . XX XX . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" ", +" ", +" "};