1 ;;; emchat-buddy.el --- "Buddy" code for EMchat
3 ;; Copyright (C) 2007 - 2010 Steve Youngs
5 ;; Author: Steve Youngs <steve@emchat.org>
6 ;; Maintainer: Steve Youngs <steve@emchat.org>
8 ;; Homepage: http://www.emchat.org/
11 ;; This file is part of EMchat.
13 ;; Redistribution and use in source and binary forms, with or without
14 ;; modification, are permitted provided that the following conditions
17 ;; 1. Redistributions of source code must retain the above copyright
18 ;; notice, this list of conditions and the following disclaimer.
20 ;; 2. Redistributions in binary form must reproduce the above copyright
21 ;; notice, this list of conditions and the following disclaimer in the
22 ;; documentation and/or other materials provided with the distribution.
24 ;; 3. Neither the name of the author nor the names of any contributors
25 ;; may be used to endorse or promote products derived from this
26 ;; software without specific prior written permission.
28 ;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
29 ;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 ;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 ;; DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 ;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 ;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 ;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35 ;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
36 ;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
37 ;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
38 ;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 (require 'emchat-menu)
42 (require 'emchat-status)
43 (require 'emchat-world)
44 (require 'emchat-history))
50 (defgroup emchat-buddy nil
51 "Contact list preferences."
55 (defcustom emchat-buddy-window-width 20
56 "*Width of window for `emchat-buddy-buffer'."
57 :group 'emchat-interface)
59 (defcustom emchat-buddy-view
60 'emchat-connected-aliases
61 "*View of buddy buffer.
62 It determines what aliases to be display in buddy buffer. For example,
63 \(emchat-connected-aliases) means display all connected aliases.
65 See `emchat-buddy-view-all', `emchat-buddy-view-connected', and
66 `emchat-buddy-view-active'."
68 :type '(choice (item emchat-all-aliases)
69 (item emchat-connected-aliases)
70 (item emchat-active-aliases))
71 :initialize 'custom-initialize-default)
73 (defcustom emchat-buddy-show-xface nil
74 "*When non-nil, display XFace images in the buddy buffer.
76 The images come from BBDB. For an image to display in the buddy
77 buffer there has to be an existing BBDB entry for the contact that
78 has both a `face' field, for the image, and a `icqnick' field, to
79 match from the contact name in the buddy buffer."
84 (defcustom emchat-buddy-prefer-cface-to-xface (featurep 'png)
85 "*When non-nil, display colour faces instead of X-Face if available."
89 (defface emchat-face-selected
90 '((((background dark))
91 (:foreground "darkblue" :background "yellow"))
93 (:foreground "darkblue" :background "yellow")))
94 "Face for OFFLINE status."
97 ;;; Internal variables
100 (defvar emchat-buddy-buffer nil
101 "Buffer for contact list.")
103 (defun emchat-buddy-mode ()
104 "Major mode for contact list in emchat.
105 Commands: \\{emchat-buddy-mode-map}
107 Turning on `emchat-buddy-mode' runs the hook `emchat-buddy-mode-hook'."
109 (kill-all-local-variables)
110 (use-local-map emchat-buddy-mode-map)
111 (setq mode-name "emchat-buddy")
112 (setq major-mode 'emchat-buddy-mode)
113 ;; put easy-menu-add after set mode-name
114 (easy-menu-add emchat-main-easymenu)
115 (easy-menu-add emchat-buddy-menu)
116 (easy-menu-add emchat-log-menu)
117 (set-specifier has-modeline-p nil
118 (cons (current-buffer) nil))
119 (set-specifier horizontal-scrollbar-visible-p nil
120 (cons (current-buffer) nil))
121 ;(setq modeline-format "%b")
123 (run-hooks 'emchat-buddy-mode-hook))
125 (defun emchat-buddy-view-set (&optional symbol value)
126 "Set `emchat-buddy-view'."
127 (set-default symbol value)
128 (emchat-buddy-show-buffer 'new 'no-select))
130 (defun emchat-face-to-png (face)
131 "Base64 decode a Face header into a PNG.
135 (base64-decode-region (point-min) (point-max))
138 (defun emchat-buddy-show-xface (alias)
139 "Display an XFace image in the buddy buffer."
140 (unless (featurep '(and xface bbdb-autoloads))
141 (error 'unimplemented "X-Face and/or BBDB"))
143 (when (buffer-live-p emchat-buddy-buffer)
144 (set-buffer emchat-buddy-buffer)
145 (goto-char (point-min))
146 (when (search-forward-regexp (concat "^" (regexp-quote alias) "$") nil t)
147 (let ((ext (extent-at (point)))
148 (all-records (bbdb-records))
149 face cface nick record)
151 (setq record (car all-records)
152 nick (bbdb-record-getprop record 'icqnick)
153 face (bbdb-record-getprop record 'face)
154 cface (bbdb-record-getprop record 'cface))
155 (when (and (equal nick alias)
157 ;; put some whitespace between the image and the name
158 (set-extent-begin-glyph
159 (make-extent (point-at-bol) (point-at-eol))
163 (or (not emchat-buddy-prefer-cface-to-xface)
165 (set-extent-begin-glyph
167 (make-glyph (list (vector 'xface
168 :data (concat "X-Face: " face)
170 :background "white")))))
172 (when (and (featurep 'png)
174 emchat-buddy-prefer-cface-to-xface)
175 (set-extent-begin-glyph
177 (make-glyph (list (vector 'png
178 :data (emchat-face-to-png cface)))))))
179 (setq all-records (cdr all-records))))))))
182 (defun emchat-buddy-show-buffer (&optional new no-select)
183 "Switch to `emchat-buddy-buffer'.
184 Create buffer if buffer does not exists already or
186 Don't select buddy window if NO-SELECT is non-nil.
187 See `emchat-buddy-view' and `emchat-buddy-status-color-hint-flag'."
189 (when (or (not (buffer-live-p emchat-buddy-buffer))
191 (setq emchat-buddy-buffer (get-buffer-create "*emchat buddy*"))
192 (set-buffer emchat-buddy-buffer)
194 (loop for alias in (symbol-value emchat-buddy-view)
195 as status = (emchat-world-getf alias 'status)
196 as face = (emchat-status-face status)
197 do (insert-face (concat alias "\n") face)
198 do (when emchat-buddy-show-xface (emchat-buddy-show-xface alias))
199 do (emchat-buddy-update-face alias))
202 (switch-to-buffer emchat-buddy-buffer)))
204 (defun emchat-buddy-view-all ()
205 "Display all aliases in `emchat-world'.
206 See `emchat-buddy-view'."
208 (emchat-buddy-view-set 'emchat-buddy-view 'emchat-all-aliases))
210 (defun emchat-buddy-view-connected ()
211 "Display all connected aliases.
212 See `emchat-buddy-view' and `emchat-connected-aliases'."
214 (emchat-buddy-view-set 'emchat-buddy-view 'emchat-connected-aliases))
216 (defun emchat-buddy-view-active ()
217 "Display all active aliases.
218 See `emchat-buddy-view' and `emchat-active-aliases'."
220 (emchat-buddy-view-set 'emchat-buddy-view 'emchat-active-aliases))
222 (eval-when-compile (defvar emchat-history-directory))
224 (defun emchat-buddy-show-xface-in-balloon (alias)
225 "Display an XFace image in the balloon-help buffer."
226 (unless (featurep '(and xface bbdb-autoloads))
227 (error 'unimplemented "X-Face and/or BBDB"))
229 (let ((ext (or (extent-at (point))
230 (make-extent (point-min) (point-min))))
231 (all-records (bbdb-records))
232 face cface nick record)
234 (setq record (car all-records)
235 nick (bbdb-record-getprop record 'icqnick)
236 face (bbdb-record-getprop record 'face)
237 cface (bbdb-record-getprop record 'cface))
238 (when (and (equal nick alias)