1 ;;; -*- Mode:Emacs-Lisp -*-
3 ;;; This file is part of the Insidious Big Brother Database (aka BBDB),
4 ;;; copyright (c) 1991 Todd Kaufmann <toad@cs.cmu.edu>
5 ;;; Interface to mh-e version 3.7 or later (modeled after bbdb-rmail).
7 ;;; Modified: 28-Jul-94 by Fritz Knabe <knabe@ecrc.de>
8 ;;; Jack Repenning <jackr@dblues.wpd.sgi.com>
10 ;;; The Insidious Big Brother Database is free software; you can redistribute
11 ;;; it and/or modify it under the terms of the GNU General Public License as
12 ;;; published by the Free Software Foundation; either version 1, or (at your
13 ;;; option) any later version.
15 ;;; BBDB is distributed in the hope that it will be useful, but WITHOUT ANY
16 ;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 ;;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with GNU Emacs; see the file COPYING. If not, write to
22 ;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25 ;; $Id: bbdb-mhe.el,v 1.6 2007-02-23 20:24:07 fenk Exp $
32 ;; We advise several mh-e functions
34 (if (fboundp 'mh-version)
35 (require 'mh-comp)) ; For mh-e 4.x
38 (defmacro bbdb/mh-cache-key (message)
39 "Return a (numeric) key for MESSAGE"
40 (`(let* ((attrs (file-attributes (, message)))
41 (status-time (nth 6 attrs))
42 (status-time-2 (cdr status-time))
43 (inode (nth 10 attrs)))
44 (logxor (if (integerp inode) ;; if inode is larger than an emacs int,
45 inode ;; it's returned as a dotted pair
48 ;; We need the following test because XEmacs returns the
49 ;; status time as a dotted pair, whereas FSF and Epoch
51 (if (integerp status-time-2)
53 (car status-time-2))))))
56 (defun bbdb/mh-update-record (&optional offer-to-create)
57 "Returns the record corresponding to the current MH message, creating or
58 modifying it as necessary. A record will be created if
59 bbdb/mail-auto-create-p is non-nil, or if OFFER-TO-CREATE is true and
60 the user confirms the creation."
62 (and mh-show-buffer (set-buffer mh-show-buffer))
64 (bbdb/mh-pop-up-bbdb-buffer offer-to-create)
65 (let ((msg (bbdb/mh-cache-key buffer-file-name))
67 (if (eq msg 0) (setq msg nil)) ; 0 could mean trouble; be safe.
68 (setq records (bbdb-message-cache-lookup msg))
71 (let ((from (bbdb/mh-get-field "^From[ \t]*:")))
72 (if (or (string= "" from)
73 (string-match (bbdb-user-mail-names)
74 (mail-strip-quoted-names from)))
75 ;; if logged-in user sent this, use recipients.
77 (setq from (bbdb/mh-get-field "^To[ \t]*:"))
78 (if (or (string= "" from)
79 (string-match (bbdb-user-mail-names)
80 (mail-strip-quoted-names from)))
84 (bbdb-annotate-message-sender
86 (or (bbdb-invoke-hook-for-value bbdb/mail-auto-create-p)
88 ;; ugh. what the hell?
90 (bbdb-invoke-hook-for-value bbdb/mail-auto-create-p)))))
91 (if (and msg record) (bbdb-encache-message msg (list record)))
96 (defun bbdb/mh-annotate-sender (string &optional replace)
97 "Add a line to the end of the Notes field of the BBDB record
98 corresponding to the sender of this message. If REPLACE is non-nil,
99 replace the existing notes entry (if any)."
100 (interactive (list (if bbdb-readonly-p
101 (error "The Insidious Big Brother Database is read-only.")
102 (read-string "Comments: "))))
104 (let ((b (current-buffer))
106 (set-buffer mh-show-buffer)
107 (bbdb-annotate-notes (bbdb/mh-update-record t) string 'notes replace)
112 (defun bbdb/mh-edit-notes (&optional arg)
113 "Edit the notes field or (with a prefix arg) a user-defined field
114 of the BBDB record corresponding to the sender of this message."
117 (let ((b (current-buffer))
119 (set-buffer mh-show-buffer)
120 (let (bbdb-electric-p (record (or (bbdb/mh-update-record t) (error ""))))
121 (bbdb-display-records (list record))
123 (bbdb-record-edit-property record nil t)
124 (bbdb-record-edit-notes record t)))
130 (defun bbdb/mh-show-sender ()
131 "Display the contents of the BBDB for the sender of this message.
132 This buffer will be in bbdb-mode, with associated keybindings."
135 (let ((b (current-buffer))
137 (set-buffer mh-show-buffer)
138 (let ((record (bbdb/mh-update-record t)))
140 (bbdb-display-records (list record))
146 (defun bbdb/mh-pop-up-bbdb-buffer (&optional offer-to-create)
147 "Make the *BBDB* buffer be displayed along with the MH window,
148 displaying the record corresponding to the sender of the current message."
149 (bbdb-pop-up-bbdb-buffer
150 (function (lambda (w)
151 (let ((b (current-buffer)))
152 (set-buffer (window-buffer w))
153 (prog1 (eq major-mode 'mh-folder-mode)
155 (let ((bbdb-gag-messages t)
156 (bbdb-use-pop-up nil)
157 (bbdb-electric-p nil))
158 (let ((record (bbdb/mh-update-record offer-to-create)))
159 (bbdb-display-records (if record (list record) nil)
160 bbdb-pop-up-display-layout)
164 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
165 ;; this is a more strict version of mh-get-field which takes an regexp
167 (defun bbdb/mh-get-field (field)
168 ;; Find and return the value of field FIELD (regexp) in the current buffer.
169 ;; Returns the empty string if the field is not in the message.
170 (let ((case-fold-search nil))
171 (goto-char (point-min))
172 (cond ((not (re-search-forward field nil t)) "")
173 ((looking-at "[\t ]*$") "")
174 (t (re-search-forward "[\t ]*\\([^\t \n].*\\)$" nil t)
175 (let ((field (buffer-substring (match-beginning 1) (match-end 1)))
176 (end-of-match (point)))
178 (while (looking-at "[ \t]") (forward-line 1))
180 (if (<= (point) end-of-match)
183 (buffer-substring end-of-match (point)))))))))
185 (defadvice mh-process-commands (after mh-bbdb-process act)
188 (defadvice mh-send (before mh-bbdb-send act)
190 (bbdb-read-addresses-with-completion "To: ")
191 (bbdb-read-addresses-with-completion "Cc: ")
192 (read-string "Subject: "))))
194 (defadvice mh-send-other-window (before mh-bbdb-send-other act)
196 (bbdb-read-addresses-with-completion "To: ")
197 (bbdb-read-addresses-with-completion "Cc: ")
198 (read-string "Subject: "))))
200 (defadvice mh-forward (before mh-bbdb-forward act)
201 (interactive (list (bbdb-read-addresses-with-completion "To: ")
202 (bbdb-read-addresses-with-completion "Cc: ")
203 (if current-prefix-arg
204 (mh-read-seq-default "Forward" t)
205 (mh-get-msg-num t)))))
207 (defadvice mh-redistribute (before mh-bbdb-redist act)
209 (bbdb-read-addresses-with-completion "Redist-To: ")
210 (bbdb-read-addresses-with-completion "Redist-Cc: ")
211 (mh-get-msg-num t))))
213 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
214 ;; mail from bbdb-mode using mh
216 ;; these redefine the bbdb-send-mail functions to use mh-send.
218 ;;; Install bbdb into mh-e's show-message function
221 (defun bbdb-insinuate-mh ()
222 "Call this function to hook BBDB into MH-E."
223 (define-key mh-folder-mode-map ":" 'bbdb/mh-show-sender)
224 (define-key mh-folder-mode-map ";" 'bbdb/mh-edit-notes)
225 (define-key mh-letter-mode-map "\M-;" 'bbdb-complete-name)
226 (add-hook 'mh-show-hook 'bbdb/mh-update-record)
227 (define-key mh-letter-mode-map "\e\t" 'bbdb-complete-name))