1 ;;; gnus-picon.el --- displaying pretty icons in Gnus
2 ;; Copyright (C) 1996 Free Software Foundation, Inc.
4 ;; Author: Wes Hardaker <hardaker@ece.ucdavis.edu>
5 ;; Keywords: news xpm annotation glyph faces
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
27 ;; - You must have XEmacs (19.12 or above I think) to use this.
28 ;; - Read the variable descriptions below.
32 ;; 1) display the icons in its own buffer:
34 ;; (add-hook 'gnus-article-display-hook 'gnus-article-display-picons t)
35 ;; (add-hook 'gnus-summary-prepare-hook 'gnus-group-display-picons t)
36 ;; (setq gnus-picons-display-where 'picons)
38 ;; Then add the picons buffer to your display configuration:
39 ;; The picons buffer needs to be at least 48 pixels high,
40 ;; which for me is 5 lines:
42 ;; (gnus-add-configuration
43 ;; '(article (vertical 1.0
46 ;; (summary .25 point)
49 ;; (gnus-add-configuration
50 ;; '(summary (vertical 1.0 (group 6)
52 ;; (summary 1.0 point))))
54 ;; 2) display the icons in the summary buffer
56 ;; (add-hook 'gnus-article-display-hook 'gnus-article-display-picons t)
57 ;; (add-hook 'gnus-summary-prepare-hook 'gnus-group-display-picons t)
58 ;; (setq gnus-picons-display-where 'summary)
60 ;; 3) display the icons in the article buffer
62 ;; (add-hook 'gnus-article-display-hook 'gnus-article-display-picons t)
63 ;; (add-hook 'gnus-article-prepare-hook 'gnus-group-display-picons t)
64 ;; (setq gnus-picons-display-where 'article)
68 ;; - I'm not even close to being a lisp expert.
69 ;; - The 't' (append) flag MUST be in the add-hook line
72 ;; - Remove the TODO section in the headers.
78 (require 'annotations)
79 (eval-when-compile (require 'cl))
81 (defvar gnus-picons-buffer "*Icon Buffer*"
82 "Buffer name to display the icons in if gnus-picons-display-where is 'picons.")
84 (defvar gnus-picons-display-where 'picons
85 "Where to display the group and article icons.")
87 (defvar gnus-picons-database "/usr/local/faces"
88 "Defines the location of the faces database.
89 For information on obtaining this database of pretty pictures, please
90 see http://www.cs.indiana.edu/picons/ftp/index.html" )
92 (defvar gnus-picons-news-directory "news"
93 "Sub-directory of the faces database containing the icons for newsgroups."
96 (defvar gnus-picons-user-directories '("local" "users" "usenix" "misc/MISC")
97 "List of directories to search for user faces."
100 (defvar gnus-picons-domain-directories '("domains")
101 "List of directories to search for domain faces.
102 Some people may want to add \"unknown\" to this list."
105 (defvar gnus-picons-x-face-file-name
106 (format "/tmp/picon-xface.%s.xbm" (user-login-name))
107 "The name of the file in which to store the converted X-face header.")
109 (defvar gnus-picons-convert-x-face (format "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | pbmtoxbm > %s" gnus-picons-x-face-file-name)
110 "Command to convert the x-face header into a xbm file."
113 (defvar gnus-group-annotations nil)
114 (defvar gnus-article-annotations nil)
115 (defvar gnus-x-face-annotations nil)
117 (defun gnus-picons-remove (plist)
118 (let ((listitem (car plist)))
119 (while (setq listitem (car plist))
120 (if (annotationp listitem)
121 (delete-annotation listitem))
122 (setq plist (cdr plist))))
125 (defun gnus-picons-remove-all ()
126 "Removes all picons from the Gnus display(s)."
128 (gnus-picons-remove gnus-article-annotations)
129 (gnus-picons-remove gnus-group-annotations)
130 (gnus-picons-remove gnus-x-face-annotations)
131 (setq gnus-article-annotations nil
132 gnus-group-annotations nil
133 gnus-x-face-annotations nil)
134 (if (bufferp gnus-picons-buffer)
135 (kill-buffer gnus-picons-buffer))
138 (defun gnus-get-buffer-name (variable)
139 "Returns the buffer name associated with the contents of a variable."
140 (cond ((symbolp variable)
141 (let ((newvar (cdr (assq variable gnus-window-to-buffer))))
142 (cond ((symbolp newvar)
143 (symbol-value newvar))
144 ((stringp newvar) newvar))))
148 (defun gnus-picons-article-display-x-face ()
149 "Display the x-face header bitmap in the 'gnus-picons-display-where buffer."
150 ;; delete any old ones.
151 (gnus-picons-remove gnus-x-face-annotations)
152 (setq gnus-x-face-annotations nil)
153 ;; display the new one.
154 (let ((gnus-article-x-face-command 'gnus-picons-display-x-face))
155 (gnus-article-display-x-face)))
157 (defun gnus-picons-display-x-face (beg end)
158 "Function to display the x-face header in the picons window.
159 To use: (setq gnus-article-x-face-command 'gnus-picons-display-x-face)"
161 ;; convert the x-face header to a .xbm file
162 (let ((process-connection-type nil)
164 (process-kill-without-query
165 (setq process (start-process
166 "gnus-x-face" nil "sh" "-c" gnus-picons-convert-x-face)))
167 (process-send-region "gnus-x-face" beg end)
168 (process-send-eof "gnus-x-face")
170 (while (not (equal (process-status process) 'exit))
174 (set-buffer (get-buffer-create (gnus-get-buffer-name
175 gnus-picons-display-where)))
176 (gnus-add-current-to-buffer-list)
177 (beginning-of-buffer)
178 (let ((iconpoint (point)))
179 (if (not (looking-at "^$"))
188 ;; append the annotation to gnus-article-annotations for deletion.
189 (setq gnus-x-face-annotations
191 (gnus-picons-try-to-find-face
192 gnus-picons-x-face-file-name iconpoint)
193 gnus-x-face-annotations)))
194 ;; delete the tmp file
195 (delete-file gnus-picons-x-face-file-name)))
197 (defun gnus-article-display-picons ()
198 "Display faces for an author and his/her domain in gnus-picons-display-where."
200 (if (and (featurep 'xpm)
201 (or (not (fboundp 'device-type)) (equal (device-type) 'x))
202 (mail-fetch-field "from"))
204 (let* ((iconpoint (point)) (from (mail-fetch-field "from"))
207 (string-match "\\([-_a-zA-Z0-9]+\\)@" from)
208 (match-string 1 from)))
210 (concat (gnus-picons-reverse-domain-path
212 (replace-in-string from ".*@\\([_a-zA-Z0-9-.]+\\).*"
215 (switch-to-buffer (gnus-get-buffer-name gnus-picons-display-where))
216 (gnus-add-current-to-buffer-list)
217 (beginning-of-buffer)
218 (setq iconpoint (point))
219 (if (not (looking-at "^$"))
229 (gnus-picons-remove gnus-article-annotations)
230 (setq gnus-article-annotations 'nil)
231 (if (equal username from)
232 (setq username (progn
233 (string-match "<\\([_a-zA-Z0-9-.]+\\)>" from)
234 (match-string 1 from))))
235 (mapcar '(lambda (pathpart)
236 (setq gnus-article-annotations
238 (gnus-picons-insert-face-if-exists
240 (file-name-as-directory
241 gnus-picons-database) pathpart)
242 (concat hostpath username)
244 gnus-article-annotations)))
245 gnus-picons-user-directories)
246 (mapcar '(lambda (pathpart)
247 (setq gnus-article-annotations
249 (gnus-picons-insert-face-if-exists
250 (concat (file-name-as-directory
251 gnus-picons-database) pathpart)
252 (concat hostpath "unknown")
254 gnus-article-annotations)))
255 gnus-picons-domain-directories)
256 (add-hook 'gnus-summary-exit-hook 'gnus-picons-remove-all)
259 (defun gnus-group-display-picons ()
260 "Display icons for the group in the gnus-picons-display-where buffer."
262 (if (and (featurep 'xpm)
263 (or (not (fboundp 'device-type)) (equal (device-type) 'x)))
266 ((iconpoint (point)))
267 (switch-to-buffer (gnus-get-buffer-name gnus-picons-display-where))
268 (gnus-add-current-to-buffer-list)
269 (beginning-of-buffer)
271 ((listp gnus-group-annotations)
272 (mapcar 'delete-annotation gnus-group-annotations)
273 (setq gnus-group-annotations nil))
274 ((annotationp gnus-group-annotations)
275 (delete-annotation gnus-group-annotations)
276 (setq gnus-group-annotations nil))
278 (setq iconpoint (point))
279 (if (not (looking-at "^$"))
281 (gnus-picons-remove gnus-group-annotations)
282 (setq gnus-group-annotations nil)
283 (setq gnus-group-annotations
284 (gnus-picons-insert-face-if-exists
285 (concat (file-name-as-directory gnus-picons-database)
286 gnus-picons-news-directory)
287 (concat (replace-in-string gnus-newsgroup-name "\\." "/")
290 (add-hook 'gnus-summary-exit-hook 'gnus-picons-remove-all)))))
293 (defun gnus-picons-insert-face-if-exists (path filename ipoint &optional rev)
294 "Inserts a face at point if I can find one"
295 (let ((pathfile (concat path "/" filename "/face"))
297 (replace-in-string filename
298 "[_a-zA-Z0-9-]+/\\([_A-Za-z0-9-]+\\)$" "\\1"))
301 (not (equal filename newfilename)))
302 (setq annotations (append
303 (gnus-picons-insert-face-if-exists path newfilename ipoint rev)
305 (if (eq (length annotations) (length (setq annotations (append
306 (gnus-picons-try-to-find-face (concat pathfile ".xpm") ipoint)
308 (setq annotations (append
309 (gnus-picons-try-to-find-face
310 (concat pathfile ".xbm") ipoint)
313 (not (equal filename newfilename)))
314 (setq annotations (append
315 (gnus-picons-insert-face-if-exists path newfilename ipoint rev)
321 (defun gnus-picons-try-to-find-face (path ipoint)
322 "If PATH exists, display it as a bitmap. Returns t if succedded."
323 (when (file-exists-p path)
324 (let ((gl (make-glyph path)))
325 (set-glyph-face gl 'default)
326 (list (make-annotation gl ipoint 'text)))))
328 (defun gnus-picons-reverse-domain-path (str)
330 (if (equal (replace-in-string str "^[^/]*$" "") "")
332 (concat (replace-in-string str "^.*/\\([_a-zA-Z0-9-]+\\)$" "\\1") "/"
333 (gnus-picons-reverse-domain-path
334 (replace-in-string str "^\\(.*\\)/[_a-zA-Z0-9-]+$" "\\1")))))
336 (provide 'gnus-picon)
338 ;;; gnus-picon.el ends here