+2000-04-27 Dave Love <fx@gnu.org>
+
+ * gnus-art.el: Don't bother to require custom, browse-url.
+ (gnus-article-x-face-command): Include gnus-article-display-xface.
+
+ * gnus-ems.el: Assume only (X)Emacs 20+. Simplify XEmacs checks.
+ Use defalias, not fset.
+ (gnus-article-display-xface): New function.
+
+ * mm-view.el (mm-inline-image-emacs): Use put-image, remove-images.
+
+ * mm-decode.el: Small doc fixes. Require cl when compiling.
+ (mm-xemacs-p): Deleted.
+ (mm-get-image-emacs, mm-get-image-xemacs): Deleted.
+ (mm-get-image): Amalgamate Emacs and XEmacs code here; for Emacs,
+ use create-image and don't special-case xbm.
+ (mm-valid-image-format-p): Use display-graphic-p.
+
+2000-04-27 15:27:54 Shenghuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-send-mail-partially-limit): New variable.
+ (message-send-mail-partially): New function.
+ (message-send-mail): Use it.
+ * mm-bodies.el (mm-decode-content-transfer-encoding): Remove
+ all blank lines inside of base64.
+ * mm-partial.el (mm-inline-partial): Add an option. Remove tail
+ blank lines.
+
+2000-04-27 10:03:36 Shenghuo ZHU <zsh@cs.rochester.edu>
+
+ * mml.el (mml-insert-tag): Match more special characters.
+
2000-04-27 09:06:29 Shenghuo ZHU <zsh@cs.rochester.edu>
* gnus-msg.el (gnus-bug): Avoid attaching the external buffer.
(eval-when-compile (require 'static))
(require 'path-util)
-(require 'custom)
(require 'gnus)
(require 'gnus-sum)
(require 'gnus-spec)
(require 'gnus-int)
-(require 'browse-url)
(require 'alist)
(require 'mime-view)
:group 'gnus-article-hiding)
(defcustom gnus-article-x-face-command
- (if (and (not gnus-xemacs)
- window-system
- (module-installed-p 'x-face-mule))
- 'x-face-mule-gnus-article-display-x-face
- "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | display -"
- )
+ (cond
+ ((and (fboundp 'image-type-available-p)
+ (or (image-type-available-p 'xpm)
+ (image-type-available-p 'xbm)))
+ 'gnus-article-display-xface)
+ ((and (not gnus-xemacs)
+ window-system
+ (module-installed-p 'x-face-mule))
+ 'x-face-mule-gnus-article-display-x-face)
+ (t
+ "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | display -"))
"*String or function to be executed to display an X-Face header.
If it is a string, the command will be executed in a sub-shell
asynchronously. The compressed face will be piped to this command."
- :type 'string ;Leave function case to Lisp.
+ :type '(choice string
+ (function-item gnus-article-display-xface)
+ (function-item x-face-mule-gnus-article-display-x-face)
+ function)
:group 'gnus-article-washing)
(defcustom gnus-article-x-face-too-ugly nil
;;; Function aliases later to be redefined for XEmacs usage.
-(defvar gnus-xemacs (string-match "XEmacs\\|Lucid" emacs-version)
- "Non-nil if running under XEmacs.")
+(eval-and-compile
+ (defvar gnus-xemacs (string-match "XEmacs" emacs-version)
+ "Non-nil if running under XEmacs."))
(defvar gnus-mouse-2 [mouse-2])
(defvar gnus-down-mouse-3 [down-mouse-3])
;;; Mule functions.
(eval-and-compile
- (if (string-match "XEmacs\\|Lucid" emacs-version)
- nil
-
+ (if gnus-xemacs
+ (gnus-xmas-define)
(defvar gnus-mouse-face-prop 'mouse-face
- "Property used for highlighting mouse regions."))
-
- (cond
- ((string-match "XEmacs\\|Lucid" emacs-version)
- (gnus-xmas-define))
-
- ((or (not (boundp 'emacs-minor-version))
- (and (< emacs-major-version 20)
- (< emacs-minor-version 30)))
- ;; Remove the `intangible' prop.
- (let ((props (and (boundp 'gnus-hidden-properties)
- gnus-hidden-properties)))
- (while (and props (not (eq (car (cdr props)) 'intangible)))
- (setq props (cdr props)))
- (when props
- (setcdr props (cdr (cdr (cdr props))))))
- (unless (fboundp 'buffer-substring-no-properties)
- (defun buffer-substring-no-properties (beg end)
- (format "%s" (buffer-substring beg end)))))
-
- ((boundp 'MULE)
- (provide 'gnusutil))))
+ "Property used for highlighting mouse regions.")))
(eval-and-compile
(cond
set-face-background x-popup-menu)))
(while funcs
(unless (fboundp (car funcs))
- (fset (car funcs) 'gnus-dummy-func))
+ (defalias (car funcs) 'gnus-dummy-func))
(setq funcs (cdr funcs)))))))
(eval-and-compile
(defun gnus-ems-redefine ()
(cond
- ((string-match "XEmacs\\|Lucid" emacs-version)
+ (gnus-xemacs
(gnus-xmas-redefine))
((featurep 'mule)
;; Mule and new Emacs definitions
;; [Note] Now there are three kinds of mule implementations,
- ;; original MULE, XEmacs/mule and beta version of Emacs including
- ;; some mule features. Unfortunately these API are different. In
+ ;; original MULE, XEmacs/mule and Emacs 20+ including
+ ;; MULE features. Unfortunately these API are different. In
;; particular, Emacs (including original MULE) and XEmacs are
- ;; quite different.
+ ;; quite different. However, this version of Gnus doesn't support
+ ;; anything other than XEmacs 20+ and Emacs 20.3+.
+
;; Predicates to check are following:
;; (boundp 'MULE) is t only if MULE (original; anything older than
;; Mule 2.3) is running.
;; (featurep 'mule) is t when every mule variants are running.
- ;; These implementations may be able to share between original
- ;; MULE and beta version of new Emacs. In addition, it is able to
- ;; detect XEmacs/mule by (featurep 'mule) and to check variable
- ;; `emacs-version'. In this case, implementation for XEmacs/mule
- ;; may be able to share between XEmacs and XEmacs/mule.
+ ;; It is possible to detect XEmacs/mule by (featurep 'mule) and
+ ;; checking `emacs-version'. In this case, the implementation for
+ ;; XEmacs/mule may be shareable between XEmacs and XEmacs/mule.
(defvar gnus-summary-display-table nil
"Display table used in summary mode buffers.")
- (fset 'gnus-summary-set-display-table (lambda ()))
+ (defalias 'gnus-summary-set-display-table (lambda ()))
(if (fboundp 'truncate-string-to-width)
(fset 'gnus-truncate-string 'truncate-string-to-width)
(goto-char (point-min))
(sit-for 0))))))
+(defun gnus-article-display-xface (beg end)
+ "Display an XFace header from between BEG and END in the current article.
+This requires support for XPM or XBM images in your Emacs and the
+external programs `uncompface', `icontopbm' and either `ppmtoxpm' (for
+XPM support) or `ppmtoxbm' (for XBM support). On a GNU/Linux system
+these might be in packages with names like `compface' or `faces-xface'
+and `netpbm' or `libgr-progs', for instance.
+
+This function is for Emacs 21+. See `gnus-xmas-article-display-xface'
+for XEmacs."
+ (save-excursion
+ (let ((cur (current-buffer))
+ image type)
+ (when (and (fboundp 'image-type-available-p)
+ (cond ((image-type-available-p 'xpm) (setq type 'xpm))
+ ((image-type-available-p 'xbm) (setq type 'xbm))))
+ (with-temp-buffer
+ (insert-buffer-substring cur beg end)
+ (call-process-region (point-min) (point-max) "uncompface"
+ 'delete '(t nil))
+ (goto-char (point-min))
+ (insert "/* Width=48, Height=48 */\n")
+ (and (eq 0 (call-process-region (point-min) (point-max) "icontopbm"
+ 'delete '(t nil)))
+ (eq 0 (call-process-region (point-min) (point-max)
+ (if (eq type 'xpm)
+ "ppmtoxpm"
+ "pbmtoxbm")
+ 'delete '(t nil)))
+ (setq image (create-image (buffer-string) type t))))
+ (when image
+ (goto-char (point-min))
+ (re-search-forward "^From:" nil 'move)
+ (insert-image image " "))))))
+
(defun-maybe assoc-ignore-case (key alist)
"Like `assoc', but assumes KEY is a string and ignores case when comparing."
(setq key (downcase key))
(t nil))
"Coding system to compose mail.")
+(defcustom message-send-mail-partially-limit nil
+ "The limitation of messages sent as message/partial.
+The lower bound of message size in characters, beyond which the message
+should be sent in several parts. *Nil means unlimited."
+ :group 'message-buffers
+ :type '(choice (const :tag "unlimited" nil)
+ (integer 50000)))
+
;;; Internal variables.
(defvar message-buffer-list nil)
(cadr failure)
(prin1-to-string failure)))))
+(defun message-send-mail-partially ()
+ "Sendmail as message/partial."
+ (let ((p (goto-char (point-min)))
+ (tembuf (message-generate-new-buffer-clone-locals " message temp"))
+ (curbuf (current-buffer))
+ (id (message-make-message-id)) (n 1)
+ plist total header required-mail-headers)
+ (while (not (eobp))
+ (if (< (point-max) (+ p message-send-mail-partially-limit))
+ (goto-char (point-max))
+ (goto-char (+ p message-send-mail-partially-limit))
+ (beginning-of-line)
+ (if (<= (point) p) (end-of-line))) ;; In case of bad message.
+ (push p plist)
+ (setq p (point)))
+ (setq total (length plist))
+ (push (point-max) plist)
+ (setq plist (nreverse plist))
+ (unwind-protect
+ (save-excursion
+ (setq p (pop plist))
+ (while plist
+ (set-buffer curbuf)
+ (copy-to-buffer tembuf p (car plist))
+ (set-buffer tembuf)
+ (goto-char (point-min))
+ (if header
+ (progn
+ (goto-char (point-min))
+ (narrow-to-region (point) (point))
+ (insert header))
+ (message-goto-eoh)
+ (setq header (buffer-substring (point-min) (point)))
+ (goto-char (point-min))
+ (narrow-to-region (point) (point))
+ (insert header)
+ (message-remove-header "Mime-Version")
+ (message-remove-header "Content-Type")
+ (message-remove-header "Message-ID")
+ (message-remove-header "Lines")
+ (goto-char (point-max))
+ (insert "Mime-Version: 1.0\n")
+ (setq header (buffer-substring (point-min) (point-max))))
+ (goto-char (point-max))
+ (insert (format "Content-Type: message/partial; id=\"%s\"; number=%d; total=%d\n"
+ id n total))
+ (let ((mail-header-separator ""))
+ (when (memq 'Message-ID message-required-mail-headers)
+ (insert "Message-ID: " (message-make-message-id) "\n"))
+ (when (memq 'Lines message-required-mail-headers)
+ (let ((mail-header-separator ""))
+ (insert "Lines: " (message-make-lines) "\n")))
+ (message-goto-subject)
+ (end-of-line)
+ (insert (format " (%d/%d)" n total))
+ (goto-char (point-max))
+ (insert "\n")
+ (widen)
+ (funcall message-send-mail-function))
+ (setq n (+ n 1))
+ (setq p (pop plist))
+ (erase-buffer)))
+ (kill-buffer tembuf))))
+
(defun message-send-mail (&optional arg)
(require 'mail-utils)
(let* ((tembuf (message-generate-new-buffer-clone-locals " message temp"))
;; have been added by mailing list software.
(save-excursion
(goto-char (point-min))
- (if (re-search-forward "^[\t ]*$" nil t)
- (delete-region (point) (point-max))
- (goto-char (point-max)))
- (skip-chars-backward "\n\t ")
- (delete-region (point) (point-max))
- (point))))
+ (while (re-search-forward "^[\t ]*\r?\n" nil t)
+ (delete-region (match-beginning 0) (match-end 0)))
+ (point-max))))
((memq encoding '(7bit 8bit binary))
;; Do nothing.
)
(require 'mail-parse)
(require 'gnus-mailcap)
(require 'mm-bodies)
+(eval-when-compile (require 'cl))
(eval-and-compile
(autoload 'mm-inline-partial "mm-partial"))
-(defvar mm-xemacs-p (string-match "XEmacs" (emacs-version)))
-
(defgroup mime-display ()
"Display of MIME in mail and news articles."
:link '(custom-manual "(emacs-mime)Customization")
Viewing agents are supposed to view the last possible part of a message,
as that is supposed to be the richest. However, users may prefer other
types instead, and this list says what types are most unwanted. If,
-for instance, text/html parts are very unwanted, and text/richtech are
+for instance, text/html parts are very unwanted, and text/richtext are
somewhat unwanted, then the value of this variable should be set
to:
(if (or (not ctl)
(not (string-match "/" (car ctl))))
(mm-dissect-singlepart
- '("text/plain")
+ '("text/plain")
(and cte (intern (downcase (mail-header-remove-whitespace
(mail-header-remove-comments
cte)))))
(unwind-protect
(start-process "*display*" nil
"xterm"
- "-e" shell-file-name
+ "-e" shell-file-name
shell-command-switch
(mm-mailcap-command
method file (mm-handle-type handle)))
(unwind-protect
(progn
(call-process shell-file-name nil
- (setq buffer
+ (setq buffer
(generate-new-buffer "*mm*"))
nil
shell-command-switch
(mapconcat 'identity (nreverse out) "")))
(defun mm-remove-parts (handles)
- "Remove the displayed MIME parts represented by HANDLE."
+ "Remove the displayed MIME parts represented by HANDLES."
(if (and (listp handles)
(bufferp (car handles)))
(mm-remove-part handles)
(mm-remove-part handle)))))))
(defun mm-destroy-parts (handles)
- "Remove the displayed MIME parts represented by HANDLE."
+ "Remove the displayed MIME parts represented by HANDLES."
(if (and (listp handles)
(bufferp (car handles)))
(mm-destroy-part handles)
result))
(defun mm-preferred-alternative-precedence (handles)
- "Return the precedence based on HANDLES and mm-discouraged-alternatives."
- (let ((seq (nreverse (mapcar (lambda (h)
- (mm-handle-media-type h))
+ "Return the precedence based on HANDLES and `mm-discouraged-alternatives'."
+ (let ((seq (nreverse (mapcar #'mm-handle-media-type
handles))))
(dolist (disc (reverse mm-discouraged-alternatives))
(dolist (elem (copy-sequence seq))
"Return the handle(s) referred to by ID."
(cdr (assoc id mm-content-id-alist)))
-(defun mm-get-image-emacs (handle)
- "Return an image instance based on HANDLE."
- (let ((type (mm-handle-media-subtype handle))
- spec)
- ;; Allow some common translations.
- (setq type
- (cond
- ((equal type "x-pixmap")
- "xpm")
- ((equal type "x-xbitmap")
- "xbm")
- (t type)))
- (or (mm-handle-cache handle)
- (mm-with-unibyte-buffer
- (mm-insert-part handle)
- (prog1
- (setq spec
- (ignore-errors
- (cond
- ((equal type "xbm")
- ;; xbm images require special handling, since
- ;; the only way to create glyphs from these
- ;; (without a ton of work) is to write them
- ;; out to a file, and then create a file
- ;; specifier.
- (error "Don't know what to do for XBMs right now."))
- (t
- (list 'image :type (intern type) :data (buffer-string))))))
- (mm-handle-set-cache handle spec))))))
-
-(defun mm-get-image-xemacs (handle)
+(defun mm-get-image (handle)
"Return an image instance based on HANDLE."
(let ((type (mm-handle-media-subtype handle))
spec)
(prog1
(setq spec
(ignore-errors
- (cond
- ((equal type "xbm")
- ;; xbm images require special handling, since
- ;; the only way to create glyphs from these
- ;; (without a ton of work) is to write them
- ;; out to a file, and then create a file
- ;; specifier.
- (let ((file (make-temp-name
- (expand-file-name "emm.xbm"
- mm-tmp-directory))))
- (unwind-protect
- (progn
- (write-region (point-min) (point-max) file)
- (make-glyph (list (cons 'x file))))
- (ignore-errors
- (delete-file file)))))
- (t
- (make-glyph
- (vector (intern type) :data (buffer-string)))))))
+ (if (fboundp 'make-glyph)
+ (cond
+ ((equal type "xbm")
+ ;; xbm images require special handling, since
+ ;; the only way to create glyphs from these
+ ;; (without a ton of work) is to write them
+ ;; out to a file, and then create a file
+ ;; specifier.
+ (let ((file (make-temp-name
+ (expand-file-name "emm.xbm"
+ mm-tmp-directory))))
+ (unwind-protect
+ (progn
+ (write-region (point-min) (point-max) file)
+ (make-glyph (list (cons 'x file))))
+ (ignore-errors
+ (delete-file file)))))
+ (t
+ (make-glyph
+ (vector (intern type) :data (buffer-string)))))
+ (create-image (buffer-string) (intern type) 'data-p))))
(mm-handle-set-cache handle spec))))))
-(defun mm-get-image (handle)
- (if mm-xemacs-p
- (mm-get-image-xemacs handle)
- (mm-get-image-emacs handle)))
-
(defun mm-image-fit-p (handle)
"Say whether the image in HANDLE will fit the current window."
(let ((image (mm-get-image handle)))
(valid-image-instantiator-format-p format))
;; Handle Emacs 21
((fboundp 'image-type-available-p)
- (image-type-available-p format))
+ (and (display-graphic-p)
+ (image-type-available-p format)))
;; Nobody else can do images yet.
(t
nil)))
(provide 'mm-decode)
-;; mm-decode.el ends here
+;;; mm-decode.el ends here
phandles))
;;;###autoload
-(defun mm-inline-partial (handle)
+(defun mm-inline-partial (handle &optional no-display)
+ "Show the partial part of HANDLE.
+This function replaces the buffer of HANDLE with a buffer contains
+the entire message.
+If NO-DISPLAY is nil, display it. Otherwise, do nothing after replacing."
(let ((id (cdr (assq 'id (cdr (mm-handle-type handle)))))
phandles
(b (point)) (n 1) total
(error "Missing part %d" n))
(mm-insert-part phandle)
(goto-char (point-max))
+ (when (not (eq 0 (skip-chars-backward "\r\n")))
+ ;; remove tail blank spaces except one
+ (if (looking-at "\r?\n")
+ (goto-char (match-end 0)))
+ (delete-region (point) (point-max)))
(setq n (+ n 1))))
(unless total
(error "Don't known the total number of"))
(kill-buffer (mm-handle-buffer handle))
(setcar handle (current-buffer))
(mm-handle-set-cache handle t)))
- (save-excursion
- (save-restriction
- (narrow-to-region b b)
- (mm-insert-part handle)
- (let (gnus-article-mime-handles)
- (run-hooks 'gnus-article-decode-hook)
- (gnus-article-prepare-display)
- (setq handles gnus-article-mime-handles))
- (when handles
- ;; It is in article buffer.
- (setq gnus-article-mime-handles
- (nconc (if (listp (car gnus-article-mime-handles))
+ (unless no-display
+ (save-excursion
+ (save-restriction
+ (narrow-to-region b b)
+ (mm-insert-part handle)
+ (let (gnus-article-mime-handles)
+ (run-hooks 'gnus-article-decode-hook)
+ (gnus-article-prepare-display)
+ (setq handles gnus-article-mime-handles))
+ (when handles
+ ;; It is in article buffer.
+ (setq gnus-article-mime-handles
+ (nconc (if (listp (car gnus-article-mime-handles))
gnus-article-mime-handles
- (list gnus-article-mime-handles))
- (if (listp (car handles))
- handles (list handles)))))
- (mm-handle-set-undisplayer
- handle
- `(lambda ()
- (let (buffer-read-only)
- (condition-case nil
- ;; This is only valid on XEmacs.
- (mapcar (lambda (prop)
+ (list gnus-article-mime-handles))
+ (if (listp (car handles))
+ handles (list handles)))))
+ (mm-handle-set-undisplayer
+ handle
+ `(lambda ()
+ (let (buffer-read-only)
+ (condition-case nil
+ ;; This is only valid on XEmacs.
+ (mapcar (lambda (prop)
(remove-specifier
(face-property 'default prop) (current-buffer)))
- '(background background-pixmap foreground))
- (error nil))
- (delete-region ,(point-min-marker) ,(point-max-marker)))))))))
+ '(background background-pixmap foreground))
+ (error nil))
+ (delete-region ,(point-min-marker) ,(point-max-marker))))))))))
;; mm-partial.el ends here
;;; Functions for displaying various formats inline
;;;
(defun mm-inline-image-emacs (handle)
- (let ((b (point))
- (overlay nil)
- (string (copy-sequence "[MM-INLINED-IMAGE]"))
+ (let ((b (point-marker))
buffer-read-only)
(insert "\n")
- (buffer-name)
- (setq overlay (make-overlay (point) (point) (current-buffer)))
- (put-text-property 0 (length string) 'display (mm-get-image handle) string)
- (overlay-put overlay 'before-string string)
-
+ (put-image (mm-get-image handle) b "x")
(mm-handle-set-undisplayer
handle
- `(lambda ()
- (let (buffer-read-only)
- (delete-overlay ,overlay)
- (delete-region ,(set-marker (make-marker) b)
- ,(set-marker (make-marker) (point))))))))
+ `(lambda () (remove-images ,b (1+ ,b))))))
(defun mm-inline-image-xemacs (handle)
(let ((b (point))
(value (pop plist)))
(when value
;; Quote VALUE if it contains suspicious characters.
- (when (string-match "[\"\\~/* \t\n]" value)
+ (when (string-match "[\"'\\~/*;() \t\n]" value)
(setq value (prin1-to-string value)))
(insert (format " %s=%s" key value)))))
(insert ">\n"))
+2000-04-27 Dave Love <fx@gnu.org>
+
+ * gnus.texi (Article Washing): Update x-face bit.
+
2000-04-26 Florian Weimer <fw@deneb.cygnus.argh.org>
* message.texi (Various Message Variables): Document
\e$(B$3$NL?Na$OJQ?t\e(B @code{gnus-article-x-face-command} \e$(B$K$h$C$FM?$($i$l$?4X?t$K\e(B
\e$(B$h$C$F<B9T$5$l$^$9!#$3$NJQ?t$,J8;zNs$J$i$P!"$3$NJ8;zNs$,%5%V%7%'%k$G<B9T$5\e(B
\e$(B$l$^$9!#4X?t$J$i$P!"$3$N4X?t$,4i$r0z?t$H$7$F8F$P$l$^$9!#$b$7\e(B
-@code{gnus-article-x-face-too-ugly}\e$(B!J$3$l$O@55,I=8=$G$9!K$,\e(B @code{From} \e$(BMs\e(B
-\e$(B$K9gCW$9$l$P!"4i$OI=<($5$l$^$;$s!#\e(BEmacs \e$(B$G$N%G%#%U%)%k%H$NF0:n$O\e(B
-@code{xv} \e$(B$r%U%)!<%/$7$F8+$h$&$H$7$^$9!#\e(BXEmacs \e$(B$G$N%G%#%U%)%k%H$NF0:n$O\e(B
-@code{From} \e$(BMs$NA0$K4i$rI=<($7$^$9!#!J\e(BXEmacs \e$(B$,\e(B X-Face \e$(B5!G=IU$-$G%3%s%Q%$\e(B
-\e$(B%k$5$l$F$$$k$HNI$$$G$7$g$&!=!=$=$l$OI=<($r>/$7Aa$/$7$^$9!#$b$7:,K\E*\e(B
-X-Face \e$(B5!G=$,$J$$$N$G$"$l$P!"\e(Bgnus \e$(B$O\e(B @code{pbmplus} \e$(B$d$=$NCg4V$N30It%W%m%0\e(B
-\e$(B%i%`$r;H$C$F\e(B @code{X-Face} \e$(BMs$rJQ49$7$h$&$H;n$_$^$9!#!K$3$N4X?t$rI=<(%U%C\e(B
-\e$(B%/$KF~$l$?$$$N$G$"$l$P!"$*$=$i$/$=$l$":G8e$K$J$k$Y$-$G$7$g$&!#\e(B
+ @code{gnus-article-x-face-too-ugly}\e$(B!J$3$l$O@55,I=8=$G$9!K$,\e(B @code{From}
+ \e$(BMs$K9gCW$9$l$P!"4i$OI=<($5$l$^$;$s!#\e(BEmacs \e$(B$G$N%G%#%U%)%k%H$NF0:n$O\e(B
+ @code{display} \e$(B%W%m%0%i%`\e(B @footnote{@code{display} \e$(B$O\e(B ImageMagick \e$(B%Q%C\e(B
+\e$(B%1!<%8$K4^$^$l$F$$$^$9!#\e(B@code{uncompface} \e$(B$H\e(B @code{icontopbm} \e$(B$NN>%W%m%0\e(B
+\e$(B%i%`$K$D$$$F$O!"\e(B`compface' \e$(B$d\e(B GNU/Linux \e$(B%7%9%F%`$K$*$1$k\e(B `faces-xface'
+ \e$(B$N$h$&$J%Q%C%1!<%8$rC5$7$F2<$5$$!#\e(B} \e$(B$r%U%)!<%/$7$F8+$h$&$H$7$^$9!#\e(B
+XEmacs \e$(B$G$N%G%#%U%)%k%H$NF0:n$O\e(B @code{From} \e$(BMs$NA0$K4i$rI=<($7$^$9!#\e(B
+\e$(B!J\e(BXEmacs \e$(B$,\e(B X-Face \e$(B5!G=IU$-$G%3%s%Q%$%k$5$l$F$$$k$HNI$$$G$7$g$&!=!=$=$l\e(B
+\e$(B$OI=<($r>/$7Aa$/$7$^$9!#$b$7:,K\E*\e(B X-Face \e$(B5!G=$,$J$$$N$G$"$l$P!"\e(Bgnus \e$(B$O\e(B
+ @code{pbmplus} \e$(B$d$=$NCg4V$N30It%W%m%0%i%`$r;H$C$F\e(B @code{X-Face} \e$(BMs$rJQ\e(B
+\e$(B49$7$h$&$H;n$_$^$9!#!K$3$N4X?t$rI=<(%U%C%/$KF~$l$?$$$N$G$"$l$P!"$*$=$i$/\e(B
+\e$(B$=$l$O:G8e$K$J$k$Y$-$G$7$g$&!#\e(B
@item W b
@kindex W b \e$(B!J35N,!K\e(B
sub-shell. If it is a function, this function will be called with the
face as the argument. If the @code{gnus-article-x-face-too-ugly} (which
is a regexp) matches the @code{From} header, the face will not be shown.
-The default action under Emacs is to fork off an @code{xv} to view the
-face; under XEmacs the default action is to display the face before the
+The default action under Emacs is to fork off the @code{display}
+program@footnote{@code{display} is from the ImageMagick package. For the
+@code{uncompface} and @code{icontopbm} programs look for a package
+like `compface' or `faces-xface' on a GNU/Linux system.}
+to view the face. Under XEmacs or Emacs 21+ with suitable image
+support, the default action is to display the face before the
@code{From} header. (It's nicer if XEmacs has been compiled with X-Face
support---that will make display somewhat faster. If there's no native
X-Face support, Gnus will try to convert the @code{X-Face} header using
-external programs from the @code{pbmplus} package and friends.) If you
+external programs from the @code{pbmplus} package and
+friends.@footnote{On a GNU/Linux system look for packages with names
+like @code{netpbm} or @code{libgr-progs}.}) If you
want to have this function in the display hook, it should probably come
last.