diff lisp/mh-e/mh-xface.el @ 68465:37d03b3298bf

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.
author Bill Wohler <wohler@newt.com>
date Sun, 29 Jan 2006 19:34:57 +0000
parents
children 4bd450a8dbe2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/mh-e/mh-xface.el	Sun Jan 29 19:34:57 2006 +0000
@@ -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