mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-21 18:23:59 +00:00
The Great Cleanup
Remove circular dependencies. mh-e.el now includes few require statements and stands alone. Other files should need to require mh-e.el, which requires mh-loaddefs.el, plus variable-only files such as mh-scan.el. Remove unneeded require statements. Remove unneeded load statements, or replace them with non-fatal require statements. Break out components into their own files that were often spread between many files. As a result, many functions that are now only used within a single file no longer need to be autoloaded. Rearrange and provide consistent headings. Untabify. * mh-acros.el: Update commentary to reflect current usage. Add autoload cookies to all macros. (mh-require-cl): Merge docstring and comment. (mh-do-in-xemacs): Fix typo in docstring. (assoc-string): Move to new file mh-compat.el. (with-mh-folder-updating, mh-in-show-buffer) (mh-do-at-event-location, mh-seq-msgs): Move here from mh-utils.el. (mh-iterate-on-messages-in-region, mh-iterate-on-range): Move here from mh-seq.el. * mh-alias.el (mh-address-mail-regexp) (mh-goto-address-find-address-at-point): Move here from mh-utils.el. (mh-folder-line-matches-show-buffer-p): Move here from mh-e.el. * mh-buffers.el: Update descriptive text. * mh-comp.el (mh-note-repl, mh-note-forw, mh-note-dist): Move to new file mh-scan.el. (mh-yank-hooks, mh-to-field-choices, mh-position-on-field) (mh-letter-menu, mh-letter-mode-help-messages) (mh-letter-buttons-init-flag, mh-letter-mode) (mh-font-lock-field-data, mh-letter-header-end) (mh-auto-fill-for-letter, mh-to-field, mh-to-fcc) (mh-file-is-vcard-p, mh-insert-signature, mh-check-whom) (mh-insert-letter, mh-extract-from-attribution, mh-yank-cur-msg) (mh-filter-out-non-text, mh-insert-prefix-string) (mh-current-fill-prefix, mh-open-line, mh-complete-word) (mh-folder-expand-at-point, mh-letter-complete-function-alist) (mh-letter-complete, mh-letter-complete-or-space) (mh-letter-confirm-address, mh-letter-header-field-at-point) (mh-letter-next-header-field-or-indent) (mh-letter-next-header-field, mh-letter-previous-header-field) (mh-letter-skipped-header-field-p) (mh-letter-skip-leading-whitespace-in-header-field) (mh-hidden-header-keymap) (mh-letter-toggle-header-field-display-button) (mh-letter-toggle-header-field-display) (mh-letter-truncate-header-field, mh-letter-mode-map): Move to new file mh-letter.el. (mh-letter-mode-map, mh-sent-from-folder, mh-send-args) (mh-pgp-support-flag, mh-x-mailer-string) (mh-letter-header-field-regexp): Move to mh-e.el. (mh-goto-header-field, mh-goto-header-end) (mh-extract-from-header-value, mh-beginning-of-word): Move to mh-utils.el. (mh-insert-header-separator): Move to mh-comp.el. (mh-display-completion-list-compat): Move to new file mh-compat.el. * mh-compat.el: New file. (assoc-string): Move here from mh-acros.el. (mh-display-completion-list): Move here from mh-comp.el. * mh-customize.el: Move content into mh-e.el and remove. * mh-e.el (mh-folder-mode-map, mh-folder-seq-tool-bar-map) (mh-folder-tool-bar-map, mh-inc-spool-map, mh-letter-mode-map) (mh-letter-tool-bar-map, mh-search-mode-map, mh-show-mode-map) (mh-show-seq-tool-bar-map, mh-show-tool-bar-map): All maps now declared here so that they can be used in docstrings. (mh-sent-from-folder, mh-sent-from-msg) (mh-letter-header-field-regexp, mh-pgp-support-flag) (mh-x-mailer-string): Move here from mh-comp.el. (mh-folder-line-matches-show-buffer-p): Move to mh-alias.el. (mh-thread-scan-line-map, mh-thread-scan-line-map-stack): Move here from mh-seq.el. (mh-draft-folder, mh-inbox, mh-user-path, mh-current-folder) (mh-previous-window-config, mh-seen-list, mh-seq-list) (mh-show-buffer, mh-showing-mode, mh-globals-hash) (mh-show-folder-buffer, mh-mail-header-separator) (mh-unseen-seq, mh-previous-seq, mh-page-to-next-msg-flag) (mh-signature-separator, mh-signature-separator-regexp) (mh-list-to-string, mh-list-to-string-1): Move here from mh-utils.el. (mh-index-max-cmdline-args, mh-xargs, mh-quote-for-shell) (mh-exec-cmd, mh-exec-cmd-error, mh-exec-cmd-daemon) (mh-exec-cmd-env-daemon, mh-process-daemon, mh-exec-cmd-quiet) (mh-exec-cmd-output) (mh-exchange-point-and-mark-preserving-active-mark) (mh-exec-lib-cmd-output, mh-handle-process-error): Move here from deprecated file mh-exec.el. (mh-path): Move here from deprecated file mh-customize.el. (mh-sys-path, mh-variants, mh-variant-in-use, mh-progs, mh-lib) (mh-flists-present-flag, mh-variants, mh-variant-mh-info) (mh-variant-mu-mh-info, mh-variant-nmh-info, mh-file-command-p) (mh-variant-set-variant, mh-variant-p, mh-profile-component) (mh-profile-component-value, mh-defface-compat): Move here from deprecated file mh-init.el. (mh-goto-next-button, mh-folder-mime-action) (mh-folder-toggle-mime-part, mh-folder-inline-mime-part) (mh-folder-save-mime-part, mh-toggle-mime-buttons): Move to to mh-mime.el. (mh-scan-format-mh, mh-scan-format-nmh, mh-note-deleted) (mh-note-refiled, mh-note-cur, mh-scan-good-msg-regexp) (mh-scan-deleted-msg-regexp, mh-scan-refiled-msg-regexp) (mh-scan-valid-regexp, mh-scan-cur-msg-number-regexp) (mh-scan-date-regexp, mh-scan-rcpt-regexp, mh-scan-body-regexp) (mh-scan-subject-regexp, mh-scan-sent-to-me-sender-regexp) (mh-scan-cmd-note-width, mh-scan-destination-width) (mh-scan-date-width, mh-scan-date-flag-width) (mh-scan-from-mbox-width, mh-scan-from-mbox-sep-width) (mh-scan-field-destination-offset) (mh-scan-field-from-start-offset, mh-scan-field-from-end-offset) (mh-scan-field-subject-start-offset, mh-scan-format) (mh-msg-num-width-to-column, mh-set-cmd-note): Move to new file mh-scan.el. (mh-partial-folder-mode-line-annotation) (mh-folder-font-lock-keywords, mh-folder-font-lock-subject) (mh-generate-sequence-font-lock, mh-last-destination) (mh-last-destination-write, mh-first-msg-num, mh-last-msg-num) (mh-rmail, mh-nmail, mh-delete-msg, mh-delete-msg-no-motion) (mh-execute-commands, mh-first-msg, mh-header-display) (mh-inc-folder, mh-last-msg, mh-next-undeleted-msg) (mh-folder-from-address, mh-prompt-for-refile-folder) (mh-refile-msg, mh-refile-or-write-again, mh-quit, mh-page-msg) (mh-previous-page, mh-previous-undeleted-msg) (mh-previous-unread-msg, mh-next-button, mh-prev-button) (mh-reset-threads-and-narrowing, mh-rescan-folder) (mh-write-msg-to-file, mh-toggle-showing, mh-undo) (mh-visit-folder, mh-update-sequences, mh-delete-a-msg) (mh-refile-a-msg, mh-next-msg, mh-next-unread-msg) (mh-set-scan-mode, mh-undo-msg, mh-make-folder) (mh-folder-sequence-menu, mh-folder-message-menu) (mh-folder-folder-menu, mh-remove-xemacs-horizontal-scrollbar) (mh-write-file-functions-compat, mh-folder-mode) (mh-restore-desktop-buffer, mh-scan-folder) (mh-regenerate-headers, mh-generate-new-cmd-note) (mh-get-new-mail, mh-make-folder-mode-line, mh-goto-cur-msg) (mh-process-or-undo-commands, mh-process-commands) (mh-update-unseen, mh-delete-scan-msgs) (mh-outstanding-commands-p): Move to new file mh-folder.el. (mh-mapc, mh-colors-available-p, mh-colors-in-use-p) (mh-make-local-vars, mh-coalesce-msg-list, mh-greaterp) (mh-lessp): Move to mh-utils.el. (mh-parse-flist-output-line, mh-folder-size-folder) (mh-folder-size-flist, mh-folder-size, mh-add-sequence-notation) (mh-remove-sequence-notation, mh-remove-cur-notation) (mh-remove-all-notation, mh-delete-seq-locally) (mh-read-folder-sequences, mh-read-msg-list) (mh-notate-user-sequences, mh-internal-seqs, mh-internal-seq) (mh-valid-seq-p, mh-delete-msg-from-seq, mh-catchup) (mh-delete-a-msg-from-seq, mh-undefine-sequence) (mh-define-sequence, mh-seq-containing-msg): Move to mh-seq.el. (mh-xemacs-flag) (mh-customize, mh-e, mh-alias, mh-folder, mh-folder-selection) (mh-identity, mh-inc, mh-junk, mh-letter, mh-ranges) (mh-scan-line-formats, mh-search, mh-sending-mail, mh-sequences) (mh-show, mh-speedbar, mh-thread, mh-tool-bar, mh-hooks) (mh-faces, mh-alias-completion-ignore-case-flag) (mh-alias-expand-aliases-flag, mh-alias-flash-on-comma) (mh-alias-insert-file, mh-alias-insertion-location) (mh-alias-local-users, mh-alias-local-users-prefix) (mh-alias-passwd-gecos-comma-separator-flag) (mh-new-messages-folders, mh-ticked-messages-folders) (mh-large-folder, mh-recenter-summary-flag) (mh-recursive-folders-flag, mh-sortm-args) (mh-default-folder-for-message-function, mh-default-folder-list) (mh-default-folder-must-exist-flag, mh-default-folder-prefix) (mh-identity-list, mh-auto-fields-list) (mh-auto-fields-prompt-flag, mh-identity-default) (mh-identity-handlers, mh-inc-prog, mh-inc-spool-list) (mh-junk-choice, mh-junk-function-alist, mh-junk-choose) (mh-junk-background, mh-junk-disposition, mh-junk-program) (mh-compose-insertion, mh-compose-skipped-header-fields) (mh-compose-space-does-completion-flag) (mh-delete-yanked-msg-window-flag) (mh-extract-from-attribution-verb, mh-ins-buf-prefix) (mh-letter-complete-function, mh-letter-fill-column) (mh-mml-method-default, mh-signature-file-name) (mh-signature-separator-flag, mh-x-face-file, mh-yank-behavior) (mh-interpret-number-as-range-flag, mh-adaptive-cmd-note-flag) (mh-scan-format-file-check, mh-scan-format-file) (mh-adaptive-cmd-note-flag-check, mh-scan-prog) (mh-search-program, mh-compose-forward-as-mime-flag) (mh-compose-letter-function, mh-compose-prompt-flag) (mh-forward-subject-format, mh-insert-x-mailer-flag) (mh-redist-full-contents-flag, mh-reply-default-reply-to) (mh-reply-show-message-flag, mh-refile-preserves-sequences-flag) (mh-tick-seq, mh-update-sequences-after-mh-show-flag) (mh-bury-show-buffer-flag, mh-clean-message-header-flag) (mh-decode-mime-flag, mh-display-buttons-for-alternatives-flag) (mh-display-buttons-for-inline-parts-flag) (mh-do-not-confirm-flag, mh-fetch-x-image-url) (mh-graphical-smileys-flag, mh-graphical-emphasis-flag) (mh-highlight-citation-style) (mh-invisible-header-fields-internal) (mh-delay-invisible-header-generation-flag) (mh-invisible-header-fields, mh-invisible-header-fields-default) (mh-invisible-header-fields-compiled, mh-invisible-headers) (mh-lpr-command-format, mh-max-inline-image-height) (mh-max-inline-image-width, mh-mhl-format-file) (mh-mime-save-parts-default-directory, mh-print-background-flag) (mh-show-maximum-size, mh-show-use-goto-addr-flag) (mh-show-use-xface-flag, mh-store-default-directory) (mh-summary-height, mh-speed-update-interval) (mh-show-threads-flag, mh-tool-bar-search-function) (mh-after-commands-processed-hook, mh-alias-reloaded-hook) (mh-before-commands-processed-hook, mh-before-quit-hook) (mh-before-send-letter-hook, mh-delete-msg-hook) (mh-find-path-hook, mh-folder-mode-hook, mh-forward-hook) (mh-inc-folder-hook, mh-insert-signature-hook) (mh-kill-folder-suppress-prompt-hooks, mh-letter-mode-hook) (mh-mh-to-mime-hook, mh-search-mode-hook, mh-quit-hook) (mh-refile-msg-hook, mh-show-hook, mh-show-mode-hook) (mh-unseen-updated-hook, mh-min-colors-defined-flag) (mh-folder-address, mh-folder-body) (mh-folder-cur-msg-number, mh-folder-date, mh-folder-deleted) (mh-folder-followup, mh-folder-msg-number, mh-folder-refiled) (mh-folder-sent-to-me-hint, mh-folder-sent-to-me-sender) (mh-folder-subject, mh-folder-tick, mh-folder-to) (mh-search-folder, mh-letter-header-field, mh-show-cc) (mh-show-date, mh-show-from, mh-show-header, mh-show-pgg-bad) (mh-show-pgg-good, mh-show-pgg-unknown, mh-show-signature) (mh-show-subject, mh-show-to, mh-show-xface, mh-speedbar-folder) (mh-speedbar-folder-with-unseen-messages) (mh-speedbar-selected-folder) (mh-speedbar-selected-folder-with-unseen-messages): Move here from deprecated file mh-customize.el. * mh-exec.el: Move content into mh-e.el and remove. * mh-folder.el: New file. Contains mh-folder-mode from mh-e.el * mh-funcs.el (mh-note-copied, mh-note-printed): Move to new file mh-scan.el. (mh-ephem-message, mh-help, mh-prefix-help): Move to mh-utils.el. * mh-gnus.el (mm-uu-dissect-text-parts): Add. (mh-mail-abbrev-make-syntax-table): Move to mh-utils.el and rename to mail-abbrev-make-syntax-table. * mh-identity.el (mh-identity-menu): New variable for existing menu. (mh-identity-make-menu-no-autoload): New alias for mh-identity-make-menu which can be called from mh-e.el. (mh-identity-list-set): Move to mh-e.el. (mh-identity-add-menu): New function (mh-insert-identity): Add optional argument maybe-insert so that local variable mh-identity-local does not have to be visible. (mh-identity-handler-default): * mh-inc.el (mh-inc-spool-map): Move declaration to mh-e.el (with rest of keymaps). Update key binding for ? to call mh-help with help messages in new argument. (mh-inc-spool-make-no-autoload): New alias for mh-inc-spool-make which can be called from mh-e.el. (mh-inc-spool-list-set): Simplify update of mh-inc-spool-map-help. * mh-init.el: Move content into mh-e.el and remove. * mh-junk.el: Update requires, untabify, and add mh-autoload cookies. * mh-letter.el: New file. Contains mh-letter-mode from mh-comp.el. * mh-limit.el: New file. Contains display limit commands from mh-mime.el. * mh-mime.el: Rearrange for consistency with other files. (mh-buffer-data, mh-mm-inline-media-tests): Move here from mh-utils.el. (mh-folder-inline-mime-part, mh-folder-save-mime-part) (mh-folder-toggle-mime-part, mh-toggle-mime-buttons) (mh-goto-next-button): Move here from mh-e.el. * mh-print.el: Rearrange for consistency with other files. * mh-scan.el: New file. Contains scan line constants and utilities from XXX, mh-funcs, mh-utils.el. * mh-search.el: Rearrange for consistency with other files. (mh-search-mode-map): Drop C-c C-f {dr} bindings since these fields which don't exist in the saved header. Replace C-c C-f f with C-c C-f m per mail-mode consistency. (mh-search-mode): Use mh-set-help instead of setting mh-help-messages. * mh-seq.el (mh-thread-message, mh-thread-container) (mh-thread-id-hash, mh-thread-subject-hash, mh-thread-id-table) (mh-thread-id-index-map, mh-thread-index-id-map) (mh-thread-scan-line-map, mh-thread-scan-line-map-stack) (mh-thread-subject-container-hash, mh-thread-duplicates) (mh-thread-history, mh-thread-body-width) (mh-thread-find-msg-subject mh-thread-initialize-hash) (mh-thread-initialize, mh-thread-id-container) (mh-thread-remove-parent-link, mh-thread-add-link) (mh-thread-ancestor-p, mh-thread-get-message-container) (mh-thread-get-message, mh-thread-canonicalize-id) (mh-thread-prune-subject, mh-thread-container-subject) (mh-thread-rewind-pruning, mh-thread-prune-containers) (mh-thread-sort-containers, mh-thread-group-by-subject) (mh-thread-process-in-reply-to, mh-thread-set-tables) (mh-thread-update-id-index-maps, mh-thread-generate) (mh-thread-inc, mh-thread-generate-scan-lines) (mh-thread-parse-scan-line, mh-thread-update-scan-line-map) (mh-thread-add-spaces, mh-thread-print-scan-lines) (mh-thread-folder, mh-toggle-threads, mh-thread-forget-message) (mh-thread-current-indentation-level, mh-thread-next-sibling) (mh-thread-previous-sibling, mh-thread-immediate-ancestor) (mh-thread-ancestor, mh-thread-find-children) (mh-message-id-regexp, mh-thread-delete, mh-thread-refile): Move to new file mh-thread.el. (mh-subject-to-sequence, mh-subject-to-sequence-unthreaded) (mh-subject-to-sequence-threaded, mh-edit-pick-expr) (mh-pick-args-list, mh-narrow-to-subject, mh-narrow-to-from) (mh-narrow-to-cc, mh-narrow-to-to, mh-narrow-to-header-field) (mh-current-message-header-field, mh-narrow-to-range) (mh-delete-subject, mh-delete-subject-or-thread): Move to new file mh-limit.el. (mh-iterate-on-messages-in-region, mh-iterate-on-range): Move to mh-acros.el. (mh-internal-seqs, mh-catchup, mh-delete-msg-from-seq) (mh-internal-seq, mh-valid-seq-p, mh-seq-containing-msg) (mh-define-sequence, mh-undefine-sequence) (mh-delete-a-msg-from-seq, mh-delete-seq-locally) (mh-folder-size, mh-folder-size-flist, mh-folder-size-folder) (mh-parse-flist-output-line, mh-read-folder-sequences) (mh-read-msg-list, mh-notate-user-sequences) (mh-remove-cur-notation, mh-add-sequence-notation) (mh-remove-sequence-notation, mh-remove-all-notation): Move here from mh-e.el. (mh-make-seq, mh-seq-name, mh-find-seq, mh-seq-to-msgs) (mh-add-msgs-to-seq, mh-notate): Move here from mh-utils.el. * mh-show.el: New file. Contains mh-show-mode from mh-utils.el. * mh-speed.el: Rearrange for consistency with other files. * mh-thread.el: New file. Contains threading code from mh-seq.el. * mh-tool-bar.el: New file. Contains tool bar creation code from deprecated file mh-customize.el. * mh-utils.el (recursive-load-depth-limit): Remove setting. No longer needed. (mh-scan-msg-number-regexp, mh-scan-msg-overflow-regexp) (mh-scan-msg-format-regexp, mh-scan-msg-format-string) (mh-scan-msg-search-regexp, mh-cmd-note, mh-note-seq) (mh-update-scan-format, mh-msg-num-width): Move to new file mh-scan.el. (mh-show-buffer-mode-line-buffer-id, mh-letter-header-font-lock) (mh-header-field-font-lock, mh-header-to-font-lock) (mh-header-cc-font-lock, mh-header-subject-font-lock) (mh-show-font-lock-keywords) (mh-show-font-lock-keywords-with-cite) (mh-show-font-lock-fontify-region) (mh-gnus-article-highlight-citation, mh-showing-with-headers) (mh-start-of-uncleaned-message, mh-invalidate-show-buffer) (mh-unvisit-file, mh-defun-show-buffer, mh-show-mode-map) (mh-show-sequence-menu, mh-show-message-menu) (mh-show-folder-menu, mh-show-mode, mh-show-addr) (mh-maybe-show, mh-show, mh-show-msg, mh-show-unquote-From) (mh-msg-folder, mh-display-msg, mh-clean-msg-header): Move to new file mh-show.el. (mh-mail-header-separator, mh-signature-separator-regexp) (mh-signature-separator, mh-globals-hash, mh-user-path) (mh-draft-folder, mh-unseen-seq, mh-previous-seq, mh-inbox) (mh-previous-window-config, mh-current-folder mh-show-buffer) (mh-showing-mode, mh-show-mode-map, mh-show-folder-buffer) (mh-showing-mode, mh-seq-list, mh-seen-list, mh-summary-height) (mh-list-to-string, mh-list-to-string-1): Move to mh-e.el. (mh-buffer-data, mh-mm-inline-media-tests): Move to mh-mime.el. (mh-address-mail-regexp, mh-goto-address-find-address-at-point): Move to mh-alias.el. (mh-letter-font-lock-keywords): Move to new file mh-letter.el. (mh-folder-filename, mh-msg-count, mh-recenter, mh-msg-filename) (mh-show-mouse, mh-modify, mh-goto-msg, mh-set-folder-modified-p): Move to new file mh-folder.el. (with-mh-folder-updating, mh-in-show-buffer) (mh-do-at-event-location, mh-seq-msgs): Moved to mh-acros.el. (mh-make-seq, mh-seq-name, mh-notate, mh-find-seq) (mh-seq-to-msgs, mh-add-msgs-to-seq, mh-canonicalize-sequence): Moved to mh-seq.el. (mh-show-xface-function, mh-uncompface-executable, mh-face-to-png) (mh-uncompface, mh-icontopbm, mh-face-foreground-compat) (mh-face-background-compat, mh-face-display-function) (mh-show-xface, mh-picon-directory-list) (mh-picon-existing-directory-list) (mh-picon-cache, mh-picon-image-types) (mh-picon-set-directory-list, mh-picon-get-image) (mh-picon-file-contents, mh-picon-generate-path) (mh-x-image-cache-directory, mh-x-image-scaling-function) (mh-wget-executable, mh-wget-choice, mh-wget-option) (mh-x-image-temp-file, mh-x-image-url, mh-x-image-marker) (mh-x-image-url-cache-file, mh-x-image-scale-with-pnm) (mh-x-image-scale-with-convert) (url-unreserved-chars, url-hexify-string) (mh-x-image-url-cache-canonicalize) (mh-x-image-set-download-state, mh-x-image-get-download-state) (mh-x-image-url-fetch-image, mh-x-image-display) (mh-x-image-scale-and-display, mh-x-image-url-sane-p) (mh-x-image-url-display): Move to new file mh-xface.el. (mh-logo-display): Call mh-image-load-path. (mh-find-path-run, mh-find-path): Move here from deprecated file mh-init.el. (mh-help-messages): Now an alist of modes to an alist of messages. (mh-set-help): New function used to set mh-help-messages (mh-help): Adjust for new format of mh-help-messages. Add help-messages argument. (mh-prefix-help): Refactor to use mh-help. (mh-coalesce-msg-list, mh-greaterp, mh-lessp): Move here from mh-e.el. (mh-clear-sub-folders-cache): New function added to avoid exposing mh-sub-folders-cache variable. * mh-xface.el: New file. Contains X-Face and Face header field display routines from mh-utils.el.
This commit is contained in:
parent
a102b25292
commit
dda00b2cb5
1
lisp/mh-e/.gitignore
vendored
1
lisp/mh-e/.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
mh-autoloads.el
|
||||
mh-cus-load.el
|
||||
mh-loaddefs.el
|
||||
|
@ -1,3 +1,430 @@
|
||||
2006-01-29 Bill Wohler <wohler@newt.com>
|
||||
|
||||
The Great Cleanup
|
||||
Remove circular dependencies. mh-e.el now includes few require
|
||||
statements and stands alone. Other files should need to require
|
||||
mh-e.el, which requires mh-loaddefs.el, plus variable-only files
|
||||
such as mh-scan.el.
|
||||
Remove unneeded require statements.
|
||||
Remove unneeded load statements, or replace them with non-fatal
|
||||
require statements.
|
||||
Break out components into their own files that were often spread
|
||||
between many files.
|
||||
As a result, many functions that are now only used within a single
|
||||
file no longer need to be autoloaded.
|
||||
Rearrange and provide consistent headings.
|
||||
Untabify.
|
||||
|
||||
* mh-acros.el: Update commentary to reflect current usage. Add
|
||||
autoload cookies to all macros.
|
||||
(mh-require-cl): Merge docstring and comment.
|
||||
(mh-do-in-xemacs): Fix typo in docstring.
|
||||
(assoc-string): Move to new file mh-compat.el.
|
||||
(with-mh-folder-updating, mh-in-show-buffer)
|
||||
(mh-do-at-event-location, mh-seq-msgs): Move here from
|
||||
mh-utils.el.
|
||||
(mh-iterate-on-messages-in-region, mh-iterate-on-range): Move here
|
||||
from mh-seq.el.
|
||||
|
||||
* mh-alias.el (mh-address-mail-regexp)
|
||||
(mh-goto-address-find-address-at-point): Move here from
|
||||
mh-utils.el.
|
||||
(mh-folder-line-matches-show-buffer-p): Move here from mh-e.el.
|
||||
|
||||
* mh-buffers.el: Update descriptive text.
|
||||
|
||||
* mh-comp.el (mh-note-repl, mh-note-forw, mh-note-dist): Move to
|
||||
new file mh-scan.el.
|
||||
(mh-yank-hooks, mh-to-field-choices, mh-position-on-field)
|
||||
(mh-letter-menu, mh-letter-mode-help-messages)
|
||||
(mh-letter-buttons-init-flag, mh-letter-mode)
|
||||
(mh-font-lock-field-data, mh-letter-header-end)
|
||||
(mh-auto-fill-for-letter, mh-to-field, mh-to-fcc)
|
||||
(mh-file-is-vcard-p, mh-insert-signature, mh-check-whom)
|
||||
(mh-insert-letter, mh-extract-from-attribution, mh-yank-cur-msg)
|
||||
(mh-filter-out-non-text, mh-insert-prefix-string)
|
||||
(mh-current-fill-prefix, mh-open-line, mh-complete-word)
|
||||
(mh-folder-expand-at-point, mh-letter-complete-function-alist)
|
||||
(mh-letter-complete, mh-letter-complete-or-space)
|
||||
(mh-letter-confirm-address, mh-letter-header-field-at-point)
|
||||
(mh-letter-next-header-field-or-indent)
|
||||
(mh-letter-next-header-field, mh-letter-previous-header-field)
|
||||
(mh-letter-skipped-header-field-p)
|
||||
(mh-letter-skip-leading-whitespace-in-header-field)
|
||||
(mh-hidden-header-keymap)
|
||||
(mh-letter-toggle-header-field-display-button)
|
||||
(mh-letter-toggle-header-field-display)
|
||||
(mh-letter-truncate-header-field, mh-letter-mode-map): Move to new
|
||||
file mh-letter.el.
|
||||
(mh-letter-mode-map, mh-sent-from-folder, mh-send-args)
|
||||
(mh-pgp-support-flag, mh-x-mailer-string)
|
||||
(mh-letter-header-field-regexp): Move to mh-e.el.
|
||||
(mh-goto-header-field, mh-goto-header-end)
|
||||
(mh-extract-from-header-value, mh-beginning-of-word): Move to
|
||||
mh-utils.el.
|
||||
(mh-insert-header-separator): Move to mh-comp.el.
|
||||
(mh-display-completion-list-compat): Move to new file
|
||||
mh-compat.el.
|
||||
|
||||
* mh-compat.el: New file.
|
||||
(assoc-string): Move here from mh-acros.el.
|
||||
(mh-display-completion-list): Move here from mh-comp.el.
|
||||
|
||||
* mh-customize.el: Move content into mh-e.el and remove.
|
||||
|
||||
* mh-e.el (mh-folder-mode-map, mh-folder-seq-tool-bar-map)
|
||||
(mh-folder-tool-bar-map, mh-inc-spool-map, mh-letter-mode-map)
|
||||
(mh-letter-tool-bar-map, mh-search-mode-map, mh-show-mode-map)
|
||||
(mh-show-seq-tool-bar-map, mh-show-tool-bar-map): All maps now
|
||||
declared here so that they can be used in docstrings.
|
||||
(mh-sent-from-folder, mh-sent-from-msg)
|
||||
(mh-letter-header-field-regexp, mh-pgp-support-flag)
|
||||
(mh-x-mailer-string): Move here from mh-comp.el.
|
||||
(mh-folder-line-matches-show-buffer-p): Move to mh-alias.el.
|
||||
(mh-thread-scan-line-map, mh-thread-scan-line-map-stack): Move
|
||||
here from mh-seq.el.
|
||||
(mh-draft-folder, mh-inbox, mh-user-path, mh-current-folder)
|
||||
(mh-previous-window-config, mh-seen-list, mh-seq-list)
|
||||
(mh-show-buffer, mh-showing-mode, mh-globals-hash)
|
||||
(mh-show-folder-buffer, mh-mail-header-separator)
|
||||
(mh-unseen-seq, mh-previous-seq, mh-page-to-next-msg-flag)
|
||||
(mh-signature-separator, mh-signature-separator-regexp)
|
||||
(mh-list-to-string, mh-list-to-string-1): Move here from
|
||||
mh-utils.el.
|
||||
(mh-index-max-cmdline-args, mh-xargs, mh-quote-for-shell)
|
||||
(mh-exec-cmd, mh-exec-cmd-error, mh-exec-cmd-daemon)
|
||||
(mh-exec-cmd-env-daemon, mh-process-daemon, mh-exec-cmd-quiet)
|
||||
(mh-exec-cmd-output)
|
||||
(mh-exchange-point-and-mark-preserving-active-mark)
|
||||
(mh-exec-lib-cmd-output, mh-handle-process-error): Move here from
|
||||
deprecated file mh-exec.el.
|
||||
(mh-path): Move here from deprecated file mh-customize.el.
|
||||
(mh-sys-path, mh-variants, mh-variant-in-use, mh-progs, mh-lib)
|
||||
(mh-flists-present-flag, mh-variants, mh-variant-mh-info)
|
||||
(mh-variant-mu-mh-info, mh-variant-nmh-info, mh-file-command-p)
|
||||
(mh-variant-set-variant, mh-variant-p, mh-profile-component)
|
||||
(mh-profile-component-value, mh-defface-compat): Move here from
|
||||
deprecated file mh-init.el.
|
||||
(mh-goto-next-button, mh-folder-mime-action)
|
||||
(mh-folder-toggle-mime-part, mh-folder-inline-mime-part)
|
||||
(mh-folder-save-mime-part, mh-toggle-mime-buttons): Move to to
|
||||
mh-mime.el.
|
||||
(mh-scan-format-mh, mh-scan-format-nmh, mh-note-deleted)
|
||||
(mh-note-refiled, mh-note-cur, mh-scan-good-msg-regexp)
|
||||
(mh-scan-deleted-msg-regexp, mh-scan-refiled-msg-regexp)
|
||||
(mh-scan-valid-regexp, mh-scan-cur-msg-number-regexp)
|
||||
(mh-scan-date-regexp, mh-scan-rcpt-regexp, mh-scan-body-regexp)
|
||||
(mh-scan-subject-regexp, mh-scan-sent-to-me-sender-regexp)
|
||||
(mh-scan-cmd-note-width, mh-scan-destination-width)
|
||||
(mh-scan-date-width, mh-scan-date-flag-width)
|
||||
(mh-scan-from-mbox-width, mh-scan-from-mbox-sep-width)
|
||||
(mh-scan-field-destination-offset)
|
||||
(mh-scan-field-from-start-offset, mh-scan-field-from-end-offset)
|
||||
(mh-scan-field-subject-start-offset, mh-scan-format)
|
||||
(mh-msg-num-width-to-column, mh-set-cmd-note): Move to new file
|
||||
mh-scan.el.
|
||||
(mh-partial-folder-mode-line-annotation)
|
||||
(mh-folder-font-lock-keywords, mh-folder-font-lock-subject)
|
||||
(mh-generate-sequence-font-lock, mh-last-destination)
|
||||
(mh-last-destination-write, mh-first-msg-num, mh-last-msg-num)
|
||||
(mh-rmail, mh-nmail, mh-delete-msg, mh-delete-msg-no-motion)
|
||||
(mh-execute-commands, mh-first-msg, mh-header-display)
|
||||
(mh-inc-folder, mh-last-msg, mh-next-undeleted-msg)
|
||||
(mh-folder-from-address, mh-prompt-for-refile-folder)
|
||||
(mh-refile-msg, mh-refile-or-write-again, mh-quit, mh-page-msg)
|
||||
(mh-previous-page, mh-previous-undeleted-msg)
|
||||
(mh-previous-unread-msg, mh-next-button, mh-prev-button)
|
||||
(mh-reset-threads-and-narrowing, mh-rescan-folder)
|
||||
(mh-write-msg-to-file, mh-toggle-showing, mh-undo)
|
||||
(mh-visit-folder, mh-update-sequences, mh-delete-a-msg)
|
||||
(mh-refile-a-msg, mh-next-msg, mh-next-unread-msg)
|
||||
(mh-set-scan-mode, mh-undo-msg, mh-make-folder)
|
||||
(mh-folder-sequence-menu, mh-folder-message-menu)
|
||||
(mh-folder-folder-menu, mh-remove-xemacs-horizontal-scrollbar)
|
||||
(mh-write-file-functions-compat, mh-folder-mode)
|
||||
(mh-restore-desktop-buffer, mh-scan-folder)
|
||||
(mh-regenerate-headers, mh-generate-new-cmd-note)
|
||||
(mh-get-new-mail, mh-make-folder-mode-line, mh-goto-cur-msg)
|
||||
(mh-process-or-undo-commands, mh-process-commands)
|
||||
(mh-update-unseen, mh-delete-scan-msgs)
|
||||
(mh-outstanding-commands-p): Move to new file mh-folder.el.
|
||||
(mh-mapc, mh-colors-available-p, mh-colors-in-use-p)
|
||||
(mh-make-local-vars, mh-coalesce-msg-list, mh-greaterp)
|
||||
(mh-lessp): Move to mh-utils.el.
|
||||
(mh-parse-flist-output-line, mh-folder-size-folder)
|
||||
(mh-folder-size-flist, mh-folder-size, mh-add-sequence-notation)
|
||||
(mh-remove-sequence-notation, mh-remove-cur-notation)
|
||||
(mh-remove-all-notation, mh-delete-seq-locally)
|
||||
(mh-read-folder-sequences, mh-read-msg-list)
|
||||
(mh-notate-user-sequences, mh-internal-seqs, mh-internal-seq)
|
||||
(mh-valid-seq-p, mh-delete-msg-from-seq, mh-catchup)
|
||||
(mh-delete-a-msg-from-seq, mh-undefine-sequence)
|
||||
(mh-define-sequence, mh-seq-containing-msg): Move to mh-seq.el.
|
||||
(mh-xemacs-flag)
|
||||
(mh-customize, mh-e, mh-alias, mh-folder, mh-folder-selection)
|
||||
(mh-identity, mh-inc, mh-junk, mh-letter, mh-ranges)
|
||||
(mh-scan-line-formats, mh-search, mh-sending-mail, mh-sequences)
|
||||
(mh-show, mh-speedbar, mh-thread, mh-tool-bar, mh-hooks)
|
||||
(mh-faces, mh-alias-completion-ignore-case-flag)
|
||||
(mh-alias-expand-aliases-flag, mh-alias-flash-on-comma)
|
||||
(mh-alias-insert-file, mh-alias-insertion-location)
|
||||
(mh-alias-local-users, mh-alias-local-users-prefix)
|
||||
(mh-alias-passwd-gecos-comma-separator-flag)
|
||||
(mh-new-messages-folders, mh-ticked-messages-folders)
|
||||
(mh-large-folder, mh-recenter-summary-flag)
|
||||
(mh-recursive-folders-flag, mh-sortm-args)
|
||||
(mh-default-folder-for-message-function, mh-default-folder-list)
|
||||
(mh-default-folder-must-exist-flag, mh-default-folder-prefix)
|
||||
(mh-identity-list, mh-auto-fields-list)
|
||||
(mh-auto-fields-prompt-flag, mh-identity-default)
|
||||
(mh-identity-handlers, mh-inc-prog, mh-inc-spool-list)
|
||||
(mh-junk-choice, mh-junk-function-alist, mh-junk-choose)
|
||||
(mh-junk-background, mh-junk-disposition, mh-junk-program)
|
||||
(mh-compose-insertion, mh-compose-skipped-header-fields)
|
||||
(mh-compose-space-does-completion-flag)
|
||||
(mh-delete-yanked-msg-window-flag)
|
||||
(mh-extract-from-attribution-verb, mh-ins-buf-prefix)
|
||||
(mh-letter-complete-function, mh-letter-fill-column)
|
||||
(mh-mml-method-default, mh-signature-file-name)
|
||||
(mh-signature-separator-flag, mh-x-face-file, mh-yank-behavior)
|
||||
(mh-interpret-number-as-range-flag, mh-adaptive-cmd-note-flag)
|
||||
(mh-scan-format-file-check, mh-scan-format-file)
|
||||
(mh-adaptive-cmd-note-flag-check, mh-scan-prog)
|
||||
(mh-search-program, mh-compose-forward-as-mime-flag)
|
||||
(mh-compose-letter-function, mh-compose-prompt-flag)
|
||||
(mh-forward-subject-format, mh-insert-x-mailer-flag)
|
||||
(mh-redist-full-contents-flag, mh-reply-default-reply-to)
|
||||
(mh-reply-show-message-flag, mh-refile-preserves-sequences-flag)
|
||||
(mh-tick-seq, mh-update-sequences-after-mh-show-flag)
|
||||
(mh-bury-show-buffer-flag, mh-clean-message-header-flag)
|
||||
(mh-decode-mime-flag, mh-display-buttons-for-alternatives-flag)
|
||||
(mh-display-buttons-for-inline-parts-flag)
|
||||
(mh-do-not-confirm-flag, mh-fetch-x-image-url)
|
||||
(mh-graphical-smileys-flag, mh-graphical-emphasis-flag)
|
||||
(mh-highlight-citation-style)
|
||||
(mh-invisible-header-fields-internal)
|
||||
(mh-delay-invisible-header-generation-flag)
|
||||
(mh-invisible-header-fields, mh-invisible-header-fields-default)
|
||||
(mh-invisible-header-fields-compiled, mh-invisible-headers)
|
||||
(mh-lpr-command-format, mh-max-inline-image-height)
|
||||
(mh-max-inline-image-width, mh-mhl-format-file)
|
||||
(mh-mime-save-parts-default-directory, mh-print-background-flag)
|
||||
(mh-show-maximum-size, mh-show-use-goto-addr-flag)
|
||||
(mh-show-use-xface-flag, mh-store-default-directory)
|
||||
(mh-summary-height, mh-speed-update-interval)
|
||||
(mh-show-threads-flag, mh-tool-bar-search-function)
|
||||
(mh-after-commands-processed-hook, mh-alias-reloaded-hook)
|
||||
(mh-before-commands-processed-hook, mh-before-quit-hook)
|
||||
(mh-before-send-letter-hook, mh-delete-msg-hook)
|
||||
(mh-find-path-hook, mh-folder-mode-hook, mh-forward-hook)
|
||||
(mh-inc-folder-hook, mh-insert-signature-hook)
|
||||
(mh-kill-folder-suppress-prompt-hooks, mh-letter-mode-hook)
|
||||
(mh-mh-to-mime-hook, mh-search-mode-hook, mh-quit-hook)
|
||||
(mh-refile-msg-hook, mh-show-hook, mh-show-mode-hook)
|
||||
(mh-unseen-updated-hook, mh-min-colors-defined-flag)
|
||||
(mh-folder-address, mh-folder-body)
|
||||
(mh-folder-cur-msg-number, mh-folder-date, mh-folder-deleted)
|
||||
(mh-folder-followup, mh-folder-msg-number, mh-folder-refiled)
|
||||
(mh-folder-sent-to-me-hint, mh-folder-sent-to-me-sender)
|
||||
(mh-folder-subject, mh-folder-tick, mh-folder-to)
|
||||
(mh-search-folder, mh-letter-header-field, mh-show-cc)
|
||||
(mh-show-date, mh-show-from, mh-show-header, mh-show-pgg-bad)
|
||||
(mh-show-pgg-good, mh-show-pgg-unknown, mh-show-signature)
|
||||
(mh-show-subject, mh-show-to, mh-show-xface, mh-speedbar-folder)
|
||||
(mh-speedbar-folder-with-unseen-messages)
|
||||
(mh-speedbar-selected-folder)
|
||||
(mh-speedbar-selected-folder-with-unseen-messages): Move here from
|
||||
deprecated file mh-customize.el.
|
||||
|
||||
* mh-exec.el: Move content into mh-e.el and remove.
|
||||
|
||||
* mh-folder.el: New file. Contains mh-folder-mode from mh-e.el
|
||||
|
||||
* mh-funcs.el (mh-note-copied, mh-note-printed): Move to new file
|
||||
mh-scan.el.
|
||||
(mh-ephem-message, mh-help, mh-prefix-help): Move to mh-utils.el.
|
||||
|
||||
* mh-gnus.el (mm-uu-dissect-text-parts): Add.
|
||||
(mh-mail-abbrev-make-syntax-table): Move to mh-utils.el and rename
|
||||
to mail-abbrev-make-syntax-table.
|
||||
|
||||
* mh-identity.el (mh-identity-menu): New variable for existing
|
||||
menu.
|
||||
(mh-identity-make-menu-no-autoload): New alias for
|
||||
mh-identity-make-menu which can be called from mh-e.el.
|
||||
(mh-identity-list-set): Move to mh-e.el.
|
||||
(mh-identity-add-menu): New function
|
||||
(mh-insert-identity): Add optional argument maybe-insert so that
|
||||
local variable mh-identity-local does not have to be visible.
|
||||
(mh-identity-handler-default):
|
||||
|
||||
* mh-inc.el (mh-inc-spool-map): Move declaration to mh-e.el (with
|
||||
rest of keymaps). Update key binding for ? to call mh-help with
|
||||
help messages in new argument.
|
||||
(mh-inc-spool-make-no-autoload): New alias for mh-inc-spool-make
|
||||
which can be called from mh-e.el.
|
||||
(mh-inc-spool-list-set): Simplify update of mh-inc-spool-map-help.
|
||||
|
||||
* mh-init.el: Move content into mh-e.el and remove.
|
||||
|
||||
* mh-junk.el: Update requires, untabify, and add mh-autoload
|
||||
cookies.
|
||||
|
||||
* mh-letter.el: New file. Contains mh-letter-mode from mh-comp.el.
|
||||
|
||||
* mh-limit.el: New file. Contains display limit commands from
|
||||
mh-mime.el.
|
||||
|
||||
* mh-mime.el: Rearrange for consistency with other files.
|
||||
(mh-buffer-data, mh-mm-inline-media-tests): Move here from
|
||||
mh-utils.el.
|
||||
(mh-folder-inline-mime-part, mh-folder-save-mime-part)
|
||||
(mh-folder-toggle-mime-part, mh-toggle-mime-buttons)
|
||||
(mh-goto-next-button): Move here from mh-e.el.
|
||||
|
||||
* mh-print.el: Rearrange for consistency with other files.
|
||||
|
||||
* mh-scan.el: New file. Contains scan line constants and utilities
|
||||
from XXX, mh-funcs, mh-utils.el.
|
||||
|
||||
* mh-search.el: Rearrange for consistency with other files.
|
||||
(mh-search-mode-map): Drop C-c C-f {dr} bindings since these
|
||||
fields which don't exist in the saved header. Replace C-c C-f f
|
||||
with C-c C-f m per mail-mode consistency.
|
||||
(mh-search-mode): Use mh-set-help instead of setting
|
||||
mh-help-messages.
|
||||
|
||||
* mh-seq.el (mh-thread-message, mh-thread-container)
|
||||
(mh-thread-id-hash, mh-thread-subject-hash, mh-thread-id-table)
|
||||
(mh-thread-id-index-map, mh-thread-index-id-map)
|
||||
(mh-thread-scan-line-map, mh-thread-scan-line-map-stack)
|
||||
(mh-thread-subject-container-hash, mh-thread-duplicates)
|
||||
(mh-thread-history, mh-thread-body-width)
|
||||
(mh-thread-find-msg-subject mh-thread-initialize-hash)
|
||||
(mh-thread-initialize, mh-thread-id-container)
|
||||
(mh-thread-remove-parent-link, mh-thread-add-link)
|
||||
(mh-thread-ancestor-p, mh-thread-get-message-container)
|
||||
(mh-thread-get-message, mh-thread-canonicalize-id)
|
||||
(mh-thread-prune-subject, mh-thread-container-subject)
|
||||
(mh-thread-rewind-pruning, mh-thread-prune-containers)
|
||||
(mh-thread-sort-containers, mh-thread-group-by-subject)
|
||||
(mh-thread-process-in-reply-to, mh-thread-set-tables)
|
||||
(mh-thread-update-id-index-maps, mh-thread-generate)
|
||||
(mh-thread-inc, mh-thread-generate-scan-lines)
|
||||
(mh-thread-parse-scan-line, mh-thread-update-scan-line-map)
|
||||
(mh-thread-add-spaces, mh-thread-print-scan-lines)
|
||||
(mh-thread-folder, mh-toggle-threads, mh-thread-forget-message)
|
||||
(mh-thread-current-indentation-level, mh-thread-next-sibling)
|
||||
(mh-thread-previous-sibling, mh-thread-immediate-ancestor)
|
||||
(mh-thread-ancestor, mh-thread-find-children)
|
||||
(mh-message-id-regexp, mh-thread-delete, mh-thread-refile): Move
|
||||
to new file mh-thread.el.
|
||||
(mh-subject-to-sequence, mh-subject-to-sequence-unthreaded)
|
||||
(mh-subject-to-sequence-threaded, mh-edit-pick-expr)
|
||||
(mh-pick-args-list, mh-narrow-to-subject, mh-narrow-to-from)
|
||||
(mh-narrow-to-cc, mh-narrow-to-to, mh-narrow-to-header-field)
|
||||
(mh-current-message-header-field, mh-narrow-to-range)
|
||||
(mh-delete-subject, mh-delete-subject-or-thread): Move to new file
|
||||
mh-limit.el.
|
||||
(mh-iterate-on-messages-in-region, mh-iterate-on-range): Move to
|
||||
mh-acros.el.
|
||||
(mh-internal-seqs, mh-catchup, mh-delete-msg-from-seq)
|
||||
(mh-internal-seq, mh-valid-seq-p, mh-seq-containing-msg)
|
||||
(mh-define-sequence, mh-undefine-sequence)
|
||||
(mh-delete-a-msg-from-seq, mh-delete-seq-locally)
|
||||
(mh-folder-size, mh-folder-size-flist, mh-folder-size-folder)
|
||||
(mh-parse-flist-output-line, mh-read-folder-sequences)
|
||||
(mh-read-msg-list, mh-notate-user-sequences)
|
||||
(mh-remove-cur-notation, mh-add-sequence-notation)
|
||||
(mh-remove-sequence-notation, mh-remove-all-notation): Move here
|
||||
from mh-e.el.
|
||||
(mh-make-seq, mh-seq-name, mh-find-seq, mh-seq-to-msgs)
|
||||
(mh-add-msgs-to-seq, mh-notate): Move here from mh-utils.el.
|
||||
|
||||
* mh-show.el: New file. Contains mh-show-mode from mh-utils.el.
|
||||
|
||||
* mh-speed.el: Rearrange for consistency with other files.
|
||||
|
||||
* mh-thread.el: New file. Contains threading code from mh-seq.el.
|
||||
|
||||
* mh-tool-bar.el: New file. Contains tool bar creation code from
|
||||
deprecated file mh-customize.el.
|
||||
|
||||
* mh-utils.el (recursive-load-depth-limit): Remove setting. No
|
||||
longer needed.
|
||||
(mh-scan-msg-number-regexp, mh-scan-msg-overflow-regexp)
|
||||
(mh-scan-msg-format-regexp, mh-scan-msg-format-string)
|
||||
(mh-scan-msg-search-regexp, mh-cmd-note, mh-note-seq)
|
||||
(mh-update-scan-format, mh-msg-num-width): Move to new file
|
||||
mh-scan.el.
|
||||
(mh-show-buffer-mode-line-buffer-id, mh-letter-header-font-lock)
|
||||
(mh-header-field-font-lock, mh-header-to-font-lock)
|
||||
(mh-header-cc-font-lock, mh-header-subject-font-lock)
|
||||
(mh-show-font-lock-keywords)
|
||||
(mh-show-font-lock-keywords-with-cite)
|
||||
(mh-show-font-lock-fontify-region)
|
||||
(mh-gnus-article-highlight-citation, mh-showing-with-headers)
|
||||
(mh-start-of-uncleaned-message, mh-invalidate-show-buffer)
|
||||
(mh-unvisit-file, mh-defun-show-buffer, mh-show-mode-map)
|
||||
(mh-show-sequence-menu, mh-show-message-menu)
|
||||
(mh-show-folder-menu, mh-show-mode, mh-show-addr)
|
||||
(mh-maybe-show, mh-show, mh-show-msg, mh-show-unquote-From)
|
||||
(mh-msg-folder, mh-display-msg, mh-clean-msg-header): Move to new
|
||||
file mh-show.el.
|
||||
(mh-mail-header-separator, mh-signature-separator-regexp)
|
||||
(mh-signature-separator, mh-globals-hash, mh-user-path)
|
||||
(mh-draft-folder, mh-unseen-seq, mh-previous-seq, mh-inbox)
|
||||
(mh-previous-window-config, mh-current-folder mh-show-buffer)
|
||||
(mh-showing-mode, mh-show-mode-map, mh-show-folder-buffer)
|
||||
(mh-showing-mode, mh-seq-list, mh-seen-list, mh-summary-height)
|
||||
(mh-list-to-string, mh-list-to-string-1): Move to mh-e.el.
|
||||
(mh-buffer-data, mh-mm-inline-media-tests): Move to mh-mime.el.
|
||||
(mh-address-mail-regexp, mh-goto-address-find-address-at-point):
|
||||
Move to mh-alias.el.
|
||||
(mh-letter-font-lock-keywords): Move to new file mh-letter.el.
|
||||
(mh-folder-filename, mh-msg-count, mh-recenter, mh-msg-filename)
|
||||
(mh-show-mouse, mh-modify, mh-goto-msg, mh-set-folder-modified-p):
|
||||
Move to new file mh-folder.el.
|
||||
(with-mh-folder-updating, mh-in-show-buffer)
|
||||
(mh-do-at-event-location, mh-seq-msgs): Moved to mh-acros.el.
|
||||
(mh-make-seq, mh-seq-name, mh-notate, mh-find-seq)
|
||||
(mh-seq-to-msgs, mh-add-msgs-to-seq, mh-canonicalize-sequence):
|
||||
Moved to mh-seq.el.
|
||||
(mh-show-xface-function, mh-uncompface-executable, mh-face-to-png)
|
||||
(mh-uncompface, mh-icontopbm, mh-face-foreground-compat)
|
||||
(mh-face-background-compat, mh-face-display-function)
|
||||
(mh-show-xface, mh-picon-directory-list)
|
||||
(mh-picon-existing-directory-list)
|
||||
(mh-picon-cache, mh-picon-image-types)
|
||||
(mh-picon-set-directory-list, mh-picon-get-image)
|
||||
(mh-picon-file-contents, mh-picon-generate-path)
|
||||
(mh-x-image-cache-directory, mh-x-image-scaling-function)
|
||||
(mh-wget-executable, mh-wget-choice, mh-wget-option)
|
||||
(mh-x-image-temp-file, mh-x-image-url, mh-x-image-marker)
|
||||
(mh-x-image-url-cache-file, mh-x-image-scale-with-pnm)
|
||||
(mh-x-image-scale-with-convert)
|
||||
(url-unreserved-chars, url-hexify-string)
|
||||
(mh-x-image-url-cache-canonicalize)
|
||||
(mh-x-image-set-download-state, mh-x-image-get-download-state)
|
||||
(mh-x-image-url-fetch-image, mh-x-image-display)
|
||||
(mh-x-image-scale-and-display, mh-x-image-url-sane-p)
|
||||
(mh-x-image-url-display): Move to new file mh-xface.el.
|
||||
(mh-logo-display): Call mh-image-load-path.
|
||||
(mh-find-path-run, mh-find-path): Move here from deprecated file
|
||||
mh-init.el.
|
||||
(mh-help-messages): Now an alist of modes to an alist of messages.
|
||||
(mh-set-help): New function used to set mh-help-messages
|
||||
(mh-help): Adjust for new format of mh-help-messages. Add
|
||||
help-messages argument.
|
||||
(mh-prefix-help): Refactor to use mh-help.
|
||||
(mh-coalesce-msg-list, mh-greaterp, mh-lessp): Move here from
|
||||
mh-e.el.
|
||||
(mh-clear-sub-folders-cache): New function added to avoid exposing
|
||||
mh-sub-folders-cache variable.
|
||||
|
||||
* mh-xface.el: New file. Contains X-Face and Face header field
|
||||
display routines from mh-utils.el.
|
||||
|
||||
2006-01-17 Bill Wohler <wohler@newt.com>
|
||||
|
||||
* mh-acros.el (assoc-string): Fix typo in argument.
|
||||
|
@ -1,4 +1,4 @@
|
||||
;;; mh-acros.el --- Macros used in MH-E
|
||||
;;; mh-acros.el --- macros used in MH-E
|
||||
|
||||
;; Copyright (C) 2004, 2006 Free Software Foundation, Inc.
|
||||
|
||||
@ -26,54 +26,62 @@
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file contains most, if not all, macros. It is so named with a
|
||||
;; silent "m" so that it is compiled first. Otherwise, "make
|
||||
;; recompile" in CVS Emacs may use compiled files with stale macro
|
||||
;; definitions.
|
||||
;; This file contains all macros that are used in more than one file.
|
||||
;; If you run "make recompile" in CVS Emacs and see the message
|
||||
;; "Source is newer than compiled," it is a sign that macro probably
|
||||
;; needs to be moved here.
|
||||
|
||||
;; This file must always be included like this:
|
||||
;;
|
||||
;; (eval-when-compile (require 'mh-acros))
|
||||
;; Historically, it was so named with a silent "m" so that it would be
|
||||
;; compiled first. Otherwise, "make recompile" in CVS Emacs would use
|
||||
;; compiled files with stale macro definitions. Later, no-byte-compile
|
||||
;; was added to the Local Variables section to avoid this problem and
|
||||
;; because it's pointless to compile a file full of macros. But we
|
||||
;; kept the name.
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cl)
|
||||
(require 'advice)
|
||||
|
||||
;; The Emacs coding conventions require that the cl package not be required at
|
||||
;; runtime. However, the cl package in versions of Emacs prior to 21.4 left cl
|
||||
;; routines in their macro expansions. Use mh-require-cl to provide the cl
|
||||
;; routines in the best way possible.
|
||||
|
||||
|
||||
;;; Compatibility
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-require-cl ()
|
||||
"Macro to load \"cl\" if needed.
|
||||
Some versions of \"cl\" produce code for the expansion of
|
||||
\(setf (gethash ...) ...) that uses functions in \"cl\" at run
|
||||
time. This macro recognizes that and loads \"cl\" where
|
||||
appropriate."
|
||||
|
||||
Emacs coding conventions require that the \"cl\" package not be
|
||||
required at runtime. However, the \"cl\" package in Emacs 21.4
|
||||
and earlier left \"cl\" routines in their macro expansions. In
|
||||
particular, the expansion of (setf (gethash ...) ...) used
|
||||
functions in \"cl\" at run time. This macro recognizes that and
|
||||
loads \"cl\" appropriately."
|
||||
(if (eq (car (macroexpand '(setf (gethash foo bar) baz))) 'cl-puthash)
|
||||
`(require 'cl)
|
||||
`(eval-when-compile (require 'cl))))
|
||||
|
||||
;; Macros to generate correct code for different emacs variants
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-do-in-gnu-emacs (&rest body)
|
||||
"Execute BODY if in GNU Emacs."
|
||||
(unless (featurep 'xemacs) `(progn ,@body)))
|
||||
(put 'mh-do-in-gnu-emacs 'lisp-indent-hook 'defun)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-do-in-xemacs (&rest body)
|
||||
"Execute BODY if in GNU Emacs."
|
||||
"Execute BODY if in XEmacs."
|
||||
(when (featurep 'xemacs) `(progn ,@body)))
|
||||
(put 'mh-do-in-xemacs 'lisp-indent-hook 'defun)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-funcall-if-exists (function &rest args)
|
||||
"Call FUNCTION with ARGS as parameters if it exists."
|
||||
(when (fboundp function)
|
||||
`(when (fboundp ',function)
|
||||
(funcall ',function ,@args))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-defun-compat (function arg-list &rest body)
|
||||
"This is a macro to define functions which are not defined.
|
||||
It is used for functions which were added to Emacs recently.
|
||||
@ -84,6 +92,7 @@ list, ARG-LIST and body, BODY."
|
||||
`(defun ,function ,arg-list ,@body))))
|
||||
(put 'mh-defun-compat 'lisp-indent-function 'defun)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-defmacro-compat (function arg-list &rest body)
|
||||
"This is a macro to define functions which are not defined.
|
||||
It is used for macros which were added to Emacs recently.
|
||||
@ -94,6 +103,11 @@ list, ARG-LIST and body, BODY."
|
||||
`(defmacro ,function ,arg-list ,@body))))
|
||||
(put 'mh-defmacro-compat 'lisp-indent-function 'defun)
|
||||
|
||||
|
||||
|
||||
;;; Miscellaneous
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-make-local-hook (hook)
|
||||
"Make HOOK local if needed.
|
||||
XEmacs and versions of GNU Emacs before 21.1 require
|
||||
@ -102,6 +116,7 @@ XEmacs and versions of GNU Emacs before 21.1 require
|
||||
(not (get 'make-local-hook 'byte-obsolete-info)))
|
||||
`(make-local-hook ,hook)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-mark-active-p (check-transient-mark-mode-flag)
|
||||
"A macro that expands into appropriate code in XEmacs and nil in GNU Emacs.
|
||||
In GNU Emacs if CHECK-TRANSIENT-MARK-MODE-FLAG is non-nil then
|
||||
@ -114,6 +129,10 @@ check if variable `transient-mark-mode' is active."
|
||||
`(and (boundp 'transient-mark-mode) transient-mark-mode
|
||||
(boundp 'mark-active) mark-active))))
|
||||
|
||||
;; Shush compiler.
|
||||
(eval-when-compile (mh-do-in-xemacs (defvar struct) (defvar x) (defvar y)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-defstruct (name-spec &rest fields)
|
||||
"Replacement for `defstruct' from the \"cl\" package.
|
||||
The `defstruct' in the \"cl\" library produces compiler warnings,
|
||||
@ -150,15 +169,145 @@ more details."
|
||||
(list 'nth ,x z)))
|
||||
(quote ,struct-name))))
|
||||
|
||||
(unless (fboundp 'assoc-string)
|
||||
(defsubst assoc-string (key list case-fold)
|
||||
"Like `assoc' but specifically for strings.
|
||||
Case is ignored if CASE-FOLD is non-nil.
|
||||
This function added by MH-E for Emacs versions that lack
|
||||
`assoc-string', introduced in Emacs 22."
|
||||
(if case-fold
|
||||
(assoc-ignore-case key list)
|
||||
(assoc key list))))
|
||||
;;;###mh-autoload
|
||||
(defmacro with-mh-folder-updating (save-modification-flag &rest body)
|
||||
"Format is (with-mh-folder-updating (SAVE-MODIFICATION-FLAG) &body BODY).
|
||||
Execute BODY, which can modify the folder buffer without having to
|
||||
worry about file locking or the read-only flag, and return its result.
|
||||
If SAVE-MODIFICATION-FLAG is non-nil, the buffer's modification flag
|
||||
is unchanged, otherwise it is cleared."
|
||||
(setq save-modification-flag (car save-modification-flag)) ; CL style
|
||||
`(prog1
|
||||
(let ((mh-folder-updating-mod-flag (buffer-modified-p))
|
||||
(buffer-read-only nil)
|
||||
(buffer-file-name nil)) ;don't let the buffer get locked
|
||||
(prog1
|
||||
(progn
|
||||
,@body)
|
||||
(mh-set-folder-modified-p mh-folder-updating-mod-flag)))
|
||||
,@(if (not save-modification-flag)
|
||||
'((mh-set-folder-modified-p nil)))))
|
||||
(put 'with-mh-folder-updating 'lisp-indent-hook 'defun)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-in-show-buffer (show-buffer &rest body)
|
||||
"Format is (mh-in-show-buffer (SHOW-BUFFER) &body BODY).
|
||||
Display buffer SHOW-BUFFER in other window and execute BODY in it.
|
||||
Stronger than `save-excursion', weaker than `save-window-excursion'."
|
||||
(setq show-buffer (car show-buffer)) ; CL style
|
||||
`(let ((mh-in-show-buffer-saved-window (selected-window)))
|
||||
(switch-to-buffer-other-window ,show-buffer)
|
||||
(if mh-bury-show-buffer-flag (bury-buffer (current-buffer)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
,@body)
|
||||
(select-window mh-in-show-buffer-saved-window))))
|
||||
(put 'mh-in-show-buffer 'lisp-indent-hook 'defun)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-do-at-event-location (event &rest body)
|
||||
"Switch to the location of EVENT and execute BODY.
|
||||
After BODY has been executed return to original window. The
|
||||
modification flag of the buffer in the event window is
|
||||
preserved."
|
||||
(let ((event-window (make-symbol "event-window"))
|
||||
(event-position (make-symbol "event-position"))
|
||||
(original-window (make-symbol "original-window"))
|
||||
(original-position (make-symbol "original-position"))
|
||||
(modified-flag (make-symbol "modified-flag")))
|
||||
`(save-excursion
|
||||
(let* ((,event-window
|
||||
(or (mh-funcall-if-exists posn-window (event-start ,event))
|
||||
(mh-funcall-if-exists event-window ,event)))
|
||||
(,event-position
|
||||
(or (mh-funcall-if-exists posn-point (event-start ,event))
|
||||
(mh-funcall-if-exists event-closest-point ,event)))
|
||||
(,original-window (selected-window))
|
||||
(,original-position (progn
|
||||
(set-buffer (window-buffer ,event-window))
|
||||
(set-marker (make-marker) (point))))
|
||||
(,modified-flag (buffer-modified-p))
|
||||
(buffer-read-only nil))
|
||||
(unwind-protect (progn
|
||||
(select-window ,event-window)
|
||||
(goto-char ,event-position)
|
||||
,@body)
|
||||
(set-buffer-modified-p ,modified-flag)
|
||||
(goto-char ,original-position)
|
||||
(set-marker ,original-position nil)
|
||||
(select-window ,original-window))))))
|
||||
(put 'mh-do-at-event-location 'lisp-indent-hook 'defun)
|
||||
|
||||
|
||||
|
||||
;;; Sequences and Ranges
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-seq-msgs (sequence)
|
||||
"Extract messages from the given SEQUENCE."
|
||||
(list 'cdr sequence))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-iterate-on-messages-in-region (var begin end &rest body)
|
||||
"Iterate over region.
|
||||
|
||||
VAR is bound to the message on the current line as we loop
|
||||
starting from BEGIN till END. In each step BODY is executed.
|
||||
|
||||
If VAR is nil then the loop is executed without any binding."
|
||||
(unless (symbolp var)
|
||||
(error "Can not bind the non-symbol %s" var))
|
||||
(let ((binding-needed-flag var))
|
||||
`(save-excursion
|
||||
(goto-char ,begin)
|
||||
(beginning-of-line)
|
||||
(while (and (<= (point) ,end) (not (eobp)))
|
||||
(when (looking-at mh-scan-valid-regexp)
|
||||
(let ,(if binding-needed-flag `((,var (mh-get-msg-num t))) ())
|
||||
,@body))
|
||||
(forward-line 1)))))
|
||||
(put 'mh-iterate-on-messages-in-region 'lisp-indent-hook 'defun)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defmacro mh-iterate-on-range (var range &rest body)
|
||||
"Iterate an operation over a region or sequence.
|
||||
|
||||
VAR is bound to each message in turn in a loop over RANGE, which
|
||||
can be a message number, a list of message numbers, a sequence, a
|
||||
region in a cons cell, or a MH range (something like last:20) in
|
||||
a string. In each iteration, BODY is executed.
|
||||
|
||||
The parameter RANGE is usually created with
|
||||
`mh-interactive-range' in order to provide a uniform interface to
|
||||
MH-E functions."
|
||||
(unless (symbolp var)
|
||||
(error "Can not bind the non-symbol %s" var))
|
||||
(let ((binding-needed-flag var)
|
||||
(msgs (make-symbol "msgs"))
|
||||
(seq-hash-table (make-symbol "seq-hash-table")))
|
||||
`(cond ((numberp ,range)
|
||||
(when (mh-goto-msg ,range t t)
|
||||
(let ,(if binding-needed-flag `((,var ,range)) ())
|
||||
,@body)))
|
||||
((and (consp ,range)
|
||||
(numberp (car ,range)) (numberp (cdr ,range)))
|
||||
(mh-iterate-on-messages-in-region ,var
|
||||
(car ,range) (cdr ,range)
|
||||
,@body))
|
||||
(t (let ((,msgs (cond ((and ,range (symbolp ,range))
|
||||
(mh-seq-to-msgs ,range))
|
||||
((stringp ,range)
|
||||
(mh-translate-range mh-current-folder
|
||||
,range))
|
||||
(t ,range)))
|
||||
(,seq-hash-table (make-hash-table)))
|
||||
(dolist (msg ,msgs)
|
||||
(setf (gethash msg ,seq-hash-table) t))
|
||||
(mh-iterate-on-messages-in-region v (point-min) (point-max)
|
||||
(when (gethash v ,seq-hash-table)
|
||||
(let ,(if binding-needed-flag `((,var v)) ())
|
||||
,@body))))))))
|
||||
(put 'mh-iterate-on-range 'lisp-indent-hook 'defun)
|
||||
|
||||
(provide 'mh-acros)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
;;; mh-alias.el --- MH-E mail alias completion and expansion
|
||||
;;
|
||||
|
||||
;; Copyright (C) 1994, 1995, 1996, 1997,
|
||||
;; 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
@ -31,24 +31,9 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;(message "> mh-alias")
|
||||
(eval-when-compile (require 'mh-acros))
|
||||
(mh-require-cl)
|
||||
(require 'mh-buffers)
|
||||
(require 'mh-e)
|
||||
;;(message "< mh-alias")
|
||||
(load "cmr" t t) ; Non-fatal dependency for
|
||||
; completing-read-multiple.
|
||||
(eval-when-compile (defvar mail-abbrev-syntax-table))
|
||||
|
||||
|
||||
|
||||
;;; Autoloads
|
||||
|
||||
(eval-when (compile load eval)
|
||||
(ignore-errors
|
||||
(require 'mailabbrev)
|
||||
(require 'multi-prompt)))
|
||||
(mh-require-cl)
|
||||
|
||||
(defvar mh-alias-alist 'not-read
|
||||
"Alist of MH aliases.")
|
||||
@ -61,7 +46,7 @@
|
||||
(defvar mh-alias-read-address-map nil)
|
||||
(unless mh-alias-read-address-map
|
||||
(setq mh-alias-read-address-map
|
||||
(copy-keymap minibuffer-local-completion-map))
|
||||
(copy-keymap minibuffer-local-completion-map))
|
||||
(define-key mh-alias-read-address-map
|
||||
"," 'mh-alias-minibuffer-confirm-address)
|
||||
(define-key mh-alias-read-address-map " " 'self-insert-command))
|
||||
@ -77,6 +62,11 @@ alias files listed in your \"Aliasfile:\" MH profile component are
|
||||
automatically included. You can update the alias list manually using
|
||||
\\[mh-alias-reload].")
|
||||
|
||||
;; Copy of `goto-address-mail-regexp'.
|
||||
(defvar mh-address-mail-regexp
|
||||
"[-a-zA-Z0-9._]+@\\([-a-zA-z0-9_]+\\.\\)+[a-zA-Z0-9]+"
|
||||
"A regular expression probably matching an e-mail address.")
|
||||
|
||||
|
||||
|
||||
;;; Alias Loading
|
||||
@ -185,7 +175,6 @@ Exclude all aliases already in `mh-alias-alist' from \"ali\""
|
||||
(forward-line 1)))
|
||||
passwd-alist))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-alias-reload ()
|
||||
"Reload MH aliases.
|
||||
|
||||
@ -269,11 +258,14 @@ Blind aliases or users from /etc/passwd are not expanded."
|
||||
(t
|
||||
(mh-alias-ali alias))))
|
||||
|
||||
(require 'crm nil t) ; completing-read-multiple
|
||||
(require 'multi-prompt nil t)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-read-address (prompt)
|
||||
"Read an address from the minibuffer with PROMPT."
|
||||
(mh-alias-reload-maybe)
|
||||
(if (not mh-alias-alist) ; If still no aliases, just prompt
|
||||
(if (not mh-alias-alist) ; If still no aliases, just prompt
|
||||
(read-string prompt)
|
||||
(let* ((minibuffer-local-completion-map mh-alias-read-address-map)
|
||||
(completion-ignore-case mh-alias-completion-ignore-case-flag)
|
||||
@ -308,8 +300,6 @@ Blind aliases or users from /etc/passwd are not expanded."
|
||||
(message "No alias for %s" the-name))))))
|
||||
(self-insert-command 1))
|
||||
|
||||
(mh-do-in-xemacs (defvar mail-abbrevs))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-alias-letter-expand-alias ()
|
||||
"Expand mail alias before point."
|
||||
@ -323,9 +313,10 @@ Blind aliases or users from /etc/passwd are not expanded."
|
||||
(expansion (mh-alias-expand (buffer-substring begin end))))
|
||||
(delete-region begin end)
|
||||
(insert expansion)))))
|
||||
|
||||
|
||||
|
||||
;;; Adding addresses to alias file.
|
||||
;;; Alias File Updating
|
||||
|
||||
(defun mh-alias-suggest-alias (string &optional no-comma-swap)
|
||||
"Suggest an alias for STRING.
|
||||
@ -451,8 +442,8 @@ contains it."
|
||||
(mh-alias-filenames t)))))
|
||||
(cond
|
||||
((not autolist)
|
||||
(error "No writable alias file.
|
||||
Set `mh-alias-insert-file' or the \"Aliasfile:\" profile component"))
|
||||
(error "No writable alias file;
|
||||
set `mh-alias-insert-file' or the \"Aliasfile:\" profile component"))
|
||||
((not (elt autolist 1)) ; Only one entry, use it
|
||||
(car autolist))
|
||||
((or (not alias)
|
||||
@ -549,7 +540,6 @@ folder name hint when filing messages."
|
||||
(insert (format "%s: %s\n" alias address))
|
||||
(save-buffer)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-alias-add-alias (alias address)
|
||||
"Add ALIAS for ADDRESS in personal alias file.
|
||||
|
||||
@ -602,7 +592,6 @@ filing messages."
|
||||
(alias (mh-alias-suggest-alias address)))
|
||||
(mh-alias-add-alias alias address))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-alias-add-address-under-point ()
|
||||
"Insert an alias for address under point."
|
||||
(interactive)
|
||||
@ -611,7 +600,19 @@ filing messages."
|
||||
(mh-alias-add-alias nil address)
|
||||
(message "No email address found under point"))))
|
||||
|
||||
;;;###mh-autoload
|
||||
;; From goto-addr.el, which we don't want to force-load on users.
|
||||
(defun mh-goto-address-find-address-at-point ()
|
||||
"Find e-mail address around or before point.
|
||||
|
||||
Then search backwards to beginning of line for the start of an
|
||||
e-mail address. If no e-mail address found, return nil."
|
||||
(re-search-backward "[^-_A-z0-9.@]" (line-beginning-position) 'lim)
|
||||
(if (or (looking-at mh-address-mail-regexp) ; already at start
|
||||
(and (re-search-forward mh-address-mail-regexp
|
||||
(line-end-position) 'lim)
|
||||
(goto-char (match-beginning 0))))
|
||||
(match-string-no-properties 0)))
|
||||
|
||||
(defun mh-alias-apropos (regexp)
|
||||
"Show all aliases or addresses that match a regular expression REGEXP."
|
||||
(interactive "sAlias regexp: ")
|
||||
@ -668,6 +669,21 @@ filing messages."
|
||||
(princ "\nLocal User Aliases:\n\n")
|
||||
(princ passwd-matches))))))
|
||||
|
||||
(defun mh-folder-line-matches-show-buffer-p ()
|
||||
"Return t if the message under point in folder-mode is in the show buffer.
|
||||
Return nil in any other circumstance (no message under point, no
|
||||
show buffer, the message in the show buffer doesn't match."
|
||||
(and (eq major-mode 'mh-folder-mode)
|
||||
(mh-get-msg-num nil)
|
||||
mh-show-buffer
|
||||
(get-buffer mh-show-buffer)
|
||||
(buffer-file-name (get-buffer mh-show-buffer))
|
||||
(string-match ".*/\\([0-9]+\\)$"
|
||||
(buffer-file-name (get-buffer mh-show-buffer)))
|
||||
(string-equal
|
||||
(match-string 1 (buffer-file-name (get-buffer mh-show-buffer)))
|
||||
(int-to-string (mh-get-msg-num nil)))))
|
||||
|
||||
(provide 'mh-alias)
|
||||
|
||||
;; Local Variables:
|
||||
|
@ -1,4 +1,4 @@
|
||||
;;; mh-buffers.el --- Temporary buffer constants and utilities used by MH-E
|
||||
;;; mh-buffers.el --- MH-E buffer constants and utilities
|
||||
|
||||
;; Copyright (C) 1993, 1995, 1997,
|
||||
;; 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
@ -27,8 +27,6 @@
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Temporary buffer constants and utilities used by MH-E.
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
1704
lisp/mh-e/mh-comp.el
1704
lisp/mh-e/mh-comp.el
File diff suppressed because it is too large
Load Diff
72
lisp/mh-e/mh-compat.el
Normal file
72
lisp/mh-e/mh-compat.el
Normal file
@ -0,0 +1,72 @@
|
||||
;;; mh-compat.el --- make MH-E compatibile with various versions of Emacs
|
||||
|
||||
;; Copyright (C) 2006 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.
|
||||
|
||||
;; 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., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; This is a good place to gather code that is used for compatibility
|
||||
;; between different versions of Emacs. Please document which versions
|
||||
;; of Emacs that the defsubst, defalias, or defmacro applies. That
|
||||
;; way, it's easy to occasionally go through this file and see which
|
||||
;; macros we can retire.
|
||||
|
||||
;; See also mh-gnus.el for compatibility macros used to span different
|
||||
;; versions of Gnus.
|
||||
|
||||
;; Macros are listed alphabetically.
|
||||
|
||||
(unless (fboundp 'assoc-string)
|
||||
(defsubst assoc-string (key list case-fold)
|
||||
"Like `assoc' but specifically for strings.
|
||||
Case is ignored if CASE-FOLD is non-nil.
|
||||
This function added by MH-E for Emacs versions that lack
|
||||
`assoc-string', introduced in Emacs 22."
|
||||
(if case-fold
|
||||
(assoc-ignore-case key list)
|
||||
(assoc key list))))
|
||||
|
||||
(defmacro mh-display-completion-list (completions &optional common-substring)
|
||||
"Display the list of COMPLETIONS.
|
||||
Calls `display-completion-list' correctly in older environments.
|
||||
Versions of Emacs prior to version 22 lacked a COMMON-SUBSTRING
|
||||
argument which is used to highlight the next possible character you
|
||||
can enter in the current list of completions."
|
||||
(if (< emacs-major-version 22)
|
||||
`(display-completion-list ,completions)
|
||||
`(display-completion-list ,completions ,common-substring)))
|
||||
|
||||
(provide 'mh-compat)
|
||||
|
||||
;; Local Variables:
|
||||
;; no-byte-compile: t
|
||||
;; indent-tabs-mode: nil
|
||||
;; sentence-end-double-space: nil
|
||||
;; End:
|
||||
|
||||
;;; mh-compat.el ends here
|
File diff suppressed because it is too large
Load Diff
5677
lisp/mh-e/mh-e.el
5677
lisp/mh-e/mh-e.el
File diff suppressed because it is too large
Load Diff
@ -1,264 +0,0 @@
|
||||
;;; mh-exec.el --- MH-E process support
|
||||
|
||||
;; Copyright (C) 1993, 1995, 1997,
|
||||
;; 2000, 2001, 2002, 2003, 2004, 2005, 2006 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.
|
||||
|
||||
;; 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., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Issue shell and MH commands
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(eval-when-compile (require 'mh-acros))
|
||||
(mh-require-cl)
|
||||
|
||||
(require 'mh-buffers)
|
||||
(require 'mh-utils)
|
||||
|
||||
(defvar mh-progs nil
|
||||
"Directory containing MH commands, such as inc, repl, and rmm.")
|
||||
|
||||
;;;###autoload
|
||||
(put 'mh-progs 'risky-local-variable t)
|
||||
|
||||
(defvar mh-lib nil
|
||||
"Directory containing the MH library.
|
||||
This directory contains, among other things, the components file.")
|
||||
|
||||
;;;###autoload
|
||||
(put 'mh-lib 'risky-local-variable t)
|
||||
|
||||
(defvar mh-lib-progs nil
|
||||
"Directory containing MH helper programs.
|
||||
This directory contains, among other things, the mhl program.")
|
||||
|
||||
;;;###autoload
|
||||
(put 'mh-lib-progs 'risky-local-variable t)
|
||||
|
||||
(defvar mh-index-max-cmdline-args 500
|
||||
"Maximum number of command line args.")
|
||||
|
||||
(defun mh-xargs (cmd &rest args)
|
||||
"Partial imitation of xargs.
|
||||
The current buffer contains a list of strings, one on each line.
|
||||
The function will execute CMD with ARGS and pass the first
|
||||
`mh-index-max-cmdline-args' strings to it. This is repeated till
|
||||
all the strings have been used."
|
||||
(goto-char (point-min))
|
||||
(let ((current-buffer (current-buffer)))
|
||||
(with-temp-buffer
|
||||
(let ((out (current-buffer)))
|
||||
(set-buffer current-buffer)
|
||||
(while (not (eobp))
|
||||
(let ((arg-list (reverse args))
|
||||
(count 0))
|
||||
(while (and (not (eobp)) (< count mh-index-max-cmdline-args))
|
||||
(push (buffer-substring-no-properties (point) (line-end-position))
|
||||
arg-list)
|
||||
(incf count)
|
||||
(forward-line))
|
||||
(apply #'call-process cmd nil (list out nil) nil
|
||||
(nreverse arg-list))))
|
||||
(erase-buffer)
|
||||
(insert-buffer-substring out)))))
|
||||
|
||||
;; XXX This should be applied anywhere MH-E calls out to /bin/sh.
|
||||
(defun mh-quote-for-shell (string)
|
||||
"Quote STRING for /bin/sh.
|
||||
Adds double-quotes around entire string and quotes the characters
|
||||
\\, `, and $ with a backslash."
|
||||
(concat "\""
|
||||
(loop for x across string
|
||||
concat (format (if (memq x '(?\\ ?` ?$)) "\\%c" "%c") x))
|
||||
"\""))
|
||||
|
||||
(defun mh-exec-cmd (command &rest args)
|
||||
"Execute mh-command COMMAND with ARGS.
|
||||
The side effects are what is desired. Any output is assumed to be
|
||||
an error and is shown to the user. The output is not read or
|
||||
parsed by MH-E."
|
||||
(save-excursion
|
||||
(set-buffer (get-buffer-create mh-log-buffer))
|
||||
(let* ((initial-size (mh-truncate-log-buffer))
|
||||
(start (point))
|
||||
(args (mh-list-to-string args)))
|
||||
(apply 'call-process (expand-file-name command mh-progs) nil t nil args)
|
||||
(when (> (buffer-size) initial-size)
|
||||
(save-excursion
|
||||
(goto-char start)
|
||||
(insert "Errors when executing: " command)
|
||||
(loop for arg in args do (insert " " arg))
|
||||
(insert "\n"))
|
||||
(save-window-excursion
|
||||
(switch-to-buffer-other-window mh-log-buffer)
|
||||
(sit-for 5))))))
|
||||
|
||||
(defun mh-exec-cmd-error (env command &rest args)
|
||||
"In environment ENV, execute mh-command COMMAND with ARGS.
|
||||
ENV is nil or a string of space-separated \"var=value\" elements.
|
||||
Signals an error if process does not complete successfully."
|
||||
(save-excursion
|
||||
(set-buffer (get-buffer-create mh-temp-buffer))
|
||||
(erase-buffer)
|
||||
(let ((process-environment process-environment))
|
||||
;; XXX: We should purge the list that split-string returns of empty
|
||||
;; strings. This can happen in XEmacs if leading or trailing spaces
|
||||
;; are present.
|
||||
(dolist (elem (if (stringp env) (split-string env " ") ()))
|
||||
(push elem process-environment))
|
||||
(mh-handle-process-error
|
||||
command (apply #'call-process (expand-file-name command mh-progs)
|
||||
nil t nil (mh-list-to-string args))))))
|
||||
|
||||
(defun mh-exec-cmd-daemon (command filter &rest args)
|
||||
"Execute MH command COMMAND in the background.
|
||||
|
||||
If FILTER is non-nil then it is used to process the output
|
||||
otherwise the default filter `mh-process-daemon' is used. See
|
||||
`set-process-filter' for more details of FILTER.
|
||||
|
||||
ARGS are passed to COMMAND as command line arguments."
|
||||
(save-excursion
|
||||
(set-buffer (get-buffer-create mh-log-buffer))
|
||||
(mh-truncate-log-buffer))
|
||||
(let* ((process-connection-type nil)
|
||||
(process (apply 'start-process
|
||||
command nil
|
||||
(expand-file-name command mh-progs)
|
||||
(mh-list-to-string args))))
|
||||
(set-process-filter process (or filter 'mh-process-daemon))
|
||||
process))
|
||||
|
||||
(defun mh-exec-cmd-env-daemon (env command filter &rest args)
|
||||
"In ennvironment ENV, execute mh-command COMMAND in the background.
|
||||
|
||||
ENV is nil or a string of space-separated \"var=value\" elements.
|
||||
Signals an error if process does not complete successfully.
|
||||
|
||||
If FILTER is non-nil then it is used to process the output
|
||||
otherwise the default filter `mh-process-daemon' is used. See
|
||||
`set-process-filter' for more details of FILTER.
|
||||
|
||||
ARGS are passed to COMMAND as command line arguments."
|
||||
(let ((process-environment process-environment))
|
||||
(dolist (elem (if (stringp env) (split-string env " ") ()))
|
||||
(push elem process-environment))
|
||||
(apply #'mh-exec-cmd-daemon command filter args)))
|
||||
|
||||
(defun mh-process-daemon (process output)
|
||||
"PROCESS daemon that puts OUTPUT into a temporary buffer.
|
||||
Any output from the process is displayed in an asynchronous
|
||||
pop-up window."
|
||||
(with-current-buffer (get-buffer-create mh-log-buffer)
|
||||
(insert-before-markers output)
|
||||
(display-buffer mh-log-buffer)))
|
||||
|
||||
(defun mh-exec-cmd-quiet (raise-error command &rest args)
|
||||
"Signal RAISE-ERROR if COMMAND with ARGS fails.
|
||||
Execute MH command COMMAND with ARGS. ARGS is a list of strings.
|
||||
Return at start of mh-temp buffer, where output can be parsed and
|
||||
used.
|
||||
Returns value of `call-process', which is 0 for success, unless
|
||||
RAISE-ERROR is non-nil, in which case an error is signaled if
|
||||
`call-process' returns non-0."
|
||||
(set-buffer (get-buffer-create mh-temp-buffer))
|
||||
(erase-buffer)
|
||||
(let ((value
|
||||
(apply 'call-process
|
||||
(expand-file-name command mh-progs) nil t nil
|
||||
args)))
|
||||
(goto-char (point-min))
|
||||
(if raise-error
|
||||
(mh-handle-process-error command value)
|
||||
value)))
|
||||
|
||||
;; Shush compiler.
|
||||
(eval-when-compile (defvar mark-active))
|
||||
|
||||
(defun mh-exec-cmd-output (command display &rest args)
|
||||
"Execute MH command COMMAND with DISPLAY flag and ARGS.
|
||||
Put the output into buffer after point.
|
||||
Set mark after inserted text.
|
||||
Output is expected to be shown to user, not parsed by MH-E."
|
||||
(push-mark (point) t)
|
||||
(apply 'call-process
|
||||
(expand-file-name command mh-progs) nil t display
|
||||
(mh-list-to-string args))
|
||||
|
||||
;; The following is used instead of 'exchange-point-and-mark because the
|
||||
;; latter activates the current region (between point and mark), which
|
||||
;; turns on highlighting. So prior to this bug fix, doing "inc" would
|
||||
;; highlight a region containing the new messages, which is undesirable.
|
||||
;; The bug wasn't seen in emacs21 but still occurred in XEmacs21.4.
|
||||
(mh-exchange-point-and-mark-preserving-active-mark))
|
||||
|
||||
(defun mh-exchange-point-and-mark-preserving-active-mark ()
|
||||
"Put the mark where point is now, and point where the mark is now.
|
||||
This command works even when the mark is not active, and
|
||||
preserves whether the mark is active or not."
|
||||
(interactive nil)
|
||||
(let ((is-active (and (boundp 'mark-active) mark-active)))
|
||||
(let ((omark (mark t)))
|
||||
(if (null omark)
|
||||
(error "No mark set in this buffer"))
|
||||
(set-mark (point))
|
||||
(goto-char omark)
|
||||
(if (boundp 'mark-active)
|
||||
(setq mark-active is-active))
|
||||
nil)))
|
||||
|
||||
(defun mh-exec-lib-cmd-output (command &rest args)
|
||||
"Execute MH library command COMMAND with ARGS.
|
||||
Put the output into buffer after point.
|
||||
Set mark after inserted text."
|
||||
(apply 'mh-exec-cmd-output (expand-file-name command mh-lib-progs) nil args))
|
||||
|
||||
(defun mh-handle-process-error (command status)
|
||||
"Raise error if COMMAND returned non-zero STATUS, otherwise return STATUS."
|
||||
(if (equal status 0)
|
||||
status
|
||||
(goto-char (point-min))
|
||||
(insert (if (integerp status)
|
||||
(format "%s: exit code %d\n" command status)
|
||||
(format "%s: %s\n" command status)))
|
||||
(save-excursion
|
||||
(let ((error-message (buffer-substring (point-min) (point-max))))
|
||||
(set-buffer (get-buffer-create mh-log-buffer))
|
||||
(mh-truncate-log-buffer)
|
||||
(insert error-message)))
|
||||
(error "%s failed, check buffer %s for error message"
|
||||
command mh-log-buffer)))
|
||||
|
||||
(provide 'mh-exec)
|
||||
|
||||
;; Local Variables:
|
||||
;; indent-tabs-mode: nil
|
||||
;; sentence-end-double-space: nil
|
||||
;; End:
|
||||
|
||||
;; arch-tag: 2857996c-e624-46b2-a58d-979cd279d288
|
||||
;;; mh-utils.el ends here
|
1989
lisp/mh-e/mh-folder.el
Normal file
1989
lisp/mh-e/mh-folder.el
Normal file
File diff suppressed because it is too large
Load Diff
@ -27,34 +27,19 @@
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Internal support for MH-E package.
|
||||
;; Putting these functions in a separate file lets MH-E start up faster,
|
||||
;; since less Lisp code needs to be loaded all at once.
|
||||
|
||||
;; Please add the functions in alphabetical order. If only one or two
|
||||
;; small support routines are needed, place them with the function;
|
||||
;; otherwise, create a separate section for them.
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;(message "> mh-funcs")
|
||||
(eval-when-compile (require 'mh-acros))
|
||||
(mh-require-cl)
|
||||
(require 'mh-buffers)
|
||||
(require 'mh-e)
|
||||
;;(message "< mh-funcs")
|
||||
|
||||
|
||||
|
||||
;;; Scan Line Formats
|
||||
|
||||
(defvar mh-note-copied "C"
|
||||
"Messages that have been copied are marked by this character.")
|
||||
|
||||
(defvar mh-note-printed "P"
|
||||
"Messages that have been printed are marked by this character.")
|
||||
|
||||
|
||||
|
||||
;;; Functions
|
||||
(require 'mh-scan)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-burst-digest ()
|
||||
@ -212,27 +197,6 @@ Display RANGE after packing, or the entire folder if RANGE is nil."
|
||||
(mh-reset-threads-and-narrowing)
|
||||
(mh-regenerate-headers range))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-pipe-msg (command include-header)
|
||||
"Pipe message through shell command COMMAND.
|
||||
|
||||
You are prompted for the Unix command through which you wish to
|
||||
run your message. If you give a prefix argument INCLUDE-HEADER to
|
||||
this command, the message header is included in the text passed
|
||||
to the command."
|
||||
(interactive
|
||||
(list (read-string "Shell command on message: ") current-prefix-arg))
|
||||
(let ((msg-file-to-pipe (mh-msg-filename (mh-get-msg-num t)))
|
||||
(message-directory default-directory))
|
||||
(save-excursion
|
||||
(set-buffer (get-buffer-create mh-temp-buffer))
|
||||
(erase-buffer)
|
||||
(insert-file-contents msg-file-to-pipe)
|
||||
(goto-char (point-min))
|
||||
(if (not include-header) (search-forward "\n\n"))
|
||||
(let ((default-directory message-directory))
|
||||
(shell-command-on-region (point) (point-max) command nil)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-page-digest ()
|
||||
"Display next message in digest."
|
||||
@ -267,6 +231,27 @@ to the command."
|
||||
(forward-line 2))
|
||||
(mh-recenter 0)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-pipe-msg (command include-header)
|
||||
"Pipe message through shell command COMMAND.
|
||||
|
||||
You are prompted for the Unix command through which you wish to
|
||||
run your message. If you give a prefix argument INCLUDE-HEADER to
|
||||
this command, the message header is included in the text passed
|
||||
to the command."
|
||||
(interactive
|
||||
(list (read-string "Shell command on message: ") current-prefix-arg))
|
||||
(let ((msg-file-to-pipe (mh-msg-filename (mh-get-msg-num t)))
|
||||
(message-directory default-directory))
|
||||
(save-excursion
|
||||
(set-buffer (get-buffer-create mh-temp-buffer))
|
||||
(erase-buffer)
|
||||
(insert-file-contents msg-file-to-pipe)
|
||||
(goto-char (point-min))
|
||||
(if (not include-header) (search-forward "\n\n"))
|
||||
(let ((default-directory message-directory))
|
||||
(shell-command-on-region (point) (point-max) command nil)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-sort-folder (&optional extra-args)
|
||||
"Sort folder.
|
||||
@ -288,21 +273,6 @@ By default, messages are sorted by date. The option
|
||||
(cond (threaded-flag (mh-toggle-threads))
|
||||
(mh-index-data (mh-index-insert-folder-headers)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-undo-folder ()
|
||||
"Undo all refiles and deletes in the current folder."
|
||||
(interactive)
|
||||
(cond ((or mh-do-not-confirm-flag
|
||||
(yes-or-no-p "Undo all commands in folder? "))
|
||||
(setq mh-delete-list nil
|
||||
mh-refile-list nil
|
||||
mh-seq-list nil
|
||||
mh-next-direction 'forward)
|
||||
(with-mh-folder-updating (nil)
|
||||
(mh-remove-all-notation)))
|
||||
(t
|
||||
(message "Commands not undone"))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-store-msg (directory)
|
||||
"Unpack message created with \"uudecode\" or \"shar\".
|
||||
@ -326,7 +296,6 @@ storing the content of these messages."
|
||||
(insert-file-contents msg-file-to-store)
|
||||
(mh-store-buffer directory))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-store-buffer (directory)
|
||||
"Unpack buffer created with \"uudecode\" or \"shar\".
|
||||
|
||||
@ -383,48 +352,20 @@ See `mh-store-msg' for a description of DIRECTORY."
|
||||
(insert "\n(mh-store finished)\n"))
|
||||
(error "Error occurred during execution of %s" command)))))
|
||||
|
||||
|
||||
|
||||
;;; Help Functions
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-ephem-message (string)
|
||||
"Display STRING in the minibuffer momentarily."
|
||||
(message "%s" string)
|
||||
(sit-for 5)
|
||||
(message ""))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-help ()
|
||||
"Display cheat sheet for the MH-E commands."
|
||||
(defun mh-undo-folder ()
|
||||
"Undo all refiles and deletes in the current folder."
|
||||
(interactive)
|
||||
(with-electric-help
|
||||
(function
|
||||
(lambda ()
|
||||
(insert
|
||||
(substitute-command-keys
|
||||
(mapconcat 'identity (cdr (assoc nil mh-help-messages)) ""))))
|
||||
mh-help-buffer)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-prefix-help ()
|
||||
"Display cheat sheet for the commands of the current prefix in minibuffer."
|
||||
(interactive)
|
||||
;; We got here because the user pressed a "?", but he pressed a prefix key
|
||||
;; before that. Since the the key vector starts at index 0, the index of the
|
||||
;; last keystroke is length-1 and thus the second to last keystroke is at
|
||||
;; length-2. We use that information to obtain a suitable prefix character
|
||||
;; from the recent keys.
|
||||
(let* ((keys (recent-keys))
|
||||
(prefix-char (elt keys (- (length keys) 2))))
|
||||
(with-electric-help
|
||||
(function
|
||||
(lambda ()
|
||||
(insert
|
||||
(substitute-command-keys
|
||||
(mapconcat 'identity
|
||||
(cdr (assoc prefix-char mh-help-messages)) "")))))
|
||||
mh-help-buffer)))
|
||||
(cond ((or mh-do-not-confirm-flag
|
||||
(yes-or-no-p "Undo all commands in folder? "))
|
||||
(setq mh-delete-list nil
|
||||
mh-refile-list nil
|
||||
mh-seq-list nil
|
||||
mh-next-direction 'forward)
|
||||
(with-mh-folder-updating (nil)
|
||||
(mh-remove-all-notation)))
|
||||
(t
|
||||
(message "Commands not undone"))))
|
||||
|
||||
(provide 'mh-funcs)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
;;; mh-gnus.el --- Make MH-E compatible with installed version of Gnus.
|
||||
;;; mh-gnus.el --- make MH-E compatible with various versions of Gnus
|
||||
|
||||
;; Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
|
||||
|
||||
@ -30,18 +30,13 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;(message "> mh-gnus")
|
||||
(eval-when-compile (require 'mh-acros))
|
||||
;;(message "< mh-gnus")
|
||||
(require 'mh-e)
|
||||
|
||||
;; Load libraries in a non-fatal way in order to see if certain functions are
|
||||
;; pre-defined.
|
||||
(load "mailabbrev" t t)
|
||||
(load "mailcap" t t)
|
||||
(load "mm-decode" t t)
|
||||
(load "mm-uu" t t)
|
||||
(load "mml" t t)
|
||||
(load "smiley" t t)
|
||||
(require 'gnus-util nil t)
|
||||
(require 'mm-bodies nil t)
|
||||
(require 'mm-decode nil t)
|
||||
(require 'mm-view nil t)
|
||||
(require 'mml nil t)
|
||||
|
||||
;; Copy of function from gnus-util.el.
|
||||
(mh-defun-compat gnus-local-map-property (map)
|
||||
@ -68,12 +63,12 @@
|
||||
(mm-insert-inline
|
||||
handle
|
||||
(concat "\n-- \n"
|
||||
(ignore-errors
|
||||
(if (fboundp 'vcard-pretty-print)
|
||||
(vcard-pretty-print (mm-get-part handle))
|
||||
(vcard-format-string
|
||||
(vcard-parse-string (mm-get-part handle)
|
||||
'vcard-standard-filter))))))))
|
||||
(ignore-errors
|
||||
(if (fboundp 'vcard-pretty-print)
|
||||
(vcard-pretty-print (mm-get-part handle))
|
||||
(vcard-format-string
|
||||
(vcard-parse-string (mm-get-part handle)
|
||||
'vcard-standard-filter))))))))
|
||||
|
||||
;; Function from mm-decode.el used in PGP messages. Just define it with older
|
||||
;; Gnus to avoid compiler warning.
|
||||
@ -116,6 +111,10 @@
|
||||
"Older versions of Emacs don't have this function."
|
||||
nil)
|
||||
|
||||
(mh-defun-compat mm-uu-dissect-text-parts (handles)
|
||||
"Emacs 21 and XEmacs don't have this function."
|
||||
nil)
|
||||
|
||||
;; Copy of function in mml.el.
|
||||
(mh-defun-compat mml-minibuffer-read-disposition (type &optional default)
|
||||
(unless default (setq default
|
||||
@ -128,7 +127,7 @@
|
||||
'(("attachment") ("inline") (""))
|
||||
nil t nil nil default)))
|
||||
(if (not (equal disposition ""))
|
||||
disposition
|
||||
disposition
|
||||
default)))
|
||||
|
||||
;; This is mm-save-part from Gnus 5.10 since that function in emacs21.2 is
|
||||
@ -158,11 +157,6 @@
|
||||
(or (and (boundp 'mm-inline-text-html-renderer) mm-inline-text-html-renderer)
|
||||
(and (boundp 'mm-text-html-renderer) mm-text-html-renderer)))
|
||||
|
||||
(defun mh-mail-abbrev-make-syntax-table ()
|
||||
"Call `mail-abbrev-make-syntax-table' if available."
|
||||
(when (fboundp 'mail-abbrev-make-syntax-table)
|
||||
(mail-abbrev-make-syntax-table)))
|
||||
|
||||
(provide 'mh-gnus)
|
||||
|
||||
;; Local Variables:
|
||||
|
@ -1,4 +1,4 @@
|
||||
;;; mh-identity.el --- Multiple identify support for MH-E.
|
||||
;;; mh-identity.el --- multiple identify support for MH-E
|
||||
|
||||
;; Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
@ -27,23 +27,19 @@
|
||||
;;; Commentary:
|
||||
|
||||
;; Multiple identity support for MH-E.
|
||||
;;
|
||||
;; Used to easily set different fields such as From and Organization, as
|
||||
;; well as different signature files.
|
||||
;;
|
||||
;; Customize the variable `mh-identity-list' and an Identity menu will
|
||||
;; appear in mh-letter-mode. The command 'mh-insert-identity can be used
|
||||
;; from the command line.
|
||||
|
||||
;; Used to easily set different fields such as From and Organization,
|
||||
;; as well as different signature files.
|
||||
|
||||
;; Customize the variable `mh-identity-list' and see the Identity menu
|
||||
;; in MH-Letter mode. The command `mh-insert-identity' can be used
|
||||
;; to manually insert an identity.
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;(message "> mh-identity")
|
||||
(eval-when-compile (require 'mh-acros))
|
||||
|
||||
(require 'mh-comp)
|
||||
;;(message "< mh-identity")
|
||||
(require 'mh-e)
|
||||
|
||||
(autoload 'mml-insert-tag "mml")
|
||||
|
||||
@ -53,11 +49,17 @@ This is normally set as part of an Identity in
|
||||
`mh-identity-list'.")
|
||||
(make-variable-buffer-local 'mh-identity-pgg-default-user-id)
|
||||
|
||||
(defvar mh-identity-menu nil
|
||||
"The Identity menu.")
|
||||
|
||||
(defalias 'mh-identity-make-menu-no-autoload 'mh-identity-make-menu)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-identity-make-menu ()
|
||||
"Build the Identity menu.
|
||||
This should be called any time `mh-identity-list' or
|
||||
`mh-auto-fields-list' change."
|
||||
`mh-auto-fields-list' change.
|
||||
See `mh-identity-add-menu'."
|
||||
(easy-menu-define mh-identity-menu mh-letter-mode-map
|
||||
"MH-E identity menu"
|
||||
(append
|
||||
@ -88,13 +90,11 @@ This should be called any time `mh-identity-list' or
|
||||
))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-identity-list-set (symbol value)
|
||||
"Update the `mh-identity-list' variable, and rebuild the menu.
|
||||
Sets the default for SYMBOL (for example, `mh-identity-list') to
|
||||
VALUE (as set in customization). This is called after 'customize
|
||||
is used to alter `mh-identity-list'."
|
||||
(set-default symbol value)
|
||||
(mh-identity-make-menu))
|
||||
(defun mh-identity-add-menu ()
|
||||
"Add the current Identity menu.
|
||||
See `mh-identity-make-menu'."
|
||||
(if mh-identity-menu
|
||||
(easy-menu-add mh-identity-menu)))
|
||||
|
||||
(defvar mh-identity-local nil
|
||||
"Buffer-local variable that holds the identity currently in use.")
|
||||
@ -134,8 +134,13 @@ valid header field."
|
||||
'mh-identity-handler-default))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-insert-identity (identity)
|
||||
(defun mh-insert-identity (identity &optional maybe-insert)
|
||||
"Insert fields specified by given IDENTITY.
|
||||
|
||||
In a program, do not insert fields if MAYBE-INSERT is non-nil,
|
||||
`mh-identity-default' is non-nil, and fields have already been
|
||||
inserted.
|
||||
|
||||
See `mh-identity-list'."
|
||||
(interactive
|
||||
(list (completing-read
|
||||
@ -144,29 +149,35 @@ See `mh-identity-list'."
|
||||
(cons '("None")
|
||||
(mapcar 'list (mapcar 'car mh-identity-list)))
|
||||
(mapcar 'list (mapcar 'car mh-identity-list)))
|
||||
nil t)))
|
||||
(save-excursion
|
||||
;;First remove old settings, if any.
|
||||
(when mh-identity-local
|
||||
(let ((pers-list (cadr (assoc mh-identity-local mh-identity-list))))
|
||||
(while pers-list
|
||||
(let* ((field (caar pers-list))
|
||||
(handler (mh-identity-field-handler field)))
|
||||
(funcall handler field 'remove))
|
||||
(setq pers-list (cdr pers-list)))))
|
||||
;; Then insert the replacement
|
||||
(when (not (equal "None" identity))
|
||||
(let ((pers-list (cadr (assoc identity mh-identity-list))))
|
||||
(while pers-list
|
||||
(let* ((field (caar pers-list))
|
||||
(value (cdar pers-list))
|
||||
(handler (mh-identity-field-handler field)))
|
||||
(funcall handler field 'add value))
|
||||
(setq pers-list (cdr pers-list))))))
|
||||
;; Remember what is in use in this buffer
|
||||
(if (equal "None" identity)
|
||||
(setq mh-identity-local nil)
|
||||
(setq mh-identity-local identity)))
|
||||
nil t)
|
||||
nil))
|
||||
|
||||
(when (or (not maybe-insert)
|
||||
(and (boundp 'mh-identity-default)
|
||||
mh-identity-default
|
||||
(not mh-identity-local)))
|
||||
(save-excursion
|
||||
;;First remove old settings, if any.
|
||||
(when mh-identity-local
|
||||
(let ((pers-list (cadr (assoc mh-identity-local mh-identity-list))))
|
||||
(while pers-list
|
||||
(let* ((field (caar pers-list))
|
||||
(handler (mh-identity-field-handler field)))
|
||||
(funcall handler field 'remove))
|
||||
(setq pers-list (cdr pers-list)))))
|
||||
;; Then insert the replacement
|
||||
(when (not (equal "None" identity))
|
||||
(let ((pers-list (cadr (assoc identity mh-identity-list))))
|
||||
(while pers-list
|
||||
(let* ((field (caar pers-list))
|
||||
(value (cdar pers-list))
|
||||
(handler (mh-identity-field-handler field)))
|
||||
(funcall handler field 'add value))
|
||||
(setq pers-list (cdr pers-list))))))
|
||||
;; Remember what is in use in this buffer
|
||||
(if (equal "None" identity)
|
||||
(setq mh-identity-local nil)
|
||||
(setq mh-identity-local identity))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-identity-handler-gpg-identity (field action &optional value)
|
||||
@ -268,7 +279,7 @@ bottom of the header. If action is 'add, the VALUE is added."
|
||||
(t
|
||||
(goto-char (point-min))
|
||||
(if (not top)
|
||||
(mh-goto-header-end 0))
|
||||
(mh-goto-header-end 0))
|
||||
(insert field-colon " " value "\n")))))))
|
||||
|
||||
;;;###mh-autoload
|
||||
|
@ -1,5 +1,5 @@
|
||||
;;; mh-inc.el --- MH-E "inc" and separate mail spool handling
|
||||
;;
|
||||
|
||||
;; Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Peter S. Galbraith <psg@debian.org>
|
||||
@ -26,33 +26,42 @@
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Support for inc. In addition to reading from the system mailbox, inc can
|
||||
;; also be used to incorporate mail from multiple spool files into separate
|
||||
;; folders. See "C-h v mh-inc-spool-list".
|
||||
;; Support for inc. In addition to reading from the system mailbox,
|
||||
;; inc can also be used to incorporate mail from multiple spool files
|
||||
;; into separate folders. See "C-h v mh-inc-spool-list".
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;(message "> mh-inc")
|
||||
(eval-when-compile (require 'mh-acros))
|
||||
(require 'mh-e)
|
||||
(mh-require-cl)
|
||||
;;(message "< mh-inc")
|
||||
|
||||
(defvar mh-inc-spool-map (make-sparse-keymap)
|
||||
"Keymap for MH-E's mh-inc-spool commands.")
|
||||
|
||||
(defvar mh-inc-spool-map-help nil
|
||||
"Help text to for `mh-inc-spool-map'.")
|
||||
"Help text for `mh-inc-spool-map'.")
|
||||
|
||||
(define-key mh-inc-spool-map "?"
|
||||
'(lambda ()
|
||||
(interactive)
|
||||
(if mh-inc-spool-map-help
|
||||
(let ((mh-help-messages (list (list nil mh-inc-spool-map-help))))
|
||||
(mh-help))
|
||||
(mh-help mh-inc-spool-map-help)
|
||||
(mh-ephem-message
|
||||
"There are no keys defined yet. Customize `mh-inc-spool-list'"))))
|
||||
"There are no keys defined yet; customize `mh-inc-spool-list'"))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-inc-spool-make ()
|
||||
"Make all commands and defines keys for contents of `mh-inc-spool-list'."
|
||||
(setq mh-inc-spool-map-help nil)
|
||||
(when mh-inc-spool-list
|
||||
(loop for elem in mh-inc-spool-list
|
||||
do (let ((spool (nth 0 elem))
|
||||
(folder (nth 1 elem))
|
||||
(key (nth 2 elem)))
|
||||
(progn
|
||||
(mh-inc-spool-generator folder spool)
|
||||
(mh-inc-spool-def-key key folder))))))
|
||||
|
||||
(defalias 'mh-inc-spool-make-no-autoload 'mh-inc-spool-make)
|
||||
|
||||
(defun mh-inc-spool-generator (folder spool)
|
||||
"Create a command to inc into FOLDER from SPOOL file."
|
||||
@ -62,7 +71,7 @@
|
||||
(set spool1 spool)
|
||||
(setf (symbol-function (intern (concat "mh-inc-spool-" folder)))
|
||||
`(lambda ()
|
||||
,(format "Inc spool file %s into folder %s" spool folder)
|
||||
,(format "Inc spool file %s into folder %s." spool folder)
|
||||
(interactive)
|
||||
(mh-inc-folder ,spool1 (concat "+" ,folder1))))))
|
||||
|
||||
@ -71,32 +80,9 @@
|
||||
(when (not (= 0 key))
|
||||
(define-key mh-inc-spool-map (format "%c" key)
|
||||
(intern (concat "mh-inc-spool-" folder)))
|
||||
(setq mh-inc-spool-map-help (concat mh-inc-spool-map-help "["
|
||||
(char-to-string key)
|
||||
"] inc " folder " folder\n"))))
|
||||
|
||||
;; Shush compiler.
|
||||
(eval-when-compile (defvar mh-inc-spool-list))
|
||||
|
||||
(defun mh-inc-spool-make ()
|
||||
"Make all commands and defines keys for contents of `mh-inc-spool-list'."
|
||||
(when mh-inc-spool-list
|
||||
(setq mh-inc-spool-map-help nil)
|
||||
(loop for elem in mh-inc-spool-list
|
||||
do (let ((spool (nth 0 elem))
|
||||
(folder (nth 1 elem))
|
||||
(key (nth 2 elem)))
|
||||
(progn
|
||||
(mh-inc-spool-generator folder spool)
|
||||
(mh-inc-spool-def-key key folder))))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-inc-spool-list-set (symbol value)
|
||||
"Set-default SYMBOL to VALUE to update the `mh-inc-spool-list' variable.
|
||||
Also rebuilds the user commands.
|
||||
This is called after 'customize is used to alter `mh-inc-spool-list'."
|
||||
(set-default symbol value)
|
||||
(mh-inc-spool-make))
|
||||
(add-to-list 'mh-inc-spool-map-help
|
||||
(concat "[" (char-to-string key) "] inc " folder " folder\n")
|
||||
t)))
|
||||
|
||||
(provide 'mh-inc)
|
||||
|
||||
|
@ -1,441 +0,0 @@
|
||||
;;; mh-init.el --- MH-E initialization
|
||||
|
||||
;; Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Peter S. Galbraith <psg@debian.org>
|
||||
;; 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., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Sets up the MH variant (currently nmh, MH, or GNU mailutils).
|
||||
;;
|
||||
;; Users may customize `mh-variant' to switch between available variants.
|
||||
;; Available MH variants are returned by the function `mh-variants'.
|
||||
;; Developers may check which variant is currently in use with the
|
||||
;; variable `mh-variant-in-use' or the function `mh-variant-p'.
|
||||
;;
|
||||
;; Also contains code that is used at load or initialization time only.
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;(message "> mh-init")
|
||||
(eval-when-compile (require 'mh-acros))
|
||||
(mh-require-cl)
|
||||
(require 'mh-buffers)
|
||||
(require 'mh-exec)
|
||||
;;(message "< mh-init")
|
||||
|
||||
(defvar mh-sys-path
|
||||
'("/usr/local/nmh/bin" ; nmh default
|
||||
"/usr/local/bin/mh/"
|
||||
"/usr/local/mh/"
|
||||
"/usr/bin/mh/" ; Ultrix 4.2, Linux
|
||||
"/usr/new/mh/" ; Ultrix < 4.2
|
||||
"/usr/contrib/mh/bin/" ; BSDI
|
||||
"/usr/pkg/bin/" ; NetBSD
|
||||
"/usr/local/bin/"
|
||||
"/usr/local/bin/mu-mh/" ; GNU mailutils - default
|
||||
"/usr/bin/mu-mh/") ; GNU mailutils - packaged
|
||||
"List of directories to search for variants of the MH variant.
|
||||
The list `exec-path' is searched in addition to this list.
|
||||
There's no need for users to modify this list. Instead add extra
|
||||
directories to the customizable variable `mh-path'.")
|
||||
|
||||
;; 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
|
||||
;; was installed into. But if you installed MH after building Emacs,
|
||||
;; this would almost certainly be wrong, so now we do it at run time.
|
||||
|
||||
(defvar mh-flists-present-flag nil
|
||||
"Non-nil means that we have \"flists\".")
|
||||
|
||||
(defvar mh-variants nil
|
||||
"List describing known MH variants.
|
||||
Do not access this variable directly as it may not have yet been initialized.
|
||||
Use the function `mh-variants' instead.")
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-variants ()
|
||||
"Return a list of installed variants of MH on the system.
|
||||
This function looks for MH in `mh-sys-path', `mh-path' and
|
||||
`exec-path'. The format of the list of variants that is returned
|
||||
is described by the variable `mh-variants'."
|
||||
(if mh-variants
|
||||
mh-variants
|
||||
(let ((list-unique))
|
||||
;; Make a unique list of directories, keeping the given order.
|
||||
;; We don't want the same MH variant to be listed multiple times.
|
||||
(loop for dir in (append mh-path mh-sys-path exec-path) do
|
||||
(setq dir (file-chase-links (directory-file-name dir)))
|
||||
(add-to-list 'list-unique dir))
|
||||
(loop for dir in (nreverse list-unique) do
|
||||
(when (and dir (file-directory-p dir) (file-readable-p dir))
|
||||
(let ((variant (mh-variant-info dir)))
|
||||
(if variant
|
||||
(add-to-list 'mh-variants variant)))))
|
||||
mh-variants)))
|
||||
|
||||
(defun mh-variant-info (dir)
|
||||
"Return MH variant found in DIR, or nil if none present."
|
||||
(save-excursion
|
||||
(let ((tmp-buffer (get-buffer-create mh-temp-buffer)))
|
||||
(set-buffer tmp-buffer)
|
||||
(cond
|
||||
((mh-variant-mh-info dir))
|
||||
((mh-variant-nmh-info dir))
|
||||
((mh-variant-mu-mh-info dir))))))
|
||||
|
||||
(defun mh-variant-mh-info (dir)
|
||||
"Return info for MH variant in DIR assuming a temporary buffer is setup."
|
||||
;; MH does not have the -version option.
|
||||
;; Its version number is included in the output of "-help" as:
|
||||
;;
|
||||
;; version: MH 6.8.4 #2[UCI] (burrito) of Fri Jan 15 20:01:39 EST 1999
|
||||
;; options: [ATHENA] [BIND] [DUMB] [LIBLOCKFILE] [LOCALE] [MAILGROUP] [MHE]
|
||||
;; [MHRC] [MIME] [MORE='"/usr/bin/sensible-pager"'] [NLINK_HACK]
|
||||
;; [NORUSERPASS] [OVERHEAD] [POP] [POPSERVICE='"pop-3"'] [RENAME]
|
||||
;; [RFC1342] [RPATHS] [RPOP] [SENDMTS] [SMTP] [SOCKETS]
|
||||
;; [SPRINTFTYPE=int] [SVR4] [SYS5] [SYS5DIR] [TERMINFO]
|
||||
;; [TYPESIG=void] [UNISTD] [UTK] [VSPRINTF]
|
||||
(let ((mhparam (expand-file-name "mhparam" dir)))
|
||||
(when (mh-file-command-p mhparam)
|
||||
(erase-buffer)
|
||||
(call-process mhparam nil '(t nil) nil "-help")
|
||||
(goto-char (point-min))
|
||||
(when (search-forward-regexp "version: MH \\(\\S +\\)" nil t)
|
||||
(let ((version (format "MH %s" (match-string 1))))
|
||||
(erase-buffer)
|
||||
(call-process mhparam nil '(t nil) nil "libdir")
|
||||
(goto-char (point-min))
|
||||
(when (search-forward-regexp "^.*$" nil t)
|
||||
(let ((libdir (match-string 0)))
|
||||
`(,version
|
||||
(variant mh)
|
||||
(mh-lib-progs ,libdir)
|
||||
(mh-lib ,libdir)
|
||||
(mh-progs ,dir)
|
||||
(flists nil)))))))))
|
||||
|
||||
(defun mh-variant-mu-mh-info (dir)
|
||||
"Return info for GNU mailutils variant in DIR.
|
||||
This assumes that a temporary buffer is setup."
|
||||
;; 'mhparam -version' output:
|
||||
;; mhparam (GNU mailutils 0.3.2)
|
||||
(let ((mhparam (expand-file-name "mhparam" dir)))
|
||||
(when (mh-file-command-p mhparam)
|
||||
(erase-buffer)
|
||||
(call-process mhparam nil '(t nil) nil "-version")
|
||||
(goto-char (point-min))
|
||||
(when (search-forward-regexp "mhparam (\\(GNU [Mm]ailutils \\S +\\))"
|
||||
nil t)
|
||||
(let ((version (match-string 1))
|
||||
(mh-progs dir))
|
||||
`(,version
|
||||
(variant mu-mh)
|
||||
(mh-lib-progs ,(mh-profile-component "libdir"))
|
||||
(mh-lib ,(mh-profile-component "etcdir"))
|
||||
(mh-progs ,dir)
|
||||
(flists ,(file-exists-p
|
||||
(expand-file-name "flists" dir)))))))))
|
||||
|
||||
(defun mh-variant-nmh-info (dir)
|
||||
"Return info for nmh variant in DIR assuming a temporary buffer is setup."
|
||||
;; `mhparam -version' outputs:
|
||||
;; mhparam -- nmh-1.1-RC1 [compiled on chaak at Fri Jun 20 11:03:28 PDT 2003]
|
||||
(let ((mhparam (expand-file-name "mhparam" dir)))
|
||||
(when (mh-file-command-p mhparam)
|
||||
(erase-buffer)
|
||||
(call-process mhparam nil '(t nil) nil "-version")
|
||||
(goto-char (point-min))
|
||||
(when (search-forward-regexp "mhparam -- nmh-\\(\\S +\\)" nil t)
|
||||
(let ((version (format "nmh %s" (match-string 1)))
|
||||
(mh-progs dir))
|
||||
`(,version
|
||||
(variant nmh)
|
||||
(mh-lib-progs ,(mh-profile-component "libdir"))
|
||||
(mh-lib ,(mh-profile-component "etcdir"))
|
||||
(mh-progs ,dir)
|
||||
(flists ,(file-exists-p
|
||||
(expand-file-name "flists" dir)))))))))
|
||||
|
||||
(defun mh-file-command-p (file)
|
||||
"Return t if file FILE is the name of a executable regular file."
|
||||
(and (file-regular-p file) (file-executable-p file)))
|
||||
|
||||
(defvar mh-variant-in-use nil
|
||||
"The MH variant currently in use; a string with variant and version number.
|
||||
This differs from `mh-variant' when the latter is set to
|
||||
\"autodetect\".")
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-variant-set (variant)
|
||||
"Set the MH variant to VARIANT.
|
||||
Sets `mh-progs', `mh-lib', `mh-lib-progs' and
|
||||
`mh-flists-present-flag'.
|
||||
If the VARIANT is \"autodetect\", then first try nmh, then MH and
|
||||
finally GNU mailutils."
|
||||
(interactive
|
||||
(list (completing-read
|
||||
"MH variant: "
|
||||
(mapcar (lambda (x) (list (car x))) (mh-variants))
|
||||
nil t)))
|
||||
(let ((valid-list (mapcar (lambda (x) (car x)) (mh-variants))))
|
||||
(cond
|
||||
((eq variant 'none))
|
||||
((eq variant 'autodetect)
|
||||
(cond
|
||||
((mh-variant-set-variant 'nmh)
|
||||
(message "%s installed as MH variant" mh-variant-in-use))
|
||||
((mh-variant-set-variant 'mh)
|
||||
(message "%s installed as MH variant" mh-variant-in-use))
|
||||
((mh-variant-set-variant 'mu-mh)
|
||||
(message "%s installed as MH variant" mh-variant-in-use))
|
||||
(t
|
||||
(message "No MH variant found on the system"))))
|
||||
((member variant valid-list)
|
||||
(when (not (mh-variant-set-variant variant))
|
||||
(message "Warning: %s variant not found. Autodetecting..." variant)
|
||||
(mh-variant-set 'autodetect)))
|
||||
(t
|
||||
(message "Unknown variant; use %s"
|
||||
(mapconcat '(lambda (x) (format "%s" (car x)))
|
||||
(mh-variants) " or "))))))
|
||||
|
||||
(defun mh-variant-set-variant (variant)
|
||||
"Setup the system variables for the MH variant named VARIANT.
|
||||
If VARIANT is a string, use that key in the alist returned by the
|
||||
function `mh-variants'.
|
||||
If VARIANT is a symbol, select the first entry that matches that
|
||||
variant."
|
||||
(cond
|
||||
((stringp variant) ;e.g. "nmh 1.1-RC1"
|
||||
(when (assoc variant (mh-variants))
|
||||
(let* ((alist (cdr (assoc variant (mh-variants))))
|
||||
(lib-progs (cadr (assoc 'mh-lib-progs alist)))
|
||||
(lib (cadr (assoc 'mh-lib alist)))
|
||||
(progs (cadr (assoc 'mh-progs alist)))
|
||||
(flists (cadr (assoc 'flists alist))))
|
||||
;;(set-default mh-variant variant)
|
||||
(setq mh-x-mailer-string nil
|
||||
mh-flists-present-flag flists
|
||||
mh-lib-progs lib-progs
|
||||
mh-lib lib
|
||||
mh-progs progs
|
||||
mh-variant-in-use variant))))
|
||||
((symbolp variant) ;e.g. 'nmh (pick the first match)
|
||||
(loop for variant-list in (mh-variants)
|
||||
when (eq variant (cadr (assoc 'variant (cdr variant-list))))
|
||||
return (let* ((version (car variant-list))
|
||||
(alist (cdr variant-list))
|
||||
(lib-progs (cadr (assoc 'mh-lib-progs alist)))
|
||||
(lib (cadr (assoc 'mh-lib alist)))
|
||||
(progs (cadr (assoc 'mh-progs alist)))
|
||||
(flists (cadr (assoc 'flists alist))))
|
||||
;;(set-default mh-variant flavor)
|
||||
(setq mh-x-mailer-string nil
|
||||
mh-flists-present-flag flists
|
||||
mh-lib-progs lib-progs
|
||||
mh-lib lib
|
||||
mh-progs progs
|
||||
mh-variant-in-use version)
|
||||
t)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-variant-p (&rest variants)
|
||||
"Return t if variant is any of VARIANTS.
|
||||
Currently known variants are 'MH, 'nmh, and 'mu-mh."
|
||||
(let ((variant-in-use
|
||||
(cadr (assoc 'variant (assoc mh-variant-in-use (mh-variants))))))
|
||||
(not (null (member variant-in-use variants)))))
|
||||
|
||||
|
||||
|
||||
;;; Read MH Profile
|
||||
|
||||
(defvar mh-find-path-run nil
|
||||
"Non-nil if `mh-find-path' has been run already.
|
||||
Do not access this variable; `mh-find-path' already uses it to
|
||||
avoid running more than once.")
|
||||
|
||||
(defun mh-find-path ()
|
||||
"Set variables from user's MH profile.
|
||||
|
||||
This function sets `mh-user-path' from your \"Path:\" MH profile
|
||||
component (but defaults to \"Mail\" if one isn't present),
|
||||
`mh-draft-folder' from \"Draft-Folder:\", `mh-unseen-seq' from
|
||||
\"Unseen-Sequence:\", `mh-previous-seq' from
|
||||
\"Previous-Sequence:\", and `mh-inbox' from \"Inbox:\" (defaults
|
||||
to \"+inbox\").
|
||||
|
||||
The hook `mh-find-path-hook' is run after these variables have
|
||||
been set. This hook can be used the change the value of these
|
||||
variables if you need to run with different values between MH and
|
||||
MH-E."
|
||||
(unless mh-find-path-run
|
||||
;; Sanity checks.
|
||||
(if (and (getenv "MH")
|
||||
(not (file-readable-p (getenv "MH"))))
|
||||
(error "MH environment variable contains unreadable file %s"
|
||||
(getenv "MH")))
|
||||
(if (null (mh-variants))
|
||||
(error "Install MH and run install-mh before running MH-E"))
|
||||
(let ((profile "~/.mh_profile"))
|
||||
(if (not (file-readable-p profile))
|
||||
(error "Run install-mh before running MH-E")))
|
||||
;; Read MH profile.
|
||||
(setq mh-user-path (mh-profile-component "Path"))
|
||||
(if (not mh-user-path)
|
||||
(setq mh-user-path "Mail"))
|
||||
(setq mh-user-path
|
||||
(file-name-as-directory
|
||||
(expand-file-name mh-user-path (expand-file-name "~"))))
|
||||
(unless mh-x-image-cache-directory
|
||||
(setq mh-x-image-cache-directory
|
||||
(expand-file-name ".mhe-x-image-cache" mh-user-path)))
|
||||
(setq mh-draft-folder (mh-profile-component "Draft-Folder"))
|
||||
(if mh-draft-folder
|
||||
(progn
|
||||
(if (not (mh-folder-name-p mh-draft-folder))
|
||||
(setq mh-draft-folder (format "+%s" mh-draft-folder)))
|
||||
(if (not (file-exists-p (mh-expand-file-name mh-draft-folder)))
|
||||
(error
|
||||
"Draft folder \"%s\" not found; create it and try again"
|
||||
(mh-expand-file-name mh-draft-folder)))))
|
||||
(setq mh-inbox (mh-profile-component "Inbox"))
|
||||
(cond ((not mh-inbox)
|
||||
(setq mh-inbox "+inbox"))
|
||||
((not (mh-folder-name-p mh-inbox))
|
||||
(setq mh-inbox (format "+%s" mh-inbox))))
|
||||
(setq mh-unseen-seq (mh-profile-component "Unseen-Sequence"))
|
||||
(if mh-unseen-seq
|
||||
(setq mh-unseen-seq (intern mh-unseen-seq))
|
||||
(setq mh-unseen-seq 'unseen)) ;old MH default?
|
||||
(setq mh-previous-seq (mh-profile-component "Previous-Sequence"))
|
||||
(if mh-previous-seq
|
||||
(setq mh-previous-seq (intern mh-previous-seq)))
|
||||
(run-hooks 'mh-find-path-hook)
|
||||
(mh-collect-folder-names)
|
||||
(setq mh-find-path-run t)))
|
||||
|
||||
|
||||
|
||||
;;; MH profile
|
||||
|
||||
(defun mh-profile-component (component)
|
||||
"Return COMPONENT value from mhparam, or nil if unset."
|
||||
(save-excursion
|
||||
(mh-exec-cmd-quiet nil "mhparam" "-components" component)
|
||||
(mh-profile-component-value component)))
|
||||
|
||||
(defun mh-profile-component-value (component)
|
||||
"Find and return the value of COMPONENT in the current buffer.
|
||||
Returns nil if the component is not in the buffer."
|
||||
(let ((case-fold-search t))
|
||||
(goto-char (point-min))
|
||||
(cond ((not (re-search-forward (format "^%s:" component) nil t)) nil)
|
||||
((looking-at "[\t ]*$") nil)
|
||||
(t
|
||||
(re-search-forward "[\t ]*\\([^\t \n].*\\)$" nil t)
|
||||
(let ((start (match-beginning 1)))
|
||||
(end-of-line)
|
||||
(buffer-substring start (point)))))))
|
||||
|
||||
|
||||
|
||||
;;; MH-E images
|
||||
|
||||
;; Shush compiler.
|
||||
(eval-when-compile (defvar image-load-path))
|
||||
|
||||
(defvar mh-image-load-path-called-flag nil)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-image-load-path ()
|
||||
"Ensure that the MH-E images are accessible by `find-image'.
|
||||
Images for MH-E are found in ../../etc/images relative to the
|
||||
files in \"lisp/mh-e\". If `image-load-path' exists (since Emacs
|
||||
22), then the images directory is added to it if isn't already
|
||||
there. Otherwise, the images directory is added to the
|
||||
`load-path' if it isn't already there."
|
||||
(unless mh-image-load-path-called-flag
|
||||
(let (mh-library-name mh-image-load-path)
|
||||
;; First, find mh-e in the load-path.
|
||||
(setq mh-library-name (locate-library "mh-e"))
|
||||
(if (not mh-library-name)
|
||||
(error "Can not find MH-E in load-path"))
|
||||
(setq mh-image-load-path
|
||||
(expand-file-name (concat (file-name-directory mh-library-name)
|
||||
"../../etc/images")))
|
||||
(if (not (file-exists-p mh-image-load-path))
|
||||
(error "Can not find image directory %s" mh-image-load-path))
|
||||
(if (boundp 'image-load-path)
|
||||
(add-to-list 'image-load-path mh-image-load-path)
|
||||
(add-to-list 'load-path mh-image-load-path)))
|
||||
(setq mh-image-load-path-called-flag t)))
|
||||
|
||||
|
||||
|
||||
;;; Support routines for mh-customize.el
|
||||
|
||||
(defvar mh-min-colors-defined-flag (and (not mh-xemacs-flag)
|
||||
(>= emacs-major-version 22))
|
||||
"Non-nil means defface supports min-colors display requirement.")
|
||||
|
||||
(defun mh-defface-compat (spec)
|
||||
"Convert SPEC for defface if necessary to run on older platforms.
|
||||
Modifies SPEC in place and returns it. See `defface' for the spec definition.
|
||||
|
||||
When `mh-min-colors-defined-flag' is nil, this function finds
|
||||
display entries with \"min-colors\" requirements and either
|
||||
removes the \"min-colors\" requirement or strips the display
|
||||
entirely if the display does not support the number of specified
|
||||
colors."
|
||||
(if mh-min-colors-defined-flag
|
||||
spec
|
||||
(let ((cells (display-color-cells))
|
||||
new-spec)
|
||||
;; Remove entries with min-colors, or delete them if we have fewer colors
|
||||
;; than they specify.
|
||||
(loop for entry in (reverse spec) do
|
||||
(let ((requirement (if (eq (car entry) t)
|
||||
nil
|
||||
(assoc 'min-colors (car entry)))))
|
||||
(if requirement
|
||||
(when (>= cells (nth 1 requirement))
|
||||
(setq new-spec (cons (cons (delq requirement (car entry))
|
||||
(cdr entry))
|
||||
new-spec)))
|
||||
(setq new-spec (cons entry new-spec)))))
|
||||
new-spec)))
|
||||
|
||||
(provide 'mh-init)
|
||||
|
||||
;; Local Variables:
|
||||
;; indent-tabs-mode: nil
|
||||
;; sentence-end-double-space: nil
|
||||
;; End:
|
||||
|
||||
;; arch-tag: e8372aeb-d803-42b1-9c95-3c93ad22f63c
|
||||
;;; mh-init.el ends here
|
@ -1,4 +1,4 @@
|
||||
;;; mh-junk.el --- Interface to anti-spam measures
|
||||
;;; mh-junk.el --- MH-E interface to anti-spam measures
|
||||
|
||||
;; Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
@ -32,14 +32,10 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;(message "< mh-junk")
|
||||
(eval-when-compile (require 'mh-acros))
|
||||
(mh-require-cl)
|
||||
(require 'mh-buffers)
|
||||
(require 'mh-e)
|
||||
;;(message "> mh-junk")
|
||||
(require 'mh-scan)
|
||||
(mh-require-cl)
|
||||
|
||||
;; Interactive functions callable from the folder buffer
|
||||
;;;###mh-autoload
|
||||
(defun mh-junk-blacklist (range)
|
||||
"Blacklist RANGE as spam.
|
||||
@ -108,6 +104,7 @@ RANGE is read in interactive use."
|
||||
(defvar mh-spamassassin-executable (executable-find "spamassassin"))
|
||||
(defvar mh-sa-learn-executable (executable-find "sa-learn"))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-spamassassin-blacklist (msg)
|
||||
"Blacklist MSG with SpamAssassin.
|
||||
|
||||
@ -189,7 +186,7 @@ SpamAssassin, rebuilds the database after adding words, so you
|
||||
will need to run \"sa-learn --rebuild\" periodically. This can be
|
||||
done by adding the following to your crontab:
|
||||
|
||||
0 * * * * sa-learn --rebuild > /dev/null 2>&1"
|
||||
0 * * * * sa-learn --rebuild > /dev/null 2>&1"
|
||||
(unless mh-spamassassin-executable
|
||||
(error "Unable to find the spamassassin executable"))
|
||||
(let ((current-folder mh-current-folder)
|
||||
@ -220,6 +217,7 @@ done by adding the following to your crontab:
|
||||
(message "Blacklisting message %d...done" msg))
|
||||
(message "Blacklisting message %d...not done (from my address)" msg)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-spamassassin-whitelist (msg)
|
||||
"Whitelist MSG with SpamAssassin.
|
||||
|
||||
@ -273,6 +271,7 @@ The name of the rule is RULE and its body is BODY."
|
||||
(if (not buffer-exists)
|
||||
(kill-buffer nil)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-spamassassin-identify-spammers ()
|
||||
"Identify spammers who are repeat offenders.
|
||||
|
||||
@ -322,6 +321,7 @@ information can be used so that you can replace multiple
|
||||
|
||||
(defvar mh-bogofilter-executable (executable-find "bogofilter"))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-bogofilter-blacklist (msg)
|
||||
"Blacklist MSG with bogofilter.
|
||||
|
||||
@ -375,6 +375,7 @@ The \"Bogofilter tuning HOWTO\" describes how you can fine-tune Bogofilter."
|
||||
(call-process mh-bogofilter-executable msg-file mh-junk-background
|
||||
nil "-s")))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-bogofilter-whitelist (msg)
|
||||
"Whitelist MSG with bogofilter.
|
||||
|
||||
@ -391,6 +392,7 @@ See `mh-bogofilter-blacklist' for more information."
|
||||
|
||||
(defvar mh-spamprobe-executable (executable-find "spamprobe"))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-spamprobe-blacklist (msg)
|
||||
"Blacklist MSG with SpamProbe.
|
||||
|
||||
@ -421,6 +423,7 @@ update SpamProbe's training."
|
||||
(call-process mh-spamprobe-executable msg-file mh-junk-background
|
||||
nil "spam")))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-spamprobe-whitelist (msg)
|
||||
"Whitelist MSG with SpamProbe.
|
||||
|
||||
|
1040
lisp/mh-e/mh-letter.el
Normal file
1040
lisp/mh-e/mh-letter.el
Normal file
File diff suppressed because it is too large
Load Diff
329
lisp/mh-e/mh-limit.el
Normal file
329
lisp/mh-e/mh-limit.el
Normal file
@ -0,0 +1,329 @@
|
||||
;;; mh-limit.el --- MH-E display limits
|
||||
|
||||
;; Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Peter S. Galbraith <psg@debian.org>
|
||||
;; 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., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; "Poor man's threading" by psg.
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'mh-e)
|
||||
(mh-require-cl)
|
||||
(require 'mh-scan)
|
||||
|
||||
(autoload 'message-fetch-field "message")
|
||||
|
||||
|
||||
|
||||
;;; MH-Folder Commands
|
||||
|
||||
;; Alphabetical.
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-delete-subject ()
|
||||
"Delete messages with same subject\\<mh-folder-mode-map>.
|
||||
|
||||
To delete messages faster, you can use this command to delete all
|
||||
the messages with the same subject as the current message. This
|
||||
command puts these messages in a sequence named \"subject\". You
|
||||
can undo this action by using \\[mh-undo] with a prefix argument
|
||||
and then specifying the \"subject\" sequence."
|
||||
(interactive)
|
||||
(let ((count (mh-subject-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)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-delete-subject-or-thread ()
|
||||
"Delete messages with same subject or thread\\<mh-folder-mode-map>.
|
||||
|
||||
To delete messages faster, you can use this command to delete all
|
||||
the messages with the same subject as the current message. This
|
||||
command puts these messages in a sequence named \"subject\". You
|
||||
can undo this action by using \\[mh-undo] with a prefix argument
|
||||
and then specifying the \"subject\" sequence.
|
||||
|
||||
However, if the buffer is displaying a threaded view of the
|
||||
folder then this command behaves like \\[mh-thread-delete]."
|
||||
(interactive)
|
||||
(if (memq 'unthread mh-view-ops)
|
||||
(mh-thread-delete)
|
||||
(mh-delete-subject)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-narrow-to-cc (&optional pick-expr)
|
||||
"Limit to messages with the same \"Cc:\" field.
|
||||
With a prefix argument, edit PICK-EXPR.
|
||||
|
||||
Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
|
||||
(interactive
|
||||
(list (mh-edit-pick-expr (mh-current-message-header-field 'cc))))
|
||||
(mh-narrow-to-header-field 'cc pick-expr))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-narrow-to-from (&optional pick-expr)
|
||||
"Limit to messages with the same \"From:\" field.
|
||||
With a prefix argument, edit PICK-EXPR.
|
||||
|
||||
Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
|
||||
(interactive
|
||||
(list (mh-edit-pick-expr (mh-current-message-header-field 'from))))
|
||||
(mh-narrow-to-header-field 'from pick-expr))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-narrow-to-range (range)
|
||||
"Limit to RANGE.
|
||||
|
||||
Check the documentation of `mh-interactive-range' to see how
|
||||
RANGE is read in interactive use.
|
||||
|
||||
Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
|
||||
(interactive (list (mh-interactive-range "Narrow to")))
|
||||
(when (assoc 'range mh-seq-list) (mh-delete-seq 'range))
|
||||
(mh-add-msgs-to-seq (mh-range-to-msg-list range) 'range)
|
||||
(mh-narrow-to-seq 'range))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-narrow-to-subject (&optional pick-expr)
|
||||
"Limit to messages with same subject.
|
||||
With a prefix argument, edit PICK-EXPR.
|
||||
|
||||
Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
|
||||
(interactive
|
||||
(list (mh-edit-pick-expr (mh-current-message-header-field 'subject))))
|
||||
(mh-narrow-to-header-field 'subject pick-expr))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-narrow-to-to (&optional pick-expr)
|
||||
"Limit to messages with the same \"To:\" field.
|
||||
With a prefix argument, edit PICK-EXPR.
|
||||
|
||||
Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
|
||||
(interactive
|
||||
(list (mh-edit-pick-expr (mh-current-message-header-field 'to))))
|
||||
(mh-narrow-to-header-field 'to pick-expr))
|
||||
|
||||
|
||||
|
||||
;;; Support Routines
|
||||
|
||||
(defun mh-subject-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 (memq 'unthread mh-view-ops)
|
||||
(mh-subject-to-sequence-threaded all)
|
||||
(mh-subject-to-sequence-unthreaded all)))
|
||||
|
||||
(defun mh-subject-to-sequence-threaded (all)
|
||||
"Put all messages with the same subject in the 'subject sequence.
|
||||
|
||||
This function works when the folder is threaded. In this
|
||||
situation the subject could get truncated and so the normal
|
||||
matching doesn't work.
|
||||
|
||||
The parameter ALL is non-nil then all the messages in the buffer
|
||||
are considered, otherwise only the messages after the current one
|
||||
are taken into account."
|
||||
(let* ((cur (mh-get-msg-num nil))
|
||||
(subject (mh-thread-find-msg-subject cur))
|
||||
region msgs)
|
||||
(if (null subject)
|
||||
(and (message "No subject line") nil)
|
||||
(setq region (cons (if all (point-min) (point)) (point-max)))
|
||||
(mh-iterate-on-range msg region
|
||||
(when (eq (mh-thread-find-msg-subject msg) subject)
|
||||
(push msg msgs)))
|
||||
(setq msgs (sort msgs #'mh-lessp))
|
||||
(if (null msgs)
|
||||
0
|
||||
(when (assoc 'subject mh-seq-list)
|
||||
(mh-delete-seq 'subject))
|
||||
(mh-add-msgs-to-seq msgs 'subject)
|
||||
(length msgs)))))
|
||||
|
||||
(defvar mh-limit-max-subject-size 41
|
||||
"Maximum size of the subject part.
|
||||
It would be desirable to avoid hard-coding this.")
|
||||
|
||||
(defun mh-subject-to-sequence-unthreaded (all)
|
||||
"Put all following messages with same subject in sequence 'subject.
|
||||
|
||||
This function only works with an unthreaded folder. 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 3))
|
||||
(string-equal "" (match-string 3)))
|
||||
(progn (message "No subject line")
|
||||
nil)
|
||||
(let ((subject (match-string-no-properties 3))
|
||||
(list))
|
||||
(if (> (length subject) mh-limit-max-subject-size)
|
||||
(setq subject (substring subject 0 mh-limit-max-subject-size)))
|
||||
(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 3)))
|
||||
(if (> (length this-subject) mh-limit-max-subject-size)
|
||||
(setq this-subject (substring this-subject
|
||||
0 mh-limit-max-subject-size)))
|
||||
(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)))
|
||||
(if (assoc 'subject mh-seq-list) (mh-delete-seq 'subject))
|
||||
;; sort the result into a sequence
|
||||
(let ((sorted-list (sort (copy-sequence list) 'mh-lessp)))
|
||||
(while sorted-list
|
||||
(mh-add-msgs-to-seq (car sorted-list) 'subject nil)
|
||||
(setq sorted-list (cdr sorted-list)))
|
||||
(safe-length list)))
|
||||
(t
|
||||
0))))))
|
||||
|
||||
(defun mh-edit-pick-expr (default)
|
||||
"With prefix arg edit a pick expression.
|
||||
If no prefix arg is given, then return DEFAULT."
|
||||
(let ((default-string (loop for x in default concat (format " %s" x))))
|
||||
(if (or current-prefix-arg (equal default-string ""))
|
||||
(mh-pick-args-list (read-string "Pick expression: "
|
||||
default-string))
|
||||
default)))
|
||||
|
||||
(defun mh-pick-args-list (s)
|
||||
"Form list by grouping elements in string S suitable for pick arguments.
|
||||
For example, the string \"-subject a b c -from Joe User
|
||||
<user@domain.com>\" is converted to (\"-subject\" \"a b c\"
|
||||
\"-from\" \"Joe User <user@domain.com>\""
|
||||
(let ((full-list (split-string s))
|
||||
current-arg collection arg-list)
|
||||
(while full-list
|
||||
(setq current-arg (car full-list))
|
||||
(if (null (string-match "^-" current-arg))
|
||||
(setq collection
|
||||
(if (null collection)
|
||||
current-arg
|
||||
(format "%s %s" collection current-arg)))
|
||||
(when collection
|
||||
(setq arg-list (append arg-list (list collection)))
|
||||
(setq collection nil))
|
||||
(setq arg-list (append arg-list (list current-arg))))
|
||||
(setq full-list (cdr full-list)))
|
||||
(when collection
|
||||
(setq arg-list (append arg-list (list collection))))
|
||||
arg-list))
|
||||
|
||||
(defun mh-current-message-header-field (header-field)
|
||||
"Return a pick regexp to match HEADER-FIELD of the message at point."
|
||||
(let ((num (mh-get-msg-num nil)))
|
||||
(when num
|
||||
(let ((folder mh-current-folder))
|
||||
(with-temp-buffer
|
||||
(insert-file-contents-literally (mh-msg-filename num folder))
|
||||
(goto-char (point-min))
|
||||
(when (search-forward "\n\n" nil t)
|
||||
(narrow-to-region (point-min) (point)))
|
||||
(let* ((field (or (message-fetch-field (format "%s" header-field))
|
||||
""))
|
||||
(field-option (format "-%s" header-field))
|
||||
(patterns (loop for x in (split-string field "[ ]*,[ ]*")
|
||||
unless (equal x "")
|
||||
collect (if (string-match "<\\(.*@.*\\)>" x)
|
||||
(match-string 1 x)
|
||||
x))))
|
||||
(when patterns
|
||||
(loop with accum = `(,field-option ,(car patterns))
|
||||
for e in (cdr patterns)
|
||||
do (setq accum `(,field-option ,e "-or" ,@accum))
|
||||
finally return accum))))))))
|
||||
|
||||
(defun mh-narrow-to-header-field (header-field pick-expr)
|
||||
"Limit to messages whose HEADER-FIELD match PICK-EXPR.
|
||||
The MH command pick is used to do the match."
|
||||
(let ((folder mh-current-folder)
|
||||
(original (mh-coalesce-msg-list
|
||||
(mh-range-to-msg-list (cons (point-min) (point-max)))))
|
||||
(msg-list ()))
|
||||
(with-temp-buffer
|
||||
(apply #'mh-exec-cmd-output "pick" nil folder
|
||||
(append original (list "-list") pick-expr))
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
(let ((num (ignore-errors
|
||||
(string-to-number
|
||||
(buffer-substring (point) (line-end-position))))))
|
||||
(when num (push num msg-list))
|
||||
(forward-line))))
|
||||
(if (null msg-list)
|
||||
(message "No matches")
|
||||
(when (assoc 'header mh-seq-list) (mh-delete-seq 'header))
|
||||
(mh-add-msgs-to-seq msg-list 'header)
|
||||
(mh-narrow-to-seq 'header))))
|
||||
|
||||
(provide 'mh-limit)
|
||||
|
||||
;; Local Variables:
|
||||
;; indent-tabs-mode: nil
|
||||
;; sentence-end-double-space: nil
|
||||
;; End:
|
||||
|
||||
;;; mh-limit.el ends here
|
2549
lisp/mh-e/mh-mime.el
2549
lisp/mh-e/mh-mime.el
File diff suppressed because it is too large
Load Diff
@ -30,15 +30,10 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;(message "> mh-print")
|
||||
(eval-when-compile (require 'mh-acros))
|
||||
(mh-require-cl)
|
||||
(require 'mh-e)
|
||||
(require 'mh-scan)
|
||||
|
||||
(require 'ps-print)
|
||||
(require 'mh-buffers)
|
||||
(require 'mh-utils)
|
||||
(require 'mh-funcs)
|
||||
(eval-when-compile (require 'mh-seq))
|
||||
;;(message "< mh-print")
|
||||
|
||||
(defvar mh-ps-print-color-option ps-print-color-p
|
||||
"Specify how buffer's text color is printed.
|
||||
@ -48,7 +43,7 @@ Valid values are:
|
||||
nil - Do not print colors.
|
||||
t - Print colors.
|
||||
black-white - Print colors on black/white printer.
|
||||
See also `ps-black-white-faces'.
|
||||
See also `ps-black-white-faces'.
|
||||
|
||||
Any other value is treated as t. This variable is initialized
|
||||
from `ps-print-color-p'.")
|
||||
@ -59,54 +54,6 @@ from `ps-print-color-p'.")
|
||||
Sensible choices are the functions `ps-spool-buffer' and
|
||||
`ps-spool-buffer-with-faces'.")
|
||||
|
||||
(defun mh-ps-spool-buffer (buffer)
|
||||
"Spool BUFFER."
|
||||
(save-excursion
|
||||
(set-buffer buffer)
|
||||
(let ((ps-print-color-p mh-ps-print-color-option)
|
||||
(ps-left-header
|
||||
(list
|
||||
(concat "(" (mh-get-header-field "Subject:") ")")
|
||||
(concat "(" (mh-get-header-field "From:") ")")))
|
||||
(ps-right-header
|
||||
(list
|
||||
"/pagenumberstring load"
|
||||
(concat "(" (mh-get-header-field "Date:") ")"))))
|
||||
(funcall mh-ps-print-func))))
|
||||
|
||||
(defun mh-ps-spool-msg (msg)
|
||||
"Spool MSG."
|
||||
(let* ((folder mh-current-folder)
|
||||
(buffer (mh-in-show-buffer (mh-show-buffer)
|
||||
(if (not (equal (mh-msg-filename msg folder)
|
||||
buffer-file-name))
|
||||
(get-buffer-create mh-temp-buffer)))))
|
||||
(unwind-protect
|
||||
(save-excursion
|
||||
(if buffer
|
||||
(let ((mh-show-buffer buffer))
|
||||
(mh-display-msg msg folder)))
|
||||
(mh-ps-spool-buffer (if buffer buffer mh-show-buffer)))
|
||||
(if buffer
|
||||
(kill-buffer buffer)))))
|
||||
|
||||
(defun mh-ps-print-range (range file)
|
||||
"Print RANGE to FILE.
|
||||
|
||||
This is the function that actually does the work.
|
||||
If FILE is nil, then the messages are spooled to the printer."
|
||||
(mh-iterate-on-range msg range
|
||||
(unwind-protect
|
||||
(mh-ps-spool-msg msg))
|
||||
(mh-notate msg mh-note-printed mh-cmd-note))
|
||||
(ps-despool file))
|
||||
|
||||
(defun mh-ps-print-preprint (prefix-arg)
|
||||
"Provide a better default file name for `ps-print-preprint'.
|
||||
Pass along the PREFIX-ARG to it."
|
||||
(let ((buffer-file-name (format "mh-%s" (substring (buffer-name) 1))))
|
||||
(ps-print-preprint prefix-arg)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-ps-print-msg (range)
|
||||
"Print RANGE\\<mh-folder-mode-map>.
|
||||
@ -130,6 +77,48 @@ commands \\[mh-ps-print-toggle-color] and
|
||||
(interactive (list (mh-interactive-range "Print")))
|
||||
(mh-ps-print-range range nil))
|
||||
|
||||
(defun mh-ps-print-range (range file)
|
||||
"Print RANGE to FILE.
|
||||
|
||||
This is the function that actually does the work.
|
||||
If FILE is nil, then the messages are spooled to the printer."
|
||||
(mh-iterate-on-range msg range
|
||||
(unwind-protect
|
||||
(mh-ps-spool-msg msg))
|
||||
(mh-notate msg mh-note-printed mh-cmd-note))
|
||||
(ps-despool file))
|
||||
|
||||
(defun mh-ps-spool-msg (msg)
|
||||
"Spool MSG."
|
||||
(let* ((folder mh-current-folder)
|
||||
(buffer (mh-in-show-buffer (mh-show-buffer)
|
||||
(if (not (equal (mh-msg-filename msg folder)
|
||||
buffer-file-name))
|
||||
(get-buffer-create mh-temp-buffer)))))
|
||||
(unwind-protect
|
||||
(save-excursion
|
||||
(if buffer
|
||||
(let ((mh-show-buffer buffer))
|
||||
(mh-display-msg msg folder)))
|
||||
(mh-ps-spool-buffer (if buffer buffer mh-show-buffer)))
|
||||
(if buffer
|
||||
(kill-buffer buffer)))))
|
||||
|
||||
(defun mh-ps-spool-buffer (buffer)
|
||||
"Spool BUFFER."
|
||||
(save-excursion
|
||||
(set-buffer buffer)
|
||||
(let ((ps-print-color-p mh-ps-print-color-option)
|
||||
(ps-left-header
|
||||
(list
|
||||
(concat "(" (mh-get-header-field "Subject:") ")")
|
||||
(concat "(" (mh-get-header-field "From:") ")")))
|
||||
(ps-right-header
|
||||
(list
|
||||
"/pagenumberstring load"
|
||||
(concat "(" (mh-get-header-field "Date:") ")"))))
|
||||
(funcall mh-ps-print-func))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-ps-print-msg-file (range file)
|
||||
"Print RANGE to FILE\\<mh-folder-mode-map>.
|
||||
@ -153,6 +142,12 @@ commands \\[mh-ps-print-toggle-color] and
|
||||
(interactive (list (mh-interactive-range "Print") (mh-ps-print-preprint 1)))
|
||||
(mh-ps-print-range range file))
|
||||
|
||||
(defun mh-ps-print-preprint (prefix-arg)
|
||||
"Provide a better default file name for `ps-print-preprint'.
|
||||
Pass along the PREFIX-ARG to it."
|
||||
(let ((buffer-file-name (format "mh-%s" (substring (buffer-name) 1))))
|
||||
(ps-print-preprint prefix-arg)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-ps-print-toggle-faces ()
|
||||
"Toggle whether printing is done with faces or not.
|
||||
@ -185,8 +180,8 @@ change this setting permanently by customizing the option
|
||||
(message "Colors will be printed as black & white"))
|
||||
(if (eq mh-ps-print-color-option 'black-white)
|
||||
(progn
|
||||
(setq mh-ps-print-color-option t)
|
||||
(message "Colors will be printed"))
|
||||
(setq mh-ps-print-color-option t)
|
||||
(message "Colors will be printed"))
|
||||
(setq mh-ps-print-color-option nil)
|
||||
(message "Colors will not be printed"))))
|
||||
|
||||
|
490
lisp/mh-e/mh-scan.el
Normal file
490
lisp/mh-e/mh-scan.el
Normal file
@ -0,0 +1,490 @@
|
||||
;;; mh-scan.el --- MH-E scan line constants and utilities
|
||||
|
||||
;; Copyright (C) 1993, 1995, 1997,
|
||||
;; 2000, 2001, 2002, 2003, 2004, 2005, 2006 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.
|
||||
|
||||
;; 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., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file contains constants and a few functions for interpreting
|
||||
;; scan lines.
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'mh-e)
|
||||
|
||||
|
||||
|
||||
;;; Scan Formats
|
||||
|
||||
;; The following scan formats are passed to the scan program if the setting of
|
||||
;; `mh-scan-format-file' is t. They are identical except the later one makes
|
||||
;; use of the nmh `decode' function to decode RFC 2047 encodings. If you just
|
||||
;; want to change the column of the notations, use the `mh-set-cmd-note'
|
||||
;; function.
|
||||
|
||||
(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.
|
||||
This string is passed to the scan program via the -format
|
||||
argument. This format is identical to the default except that
|
||||
additional hints for fontification have been added to the fifth
|
||||
column (remember that in Emacs, the first column is 0).
|
||||
|
||||
The values of the fifth 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.
|
||||
This string is passed 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 fifth
|
||||
column (remember that in Emacs, the first column is 0).
|
||||
|
||||
The values of the fifth column, in priority order, are: \"-\" if
|
||||
the message has been replied to, t if an address on the To: field
|
||||
matches one of the mailboxes of the current user, \"c\" if the Cc:
|
||||
field matches, \"b\" if the Bcc: field matches, and \"n\" if a
|
||||
non-empty Newsgroups: field is present.")
|
||||
|
||||
|
||||
|
||||
;;; Regular Expressions
|
||||
|
||||
;; Alphabetical.
|
||||
|
||||
(defvar mh-scan-body-regexp "\\(<<\\([^\n]+\\)?\\)"
|
||||
"This regular expression matches the message body fragment.
|
||||
|
||||
Note that the default setting of `mh-folder-font-lock-keywords'
|
||||
expects this expression to contain at least one parenthesized
|
||||
expression which matches the body text as in the default of
|
||||
\"\\\\(<<\\\\([^\\n]+\\\\)?\\\\)\". If this regular expression is
|
||||
not correct, the body fragment will not be highlighted with the
|
||||
face `mh-folder-body'.")
|
||||
|
||||
(defvar mh-scan-cur-msg-number-regexp "^\\( *[0-9]+\\+\\).*"
|
||||
"This regular expression matches the current message.
|
||||
|
||||
It must match from the beginning of the line. Note that the
|
||||
default setting of `mh-folder-font-lock-keywords' expects this
|
||||
expression to contain at least one parenthesized expression which
|
||||
matches the message number as in the default of
|
||||
|
||||
\"^\\\\( *[0-9]+\\\\+\\\\).*\".
|
||||
|
||||
This expression includes the leading space and current message
|
||||
marker \"+\" within the parenthesis since it looks better to
|
||||
highlight these items as well. The highlighting is done with the
|
||||
face `mh-folder-cur-msg-number'. This regular expression should
|
||||
be correct as it is needed by non-fontification functions. See
|
||||
also `mh-note-cur'.")
|
||||
|
||||
(defvar mh-scan-date-regexp "\\([0-9][0-9]/[0-9][0-9]\\)"
|
||||
"This regular expression matches a valid date.
|
||||
|
||||
It must not be anchored to the beginning or the end of the line.
|
||||
Note that the default setting of `mh-folder-font-lock-keywords'
|
||||
expects this expression to contain only one parenthesized
|
||||
expression which matches the date field as in the default of
|
||||
\"\\\\([0-9][0-9]/[0-9][0-9]\\\\)\"}. If this regular expression
|
||||
is not correct, the date will not be highlighted with the face
|
||||
`mh-folder-date'.")
|
||||
|
||||
(defvar mh-scan-deleted-msg-regexp "^\\( *[0-9]+\\)D"
|
||||
"This regular expression matches deleted messages.
|
||||
|
||||
It must match from the beginning of the line. Note that the
|
||||
default setting of `mh-folder-font-lock-keywords' expects this
|
||||
expression to contain at least one parenthesized expression which
|
||||
matches the message number as in the default of
|
||||
|
||||
\"^\\\\( *[0-9]+\\\\)D\".
|
||||
|
||||
This expression includes the leading space within the parenthesis
|
||||
since it looks better to highlight it as well. The highlighting
|
||||
is done with the face `mh-folder-deleted'. This regular
|
||||
expression should be correct as it is needed by non-fontification
|
||||
functions. See also `mh-note-deleted'.")
|
||||
|
||||
(defvar mh-scan-good-msg-regexp "^\\( *[0-9]+\\)[^D^0-9]"
|
||||
"This regular expression matches \"good\" messages.
|
||||
|
||||
It must match from the beginning of the line. Note that the
|
||||
default setting of `mh-folder-font-lock-keywords' expects this
|
||||
expression to contain at least one parenthesized expression which
|
||||
matches the message number as in the default of
|
||||
|
||||
\"^\\\\( *[0-9]+\\\\)[^D^0-9]\".
|
||||
|
||||
This expression includes the leading space within the parenthesis
|
||||
since it looks better to highlight it as well. The highlighting
|
||||
is done with the face `mh-folder-msg-number'. This regular
|
||||
expression should be correct as it is needed by non-fontification
|
||||
functions.")
|
||||
|
||||
(defvar mh-scan-msg-format-regexp "%\\([0-9]*\\)(msg)"
|
||||
"This regular expression finds the message number width in a scan format.
|
||||
|
||||
Note that the message number must be placed in a parenthesized
|
||||
expression as in the default of \"%\\\\([0-9]*\\\\)(msg)\". This
|
||||
variable is only consulted if `mh-scan-format-file' is set to
|
||||
\"Use MH-E scan Format\".")
|
||||
|
||||
(defvar mh-scan-msg-format-string "%d"
|
||||
"This is a format string for width of the message number in a scan format.
|
||||
|
||||
Use \"0%d\" for zero-filled message numbers. This variable is only
|
||||
consulted if `mh-scan-format-file' is set to \"Use MH-E scan
|
||||
Format\".")
|
||||
|
||||
(defvar mh-scan-msg-number-regexp "^ *\\([0-9]+\\)"
|
||||
"This regular expression extracts the message number.
|
||||
|
||||
It must match from the beginning of the line. Note that the
|
||||
message number must be placed in a parenthesized expression as in
|
||||
the default of \"^ *\\\\([0-9]+\\\\)\".")
|
||||
|
||||
(defvar mh-scan-msg-overflow-regexp "^[?0-9][0-9]"
|
||||
"This regular expression matches overflowed message numbers.")
|
||||
|
||||
(defvar mh-scan-msg-search-regexp "^[^0-9]*%d[^0-9]"
|
||||
"This regular expression matches a particular message.
|
||||
|
||||
It is a format string; use \"%d\" to represent the location of the
|
||||
message number within the expression as in the default of
|
||||
\"^[^0-9]*%d[^0-9]\".")
|
||||
|
||||
(defvar mh-scan-rcpt-regexp "\\(To:\\)\\(..............\\)"
|
||||
"This regular expression specifies the recipient in messages you sent.
|
||||
|
||||
Note that the default setting of `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 as in the default of
|
||||
\"\\\\(To:\\\\)\\\\(..............\\\\)\". If this regular
|
||||
expression is not correct, the \"To:\" string will not be
|
||||
highlighted with the face `mh-folder-to' and the recipient will
|
||||
not be highlighted with the face `mh-folder-address'")
|
||||
|
||||
(defvar mh-scan-refiled-msg-regexp "^\\( *[0-9]+\\)\\^"
|
||||
"This regular expression matches refiled messages.
|
||||
|
||||
It must match from the beginning of the line. Note that the
|
||||
default setting of `mh-folder-font-lock-keywords' expects this
|
||||
expression to contain at least one parenthesized expression which
|
||||
matches the message number as in the default of
|
||||
|
||||
\"^\\\\( *[0-9]+\\\\)\\\\^\".
|
||||
|
||||
This expression includes the leading space within the parenthesis
|
||||
since it looks better to highlight it as well. The highlighting
|
||||
is done with the face `mh-folder-refiled'. This regular
|
||||
expression should be correct as it is needed by non-fontification
|
||||
functions. See also `mh-note-refiled'.")
|
||||
|
||||
(defvar mh-scan-sent-to-me-sender-regexp
|
||||
"^ *[0-9]+.\\([bct]\\).....[ ]*\\(..................\\)"
|
||||
"This regular expression matches messages sent to us.
|
||||
|
||||
Note that the default setting of `mh-folder-font-lock-keywords'
|
||||
expects this expression to contain at least two parenthesized
|
||||
expressions. The first should match the fontification hint (see
|
||||
`mh-scan-format-nmh') and the second should match the user name
|
||||
as in the default of
|
||||
|
||||
^ *[0-9]+.\\\\([bct]\\\\).....[ ]*\\\\(..................\\\\)
|
||||
|
||||
If this regular expression is not correct, the notation hints
|
||||
will not be highlighted with the face
|
||||
`mh-mh-folder-sent-to-me-hint' and the sender will not be
|
||||
highlighted with the face `mh-folder-sent-to-me-sender'.")
|
||||
|
||||
(defvar mh-scan-subject-regexp
|
||||
"^ *[0-9]+........[ ]*...................\\([Rr][Ee]\\(\\[[0-9]+\\]\\)?:\\s-*\\)*\\([^<\n]*\\)"
|
||||
"This regular expression matches the subject.
|
||||
|
||||
It must match from the beginning of the line. Note that the
|
||||
default setting of `mh-folder-font-lock-keywords' expects this
|
||||
expression to contain at least three parenthesized expressions.
|
||||
The first is expected to match the \"Re:\" string, if any, and is
|
||||
highlighted with the face `mh-folder-followup'. The second
|
||||
matches an optional bracketed number after \"Re:\", such as in
|
||||
\"Re[2]:\" (and is thus a sub-expression of the first expression)
|
||||
and the third is expected to match the subject line itself which
|
||||
is highlighted with the face `mh-folder-subject'. For example,
|
||||
the default (broken on multiple lines for readability) is
|
||||
|
||||
^ *[0-9]+........[ ]*...................
|
||||
\\\\([Rr][Ee]\\\\(\\\\\\=[[0-9]+\\\\]\\\\)?:\\\\s-*\\\\)*
|
||||
\\\\([^<\\n]*\\\\)
|
||||
|
||||
This regular expression should be correct as it is needed by
|
||||
non-fontification functions.")
|
||||
|
||||
(defvar mh-scan-valid-regexp "^ *[0-9]"
|
||||
"This regular expression describes a valid scan line.
|
||||
|
||||
This is used to eliminate error messages that are occasionally
|
||||
produced by \"inc\".")
|
||||
|
||||
|
||||
|
||||
;;; Widths, Offsets and Columns
|
||||
|
||||
(defvar mh-cmd-note 4
|
||||
"Column for notations.
|
||||
|
||||
This variable should be set with the function `mh-set-cmd-note'.
|
||||
This variable may be updated dynamically if
|
||||
`mh-adaptive-cmd-note-flag' is on.
|
||||
|
||||
Note that columns in Emacs start with 0.")
|
||||
(make-variable-buffer-local 'mh-cmd-note)
|
||||
|
||||
(defvar mh-scan-cmd-note-width 1
|
||||
"Number of columns consumed by the cmd-note field in `mh-scan-format'.
|
||||
|
||||
This column will have one of the values: \" \", \"D\", \"^\", \"+\" and
|
||||
where \" \" is the default value,
|
||||
|
||||
\"D\" is the `mh-note-deleted' character,
|
||||
\"^\" is the `mh-note-refiled' character, and
|
||||
\"+\" is the `mh-note-cur' character.")
|
||||
|
||||
(defvar mh-scan-destination-width 1
|
||||
"Number of columns consumed by the destination field in `mh-scan-format'.
|
||||
|
||||
This column will have one of \" \", \"%\", \"-\", \"t\", \"c\", \"b\", or \"n\"
|
||||
in it.
|
||||
|
||||
\" \" blank space is the default character.
|
||||
\"%\" indicates that the message in in a named MH sequence.
|
||||
\"-\" indicates that the message has been annotated with a replied field.
|
||||
\"t\" indicates that the message contains mymbox in the To: field.
|
||||
\"c\" indicates that the message contains mymbox in the Cc: field.
|
||||
\"b\" indicates that the message contains mymbox in the Bcc: field.
|
||||
\"n\" indicates that the message contains a Newsgroups: field.")
|
||||
|
||||
(defvar mh-scan-date-width 5
|
||||
"Number of columns consumed by the date field in `mh-scan-format'.
|
||||
This column will typically be of the form mm/dd.")
|
||||
|
||||
(defvar mh-scan-date-flag-width 1
|
||||
"Number of columns consumed to flag (in)valid dates in `mh-scan-format'.
|
||||
This column will have \" \" for valid and \"*\" for invalid or
|
||||
missing dates.")
|
||||
|
||||
(defvar mh-scan-from-mbox-width 17
|
||||
"Number of columns consumed with the \"From:\" line in `mh-scan-format'.
|
||||
This column will have a friendly name or e-mail address of the
|
||||
originator, or a \"To: address\" for outgoing e-mail messages.")
|
||||
|
||||
(defvar mh-scan-from-mbox-sep-width 2
|
||||
"Number of columns consumed by whitespace after from-mbox in `mh-scan-format'.
|
||||
This column will only ever have spaces in it.")
|
||||
|
||||
(defvar mh-scan-field-destination-offset
|
||||
(+ mh-scan-cmd-note-width)
|
||||
"The offset from the `mh-cmd-note' for the destination column.")
|
||||
|
||||
(defvar mh-scan-field-from-start-offset
|
||||
(+ mh-scan-cmd-note-width
|
||||
mh-scan-destination-width
|
||||
mh-scan-date-width
|
||||
mh-scan-date-flag-width)
|
||||
"The offset from the `mh-cmd-note' to find the start of \"From:\" address.")
|
||||
|
||||
(defvar mh-scan-field-from-end-offset
|
||||
(+ mh-scan-field-from-start-offset mh-scan-from-mbox-width)
|
||||
"The offset from the `mh-cmd-note' to find the end of \"From:\" address.")
|
||||
|
||||
(defvar mh-scan-field-subject-start-offset
|
||||
(+ mh-scan-cmd-note-width
|
||||
mh-scan-destination-width
|
||||
mh-scan-date-width
|
||||
mh-scan-date-flag-width
|
||||
mh-scan-from-mbox-width
|
||||
mh-scan-from-mbox-sep-width)
|
||||
"The offset from the `mh-cmd-note' to find the start of the subject.")
|
||||
|
||||
|
||||
|
||||
;;; Notation
|
||||
|
||||
;; Alphabetical.
|
||||
|
||||
(defvar mh-note-cur ?+
|
||||
"The current message (in MH, not in MH-E) is marked by this character.
|
||||
See also `mh-scan-cur-msg-number-regexp'.")
|
||||
|
||||
(defvar mh-note-copied "C"
|
||||
"Messages that have been copied are marked by this character.")
|
||||
|
||||
(defvar mh-note-deleted ?D
|
||||
"Messages that have been deleted are marked by this character.
|
||||
See also `mh-scan-deleted-msg-regexp'.")
|
||||
|
||||
(defvar mh-note-dist ?R
|
||||
"Messages that have been redistributed are marked by this character.")
|
||||
|
||||
(defvar mh-note-forw ?F
|
||||
"Messages that have been forwarded are marked by this character.")
|
||||
|
||||
(defvar mh-note-printed "P"
|
||||
"Messages that have been printed are marked by this character.")
|
||||
|
||||
(defvar mh-note-refiled ?^
|
||||
"Messages that have been refiled are marked by this character.
|
||||
See also `mh-scan-refiled-msg-regexp'.")
|
||||
|
||||
(defvar mh-note-repl ?-
|
||||
"Messages that have been replied to are marked by this character.")
|
||||
|
||||
(defvar mh-note-seq ?%
|
||||
"Messages in a user-defined sequence are marked by this character.
|
||||
|
||||
Messages in the \"search\" sequence are marked by this character as
|
||||
well.")
|
||||
|
||||
|
||||
|
||||
;;; Utilities
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-scan-msg-number-regexp ()
|
||||
"Return value of variable `mh-scan-msg-number-regexp'."
|
||||
mh-scan-msg-number-regexp)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-scan-msg-search-regexp ()
|
||||
"Return value of variable `mh-scan-msg-search-regexp'."
|
||||
mh-scan-msg-search-regexp)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-set-cmd-note (column)
|
||||
"Set `mh-cmd-note' to COLUMN.
|
||||
Note that columns in Emacs start with 0."
|
||||
(setq mh-cmd-note column))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-scan-format ()
|
||||
"Return the output format argument for the scan program."
|
||||
(if (equal mh-scan-format-file t)
|
||||
(list "-format" (if (mh-variant-p 'nmh 'mu-mh)
|
||||
(list (mh-update-scan-format
|
||||
mh-scan-format-nmh mh-cmd-note))
|
||||
(list (mh-update-scan-format
|
||||
mh-scan-format-mh mh-cmd-note))))
|
||||
(if (not (equal mh-scan-format-file nil))
|
||||
(list "-form" mh-scan-format-file))))
|
||||
|
||||
(defun mh-update-scan-format (fmt width)
|
||||
"Return a scan format with the (msg) width in the FMT replaced with WIDTH.
|
||||
|
||||
The message number width portion of the format is discovered
|
||||
using `mh-scan-msg-format-regexp'. Its replacement is controlled
|
||||
with `mh-scan-msg-format-string'."
|
||||
(or (and
|
||||
(string-match mh-scan-msg-format-regexp fmt)
|
||||
(let ((begin (match-beginning 1))
|
||||
(end (match-end 1)))
|
||||
(concat (substring fmt 0 begin)
|
||||
(format mh-scan-msg-format-string width)
|
||||
(substring fmt end))))
|
||||
fmt))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-msg-num-width (folder)
|
||||
"Return the width of the largest message number in this FOLDER."
|
||||
(or mh-progs (mh-find-path))
|
||||
(let ((tmp-buffer (get-buffer-create mh-temp-buffer))
|
||||
(width 0))
|
||||
(save-excursion
|
||||
(set-buffer tmp-buffer)
|
||||
(erase-buffer)
|
||||
(apply 'call-process
|
||||
(expand-file-name mh-scan-prog mh-progs) nil '(t nil) nil
|
||||
(list folder "last" "-format" "%(msg)"))
|
||||
(goto-char (point-min))
|
||||
(if (re-search-forward mh-scan-msg-number-regexp nil 0 1)
|
||||
(setq width (length (buffer-substring
|
||||
(match-beginning 1) (match-end 1))))))
|
||||
width))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-msg-num-width-to-column (width)
|
||||
"Return the column for notations given message number WIDTH.
|
||||
Note that columns in Emacs start with 0.
|
||||
|
||||
If `mh-scan-format-file' is set to \"Use MH-E scan Format\" this
|
||||
means that either `mh-scan-format-mh' or `mh-scan-format-nmh' are
|
||||
in use. This function therefore assumes that the first column is
|
||||
empty (to provide room for the cursor), the following WIDTH
|
||||
columns contain the message number, and the column for notations
|
||||
comes after that."
|
||||
(if (eq mh-scan-format-file t)
|
||||
(max (1+ width) 2)
|
||||
(error "%s %s" "Can't call `mh-msg-num-width-to-column' when"
|
||||
"`mh-scan-format-file' is not set to \"Use MH-E scan Format\"")))
|
||||
|
||||
(provide 'mh-scan)
|
||||
|
||||
;; Local Variables:
|
||||
;; indent-tabs-mode: nil
|
||||
;; sentence-end-double-space: nil
|
||||
;; End:
|
||||
|
||||
;;; mh-scan.el ends here
|
@ -1,4 +1,4 @@
|
||||
;;; mh-search --- MH-E search
|
||||
;;; mh-search --- MH-Search mode
|
||||
|
||||
;; Copyright (C) 1993, 1995,
|
||||
;; 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
@ -27,6 +27,8 @@
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Mode used to compose search criteria.
|
||||
|
||||
;; (1) The following search engines are supported:
|
||||
;; swish++
|
||||
;; swish-e
|
||||
@ -34,7 +36,7 @@
|
||||
;; namazu
|
||||
;; pick
|
||||
;; grep
|
||||
;;
|
||||
|
||||
;; (2) To use this package, you first have to build an index. Please
|
||||
;; read the documentation for `mh-search' to get started. That
|
||||
;; documentation will direct you to the specific instructions for
|
||||
@ -44,14 +46,12 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;(message "> mh-search")
|
||||
(eval-when-compile (require 'mh-acros))
|
||||
(require 'mh-e)
|
||||
(mh-require-cl)
|
||||
|
||||
(require 'gnus-util)
|
||||
(require 'mh-buffers)
|
||||
(require 'mh-e)
|
||||
;;(message "< mh-search")
|
||||
(require 'imenu)
|
||||
(require 'which-func nil t)
|
||||
|
||||
(defvar mh-searcher nil
|
||||
"Cached value of chosen search program.")
|
||||
@ -79,7 +79,7 @@ message number, and optionally the match.")
|
||||
|
||||
|
||||
|
||||
;;; MH-Search mode
|
||||
;;; MH-Folder Commands
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun* mh-search (folder search-regexp
|
||||
@ -322,6 +322,9 @@ folder containing the index search results."
|
||||
(loop for msg-hash being hash-values of mh-index-data
|
||||
count (> (hash-table-count msg-hash) 0))))))
|
||||
|
||||
;; Shush compiler.
|
||||
(eval-when-compile (mh-do-in-xemacs (defvar pick-folder)))
|
||||
|
||||
(defun mh-search-folder (folder window-config)
|
||||
"Search FOLDER for messages matching a pattern.
|
||||
|
||||
@ -363,30 +366,182 @@ configuration and is used when the search folder is dismissed."
|
||||
(add-text-properties (point) (1- (line-end-position)) '(read-only t))
|
||||
(goto-char (point-max)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defvar mh-search-mode-map (make-sparse-keymap)
|
||||
"Keymap for searching folder.")
|
||||
;; Sequence Searches
|
||||
|
||||
;;;###mh-autoload
|
||||
;; If this changes, modify mh-search-mode-help-messages accordingly, below.
|
||||
(gnus-define-keys mh-search-mode-map
|
||||
"\C-c?" mh-help
|
||||
"\C-c\C-c" mh-index-do-search
|
||||
"\C-c\C-p" mh-pick-do-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)
|
||||
(defun mh-index-new-messages (folders)
|
||||
"Display unseen messages.
|
||||
|
||||
If you use a program such as \"procmail\" to use \"rcvstore\" to file
|
||||
your incoming mail automatically, you can display new, unseen,
|
||||
messages using this command. All messages in the \"unseen\"
|
||||
sequence from the folders in `mh-new-messages-folders' are
|
||||
listed.
|
||||
|
||||
With a prefix argument, enter a space-separated list of FOLDERS,
|
||||
or nothing to search all folders."
|
||||
(interactive
|
||||
(list (if current-prefix-arg
|
||||
(split-string (read-string "Search folder(s) (default all): "))
|
||||
mh-new-messages-folders)))
|
||||
(mh-index-sequenced-messages folders mh-unseen-seq))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-ticked-messages (folders)
|
||||
"Display ticked messages.
|
||||
|
||||
All messages in `mh-tick-seq' from the folders in
|
||||
`mh-ticked-messages-folders' are listed.
|
||||
|
||||
With a prefix argument, enter a space-separated list of FOLDERS,
|
||||
or nothing to search all folders."
|
||||
(interactive
|
||||
(list (if current-prefix-arg
|
||||
(split-string (read-string "Search folder(s) (default all): "))
|
||||
mh-ticked-messages-folders)))
|
||||
(mh-index-sequenced-messages folders mh-tick-seq))
|
||||
|
||||
;; Shush compiler.
|
||||
(eval-when-compile
|
||||
(mh-do-in-xemacs
|
||||
(defvar mh-mairix-folder)
|
||||
(defvar mh-flists-search-folders)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-sequenced-messages (folders sequence)
|
||||
"Display messages in any sequence.
|
||||
|
||||
All messages from the FOLDERS in `mh-new-messages-folders' in the
|
||||
SEQUENCE you provide are listed. With a prefix argument, enter a
|
||||
space-separated list of folders at the prompt, or nothing to
|
||||
search all folders."
|
||||
(interactive
|
||||
(list (if current-prefix-arg
|
||||
(split-string (read-string "Search folder(s) (default all): "))
|
||||
mh-new-messages-folders)
|
||||
(mh-read-seq-default "Search" nil)))
|
||||
(unless sequence (setq sequence mh-unseen-seq))
|
||||
(let* ((mh-flists-search-folders folders)
|
||||
(mh-flists-sequence sequence)
|
||||
(mh-flists-called-flag t)
|
||||
(mh-searcher 'flists)
|
||||
(mh-search-function 'mh-flists-execute)
|
||||
(mh-search-next-result-function 'mh-mairix-next-result)
|
||||
(mh-mairix-folder mh-user-path)
|
||||
(mh-search-regexp-builder nil)
|
||||
(new-folder (format "%s/%s/%s" mh-index-folder
|
||||
mh-flists-results-folder sequence))
|
||||
(window-config (if (equal new-folder mh-current-folder)
|
||||
mh-previous-window-config
|
||||
(current-window-configuration)))
|
||||
(redo-flag nil)
|
||||
message)
|
||||
(cond ((buffer-live-p (get-buffer new-folder))
|
||||
;; The destination folder is being visited. Trick `mh-search'
|
||||
;; into thinking that the folder resulted from a previous search.
|
||||
(set-buffer new-folder)
|
||||
(setq mh-index-previous-search (list folders mh-searcher sequence))
|
||||
(setq redo-flag t))
|
||||
((mh-folder-exists-p new-folder)
|
||||
;; Folder exists but we don't have it open. That means they are
|
||||
;; stale results from a old flists search. Clear it out.
|
||||
(mh-exec-cmd-quiet nil "rmf" new-folder)))
|
||||
(setq message (mh-search "+" mh-flists-results-folder
|
||||
redo-flag window-config)
|
||||
mh-index-sequence-search-flag t
|
||||
mh-index-previous-search (list folders mh-searcher sequence))
|
||||
(mh-index-write-data)
|
||||
(when (stringp message) (message "%s" message))))
|
||||
|
||||
(defvar mh-flists-search-folders)
|
||||
|
||||
(defun mh-flists-execute (&rest args)
|
||||
"Execute flists.
|
||||
Search for messages belonging to `mh-flists-sequence' in the
|
||||
folders specified by `mh-flists-search-folders'. If
|
||||
`mh-recursive-folders-flag' is t, then the folders are searched
|
||||
recursively. All parameters ARGS are ignored."
|
||||
(set-buffer (get-buffer-create mh-temp-index-buffer))
|
||||
(erase-buffer)
|
||||
(unless (executable-find "sh")
|
||||
(error "Didn't find sh"))
|
||||
(with-temp-buffer
|
||||
(let ((seq (symbol-name mh-flists-sequence)))
|
||||
(insert "for folder in `" (expand-file-name "flists" mh-progs) " "
|
||||
(cond ((eq mh-flists-search-folders t)
|
||||
(mh-quote-for-shell mh-inbox))
|
||||
((eq mh-flists-search-folders nil) "")
|
||||
((listp mh-flists-search-folders)
|
||||
(loop for folder in mh-flists-search-folders
|
||||
concat
|
||||
(concat " " (mh-quote-for-shell folder)))))
|
||||
(if mh-recursive-folders-flag " -recurse" "")
|
||||
" -sequence " seq " -noshowzero -fast` ; do\n"
|
||||
(expand-file-name "mhpath" mh-progs) " \"+$folder\" " seq "\n"
|
||||
"done\n"))
|
||||
(call-process-region
|
||||
(point-min) (point-max) "sh" nil (get-buffer mh-temp-index-buffer))))
|
||||
|
||||
;; Navigation
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-next-folder (&optional backward-flag)
|
||||
"Jump to the next folder marker.
|
||||
|
||||
With non-nil optional argument BACKWARD-FLAG, jump to the previous
|
||||
group of results."
|
||||
(interactive "P")
|
||||
(if (null mh-index-data)
|
||||
(message "Only applicable in an MH-E index search buffer")
|
||||
(let ((point (point)))
|
||||
(forward-line (if backward-flag 0 1))
|
||||
(cond ((if backward-flag
|
||||
(re-search-backward "^+" (point-min) t)
|
||||
(re-search-forward "^+" (point-max) t))
|
||||
(beginning-of-line))
|
||||
((and (if backward-flag
|
||||
(goto-char (point-max))
|
||||
(goto-char (point-min)))
|
||||
nil))
|
||||
((if backward-flag
|
||||
(re-search-backward "^+" (point-min) t)
|
||||
(re-search-forward "^+" (point-max) t))
|
||||
(beginning-of-line))
|
||||
(t (goto-char point))))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-previous-folder ()
|
||||
"Jump to the previous folder marker."
|
||||
(interactive)
|
||||
(mh-index-next-folder t))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-visit-folder ()
|
||||
"Visit original folder from where the message at point was found."
|
||||
(interactive)
|
||||
(unless mh-index-data
|
||||
(error "Not in an index folder"))
|
||||
(let (folder msg)
|
||||
(save-excursion
|
||||
(cond ((and (bolp) (eolp))
|
||||
(ignore-errors (forward-line -1))
|
||||
(setq msg (mh-get-msg-num t)))
|
||||
((equal (char-after (line-beginning-position)) ?+)
|
||||
(setq folder (buffer-substring-no-properties
|
||||
(line-beginning-position) (line-end-position))))
|
||||
(t (setq msg (mh-get-msg-num t)))))
|
||||
(when (not folder)
|
||||
(setq folder (car (gethash (gethash msg mh-index-msg-checksum-map)
|
||||
mh-index-checksum-origin-map))))
|
||||
(when (or (not (get-buffer folder))
|
||||
(y-or-n-p (format "Reuse buffer displaying %s? " folder)))
|
||||
(mh-visit-folder
|
||||
folder (loop for x being the hash-keys of (gethash folder mh-index-data)
|
||||
when (mh-msg-exists-p x folder) collect x)))))
|
||||
|
||||
|
||||
|
||||
;;; Search Menu
|
||||
|
||||
(easy-menu-define
|
||||
mh-pick-menu mh-search-mode-map "Menu for MH-E Search"
|
||||
@ -394,11 +549,35 @@ configuration and is used when the search folder is dismissed."
|
||||
["Perform Search" mh-index-do-search t]
|
||||
["Search with pick" mh-pick-do-search t]))
|
||||
|
||||
|
||||
|
||||
;;; MH-Search Keys
|
||||
|
||||
;; If this changes, modify mh-search-mode-help-messages accordingly, below.
|
||||
(gnus-define-keys mh-search-mode-map
|
||||
"\C-c?" mh-help
|
||||
"\C-c\C-c" mh-index-do-search
|
||||
"\C-c\C-p" mh-pick-do-search
|
||||
"\C-c\C-f\C-b" mh-to-field
|
||||
"\C-c\C-f\C-c" mh-to-field
|
||||
"\C-c\C-f\C-m" 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-fm" mh-to-field
|
||||
"\C-c\C-fs" mh-to-field
|
||||
"\C-c\C-ft" mh-to-field)
|
||||
|
||||
|
||||
|
||||
;;; MH-Search Help Messages
|
||||
|
||||
;; Group messages logically, more or less.
|
||||
(defvar mh-search-mode-help-messages
|
||||
'((nil
|
||||
"Perform search: \\[mh-index-do-search]\n"
|
||||
"Search with pick: \\[mh-pick-do-search]\n"
|
||||
"Perform search: \\[mh-index-do-search]\n"
|
||||
"Search with pick: \\[mh-pick-do-search]\n\n"
|
||||
"Move to a field by typing C-c C-f C-<field>\n"
|
||||
"where <field> is the first letter of the desired field\n"
|
||||
"(except for From: which uses \"m\")."))
|
||||
@ -413,6 +592,10 @@ display the non-prefixed commands.
|
||||
The substitutions described in `substitute-command-keys' are performed
|
||||
as well.")
|
||||
|
||||
|
||||
|
||||
;;; MH-Search Mode
|
||||
|
||||
(put 'mh-search-mode 'mode-class 'special)
|
||||
|
||||
(define-derived-mode mh-search-mode fundamental-mode "MH-Search"
|
||||
@ -435,11 +618,13 @@ The hook `mh-search-mode-hook' is called upon entry to this mode.
|
||||
|
||||
\\{mh-search-mode-map}"
|
||||
|
||||
(make-local-variable 'mh-help-messages)
|
||||
(easy-menu-add mh-pick-menu)
|
||||
(setq mh-help-messages mh-search-mode-help-messages))
|
||||
(mh-set-help mh-search-mode-help-messages))
|
||||
|
||||
|
||||
|
||||
;;; MH-Search Commands
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-do-search (&optional searcher)
|
||||
"Find messages using `mh-search-program'.
|
||||
If optional argument SEARCHER is present, use it instead of
|
||||
@ -452,7 +637,6 @@ If optional argument SEARCHER is present, use it instead of
|
||||
(mh-search mh-current-folder pattern nil mh-previous-window-config)
|
||||
(error "No search terms"))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-pick-do-search ()
|
||||
"Find messages using \"pick\".
|
||||
|
||||
@ -490,7 +674,6 @@ The cdr of the element is the pattern to search."
|
||||
(forward-line))
|
||||
pattern-list)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-parse-search-regexp (input-string)
|
||||
"Construct parse tree for INPUT-STRING.
|
||||
All occurrences of &, |, ! and ~ in INPUT-STRING are replaced by
|
||||
@ -594,296 +777,7 @@ parsed."
|
||||
|
||||
|
||||
|
||||
;;; Sequence browsing
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-new-messages (folders)
|
||||
"Display unseen messages.
|
||||
|
||||
If you use a program such as \"procmail\" to use \"rcvstore\" to file
|
||||
your incoming mail automatically, you can display new, unseen,
|
||||
messages using this command. All messages in the \"unseen\"
|
||||
sequence from the folders in `mh-new-messages-folders' are
|
||||
listed.
|
||||
|
||||
With a prefix argument, enter a space-separated list of FOLDERS,
|
||||
or nothing to search all folders."
|
||||
(interactive
|
||||
(list (if current-prefix-arg
|
||||
(split-string (read-string "Search folder(s) (default all): "))
|
||||
mh-new-messages-folders)))
|
||||
(mh-index-sequenced-messages folders mh-unseen-seq))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-ticked-messages (folders)
|
||||
"Display ticked messages.
|
||||
|
||||
All messages in `mh-tick-seq' from the folders in
|
||||
`mh-ticked-messages-folders' are listed.
|
||||
|
||||
With a prefix argument, enter a space-separated list of FOLDERS,
|
||||
or nothing to search all folders."
|
||||
(interactive
|
||||
(list (if current-prefix-arg
|
||||
(split-string (read-string "Search folder(s) (default all): "))
|
||||
mh-ticked-messages-folders)))
|
||||
(mh-index-sequenced-messages folders mh-tick-seq))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-sequenced-messages (folders sequence)
|
||||
"Display messages in any sequence.
|
||||
|
||||
All messages from the FOLDERS in `mh-new-messages-folders' in the
|
||||
SEQUENCE you provide are listed. With a prefix argument, enter a
|
||||
space-separated list of folders at the prompt, or nothing to
|
||||
search all folders."
|
||||
(interactive
|
||||
(list (if current-prefix-arg
|
||||
(split-string (read-string "Search folder(s) (default all): "))
|
||||
mh-new-messages-folders)
|
||||
(mh-read-seq-default "Search" nil)))
|
||||
(unless sequence (setq sequence mh-unseen-seq))
|
||||
(let* ((mh-flists-search-folders folders)
|
||||
(mh-flists-sequence sequence)
|
||||
(mh-flists-called-flag t)
|
||||
(mh-searcher 'flists)
|
||||
(mh-search-function 'mh-flists-execute)
|
||||
(mh-search-next-result-function 'mh-mairix-next-result)
|
||||
(mh-mairix-folder mh-user-path)
|
||||
(mh-search-regexp-builder nil)
|
||||
(new-folder (format "%s/%s/%s" mh-index-folder
|
||||
mh-flists-results-folder sequence))
|
||||
(window-config (if (equal new-folder mh-current-folder)
|
||||
mh-previous-window-config
|
||||
(current-window-configuration)))
|
||||
(redo-flag nil)
|
||||
message)
|
||||
(cond ((buffer-live-p (get-buffer new-folder))
|
||||
;; The destination folder is being visited. Trick `mh-search'
|
||||
;; into thinking that the folder resulted from a previous search.
|
||||
(set-buffer new-folder)
|
||||
(setq mh-index-previous-search (list folders mh-searcher sequence))
|
||||
(setq redo-flag t))
|
||||
((mh-folder-exists-p new-folder)
|
||||
;; Folder exists but we don't have it open. That means they are
|
||||
;; stale results from a old flists search. Clear it out.
|
||||
(mh-exec-cmd-quiet nil "rmf" new-folder)))
|
||||
(setq message (mh-search "+" mh-flists-results-folder
|
||||
redo-flag window-config)
|
||||
mh-index-sequence-search-flag t
|
||||
mh-index-previous-search (list folders mh-searcher sequence))
|
||||
(mh-index-write-data)
|
||||
(when (stringp message) (message "%s" message))))
|
||||
|
||||
(defvar mh-flists-search-folders)
|
||||
|
||||
(defun mh-flists-execute (&rest args)
|
||||
"Execute flists.
|
||||
Search for messages belonging to `mh-flists-sequence' in the
|
||||
folders specified by `mh-flists-search-folders'. If
|
||||
`mh-recursive-folders-flag' is t, then the folders are searched
|
||||
recursively. All parameters ARGS are ignored."
|
||||
(set-buffer (get-buffer-create mh-temp-index-buffer))
|
||||
(erase-buffer)
|
||||
(unless (executable-find "sh")
|
||||
(error "Didn't find sh"))
|
||||
(with-temp-buffer
|
||||
(let ((seq (symbol-name mh-flists-sequence)))
|
||||
(insert "for folder in `" (expand-file-name "flists" mh-progs) " "
|
||||
(cond ((eq mh-flists-search-folders t)
|
||||
(mh-quote-for-shell mh-inbox))
|
||||
((eq mh-flists-search-folders nil) "")
|
||||
((listp mh-flists-search-folders)
|
||||
(loop for folder in mh-flists-search-folders
|
||||
concat
|
||||
(concat " " (mh-quote-for-shell folder)))))
|
||||
(if mh-recursive-folders-flag " -recurse" "")
|
||||
" -sequence " seq " -noshowzero -fast` ; do\n"
|
||||
(expand-file-name "mhpath" mh-progs) " \"+$folder\" " seq "\n"
|
||||
"done\n"))
|
||||
(call-process-region
|
||||
(point-min) (point-max) "sh" nil (get-buffer mh-temp-index-buffer))))
|
||||
|
||||
|
||||
|
||||
;;; Folder navigation and utilities
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-group-by-folder ()
|
||||
"Partition the messages based on source folder.
|
||||
Returns an alist with the the folder names in the car and the cdr
|
||||
being the list of messages originally from that folder."
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(let ((result-table (make-hash-table :test #'equal)))
|
||||
(loop for msg being hash-keys of mh-index-msg-checksum-map
|
||||
do (push msg (gethash (car (gethash
|
||||
(gethash msg mh-index-msg-checksum-map)
|
||||
mh-index-checksum-origin-map))
|
||||
result-table)))
|
||||
(loop for x being the hash-keys of result-table
|
||||
collect (cons x (nreverse (gethash x result-table)))))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-insert-folder-headers ()
|
||||
"Annotate the search results with original folder names."
|
||||
(let ((cur-msg (mh-get-msg-num nil))
|
||||
(old-buffer-modified-flag (buffer-modified-p))
|
||||
(buffer-read-only nil)
|
||||
current-folder last-folder)
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
(setq current-folder (car (gethash (gethash (mh-get-msg-num nil)
|
||||
mh-index-msg-checksum-map)
|
||||
mh-index-checksum-origin-map)))
|
||||
(when (and current-folder (not (equal current-folder last-folder)))
|
||||
(insert (if last-folder "\n" "") current-folder "\n")
|
||||
(setq last-folder current-folder))
|
||||
(forward-line))
|
||||
(when cur-msg
|
||||
(mh-notate-cur)
|
||||
(mh-goto-msg cur-msg t))
|
||||
(set-buffer-modified-p old-buffer-modified-flag))
|
||||
(mh-index-create-imenu-index))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-delete-folder-headers ()
|
||||
"Delete the folder headers."
|
||||
(let ((cur-msg (mh-get-msg-num nil))
|
||||
(old-buffer-modified-flag (buffer-modified-p))
|
||||
(buffer-read-only nil))
|
||||
(while (and (not cur-msg) (not (eobp)))
|
||||
(forward-line)
|
||||
(setq cur-msg (mh-get-msg-num nil)))
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
(if (or (char-equal (char-after) ?+) (char-equal (char-after) 10))
|
||||
(delete-region (point) (progn (forward-line) (point)))
|
||||
(forward-line)))
|
||||
(when cur-msg (mh-goto-msg cur-msg t t))
|
||||
(set-buffer-modified-p old-buffer-modified-flag)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-create-imenu-index ()
|
||||
"Create alist of folder names and positions in index folder buffers."
|
||||
(save-excursion
|
||||
(setq which-func-mode t)
|
||||
(let ((alist ()))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "^+" nil t)
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(push (cons (buffer-substring-no-properties
|
||||
(point) (line-end-position))
|
||||
(set-marker (make-marker) (point)))
|
||||
alist)))
|
||||
(setq imenu--index-alist (nreverse alist)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-next-folder (&optional backward-flag)
|
||||
"Jump to the next folder marker.
|
||||
|
||||
With non-nil optional argument BACKWARD-FLAG, jump to the previous
|
||||
group of results."
|
||||
(interactive "P")
|
||||
(if (null mh-index-data)
|
||||
(message "Only applicable in an MH-E index search buffer")
|
||||
(let ((point (point)))
|
||||
(forward-line (if backward-flag 0 1))
|
||||
(cond ((if backward-flag
|
||||
(re-search-backward "^+" (point-min) t)
|
||||
(re-search-forward "^+" (point-max) t))
|
||||
(beginning-of-line))
|
||||
((and (if backward-flag
|
||||
(goto-char (point-max))
|
||||
(goto-char (point-min)))
|
||||
nil))
|
||||
((if backward-flag
|
||||
(re-search-backward "^+" (point-min) t)
|
||||
(re-search-forward "^+" (point-max) t))
|
||||
(beginning-of-line))
|
||||
(t (goto-char point))))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-previous-folder ()
|
||||
"Jump to the previous folder marker."
|
||||
(interactive)
|
||||
(mh-index-next-folder t))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-visit-folder ()
|
||||
"Visit original folder from where the message at point was found."
|
||||
(interactive)
|
||||
(unless mh-index-data
|
||||
(error "Not in an index folder"))
|
||||
(let (folder msg)
|
||||
(save-excursion
|
||||
(cond ((and (bolp) (eolp))
|
||||
(ignore-errors (forward-line -1))
|
||||
(setq msg (mh-get-msg-num t)))
|
||||
((equal (char-after (line-beginning-position)) ?+)
|
||||
(setq folder (buffer-substring-no-properties
|
||||
(line-beginning-position) (line-end-position))))
|
||||
(t (setq msg (mh-get-msg-num t)))))
|
||||
(when (not folder)
|
||||
(setq folder (car (gethash (gethash msg mh-index-msg-checksum-map)
|
||||
mh-index-checksum-origin-map))))
|
||||
(when (or (not (get-buffer folder))
|
||||
(y-or-n-p (format "Reuse buffer displaying %s? " folder)))
|
||||
(mh-visit-folder
|
||||
folder (loop for x being the hash-keys of (gethash folder mh-index-data)
|
||||
when (mh-msg-exists-p x folder) collect x)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-search-p ()
|
||||
"Non-nil means that this folder was generated by searching."
|
||||
mh-index-data)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-execute-commands ()
|
||||
"Delete/refile the actual messages.
|
||||
The copies in the searched folder are then deleted/refiled to get
|
||||
the desired result. Before deleting the messages we make sure
|
||||
that the message being deleted is identical to the one that the
|
||||
user has marked in the index buffer."
|
||||
(save-excursion
|
||||
(let ((folders ())
|
||||
(mh-speed-flists-inhibit-flag t))
|
||||
(maphash
|
||||
(lambda (folder msgs)
|
||||
(push folder folders)
|
||||
(if (not (get-buffer folder))
|
||||
;; If source folder not open, just delete the messages...
|
||||
(apply #'mh-exec-cmd "rmm" folder (mh-coalesce-msg-list msgs))
|
||||
;; Otherwise delete the messages in the source buffer...
|
||||
(save-excursion
|
||||
(set-buffer folder)
|
||||
(let ((old-refile-list mh-refile-list)
|
||||
(old-delete-list mh-delete-list))
|
||||
(setq mh-refile-list nil
|
||||
mh-delete-list msgs)
|
||||
(unwind-protect (mh-execute-commands)
|
||||
(setq mh-refile-list
|
||||
(mapcar (lambda (x)
|
||||
(cons (car x)
|
||||
(loop for y in (cdr x)
|
||||
unless (memq y msgs) collect y)))
|
||||
old-refile-list)
|
||||
mh-delete-list
|
||||
(loop for x in old-delete-list
|
||||
unless (memq x msgs) collect x))
|
||||
(mh-set-folder-modified-p (mh-outstanding-commands-p))
|
||||
(when (mh-outstanding-commands-p)
|
||||
(mh-notate-deleted-and-refiled)))))))
|
||||
(mh-index-matching-source-msgs (append (loop for x in mh-refile-list
|
||||
append (cdr x))
|
||||
mh-delete-list)
|
||||
t))
|
||||
folders)))
|
||||
|
||||
|
||||
|
||||
;;; Indexing functions
|
||||
;;; Indexing Functions
|
||||
|
||||
;; Support different search programs
|
||||
(defvar mh-search-choices
|
||||
@ -930,14 +824,13 @@ optional argument SEARCHER is present, use it instead of
|
||||
(return mh-searcher))))
|
||||
nil)))
|
||||
|
||||
;;; Swish++ interface
|
||||
;;; Swish++
|
||||
|
||||
(defvar mh-swish++-binary (or (executable-find "search++")
|
||||
(executable-find "search")))
|
||||
(defvar mh-swish++-directory ".swish++")
|
||||
(defvar mh-swish-folder nil)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-swish++-execute-search (folder-path search-regexp)
|
||||
"Execute swish++.
|
||||
|
||||
@ -1012,12 +905,11 @@ REGEXP-LIST is an alist of fields and values."
|
||||
(symbol-name (car expr))
|
||||
(mh-swish++-print-regexp (caddr expr))))))
|
||||
|
||||
;;; Swish interface
|
||||
;;; Swish
|
||||
|
||||
(defvar mh-swish-binary (executable-find "swish-e"))
|
||||
(defvar mh-swish-directory ".swish")
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-swish-execute-search (folder-path search-regexp)
|
||||
"Execute swish-e.
|
||||
|
||||
@ -1110,13 +1002,12 @@ is used to search."
|
||||
nil)))
|
||||
(forward-line)))
|
||||
|
||||
;;; Mairix interface
|
||||
;;; Mairix
|
||||
|
||||
(defvar mh-mairix-binary (executable-find "mairix"))
|
||||
(defvar mh-mairix-directory ".mairix")
|
||||
(defvar mh-mairix-folder nil)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-mairix-execute-search (folder-path search-regexp-list)
|
||||
"Execute mairix.
|
||||
|
||||
@ -1244,13 +1135,12 @@ REGEXP-LIST is an alist of fields and values."
|
||||
(cdadr expr)))))
|
||||
(t (error "Unreachable: %s" expr))))
|
||||
|
||||
;;; Namazu interface
|
||||
;;; Namazu
|
||||
|
||||
(defvar mh-namazu-binary (executable-find "namazu"))
|
||||
(defvar mh-namazu-directory ".namazu")
|
||||
(defvar mh-namazu-folder nil)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-namazu-execute-search (folder-path search-regexp)
|
||||
"Execute namazu.
|
||||
|
||||
@ -1317,14 +1207,13 @@ is used to search."
|
||||
nil))))
|
||||
(forward-line)))
|
||||
|
||||
;;; Pick interface
|
||||
;;; Pick
|
||||
|
||||
(defvar mh-index-pick-folder)
|
||||
(defvar mh-pick-binary "pick")
|
||||
(defconst mh-pick-single-dash '(cc date from subject to)
|
||||
"Search components that are supported by single-dash option in pick.")
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-pick-execute-search (folder-path search-regexp)
|
||||
"Execute pick.
|
||||
|
||||
@ -1408,11 +1297,10 @@ COMPONENT is the component to search."
|
||||
"-rbrace"))
|
||||
(t (error "Unknown operator %s seen" (car expr)))))
|
||||
|
||||
;;; Grep interface
|
||||
;;; Grep
|
||||
|
||||
(defvar mh-grep-binary (executable-find "grep"))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-grep-execute-search (folder-path search-regexp)
|
||||
"Execute grep.
|
||||
|
||||
@ -1463,7 +1351,132 @@ record is invalid return 'error."
|
||||
|
||||
|
||||
|
||||
;;; Folder support
|
||||
;;; Folder Utilities
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-group-by-folder ()
|
||||
"Partition the messages based on source folder.
|
||||
Returns an alist with the the folder names in the car and the cdr
|
||||
being the list of messages originally from that folder."
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(let ((result-table (make-hash-table :test #'equal)))
|
||||
(loop for msg being hash-keys of mh-index-msg-checksum-map
|
||||
do (push msg (gethash (car (gethash
|
||||
(gethash msg mh-index-msg-checksum-map)
|
||||
mh-index-checksum-origin-map))
|
||||
result-table)))
|
||||
(loop for x being the hash-keys of result-table
|
||||
collect (cons x (nreverse (gethash x result-table)))))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-insert-folder-headers ()
|
||||
"Annotate the search results with original folder names."
|
||||
(let ((cur-msg (mh-get-msg-num nil))
|
||||
(old-buffer-modified-flag (buffer-modified-p))
|
||||
(buffer-read-only nil)
|
||||
current-folder last-folder)
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
(setq current-folder (car (gethash (gethash (mh-get-msg-num nil)
|
||||
mh-index-msg-checksum-map)
|
||||
mh-index-checksum-origin-map)))
|
||||
(when (and current-folder (not (equal current-folder last-folder)))
|
||||
(insert (if last-folder "\n" "") current-folder "\n")
|
||||
(setq last-folder current-folder))
|
||||
(forward-line))
|
||||
(when cur-msg
|
||||
(mh-notate-cur)
|
||||
(mh-goto-msg cur-msg t))
|
||||
(set-buffer-modified-p old-buffer-modified-flag))
|
||||
(mh-index-create-imenu-index))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-delete-folder-headers ()
|
||||
"Delete the folder headers."
|
||||
(let ((cur-msg (mh-get-msg-num nil))
|
||||
(old-buffer-modified-flag (buffer-modified-p))
|
||||
(buffer-read-only nil))
|
||||
(while (and (not cur-msg) (not (eobp)))
|
||||
(forward-line)
|
||||
(setq cur-msg (mh-get-msg-num nil)))
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
(if (or (char-equal (char-after) ?+) (char-equal (char-after) 10))
|
||||
(delete-region (point) (progn (forward-line) (point)))
|
||||
(forward-line)))
|
||||
(when cur-msg (mh-goto-msg cur-msg t t))
|
||||
(set-buffer-modified-p old-buffer-modified-flag)))
|
||||
|
||||
;; Shush compiler.
|
||||
(eval-when-compile (mh-do-in-xemacs (defvar which-func-mode)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-create-imenu-index ()
|
||||
"Create alist of folder names and positions in index folder buffers."
|
||||
(save-excursion
|
||||
(if (boundp 'which-func-mode)
|
||||
(setq which-func-mode t))
|
||||
(let ((alist ()))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "^+" nil t)
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(push (cons (buffer-substring-no-properties
|
||||
(point) (line-end-position))
|
||||
(set-marker (make-marker) (point)))
|
||||
alist)))
|
||||
(setq imenu--index-alist (nreverse alist)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-search-p ()
|
||||
"Non-nil means that this folder was generated by searching."
|
||||
mh-index-data)
|
||||
|
||||
;; Shush compiler
|
||||
(eval-when-compile (if mh-xemacs-flag (defvar mh-speed-flists-inhibit-flag)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-execute-commands ()
|
||||
"Delete/refile the actual messages.
|
||||
The copies in the searched folder are then deleted/refiled to get
|
||||
the desired result. Before deleting the messages we make sure
|
||||
that the message being deleted is identical to the one that the
|
||||
user has marked in the index buffer."
|
||||
(save-excursion
|
||||
(let ((folders ())
|
||||
(mh-speed-flists-inhibit-flag t))
|
||||
(maphash
|
||||
(lambda (folder msgs)
|
||||
(push folder folders)
|
||||
(if (not (get-buffer folder))
|
||||
;; If source folder not open, just delete the messages...
|
||||
(apply #'mh-exec-cmd "rmm" folder (mh-coalesce-msg-list msgs))
|
||||
;; Otherwise delete the messages in the source buffer...
|
||||
(save-excursion
|
||||
(set-buffer folder)
|
||||
(let ((old-refile-list mh-refile-list)
|
||||
(old-delete-list mh-delete-list))
|
||||
(setq mh-refile-list nil
|
||||
mh-delete-list msgs)
|
||||
(unwind-protect (mh-execute-commands)
|
||||
(setq mh-refile-list
|
||||
(mapcar (lambda (x)
|
||||
(cons (car x)
|
||||
(loop for y in (cdr x)
|
||||
unless (memq y msgs) collect y)))
|
||||
old-refile-list)
|
||||
mh-delete-list
|
||||
(loop for x in old-delete-list
|
||||
unless (memq x msgs) collect x))
|
||||
(mh-set-folder-modified-p (mh-outstanding-commands-p))
|
||||
(when (mh-outstanding-commands-p)
|
||||
(mh-notate-deleted-and-refiled)))))))
|
||||
(mh-index-matching-source-msgs (append (loop for x in mh-refile-list
|
||||
append (cdr x))
|
||||
mh-delete-list)
|
||||
t))
|
||||
folders)))
|
||||
|
||||
(defun mh-index-generate-pretty-name (string)
|
||||
"Given STRING generate a name which is suitable for use as a folder name.
|
||||
@ -1559,7 +1572,7 @@ garbled."
|
||||
|
||||
|
||||
|
||||
;;; Sequence support
|
||||
;;; Sequence Support
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-index-create-sequences ()
|
||||
@ -1688,7 +1701,7 @@ folder, is removed from `mh-index-data'."
|
||||
|
||||
|
||||
|
||||
;;; Serialization of index data
|
||||
;;; Serialization of Index Data
|
||||
|
||||
(defun mh-index-write-data ()
|
||||
"Write index data to file."
|
||||
@ -1756,20 +1769,21 @@ PROC is used to convert the value to actual data."
|
||||
|
||||
|
||||
|
||||
;;; Checksum routines
|
||||
;;; Checksum Routines
|
||||
|
||||
;; A few different checksum programs are supported. The supported
|
||||
;; programs are:
|
||||
|
||||
;; A few different checksum programs are supported. The supported programs
|
||||
;; are:
|
||||
;;
|
||||
;; 1. md5sum
|
||||
;; 2. md5
|
||||
;; 3. openssl
|
||||
;;
|
||||
;; To add support for your favorite checksum program add a clause to the cond
|
||||
;; statement in mh-checksum-choose. This should set the variable
|
||||
;; mh-checksum-cmd to the command line needed to run the checsum program and
|
||||
;; should set mh-checksum-parser to a function which returns a cons cell
|
||||
;; containing the message number and checksum string.
|
||||
|
||||
;; To add support for your favorite checksum program add a clause to
|
||||
;; the cond statement in mh-checksum-choose. This should set the
|
||||
;; variable mh-checksum-cmd to the command line needed to run the
|
||||
;; checsum program and should set mh-checksum-parser to a function
|
||||
;; which returns a cons cell containing the message number and
|
||||
;; checksum string.
|
||||
|
||||
(defvar mh-checksum-cmd)
|
||||
(defvar mh-checksum-parser)
|
||||
|
1934
lisp/mh-e/mh-seq.el
1934
lisp/mh-e/mh-seq.el
File diff suppressed because it is too large
Load Diff
906
lisp/mh-e/mh-show.el
Normal file
906
lisp/mh-e/mh-show.el
Normal file
@ -0,0 +1,906 @@
|
||||
;;; mh-show.el --- MH-Show mode
|
||||
|
||||
;; Copyright (C) 1993, 1995, 1997,
|
||||
;; 2000, 2001, 2002, 2003, 2004, 2005, 2006 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.
|
||||
|
||||
;; 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., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Mode for showing messages.
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'mh-e)
|
||||
(require 'mh-scan)
|
||||
|
||||
(require 'gnus-cite)
|
||||
(require 'gnus-util)
|
||||
|
||||
(autoload 'mh-make-buffer-data "mh-mime") ;can't be automatically generated
|
||||
|
||||
(require 'font-lock)
|
||||
|
||||
|
||||
|
||||
;;; MH-Folder Commands
|
||||
|
||||
(defvar mh-showing-with-headers nil
|
||||
"If non-nil, MH-Show buffer contains message with all header fields.
|
||||
If nil, MH-Show buffer contains message processed normally.")
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-show (&optional message redisplay-flag)
|
||||
"Display message\\<mh-folder-mode-map>.
|
||||
|
||||
If the message under the cursor is already displayed, this command
|
||||
scrolls to the beginning of the message. MH-E normally hides a lot of
|
||||
the superfluous header fields that mailers add to a message, but if
|
||||
you wish to see all of them, use the command \\[mh-header-display].
|
||||
|
||||
Two hooks can be used to control how messages are displayed. The
|
||||
first hook, `mh-show-mode-hook', is called early on in the
|
||||
process of the message display. It is usually used to perform
|
||||
some action on the message's content. The second hook,
|
||||
`mh-show-hook', is the last thing called after messages are
|
||||
displayed. It's used to affect the behavior of MH-E in general or
|
||||
when `mh-show-mode-hook' is too early.
|
||||
|
||||
From a program, optional argument MESSAGE can be used to display an
|
||||
alternative message. The optional argument REDISPLAY-FLAG forces the
|
||||
redisplay of the message even if the show buffer was already
|
||||
displaying the correct message.
|
||||
|
||||
See the \"mh-show\" customization group for a litany of options that
|
||||
control what displayed messages look like."
|
||||
(interactive (list nil t))
|
||||
(when (or redisplay-flag
|
||||
(and mh-showing-with-headers
|
||||
(or mh-mhl-format-file mh-clean-message-header-flag)))
|
||||
(mh-invalidate-show-buffer))
|
||||
(mh-show-msg message))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-header-display ()
|
||||
"Display message with all header fields\\<mh-folder-mode-map>.
|
||||
|
||||
Use the command \\[mh-show] to show the message normally again."
|
||||
(interactive)
|
||||
(and (not mh-showing-with-headers)
|
||||
(or mh-mhl-format-file mh-clean-message-header-flag)
|
||||
(mh-invalidate-show-buffer))
|
||||
(let ((mh-decode-mime-flag nil)
|
||||
(mh-mhl-format-file nil)
|
||||
(mh-clean-message-header-flag nil))
|
||||
(mh-show-msg nil)
|
||||
(mh-in-show-buffer (mh-show-buffer)
|
||||
(goto-char (point-min))
|
||||
(mh-recenter 0))
|
||||
(setq mh-showing-with-headers t)))
|
||||
|
||||
|
||||
|
||||
;;; Support Routines for MH-Folder Commands
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-maybe-show (&optional msg)
|
||||
"Display message at cursor, but only if in show mode.
|
||||
If optional arg MSG is non-nil, display that message instead."
|
||||
(if mh-showing-mode (mh-show msg)))
|
||||
|
||||
(defun mh-show-msg (msg)
|
||||
"Show MSG.
|
||||
|
||||
The hook `mh-show-hook' is called after the message has been
|
||||
displayed."
|
||||
(if (not msg)
|
||||
(setq msg (mh-get-msg-num t)))
|
||||
(mh-showing-mode t)
|
||||
(setq mh-page-to-next-msg-flag nil)
|
||||
(let ((folder mh-current-folder)
|
||||
(folders (list mh-current-folder))
|
||||
(clean-message-header mh-clean-message-header-flag)
|
||||
(show-window (get-buffer-window mh-show-buffer))
|
||||
(display-mime-buttons-flag mh-display-buttons-for-inline-parts-flag))
|
||||
(if (not (eq (next-window (minibuffer-window)) (selected-window)))
|
||||
(delete-other-windows)) ; force ourself to the top window
|
||||
(mh-in-show-buffer (mh-show-buffer)
|
||||
(setq mh-display-buttons-for-inline-parts-flag display-mime-buttons-flag)
|
||||
(if (and show-window
|
||||
(equal (mh-msg-filename msg folder) buffer-file-name))
|
||||
(progn ;just back up to start
|
||||
(goto-char (point-min))
|
||||
(if (not clean-message-header)
|
||||
(mh-start-of-uncleaned-message)))
|
||||
(mh-display-msg msg folder)))
|
||||
(if (not (= (1+ (window-height)) (frame-height))) ;not horizontally split
|
||||
(shrink-window (- (window-height) (or mh-summary-height
|
||||
(mh-summary-height)))))
|
||||
(mh-recenter nil)
|
||||
;; The following line is a nop which forces update of the scan line so
|
||||
;; that font-lock will update it (if needed)...
|
||||
(mh-notate nil nil mh-cmd-note)
|
||||
(if (not (memq msg mh-seen-list))
|
||||
(setq mh-seen-list (cons msg mh-seen-list)))
|
||||
(when mh-update-sequences-after-mh-show-flag
|
||||
(mh-update-sequences)
|
||||
(when mh-index-data
|
||||
(setq folders
|
||||
(append (mh-index-delete-from-sequence mh-unseen-seq (list msg))
|
||||
folders)))
|
||||
(when (mh-speed-flists-active-p)
|
||||
(apply #'mh-speed-flists t folders)))
|
||||
(run-hooks 'mh-show-hook)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(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))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-start-of-uncleaned-message ()
|
||||
"Position uninteresting headers off the top of the window."
|
||||
(let ((case-fold-search t))
|
||||
(re-search-forward
|
||||
"^To:\\|^Cc:\\|^From:\\|^Subject:\\|^Date:" nil t)
|
||||
(beginning-of-line)
|
||||
(mh-recenter 0)))
|
||||
|
||||
(defvar mh-show-buffer-mode-line-buffer-id " {show-%s} %d"
|
||||
"Format string to produce `mode-line-buffer-identification' for show buffers.
|
||||
|
||||
First argument is folder name. Second is message number.")
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-display-msg (msg-num folder-name)
|
||||
"Display MSG-NUM of FOLDER-NAME.
|
||||
Sets the current buffer to the show buffer."
|
||||
(let ((folder (mh-msg-folder folder-name)))
|
||||
(set-buffer folder)
|
||||
;; When Gnus uses external displayers it has to keep handles longer. So
|
||||
;; we will delete these handles when mh-quit is called on the folder. It
|
||||
;; would be nicer if there are weak pointers in emacs lisp, then we could
|
||||
;; get the garbage collector to do this for us.
|
||||
(unless (mh-buffer-data)
|
||||
(setf (mh-buffer-data) (mh-make-buffer-data)))
|
||||
;; Bind variables in folder buffer in case they are local
|
||||
(let ((formfile mh-mhl-format-file)
|
||||
(clean-message-header mh-clean-message-header-flag)
|
||||
(invisible-headers mh-invisible-header-fields-compiled)
|
||||
(visible-headers nil)
|
||||
(msg-filename (mh-msg-filename msg-num folder-name))
|
||||
(show-buffer mh-show-buffer)
|
||||
(mm-inline-media-tests mh-mm-inline-media-tests))
|
||||
(if (not (file-exists-p msg-filename))
|
||||
(error "Message %d does not exist" msg-num))
|
||||
(if (and (> mh-show-maximum-size 0)
|
||||
(> (elt (file-attributes msg-filename) 7)
|
||||
mh-show-maximum-size)
|
||||
(not (y-or-n-p
|
||||
(format
|
||||
"Message %d (%d bytes) exceeds %d bytes. Display it? "
|
||||
msg-num (elt (file-attributes msg-filename) 7)
|
||||
mh-show-maximum-size))))
|
||||
(error "Message %d not displayed" msg-num))
|
||||
(set-buffer show-buffer)
|
||||
(cond ((not (equal msg-filename buffer-file-name))
|
||||
(mh-unvisit-file)
|
||||
(setq buffer-read-only nil)
|
||||
;; Cleanup old mime handles
|
||||
(mh-mime-cleanup)
|
||||
(erase-buffer)
|
||||
;; Changing contents, so this hook needs to be reinitialized.
|
||||
;; pgp.el uses this.
|
||||
(if (boundp 'write-contents-hooks) ;Emacs 19
|
||||
(kill-local-variable 'write-contents-hooks))
|
||||
(if formfile
|
||||
(mh-exec-lib-cmd-output "mhl" "-nobell" "-noclear"
|
||||
(if (stringp formfile)
|
||||
(list "-form" formfile))
|
||||
msg-filename)
|
||||
(insert-file-contents-literally msg-filename))
|
||||
;; Use mm to display buffer
|
||||
(when (and mh-decode-mime-flag (not formfile))
|
||||
(mh-add-missing-mime-version-header)
|
||||
(setf (mh-buffer-data) (mh-make-buffer-data))
|
||||
(mh-mime-display))
|
||||
(mh-show-mode)
|
||||
;; Header cleanup
|
||||
(goto-char (point-min))
|
||||
(cond (clean-message-header
|
||||
(mh-clean-msg-header (point-min)
|
||||
invisible-headers
|
||||
visible-headers)
|
||||
(goto-char (point-min)))
|
||||
(t
|
||||
(mh-start-of-uncleaned-message)))
|
||||
(mh-decode-message-header)
|
||||
;; the parts of visiting we want to do (no locking)
|
||||
(or (eq buffer-undo-list t) ;don't save undo info for prev msgs
|
||||
(setq buffer-undo-list nil))
|
||||
(set-buffer-auto-saved)
|
||||
;; the parts of set-visited-file-name we want to do (no locking)
|
||||
(setq buffer-file-name msg-filename)
|
||||
(setq buffer-backed-up nil)
|
||||
(auto-save-mode 1)
|
||||
(set-mark nil)
|
||||
(unwind-protect
|
||||
(when (and mh-decode-mime-flag (not formfile))
|
||||
(setq buffer-read-only nil)
|
||||
(mh-display-smileys)
|
||||
(mh-display-emphasis))
|
||||
(setq buffer-read-only t))
|
||||
(set-buffer-modified-p nil)
|
||||
(setq mh-show-folder-buffer folder)
|
||||
(setq mode-line-buffer-identification
|
||||
(list (format mh-show-buffer-mode-line-buffer-id
|
||||
folder-name msg-num)))
|
||||
(mh-logo-display)
|
||||
(set-buffer folder)
|
||||
(setq mh-showing-with-headers nil))))))
|
||||
|
||||
(defun mh-msg-folder (folder-name)
|
||||
"Return the name of the buffer for FOLDER-NAME."
|
||||
folder-name)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-clean-msg-header (start invisible-headers visible-headers)
|
||||
"Flush extraneous lines in message header.
|
||||
|
||||
Header is cleaned from START to the end of the message header.
|
||||
INVISIBLE-HEADERS contains a regular expression specifying lines
|
||||
to delete from the header. VISIBLE-HEADERS contains a regular
|
||||
expression specifying the lines to display. INVISIBLE-HEADERS is
|
||||
ignored if VISIBLE-HEADERS is non-nil."
|
||||
;; XXX Note that MH-E no longer supports the `mh-visible-headers'
|
||||
;; variable, so this function could be trimmed of this feature too."
|
||||
(let ((case-fold-search t)
|
||||
(buffer-read-only nil))
|
||||
(save-restriction
|
||||
(goto-char start)
|
||||
(if (search-forward "\n\n" nil 'move)
|
||||
(backward-char 1))
|
||||
(narrow-to-region start (point))
|
||||
(goto-char (point-min))
|
||||
(if visible-headers
|
||||
(while (< (point) (point-max))
|
||||
(cond ((looking-at visible-headers)
|
||||
(forward-line 1)
|
||||
(while (looking-at "[ \t]") (forward-line 1)))
|
||||
(t
|
||||
(mh-delete-line 1)
|
||||
(while (looking-at "[ \t]")
|
||||
(mh-delete-line 1)))))
|
||||
(while (re-search-forward invisible-headers nil t)
|
||||
(beginning-of-line)
|
||||
(mh-delete-line 1)
|
||||
(while (looking-at "[ \t]")
|
||||
(mh-delete-line 1)))))
|
||||
(let ((mh-compose-skipped-header-fields ()))
|
||||
(mh-letter-hide-all-skipped-fields))
|
||||
(unlock-buffer)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-invalidate-show-buffer ()
|
||||
"Invalidate the show buffer so we must update it to use it."
|
||||
(if (get-buffer mh-show-buffer)
|
||||
(save-excursion
|
||||
(set-buffer mh-show-buffer)
|
||||
(mh-unvisit-file))))
|
||||
|
||||
(defun mh-unvisit-file ()
|
||||
"Separate current buffer from the message file it was visiting."
|
||||
(or (not (buffer-modified-p))
|
||||
(null buffer-file-name) ;we've been here before
|
||||
(yes-or-no-p (format "Message %s modified; flush changes? "
|
||||
(file-name-nondirectory buffer-file-name)))
|
||||
(error "Flushing changes not confirmed"))
|
||||
(clear-visited-file-modtime)
|
||||
(unlock-buffer)
|
||||
(setq buffer-file-name nil))
|
||||
|
||||
(defun mh-summary-height ()
|
||||
"Return ideal value for the variable `mh-summary-height'.
|
||||
The current frame height is taken into consideration."
|
||||
(or (and (fboundp 'frame-height)
|
||||
(> (frame-height) 24)
|
||||
(min 10 (/ (frame-height) 6)))
|
||||
4))
|
||||
|
||||
|
||||
|
||||
;; Infrastructure to generate show-buffer functions from folder functions
|
||||
;; XEmacs does not have deactivate-mark? What is the equivalent of
|
||||
;; transient-mark-mode for XEmacs? Should we be restoring the mark in the
|
||||
;; folder buffer after the operation has been carried out.
|
||||
(defmacro mh-defun-show-buffer (function original-function
|
||||
&optional dont-return)
|
||||
"Define FUNCTION to run ORIGINAL-FUNCTION in folder buffer.
|
||||
If the buffer we start in is still visible and DONT-RETURN is nil
|
||||
then switch to it after that."
|
||||
`(defun ,function ()
|
||||
,(format "Calls %s from the message's folder.\n%s\nSee \"%s\" for more info.\n"
|
||||
original-function
|
||||
(if dont-return ""
|
||||
"When function completes, returns to the show buffer if it is
|
||||
still visible.\n")
|
||||
original-function)
|
||||
(interactive)
|
||||
(when (buffer-live-p (get-buffer mh-show-folder-buffer))
|
||||
(let ((config (current-window-configuration))
|
||||
(folder-buffer mh-show-folder-buffer)
|
||||
(normal-exit nil)
|
||||
,@(if dont-return () '((cur-buffer-name (buffer-name)))))
|
||||
(pop-to-buffer mh-show-folder-buffer nil)
|
||||
(unless (equal (buffer-name
|
||||
(window-buffer (frame-first-window (selected-frame))))
|
||||
folder-buffer)
|
||||
(delete-other-windows))
|
||||
(mh-goto-cur-msg t)
|
||||
(mh-funcall-if-exists deactivate-mark)
|
||||
(unwind-protect
|
||||
(prog1 (call-interactively (function ,original-function))
|
||||
(setq normal-exit t))
|
||||
(mh-funcall-if-exists deactivate-mark)
|
||||
(when (eq major-mode 'mh-folder-mode)
|
||||
(mh-funcall-if-exists hl-line-highlight))
|
||||
(cond ((not normal-exit)
|
||||
(set-window-configuration config))
|
||||
,(if dont-return
|
||||
`(t (setq mh-previous-window-config config))
|
||||
`((and (get-buffer cur-buffer-name)
|
||||
(window-live-p (get-buffer-window
|
||||
(get-buffer cur-buffer-name))))
|
||||
(pop-to-buffer (get-buffer cur-buffer-name) nil)))))))))
|
||||
|
||||
;; Generate interactive functions for the show buffer from the corresponding
|
||||
;; folder functions.
|
||||
(mh-defun-show-buffer mh-show-previous-undeleted-msg
|
||||
mh-previous-undeleted-msg)
|
||||
(mh-defun-show-buffer mh-show-next-undeleted-msg
|
||||
mh-next-undeleted-msg)
|
||||
(mh-defun-show-buffer mh-show-quit mh-quit)
|
||||
(mh-defun-show-buffer mh-show-delete-msg mh-delete-msg)
|
||||
(mh-defun-show-buffer mh-show-refile-msg mh-refile-msg)
|
||||
(mh-defun-show-buffer mh-show-undo mh-undo)
|
||||
(mh-defun-show-buffer mh-show-execute-commands mh-execute-commands)
|
||||
(mh-defun-show-buffer mh-show-reply mh-reply t)
|
||||
(mh-defun-show-buffer mh-show-redistribute mh-redistribute)
|
||||
(mh-defun-show-buffer mh-show-forward mh-forward t)
|
||||
(mh-defun-show-buffer mh-show-header-display mh-header-display)
|
||||
(mh-defun-show-buffer mh-show-refile-or-write-again
|
||||
mh-refile-or-write-again)
|
||||
(mh-defun-show-buffer mh-show-show mh-show)
|
||||
(mh-defun-show-buffer mh-show-write-message-to-file
|
||||
mh-write-msg-to-file)
|
||||
(mh-defun-show-buffer mh-show-extract-rejected-mail
|
||||
mh-extract-rejected-mail t)
|
||||
(mh-defun-show-buffer mh-show-delete-msg-no-motion
|
||||
mh-delete-msg-no-motion)
|
||||
(mh-defun-show-buffer mh-show-first-msg mh-first-msg)
|
||||
(mh-defun-show-buffer mh-show-last-msg mh-last-msg)
|
||||
(mh-defun-show-buffer mh-show-copy-msg mh-copy-msg)
|
||||
(mh-defun-show-buffer mh-show-edit-again mh-edit-again t)
|
||||
(mh-defun-show-buffer mh-show-goto-msg mh-goto-msg)
|
||||
(mh-defun-show-buffer mh-show-inc-folder mh-inc-folder)
|
||||
(mh-defun-show-buffer mh-show-delete-subject-or-thread
|
||||
mh-delete-subject-or-thread)
|
||||
(mh-defun-show-buffer mh-show-delete-subject mh-delete-subject)
|
||||
(mh-defun-show-buffer mh-show-print-msg mh-print-msg)
|
||||
(mh-defun-show-buffer mh-show-send mh-send t)
|
||||
(mh-defun-show-buffer mh-show-toggle-showing mh-toggle-showing t)
|
||||
(mh-defun-show-buffer mh-show-pipe-msg mh-pipe-msg t)
|
||||
(mh-defun-show-buffer mh-show-sort-folder mh-sort-folder)
|
||||
(mh-defun-show-buffer mh-show-visit-folder mh-visit-folder t)
|
||||
(mh-defun-show-buffer mh-show-rescan-folder mh-rescan-folder)
|
||||
(mh-defun-show-buffer mh-show-pack-folder mh-pack-folder)
|
||||
(mh-defun-show-buffer mh-show-kill-folder mh-kill-folder t)
|
||||
(mh-defun-show-buffer mh-show-list-folders mh-list-folders t)
|
||||
(mh-defun-show-buffer mh-show-undo-folder mh-undo-folder)
|
||||
(mh-defun-show-buffer mh-show-delete-msg-from-seq
|
||||
mh-delete-msg-from-seq)
|
||||
(mh-defun-show-buffer mh-show-delete-seq mh-delete-seq)
|
||||
(mh-defun-show-buffer mh-show-list-sequences mh-list-sequences)
|
||||
(mh-defun-show-buffer mh-show-narrow-to-seq mh-narrow-to-seq)
|
||||
(mh-defun-show-buffer mh-show-put-msg-in-seq mh-put-msg-in-seq)
|
||||
(mh-defun-show-buffer mh-show-msg-is-in-seq mh-msg-is-in-seq)
|
||||
(mh-defun-show-buffer mh-show-widen mh-widen)
|
||||
(mh-defun-show-buffer mh-show-narrow-to-subject mh-narrow-to-subject)
|
||||
(mh-defun-show-buffer mh-show-narrow-to-from mh-narrow-to-from)
|
||||
(mh-defun-show-buffer mh-show-narrow-to-cc mh-narrow-to-cc)
|
||||
(mh-defun-show-buffer mh-show-narrow-to-range mh-narrow-to-range)
|
||||
(mh-defun-show-buffer mh-show-narrow-to-to mh-narrow-to-to)
|
||||
(mh-defun-show-buffer mh-show-store-msg mh-store-msg)
|
||||
(mh-defun-show-buffer mh-show-page-digest mh-page-digest)
|
||||
(mh-defun-show-buffer mh-show-page-digest-backwards
|
||||
mh-page-digest-backwards)
|
||||
(mh-defun-show-buffer mh-show-burst-digest mh-burst-digest)
|
||||
(mh-defun-show-buffer mh-show-page-msg mh-page-msg)
|
||||
(mh-defun-show-buffer mh-show-previous-page mh-previous-page)
|
||||
(mh-defun-show-buffer mh-show-modify mh-modify t)
|
||||
(mh-defun-show-buffer mh-show-next-button mh-next-button)
|
||||
(mh-defun-show-buffer mh-show-prev-button mh-prev-button)
|
||||
(mh-defun-show-buffer mh-show-toggle-mime-part mh-folder-toggle-mime-part)
|
||||
(mh-defun-show-buffer mh-show-save-mime-part mh-folder-save-mime-part)
|
||||
(mh-defun-show-buffer mh-show-inline-mime-part mh-folder-inline-mime-part)
|
||||
(mh-defun-show-buffer mh-show-toggle-threads mh-toggle-threads)
|
||||
(mh-defun-show-buffer mh-show-thread-delete mh-thread-delete)
|
||||
(mh-defun-show-buffer mh-show-thread-refile mh-thread-refile)
|
||||
(mh-defun-show-buffer mh-show-update-sequences mh-update-sequences)
|
||||
(mh-defun-show-buffer mh-show-next-unread-msg mh-next-unread-msg)
|
||||
(mh-defun-show-buffer mh-show-previous-unread-msg mh-previous-unread-msg)
|
||||
(mh-defun-show-buffer mh-show-thread-ancestor mh-thread-ancestor)
|
||||
(mh-defun-show-buffer mh-show-thread-next-sibling mh-thread-next-sibling)
|
||||
(mh-defun-show-buffer mh-show-thread-previous-sibling
|
||||
mh-thread-previous-sibling)
|
||||
(mh-defun-show-buffer mh-show-index-visit-folder mh-index-visit-folder t)
|
||||
(mh-defun-show-buffer mh-show-toggle-tick mh-toggle-tick)
|
||||
(mh-defun-show-buffer mh-show-narrow-to-tick mh-narrow-to-tick)
|
||||
(mh-defun-show-buffer mh-show-junk-blacklist mh-junk-blacklist)
|
||||
(mh-defun-show-buffer mh-show-junk-whitelist mh-junk-whitelist)
|
||||
(mh-defun-show-buffer mh-show-index-new-messages mh-index-new-messages)
|
||||
(mh-defun-show-buffer mh-show-index-ticked-messages mh-index-ticked-messages)
|
||||
(mh-defun-show-buffer mh-show-index-sequenced-messages
|
||||
mh-index-sequenced-messages)
|
||||
(mh-defun-show-buffer mh-show-catchup mh-catchup)
|
||||
(mh-defun-show-buffer mh-show-ps-print-toggle-color mh-ps-print-toggle-color)
|
||||
(mh-defun-show-buffer mh-show-ps-print-toggle-faces mh-ps-print-toggle-faces)
|
||||
(mh-defun-show-buffer mh-show-ps-print-msg-file mh-ps-print-msg-file)
|
||||
(mh-defun-show-buffer mh-show-ps-print-msg mh-ps-print-msg)
|
||||
(mh-defun-show-buffer mh-show-toggle-mime-buttons mh-toggle-mime-buttons)
|
||||
(mh-defun-show-buffer mh-show-display-with-external-viewer
|
||||
mh-display-with-external-viewer)
|
||||
|
||||
|
||||
|
||||
;;; Sequence Menu
|
||||
|
||||
(easy-menu-define
|
||||
mh-show-sequence-menu mh-show-mode-map "Menu for MH-E folder-sequence."
|
||||
'("Sequence"
|
||||
["Add Message to Sequence..." mh-show-put-msg-in-seq t]
|
||||
["List Sequences for Message" mh-show-msg-is-in-seq t]
|
||||
["Delete Message from Sequence..." mh-show-delete-msg-from-seq t]
|
||||
["List Sequences in Folder..." mh-show-list-sequences t]
|
||||
["Delete Sequence..." mh-show-delete-seq t]
|
||||
["Narrow to Sequence..." mh-show-narrow-to-seq t]
|
||||
["Widen from Sequence" mh-show-widen t]
|
||||
"--"
|
||||
["Narrow to Subject Sequence" mh-show-narrow-to-subject t]
|
||||
["Narrow to Tick Sequence" mh-show-narrow-to-tick
|
||||
(save-excursion
|
||||
(set-buffer mh-show-folder-buffer)
|
||||
(and mh-tick-seq (mh-seq-msgs (mh-find-seq mh-tick-seq))))]
|
||||
["Delete Rest of Same Subject" mh-show-delete-subject t]
|
||||
["Toggle Tick Mark" mh-show-toggle-tick t]
|
||||
"--"
|
||||
["Push State Out to MH" mh-show-update-sequences t]))
|
||||
|
||||
;;; Message Menu
|
||||
|
||||
(easy-menu-define
|
||||
mh-show-message-menu mh-show-mode-map "Menu for MH-E folder-message."
|
||||
'("Message"
|
||||
["Show Message" mh-show-show t]
|
||||
["Show Message with Header" mh-show-header-display t]
|
||||
["Next Message" mh-show-next-undeleted-msg t]
|
||||
["Previous Message" mh-show-previous-undeleted-msg t]
|
||||
["Go to First Message" mh-show-first-msg t]
|
||||
["Go to Last Message" mh-show-last-msg t]
|
||||
["Go to Message by Number..." mh-show-goto-msg t]
|
||||
["Modify Message" mh-show-modify t]
|
||||
["Delete Message" mh-show-delete-msg t]
|
||||
["Refile Message" mh-show-refile-msg t]
|
||||
["Undo Delete/Refile" mh-show-undo t]
|
||||
["Process Delete/Refile" mh-show-execute-commands t]
|
||||
"--"
|
||||
["Compose a New Message" mh-send t]
|
||||
["Reply to Message..." mh-show-reply t]
|
||||
["Forward Message..." mh-show-forward t]
|
||||
["Redistribute Message..." mh-show-redistribute t]
|
||||
["Edit Message Again" mh-show-edit-again t]
|
||||
["Re-edit a Bounced Message" mh-show-extract-rejected-mail t]
|
||||
"--"
|
||||
["Copy Message to Folder..." mh-show-copy-msg t]
|
||||
["Print Message" mh-show-print-msg t]
|
||||
["Write Message to File..." mh-show-write-msg-to-file t]
|
||||
["Pipe Message to Command..." mh-show-pipe-msg t]
|
||||
["Unpack Uuencoded Message..." mh-show-store-msg t]
|
||||
["Burst Digest Message" mh-show-burst-digest t]))
|
||||
|
||||
;;; Folder Menu
|
||||
|
||||
(easy-menu-define
|
||||
mh-show-folder-menu mh-show-mode-map "Menu for MH-E folder."
|
||||
'("Folder"
|
||||
["Incorporate New Mail" mh-show-inc-folder t]
|
||||
["Toggle Show/Folder" mh-show-toggle-showing t]
|
||||
["Execute Delete/Refile" mh-show-execute-commands t]
|
||||
["Rescan Folder" mh-show-rescan-folder t]
|
||||
["Thread Folder" mh-show-toggle-threads t]
|
||||
["Pack Folder" mh-show-pack-folder t]
|
||||
["Sort Folder" mh-show-sort-folder t]
|
||||
"--"
|
||||
["List Folders" mh-show-list-folders t]
|
||||
["Visit a Folder..." mh-show-visit-folder t]
|
||||
["View New Messages" mh-show-index-new-messages t]
|
||||
["Search..." mh-search t]
|
||||
"--"
|
||||
["Quit MH-E" mh-quit t]))
|
||||
|
||||
|
||||
|
||||
;;; MH-Show Keys
|
||||
|
||||
(gnus-define-keys mh-show-mode-map
|
||||
" " mh-show-page-msg
|
||||
"!" mh-show-refile-or-write-again
|
||||
"'" mh-show-toggle-tick
|
||||
"," mh-show-header-display
|
||||
"." mh-show-show
|
||||
">" mh-show-write-message-to-file
|
||||
"?" mh-help
|
||||
"E" mh-show-extract-rejected-mail
|
||||
"M" mh-show-modify
|
||||
"\177" mh-show-previous-page
|
||||
"\C-d" mh-show-delete-msg-no-motion
|
||||
"\t" mh-show-next-button
|
||||
[backtab] mh-show-prev-button
|
||||
"\M-\t" mh-show-prev-button
|
||||
"\ed" mh-show-redistribute
|
||||
"^" mh-show-refile-msg
|
||||
"c" mh-show-copy-msg
|
||||
"d" mh-show-delete-msg
|
||||
"e" mh-show-edit-again
|
||||
"f" mh-show-forward
|
||||
"g" mh-show-goto-msg
|
||||
"i" mh-show-inc-folder
|
||||
"k" mh-show-delete-subject-or-thread
|
||||
"m" mh-show-send
|
||||
"n" mh-show-next-undeleted-msg
|
||||
"\M-n" mh-show-next-unread-msg
|
||||
"o" mh-show-refile-msg
|
||||
"p" mh-show-previous-undeleted-msg
|
||||
"\M-p" mh-show-previous-unread-msg
|
||||
"q" mh-show-quit
|
||||
"r" mh-show-reply
|
||||
"s" mh-show-send
|
||||
"t" mh-show-toggle-showing
|
||||
"u" mh-show-undo
|
||||
"x" mh-show-execute-commands
|
||||
"v" mh-show-index-visit-folder
|
||||
"|" mh-show-pipe-msg)
|
||||
|
||||
(gnus-define-keys (mh-show-folder-map "F" mh-show-mode-map)
|
||||
"?" mh-prefix-help
|
||||
"'" mh-index-ticked-messages
|
||||
"S" mh-show-sort-folder
|
||||
"c" mh-show-catchup
|
||||
"f" mh-show-visit-folder
|
||||
"k" mh-show-kill-folder
|
||||
"l" mh-show-list-folders
|
||||
"n" mh-index-new-messages
|
||||
"o" mh-show-visit-folder
|
||||
"q" mh-show-index-sequenced-messages
|
||||
"r" mh-show-rescan-folder
|
||||
"s" mh-search
|
||||
"t" mh-show-toggle-threads
|
||||
"u" mh-show-undo-folder
|
||||
"v" mh-show-visit-folder)
|
||||
|
||||
(gnus-define-keys (mh-show-sequence-map "S" mh-show-mode-map)
|
||||
"'" mh-show-narrow-to-tick
|
||||
"?" mh-prefix-help
|
||||
"d" mh-show-delete-msg-from-seq
|
||||
"k" mh-show-delete-seq
|
||||
"l" mh-show-list-sequences
|
||||
"n" mh-show-narrow-to-seq
|
||||
"p" mh-show-put-msg-in-seq
|
||||
"s" mh-show-msg-is-in-seq
|
||||
"w" mh-show-widen)
|
||||
|
||||
(define-key mh-show-mode-map "I" mh-inc-spool-map)
|
||||
|
||||
(gnus-define-keys (mh-show-junk-map "J" mh-show-mode-map)
|
||||
"?" mh-prefix-help
|
||||
"b" mh-show-junk-blacklist
|
||||
"w" mh-show-junk-whitelist)
|
||||
|
||||
(gnus-define-keys (mh-show-ps-print-map "P" mh-show-mode-map)
|
||||
"?" mh-prefix-help
|
||||
"C" mh-show-ps-print-toggle-color
|
||||
"F" mh-show-ps-print-toggle-faces
|
||||
"f" mh-show-ps-print-msg-file
|
||||
"l" mh-show-print-msg
|
||||
"p" mh-show-ps-print-msg)
|
||||
|
||||
(gnus-define-keys (mh-show-thread-map "T" mh-show-mode-map)
|
||||
"?" mh-prefix-help
|
||||
"u" mh-show-thread-ancestor
|
||||
"p" mh-show-thread-previous-sibling
|
||||
"n" mh-show-thread-next-sibling
|
||||
"t" mh-show-toggle-threads
|
||||
"d" mh-show-thread-delete
|
||||
"o" mh-show-thread-refile)
|
||||
|
||||
(gnus-define-keys (mh-show-limit-map "/" mh-show-mode-map)
|
||||
"'" mh-show-narrow-to-tick
|
||||
"?" mh-prefix-help
|
||||
"c" mh-show-narrow-to-cc
|
||||
"g" mh-show-narrow-to-range
|
||||
"m" mh-show-narrow-to-from
|
||||
"s" mh-show-narrow-to-subject
|
||||
"t" mh-show-narrow-to-to
|
||||
"w" mh-show-widen)
|
||||
|
||||
(gnus-define-keys (mh-show-extract-map "X" mh-show-mode-map)
|
||||
"?" mh-prefix-help
|
||||
"s" mh-show-store-msg
|
||||
"u" mh-show-store-msg)
|
||||
|
||||
(gnus-define-keys (mh-show-digest-map "D" mh-show-mode-map)
|
||||
"?" mh-prefix-help
|
||||
" " mh-show-page-digest
|
||||
"\177" mh-show-page-digest-backwards
|
||||
"b" mh-show-burst-digest)
|
||||
|
||||
(gnus-define-keys (mh-show-mime-map "K" mh-show-mode-map)
|
||||
"?" mh-prefix-help
|
||||
"a" mh-mime-save-parts
|
||||
"e" mh-show-display-with-external-viewer
|
||||
"v" mh-show-toggle-mime-part
|
||||
"o" mh-show-save-mime-part
|
||||
"i" mh-show-inline-mime-part
|
||||
"t" mh-show-toggle-mime-buttons
|
||||
"\t" mh-show-next-button
|
||||
[backtab] mh-show-prev-button
|
||||
"\M-\t" mh-show-prev-button)
|
||||
|
||||
|
||||
|
||||
;;; MH-Show Font Lock
|
||||
|
||||
(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 (mh-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)
|
||||
"Return the value of a header field To to font-lock.
|
||||
Argument LIMIT limits search."
|
||||
(mh-header-field-font-lock "To:" limit))
|
||||
|
||||
(defun mh-header-cc-font-lock (limit)
|
||||
"Return the value of a header field cc to font-lock.
|
||||
Argument LIMIT limits search."
|
||||
(mh-header-field-font-lock "cc:" limit))
|
||||
|
||||
(defun mh-header-subject-font-lock (limit)
|
||||
"Return the value of a header field Subject to font-lock.
|
||||
Argument LIMIT limits search."
|
||||
(mh-header-field-font-lock "Subject:" limit))
|
||||
|
||||
(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 (mh-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-show-font-lock-fontify-region (beg end loudly)
|
||||
"Limit font-lock in `mh-show-mode' to the header.
|
||||
|
||||
Used when the option `mh-highlight-citation-style' is set to
|
||||
\"Gnus\", leaving the body to be dealt with by Gnus highlighting.
|
||||
The region between BEG and END is given over to be fontified and
|
||||
LOUDLY controls if a user sees a message about the fontification
|
||||
operation."
|
||||
(let ((header-end (mh-mail-header-end)))
|
||||
(cond
|
||||
((and (< beg header-end)(< end header-end))
|
||||
(font-lock-default-fontify-region beg end loudly))
|
||||
((and (< beg header-end)(>= end header-end))
|
||||
(font-lock-default-fontify-region beg header-end loudly))
|
||||
(t
|
||||
nil))))
|
||||
|
||||
(defvar mh-show-font-lock-keywords
|
||||
'(("^\\(From:\\|Sender:\\)\\(.*\\)"
|
||||
(1 'default)
|
||||
(2 'mh-show-from))
|
||||
(mh-header-to-font-lock
|
||||
(0 'default)
|
||||
(1 'mh-show-to))
|
||||
(mh-header-cc-font-lock
|
||||
(0 'default)
|
||||
(1 'mh-show-cc))
|
||||
("^\\(Reply-To:\\|Return-Path:\\)\\(.*\\)$"
|
||||
(1 'default)
|
||||
(2 'mh-show-from))
|
||||
(mh-header-subject-font-lock
|
||||
(0 'default)
|
||||
(1 'mh-show-subject))
|
||||
("^\\(Apparently-To:\\|Newsgroups:\\)\\(.*\\)"
|
||||
(1 'default)
|
||||
(2 'mh-show-cc))
|
||||
("^\\(In-reply-to\\|Date\\):\\(.*\\)$"
|
||||
(1 'default)
|
||||
(2 'mh-show-date))
|
||||
(mh-letter-header-font-lock
|
||||
(0 'mh-show-header append t)))
|
||||
"Additional expressions to highlight in MH-Show buffers.")
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-show-font-lock-keywords ()
|
||||
"Return variable `mh-show-font-lock-keywords'."
|
||||
mh-show-font-lock-keywords)
|
||||
|
||||
(defvar mh-show-font-lock-keywords-with-cite
|
||||
(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 buffers.")
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-show-font-lock-keywords-with-cite ()
|
||||
"Return variable `mh-show-font-lock-keywords-with-cite'."
|
||||
mh-show-font-lock-keywords-with-cite)
|
||||
|
||||
|
||||
|
||||
;;; MH-Show Mode
|
||||
|
||||
;; Ensure new buffers won't get this mode if default-major-mode is nil.
|
||||
(put 'mh-show-mode 'mode-class 'special)
|
||||
|
||||
;; Shush compiler.
|
||||
(eval-when-compile (defvar font-lock-auto-fontify))
|
||||
|
||||
;;;###mh-autoload
|
||||
(define-derived-mode mh-show-mode text-mode "MH-Show"
|
||||
"Major mode for showing messages in MH-E.\\<mh-show-mode-map>
|
||||
|
||||
The hook `mh-show-mode-hook' is called upon entry to this mode.
|
||||
|
||||
See also `mh-folder-mode'.
|
||||
|
||||
\\{mh-show-mode-map}"
|
||||
(set (make-local-variable 'mail-header-separator) mh-mail-header-separator)
|
||||
(setq paragraph-start (default-value 'paragraph-start))
|
||||
(mh-show-unquote-From)
|
||||
(mh-show-xface)
|
||||
(mh-show-addr)
|
||||
(setq buffer-invisibility-spec '((vanish . t) t))
|
||||
(set (make-local-variable 'line-move-ignore-invisible) t)
|
||||
(make-local-variable 'font-lock-defaults)
|
||||
;;(set (make-local-variable 'font-lock-support-mode) nil)
|
||||
(cond
|
||||
((equal mh-highlight-citation-style 'font-lock)
|
||||
(setq font-lock-defaults '(mh-show-font-lock-keywords-with-cite t)))
|
||||
((equal mh-highlight-citation-style 'gnus)
|
||||
(setq font-lock-defaults '((mh-show-font-lock-keywords)
|
||||
t nil nil nil
|
||||
(font-lock-fontify-region-function
|
||||
. mh-show-font-lock-fontify-region)))
|
||||
(mh-gnus-article-highlight-citation))
|
||||
(t
|
||||
(setq font-lock-defaults '(mh-show-font-lock-keywords t))))
|
||||
(if (and mh-xemacs-flag
|
||||
font-lock-auto-fontify)
|
||||
(turn-on-font-lock))
|
||||
(set (make-local-variable 'tool-bar-map) mh-show-tool-bar-map)
|
||||
(mh-funcall-if-exists mh-tool-bar-init :show)
|
||||
(when mh-decode-mime-flag
|
||||
(mh-make-local-hook 'kill-buffer-hook)
|
||||
(add-hook 'kill-buffer-hook 'mh-mime-cleanup nil t))
|
||||
(easy-menu-add mh-show-sequence-menu)
|
||||
(easy-menu-add mh-show-message-menu)
|
||||
(easy-menu-add mh-show-folder-menu)
|
||||
(make-local-variable 'mh-show-folder-buffer)
|
||||
(buffer-disable-undo)
|
||||
(setq buffer-read-only t)
|
||||
(use-local-map mh-show-mode-map))
|
||||
|
||||
|
||||
|
||||
;;; Support Routines
|
||||
|
||||
(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)
|
||||
(buffer-read-only nil))
|
||||
(goto-char (mh-mail-header-end))
|
||||
(while (re-search-forward "^>From" nil t)
|
||||
(replace-match "From"))
|
||||
(set-buffer-modified-p modified))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-show-addr ()
|
||||
"Use `goto-address'."
|
||||
(when mh-show-use-goto-addr-flag
|
||||
(require 'goto-addr nil t)
|
||||
(if (fboundp 'goto-address)
|
||||
(goto-address))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-gnus-article-highlight-citation ()
|
||||
"Highlight cited text in current buffer using Gnus."
|
||||
(interactive)
|
||||
;; Don't allow Gnus to create buttons while highlighting, maybe this is bad
|
||||
;; style?
|
||||
(flet ((gnus-article-add-button (&rest args) nil))
|
||||
(let* ((modified (buffer-modified-p))
|
||||
(gnus-article-buffer (buffer-name))
|
||||
(gnus-cite-face-list `(,@(cdr gnus-cite-face-list)
|
||||
,(car gnus-cite-face-list))))
|
||||
(gnus-article-highlight-citation t)
|
||||
(set-buffer-modified-p modified))))
|
||||
|
||||
(provide 'mh-show)
|
||||
|
||||
;; Local Variables:
|
||||
;; indent-tabs-mode: nil
|
||||
;; sentence-end-double-space: nil
|
||||
;; End:
|
||||
|
||||
;;; mh-show.el ends here
|
@ -1,6 +1,6 @@
|
||||
;;; mh-speed.el --- Speedbar interface for MH-E.
|
||||
;;; mh-speed.el --- MH-E speedbar support
|
||||
|
||||
;; Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
;; Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Satyaki Das <satyaki@theforce.stanford.edu>
|
||||
;; Maintainer: Bill Wohler <wohler@newt.com>
|
||||
@ -25,23 +25,21 @@
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;; Future versions should only use flists.
|
||||
|
||||
;; Speedbar support for MH-E package.
|
||||
;; Future versions should only use flists.
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;(message "> mh-speed")
|
||||
(eval-when-compile (require 'mh-acros))
|
||||
(mh-require-cl)
|
||||
(require 'mh-e)
|
||||
(mh-require-cl)
|
||||
|
||||
(require 'gnus-util)
|
||||
(require 'speedbar)
|
||||
(require 'timer)
|
||||
;;(message "< mh-speed")
|
||||
|
||||
;; Global variables
|
||||
;; Global variables.
|
||||
(defvar mh-speed-refresh-flag nil)
|
||||
(defvar mh-speed-last-selected-folder nil)
|
||||
(defvar mh-speed-folder-map (make-hash-table :test #'equal))
|
||||
@ -50,7 +48,10 @@
|
||||
(defvar mh-speed-flists-timer nil)
|
||||
(defvar mh-speed-partial-line "")
|
||||
|
||||
;; Add our stealth update function
|
||||
|
||||
|
||||
;;; Speedbar Hook
|
||||
|
||||
(unless (member 'mh-speed-stealth-update
|
||||
(cdr (assoc "files" speedbar-stealthy-function-list)))
|
||||
;; Is changing constant lists in elisp safe?
|
||||
@ -59,7 +60,132 @@
|
||||
(push 'mh-speed-stealth-update
|
||||
(cdr (assoc "files" speedbar-stealthy-function-list))))
|
||||
|
||||
;; Functions called by speedbar to initialize display...
|
||||
|
||||
|
||||
;;; Speedbar Menus
|
||||
|
||||
(defvar mh-folder-speedbar-menu-items
|
||||
'("--"
|
||||
["Visit Folder" mh-speed-view
|
||||
(save-excursion
|
||||
(set-buffer speedbar-buffer)
|
||||
(get-text-property (line-beginning-position) 'mh-folder))]
|
||||
["Expand Nested Folders" mh-speed-expand-folder
|
||||
(and (get-text-property (line-beginning-position) 'mh-children-p)
|
||||
(not (get-text-property (line-beginning-position) 'mh-expanded)))]
|
||||
["Contract Nested Folders" mh-speed-contract-folder
|
||||
(and (get-text-property (line-beginning-position) 'mh-children-p)
|
||||
(get-text-property (line-beginning-position) 'mh-expanded))]
|
||||
["Refresh Speedbar" mh-speed-refresh t])
|
||||
"Extra menu items for speedbar.")
|
||||
|
||||
(defvar mh-show-speedbar-menu-items mh-folder-speedbar-menu-items)
|
||||
(defvar mh-letter-speedbar-menu-items mh-folder-speedbar-menu-items)
|
||||
|
||||
|
||||
|
||||
;;; Speedbar Keys
|
||||
|
||||
(defvar mh-folder-speedbar-key-map (speedbar-make-specialized-keymap)
|
||||
"Specialized speedbar keymap for MH-E buffers.")
|
||||
|
||||
(gnus-define-keys mh-folder-speedbar-key-map
|
||||
"+" mh-speed-expand-folder
|
||||
"-" mh-speed-contract-folder
|
||||
"\r" mh-speed-view
|
||||
"r" mh-speed-refresh)
|
||||
|
||||
(defvar mh-show-speedbar-key-map mh-folder-speedbar-key-map)
|
||||
(defvar mh-letter-speedbar-key-map mh-folder-speedbar-key-map)
|
||||
|
||||
|
||||
|
||||
;;; Speedbar Commands
|
||||
|
||||
;; Alphabetical.
|
||||
|
||||
(defalias 'mh-speed-contract-folder 'mh-speed-toggle)
|
||||
|
||||
(defalias 'mh-speed-expand-folder 'mh-speed-toggle)
|
||||
|
||||
(defun mh-speed-refresh ()
|
||||
"Regenerates the list of folders in the speedbar.
|
||||
|
||||
Run this command if you've added or deleted a folder, or want to
|
||||
update the unseen message count before the next automatic
|
||||
update."
|
||||
(interactive)
|
||||
(mh-speed-flists t)
|
||||
(mh-speed-invalidate-map ""))
|
||||
|
||||
(defun mh-speed-stealth-update (&optional force)
|
||||
"Do stealth update.
|
||||
With non-nil FORCE, the update is always carried out."
|
||||
(cond ((save-excursion (set-buffer speedbar-buffer)
|
||||
(get-text-property (point-min) 'mh-level))
|
||||
;; Execute this hook and *don't* run anything else
|
||||
(mh-speed-update-current-folder force)
|
||||
nil)
|
||||
;; Otherwise on to your regular programming
|
||||
(t t)))
|
||||
|
||||
(defun mh-speed-toggle (&rest args)
|
||||
"Toggle the display of child folders in the speedbar.
|
||||
The optional ARGS from speedbar are ignored."
|
||||
(interactive)
|
||||
(declare (ignore args))
|
||||
(beginning-of-line)
|
||||
(let ((parent (get-text-property (point) 'mh-folder))
|
||||
(kids-p (get-text-property (point) 'mh-children-p))
|
||||
(expanded (get-text-property (point) 'mh-expanded))
|
||||
(level (get-text-property (point) 'mh-level))
|
||||
(point (point))
|
||||
start-region)
|
||||
(speedbar-with-writable
|
||||
(cond ((not kids-p) nil)
|
||||
(expanded
|
||||
(forward-line)
|
||||
(setq start-region (point))
|
||||
(while (and (get-text-property (point) 'mh-level)
|
||||
(> (get-text-property (point) 'mh-level) level))
|
||||
(let ((folder (get-text-property (point) 'mh-folder)))
|
||||
(when (gethash folder mh-speed-folder-map)
|
||||
(set-marker (gethash folder mh-speed-folder-map) nil)
|
||||
(remhash folder mh-speed-folder-map)))
|
||||
(forward-line))
|
||||
(delete-region start-region (point))
|
||||
(forward-line -1)
|
||||
(speedbar-change-expand-button-char ?+)
|
||||
(add-text-properties
|
||||
(line-beginning-position) (1+ (line-beginning-position))
|
||||
'(mh-expanded nil)))
|
||||
(t
|
||||
(forward-line)
|
||||
(mh-speed-add-buttons parent (1+ level))
|
||||
(goto-char point)
|
||||
(speedbar-change-expand-button-char ?-)
|
||||
(add-text-properties
|
||||
(line-beginning-position) (1+ (line-beginning-position))
|
||||
`(mh-expanded t)))))))
|
||||
|
||||
(defun mh-speed-view (&rest args)
|
||||
"Visits the selected folder just as if you had used \\<mh-folder-mode-map>\\[mh-visit-folder].
|
||||
The optional ARGS from speedbar are ignored."
|
||||
(interactive)
|
||||
(declare (ignore args))
|
||||
(let* ((folder (get-text-property (line-beginning-position) 'mh-folder))
|
||||
(range (and (stringp folder)
|
||||
(mh-read-range "Scan" folder t nil nil
|
||||
mh-interpret-number-as-range-flag))))
|
||||
(when (stringp folder)
|
||||
(speedbar-with-attached-buffer
|
||||
(mh-visit-folder folder range)
|
||||
(delete-other-windows)))))
|
||||
|
||||
|
||||
|
||||
;;; Support Routines
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-folder-speedbar-buttons (buffer)
|
||||
"Interface function to create MH-E speedbar buffer.
|
||||
@ -86,37 +212,6 @@ created."
|
||||
;;;###mh-autoload
|
||||
(defalias 'mh-letter-speedbar-buttons 'mh-folder-speedbar-buttons)
|
||||
|
||||
;; Keymaps for speedbar...
|
||||
(defvar mh-folder-speedbar-key-map (speedbar-make-specialized-keymap)
|
||||
"Specialized speedbar keymap for MH-E buffers.")
|
||||
(gnus-define-keys mh-folder-speedbar-key-map
|
||||
"+" mh-speed-expand-folder
|
||||
"-" mh-speed-contract-folder
|
||||
"\r" mh-speed-view
|
||||
"r" mh-speed-refresh)
|
||||
|
||||
(defvar mh-show-speedbar-key-map mh-folder-speedbar-key-map)
|
||||
(defvar mh-letter-speedbar-key-map mh-folder-speedbar-key-map)
|
||||
|
||||
;; Menus for speedbar...
|
||||
(defvar mh-folder-speedbar-menu-items
|
||||
'("--"
|
||||
["Visit Folder" mh-speed-view
|
||||
(save-excursion
|
||||
(set-buffer speedbar-buffer)
|
||||
(get-text-property (line-beginning-position) 'mh-folder))]
|
||||
["Expand Nested Folders" mh-speed-expand-folder
|
||||
(and (get-text-property (line-beginning-position) 'mh-children-p)
|
||||
(not (get-text-property (line-beginning-position) 'mh-expanded)))]
|
||||
["Contract Nested Folders" mh-speed-contract-folder
|
||||
(and (get-text-property (line-beginning-position) 'mh-children-p)
|
||||
(get-text-property (line-beginning-position) 'mh-expanded))]
|
||||
["Refresh Speedbar" mh-speed-refresh t])
|
||||
"Extra menu items for speedbar.")
|
||||
|
||||
(defvar mh-show-speedbar-menu-items mh-folder-speedbar-menu-items)
|
||||
(defvar mh-letter-speedbar-menu-items mh-folder-speedbar-menu-items)
|
||||
|
||||
(defmacro mh-speed-select-attached-frame ()
|
||||
"Compatibility macro to handle speedbar versions 0.11a and 0.14beta4."
|
||||
(cond ((fboundp 'dframe-select-attached-frame)
|
||||
@ -167,6 +262,19 @@ The update is always carried out if FORCE is non-nil."
|
||||
(when (eq lastf speedbar-frame)
|
||||
(setq mh-speed-refresh-flag t))))
|
||||
|
||||
(defun mh-speed-highlight (folder face)
|
||||
"Set FOLDER to FACE."
|
||||
(save-excursion
|
||||
(speedbar-with-writable
|
||||
(goto-char (gethash folder mh-speed-folder-map (point)))
|
||||
(beginning-of-line)
|
||||
(if (re-search-forward "([1-9][0-9]*/[0-9]+)" (line-end-position) t)
|
||||
(setq face (mh-speed-bold-face face))
|
||||
(setq face (mh-speed-normal-face face)))
|
||||
(beginning-of-line)
|
||||
(when (re-search-forward "\\[.\\] " (line-end-position) t)
|
||||
(put-text-property (point) (line-end-position) 'face face)))))
|
||||
|
||||
(defun mh-speed-normal-face (face)
|
||||
"Return normal face for given FACE."
|
||||
(cond ((eq face 'mh-speedbar-folder-with-unseen-messages)
|
||||
@ -183,30 +291,6 @@ The update is always carried out if FORCE is non-nil."
|
||||
'mh-speedbar-selected-folder-with-unseen-messages)
|
||||
(t face)))
|
||||
|
||||
(defun mh-speed-highlight (folder face)
|
||||
"Set FOLDER to FACE."
|
||||
(save-excursion
|
||||
(speedbar-with-writable
|
||||
(goto-char (gethash folder mh-speed-folder-map (point)))
|
||||
(beginning-of-line)
|
||||
(if (re-search-forward "([1-9][0-9]*/[0-9]+)" (line-end-position) t)
|
||||
(setq face (mh-speed-bold-face face))
|
||||
(setq face (mh-speed-normal-face face)))
|
||||
(beginning-of-line)
|
||||
(when (re-search-forward "\\[.\\] " (line-end-position) t)
|
||||
(put-text-property (point) (line-end-position) 'face face)))))
|
||||
|
||||
(defun mh-speed-stealth-update (&optional force)
|
||||
"Do stealth update.
|
||||
With non-nil FORCE, the update is always carried out."
|
||||
(cond ((save-excursion (set-buffer speedbar-buffer)
|
||||
(get-text-property (point-min) 'mh-level))
|
||||
;; Execute this hook and *don't* run anything else
|
||||
(mh-speed-update-current-folder force)
|
||||
nil)
|
||||
;; Otherwise on to your regular programming
|
||||
(t t)))
|
||||
|
||||
(defun mh-speed-goto-folder (folder)
|
||||
"Move point to line containing FOLDER.
|
||||
The function will expand out parent folders of FOLDER if needed."
|
||||
@ -295,64 +379,6 @@ uses."
|
||||
mh-level ,level))))))
|
||||
folder-list)))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-speed-toggle (&rest args)
|
||||
"Toggle the display of child folders in the speedbar.
|
||||
The optional ARGS from speedbar are ignored."
|
||||
(interactive)
|
||||
(declare (ignore args))
|
||||
(beginning-of-line)
|
||||
(let ((parent (get-text-property (point) 'mh-folder))
|
||||
(kids-p (get-text-property (point) 'mh-children-p))
|
||||
(expanded (get-text-property (point) 'mh-expanded))
|
||||
(level (get-text-property (point) 'mh-level))
|
||||
(point (point))
|
||||
start-region)
|
||||
(speedbar-with-writable
|
||||
(cond ((not kids-p) nil)
|
||||
(expanded
|
||||
(forward-line)
|
||||
(setq start-region (point))
|
||||
(while (and (get-text-property (point) 'mh-level)
|
||||
(> (get-text-property (point) 'mh-level) level))
|
||||
(let ((folder (get-text-property (point) 'mh-folder)))
|
||||
(when (gethash folder mh-speed-folder-map)
|
||||
(set-marker (gethash folder mh-speed-folder-map) nil)
|
||||
(remhash folder mh-speed-folder-map)))
|
||||
(forward-line))
|
||||
(delete-region start-region (point))
|
||||
(forward-line -1)
|
||||
(speedbar-change-expand-button-char ?+)
|
||||
(add-text-properties
|
||||
(line-beginning-position) (1+ (line-beginning-position))
|
||||
'(mh-expanded nil)))
|
||||
(t
|
||||
(forward-line)
|
||||
(mh-speed-add-buttons parent (1+ level))
|
||||
(goto-char point)
|
||||
(speedbar-change-expand-button-char ?-)
|
||||
(add-text-properties
|
||||
(line-beginning-position) (1+ (line-beginning-position))
|
||||
`(mh-expanded t)))))))
|
||||
|
||||
(defalias 'mh-speed-expand-folder 'mh-speed-toggle)
|
||||
(defalias 'mh-speed-contract-folder 'mh-speed-toggle)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-speed-view (&rest args)
|
||||
"Visits the selected folder just as if you had used \\<mh-folder-mode-map>\\[mh-visit-folder].
|
||||
The optional ARGS from speedbar are ignored."
|
||||
(interactive)
|
||||
(declare (ignore args))
|
||||
(let* ((folder (get-text-property (line-beginning-position) 'mh-folder))
|
||||
(range (and (stringp folder)
|
||||
(mh-read-range "Scan" folder t nil nil
|
||||
mh-interpret-number-as-range-flag))))
|
||||
(when (stringp folder)
|
||||
(speedbar-with-attached-buffer
|
||||
(mh-visit-folder folder range)
|
||||
(delete-other-windows)))))
|
||||
|
||||
(defvar mh-speed-current-folder nil)
|
||||
(defvar mh-speed-flists-folder nil)
|
||||
|
||||
@ -415,6 +441,7 @@ flists is run only for that one folder."
|
||||
'mh-speed-parse-flists-output)))))))
|
||||
|
||||
;; Copied from mh-make-folder-list-filter...
|
||||
;; XXX Refactor to use mh-make-folder-list-filer?
|
||||
(defun mh-speed-parse-flists-output (process output)
|
||||
"Parse the incremental results from flists.
|
||||
PROCESS is the flists process and OUTPUT is the results that must
|
||||
@ -506,17 +533,23 @@ be handled next."
|
||||
(setq mh-speed-last-selected-folder nil)
|
||||
(setq mh-speed-refresh-flag t)))
|
||||
(when (equal folder "")
|
||||
(clrhash mh-sub-folders-cache)))))
|
||||
(mh-clear-sub-folders-cache)))))
|
||||
|
||||
(defun mh-speed-refresh ()
|
||||
"Regenerates the list of folders in the speedbar.
|
||||
|
||||
Run this command if you've added or deleted a folder, or want to
|
||||
update the unseen message count before the next automatic
|
||||
update."
|
||||
(interactive)
|
||||
(mh-speed-flists t)
|
||||
(mh-speed-invalidate-map ""))
|
||||
;; Make it slightly more general to allow for [ ] buttons to be
|
||||
;; changed to [+].
|
||||
(defun mh-speedbar-change-expand-button-char (char)
|
||||
"Change the expansion button character to CHAR for the current line."
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(if (re-search-forward "\\[.\\]" (line-end-position) t)
|
||||
(speedbar-with-writable
|
||||
(backward-char 2)
|
||||
(delete-char 1)
|
||||
(insert-char char 1 t)
|
||||
(put-text-property (point) (1- (point)) 'invisible nil)
|
||||
;; make sure we fix the image on the text here.
|
||||
(mh-funcall-if-exists
|
||||
speedbar-insert-image-button-maybe (- (point) 2) 3)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-speed-add-folder (folder)
|
||||
@ -546,22 +579,6 @@ The function invalidates the latest ancestor that is present."
|
||||
(mh-speed-toggle))
|
||||
(setq mh-speed-refresh-flag t))))
|
||||
|
||||
;; Make it slightly more general to allow for [ ] buttons to be changed to
|
||||
;; [+].
|
||||
(defun mh-speedbar-change-expand-button-char (char)
|
||||
"Change the expansion button character to CHAR for the current line."
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(if (re-search-forward "\\[.\\]" (line-end-position) t)
|
||||
(speedbar-with-writable
|
||||
(backward-char 2)
|
||||
(delete-char 1)
|
||||
(insert-char char 1 t)
|
||||
(put-text-property (point) (1- (point)) 'invisible nil)
|
||||
;; make sure we fix the image on the text here.
|
||||
(mh-funcall-if-exists
|
||||
speedbar-insert-image-button-maybe (- (point) 2) 3)))))
|
||||
|
||||
(provide 'mh-speed)
|
||||
|
||||
;; Local Variables:
|
||||
|
883
lisp/mh-e/mh-thread.el
Normal file
883
lisp/mh-e/mh-thread.el
Normal file
@ -0,0 +1,883 @@
|
||||
;;; mh-thread.el --- MH-E threading support
|
||||
|
||||
;; Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Satyaki Das <satyaki@theforce.stanford.edu>
|
||||
;; 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., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; The threading portion of this files tries to implement the
|
||||
;; algorithm described at:
|
||||
;; http://www.jwz.org/doc/threading.html
|
||||
;; It also begins to implement the IMAP Threading extension RFC. The
|
||||
;; implementation lacks the reference and subject canonicalization of
|
||||
;; the RFC.
|
||||
|
||||
;; In the presentation buffer, children messages are shown indented
|
||||
;; with either [ ] or < > around them. Square brackets ([ ]) denote
|
||||
;; that the algorithm can point out some headers which when taken
|
||||
;; together implies that the unindented message is an ancestor of the
|
||||
;; indented message. If no such proof exists then angles (< >) are
|
||||
;; used.
|
||||
|
||||
;; If threading is slow on your machine, compile this file. Of all the
|
||||
;; files in MH-E, this one really benefits from compilation.
|
||||
|
||||
;; Some issues and problems are as follows:
|
||||
|
||||
;; (1) Scan truncates the fields at length 512. So longer
|
||||
;; references: headers get mutilated. The same kind of MH
|
||||
;; format string works when composing messages. Is there a way
|
||||
;; to avoid this? My scan command is as follows:
|
||||
;; scan +folder -width 10000 \
|
||||
;; -format "%(msg)\n%{message-id}\n%{references}\n%{subject}\n"
|
||||
;; I would really appreciate it if someone would help me with this.
|
||||
|
||||
;; (2) Implement heuristics to recognize message identifiers in
|
||||
;; In-Reply-To: header. Right now it just assumes that the last
|
||||
;; text between angles (< and >) is the message identifier.
|
||||
;; There is the chance that this will incorrectly use an email
|
||||
;; address like a message identifier.
|
||||
|
||||
;; (3) Error checking of found message identifiers should be done.
|
||||
|
||||
;; (4) Since this breaks the assumption that message indices
|
||||
;; increase as one goes down the buffer, the binary search
|
||||
;; based mh-goto-msg doesn't work. I have a simpler replacement
|
||||
;; which may be less efficient.
|
||||
|
||||
;; (5) Better canonicalizing for message identifier and subject
|
||||
;; strings.
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'mh-e)
|
||||
(require 'mh-scan)
|
||||
|
||||
(mh-defstruct (mh-thread-message (:conc-name mh-message-)
|
||||
(:constructor mh-thread-make-message))
|
||||
(id nil)
|
||||
(references ())
|
||||
(subject "")
|
||||
(subject-re-p nil))
|
||||
|
||||
(mh-defstruct (mh-thread-container (:conc-name mh-container-)
|
||||
(:constructor mh-thread-make-container))
|
||||
message parent children
|
||||
(real-child-p t))
|
||||
|
||||
(defvar mh-thread-id-hash nil
|
||||
"Hashtable used to canonicalize message identifiers.")
|
||||
(make-variable-buffer-local 'mh-thread-id-hash)
|
||||
|
||||
(defvar mh-thread-subject-hash nil
|
||||
"Hashtable used to canonicalize subject strings.")
|
||||
(make-variable-buffer-local 'mh-thread-subject-hash)
|
||||
|
||||
(defvar mh-thread-id-table nil
|
||||
"Thread ID table maps from message identifiers to message containers.")
|
||||
(make-variable-buffer-local 'mh-thread-id-table)
|
||||
|
||||
(defvar mh-thread-index-id-map nil
|
||||
"Table to look up message identifier from message index.")
|
||||
(make-variable-buffer-local 'mh-thread-index-id-map)
|
||||
|
||||
(defvar mh-thread-id-index-map nil
|
||||
"Table to look up message index number from message identifier.")
|
||||
(make-variable-buffer-local 'mh-thread-id-index-map)
|
||||
|
||||
(defvar mh-thread-subject-container-hash nil
|
||||
"Hashtable used to group messages by subject.")
|
||||
(make-variable-buffer-local 'mh-thread-subject-container-hash)
|
||||
|
||||
(defvar mh-thread-duplicates nil
|
||||
"Hashtable used to associate messages with the same message identifier.")
|
||||
(make-variable-buffer-local 'mh-thread-duplicates)
|
||||
|
||||
(defvar mh-thread-history ()
|
||||
"Variable to remember the transformations to the thread tree.
|
||||
When new messages are added, these transformations are rewound,
|
||||
then the links are added from the newly seen messages. Finally
|
||||
the transformations are redone to get the new thread tree. This
|
||||
makes incremental threading easier.")
|
||||
(make-variable-buffer-local 'mh-thread-history)
|
||||
|
||||
(defvar mh-thread-body-width nil
|
||||
"Width of scan substring that contains subject and body of message.")
|
||||
|
||||
|
||||
|
||||
;;; MH-Folder Commands
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-ancestor (&optional thread-root-flag)
|
||||
"Display ancestor of current message.
|
||||
|
||||
If you do not care for the way a particular thread has turned,
|
||||
you can move up the chain of messages with this command. This
|
||||
command can also take a prefix argument THREAD-ROOT-FLAG to jump
|
||||
to the message that started everything."
|
||||
(interactive "P")
|
||||
(beginning-of-line)
|
||||
(cond ((not (memq 'unthread mh-view-ops))
|
||||
(error "Folder isn't threaded"))
|
||||
((eobp)
|
||||
(error "No message at point")))
|
||||
(let ((current-level (mh-thread-current-indentation-level)))
|
||||
(cond (thread-root-flag
|
||||
(while (mh-thread-immediate-ancestor))
|
||||
(mh-maybe-show))
|
||||
((equal current-level 1)
|
||||
(message "Message has no ancestor"))
|
||||
(t (mh-thread-immediate-ancestor)
|
||||
(mh-maybe-show)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-delete ()
|
||||
"Delete thread."
|
||||
(interactive)
|
||||
(cond ((not (memq 'unthread mh-view-ops))
|
||||
(error "Folder isn't threaded"))
|
||||
((eobp)
|
||||
(error "No message at point"))
|
||||
(t (let ((region (mh-thread-find-children)))
|
||||
(mh-iterate-on-messages-in-region () (car region) (cadr region)
|
||||
(mh-delete-a-msg nil))
|
||||
(mh-next-msg)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-next-sibling (&optional previous-flag)
|
||||
"Display next sibling.
|
||||
|
||||
With non-nil optional argument PREVIOUS-FLAG jump to the previous
|
||||
sibling."
|
||||
(interactive)
|
||||
(cond ((not (memq 'unthread mh-view-ops))
|
||||
(error "Folder isn't threaded"))
|
||||
((eobp)
|
||||
(error "No message at point")))
|
||||
(beginning-of-line)
|
||||
(let ((point (point))
|
||||
(done nil)
|
||||
(my-level (mh-thread-current-indentation-level)))
|
||||
(while (and (not done)
|
||||
(equal (forward-line (if previous-flag -1 1)) 0)
|
||||
(not (eobp)))
|
||||
(let ((level (mh-thread-current-indentation-level)))
|
||||
(cond ((equal level my-level)
|
||||
(setq done 'success))
|
||||
((< level my-level)
|
||||
(message "No %s sibling" (if previous-flag "previous" "next"))
|
||||
(setq done 'failure)))))
|
||||
(cond ((eq done 'success) (mh-maybe-show))
|
||||
((eq done 'failure) (goto-char point))
|
||||
(t (message "No %s sibling" (if previous-flag "previous" "next"))
|
||||
(goto-char point)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-previous-sibling ()
|
||||
"Display previous sibling."
|
||||
(interactive)
|
||||
(mh-thread-next-sibling t))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-refile (folder)
|
||||
"Refile (output) thread into FOLDER."
|
||||
(interactive (list (intern (mh-prompt-for-refile-folder))))
|
||||
(cond ((not (memq 'unthread mh-view-ops))
|
||||
(error "Folder isn't threaded"))
|
||||
((eobp)
|
||||
(error "No message at point"))
|
||||
(t (let ((region (mh-thread-find-children)))
|
||||
(mh-iterate-on-messages-in-region () (car region) (cadr region)
|
||||
(mh-refile-a-msg nil folder))
|
||||
(mh-next-msg)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-toggle-threads ()
|
||||
"Toggle threaded view of folder."
|
||||
(interactive)
|
||||
(let ((msg-at-point (mh-get-msg-num nil))
|
||||
(old-buffer-modified-flag (buffer-modified-p))
|
||||
(buffer-read-only nil))
|
||||
(cond ((memq 'unthread mh-view-ops)
|
||||
(unless (mh-valid-view-change-operation-p 'unthread)
|
||||
(error "Can't unthread folder"))
|
||||
(let ((msg-list ()))
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
(let ((index (mh-get-msg-num nil)))
|
||||
(when index
|
||||
(push index msg-list)))
|
||||
(forward-line))
|
||||
(mh-scan-folder mh-current-folder
|
||||
(mapcar #'(lambda (x) (format "%s" x))
|
||||
(mh-coalesce-msg-list msg-list))
|
||||
t))
|
||||
(when mh-index-data
|
||||
(mh-index-insert-folder-headers)
|
||||
(mh-notate-cur)))
|
||||
(t (mh-thread-folder)
|
||||
(push 'unthread mh-view-ops)))
|
||||
(when msg-at-point (mh-goto-msg msg-at-point t t))
|
||||
(set-buffer-modified-p old-buffer-modified-flag)
|
||||
(mh-recenter nil)))
|
||||
|
||||
|
||||
|
||||
;;; Support Routines
|
||||
|
||||
(defun mh-thread-current-indentation-level ()
|
||||
"Find the number of spaces by which current message is indented."
|
||||
(save-excursion
|
||||
(let ((address-start-offset (+ mh-cmd-note mh-scan-date-flag-width
|
||||
mh-scan-date-width 1))
|
||||
(level 0))
|
||||
(beginning-of-line)
|
||||
(forward-char address-start-offset)
|
||||
(while (char-equal (char-after) ? )
|
||||
(incf level)
|
||||
(forward-char))
|
||||
level)))
|
||||
|
||||
(defun mh-thread-immediate-ancestor ()
|
||||
"Jump to immediate ancestor in thread tree."
|
||||
(beginning-of-line)
|
||||
(let ((point (point))
|
||||
(ancestor-level (- (mh-thread-current-indentation-level) 2))
|
||||
(done nil))
|
||||
(if (< ancestor-level 0)
|
||||
nil
|
||||
(while (and (not done) (equal (forward-line -1) 0))
|
||||
(when (equal ancestor-level (mh-thread-current-indentation-level))
|
||||
(setq done t)))
|
||||
(unless done
|
||||
(goto-char point))
|
||||
done)))
|
||||
|
||||
(defun mh-thread-find-children ()
|
||||
"Return a region containing the current message and its children.
|
||||
The result is returned as a list of two elements. The first is
|
||||
the point at the start of the region and the second is the point
|
||||
at the end."
|
||||
(beginning-of-line)
|
||||
(if (eobp)
|
||||
nil
|
||||
(let ((address-start-offset (+ mh-cmd-note mh-scan-date-flag-width
|
||||
mh-scan-date-width 1))
|
||||
(level (mh-thread-current-indentation-level))
|
||||
spaces begin)
|
||||
(setq begin (point))
|
||||
(setq spaces (format (format "%%%ss" (1+ level)) ""))
|
||||
(forward-line)
|
||||
(block nil
|
||||
(while (not (eobp))
|
||||
(forward-char address-start-offset)
|
||||
(unless (equal (string-match spaces (buffer-substring-no-properties
|
||||
(point) (line-end-position)))
|
||||
0)
|
||||
(beginning-of-line)
|
||||
(backward-char)
|
||||
(return))
|
||||
(forward-line)))
|
||||
(list begin (point)))))
|
||||
|
||||
|
||||
|
||||
;;; Thread Creation
|
||||
|
||||
(defun mh-thread-folder ()
|
||||
"Generate thread view of folder."
|
||||
(message "Threading %s..." (buffer-name))
|
||||
(mh-thread-initialize)
|
||||
(goto-char (point-min))
|
||||
(mh-remove-all-notation)
|
||||
(let ((msg-list ()))
|
||||
(mh-iterate-on-range msg (cons (point-min) (point-max))
|
||||
(setf (gethash msg mh-thread-scan-line-map) (mh-thread-parse-scan-line))
|
||||
(push msg msg-list))
|
||||
(let* ((range (mh-coalesce-msg-list msg-list))
|
||||
(thread-tree (mh-thread-generate (buffer-name) range)))
|
||||
(delete-region (point-min) (point-max))
|
||||
(mh-thread-print-scan-lines thread-tree)
|
||||
(mh-notate-user-sequences)
|
||||
(mh-notate-deleted-and-refiled)
|
||||
(mh-notate-cur)
|
||||
(message "Threading %s...done" (buffer-name)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-inc (folder start-point)
|
||||
"Update thread tree for FOLDER.
|
||||
All messages after START-POINT are added to the thread tree."
|
||||
(mh-thread-rewind-pruning)
|
||||
(mh-remove-all-notation)
|
||||
(goto-char start-point)
|
||||
(let ((msg-list ()))
|
||||
(while (not (eobp))
|
||||
(let ((index (mh-get-msg-num nil)))
|
||||
(when (numberp index)
|
||||
(push index msg-list)
|
||||
(setf (gethash index mh-thread-scan-line-map)
|
||||
(mh-thread-parse-scan-line)))
|
||||
(forward-line)))
|
||||
(let ((thread-tree (mh-thread-generate folder msg-list))
|
||||
(buffer-read-only nil)
|
||||
(old-buffer-modified-flag (buffer-modified-p)))
|
||||
(delete-region (point-min) (point-max))
|
||||
(mh-thread-print-scan-lines thread-tree)
|
||||
(mh-notate-user-sequences)
|
||||
(mh-notate-deleted-and-refiled)
|
||||
(mh-notate-cur)
|
||||
(set-buffer-modified-p old-buffer-modified-flag))))
|
||||
|
||||
(defmacro mh-thread-initialize-hash (var test)
|
||||
"Initialize the hash table in VAR.
|
||||
TEST is the test to use when creating a new hash table."
|
||||
(unless (symbolp var) (error "Expected a symbol: %s" var))
|
||||
`(if ,var (clrhash ,var) (setq ,var (make-hash-table :test ,test))))
|
||||
|
||||
(defun mh-thread-initialize ()
|
||||
"Make new hash tables, or clear them if already present."
|
||||
(mh-thread-initialize-hash mh-thread-id-hash #'equal)
|
||||
(mh-thread-initialize-hash mh-thread-subject-hash #'equal)
|
||||
(mh-thread-initialize-hash mh-thread-id-table #'eq)
|
||||
(mh-thread-initialize-hash mh-thread-id-index-map #'eq)
|
||||
(mh-thread-initialize-hash mh-thread-index-id-map #'eql)
|
||||
(mh-thread-initialize-hash mh-thread-scan-line-map #'eql)
|
||||
(mh-thread-initialize-hash mh-thread-subject-container-hash #'eq)
|
||||
(mh-thread-initialize-hash mh-thread-duplicates #'eq)
|
||||
(setq mh-thread-history ()))
|
||||
|
||||
(defsubst mh-thread-id-container (id)
|
||||
"Given ID, return the corresponding container in `mh-thread-id-table'.
|
||||
If no container exists then a suitable container is created and
|
||||
the id-table is updated."
|
||||
(when (not id)
|
||||
(error "1"))
|
||||
(or (gethash id mh-thread-id-table)
|
||||
(setf (gethash id mh-thread-id-table)
|
||||
(let ((message (mh-thread-make-message :id id)))
|
||||
(mh-thread-make-container :message message)))))
|
||||
|
||||
(defsubst mh-thread-remove-parent-link (child)
|
||||
"Remove parent link of CHILD if it exists."
|
||||
(let* ((child-container (if (mh-thread-container-p child)
|
||||
child (mh-thread-id-container child)))
|
||||
(parent-container (mh-container-parent child-container)))
|
||||
(when parent-container
|
||||
(setf (mh-container-children parent-container)
|
||||
(loop for elem in (mh-container-children parent-container)
|
||||
unless (eq child-container elem) collect elem))
|
||||
(setf (mh-container-parent child-container) nil))))
|
||||
|
||||
(defsubst mh-thread-add-link (parent child &optional at-end-p)
|
||||
"Add links so that PARENT becomes a parent of CHILD.
|
||||
Doesn't make any changes if CHILD is already an ancestor of
|
||||
PARENT. If optional argument AT-END-P is non-nil, the CHILD is
|
||||
added to the end of the children list of PARENT."
|
||||
(let ((parent-container (cond ((null parent) nil)
|
||||
((mh-thread-container-p parent) parent)
|
||||
(t (mh-thread-id-container parent))))
|
||||
(child-container (if (mh-thread-container-p child)
|
||||
child (mh-thread-id-container child))))
|
||||
(when (and parent-container
|
||||
(not (mh-thread-ancestor-p child-container parent-container))
|
||||
(not (mh-thread-ancestor-p parent-container child-container)))
|
||||
(mh-thread-remove-parent-link child-container)
|
||||
(cond ((not at-end-p)
|
||||
(push child-container (mh-container-children parent-container)))
|
||||
((null (mh-container-children parent-container))
|
||||
(push child-container (mh-container-children parent-container)))
|
||||
(t (let ((last-child (mh-container-children parent-container)))
|
||||
(while (cdr last-child)
|
||||
(setq last-child (cdr last-child)))
|
||||
(setcdr last-child (cons child-container nil)))))
|
||||
(setf (mh-container-parent child-container) parent-container))
|
||||
(unless parent-container
|
||||
(mh-thread-remove-parent-link child-container))))
|
||||
|
||||
(defun mh-thread-rewind-pruning ()
|
||||
"Restore the thread tree to its state before pruning."
|
||||
(while mh-thread-history
|
||||
(let ((action (pop mh-thread-history)))
|
||||
(cond ((eq (car action) 'DROP)
|
||||
(mh-thread-remove-parent-link (cadr action))
|
||||
(mh-thread-add-link (caddr action) (cadr action)))
|
||||
((eq (car action) 'PROMOTE)
|
||||
(let ((node (cadr action))
|
||||
(parent (caddr action))
|
||||
(children (cdddr action)))
|
||||
(dolist (child children)
|
||||
(mh-thread-remove-parent-link child)
|
||||
(mh-thread-add-link node child))
|
||||
(mh-thread-add-link parent node)))
|
||||
((eq (car action) 'SUBJECT)
|
||||
(let ((node (cadr action)))
|
||||
(mh-thread-remove-parent-link node)
|
||||
(setf (mh-container-real-child-p node) t)))))))
|
||||
|
||||
(defun mh-thread-ancestor-p (ancestor successor)
|
||||
"Return t if ANCESTOR is really an ancestor of SUCCESSOR and nil otherwise.
|
||||
In the limit, the function returns t if ANCESTOR and SUCCESSOR
|
||||
are the same containers."
|
||||
(block nil
|
||||
(while successor
|
||||
(when (eq ancestor successor) (return t))
|
||||
(setq successor (mh-container-parent successor)))
|
||||
nil))
|
||||
|
||||
;; Another and may be better approach would be to generate all the info from
|
||||
;; the scan which generates the threading info. For now this will have to do.
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-parse-scan-line (&optional string)
|
||||
"Parse a scan line.
|
||||
If optional argument STRING is given then that is assumed to be
|
||||
the scan line. Otherwise uses the line at point as the scan line
|
||||
to parse."
|
||||
(let* ((string (or string
|
||||
(buffer-substring-no-properties (line-beginning-position)
|
||||
(line-end-position))))
|
||||
(address-start (+ mh-cmd-note mh-scan-field-from-start-offset))
|
||||
(body-start (+ mh-cmd-note mh-scan-field-from-end-offset))
|
||||
(first-string (substring string 0 address-start)))
|
||||
(list first-string
|
||||
(substring string address-start (- body-start 2))
|
||||
(substring string body-start)
|
||||
string)))
|
||||
|
||||
(defsubst mh-thread-canonicalize-id (id)
|
||||
"Produce canonical string representation for ID.
|
||||
This allows cheap string comparison with EQ."
|
||||
(or (and (equal id "") (copy-sequence ""))
|
||||
(gethash id mh-thread-id-hash)
|
||||
(setf (gethash id mh-thread-id-hash) id)))
|
||||
|
||||
(defsubst mh-thread-prune-subject (subject)
|
||||
"Prune leading Re:'s, Fwd:'s etc. and trailing (fwd)'s from SUBJECT.
|
||||
If the result after pruning is not the empty string then it is
|
||||
canonicalized so that subjects can be tested for equality with
|
||||
eq. This is done so that all the messages without a subject are
|
||||
not put into a single thread."
|
||||
(let ((case-fold-search t)
|
||||
(subject-pruned-flag nil))
|
||||
;; Prune subject leader
|
||||
(while (or (string-match "^[ \t]*\\(re\\|fwd?\\)\\(\\[[0-9]*\\]\\)?:[ \t]*"
|
||||
subject)
|
||||
(string-match "^[ \t]*\\[[^\\]][ \t]*" subject))
|
||||
(setq subject-pruned-flag t)
|
||||
(setq subject (substring subject (match-end 0))))
|
||||
;; Prune subject trailer
|
||||
(while (or (string-match "(fwd)$" subject)
|
||||
(string-match "[ \t]+$" subject))
|
||||
(setq subject-pruned-flag t)
|
||||
(setq subject (substring subject 0 (match-beginning 0))))
|
||||
;; Canonicalize subject only if it is non-empty
|
||||
(cond ((equal subject "") (values subject subject-pruned-flag))
|
||||
(t (values
|
||||
(or (gethash subject mh-thread-subject-hash)
|
||||
(setf (gethash subject mh-thread-subject-hash) subject))
|
||||
subject-pruned-flag)))))
|
||||
|
||||
(defsubst mh-thread-group-by-subject (roots)
|
||||
"Group the set of message containers, ROOTS based on subject.
|
||||
Bug: Check for and make sure that something without Re: is made
|
||||
the parent in preference to something that has it."
|
||||
(clrhash mh-thread-subject-container-hash)
|
||||
(let ((results ()))
|
||||
(dolist (root roots)
|
||||
(let* ((subject (mh-thread-container-subject root))
|
||||
(parent (gethash subject mh-thread-subject-container-hash)))
|
||||
(cond (parent (mh-thread-remove-parent-link root)
|
||||
(mh-thread-add-link parent root t)
|
||||
(setf (mh-container-real-child-p root) nil)
|
||||
(push `(SUBJECT ,root) mh-thread-history))
|
||||
(t
|
||||
(setf (gethash subject mh-thread-subject-container-hash) root)
|
||||
(push root results)))))
|
||||
(nreverse results)))
|
||||
|
||||
(defun mh-thread-container-subject (container)
|
||||
"Return the subject of CONTAINER.
|
||||
If CONTAINER is empty return the subject info of one of its
|
||||
children."
|
||||
(cond ((and (mh-container-message container)
|
||||
(mh-message-id (mh-container-message container)))
|
||||
(mh-message-subject (mh-container-message container)))
|
||||
(t (block nil
|
||||
(dolist (kid (mh-container-children container))
|
||||
(when (and (mh-container-message kid)
|
||||
(mh-message-id (mh-container-message kid)))
|
||||
(let ((kid-message (mh-container-message kid)))
|
||||
(return (mh-message-subject kid-message)))))
|
||||
(error "This can't happen")))))
|
||||
|
||||
(defsubst mh-thread-update-id-index-maps (id index)
|
||||
"Message with id, ID is the message in INDEX.
|
||||
The function also checks for duplicate messages (that is multiple
|
||||
messages with the same ID). These messages are put in the
|
||||
`mh-thread-duplicates' hash table."
|
||||
(let ((old-index (gethash id mh-thread-id-index-map)))
|
||||
(when old-index (push old-index (gethash id mh-thread-duplicates)))
|
||||
(setf (gethash id mh-thread-id-index-map) index)
|
||||
(setf (gethash index mh-thread-index-id-map) id)))
|
||||
|
||||
(defsubst mh-thread-get-message-container (message)
|
||||
"Return container which has MESSAGE in it.
|
||||
If there is no container present then a new container is
|
||||
allocated."
|
||||
(let* ((id (mh-message-id message))
|
||||
(container (gethash id mh-thread-id-table)))
|
||||
(cond (container (setf (mh-container-message container) message)
|
||||
container)
|
||||
(t (setf (gethash id mh-thread-id-table)
|
||||
(mh-thread-make-container :message message))))))
|
||||
|
||||
(defsubst mh-thread-get-message (id subject-re-p subject refs)
|
||||
"Return appropriate message.
|
||||
Otherwise update message already present to have the proper ID,
|
||||
SUBJECT-RE-P, SUBJECT and REFS fields."
|
||||
(let* ((container (gethash id mh-thread-id-table))
|
||||
(message (if container (mh-container-message container) nil)))
|
||||
(cond (message
|
||||
(setf (mh-message-subject-re-p message) subject-re-p)
|
||||
(setf (mh-message-subject message) subject)
|
||||
(setf (mh-message-id message) id)
|
||||
(setf (mh-message-references message) refs)
|
||||
message)
|
||||
(container
|
||||
(setf (mh-container-message container)
|
||||
(mh-thread-make-message :id id :references refs
|
||||
:subject subject
|
||||
:subject-re-p subject-re-p)))
|
||||
(t (let ((message (mh-thread-make-message :id id :references refs
|
||||
:subject-re-p subject-re-p
|
||||
:subject subject)))
|
||||
(prog1 message
|
||||
(mh-thread-get-message-container message)))))))
|
||||
|
||||
(defvar mh-message-id-regexp "^<.*@.*>$"
|
||||
"Regexp to recognize whether a string is a message identifier.")
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-generate (folder msg-list)
|
||||
"Scan FOLDER to get info for threading.
|
||||
Only information about messages in MSG-LIST are added to the tree."
|
||||
(with-temp-buffer
|
||||
(mh-thread-set-tables folder)
|
||||
(when msg-list
|
||||
(apply
|
||||
#'call-process (expand-file-name mh-scan-prog mh-progs) nil '(t nil) nil
|
||||
"-width" "10000" "-format"
|
||||
"%(msg)\n%{message-id}\n%{references}\n%{in-reply-to}\n%{subject}\n"
|
||||
folder (mapcar #'(lambda (x) (format "%s" x)) msg-list)))
|
||||
(goto-char (point-min))
|
||||
(let ((roots ())
|
||||
(case-fold-search t))
|
||||
(block nil
|
||||
(while (not (eobp))
|
||||
(block process-message
|
||||
(let* ((index-line
|
||||
(prog1 (buffer-substring (point) (line-end-position))
|
||||
(forward-line)))
|
||||
(index (string-to-number index-line))
|
||||
(id (prog1 (buffer-substring (point) (line-end-position))
|
||||
(forward-line)))
|
||||
(refs (prog1 (buffer-substring (point) (line-end-position))
|
||||
(forward-line)))
|
||||
(in-reply-to (prog1 (buffer-substring (point)
|
||||
(line-end-position))
|
||||
(forward-line)))
|
||||
(subject (prog1
|
||||
(buffer-substring (point) (line-end-position))
|
||||
(forward-line)))
|
||||
(subject-re-p nil))
|
||||
(unless (gethash index mh-thread-scan-line-map)
|
||||
(return-from process-message))
|
||||
(unless (integerp index) (return)) ;Error message here
|
||||
(multiple-value-setq (subject subject-re-p)
|
||||
(mh-thread-prune-subject subject))
|
||||
(setq in-reply-to (mh-thread-process-in-reply-to in-reply-to))
|
||||
(setq refs (loop for x in (append (split-string refs) in-reply-to)
|
||||
when (string-match mh-message-id-regexp x)
|
||||
collect x))
|
||||
(setq id (mh-thread-canonicalize-id id))
|
||||
(mh-thread-update-id-index-maps id index)
|
||||
(setq refs (mapcar #'mh-thread-canonicalize-id refs))
|
||||
(mh-thread-get-message id subject-re-p subject refs)
|
||||
(do ((ancestors refs (cdr ancestors)))
|
||||
((null (cdr ancestors))
|
||||
(when (car ancestors)
|
||||
(mh-thread-remove-parent-link id)
|
||||
(mh-thread-add-link (car ancestors) id)))
|
||||
(mh-thread-add-link (car ancestors) (cadr ancestors)))))))
|
||||
(maphash #'(lambda (k v)
|
||||
(declare (ignore k))
|
||||
(when (null (mh-container-parent v))
|
||||
(push v roots)))
|
||||
mh-thread-id-table)
|
||||
(setq roots (mh-thread-prune-containers roots))
|
||||
(prog1 (setq roots (mh-thread-group-by-subject roots))
|
||||
(let ((history mh-thread-history))
|
||||
(set-buffer folder)
|
||||
(setq mh-thread-history history))))))
|
||||
|
||||
(defun mh-thread-set-tables (folder)
|
||||
"Use the tables of FOLDER in current buffer."
|
||||
(flet ((mh-get-table (symbol)
|
||||
(save-excursion
|
||||
(set-buffer folder)
|
||||
(symbol-value symbol))))
|
||||
(setq mh-thread-id-hash (mh-get-table 'mh-thread-id-hash))
|
||||
(setq mh-thread-subject-hash (mh-get-table 'mh-thread-subject-hash))
|
||||
(setq mh-thread-id-table (mh-get-table 'mh-thread-id-table))
|
||||
(setq mh-thread-id-index-map (mh-get-table 'mh-thread-id-index-map))
|
||||
(setq mh-thread-index-id-map (mh-get-table 'mh-thread-index-id-map))
|
||||
(setq mh-thread-scan-line-map (mh-get-table 'mh-thread-scan-line-map))
|
||||
(setq mh-thread-subject-container-hash
|
||||
(mh-get-table 'mh-thread-subject-container-hash))
|
||||
(setq mh-thread-duplicates (mh-get-table 'mh-thread-duplicates))
|
||||
(setq mh-thread-history (mh-get-table 'mh-thread-history))))
|
||||
|
||||
(defun mh-thread-process-in-reply-to (reply-to-header)
|
||||
"Extract message id's from REPLY-TO-HEADER.
|
||||
Ideally this should have some regexp which will try to guess if a
|
||||
string between < and > is a message id and not an email address.
|
||||
For now it will take the last string inside angles."
|
||||
(let ((end (mh-search-from-end ?> reply-to-header)))
|
||||
(when (numberp end)
|
||||
(let ((begin (mh-search-from-end ?< (substring reply-to-header 0 end))))
|
||||
(when (numberp begin)
|
||||
(list (substring reply-to-header begin (1+ end))))))))
|
||||
|
||||
(defun mh-thread-prune-containers (roots)
|
||||
"Prune empty containers in the containers ROOTS."
|
||||
(let ((dfs-ordered-nodes ())
|
||||
(work-list roots))
|
||||
(while work-list
|
||||
(let ((node (pop work-list)))
|
||||
(dolist (child (mh-container-children node))
|
||||
(push child work-list))
|
||||
(push node dfs-ordered-nodes)))
|
||||
(while dfs-ordered-nodes
|
||||
(let ((node (pop dfs-ordered-nodes)))
|
||||
(cond ((gethash (mh-message-id (mh-container-message node))
|
||||
mh-thread-id-index-map)
|
||||
;; Keep it
|
||||
(setf (mh-container-children node)
|
||||
(mh-thread-sort-containers (mh-container-children node))))
|
||||
((and (mh-container-children node)
|
||||
(or (null (cdr (mh-container-children node)))
|
||||
(mh-container-parent node)))
|
||||
;; Promote kids
|
||||
(let ((children ()))
|
||||
(dolist (kid (mh-container-children node))
|
||||
(mh-thread-remove-parent-link kid)
|
||||
(mh-thread-add-link (mh-container-parent node) kid)
|
||||
(push kid children))
|
||||
(push `(PROMOTE ,node ,(mh-container-parent node) ,@children)
|
||||
mh-thread-history)
|
||||
(mh-thread-remove-parent-link node)))
|
||||
((mh-container-children node)
|
||||
;; Promote the first orphan to parent and add the other kids as
|
||||
;; his children
|
||||
(setf (mh-container-children node)
|
||||
(mh-thread-sort-containers (mh-container-children node)))
|
||||
(let ((new-parent (car (mh-container-children node)))
|
||||
(other-kids (cdr (mh-container-children node))))
|
||||
(mh-thread-remove-parent-link new-parent)
|
||||
(dolist (kid other-kids)
|
||||
(mh-thread-remove-parent-link kid)
|
||||
(setf (mh-container-real-child-p kid) nil)
|
||||
(mh-thread-add-link new-parent kid t))
|
||||
(push `(PROMOTE ,node ,(mh-container-parent node)
|
||||
,new-parent ,@other-kids)
|
||||
mh-thread-history)
|
||||
(mh-thread-remove-parent-link node)))
|
||||
(t
|
||||
;; Drop it
|
||||
(push `(DROP ,node ,(mh-container-parent node))
|
||||
mh-thread-history)
|
||||
(mh-thread-remove-parent-link node)))))
|
||||
(let ((results ()))
|
||||
(maphash #'(lambda (k v)
|
||||
(declare (ignore k))
|
||||
(when (and (null (mh-container-parent v))
|
||||
(gethash (mh-message-id (mh-container-message v))
|
||||
mh-thread-id-index-map))
|
||||
(push v results)))
|
||||
mh-thread-id-table)
|
||||
(mh-thread-sort-containers results))))
|
||||
|
||||
(defun mh-thread-sort-containers (containers)
|
||||
"Sort a list of message CONTAINERS to be in ascending order wrt index."
|
||||
(sort containers
|
||||
#'(lambda (x y)
|
||||
(when (and (mh-container-message x) (mh-container-message y))
|
||||
(let* ((id-x (mh-message-id (mh-container-message x)))
|
||||
(id-y (mh-message-id (mh-container-message y)))
|
||||
(index-x (gethash id-x mh-thread-id-index-map))
|
||||
(index-y (gethash id-y mh-thread-id-index-map)))
|
||||
(and (integerp index-x) (integerp index-y)
|
||||
(< index-x index-y)))))))
|
||||
|
||||
(defvar mh-thread-last-ancestor)
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-print-scan-lines (thread-tree)
|
||||
"Print scan lines in THREAD-TREE in threaded mode."
|
||||
(let ((mh-thread-body-width (- (window-width) mh-cmd-note
|
||||
(1- mh-scan-field-subject-start-offset)))
|
||||
(mh-thread-last-ancestor nil))
|
||||
(if (null mh-index-data)
|
||||
(mh-thread-generate-scan-lines thread-tree -2)
|
||||
(loop for x in (mh-index-group-by-folder)
|
||||
do (let* ((old-map mh-thread-scan-line-map)
|
||||
(mh-thread-scan-line-map (make-hash-table)))
|
||||
(setq mh-thread-last-ancestor nil)
|
||||
(loop for msg in (cdr x)
|
||||
do (let ((v (gethash msg old-map)))
|
||||
(when v
|
||||
(setf (gethash msg mh-thread-scan-line-map) v))))
|
||||
(when (> (hash-table-count mh-thread-scan-line-map) 0)
|
||||
(insert (if (bobp) "" "\n") (car x) "\n")
|
||||
(mh-thread-generate-scan-lines thread-tree -2))))
|
||||
(mh-index-create-imenu-index))))
|
||||
|
||||
(defun mh-thread-generate-scan-lines (tree level)
|
||||
"Generate scan lines.
|
||||
TREE is the hierarchical tree of messages, SCAN-LINE-MAP maps
|
||||
message indices to the corresponding scan lines and LEVEL used to
|
||||
determine indentation of the message."
|
||||
(cond ((null tree) nil)
|
||||
((mh-thread-container-p tree)
|
||||
(let* ((message (mh-container-message tree))
|
||||
(id (mh-message-id message))
|
||||
(index (gethash id mh-thread-id-index-map))
|
||||
(duplicates (gethash id mh-thread-duplicates))
|
||||
(new-level (+ level 2))
|
||||
(dupl-flag t)
|
||||
(force-angle-flag nil)
|
||||
(increment-level-flag nil))
|
||||
(dolist (scan-line (mapcar (lambda (x)
|
||||
(gethash x mh-thread-scan-line-map))
|
||||
(reverse (cons index duplicates))))
|
||||
(when scan-line
|
||||
(when (and dupl-flag (equal level 0)
|
||||
(mh-thread-ancestor-p mh-thread-last-ancestor tree))
|
||||
(setq level (+ level 2)
|
||||
new-level (+ new-level 2)
|
||||
force-angle-flag t))
|
||||
(when (equal level 0)
|
||||
(setq mh-thread-last-ancestor tree)
|
||||
(while (mh-container-parent mh-thread-last-ancestor)
|
||||
(setq mh-thread-last-ancestor
|
||||
(mh-container-parent mh-thread-last-ancestor))))
|
||||
(let* ((lev (if dupl-flag level new-level))
|
||||
(square-flag (or (and (mh-container-real-child-p tree)
|
||||
(not force-angle-flag)
|
||||
dupl-flag)
|
||||
(equal lev 0))))
|
||||
(insert (car scan-line)
|
||||
(format (format "%%%ss" lev) "")
|
||||
(if square-flag "[" "<")
|
||||
(cadr scan-line)
|
||||
(if square-flag "]" ">")
|
||||
(truncate-string-to-width
|
||||
(caddr scan-line) (- mh-thread-body-width lev))
|
||||
"\n"))
|
||||
(setq increment-level-flag t)
|
||||
(setq dupl-flag nil)))
|
||||
(unless increment-level-flag (setq new-level level))
|
||||
(dolist (child (mh-container-children tree))
|
||||
(mh-thread-generate-scan-lines child new-level))))
|
||||
(t (let ((nlevel (+ level 2)))
|
||||
(dolist (ch tree)
|
||||
(mh-thread-generate-scan-lines ch nlevel))))))
|
||||
|
||||
|
||||
|
||||
;;; Additional Utilities
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-update-scan-line-map (msg notation offset)
|
||||
"In threaded view update `mh-thread-scan-line-map'.
|
||||
MSG is the message being notated with NOTATION at OFFSET."
|
||||
(let* ((msg (or msg (mh-get-msg-num nil)))
|
||||
(cur-scan-line (and mh-thread-scan-line-map
|
||||
(gethash msg mh-thread-scan-line-map)))
|
||||
(old-scan-lines (loop for map in mh-thread-scan-line-map-stack
|
||||
collect (and map (gethash msg map)))))
|
||||
(when cur-scan-line
|
||||
(setf (aref (car cur-scan-line) offset) notation))
|
||||
(dolist (line old-scan-lines)
|
||||
(when line (setf (aref (car line) offset) notation)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-find-msg-subject (msg)
|
||||
"Find canonicalized subject of MSG.
|
||||
This function can only be used the folder is threaded."
|
||||
(ignore-errors
|
||||
(mh-message-subject
|
||||
(mh-container-message (gethash (gethash msg mh-thread-index-id-map)
|
||||
mh-thread-id-table)))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-add-spaces (count)
|
||||
"Add COUNT spaces to each scan line in `mh-thread-scan-line-map'."
|
||||
(let ((spaces (format (format "%%%ss" count) "")))
|
||||
(while (not (eobp))
|
||||
(let* ((msg-num (mh-get-msg-num nil))
|
||||
(old-line (nth 3 (gethash msg-num mh-thread-scan-line-map))))
|
||||
(when (numberp msg-num)
|
||||
(setf (gethash msg-num mh-thread-scan-line-map)
|
||||
(mh-thread-parse-scan-line (format "%s%s" spaces old-line)))))
|
||||
(forward-line 1))))
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-thread-forget-message (index)
|
||||
"Forget the message INDEX from the threading tables."
|
||||
(let* ((id (gethash index mh-thread-index-id-map))
|
||||
(id-index (gethash id mh-thread-id-index-map))
|
||||
(duplicates (gethash id mh-thread-duplicates)))
|
||||
(remhash index mh-thread-index-id-map)
|
||||
(remhash index mh-thread-scan-line-map)
|
||||
(cond ((and (eql index id-index) (null duplicates))
|
||||
(remhash id mh-thread-id-index-map))
|
||||
((eql index id-index)
|
||||
(setf (gethash id mh-thread-id-index-map) (car duplicates))
|
||||
(setf (gethash (car duplicates) mh-thread-index-id-map) id)
|
||||
(setf (gethash id mh-thread-duplicates) (cdr duplicates)))
|
||||
(t
|
||||
(setf (gethash id mh-thread-duplicates)
|
||||
(remove index duplicates))))))
|
||||
|
||||
(provide 'mh-thread)
|
||||
|
||||
;; Local Variables:
|
||||
;; indent-tabs-mode: nil
|
||||
;; sentence-end-double-space: nil
|
||||
;; End:
|
||||
|
||||
;;; mh-thread.el ends here
|
419
lisp/mh-e/mh-tool-bar.el
Normal file
419
lisp/mh-e/mh-tool-bar.el
Normal file
@ -0,0 +1,419 @@
|
||||
;;; mh-tool-bar.el --- MH-E tool bar support
|
||||
|
||||
;; Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Satyaki Das <satyaki@theforce.stanford.edu>
|
||||
;; 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., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'mh-e)
|
||||
|
||||
;;; Tool Bar Commands
|
||||
|
||||
(defun mh-tool-bar-search (&optional arg)
|
||||
"Interactively call `mh-tool-bar-search-function'.
|
||||
Optional argument ARG is not used."
|
||||
(interactive "P")
|
||||
(call-interactively mh-tool-bar-search-function))
|
||||
|
||||
(defun mh-tool-bar-customize ()
|
||||
"Call `mh-customize' from the tool bar."
|
||||
(interactive)
|
||||
(mh-customize t))
|
||||
|
||||
(defun mh-tool-bar-folder-help ()
|
||||
"Visit \"(mh-e)Top\"."
|
||||
(interactive)
|
||||
(info "(mh-e)Top")
|
||||
(delete-other-windows))
|
||||
|
||||
(defun mh-tool-bar-letter-help ()
|
||||
"Visit \"(mh-e)Editing Drafts\"."
|
||||
(interactive)
|
||||
(info "(mh-e)Editing Drafts")
|
||||
(delete-other-windows))
|
||||
|
||||
(defmacro mh-tool-bar-reply-generator (function recipient folder-buffer-flag)
|
||||
"Generate FUNCTION that replies to RECIPIENT.
|
||||
If FOLDER-BUFFER-FLAG is nil then the function generated...
|
||||
When INCLUDE-FLAG is non-nil, include message body being replied to."
|
||||
`(defun ,function (&optional arg)
|
||||
,(format "Reply to \"%s\".\nWhen ARG is non-nil include message in reply."
|
||||
recipient)
|
||||
(interactive "P")
|
||||
,(if folder-buffer-flag nil '(set-buffer mh-show-folder-buffer))
|
||||
(mh-reply (mh-get-msg-num nil) ,recipient arg)))
|
||||
|
||||
(mh-tool-bar-reply-generator mh-tool-bar-reply-from "from" t)
|
||||
(mh-tool-bar-reply-generator mh-show-tool-bar-reply-from "from" nil)
|
||||
(mh-tool-bar-reply-generator mh-tool-bar-reply-to "to" t)
|
||||
(mh-tool-bar-reply-generator mh-show-tool-bar-reply-to "to" nil)
|
||||
(mh-tool-bar-reply-generator mh-tool-bar-reply-all "all" t)
|
||||
(mh-tool-bar-reply-generator mh-show-tool-bar-reply-all "all" nil)
|
||||
|
||||
|
||||
|
||||
;;; Tool Bar Creation
|
||||
|
||||
(defmacro mh-tool-bar-define (defaults &rest buttons)
|
||||
"Define a tool bar for MH-E.
|
||||
DEFAULTS is the list of buttons that are present by default. It
|
||||
is a list of lists where the sublists are of the following form:
|
||||
|
||||
(:KEYWORD FUNC1 FUNC2 FUNC3 ...)
|
||||
|
||||
Here :KEYWORD is one of :folder or :letter. If it is :folder then
|
||||
the default buttons in the folder and show mode buffers are being
|
||||
specified. If it is :letter then the default buttons in the
|
||||
letter mode are listed. FUNC1, FUNC2, FUNC3, ... are the names of
|
||||
the functions that the buttons would execute.
|
||||
|
||||
Each element of BUTTONS is a list consisting of four mandatory
|
||||
items and one optional item as follows:
|
||||
|
||||
(FUNCTION MODES ICON DOC &optional ENABLE-EXPR)
|
||||
|
||||
where,
|
||||
|
||||
FUNCTION is the name of the function that will be executed when
|
||||
the button is clicked.
|
||||
|
||||
MODES is a list of symbols. List elements must be from \"folder\",
|
||||
\"letter\" and \"sequence\". If \"folder\" is present then the button is
|
||||
available in the folder and show buffer. If the name of FUNCTION is
|
||||
of the form \"mh-foo\", where foo is some arbitrary string, then we
|
||||
check if the function `mh-show-foo' exists. If it exists then that
|
||||
function is used in the show buffer. Otherwise the original function
|
||||
`mh-foo' is used in the show buffer as well. Presence of \"sequence\"
|
||||
is handled similar to the above. The only difference is that the
|
||||
button is shown only when the folder is narrowed to a sequence. If
|
||||
\"letter\" is present in MODES, then the button is available during
|
||||
draft editing and runs FUNCTION when clicked.
|
||||
|
||||
ICON is the icon that is drawn in the button.
|
||||
|
||||
DOC is the documentation for the button. It is used in tool-tips and
|
||||
in providing other help to the user. GNU Emacs uses only the first
|
||||
line of the string. So the DOC should be formatted such that the
|
||||
first line is useful and complete without the rest of the string.
|
||||
|
||||
Optional item ENABLE-EXPR is an arbitrary lisp expression. If it
|
||||
evaluates to nil, then the button is deactivated, otherwise it is
|
||||
active. If it isn't present then the button is always active."
|
||||
;; The following variable names have been carefully chosen to make code
|
||||
;; generation easier. Modifying the names should be done carefully.
|
||||
(let (folder-buttons folder-docs folder-button-setter sequence-button-setter
|
||||
show-buttons show-button-setter show-seq-button-setter
|
||||
letter-buttons letter-docs letter-button-setter
|
||||
folder-defaults letter-defaults
|
||||
folder-vectors show-vectors letter-vectors)
|
||||
(dolist (x defaults)
|
||||
(cond ((eq (car x) :folder) (setq folder-defaults (cdr x)))
|
||||
((eq (car x) :letter) (setq letter-defaults (cdr x)))))
|
||||
(dolist (button buttons)
|
||||
(unless (and (listp button)
|
||||
(or (equal (length button) 4) (equal (length button) 5)))
|
||||
(error "Incorrect MH-E tool-bar button specification: %s" button))
|
||||
(let* ((name (nth 0 button))
|
||||
(name-str (symbol-name name))
|
||||
(icon (nth 2 button))
|
||||
(xemacs-icon (mh-do-in-xemacs
|
||||
(cdr (assoc (intern icon) mh-xemacs-icon-map))))
|
||||
(full-doc (nth 3 button))
|
||||
(doc (if (string-match "\\(.*\\)\n" full-doc)
|
||||
(match-string 1 full-doc)
|
||||
full-doc))
|
||||
(enable-expr (or (nth 4 button) t))
|
||||
(modes (nth 1 button))
|
||||
functions show-sym)
|
||||
(when (memq 'letter modes) (setq functions `(:letter ,name)))
|
||||
(when (or (memq 'folder modes) (memq 'sequence modes))
|
||||
(setq functions
|
||||
(append `(,(if (memq 'folder modes) :folder :sequence) ,name)
|
||||
functions))
|
||||
(setq show-sym
|
||||
(if (string-match "^mh-\\(.*\\)$" name-str)
|
||||
(intern (concat "mh-show-" (match-string 1 name-str)))
|
||||
name))
|
||||
(setq functions
|
||||
(append `(,(if (memq 'folder modes) :show :show-seq)
|
||||
,(if (fboundp show-sym) show-sym name))
|
||||
functions)))
|
||||
(do ((functions functions (cddr functions)))
|
||||
((null functions))
|
||||
(let* ((type (car functions))
|
||||
(function (cadr functions))
|
||||
(type1 (substring (symbol-name type) 1))
|
||||
(vector-list (cond ((eq type :show) 'show-vectors)
|
||||
((eq type :show-seq) 'show-vectors)
|
||||
((eq type :letter) 'letter-vectors)
|
||||
(t 'folder-vectors)))
|
||||
(list (cond ((eq type :letter) 'mh-tool-bar-letter-buttons)
|
||||
(t 'mh-tool-bar-folder-buttons)))
|
||||
(key (intern (concat "mh-" type1 "tool-bar-" name-str)))
|
||||
(setter (intern (concat type1 "-button-setter")))
|
||||
(mbuttons (cond ((eq type :letter) 'letter-buttons)
|
||||
((eq type :show) 'show-buttons)
|
||||
((eq type :show-seq) 'show-buttons)
|
||||
(t 'folder-buttons)))
|
||||
(docs (cond ((eq mbuttons 'letter-buttons) 'letter-docs)
|
||||
((eq mbuttons 'folder-buttons) 'folder-docs))))
|
||||
(add-to-list vector-list `[,xemacs-icon ,function t ,full-doc])
|
||||
(add-to-list
|
||||
setter `(when (member ',name ,list)
|
||||
(mh-funcall-if-exists
|
||||
tool-bar-add-item ,icon ',function ',key
|
||||
:help ,doc :enable ',enable-expr)))
|
||||
(add-to-list mbuttons name)
|
||||
(if docs (add-to-list docs doc))))))
|
||||
(setq folder-buttons (nreverse folder-buttons)
|
||||
letter-buttons (nreverse letter-buttons)
|
||||
show-buttons (nreverse show-buttons)
|
||||
letter-docs (nreverse letter-docs)
|
||||
folder-docs (nreverse folder-docs)
|
||||
folder-vectors (nreverse folder-vectors)
|
||||
show-vectors (nreverse show-vectors)
|
||||
letter-vectors (nreverse letter-vectors))
|
||||
(dolist (x folder-defaults)
|
||||
(unless (memq x folder-buttons)
|
||||
(error "Folder defaults contains unknown button '%s'" x)))
|
||||
(dolist (x letter-defaults)
|
||||
(unless (memq x letter-buttons)
|
||||
(error "Letter defaults contains unknown button '%s'" x)))
|
||||
`(eval-when (compile load eval)
|
||||
(defun mh-buffer-exists-p (mode)
|
||||
"Test whether a buffer with major mode MODE is present."
|
||||
(loop for buf in (buffer-list)
|
||||
when (save-excursion
|
||||
(set-buffer buf)
|
||||
(eq major-mode mode))
|
||||
return t))
|
||||
|
||||
;; GNU Emacs tool bar specific code
|
||||
(mh-do-in-gnu-emacs
|
||||
;; Tool bar initialization functions
|
||||
(defun mh-tool-bar-folder-buttons-init ()
|
||||
(when (mh-buffer-exists-p 'mh-folder-mode)
|
||||
(mh-image-load-path)
|
||||
(setq mh-folder-tool-bar-map
|
||||
(let ((tool-bar-map (make-sparse-keymap)))
|
||||
,@(nreverse folder-button-setter)
|
||||
tool-bar-map))
|
||||
(setq mh-show-tool-bar-map
|
||||
(let ((tool-bar-map (make-sparse-keymap)))
|
||||
,@(nreverse show-button-setter)
|
||||
tool-bar-map))
|
||||
(setq mh-show-seq-tool-bar-map
|
||||
(let ((tool-bar-map (copy-keymap mh-show-tool-bar-map)))
|
||||
,@(nreverse show-seq-button-setter)
|
||||
tool-bar-map))
|
||||
(setq mh-folder-seq-tool-bar-map
|
||||
(let ((tool-bar-map (copy-keymap mh-folder-tool-bar-map)))
|
||||
,@(nreverse sequence-button-setter)
|
||||
tool-bar-map))))
|
||||
(defun mh-tool-bar-letter-buttons-init ()
|
||||
(when (mh-buffer-exists-p 'mh-letter-mode)
|
||||
(mh-image-load-path)
|
||||
(setq mh-letter-tool-bar-map
|
||||
(let ((tool-bar-map (make-sparse-keymap)))
|
||||
,@(nreverse letter-button-setter)
|
||||
tool-bar-map))))
|
||||
;; Custom setter functions
|
||||
(defun mh-tool-bar-folder-buttons-set (symbol value)
|
||||
"Construct tool bar for `mh-folder-mode' and `mh-show-mode'."
|
||||
(set-default symbol value)
|
||||
(mh-tool-bar-folder-buttons-init))
|
||||
(defun mh-tool-bar-letter-buttons-set (symbol value)
|
||||
"Construct tool bar for `mh-letter-mode'."
|
||||
(set-default symbol value)
|
||||
(mh-tool-bar-letter-buttons-init)))
|
||||
;; XEmacs specific code
|
||||
(mh-do-in-xemacs
|
||||
(defvar mh-tool-bar-folder-vector-map
|
||||
',(loop for button in folder-buttons
|
||||
for vector in folder-vectors
|
||||
collect (cons button vector)))
|
||||
(defvar mh-tool-bar-show-vector-map
|
||||
',(loop for button in show-buttons
|
||||
for vector in show-vectors
|
||||
collect (cons button vector)))
|
||||
(defvar mh-tool-bar-letter-vector-map
|
||||
',(loop for button in letter-buttons
|
||||
for vector in letter-vectors
|
||||
collect (cons button vector)))
|
||||
(defvar mh-tool-bar-folder-buttons nil)
|
||||
(defvar mh-tool-bar-show-buttons nil)
|
||||
(defvar mh-tool-bar-letter-buttons nil)
|
||||
;; Custom setter functions
|
||||
(defun mh-tool-bar-letter-buttons-set (symbol value)
|
||||
(set-default symbol value)
|
||||
(when mh-xemacs-has-tool-bar-flag
|
||||
(setq mh-tool-bar-letter-buttons
|
||||
(loop for b in value
|
||||
collect (cdr (assoc b mh-tool-bar-letter-vector-map))))))
|
||||
(defun mh-tool-bar-folder-buttons-set (symbol value)
|
||||
(set-default symbol value)
|
||||
(when mh-xemacs-has-tool-bar-flag
|
||||
(setq mh-tool-bar-folder-buttons
|
||||
(loop for b in value
|
||||
collect (cdr (assoc b mh-tool-bar-folder-vector-map))))
|
||||
(setq mh-tool-bar-show-buttons
|
||||
(loop for b in value
|
||||
collect (cdr (assoc b mh-tool-bar-show-vector-map))))))
|
||||
(defun mh-tool-bar-init (mode)
|
||||
"Install tool bar in MODE."
|
||||
(let ((tool-bar (cond ((eq mode :folder) mh-tool-bar-folder-buttons)
|
||||
((eq mode :letter) mh-tool-bar-letter-buttons)
|
||||
((eq mode :show) mh-tool-bar-show-buttons)))
|
||||
(height 37)
|
||||
(width 40)
|
||||
(buffer (current-buffer)))
|
||||
(when mh-xemacs-use-tool-bar-flag
|
||||
(cond
|
||||
((eq mh-xemacs-tool-bar-position 'top)
|
||||
(set-specifier top-toolbar tool-bar buffer)
|
||||
(set-specifier top-toolbar-visible-p t)
|
||||
(set-specifier top-toolbar-height height))
|
||||
((eq mh-xemacs-tool-bar-position 'bottom)
|
||||
(set-specifier bottom-toolbar tool-bar buffer)
|
||||
(set-specifier bottom-toolbar-visible-p t)
|
||||
(set-specifier bottom-toolbar-height height))
|
||||
((eq mh-xemacs-tool-bar-position 'left)
|
||||
(set-specifier left-toolbar tool-bar buffer)
|
||||
(set-specifier left-toolbar-visible-p t)
|
||||
(set-specifier left-toolbar-width width))
|
||||
((eq mh-xemacs-tool-bar-position 'right)
|
||||
(set-specifier right-toolbar tool-bar buffer)
|
||||
(set-specifier right-toolbar-visible-p t)
|
||||
(set-specifier right-toolbar-width width))
|
||||
(t (set-specifier default-toolbar tool-bar buffer)))))))
|
||||
;; Declare customizable tool bars
|
||||
(custom-declare-variable
|
||||
'mh-tool-bar-folder-buttons
|
||||
'(list ,@(mapcar (lambda (x) `(quote ,x)) folder-defaults))
|
||||
"List of buttons to include in MH-Folder tool bar."
|
||||
:group 'mh-tool-bar :set 'mh-tool-bar-folder-buttons-set
|
||||
:type '(set ,@(loop for x in folder-buttons
|
||||
for y in folder-docs
|
||||
collect `(const :tag ,y ,x))))
|
||||
(custom-declare-variable
|
||||
'mh-tool-bar-letter-buttons
|
||||
'(list ,@(mapcar (lambda (x) `(quote ,x)) letter-defaults))
|
||||
"List of buttons to include in MH-Letter tool bar."
|
||||
:group 'mh-tool-bar :set 'mh-tool-bar-letter-buttons-set
|
||||
:type '(set ,@(loop for x in letter-buttons
|
||||
for y in letter-docs
|
||||
collect `(const :tag ,y ,x)))))))
|
||||
|
||||
(mh-tool-bar-define
|
||||
((:folder mh-inc-folder mh-mime-save-parts mh-previous-undeleted-msg
|
||||
mh-page-msg mh-next-undeleted-msg mh-delete-msg mh-refile-msg
|
||||
mh-undo mh-execute-commands mh-toggle-tick mh-reply
|
||||
mh-alias-grab-from-field mh-send mh-rescan-folder
|
||||
mh-tool-bar-search mh-visit-folder
|
||||
mh-tool-bar-customize mh-tool-bar-folder-help mh-widen)
|
||||
(:letter mh-send-letter mh-compose-insertion ispell-message save-buffer
|
||||
undo kill-region menu-bar-kill-ring-save yank mh-fully-kill-draft
|
||||
mh-tool-bar-customize mh-tool-bar-letter-help))
|
||||
;; Folder/Show buffer buttons
|
||||
(mh-inc-folder (folder) "mail"
|
||||
"Incorporate new mail in Inbox
|
||||
This button runs `mh-inc-folder' which drags any
|
||||
new mail into your Inbox folder.")
|
||||
(mh-mime-save-parts (folder) "attach"
|
||||
"Save MIME parts from this message
|
||||
This button runs `mh-mime-save-parts' which saves a message's
|
||||
different parts into separate files.")
|
||||
(mh-previous-undeleted-msg (folder) "left-arrow"
|
||||
"Go to the previous undeleted message
|
||||
This button runs `mh-previous-undeleted-msg'")
|
||||
(mh-page-msg (folder) "page-down"
|
||||
"Page the current message forwards\nThis button runs `mh-page-msg'")
|
||||
(mh-next-undeleted-msg (folder) "right-arrow"
|
||||
"Go to the next undeleted message\nThe button runs `mh-next-undeleted-msg'")
|
||||
(mh-delete-msg (folder) "close"
|
||||
"Mark this message for deletion\nThis button runs `mh-delete-msg'")
|
||||
(mh-refile-msg (folder) "mail/refile"
|
||||
"Refile this message\nThis button runs `mh-refile-msg'")
|
||||
(mh-undo (folder) "undo" "Undo last operation\nThis button runs `undo'"
|
||||
(mh-outstanding-commands-p))
|
||||
(mh-execute-commands (folder) "execute"
|
||||
"Perform moves and deletes\nThis button runs `mh-execute-commands'"
|
||||
(mh-outstanding-commands-p))
|
||||
(mh-toggle-tick (folder) "highlight"
|
||||
"Toggle tick mark\nThis button runs `mh-toggle-tick'")
|
||||
(mh-toggle-showing (folder) "show"
|
||||
"Toggle showing message\nThis button runs `mh-toggle-showing'")
|
||||
(mh-tool-bar-reply-from (folder) "mail/reply-from" "Reply to \"from\"")
|
||||
(mh-tool-bar-reply-to (folder) "mail/reply-to" "Reply to \"to\"")
|
||||
(mh-tool-bar-reply-all (folder) "mail/reply-all" "Reply to \"all\"")
|
||||
(mh-reply (folder) "mail/reply"
|
||||
"Reply to this message\nThis button runs `mh-reply'")
|
||||
(mh-alias-grab-from-field (folder) "mail/alias"
|
||||
"Grab From alias\nThis button runs `mh-alias-grab-from-field'"
|
||||
(and (mh-extract-from-header-value) (not (mh-alias-for-from-p))))
|
||||
(mh-send (folder) "mail/compose"
|
||||
"Compose new message\nThis button runs `mh-send'")
|
||||
(mh-rescan-folder (folder) "refresh"
|
||||
"Rescan this folder\nThis button runs `mh-rescan-folder'")
|
||||
(mh-pack-folder (folder) "mail/repack"
|
||||
"Repack this folder\nThis button runs `mh-pack-folder'")
|
||||
(mh-tool-bar-search (folder) "search"
|
||||
"Search\nThis button runs `mh-tool-bar-search-function'")
|
||||
(mh-visit-folder (folder) "fld-open"
|
||||
"Visit other folder\nThis button runs `mh-visit-folder'")
|
||||
;; Letter buffer buttons
|
||||
(mh-send-letter (letter) "mail/send" "Send this letter")
|
||||
(mh-compose-insertion (letter) "attach" "Insert attachment")
|
||||
(ispell-message (letter) "spell" "Check spelling")
|
||||
(save-buffer (letter) "save" "Save current buffer to its file"
|
||||
(buffer-modified-p))
|
||||
(undo (letter) "undo" "Undo last operation")
|
||||
(kill-region (letter) "cut"
|
||||
"Cut (kill) text in region between mark and current position")
|
||||
(menu-bar-kill-ring-save (letter) "copy"
|
||||
"Copy text in region between mark and current position")
|
||||
(yank (letter) "paste" "Paste (yank) text cut or copied earlier")
|
||||
(mh-fully-kill-draft (letter) "close" "Kill this draft")
|
||||
;; Common buttons
|
||||
(mh-tool-bar-customize (folder letter) "preferences" "MH-E Preferences")
|
||||
(mh-tool-bar-folder-help (folder) "help"
|
||||
"Help! (general help)\nThis button runs `info'")
|
||||
(mh-tool-bar-letter-help (letter) "help"
|
||||
"Help! (general help)\nThis button runs `info'")
|
||||
;; Folder narrowed to sequence buttons
|
||||
(mh-widen (sequence) "widen"
|
||||
"Widen from the sequence\nThis button runs `mh-widen'"))
|
||||
|
||||
(provide 'mh-tool-bar)
|
||||
|
||||
;; Local Variables:
|
||||
;; indent-tabs-mode: nil
|
||||
;; sentence-end-double-space: nil
|
||||
;; End:
|
||||
|
||||
;;; mh-tool-bar.el ends here
|
File diff suppressed because it is too large
Load Diff
528
lisp/mh-e/mh-xface.el
Normal file
528
lisp/mh-e/mh-xface.el
Normal file
@ -0,0 +1,528 @@
|
||||
;;; mh-xface.el --- MH-E X-Face and Face header field display
|
||||
|
||||
;; Copyright (C) 2002, 2003, 2005, 2006 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.
|
||||
|
||||
;; 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., 51 Franklin Street, Fifth Floor,
|
||||
;; Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Change Log:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'mh-e)
|
||||
(mh-require-cl)
|
||||
|
||||
(autoload 'message-fetch-field "message")
|
||||
|
||||
(defvar mh-show-xface-function
|
||||
(cond ((and mh-xemacs-flag (locate-library "x-face") (not (featurep 'xface)))
|
||||
(load "x-face" t t)
|
||||
#'mh-face-display-function)
|
||||
((>= emacs-major-version 21)
|
||||
#'mh-face-display-function)
|
||||
(t #'ignore))
|
||||
"Determine at run time what function should be called to display X-Face.")
|
||||
|
||||
(defvar mh-uncompface-executable
|
||||
(and (fboundp 'executable-find) (executable-find "uncompface")))
|
||||
|
||||
|
||||
|
||||
;;; X-Face Display
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-show-xface ()
|
||||
"Display X-Face."
|
||||
(when (and window-system mh-show-use-xface-flag
|
||||
(or mh-decode-mime-flag mh-mhl-format-file
|
||||
mh-clean-message-header-flag))
|
||||
(funcall mh-show-xface-function)))
|
||||
|
||||
(defmacro mh-face-foreground-compat (face &optional frame inherit)
|
||||
"Return the foreground color name of FACE, or nil if unspecified.
|
||||
See documentation for `face-foreground' for a description of the
|
||||
arguments FACE, FRAME, and INHERIT.
|
||||
|
||||
Calls `face-foreground' correctly in older environments. Versions
|
||||
of Emacs prior to version 22 lacked an INHERIT argument which
|
||||
when t tells `face-foreground' to consider an inherited value for
|
||||
the foreground if the face does not define one itself."
|
||||
(if (>= emacs-major-version 22)
|
||||
`(face-foreground ,face ,frame ,inherit)
|
||||
`(face-foreground ,face ,frame)))
|
||||
|
||||
(defmacro mh-face-background-compat(face &optional frame inherit)
|
||||
"Return the background color name of face, or nil if unspecified.
|
||||
See documentation for `back-foreground' for a description of the
|
||||
arguments FACE, FRAME, and INHERIT.
|
||||
|
||||
Calls `face-background' correctly in older environments. Versions
|
||||
of Emacs prior to version 22 lacked an INHERIT argument which
|
||||
when t tells `face-background' to consider an inherited value for
|
||||
the background if the face does not define one itself."
|
||||
(if (>= emacs-major-version 22)
|
||||
`(face-background ,face ,frame ,inherit)
|
||||
`(face-background ,face ,frame)))
|
||||
|
||||
;; Shush compiler.
|
||||
(eval-when-compile
|
||||
(mh-do-in-xemacs (defvar default-enable-multibyte-characters)))
|
||||
|
||||
(defun mh-face-display-function ()
|
||||
"Display a Face, X-Face, or X-Image-URL header field.
|
||||
If more than one of these are present, then the first one found
|
||||
in this order is used."
|
||||
(save-restriction
|
||||
(goto-char (point-min))
|
||||
(re-search-forward "\n\n" (point-max) t)
|
||||
(narrow-to-region (point-min) (point))
|
||||
(let* ((case-fold-search t)
|
||||
(default-enable-multibyte-characters nil)
|
||||
(face (message-fetch-field "face" t))
|
||||
(x-face (message-fetch-field "x-face" t))
|
||||
(url (message-fetch-field "x-image-url" t))
|
||||
raw type)
|
||||
(cond (face (setq raw (mh-face-to-png face)
|
||||
type 'png))
|
||||
(x-face (setq raw (mh-uncompface x-face)
|
||||
type 'pbm))
|
||||
(url (setq type 'url))
|
||||
(t (multiple-value-setq (type raw) (mh-picon-get-image))))
|
||||
(when type
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^from:" (point-max) t)
|
||||
;; GNU Emacs
|
||||
(mh-do-in-gnu-emacs
|
||||
(if (eq type 'url)
|
||||
(mh-x-image-url-display url)
|
||||
(mh-funcall-if-exists
|
||||
insert-image (create-image
|
||||
raw type t
|
||||
:foreground
|
||||
(mh-face-foreground-compat 'mh-show-xface nil t)
|
||||
:background
|
||||
(mh-face-background-compat 'mh-show-xface nil t))
|
||||
" ")))
|
||||
;; XEmacs
|
||||
(mh-do-in-xemacs
|
||||
(cond
|
||||
((eq type 'url)
|
||||
(mh-x-image-url-display url))
|
||||
((eq type 'png)
|
||||
(when (featurep 'png)
|
||||
(set-extent-begin-glyph
|
||||
(make-extent (point) (point))
|
||||
(make-glyph (vector 'png ':data (mh-face-to-png face))))))
|
||||
;; Try internal xface support if available...
|
||||
((and (eq type 'pbm) (featurep 'xface))
|
||||
(set-glyph-face
|
||||
(set-extent-begin-glyph
|
||||
(make-extent (point) (point))
|
||||
(make-glyph (vector 'xface ':data (concat "X-Face: " x-face))))
|
||||
'mh-show-xface))
|
||||
;; Otherwise try external support with x-face...
|
||||
((and (eq type 'pbm)
|
||||
(fboundp 'x-face-xmas-wl-display-x-face)
|
||||
(fboundp 'executable-find) (executable-find "uncompface"))
|
||||
(mh-funcall-if-exists x-face-xmas-wl-display-x-face))
|
||||
;; Picon display
|
||||
((and raw (member type '(xpm xbm gif)))
|
||||
(when (featurep type)
|
||||
(set-extent-begin-glyph
|
||||
(make-extent (point) (point))
|
||||
(make-glyph (vector type ':data raw))))))
|
||||
(when raw (insert " "))))))))
|
||||
|
||||
(defun mh-face-to-png (data)
|
||||
"Convert base64 encoded DATA to png image."
|
||||
(with-temp-buffer
|
||||
(insert data)
|
||||
(ignore-errors (base64-decode-region (point-min) (point-max)))
|
||||
(buffer-string)))
|
||||
|
||||
(defun mh-uncompface (data)
|
||||
"Run DATA through `uncompface' to generate bitmap."
|
||||
(with-temp-buffer
|
||||
(insert data)
|
||||
(when (and mh-uncompface-executable
|
||||
(equal (call-process-region (point-min) (point-max)
|
||||
mh-uncompface-executable t '(t nil))
|
||||
0))
|
||||
(mh-icontopbm)
|
||||
(buffer-string))))
|
||||
|
||||
(defun mh-icontopbm ()
|
||||
"Elisp substitute for `icontopbm'."
|
||||
(goto-char (point-min))
|
||||
(let ((end (point-max)))
|
||||
(while (re-search-forward "0x\\(..\\)\\(..\\)," nil t)
|
||||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(insert (string-to-number (match-string 1) 16))
|
||||
(insert (string-to-number (match-string 2) 16))))
|
||||
(delete-region (point-min) end)
|
||||
(goto-char (point-min))
|
||||
(insert "P4\n48 48\n")))
|
||||
|
||||
|
||||
|
||||
;;; Picon Display
|
||||
|
||||
;; XXX: This should be customizable. As a side-effect of setting this
|
||||
;; variable, arrange to reset mh-picon-existing-directory-list to 'unset.
|
||||
(defvar mh-picon-directory-list
|
||||
'("~/.picons" "~/.picons/users" "~/.picons/usenix" "~/.picons/news"
|
||||
"~/.picons/domains" "~/.picons/misc"
|
||||
"/usr/share/picons/" "/usr/share/picons/users" "/usr/share/picons/usenix"
|
||||
"/usr/share/picons/news" "/usr/share/picons/domains"
|
||||
"/usr/share/picons/misc")
|
||||
"List of directories where picons reside.
|
||||
The directories are searched for in the order they appear in the list.")
|
||||
|
||||
(defvar mh-picon-existing-directory-list 'unset
|
||||
"List of directories to search in.")
|
||||
|
||||
(defvar mh-picon-cache (make-hash-table :test #'equal))
|
||||
|
||||
(defvar mh-picon-image-types
|
||||
(loop for type in '(xpm xbm gif)
|
||||
when (or (mh-do-in-gnu-emacs
|
||||
(ignore-errors
|
||||
(mh-funcall-if-exists image-type-available-p type)))
|
||||
(mh-do-in-xemacs (featurep type)))
|
||||
collect type))
|
||||
|
||||
(autoload 'message-tokenize-header "sendmail")
|
||||
|
||||
(defun* mh-picon-get-image ()
|
||||
"Find the best possible match and return contents."
|
||||
(mh-picon-set-directory-list)
|
||||
(save-restriction
|
||||
(let* ((from-field (ignore-errors (car (message-tokenize-header
|
||||
(mh-get-header-field "from:")))))
|
||||
(from (car (ignore-errors
|
||||
(mh-funcall-if-exists ietf-drums-parse-address
|
||||
from-field))))
|
||||
(host (and from
|
||||
(string-match "\\([^+]*\\)\\(+.*\\)?@\\(.*\\)" from)
|
||||
(downcase (match-string 3 from))))
|
||||
(user (and host (downcase (match-string 1 from))))
|
||||
(canonical-address (format "%s@%s" user host))
|
||||
(cached-value (gethash canonical-address mh-picon-cache))
|
||||
(host-list (and host (delete "" (split-string host "\\."))))
|
||||
(match nil))
|
||||
(cond (cached-value (return-from mh-picon-get-image cached-value))
|
||||
((not host-list) (return-from mh-picon-get-image nil)))
|
||||
(setq match
|
||||
(block 'loop
|
||||
;; u@h search
|
||||
(loop for dir in mh-picon-existing-directory-list
|
||||
do (loop for type in mh-picon-image-types
|
||||
;; [path]user@host
|
||||
for file1 = (format "%s/%s.%s"
|
||||
dir canonical-address type)
|
||||
when (file-exists-p file1)
|
||||
do (return-from 'loop file1)
|
||||
;; [path]user
|
||||
for file2 = (format "%s/%s.%s" dir user type)
|
||||
when (file-exists-p file2)
|
||||
do (return-from 'loop file2)
|
||||
;; [path]host
|
||||
for file3 = (format "%s/%s.%s" dir host type)
|
||||
when (file-exists-p file3)
|
||||
do (return-from 'loop file3)))
|
||||
;; facedb search
|
||||
;; Search order for user@foo.net:
|
||||
;; [path]net/foo/user
|
||||
;; [path]net/foo/user/face
|
||||
;; [path]net/user
|
||||
;; [path]net/user/face
|
||||
;; [path]net/foo/unknown
|
||||
;; [path]net/foo/unknown/face
|
||||
;; [path]net/unknown
|
||||
;; [path]net/unknown/face
|
||||
(loop for u in (list user "unknown")
|
||||
do (loop for dir in mh-picon-existing-directory-list
|
||||
do (loop for x on host-list by #'cdr
|
||||
for y = (mh-picon-generate-path x u dir)
|
||||
do (loop for type in mh-picon-image-types
|
||||
for z1 = (format "%s.%s" y type)
|
||||
when (file-exists-p z1)
|
||||
do (return-from 'loop z1)
|
||||
for z2 = (format "%s/face.%s"
|
||||
y type)
|
||||
when (file-exists-p z2)
|
||||
do (return-from 'loop z2)))))))
|
||||
(setf (gethash canonical-address mh-picon-cache)
|
||||
(mh-picon-file-contents match)))))
|
||||
|
||||
(defun mh-picon-set-directory-list ()
|
||||
"Update `mh-picon-existing-directory-list' if needed."
|
||||
(when (eq mh-picon-existing-directory-list 'unset)
|
||||
(setq mh-picon-existing-directory-list
|
||||
(loop for x in mh-picon-directory-list
|
||||
when (file-directory-p x) collect x))))
|
||||
|
||||
(defun mh-picon-generate-path (host-list user directory)
|
||||
"Generate the image file path.
|
||||
HOST-LIST is the parsed host address of the email address, USER
|
||||
the username and DIRECTORY is the directory relative to which the
|
||||
path is generated."
|
||||
(loop with acc = ""
|
||||
for elem in host-list
|
||||
do (setq acc (format "%s/%s" elem acc))
|
||||
finally return (format "%s/%s%s" directory acc user)))
|
||||
|
||||
(defun mh-picon-file-contents (file)
|
||||
"Return details about FILE.
|
||||
A list of consisting of a symbol for the type of the file and the
|
||||
file contents as a string is returned. If FILE is nil, then both
|
||||
elements of the list are nil."
|
||||
(if (stringp file)
|
||||
(with-temp-buffer
|
||||
(let ((type (and (string-match ".*\\.\\(...\\)$" file)
|
||||
(intern (match-string 1 file)))))
|
||||
(insert-file-contents-literally file)
|
||||
(values type (buffer-string))))
|
||||
(values nil nil)))
|
||||
|
||||
|
||||
|
||||
;;; X-Image-URL Display
|
||||
|
||||
(defvar mh-x-image-scaling-function
|
||||
(cond ((executable-find "convert")
|
||||
'mh-x-image-scale-with-convert)
|
||||
((and (executable-find "anytopnm") (executable-find "pnmscale")
|
||||
(executable-find "pnmtopng"))
|
||||
'mh-x-image-scale-with-pnm)
|
||||
(t 'ignore))
|
||||
"Function to use to scale image to proper size.")
|
||||
|
||||
(defun mh-x-image-scale-with-pnm (input output)
|
||||
"Scale image in INPUT file and write to OUTPUT file using pnm tools."
|
||||
(let ((res (shell-command-to-string
|
||||
(format "anytopnm < %s | pnmscale -xysize 96 48 | pnmtopng > %s"
|
||||
input output))))
|
||||
(unless (equal res "")
|
||||
(delete-file output))))
|
||||
|
||||
(defun mh-x-image-scale-with-convert (input output)
|
||||
"Scale image in INPUT file and write to OUTPUT file using ImageMagick."
|
||||
(call-process "convert" nil nil nil "-geometry" "96x48" input output))
|
||||
|
||||
(defvar mh-wget-executable nil)
|
||||
(defvar mh-wget-choice
|
||||
(or (and (setq mh-wget-executable (executable-find "wget")) 'wget)
|
||||
(and (setq mh-wget-executable (executable-find "fetch")) 'fetch)
|
||||
(and (setq mh-wget-executable (executable-find "curl")) 'curl)))
|
||||
(defvar mh-wget-option
|
||||
(cdr (assoc mh-wget-choice '((curl . "-o") (fetch . "-o") (wget . "-O")))))
|
||||
(defvar mh-x-image-temp-file nil)
|
||||
(defvar mh-x-image-url nil)
|
||||
(defvar mh-x-image-marker nil)
|
||||
(defvar mh-x-image-url-cache-file nil)
|
||||
|
||||
(defun mh-x-image-url-display (url)
|
||||
"Display image from location URL.
|
||||
If the URL isn't present in the cache then it is fetched with wget."
|
||||
(let* ((cache-filename (mh-x-image-url-cache-canonicalize url))
|
||||
(state (mh-x-image-get-download-state cache-filename))
|
||||
(marker (set-marker (make-marker) (point))))
|
||||
(set (make-local-variable 'mh-x-image-marker) marker)
|
||||
(cond ((not (mh-x-image-url-sane-p url)))
|
||||
((eq state 'ok)
|
||||
(mh-x-image-display cache-filename marker))
|
||||
((or (not mh-wget-executable)
|
||||
(eq mh-x-image-scaling-function 'ignore)))
|
||||
((eq state 'never))
|
||||
((not mh-fetch-x-image-url)
|
||||
(set-marker marker nil))
|
||||
((eq state 'try-again)
|
||||
(mh-x-image-set-download-state cache-filename nil)
|
||||
(mh-x-image-url-fetch-image url cache-filename marker
|
||||
'mh-x-image-scale-and-display))
|
||||
((and (eq mh-fetch-x-image-url 'ask)
|
||||
(not (y-or-n-p (format "Fetch %s? " url))))
|
||||
(mh-x-image-set-download-state cache-filename 'never))
|
||||
((eq state nil)
|
||||
(mh-x-image-url-fetch-image url cache-filename marker
|
||||
'mh-x-image-scale-and-display)))))
|
||||
|
||||
(defvar mh-x-image-cache-directory nil
|
||||
"Directory where X-Image-URL images are cached.")
|
||||
|
||||
;;;###mh-autoload
|
||||
(defun mh-set-x-image-cache-directory (directory)
|
||||
"Set the DIRECTORY where X-Image-URL images are cached.
|
||||
This is only done if `mh-x-image-cache-directory' is nil."
|
||||
;; XXX This is the code that used to be in find-user-path. Is there
|
||||
;; a good reason why the variable is set conditionally? Do we expect
|
||||
;; the user to have set this variable directly?
|
||||
(unless mh-x-image-cache-directory
|
||||
(setq mh-x-image-cache-directory directory)))
|
||||
|
||||
(defun mh-x-image-url-cache-canonicalize (url)
|
||||
"Canonicalize URL.
|
||||
Replace the ?/ character with a ?! character and append .png.
|
||||
Also replaces special characters with `url-hexify-string' since
|
||||
not all characters, such as :, are legal within Windows
|
||||
filenames. See URL `http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp'."
|
||||
(format "%s/%s.png" mh-x-image-cache-directory
|
||||
(url-hexify-string
|
||||
(with-temp-buffer
|
||||
(insert url)
|
||||
(mh-replace-string "/" "!")
|
||||
(buffer-string)))))
|
||||
|
||||
;; Copy of constant from url-util.el in Emacs 22; needed by Emacs 21.
|
||||
(if (not (boundp 'url-unreserved-chars))
|
||||
(defconst url-unreserved-chars
|
||||
'(
|
||||
?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z
|
||||
?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z
|
||||
?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
|
||||
?- ?_ ?. ?! ?~ ?* ?' ?\( ?\))
|
||||
"A list of characters that are _NOT_ reserved in the URL spec.
|
||||
This is taken from RFC 2396."))
|
||||
|
||||
(mh-defun-compat url-hexify-string (str)
|
||||
"Escape characters in a string.
|
||||
This is a copy of the function of the same name from url-util.el
|
||||
in Emacs 22; needed by Emacs 21."
|
||||
(mapconcat
|
||||
(lambda (char)
|
||||
;; Fixme: use a char table instead.
|
||||
(if (not (memq char url-unreserved-chars))
|
||||
(if (> char 255)
|
||||
(error "Hexifying multibyte character %s" str)
|
||||
(format "%%%02X" char))
|
||||
(char-to-string char)))
|
||||
str ""))
|
||||
|
||||
(defun mh-x-image-get-download-state (file)
|
||||
"Check the state of FILE by following any symbolic links."
|
||||
(unless (file-exists-p mh-x-image-cache-directory)
|
||||
(call-process "mkdir" nil nil nil mh-x-image-cache-directory))
|
||||
(cond ((file-symlink-p file)
|
||||
(intern (file-name-nondirectory (file-chase-links file))))
|
||||
((not (file-exists-p file)) nil)
|
||||
(t 'ok)))
|
||||
|
||||
(defun mh-x-image-set-download-state (file data)
|
||||
"Setup a symbolic link from FILE to DATA."
|
||||
(if data
|
||||
(make-symbolic-link (symbol-name data) file t)
|
||||
(delete-file file)))
|
||||
|
||||
(defun mh-x-image-url-sane-p (url)
|
||||
"Check if URL is something sensible."
|
||||
(let ((len (length url)))
|
||||
(cond ((< len 5) nil)
|
||||
((not (equal (substring url 0 5) "http:")) nil)
|
||||
((> len 100) nil)
|
||||
(t t))))
|
||||
|
||||
(defun mh-x-image-display (image marker)
|
||||
"Display IMAGE at MARKER."
|
||||
(save-excursion
|
||||
(set-buffer (marker-buffer marker))
|
||||
(let ((buffer-read-only nil)
|
||||
(default-enable-multibyte-characters nil)
|
||||
(buffer-modified-flag (buffer-modified-p)))
|
||||
(unwind-protect
|
||||
(when (and (file-readable-p image) (not (file-symlink-p image))
|
||||
(eq marker mh-x-image-marker))
|
||||
(goto-char marker)
|
||||
(mh-do-in-gnu-emacs
|
||||
(mh-funcall-if-exists insert-image (create-image image 'png)))
|
||||
(mh-do-in-xemacs
|
||||
(when (featurep 'png)
|
||||
(set-extent-begin-glyph
|
||||
(make-extent (point) (point))
|
||||
(make-glyph
|
||||
(vector 'png ':data (with-temp-buffer
|
||||
(insert-file-contents-literally image)
|
||||
(buffer-string))))))))
|
||||
(set-buffer-modified-p buffer-modified-flag)))))
|
||||
|
||||
(defun mh-x-image-url-fetch-image (url cache-file marker sentinel)
|
||||
"Fetch and display the image specified by URL.
|
||||
After the image is fetched, it is stored in CACHE-FILE. It will
|
||||
be displayed in a buffer and position specified by MARKER. The
|
||||
actual display is carried out by the SENTINEL function."
|
||||
(if mh-wget-executable
|
||||
(let ((buffer (get-buffer-create (generate-new-buffer-name
|
||||
mh-temp-fetch-buffer)))
|
||||
(filename (or (mh-funcall-if-exists make-temp-file "mhe-fetch")
|
||||
(expand-file-name (make-temp-name "~/mhe-fetch")))))
|
||||
(save-excursion
|
||||
(set-buffer buffer)
|
||||
(set (make-local-variable 'mh-x-image-url-cache-file) cache-file)
|
||||
(set (make-local-variable 'mh-x-image-marker) marker)
|
||||
(set (make-local-variable 'mh-x-image-temp-file) filename))
|
||||
(set-process-sentinel
|
||||
(start-process "*mh-x-image-url-fetch*" buffer
|
||||
mh-wget-executable mh-wget-option filename url)
|
||||
sentinel))
|
||||
;; Temporary failure
|
||||
(mh-x-image-set-download-state cache-file 'try-again)))
|
||||
|
||||
(defun mh-x-image-scale-and-display (process change)
|
||||
"When the wget PROCESS terminates scale and display image.
|
||||
The argument CHANGE is ignored."
|
||||
(when (eq (process-status process) 'exit)
|
||||
(let (marker temp-file cache-filename wget-buffer)
|
||||
(save-excursion
|
||||
(set-buffer (setq wget-buffer (process-buffer process)))
|
||||
(setq marker mh-x-image-marker
|
||||
cache-filename mh-x-image-url-cache-file
|
||||
temp-file mh-x-image-temp-file))
|
||||
(cond
|
||||
;; Check if we have `convert'
|
||||
((eq mh-x-image-scaling-function 'ignore)
|
||||
(message "The \"convert\" program is needed to display X-Image-URL")
|
||||
(mh-x-image-set-download-state cache-filename 'try-again))
|
||||
;; Scale fetched image
|
||||
((and (funcall mh-x-image-scaling-function temp-file cache-filename)
|
||||
nil))
|
||||
;; Attempt to display image if we have it
|
||||
((file-exists-p cache-filename)
|
||||
(mh-x-image-display cache-filename marker))
|
||||
;; We didn't find the image. Should we try to display it the next time?
|
||||
(t (mh-x-image-set-download-state cache-filename 'try-again)))
|
||||
(ignore-errors
|
||||
(set-marker marker nil)
|
||||
(delete-process process)
|
||||
(kill-buffer wget-buffer)
|
||||
(delete-file temp-file)))))
|
||||
|
||||
(provide 'mh-xface)
|
||||
|
||||
;; Local Variables:
|
||||
;; indent-tabs-mode: nil
|
||||
;; sentence-end-double-space: nil
|
||||
;; End:
|
||||
|
||||
;;; mh-xface.el ends here
|
Loading…
Reference in New Issue
Block a user