1 ;;; wl-xmas.el --- Wanderlust modules for XEmacsen.
3 ;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
4 ;; Yuuichi Teranishi <teranisi@gohome.org>
5 ;; Copyright (C) 2000, 2001, 2002, 2003 Katsumi Yamaoka <yamaoka@jpl.org>
7 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
8 ;; Katsumi Yamaoka <yamaoka@jpl.org>
9 ;; Keywords: mail, net news
11 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
13 ;; This program is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; This program is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
40 (require 'wl-highlight
)
41 (defvar-maybe wl-draft-mode-map
(make-sparse-keymap))
42 (defalias-maybe 'toolbar-make-button-list
'ignore
))
44 (add-hook 'wl-folder-mode-hook
'wl-setup-folder
)
45 (add-hook 'wl-folder-mode-hook
'wl-folder-init-icons
)
47 (add-hook 'wl-init-hook
'wl-biff-init-icons
)
48 (add-hook 'wl-init-hook
'wl-plugged-init-icons
)
50 (add-hook 'wl-summary-mode-hook
'wl-setup-summary
)
52 (add-hook 'wl-message-display-internal-hook
'wl-setup-message
)
54 (defvar wl-use-toolbar
(if (featurep 'toolbar
) 'default-toolbar nil
))
55 (defvar wl-plugged-glyph nil
)
56 (defvar wl-unplugged-glyph nil
)
57 (defvar wl-biff-mail-glyph nil
)
58 (defvar wl-biff-nomail-glyph nil
)
60 (defvar wl-folder-toolbar
61 '([wl-folder-jump-to-current-entity
62 wl-folder-jump-to-current-entity t
"Enter Current Folder"]
63 [wl-folder-next-entity
64 wl-folder-next-entity t
"Next Folder"]
65 [wl-folder-prev-entity
66 wl-folder-prev-entity t
"Previous Folder"]
67 [wl-folder-check-current-entity
68 wl-folder-check-current-entity t
"Check Current Folder"]
69 [wl-folder-sync-current-entity
70 wl-folder-sync-current-entity t
"Sync Current Folder"]
72 wl-draft t
"Write a New Message"]
73 [wl-folder-goto-draft-folder
74 wl-folder-goto-draft-folder t
"Go to Draft Folder"]
75 [wl-folder-empty-trash
76 wl-folder-empty-trash t
"Empty Trash"]
78 wl-exit t
"Quit Wanderlust"]
80 "The Folder buffer toolbar.")
82 (defvar wl-summary-toolbar
84 wl-summary-read t
"Read Messages"]
86 wl-summary-next t
"Next Message"]
88 wl-summary-prev t
"Previous Message"]
89 [wl-summary-jump-to-current-message
90 wl-summary-jump-to-current-message t
"Jump to Current Message"]
91 [wl-summary-sync-force-update
92 wl-summary-sync-force-update t
"Sync Current Folder"]
94 wl-summary-dispose t
"Dispose Current Message"]
96 wl-summary-set-flags t
"Set Flags"]
98 wl-summary-write-current-folder t
"Write for Current Folder"]
100 wl-summary-reply t
"Reply to Current Message" ]
101 [wl-summary-reply-with-citation
102 wl-summary-reply-with-citation t
"Reply to Current Message with Citation"]
104 wl-summary-forward t
"Forward Current Message"]
106 wl-summary-exit t
"Exit Current Summary"]
108 "The Summary buffer toolbar.")
110 (defvar wl-message-toolbar
112 wl-message-read t
"Read Contents"]
113 [wl-message-next-content
114 wl-message-next-content t
"Next Content"]
115 [wl-message-prev-content
116 wl-message-prev-content t
"Previous Content"]
118 wl-message-quit t
"Back to Summary"]
119 [wl-message-play-content
120 wl-message-play-content t
"Play Content"]
121 [wl-message-extract-content
122 wl-message-extract-content t
"Extract Content"]
124 "The Message buffer toolbar.")
126 (defalias 'wl-draft-insert-signature
'insert-signature
);; for draft toolbar.
128 (defvar wl-draft-toolbar
129 '([wl-draft-send-from-toolbar
130 wl-draft-send-from-toolbar t
"Send Current Draft"]
131 [wl-draft-yank-original
132 wl-draft-yank-original t
"Yank Displaying Message"]
133 [wl-draft-insert-signature
134 wl-draft-insert-signature t
"Insert Signature"]
136 wl-draft-kill t
"Kill Current Draft"]
137 [wl-draft-save-and-exit
138 wl-draft-save-and-exit t
"Save Draft and Exit"]
140 "The Draft buffer toolbar.")
142 (defun wl-xmas-setup-toolbar (bar)
143 (let ((dir wl-icon-directory
)
144 icon up down disabled name
)
147 (setq icon
(aref (car bar
) 0)
148 name
(symbol-name icon
)
150 (unless (boundp icon
)
151 (setq up
(expand-file-name (concat name
"-up.xpm") dir
)
152 down
(expand-file-name (concat name
"-down.xpm") dir
)
153 disabled
(expand-file-name (concat name
"-disabled.xpm") dir
))
154 (if (file-exists-p up
)
155 (set icon
(toolbar-make-button-list
156 up
(and (file-exists-p down
) down
)
157 (and (file-exists-p disabled
) disabled
)))
162 (defun wl-xmas-make-icon-glyph (icon-string icon-file
163 &optional locale tag-set
)
164 (let ((glyph (make-glyph (vector 'string
:data icon-string
))))
165 (when wl-highlight-folder-with-icon
166 (set-glyph-image glyph
167 (vector 'xpm
:file
(expand-file-name
168 icon-file wl-icon-directory
))
169 locale tag-set
'prepend
))
173 (defsubst wl-xmas-setup-folder-toolbar
()
175 (wl-xmas-setup-toolbar wl-folder-toolbar
)
176 (set-specifier (symbol-value wl-use-toolbar
)
177 (cons (current-buffer) wl-folder-toolbar
))))
179 (defsubst wl-xmas-setup-summary-toolbar
()
181 (wl-xmas-setup-toolbar wl-summary-toolbar
)
182 (set-specifier (symbol-value wl-use-toolbar
)
183 (cons (current-buffer) wl-summary-toolbar
))))
185 (defsubst wl-xmas-setup-draft-toolbar
()
187 (wl-xmas-setup-toolbar wl-draft-toolbar
)
188 (set-specifier (symbol-value wl-use-toolbar
)
189 (cons (current-buffer) wl-draft-toolbar
)))))
191 (defun wl-xmas-setup-message-toolbar ()
193 (wl-xmas-setup-toolbar wl-message-toolbar
)
194 (set-specifier (symbol-value wl-use-toolbar
)
195 (cons (current-buffer) wl-message-toolbar
))))
197 (defvar wl-folder-toggle-icon-list
198 '((wl-folder-opened-glyph . wl-opened-group-folder-icon
)
199 (wl-folder-closed-glyph . wl-closed-group-folder-icon
)))
202 (defsubst wl-xmas-highlight-folder-group-line
(glyph text-face numbers
)
203 (let ((start (match-beginning 1))
205 (let ((extent (or (map-extents
206 (lambda (extent maparg
)
207 (and (eq start
(extent-start-position extent
))
208 (eq end
(extent-end-position extent
))
210 nil start start nil nil
'end-glyph
)
211 (make-extent start end
))))
212 (set-extent-properties extent
`(end-open t start-closed t invisible t
))
213 (set-extent-end-glyph
215 (or (get glyph
'glyph
)
217 (wl-xmas-make-icon-glyph
218 (buffer-substring-no-properties start end
)
220 (cdr (assq glyph wl-folder-toggle-icon-list
))))))))
221 (let ((inhibit-read-only t
))
222 (when wl-use-highlight-mouse-line
223 (put-text-property start
(point-at-eol) 'mouse-face
'highlight
))
226 (if (and wl-highlight-folder-by-numbers
227 numbers
(nth 0 numbers
) (nth 1 numbers
)
228 (re-search-forward "[0-9-]+/[0-9-]+/[0-9-]+" end t
))
229 (let* ((unsync (nth 0 numbers
))
230 (unread (nth 1 numbers
))
231 (face (cond ((and unsync
(zerop unsync
))
232 (if (and unread
(zerop unread
))
233 'wl-highlight-folder-zero-face
234 'wl-highlight-folder-unread-face
))
237 wl-folder-many-unsync-threshold
))
238 'wl-highlight-folder-many-face
)
240 'wl-highlight-folder-few-face
))))
241 (if (numberp wl-highlight-folder-by-numbers
)
243 (put-text-property start
(match-beginning 0)
245 (put-text-property (match-beginning 0) (point) 'face face
))
246 (put-text-property start end
'face face
)))
247 (put-text-property start end
'face text-face
))))))
249 (defun wl-highlight-folder-current-line (&optional numbers
)
255 (;; opened folder group
256 (and (wl-folder-buffer-group-p)
257 (looking-at wl-highlight-folder-opened-regexp
))
258 (wl-xmas-highlight-folder-group-line 'wl-folder-opened-glyph
259 'wl-highlight-folder-opened-face
261 (;; closed folder group
262 (and (wl-folder-buffer-group-p)
263 (looking-at wl-highlight-folder-closed-regexp
))
264 (wl-xmas-highlight-folder-group-line 'wl-folder-closed-glyph
265 'wl-highlight-folder-closed-face
268 (and (setq fld-name
(wl-folder-get-folder-name-by-id
269 (get-text-property (point) 'wl-folder-entity-id
)))
270 (looking-at "[ \t]+\\([^ \t]+\\)"))
271 (let ((start (match-beginning 1)))
272 (let ((extent (or (map-extents
273 (lambda (extent maparg
)
274 (and (eq start
(extent-start-position extent
))
275 (eq start
(extent-end-position extent
))
277 nil start start nil nil
'begin-glyph
)
278 (make-extent start start
))))
280 (set-extent-begin-glyph
283 ((string= fld-name wl-trash-folder
);; trash folder
284 (let ((num (nth 2 numbers
)));; number of messages
285 (get (if (or (not num
) (zerop num
))
286 'wl-folder-trash-empty-glyph
287 'wl-folder-trash-glyph
)
289 ((string= fld-name wl-draft-folder
);; draft folder
290 (get 'wl-folder-draft-glyph
'glyph
))
291 ((string= fld-name wl-queue-folder
);; queue folder
292 (get 'wl-folder-queue-glyph
'glyph
))
293 (;; and one of many other folders
294 (setq type
(or (elmo-folder-type fld-name
)
295 (elmo-folder-type-internal
296 (elmo-make-folder fld-name
))))
297 (get (intern (format "wl-folder-%s-glyph" type
)) 'glyph
))))))
298 (let ((end (point-at-eol)))
299 (when wl-use-highlight-mouse-line
300 (put-text-property start end
'mouse-face
'highlight
))
302 (if (looking-at (format "^[ \t]*\\(?:%s\\|%s\\)"
303 wl-folder-unsubscribe-mark
304 wl-folder-removed-mark
))
305 'wl-highlight-folder-killed-face
306 'wl-highlight-folder-unknown-face
)))
307 (if (and wl-highlight-folder-by-numbers
308 numbers
(nth 0 numbers
) (nth 1 numbers
)
309 (re-search-forward "[0-9-]+/[0-9-]+/[0-9-]+" end t
))
310 (let* ((unsync (nth 0 numbers
))
311 (unread (nth 1 numbers
))
313 ((and unsync
(zerop unsync
))
314 (if (and unread
(zerop unread
))
315 'wl-highlight-folder-zero-face
316 'wl-highlight-folder-unread-face
))
319 wl-folder-many-unsync-threshold
))
320 'wl-highlight-folder-many-face
)
322 'wl-highlight-folder-few-face
))))
323 (if (numberp wl-highlight-folder-by-numbers
)
325 (put-text-property start
(match-beginning 0)
327 (put-text-property (match-beginning 0)
330 ;; Remove previous face.
331 (put-text-property start
(match-end 0) 'face nil
)
332 (put-text-property start
(match-end 0) 'face face
)))
333 (put-text-property start end
'face text-face
))))))))))
335 (defun wl-highlight-plugged-current-line ()
338 (let ((inhibit-read-only t
)
341 (when (looking-at "[ \t]*\\(\\[\\([^]]+\\)\\]\\)")
342 (setq switch
(elmo-match-buffer 2))
343 (when (and (setq extent
(extent-at (match-end 1) nil nil nil
'at
))
344 (extent-end-glyph extent
))
345 (delete-extent extent
))
346 (setq extent
(make-extent (match-beginning 1) (match-end 1)))
347 (set-extent-property extent
'end-open t
)
348 (set-extent-property extent
'start-closed t
)
349 (set-extent-property extent
'invisible t
)
350 (set-extent-end-glyph extent
(if (string= switch wl-plugged-plug-on
)
352 wl-unplugged-glyph
))))))
354 (defun wl-plugged-set-folder-icon (folder string
)
355 (let ((string (copy-sequence string
))
356 (len (length string
))
358 (if (string= folder wl-queue-folder
)
359 (put-text-property 0 len
'begin-glyph
360 (get 'wl-folder-queue-glyph
'glyph
)
362 (if (setq type
(elmo-folder-type folder
))
363 (put-text-property 0 len
365 (get (intern (format "wl-folder-%s-glyph" type
))
370 (defvar wl-folder-internal-icon-list
371 ;; alist of (glyph . icon-file)
372 '((wl-folder-nntp-glyph . wl-nntp-folder-icon
)
373 (wl-folder-imap4-glyph . wl-imap-folder-icon
)
374 (wl-folder-pop3-glyph . wl-pop-folder-icon
)
375 (wl-folder-localdir-glyph . wl-localdir-folder-icon
)
376 (wl-folder-localnews-glyph . wl-localnews-folder-icon
)
377 (wl-folder-internal-glyph . wl-internal-folder-icon
)
378 (wl-folder-multi-glyph . wl-multi-folder-icon
)
379 (wl-folder-filter-glyph . wl-filter-folder-icon
)
380 (wl-folder-archive-glyph . wl-archive-folder-icon
)
381 (wl-folder-pipe-glyph . wl-pipe-folder-icon
)
382 (wl-folder-maildir-glyph . wl-maildir-folder-icon
)
383 (wl-folder-search-glyph . wl-search-folder-icon
)
384 (wl-folder-shimbun-glyph . wl-shimbun-folder-icon
)
385 (wl-folder-file-glyph . wl-file-folder-icon
)
386 (wl-folder-access-glyph . wl-access-folder-icon
)
387 (wl-folder-trash-empty-glyph . wl-empty-trash-folder-icon
)
388 (wl-folder-draft-glyph . wl-draft-folder-icon
)
389 (wl-folder-queue-glyph . wl-queue-folder-icon
)
390 (wl-folder-trash-glyph . wl-trash-folder-icon
)))
392 (defun wl-folder-init-icons ()
393 (dolist (icon wl-folder-internal-icon-list
)
394 (unless (get (car icon
) 'glyph
)
395 (put (car icon
) 'glyph
396 (wl-xmas-make-icon-glyph "" (symbol-value (cdr icon
)))))))
398 (defun wl-plugged-init-icons ()
399 (unless wl-plugged-glyph
400 (setq wl-plugged-glyph
(wl-xmas-make-icon-glyph
401 wl-plug-state-indicator-on wl-plugged-icon
)
402 wl-unplugged-glyph
(wl-xmas-make-icon-glyph
403 wl-plug-state-indicator-off wl-unplugged-icon
))
404 (let ((extent (make-extent nil nil
)))
405 (let ((keymap (make-sparse-keymap)))
406 (define-key keymap
'button2
407 (make-modeline-command-wrapper 'wl-toggle-plugged
))
408 (set-extent-keymap extent keymap
)
409 (set-extent-property extent
'help-echo
410 "button2 toggles plugged status"))
411 (setq wl-modeline-plug-state-on
(cons extent wl-plugged-glyph
)
412 wl-modeline-plug-state-off
(cons extent wl-unplugged-glyph
)))))
414 (defun wl-biff-init-icons ()
415 (unless wl-biff-mail-glyph
416 (setq wl-biff-mail-glyph
(wl-xmas-make-icon-glyph
417 wl-biff-state-indicator-on
419 wl-biff-nomail-glyph
(wl-xmas-make-icon-glyph
420 wl-biff-state-indicator-off
421 wl-biff-nomail-icon
))
422 (let ((extent (make-extent nil nil
)))
423 (let ((keymap (make-sparse-keymap)))
424 (define-key keymap
'button2
425 (make-modeline-command-wrapper 'wl-biff-check-folders
))
426 (set-extent-keymap extent keymap
)
427 (set-extent-property extent
'help-echo
"button2 checks new mails"))
428 (setq wl-modeline-biff-state-on
(cons extent wl-biff-mail-glyph
)
429 wl-modeline-biff-state-off
(cons extent wl-biff-nomail-glyph
)))))
431 (defun wl-make-date-string ()
432 (let ((s (current-time-string)))
433 (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]"
435 (concat (wl-match-string 1 s
) ", "
436 (timezone-make-date-arpa-standard s
(current-time-zone)))))
438 (defun wl-setup-folder ()
439 (and (featurep 'scrollbar
)
440 (set-specifier scrollbar-height
(cons (current-buffer) 0)))
441 (wl-xmas-setup-folder-toolbar))
443 (defvar dragdrop-drop-functions
)
445 (defun wl-setup-summary ()
446 (make-local-variable 'dragdrop-drop-functions
)
447 (setq dragdrop-drop-functions
'((wl-dnd-default-drop-message t t
)))
448 (and (featurep 'scrollbar
)
449 (set-specifier scrollbar-height
(cons (current-buffer) 0)))
450 (wl-xmas-setup-summary-toolbar))
452 (defalias 'wl-setup-message
'wl-xmas-setup-message-toolbar
)
454 (defun wl-message-define-keymap ()
455 (let ((keymap (make-sparse-keymap)))
456 (define-key keymap
"D" 'wl-message-delete-current-part
)
457 (define-key keymap
"l" 'wl-message-toggle-disp-summary
)
458 (define-key keymap
"\C-c:d" 'wl-message-decrypt-pgp-nonmime
)
459 (define-key keymap
"\C-c:v" 'wl-message-verify-pgp-nonmime
)
460 (define-key keymap
"w" 'wl-draft
)
461 (define-key keymap
'button4
'wl-message-wheel-down
)
462 (define-key keymap
'button5
'wl-message-wheel-up
)
463 (define-key keymap
[(shift button4
)] 'wl-message-wheel-down
)
464 (define-key keymap
[(shift button5
)] 'wl-message-wheel-up
)
465 (set-keymap-parent wl-message-button-map keymap
)
466 (define-key wl-message-button-map
'button2
467 'wl-message-button-dispatcher
)
470 (defun wl-message-wheel-up (event)
472 (if (string-match (regexp-quote wl-message-buffer-name
)
473 (regexp-quote (buffer-name)))
474 (wl-message-prev-page)
475 (let ((cur-buf (current-buffer))
477 (save-selected-window
478 (select-window (event-window event
))
480 (setq proceed
(wl-message-next-page)))
482 (if (memq 'shift
(event-modifiers event
))
484 (wl-summary-next t
))))))
486 (defun wl-message-wheel-down (event)
488 (if (string-match (regexp-quote wl-message-buffer-name
)
489 (regexp-quote (buffer-name)))
490 (wl-message-prev-page)
491 (let ((cur-buf (current-buffer))
493 (save-selected-window
494 (select-window (event-window event
))
496 (setq proceed
(wl-message-prev-page)))
498 (if (memq 'shift
(event-modifiers event
))
500 (wl-summary-prev t
))))))
502 (defun wl-draft-overload-menubar ()
503 (when (featurep 'menubar
)
504 (add-menu-item '("Mail") "Send, Keep Editing"
505 'wl-draft-send t
"Send Mail")
506 (add-menu-item '("Mail") "Send Message"
507 'wl-draft-send-and-exit t
"Send and Exit")
508 (delete-menu-item '("Mail" "Send Mail"))
509 (delete-menu-item '("Mail" "Send and Exit"))
510 (add-menu-item '("Mail") "Preview Message"
511 'wl-draft-preview-message t
"Cancel")
512 (add-menu-item '("Mail") "Save Draft and Exit"
513 'wl-draft-save-and-exit t
"Cancel")
514 (add-menu-item '("Mail") "Kill Current Draft"
515 'wl-draft-kill t
"Cancel")
516 (delete-menu-item '("Mail" "Cancel"))))
518 (defun wl-draft-mode-setup ()
520 (define-derived-mode wl-draft-mode mail-mode
"Draft"
521 "draft mode for Wanderlust derived from mail mode.
522 See info under Wanderlust for full documentation.
525 \\{wl-draft-mode-map}"))
527 (defun wl-draft-key-setup ()
528 (define-key wl-draft-mode-map
"\C-c\C-y" 'wl-draft-yank-original
)
529 (define-key wl-draft-mode-map
"\C-c\C-s" 'wl-draft-send
)
530 (define-key wl-draft-mode-map
"\C-c\C-c" 'wl-draft-send-and-exit
)
531 (define-key wl-draft-mode-map
"\C-c\C-z" 'wl-draft-save-and-exit
)
532 (define-key wl-draft-mode-map
"\C-c\C-k" 'wl-draft-kill
)
533 (define-key wl-draft-mode-map
"\C-l" 'wl-draft-highlight-and-recenter
)
534 (define-key wl-draft-mode-map
"\C-i" 'wl-complete-field-body-or-tab
)
535 (define-key wl-draft-mode-map
"\C-c\C-r" 'wl-draft-caesar-region
)
536 (define-key wl-draft-mode-map
"\M-t" 'wl-toggle-plugged
)
537 (define-key wl-draft-mode-map
"\C-c\C-o" 'wl-jump-to-draft-buffer
)
538 (define-key wl-draft-mode-map
"\C-c\C-e" 'wl-draft-config-exec
)
539 (define-key wl-draft-mode-map
"\C-c\C-j" 'wl-template-select
)
540 (define-key wl-draft-mode-map
"\C-c\C-p" 'wl-draft-preview-message
)
541 ;; (define-key wl-draft-mode-map "\C-x\C-s" 'wl-draft-save)
542 (define-key wl-draft-mode-map
"\C-c\C-a" 'wl-addrmgr
)
543 (define-key wl-draft-mode-map
"\C-xk" 'wl-draft-mimic-kill-buffer
)
544 (define-key wl-draft-mode-map
"\C-c\C-d" 'wl-draft-elide-region
)
545 (define-key wl-draft-mode-map
"\C-a" 'wl-draft-beginning-of-line
)
546 (define-key wl-draft-mode-map
"\M-p" 'wl-draft-previous-history-element
)
547 (define-key wl-draft-mode-map
"\M-n" 'wl-draft-next-history-element
))
549 (defun wl-draft-overload-functions ()
550 (wl-mode-line-buffer-identification)
551 ;; (local-set-key "\C-c\C-s" 'wl-draft-send);; override
552 (wl-xmas-setup-draft-toolbar)
553 (wl-draft-overload-menubar))
555 (defalias 'wl-defface
'defface
)
557 (defun wl-read-event-char (&optional prompt
)
558 "Get the next event."
559 (let ((event (next-command-event nil prompt
)))
561 ;; We junk all non-key events. Is this naughty?
562 (while (not (or (key-press-event-p event
)
563 (button-press-event-p event
)))
564 (dispatch-event event
)
565 (setq event
(next-command-event)))
566 (cons (and (key-press-event-p event
)
567 (event-to-character event
))
571 (product-provide (provide 'wl-xmas
) (require 'wl-version
))
573 ;;; wl-xmas.el ends here