*** empty log message ***
[gnus] / lisp / gnus-picon.el
1 ;;; gnus-picons.el:  Icon hacks for displaying pretty icons in Gnus.
2 ;; Copyright (C) 1996 Wes Hardaker
3
4 ;; Author:  Wes Hardaker <hardaker@ece.ucdavis.edu>
5 ;; Keywords:  gnus xpm annotation glyph faces
6
7 ;;; Commentary:
8
9 ;; Usage:
10 ;;     - You must have XEmacs (19.12 or above I think) to use this.
11 ;;     - Read the variable descriptions below.
12 ;;
13 ;;     - chose a setup:
14 ;;
15 ;;       1) display the icons in its own buffer:
16 ;;
17 ;;          (add-hook 'gnus-article-display-hook 'gnus-article-display-picons t)
18 ;;          (add-hook 'gnus-summary-display-hook 'gnus-group-display-picons t)
19 ;;          (setq gnus-picons-display-where 'picons)
20 ;;
21 ;;          Then add the picons buffer to your display configuration:
22 ;;          The picons buffer needs to be at least 48 pixels high,
23 ;;          which for me is 5 lines:
24 ;;
25 ;;          (gnus-add-configuration
26 ;;           '(article (vertical 1.0 
27 ;;                             (group 6)
28 ;;                             (picons 5)
29 ;;                             (summary .25 point)
30 ;;                             (article 1.0))))
31 ;;
32 ;;          (gnus-add-configuration
33 ;;           '(summary (vertical 1.0 (group 6)
34 ;;                      (picons 5)
35 ;;                      (summary 1.0 point))))
36 ;;
37 ;;       2) display the icons in the summary buffer
38 ;;
39 ;;          (add-hook 'gnus-article-display-hook 'gnus-article-display-picons t)
40 ;;          (add-hook 'gnus-summary-display-hook 'gnus-group-display-picons t)
41 ;;          (setq gnus-picons-display-where 'summary)
42 ;;
43 ;;       3) display the icons in the article buffer
44 ;;
45 ;;          (add-hook 'gnus-article-display-hook 'gnus-article-display-picons t)
46 ;;          (add-hook 'gnus-article-display-hook 'gnus-group-display-picons t)
47 ;;          (setq gnus-picons-display-where 'article)
48 ;;
49 ;;
50 ;; Warnings:
51 ;;     - I'm not even close to being a lisp expert.
52 ;;     - The 't' (append) flag MUST be in the add-hook line
53 ;;
54 ;; TODO:
55 ;;     - Remove the TODO section in the headers.
56 ;;
57
58 ;;; Code:
59
60 (require 'xpm)
61 (require 'annotations)
62 (eval-when-compile (require 'cl))
63
64 (defvar gnus-picons-buffer "*Icon Buffer*"
65   "Buffer name to display the icons in if gnus-picons-display-where is 'picons.")
66
67 (defvar gnus-picons-display-where 'picons
68   "Where to display the group and article icons.")
69
70 (defvar gnus-picons-database "/usr/local/faces"
71   "Defines the location of the faces database.  
72 For information on obtaining this database of pretty pictures, please
73 see http://www.cs.indiana.edu/picons/ftp/index.html" )
74
75 (defvar gnus-picons-news-directory "news"
76   "Sub-directory of the faces database containing the icons for newsgroups."
77 )
78
79 (defvar gnus-picons-user-directories '("local" "users" "usenix" "misc/MISC")
80   "List of directories to search for user faces."
81 )
82
83 (defvar gnus-picons-domain-directories '("domains")
84   "List of directories to search for domain faces.  
85 Some people may want to add \"unknown\" to this list."
86 )
87
88 (defvar gnus-group-annotations nil)
89 (defvar gnus-article-annotations nil)
90 (defvar gnus-x-face-annotations nil)
91
92 (defun gnus-picons-remove (plist)
93   (let ((listitem (car plist)))
94     (while (setq listitem (car plist))
95       (if (annotationp listitem)
96           (delete-annotation listitem))
97       (setq plist (cdr plist))))
98 )
99
100 (defun gnus-picons-remove-all ()
101   "Removes all picons from the Gnus display(s)."
102   (interactive)
103   (gnus-picons-remove gnus-article-annotations)
104   (gnus-picons-remove gnus-group-annotations)
105   (gnus-picons-remove gnus-x-face-annotations)
106   (setq gnus-article-annotations nil
107         gnus-group-annotations nil
108         gnus-x-face-annotations nil)
109   (if (bufferp gnus-picons-buffer)
110       (kill-buffer gnus-picons-buffer))
111 )
112
113 (defun gnus-get-buffer-name (variable)
114   "Returns the buffer name associated with the contents of a variable."
115   (cond ((symbolp variable)
116          (let ((newvar (cdr (assq variable gnus-window-to-buffer))))
117            (cond ((symbolp newvar)
118                   (symbol-value newvar))
119                  ((stringp newvar) newvar))))
120         ((stringp variable)
121          variable)))
122
123 (defvar gnus-picons-x-face-file-name 
124   (format "/tmp/picon-xface.%s.xbm" (user-login-name))
125   "The name of the file in which to store the converted X-face header.")
126
127 (defvar gnus-picons-convert-x-face (format "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | pbmtoxbm > %s" gnus-picons-x-face-file-name)
128   "Command to convert the x-face header into a xbm file."
129 )
130        
131 (defun gnus-picons-article-display-x-face ()
132   "Display the x-face header bitmap in the 'gnus-picons-display-where buffer."
133   ;; delete any old ones.
134   (gnus-picons-remove gnus-x-face-annotations)
135   (setq gnus-x-face-annotations nil)
136   ;; display the new one.
137   (let ((gnus-article-x-face-command 'gnus-picons-display-x-face))
138     (gnus-article-display-x-face)))
139
140 (defun gnus-picons-display-x-face (beg end)
141   "Function to display the x-face header in the picons window.
142 To use:  (setq gnus-article-x-face-command 'gnus-picons-display-x-face)"
143   (interactive)
144   ;; convert the x-face header to a .xbm file
145   (let ((process-connection-type nil)
146       (process nil))
147     (process-kill-without-query
148      (setq process (start-process
149       "gnus-x-face" nil "sh" "-c" gnus-picons-convert-x-face)))
150     (process-send-region "gnus-x-face" beg end)
151     (process-send-eof "gnus-x-face")
152   ;; wait for it.
153     (while (not (equal (process-status process) 'exit))
154       (sleep-for .1)))
155   ;; display it
156   (save-excursion
157     (set-buffer (get-buffer-create (gnus-get-buffer-name 
158                                     gnus-picons-display-where)))
159     (gnus-add-current-to-buffer-list)
160     (beginning-of-buffer)
161     (let ((iconpoint (point)))
162       (if (not (looking-at "^$"))
163         (if buffer-read-only
164             (progn 
165               (toggle-read-only)
166               (open-line 1)
167               (toggle-read-only)
168               )
169           (open-line 1)))
170       (end-of-line)
171       ;; append the annotation to gnus-article-annotations for deletion.
172       (setq gnus-x-face-annotations 
173           (append
174            (gnus-picons-try-to-find-face
175             gnus-picons-x-face-file-name iconpoint)
176            gnus-x-face-annotations)))
177     ;; delete the tmp file
178     (delete-file gnus-picons-x-face-file-name)))
179
180 (defun gnus-article-display-picons ()
181 "Display faces for an author and his/her domain in gnus-picons-display-where."
182   (interactive)
183   (if (and (featurep 'xpm) 
184            (or (not (fboundp 'device-type)) (equal (device-type) 'x)))
185       (save-excursion
186         (let* ((iconpoint (point)) (from (mail-fetch-field "from"))
187           (username 
188            (progn
189              (string-match "\\([-_a-zA-Z0-9]+\\)@" from)
190              (match-string 1 from)))
191            (hostpath
192             (concat (gnus-picons-reverse-domain-path
193                      (replace-in-string
194                       (replace-in-string from ".*@\\([_a-zA-Z0-9-.]+\\).*" 
195                                          "\\1") 
196                       "\\." "/")) "/")))
197           (switch-to-buffer (gnus-get-buffer-name gnus-picons-display-where))
198           (gnus-add-current-to-buffer-list)
199           (beginning-of-buffer)
200           (setq iconpoint (point))
201           (if (not (looking-at "^$"))
202               (if buffer-read-only
203                   (progn 
204                     (toggle-read-only)
205                     (open-line 1)
206                     (toggle-read-only)
207                     )
208                 (open-line 1)))
209
210           (end-of-line)
211           (gnus-picons-remove gnus-article-annotations)
212           (setq gnus-article-annotations 'nil)
213           (if (equal username from)
214                 (setq username (progn
215                                  (string-match "<\\([_a-zA-Z0-9-.]+\\)>" from)
216                                  (match-string 1 from))))
217           (mapcar '(lambda (pathpart) 
218                      (setq gnus-article-annotations
219                            (append
220                                    (gnus-picons-insert-face-if-exists 
221                                     (concat 
222                                      (file-name-as-directory 
223                                       gnus-picons-database) pathpart)
224                                     (concat hostpath username) 
225                                     iconpoint)
226                                     gnus-article-annotations))) 
227                   gnus-picons-user-directories)
228           (mapcar '(lambda (pathpart) 
229                      (setq gnus-article-annotations 
230                            (append
231                                    (gnus-picons-insert-face-if-exists 
232                                     (concat (file-name-as-directory 
233                                              gnus-picons-database) pathpart)
234                                     (concat hostpath "unknown") 
235                                     iconpoint)
236                                     gnus-article-annotations))) 
237                            gnus-picons-domain-directories)
238           (add-hook 'gnus-summary-exit-hook 'gnus-picons-remove-all)
239           ))))
240
241 (defun gnus-group-display-picons ()
242   "Display icons for the group in the gnus-picons-display-where buffer." 
243   (interactive)
244   (if (and (featurep 'xpm) 
245            (or (not (fboundp 'device-type)) (equal (device-type) 'x)))
246       (save-excursion
247       (let
248           ((iconpoint (point)))
249         (switch-to-buffer (gnus-get-buffer-name gnus-picons-display-where))
250         (gnus-add-current-to-buffer-list)
251         (beginning-of-buffer)
252         (cond 
253          ((listp gnus-group-annotations)
254           (mapcar 'delete-annotation gnus-group-annotations)
255           (setq gnus-group-annotations nil))
256          ((annotationp gnus-group-annotations)
257           (delete-annotation gnus-group-annotations)
258           (setq gnus-group-annotations nil))
259          )
260         (setq iconpoint (point))
261         (if (not (looking-at "^$"))
262             (open-line 1))
263         (gnus-picons-remove gnus-group-annotations)
264         (setq gnus-group-annotations nil)
265         (setq gnus-group-annotations
266               (gnus-picons-insert-face-if-exists 
267                (concat (file-name-as-directory gnus-picons-database)  
268                        gnus-picons-news-directory)
269                (concat (replace-in-string gnus-newsgroup-name "\\." "/") 
270                        "/unknown")
271                iconpoint t))
272         (add-hook 'gnus-summary-exit-hook 'gnus-picons-remove-all)))))
273
274
275 (defun gnus-picons-insert-face-if-exists (path filename ipoint &optional rev)
276   "Inserts a face at point if I can find one"
277   (let ((pathfile (concat path "/" filename "/face"))
278         (newfilename 
279          (replace-in-string filename 
280                             "[_a-zA-Z0-9-]+/\\([_A-Za-z0-9-]+\\)$" "\\1"))
281         (annotations nil))
282     (if (and rev
283          (not (equal filename newfilename)))
284         (setq annotations (append
285               (gnus-picons-insert-face-if-exists path newfilename ipoint rev)
286                annotations)))
287     (if (eq (length annotations) (length (setq annotations (append
288           (gnus-picons-try-to-find-face (concat pathfile ".xpm") ipoint)
289            annotations))))
290         (setq annotations (append
291                              (gnus-picons-try-to-find-face 
292                               (concat pathfile ".xbm") ipoint)
293                               annotations)))
294     (if (and (not rev)
295          (not (equal filename newfilename)))
296         (setq annotations (append
297               (gnus-picons-insert-face-if-exists path newfilename ipoint rev)
298                annotations)))
299     annotations
300     )
301   )
302   
303 (defun gnus-picons-try-to-find-face (path ipoint)
304   "If PATH exists, display it as a bitmap.  Returns t if succedded."
305   (when (file-exists-p path)
306     (let ((gl (make-glyph path)))
307       (set-glyph-face gl 'default)
308       (list (make-annotation gl ipoint 'text)))))
309
310 (defun gnus-picons-reverse-domain-path (str)
311   "a/b/c/d -> d/c/b/a"
312   (if (equal (replace-in-string str "^[^/]*$" "") "")
313       str
314     (concat (replace-in-string str "^.*/\\([_a-zA-Z0-9-]+\\)$" "\\1") "/"
315             (gnus-picons-reverse-domain-path 
316              (replace-in-string str "^\\(.*\\)/[_a-zA-Z0-9-]+$" "\\1")))))
317
318 (provide 'gnus-picon)
319
320 ;;; gnus-picon.el ends here