1 ;;; wl-xmas.el --- Wanderlust modules for XEmacsen.
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4 ;; Copyright (C) 2000 Katsumi Yamaoka <yamaoka@jpl.org>
6 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
7 ;; Katsumi Yamaoka <yamaoka@jpl.org>
8 ;; Keywords: mail, net news
10 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
12 ;; This program 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)
17 ;; This program 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.
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., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
39 (require 'wl-highlight)
40 (defvar-maybe wl-draft-mode-map (make-sparse-keymap))
41 (defalias-maybe 'toolbar-make-button-list 'ignore))
43 (add-hook 'wl-folder-mode-hook 'wl-setup-folder)
44 (add-hook 'wl-folder-mode-hook 'wl-folder-init-icons)
46 (add-hook 'wl-init-hook 'wl-biff-init-icons)
47 (add-hook 'wl-init-hook 'wl-plugged-init-icons)
49 (add-hook 'wl-summary-mode-hook 'wl-setup-summary)
51 (add-hook 'wl-message-display-internal-hook 'wl-setup-message)
53 (defvar wl-use-toolbar (if (featurep 'toolbar) 'default-toolbar nil))
54 (defvar wl-plugged-glyph nil)
55 (defvar wl-unplugged-glyph nil)
56 (defvar wl-biff-mail-glyph nil)
57 (defvar wl-biff-nomail-glyph nil)
59 (defvar wl-folder-toolbar
60 '([wl-folder-jump-to-current-entity
61 wl-folder-jump-to-current-entity t "Enter Current Folder"]
62 [wl-folder-next-entity
63 wl-folder-next-entity t "Next Folder"]
64 [wl-folder-prev-entity
65 wl-folder-prev-entity t "Previous Folder"]
66 [wl-folder-check-current-entity
67 wl-folder-check-current-entity t "Check Current Folder"]
68 [wl-folder-sync-current-entity
69 wl-folder-sync-current-entity t "Sync Current Folder"]
71 wl-draft t "Write a New Message"]
72 [wl-folder-goto-draft-folder
73 wl-folder-goto-draft-folder t "Go to Draft Folder"]
74 [wl-folder-empty-trash
75 wl-folder-empty-trash t "Empty Trash"]
77 wl-exit t "Quit Wanderlust"]
79 "The Folder buffer toolbar.")
81 (defvar wl-summary-toolbar
83 wl-summary-read t "Read Messages"]
85 wl-summary-next t "Next Message"]
87 wl-summary-prev t "Previous Message"]
88 [wl-summary-jump-to-current-message
89 wl-summary-jump-to-current-message t "Jump to Current Message"]
90 [wl-summary-sync-force-update
91 wl-summary-sync-force-update t "Sync Current Folder"]
93 wl-summary-delete t "Delete Current Message"]
94 [wl-summary-mark-as-important
95 wl-summary-mark-as-important t "Mark Current Message as Important"]
97 wl-summary-write-current-folder t "Write for Current Folder"]
99 wl-summary-reply t "Reply to Current Message" ]
100 [wl-summary-reply-with-citation
101 wl-summary-reply-with-citation t "Reply to Current Message with Citation"]
103 wl-summary-forward t "Forward Current Message"]
105 wl-summary-exit t "Exit Current Summary"]
107 "The Summary buffer toolbar.")
109 (defvar wl-message-toolbar
111 wl-message-read t "Read Contents"]
112 [wl-message-next-content
113 wl-message-next-content t "Next Content"]
114 [wl-message-prev-content
115 wl-message-prev-content t "Previous Content"]
117 wl-message-quit t "Back to Summary"]
118 [wl-message-play-content
119 wl-message-play-content t "Play Content"]
120 [wl-message-extract-content
121 wl-message-extract-content t "Extract Content"]
123 "The Message buffer toolbar.")
125 (defalias 'wl-draft-insert-signature 'insert-signature);; for draft toolbar.
127 (defvar wl-draft-toolbar
128 '([wl-draft-send-from-toolbar
129 wl-draft-send-from-toolbar t "Send Current Draft"]
130 [wl-draft-yank-original
131 wl-draft-yank-original t "Yank Displaying Message"]
132 [wl-draft-insert-signature
133 wl-draft-insert-signature t "Insert Signature"]
135 wl-draft-kill t "Kill Current Draft"]
136 [wl-draft-save-and-exit
137 wl-draft-save-and-exit t "Save Draft and Exit"]
139 "The Draft buffer toolbar.")
141 (defun wl-xmas-setup-toolbar (bar)
142 (let ((dir wl-icon-directory)
143 icon up down disabled name)
146 (setq icon (aref (car bar) 0)
147 name (symbol-name icon)
149 (unless (boundp icon)
150 (setq up (expand-file-name (concat name "-up.xpm") dir)
151 down (expand-file-name (concat name "-down.xpm") dir)
152 disabled (expand-file-name (concat name "-disabled.xpm") dir))
153 (if (file-exists-p up)
154 (set icon (toolbar-make-button-list
155 up (and (file-exists-p down) down)
156 (and (file-exists-p disabled) disabled)))
161 (defun wl-xmas-make-icon-glyph (icon-string icon-file
162 &optional locale tag-set)
163 (let ((glyph (make-glyph (vector 'string :data icon-string))))
164 (when wl-highlight-folder-with-icon
165 (set-glyph-image glyph
166 (vector 'xpm :file (expand-file-name
167 icon-file wl-icon-directory))
168 locale tag-set 'prepend))
172 (defsubst wl-xmas-setup-folder-toolbar ()
174 (wl-xmas-setup-toolbar wl-folder-toolbar)
175 (set-specifier (symbol-value wl-use-toolbar)
176 (cons (current-buffer) wl-folder-toolbar))))
178 (defsubst wl-xmas-setup-summary-toolbar ()
180 (wl-xmas-setup-toolbar wl-summary-toolbar)
181 (set-specifier (symbol-value wl-use-toolbar)
182 (cons (current-buffer) wl-summary-toolbar))))
184 (defsubst wl-xmas-setup-draft-toolbar ()
186 (wl-xmas-setup-toolbar wl-draft-toolbar)
187 (set-specifier (symbol-value wl-use-toolbar)
188 (cons (current-buffer) wl-draft-toolbar)))))
190 (defun wl-xmas-setup-message-toolbar ()
192 (wl-xmas-setup-toolbar wl-message-toolbar)
193 (set-specifier (symbol-value wl-use-toolbar)
194 (cons (current-buffer) wl-message-toolbar))))
196 (defvar wl-folder-toggle-icon-list
197 '((wl-folder-opened-glyph . wl-opened-group-folder-icon)
198 (wl-folder-closed-glyph . wl-closed-group-folder-icon)))
201 (defsubst wl-xmas-highlight-folder-group-line (glyph text-face numbers)
202 (let ((start (match-beginning 1))
205 (while (and (setq extent (extent-at start nil nil extent 'at))
206 (not (and (eq start (extent-start-position extent))
207 (eq end (extent-end-position extent))
208 (extent-end-glyph extent)))))
210 (setq extent (make-extent start end)))
211 (set-extent-properties extent `(end-open t start-closed t invisible t))
212 (set-extent-end-glyph
214 (or (get glyph 'glyph)
216 (wl-xmas-make-icon-glyph
217 (buffer-substring-no-properties start end)
219 (cdr (assq glyph wl-folder-toggle-icon-list))))))))
220 (let ((inhibit-read-only t))
221 (when wl-use-highlight-mouse-line
222 (put-text-property start (point-at-eol) 'mouse-face 'highlight))
225 (if (and wl-highlight-folder-by-numbers
226 numbers (nth 0 numbers) (nth 1 numbers)
227 (re-search-forward "[0-9-]+/[0-9-]+/[0-9-]+" end t))
228 (let* ((unsync (nth 0 numbers))
229 (unread (nth 1 numbers))
230 (face (cond ((and unsync (zerop unsync))
231 (if (and unread (zerop unread))
232 'wl-highlight-folder-zero-face
233 'wl-highlight-folder-unread-face))
236 wl-folder-many-unsync-threshold))
237 'wl-highlight-folder-many-face)
239 'wl-highlight-folder-few-face))))
240 (if (numberp wl-highlight-folder-by-numbers)
242 (put-text-property start (match-beginning 0)
244 (put-text-property (match-beginning 0) (point) 'face face))
245 (put-text-property start end 'face face)))
246 (put-text-property start end 'face text-face))))))
248 (defun wl-highlight-folder-current-line (&optional numbers)
254 (;; opened folder group
255 (looking-at wl-highlight-folder-opened-regexp)
256 (wl-xmas-highlight-folder-group-line 'wl-folder-opened-glyph
257 'wl-highlight-folder-opened-face
259 (;; closed folder group
260 (looking-at wl-highlight-folder-closed-regexp)
261 (wl-xmas-highlight-folder-group-line 'wl-folder-closed-glyph
262 'wl-highlight-folder-closed-face
265 (and (setq fld-name (wl-folder-get-folder-name-by-id
266 (get-text-property (point) 'wl-folder-entity-id)))
267 (looking-at "[ \t]+\\([^ \t]+\\)"))
268 (let ((start (match-beginning 1)))
270 (while (and (setq extent (extent-at start nil nil extent 'at))
271 (not (and (eq start (extent-start-position extent))
272 (eq start (extent-end-position extent))
273 (extent-begin-glyph extent)))))
275 (setq extent (make-extent start start)))
277 (set-extent-begin-glyph
280 ((string= fld-name wl-trash-folder);; trash folder
281 (let ((num (nth 2 numbers)));; number of messages
282 (get (if (or (not num) (zerop num))
283 'wl-folder-trash-empty-glyph
284 'wl-folder-trash-glyph)
286 ((string= fld-name wl-draft-folder);; draft folder
287 (get 'wl-folder-draft-glyph 'glyph))
288 ((string= fld-name wl-queue-folder);; queue folder
289 (get 'wl-folder-queue-glyph 'glyph))
290 (;; and one of many other folders
291 (setq type (elmo-folder-type fld-name))
292 (get (intern (format "wl-folder-%s-glyph" type)) 'glyph))))))
293 (let ((end (point-at-eol)))
294 (when wl-use-highlight-mouse-line
295 (put-text-property start end 'mouse-face 'highlight))
297 (if (looking-at (format "^[ \t]*\\(?:%s\\|%s\\)"
298 wl-folder-unsubscribe-mark
299 wl-folder-removed-mark))
300 'wl-highlight-folder-killed-face
301 'wl-highlight-folder-unknown-face)))
302 (if (and wl-highlight-folder-by-numbers
303 numbers (nth 0 numbers) (nth 1 numbers)
304 (re-search-forward "[0-9-]+/[0-9-]+/[0-9-]+" end t))
305 (let* ((unsync (nth 0 numbers))
306 (unread (nth 1 numbers))
308 ((and unsync (zerop unsync))
309 (if (and unread (zerop unread))
310 'wl-highlight-folder-zero-face
311 'wl-highlight-folder-unread-face))
314 wl-folder-many-unsync-threshold))
315 'wl-highlight-folder-many-face)
317 'wl-highlight-folder-few-face))))
318 (if (numberp wl-highlight-folder-by-numbers)
320 (put-text-property start (match-beginning 0)
322 (put-text-property (match-beginning 0)
325 ;; Remove previous face.
326 (put-text-property start (match-end 0) 'face nil)
327 (put-text-property start (match-end 0) 'face face)))
328 (put-text-property start end 'face text-face))))))))))
330 (defun wl-highlight-plugged-current-line ()
333 (let ((inhibit-read-only t)
336 (when (looking-at "[ \t]*\\(\\[\\([^]]+\\)\\]\\)")
337 (setq switch (elmo-match-buffer 2))
338 (when (and (setq extent (extent-at (match-end 1) nil nil nil 'at))
339 (extent-end-glyph extent))
340 (delete-extent extent))
341 (setq extent (make-extent (match-beginning 1) (match-end 1)))
342 (set-extent-property extent 'end-open t)
343 (set-extent-property extent 'start-closed t)
344 (set-extent-property extent 'invisible t)
345 (set-extent-end-glyph extent (if (string= switch wl-plugged-plug-on)
347 wl-unplugged-glyph))))))
349 (defun wl-plugged-set-folder-icon (folder string)
350 (let ((string (copy-sequence string))
351 (len (length string))
353 (if (string= folder wl-queue-folder)
354 (put-text-property 0 len 'begin-glyph
355 (get 'wl-folder-queue-glyph 'glyph)
357 (if (setq type (elmo-folder-type folder))
358 (put-text-property 0 len
360 (get (intern (format "wl-folder-%s-glyph" type))
365 (defvar wl-folder-internal-icon-list
366 ;; alist of (glyph . icon-file)
367 '((wl-folder-nntp-glyph . wl-nntp-folder-icon)
368 (wl-folder-imap4-glyph . wl-imap-folder-icon)
369 (wl-folder-pop3-glyph . wl-pop-folder-icon)
370 (wl-folder-localdir-glyph . wl-localdir-folder-icon)
371 (wl-folder-localnews-glyph . wl-localnews-folder-icon)
372 (wl-folder-internal-glyph . wl-internal-folder-icon)
373 (wl-folder-multi-glyph . wl-multi-folder-icon)
374 (wl-folder-filter-glyph . wl-filter-folder-icon)
375 (wl-folder-archive-glyph . wl-archive-folder-icon)
376 (wl-folder-pipe-glyph . wl-pipe-folder-icon)
377 (wl-folder-maildir-glyph . wl-maildir-folder-icon)
378 (wl-folder-nmz-glyph . wl-nmz-folder-icon)
379 (wl-folder-shimbun-glyph . wl-shimbun-folder-icon)
380 (wl-folder-trash-empty-glyph . wl-empty-trash-folder-icon)
381 (wl-folder-draft-glyph . wl-draft-folder-icon)
382 (wl-folder-queue-glyph . wl-queue-folder-icon)
383 (wl-folder-trash-glyph . wl-trash-folder-icon)))
385 (defun wl-folder-init-icons ()
386 (dolist (icon wl-folder-internal-icon-list)
387 (unless (get (car icon) 'glyph)
388 (put (car icon) 'glyph
389 (wl-xmas-make-icon-glyph "" (symbol-value (cdr icon)))))))
391 (defun wl-plugged-init-icons ()
392 (unless wl-plugged-glyph
393 (setq wl-plugged-glyph (wl-xmas-make-icon-glyph
394 wl-plug-state-indicator-on wl-plugged-icon)
395 wl-unplugged-glyph (wl-xmas-make-icon-glyph
396 wl-plug-state-indicator-off wl-unplugged-icon))
397 (let ((extent (make-extent nil nil)))
398 (let ((keymap (make-sparse-keymap)))
399 (define-key keymap 'button2
400 (make-modeline-command-wrapper 'wl-toggle-plugged))
401 (set-extent-keymap extent keymap)
402 (set-extent-property extent 'help-echo
403 "button2 toggles plugged status"))
404 (setq wl-modeline-plug-state-on (cons extent wl-plugged-glyph)
405 wl-modeline-plug-state-off (cons extent wl-unplugged-glyph)))))
407 (defun wl-biff-init-icons ()
408 (unless wl-biff-mail-glyph
409 (setq wl-biff-mail-glyph (wl-xmas-make-icon-glyph
410 wl-biff-state-indicator-on
412 wl-biff-nomail-glyph (wl-xmas-make-icon-glyph
413 wl-biff-state-indicator-off
414 wl-biff-nomail-icon))
415 (let ((extent (make-extent nil nil)))
416 (let ((keymap (make-sparse-keymap)))
417 (define-key keymap 'button2
418 (make-modeline-command-wrapper 'wl-biff-check-folders))
419 (set-extent-keymap extent keymap)
420 (set-extent-property extent 'help-echo "button2 checks new mails"))
421 (setq wl-modeline-biff-state-on (cons extent wl-biff-mail-glyph)
422 wl-modeline-biff-state-off (cons extent wl-biff-nomail-glyph)))))
424 (defun wl-make-date-string ()
425 (let ((s (current-time-string)))
426 (string-match "\\`\\([A-Z][a-z][a-z]\\) +[A-Z][a-z][a-z] +[0-9][0-9]? *[0-9][0-9]?:[0-9][0-9]:[0-9][0-9] *[0-9]?[0-9]?[0-9][0-9]"
428 (concat (wl-match-string 1 s) ", "
429 (timezone-make-date-arpa-standard s (current-time-zone)))))
431 (defun wl-setup-folder ()
432 (and (featurep 'scrollbar)
433 (set-specifier scrollbar-height (cons (current-buffer) 0)))
434 (wl-xmas-setup-folder-toolbar))
436 (defvar dragdrop-drop-functions)
438 (defun wl-setup-summary ()
439 (make-local-variable 'dragdrop-drop-functions)
440 (setq dragdrop-drop-functions '((wl-dnd-default-drop-message t t)))
441 (and (featurep 'scrollbar)
442 (set-specifier scrollbar-height (cons (current-buffer) 0)))
443 (wl-xmas-setup-summary-toolbar))
445 (defalias 'wl-setup-message 'wl-xmas-setup-message-toolbar)
447 (defun wl-message-define-keymap ()
448 (let ((keymap (make-sparse-keymap)))
449 (define-key keymap "l" 'wl-message-toggle-disp-summary)
450 (define-key keymap 'button4 'wl-message-wheel-down)
451 (define-key keymap 'button5 'wl-message-wheel-up)
452 (define-key keymap [(shift button4)] 'wl-message-wheel-down)
453 (define-key keymap [(shift button5)] 'wl-message-wheel-up)
454 (set-keymap-parent wl-message-button-map keymap)
455 (define-key wl-message-button-map 'button2
456 'wl-message-button-dispatcher)
459 (defun wl-message-wheel-up (event)
461 (if (string-match (regexp-quote wl-message-buffer-name)
462 (regexp-quote (buffer-name)))
463 (wl-message-prev-page)
464 (let ((cur-buf (current-buffer))
466 (save-selected-window
467 (select-window (event-window event))
469 (setq proceed (wl-message-next-page)))
471 (if (memq 'shift (event-modifiers event))
473 (wl-summary-next t))))))
475 (defun wl-message-wheel-down (event)
477 (if (string-match (regexp-quote wl-message-buffer-name)
478 (regexp-quote (buffer-name)))
479 (wl-message-prev-page)
480 (let ((cur-buf (current-buffer))
482 (save-selected-window
483 (select-window (event-window event))
485 (setq proceed (wl-message-prev-page)))
487 (if (memq 'shift (event-modifiers event))
489 (wl-summary-prev t)))))
491 (defun wl-draft-overload-menubar ()
492 (when (featurep 'menubar)
493 (add-menu-item '("Mail") "Send, Keep Editing"
494 'wl-draft-send t "Send Mail")
495 (add-menu-item '("Mail") "Send Message"
496 'wl-draft-send-and-exit t "Send and Exit")
497 (delete-menu-item '("Mail" "Send Mail"))
498 (delete-menu-item '("Mail" "Send and Exit"))
499 (add-menu-item '("Mail") "Preview Message"
500 'wl-draft-preview-message t "Cancel")
501 (add-menu-item '("Mail") "Save Draft and Exit"
502 'wl-draft-save-and-exit t "Cancel")
503 (add-menu-item '("Mail") "Kill Current Draft"
504 'wl-draft-kill t "Cancel")
505 (delete-menu-item '("Mail" "Cancel"))))
507 (defun wl-draft-mode-setup ()
509 (define-derived-mode wl-draft-mode mail-mode "Draft"
510 "draft mode for Wanderlust derived from mail mode.
511 See info under Wanderlust for full documentation.
514 \\{wl-draft-mode-map}"))
516 (defun wl-draft-key-setup ()
517 (define-key wl-draft-mode-map "\C-c\C-y" 'wl-draft-yank-original)
518 (define-key wl-draft-mode-map "\C-c\C-s" 'wl-draft-send)
519 (define-key wl-draft-mode-map "\C-c\C-c" 'wl-draft-send-and-exit)
520 (define-key wl-draft-mode-map "\C-c\C-z" 'wl-draft-save-and-exit)
521 (define-key wl-draft-mode-map "\C-c\C-k" 'wl-draft-kill)
522 (define-key wl-draft-mode-map "\C-l" 'wl-draft-highlight-and-recenter)
523 (define-key wl-draft-mode-map "\C-i" 'wl-complete-field-body-or-tab)
524 (define-key wl-draft-mode-map "\C-c\C-r" 'wl-draft-caesar-region)
525 (define-key wl-draft-mode-map "\M-t" 'wl-toggle-plugged)
526 (define-key wl-draft-mode-map "\C-c\C-o" 'wl-jump-to-draft-buffer)
527 (define-key wl-draft-mode-map "\C-c\C-e" 'wl-draft-config-exec)
528 (define-key wl-draft-mode-map "\C-c\C-j" 'wl-template-select)
529 (define-key wl-draft-mode-map "\C-c\C-p" 'wl-draft-preview-message)
530 ;; (define-key wl-draft-mode-map "\C-x\C-s" 'wl-draft-save)
531 (define-key wl-draft-mode-map "\C-c\C-a" 'wl-addrmgr)
532 (define-key wl-draft-mode-map "\C-xk" 'wl-draft-mimic-kill-buffer)
533 (define-key wl-draft-mode-map "\C-c\C-d" 'wl-draft-elide-region)
534 (define-key wl-draft-mode-map "\C-a" 'wl-draft-beginning-of-line))
536 (defun wl-draft-overload-functions ()
537 (wl-mode-line-buffer-identification)
538 ;; (local-set-key "\C-c\C-s" 'wl-draft-send);; override
539 (wl-xmas-setup-draft-toolbar)
540 (wl-draft-overload-menubar))
542 (defalias 'wl-defface 'defface)
544 (defun wl-read-event-char ()
545 "Get the next event."
546 (let ((event (next-command-event)))
548 ;; We junk all non-key events. Is this naughty?
549 (while (not (or (key-press-event-p event)
550 (button-press-event-p event)))
551 (dispatch-event event)
552 (setq event (next-command-event)))
553 (cons (and (key-press-event-p event)
554 (event-to-character event))
558 (product-provide (provide 'wl-xmas) (require 'wl-version))
560 ;;; wl-xmas.el ends here