comparison 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
comparison
equal deleted inserted replaced
68464:79464a6167f5 68465:37d03b3298bf
1 ;;; mh-xface.el --- MH-E X-Face and Face header field display
2
3 ;; Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
4
5 ;; Author: Bill Wohler <wohler@newt.com>
6 ;; Maintainer: Bill Wohler <wohler@newt.com>
7 ;; Keywords: mail
8 ;; See: mh-e.el
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
26
27 ;;; Commentary:
28
29 ;;; Change Log:
30
31 ;;; Code:
32
33 (require 'mh-e)
34 (mh-require-cl)
35
36 (autoload 'message-fetch-field "message")
37
38 (defvar mh-show-xface-function
39 (cond ((and mh-xemacs-flag (locate-library "x-face") (not (featurep 'xface)))
40 (load "x-face" t t)
41 #'mh-face-display-function)
42 ((>= emacs-major-version 21)
43 #'mh-face-display-function)
44 (t #'ignore))
45 "Determine at run time what function should be called to display X-Face.")
46
47 (defvar mh-uncompface-executable
48 (and (fboundp 'executable-find) (executable-find "uncompface")))
49
50
51
52 ;;; X-Face Display
53
54 ;;;###mh-autoload
55 (defun mh-show-xface ()
56 "Display X-Face."
57 (when (and window-system mh-show-use-xface-flag
58 (or mh-decode-mime-flag mh-mhl-format-file
59 mh-clean-message-header-flag))
60 (funcall mh-show-xface-function)))
61
62 (defmacro mh-face-foreground-compat (face &optional frame inherit)
63 "Return the foreground color name of FACE, or nil if unspecified.
64 See documentation for `face-foreground' for a description of the
65 arguments FACE, FRAME, and INHERIT.
66
67 Calls `face-foreground' correctly in older environments. Versions
68 of Emacs prior to version 22 lacked an INHERIT argument which
69 when t tells `face-foreground' to consider an inherited value for
70 the foreground if the face does not define one itself."
71 (if (>= emacs-major-version 22)
72 `(face-foreground ,face ,frame ,inherit)
73 `(face-foreground ,face ,frame)))
74
75 (defmacro mh-face-background-compat(face &optional frame inherit)
76 "Return the background color name of face, or nil if unspecified.
77 See documentation for `back-foreground' for a description of the
78 arguments FACE, FRAME, and INHERIT.
79
80 Calls `face-background' correctly in older environments. Versions
81 of Emacs prior to version 22 lacked an INHERIT argument which
82 when t tells `face-background' to consider an inherited value for
83 the background if the face does not define one itself."
84 (if (>= emacs-major-version 22)
85 `(face-background ,face ,frame ,inherit)
86 `(face-background ,face ,frame)))
87
88 ;; Shush compiler.
89 (eval-when-compile
90 (mh-do-in-xemacs (defvar default-enable-multibyte-characters)))
91
92 (defun mh-face-display-function ()
93 "Display a Face, X-Face, or X-Image-URL header field.
94 If more than one of these are present, then the first one found
95 in this order is used."
96 (save-restriction
97 (goto-char (point-min))
98 (re-search-forward "\n\n" (point-max) t)
99 (narrow-to-region (point-min) (point))
100 (let* ((case-fold-search t)
101 (default-enable-multibyte-characters nil)
102 (face (message-fetch-field "face" t))
103 (x-face (message-fetch-field "x-face" t))
104 (url (message-fetch-field "x-image-url" t))
105 raw type)
106 (cond (face (setq raw (mh-face-to-png face)
107 type 'png))
108 (x-face (setq raw (mh-uncompface x-face)
109 type 'pbm))
110 (url (setq type 'url))
111 (t (multiple-value-setq (type raw) (mh-picon-get-image))))
112 (when type
113 (goto-char (point-min))
114 (when (re-search-forward "^from:" (point-max) t)
115 ;; GNU Emacs
116 (mh-do-in-gnu-emacs
117 (if (eq type 'url)
118 (mh-x-image-url-display url)
119 (mh-funcall-if-exists
120 insert-image (create-image
121 raw type t
122 :foreground
123 (mh-face-foreground-compat 'mh-show-xface nil t)
124 :background
125 (mh-face-background-compat 'mh-show-xface nil t))
126 " ")))
127 ;; XEmacs
128 (mh-do-in-xemacs
129 (cond
130 ((eq type 'url)
131 (mh-x-image-url-display url))
132 ((eq type 'png)
133 (when (featurep 'png)
134 (set-extent-begin-glyph
135 (make-extent (point) (point))
136 (make-glyph (vector 'png ':data (mh-face-to-png face))))))
137 ;; Try internal xface support if available...
138 ((and (eq type 'pbm) (featurep 'xface))
139 (set-glyph-face
140 (set-extent-begin-glyph
141 (make-extent (point) (point))
142 (make-glyph (vector 'xface ':data (concat "X-Face: " x-face))))
143 'mh-show-xface))
144 ;; Otherwise try external support with x-face...
145 ((and (eq type 'pbm)
146 (fboundp 'x-face-xmas-wl-display-x-face)
147 (fboundp 'executable-find) (executable-find "uncompface"))
148 (mh-funcall-if-exists x-face-xmas-wl-display-x-face))
149 ;; Picon display
150 ((and raw (member type '(xpm xbm gif)))
151 (when (featurep type)
152 (set-extent-begin-glyph
153 (make-extent (point) (point))
154 (make-glyph (vector type ':data raw))))))
155 (when raw (insert " "))))))))
156
157 (defun mh-face-to-png (data)
158 "Convert base64 encoded DATA to png image."
159 (with-temp-buffer
160 (insert data)
161 (ignore-errors (base64-decode-region (point-min) (point-max)))
162 (buffer-string)))
163
164 (defun mh-uncompface (data)
165 "Run DATA through `uncompface' to generate bitmap."
166 (with-temp-buffer
167 (insert data)
168 (when (and mh-uncompface-executable
169 (equal (call-process-region (point-min) (point-max)
170 mh-uncompface-executable t '(t nil))
171 0))
172 (mh-icontopbm)
173 (buffer-string))))
174
175 (defun mh-icontopbm ()
176 "Elisp substitute for `icontopbm'."
177 (goto-char (point-min))
178 (let ((end (point-max)))
179 (while (re-search-forward "0x\\(..\\)\\(..\\)," nil t)
180 (save-excursion
181 (goto-char (point-max))
182 (insert (string-to-number (match-string 1) 16))
183 (insert (string-to-number (match-string 2) 16))))
184 (delete-region (point-min) end)
185 (goto-char (point-min))
186 (insert "P4\n48 48\n")))
187
188
189
190 ;;; Picon Display
191
192 ;; XXX: This should be customizable. As a side-effect of setting this
193 ;; variable, arrange to reset mh-picon-existing-directory-list to 'unset.
194 (defvar mh-picon-directory-list
195 '("~/.picons" "~/.picons/users" "~/.picons/usenix" "~/.picons/news"
196 "~/.picons/domains" "~/.picons/misc"
197 "/usr/share/picons/" "/usr/share/picons/users" "/usr/share/picons/usenix"
198 "/usr/share/picons/news" "/usr/share/picons/domains"
199 "/usr/share/picons/misc")
200 "List of directories where picons reside.
201 The directories are searched for in the order they appear in the list.")
202
203 (defvar mh-picon-existing-directory-list 'unset
204 "List of directories to search in.")
205
206 (defvar mh-picon-cache (make-hash-table :test #'equal))
207
208 (defvar mh-picon-image-types
209 (loop for type in '(xpm xbm gif)
210 when (or (mh-do-in-gnu-emacs
211 (ignore-errors
212 (mh-funcall-if-exists image-type-available-p type)))
213 (mh-do-in-xemacs (featurep type)))
214 collect type))
215
216 (autoload 'message-tokenize-header "sendmail")
217
218 (defun* mh-picon-get-image ()
219 "Find the best possible match and return contents."
220 (mh-picon-set-directory-list)
221 (save-restriction
222 (let* ((from-field (ignore-errors (car (message-tokenize-header
223 (mh-get-header-field "from:")))))
224 (from (car (ignore-errors
225 (mh-funcall-if-exists ietf-drums-parse-address
226 from-field))))
227 (host (and from
228 (string-match "\\([^+]*\\)\\(+.*\\)?@\\(.*\\)" from)
229 (downcase (match-string 3 from))))
230 (user (and host (downcase (match-string 1 from))))
231 (canonical-address (format "%s@%s" user host))
232 (cached-value (gethash canonical-address mh-picon-cache))
233 (host-list (and host (delete "" (split-string host "\\."))))
234 (match nil))
235 (cond (cached-value (return-from mh-picon-get-image cached-value))
236 ((not host-list) (return-from mh-picon-get-image nil)))
237 (setq match
238 (block 'loop
239 ;; u@h search
240 (loop for dir in mh-picon-existing-directory-list
241 do (loop for type in mh-picon-image-types
242 ;; [path]user@host
243 for file1 = (format "%s/%s.%s"
244 dir canonical-address type)
245 when (file-exists-p file1)
246 do (return-from 'loop file1)
247 ;; [path]user
248 for file2 = (format "%s/%s.%s" dir user type)
249 when (file-exists-p file2)
250 do (return-from 'loop file2)
251 ;; [path]host
252 for file3 = (format "%s/%s.%s" dir host type)
253 when (file-exists-p file3)
254 do (return-from 'loop file3)))
255 ;; facedb search
256 ;; Search order for user@foo.net:
257 ;; [path]net/foo/user
258 ;; [path]net/foo/user/face
259 ;; [path]net/user
260 ;; [path]net/user/face
261 ;; [path]net/foo/unknown
262 ;; [path]net/foo/unknown/face
263 ;; [path]net/unknown
264 ;; [path]net/unknown/face
265 (loop for u in (list user "unknown")
266 do (loop for dir in mh-picon-existing-directory-list
267 do (loop for x on host-list by #'cdr
268 for y = (mh-picon-generate-path x u dir)
269 do (loop for type in mh-picon-image-types
270 for z1 = (format "%s.%s" y type)
271 when (file-exists-p z1)
272 do (return-from 'loop z1)
273 for z2 = (format "%s/face.%s"
274 y type)
275 when (file-exists-p z2)
276 do (return-from 'loop z2)))))))
277 (setf (gethash canonical-address mh-picon-cache)
278 (mh-picon-file-contents match)))))
279
280 (defun mh-picon-set-directory-list ()
281 "Update `mh-picon-existing-directory-list' if needed."
282 (when (eq mh-picon-existing-directory-list 'unset)
283 (setq mh-picon-existing-directory-list
284 (loop for x in mh-picon-directory-list
285 when (file-directory-p x) collect x))))
286
287 (defun mh-picon-generate-path (host-list user directory)
288 "Generate the image file path.
289 HOST-LIST is the parsed host address of the email address, USER
290 the username and DIRECTORY is the directory relative to which the
291 path is generated."
292 (loop with acc = ""
293 for elem in host-list
294 do (setq acc (format "%s/%s" elem acc))
295 finally return (format "%s/%s%s" directory acc user)))
296
297 (defun mh-picon-file-contents (file)
298 "Return details about FILE.
299 A list of consisting of a symbol for the type of the file and the
300 file contents as a string is returned. If FILE is nil, then both
301 elements of the list are nil."
302 (if (stringp file)
303 (with-temp-buffer
304 (let ((type (and (string-match ".*\\.\\(...\\)$" file)
305 (intern (match-string 1 file)))))
306 (insert-file-contents-literally file)
307 (values type (buffer-string))))
308 (values nil nil)))
309
310
311
312 ;;; X-Image-URL Display
313
314 (defvar mh-x-image-scaling-function
315 (cond ((executable-find "convert")
316 'mh-x-image-scale-with-convert)
317 ((and (executable-find "anytopnm") (executable-find "pnmscale")
318 (executable-find "pnmtopng"))
319 'mh-x-image-scale-with-pnm)
320 (t 'ignore))
321 "Function to use to scale image to proper size.")
322
323 (defun mh-x-image-scale-with-pnm (input output)
324 "Scale image in INPUT file and write to OUTPUT file using pnm tools."
325 (let ((res (shell-command-to-string
326 (format "anytopnm < %s | pnmscale -xysize 96 48 | pnmtopng > %s"
327 input output))))
328 (unless (equal res "")
329 (delete-file output))))
330
331 (defun mh-x-image-scale-with-convert (input output)
332 "Scale image in INPUT file and write to OUTPUT file using ImageMagick."
333 (call-process "convert" nil nil nil "-geometry" "96x48" input output))
334
335 (defvar mh-wget-executable nil)
336 (defvar mh-wget-choice
337 (or (and (setq mh-wget-executable (executable-find "wget")) 'wget)
338 (and (setq mh-wget-executable (executable-find "fetch")) 'fetch)
339 (and (setq mh-wget-executable (executable-find "curl")) 'curl)))
340 (defvar mh-wget-option
341 (cdr (assoc mh-wget-choice '((curl . "-o") (fetch . "-o") (wget . "-O")))))
342 (defvar mh-x-image-temp-file nil)
343 (defvar mh-x-image-url nil)
344 (defvar mh-x-image-marker nil)
345 (defvar mh-x-image-url-cache-file nil)
346
347 (defun mh-x-image-url-display (url)
348 "Display image from location URL.
349 If the URL isn't present in the cache then it is fetched with wget."
350 (let* ((cache-filename (mh-x-image-url-cache-canonicalize url))
351 (state (mh-x-image-get-download-state cache-filename))
352 (marker (set-marker (make-marker) (point))))
353 (set (make-local-variable 'mh-x-image-marker) marker)
354 (cond ((not (mh-x-image-url-sane-p url)))
355 ((eq state 'ok)
356 (mh-x-image-display cache-filename marker))
357 ((or (not mh-wget-executable)
358 (eq mh-x-image-scaling-function 'ignore)))
359 ((eq state 'never))
360 ((not mh-fetch-x-image-url)
361 (set-marker marker nil))
362 ((eq state 'try-again)
363 (mh-x-image-set-download-state cache-filename nil)
364 (mh-x-image-url-fetch-image url cache-filename marker
365 'mh-x-image-scale-and-display))
366 ((and (eq mh-fetch-x-image-url 'ask)
367 (not (y-or-n-p (format "Fetch %s? " url))))
368 (mh-x-image-set-download-state cache-filename 'never))
369 ((eq state nil)
370 (mh-x-image-url-fetch-image url cache-filename marker
371 'mh-x-image-scale-and-display)))))
372
373 (defvar mh-x-image-cache-directory nil
374 "Directory where X-Image-URL images are cached.")
375
376 ;;;###mh-autoload
377 (defun mh-set-x-image-cache-directory (directory)
378 "Set the DIRECTORY where X-Image-URL images are cached.
379 This is only done if `mh-x-image-cache-directory' is nil."
380 ;; XXX This is the code that used to be in find-user-path. Is there
381 ;; a good reason why the variable is set conditionally? Do we expect
382 ;; the user to have set this variable directly?
383 (unless mh-x-image-cache-directory
384 (setq mh-x-image-cache-directory directory)))
385
386 (defun mh-x-image-url-cache-canonicalize (url)
387 "Canonicalize URL.
388 Replace the ?/ character with a ?! character and append .png.
389 Also replaces special characters with `url-hexify-string' since
390 not all characters, such as :, are legal within Windows
391 filenames. See URL `http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp'."
392 (format "%s/%s.png" mh-x-image-cache-directory
393 (url-hexify-string
394 (with-temp-buffer
395 (insert url)
396 (mh-replace-string "/" "!")
397 (buffer-string)))))
398
399 ;; Copy of constant from url-util.el in Emacs 22; needed by Emacs 21.
400 (if (not (boundp 'url-unreserved-chars))
401 (defconst url-unreserved-chars
402 '(
403 ?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
404 ?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
405 ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
406 ?- ?_ ?. ?! ?~ ?* ?' ?\( ?\))
407 "A list of characters that are _NOT_ reserved in the URL spec.
408 This is taken from RFC 2396."))
409
410 (mh-defun-compat url-hexify-string (str)
411 "Escape characters in a string.
412 This is a copy of the function of the same name from url-util.el
413 in Emacs 22; needed by Emacs 21."
414 (mapconcat
415 (lambda (char)
416 ;; Fixme: use a char table instead.
417 (if (not (memq char url-unreserved-chars))
418 (if (> char 255)
419 (error "Hexifying multibyte character %s" str)
420 (format "%%%02X" char))
421 (char-to-string char)))
422 str ""))
423
424 (defun mh-x-image-get-download-state (file)
425 "Check the state of FILE by following any symbolic links."
426 (unless (file-exists-p mh-x-image-cache-directory)
427 (call-process "mkdir" nil nil nil mh-x-image-cache-directory))
428 (cond ((file-symlink-p file)
429 (intern (file-name-nondirectory (file-chase-links file))))
430 ((not (file-exists-p file)) nil)
431 (t 'ok)))
432
433 (defun mh-x-image-set-download-state (file data)
434 "Setup a symbolic link from FILE to DATA."
435 (if data
436 (make-symbolic-link (symbol-name data) file t)
437 (delete-file file)))
438
439 (defun mh-x-image-url-sane-p (url)
440 "Check if URL is something sensible."
441 (let ((len (length url)))
442 (cond ((< len 5) nil)
443 ((not (equal (substring url 0 5) "http:")) nil)
444 ((> len 100) nil)
445 (t t))))
446
447 (defun mh-x-image-display (image marker)
448 "Display IMAGE at MARKER."
449 (save-excursion
450 (set-buffer (marker-buffer marker))
451 (let ((buffer-read-only nil)
452 (default-enable-multibyte-characters nil)
453 (buffer-modified-flag (buffer-modified-p)))
454 (unwind-protect
455 (when (and (file-readable-p image) (not (file-symlink-p image))
456 (eq marker mh-x-image-marker))
457 (goto-char marker)
458 (mh-do-in-gnu-emacs
459 (mh-funcall-if-exists insert-image (create-image image 'png)))
460 (mh-do-in-xemacs
461 (when (featurep 'png)
462 (set-extent-begin-glyph
463 (make-extent (point) (point))
464 (make-glyph
465 (vector 'png ':data (with-temp-buffer
466 (insert-file-contents-literally image)
467 (buffer-string))))))))
468 (set-buffer-modified-p buffer-modified-flag)))))
469
470 (defun mh-x-image-url-fetch-image (url cache-file marker sentinel)
471 "Fetch and display the image specified by URL.
472 After the image is fetched, it is stored in CACHE-FILE. It will
473 be displayed in a buffer and position specified by MARKER. The
474 actual display is carried out by the SENTINEL function."
475 (if mh-wget-executable
476 (let ((buffer (get-buffer-create (generate-new-buffer-name
477 mh-temp-fetch-buffer)))
478 (filename (or (mh-funcall-if-exists make-temp-file "mhe-fetch")
479 (expand-file-name (make-temp-name "~/mhe-fetch")))))
480 (save-excursion
481 (set-buffer buffer)
482 (set (make-local-variable 'mh-x-image-url-cache-file) cache-file)
483 (set (make-local-variable 'mh-x-image-marker) marker)
484 (set (make-local-variable 'mh-x-image-temp-file) filename))
485 (set-process-sentinel
486 (start-process "*mh-x-image-url-fetch*" buffer
487 mh-wget-executable mh-wget-option filename url)
488 sentinel))
489 ;; Temporary failure
490 (mh-x-image-set-download-state cache-file 'try-again)))
491
492 (defun mh-x-image-scale-and-display (process change)
493 "When the wget PROCESS terminates scale and display image.
494 The argument CHANGE is ignored."
495 (when (eq (process-status process) 'exit)
496 (let (marker temp-file cache-filename wget-buffer)
497 (save-excursion
498 (set-buffer (setq wget-buffer (process-buffer process)))
499 (setq marker mh-x-image-marker
500 cache-filename mh-x-image-url-cache-file
501 temp-file mh-x-image-temp-file))
502 (cond
503 ;; Check if we have `convert'
504 ((eq mh-x-image-scaling-function 'ignore)
505 (message "The \"convert\" program is needed to display X-Image-URL")
506 (mh-x-image-set-download-state cache-filename 'try-again))
507 ;; Scale fetched image
508 ((and (funcall mh-x-image-scaling-function temp-file cache-filename)
509 nil))
510 ;; Attempt to display image if we have it
511 ((file-exists-p cache-filename)
512 (mh-x-image-display cache-filename marker))
513 ;; We didn't find the image. Should we try to display it the next time?
514 (t (mh-x-image-set-download-state cache-filename 'try-again)))
515 (ignore-errors
516 (set-marker marker nil)
517 (delete-process process)
518 (kill-buffer wget-buffer)
519 (delete-file temp-file)))))
520
521 (provide 'mh-xface)
522
523 ;; Local Variables:
524 ;; indent-tabs-mode: nil
525 ;; sentence-end-double-space: nil
526 ;; End:
527
528 ;;; mh-xface.el ends here