Category Archives: bbdb

BBDB pinging code

I love tweaking Emacs to fit the way I work. Here's some code to make it easier to keep track of pinged people.

(defun sacha/bbdb-ping-bbdb-record (bbdb-record text &optional date regrind)
  "Adds a note for today to the current BBDB record.
Call with a prefix to specify date."
  (interactive (list (bbdb-current-record t)
                     (read-string "Notes: ")
                     (if current-prefix-arg (planner-read-date) (planner-today))
  (bbdb-record-set-notes bbdb-record (concat date ": " text "\n" (bbdb-record-notes bbdb-record)))
  (if regrind
        (set-buffer bbdb-buffer-name)
        (bbdb-redisplay-one-record bbdb-record)))

(defun sacha/bbdb-gnus-ping (text)
  "Add a ping for authors/recipients of this message.
Call with a prefix to specify a manual note."
  (interactive (list (if current-prefix-arg (read-string "Notes: "))))
  (let* ((from-me-p
          (string-match gnus-ignored-from-addresses
                        (message-fetch-field "From")))
         (bbdb-get-only-first-address-p nil)
          (list (assoc (if from-me-p 'recipients 'authors) bbdb-get-addresses-headers)))
         (bbdb/gnus-update-records-mode 'annotating)
         (bbdb-message-cache nil)
         (bbdb-user-mail-names nil)
         (gnus-ignored-from-addresses nil)
    (setq records (bbdb/gnus-update-records t))
    (if records
        (bbdb-display-records records)
    (while records
       (car records)
        (if from-me-p "-> " "<- ")
        (or text (message-fetch-field "Subject")))
        (date-to-time (message-fetch-field "Date"))))
      (setq records (cdr records)))
    (setq records (bbdb/gnus-update-records t))
    (if records
        (bbdb-display-records records)

On Technorati: , ,


Random Japanese sentence: 猫がソファの上に寝ている。 A cat is lying on the sofa.

Emacs: Keep track of messages sent

Because a Big Brother Database of my contacts isn't complete if I don't keep track of what e-mail I sent them and when I sent it, this bit of Emacs Lisp code adds Gnus subjects to the BBDB records of the people to whom I sent e-mail.

(defun sacha/gnus-add-subject-to-bbdb-record ()
  "Add datestamped subject note for each person this message has been sent to."
  (let* ((subject (concat (planner-today)
                          ": E-mail: " (message-fetch-field "Subject") "\n"))
          (list (assoc 'recipients bbdb-get-addresses-headers)))
    (setq records
           (bbdb-get-addresses nil gnus-ignored-from-addresses 'gnus-fetch-field)
           nil nil))
    (mapc (lambda (rec)
            (bbdb-record-set-notes rec
                                   (concat subject
                                           (bbdb-record-notes rec))))
(add-hook 'message-send-hook 'sacha/gnus-add-subject-to-bbdb-record)

It should be really easy to set up Gnus to expand some kind of !followup macro into a TODO item in my planner and an "I hope to hear from you by ....". Ridiculously easy with Emacs Lisp and an insanely customizable editor, but I might not have enough battery life. I've got 28 minutes, and then I'm off PC for a while.

On Technorati: , , , ,


More Emacs coolness: List of contacts

This bit of Emacs Lisp code produces a Planner-ready list of the contacts displayed in the BBDB window.

(defun sacha/planner-bbdb-annotation-from-bbdb (&optional record)
  "If called from a bbdb buffer, return an annotation.
Suitable for use in `planner-annotation-functions'."
  (when (or record (eq major-mode 'bbdb-mode))
    (setq record (if record (car record) (bbdb-current-record)))
    (or (bbdb-record-getprop record 'plan)
        ;; From a BBDB entry with a plan page; use that. Yay!
         (concat "bbdb://"
                    " " "." (bbdb-record-name record)))
         (bbdb-record-name record)))))
(defalias 'planner-bbdb-annotation-from-bbdb 'sacha/planner-bbdb-annotation-from-bbdb)

(defun sacha/yank-planner-bbdb-list ()
  "Copy the list of people displayed in the buffer."
   (mapconcat 'sacha/planner-bbdb-annotation-from-bbdb
              ", "))
        (sacha/planner-bbdb-annotation-from-bbdb rec))

It allows me to say, for example, that I met 23 people yesterday: Bruce, Daniel Charles, Shane D'Costa, Emily, Greg A. Fitz, Clara Fong, Jay Goldman, Harvey, Kai Fai Ho, Iris, KC, Charles McCulloch, Jamie McQuay, Joshua Meles, Naomi, Helen Overland, Wayne Penney, Simon Rowland, San, Colin Smillie, Solomon, Le Quan Truong, Perry Wong

On Technorati: , , , ,

More Emacs fun: Composing mail to everyone with notes

(defun sacha/compose-mail-to-everyone (&optional subject)
  (mapc (lambda (rec)
          (setq rec (car rec))
          (when (bbdb-record-net rec)
            (bbdb-send-mail rec subject)
              (forward-line -2)
              (insert "\n---- NOTES ---\n" (bbdb-record-notes rec) "\n"))))

(defun sacha/gnus-delete-notes ()
  (goto-char (point-min))
  (when (re-search-forward "^--- NOTES ---" nil t)
    (goto-char (match-beginning 0))
(add-hook 'message-send-hook 'sacha/gnus-delete-notes)

On Technorati: , , , , ,

More Emacs goodness: Refresh your memory when you e-mail using notes from BBDB

Inspired by an e-mail-based customer relationship management system briefly described by Daniel Charles of digital ketchup at Shoeless Joe's last Friday, I decided to hack together a system that would allow me to see the notes from my contact database (aptly named the Big Brother Database, or BBDB) when I write e-mail using the Gnus mail client in Emacs.

The first thing I needed to build, of course, was something that removed my notes from outgoing messages. People really don't need to see the kinds of notes I keep on them. ;) Well, they're fairly innocuous notes: how we met and what they're interested in, usually, although sometimes I'll have notes on people's food preferences or shoe sizes. I've recently started keeping track of the subjects of e-mail I send them, too.

(defun sacha/gnus-remove-notes ()
  "Remove everything from --- NOTES --- to the signature."
  (goto-char (point-min))
  (when (re-search-forward "^--- NOTES ---" nil t)
    (let ((start (match-beginning 0))
          (end (and (re-search-forward "^--- END NOTES ---") (match-end 0))))
      (delete-region start end))))
(add-hook 'message-send-hook 'sacha/gnus-remove-notes)

Then it was easy to write another function that composed individual messages to all the people currently displayed in the BBDB buffer, adding notes to each message.

(defun sacha/gnus-send-message-to-all (subject)
  "Compose message to everyone, with notes."
  (interactive "MSubject: ")
  (let ((records bbdb-records))
    (while records
      (when (bbdb-record-net (caar records))
        (bbdb-send-mail (caar records) subject)
        (when (bbdb-record-notes (caar records))
            (insert "\n--- NOTES ---\n"
                    (bbdb-record-notes (caar records))
                    "\n--- END NOTES ---\n"))))
      (setq records (cdr records)))))

I use BBDB to display only the people I want to e-mail, then I call M-x sacha/gnus-send-message-to-all and specify a message subject. This creates a gazillion message buffers which I can then edit. If I feel particularly paranoid, I can remove the notes section myself with C-c C-z (message-kill-to-signature), but sacha/gnus-remove-notes does it as long as it's in message-send-hook.

This code works particularly well with these other customizations:

It supersedes More Emacs fun: Composing mail to everyone with notes.

On Technorati: , , , , ,


Emacs: Show only people whom I haven’t pinged since…

One of the things I want in a contact management system is a quick way to find out who I haven't pinged in a while. The following code filters currently-displayed contacts to show who I might want to get back in touch with. Call it from a *BBDB* window and specify the date (could be 2006.01.01 for annual, -7 for the last seven days, etc.). This works incredibly well with the following hacks:

I should write a small book about how to build a contact management system with Emacs. ;) It's insanely powerful, you know.

(require 'planner)
(require 'bbdb)
(defun sacha/bbdb-show-only-no-contact-since (date)
  "Show only people who haven't been pinged since DATE or at all."
  (interactive (list (planner-read-date)))
  (let ((records bbdb-records)
    (while records
      ;; Find the latest date mentioned in the entry
      (setq notes (or (bbdb-record-notes (caar records)) ""))
      (setq last-match nil omit nil)
      (while (string-match
              (or last-match 0))
        (unless (string> date (match-string 0 notes))
          (setq omit t)
          (setq last-match (length notes)))
        (setq last-match (match-end 0)))
      (unless (and last-match omit)
        (add-to-list 'new-records (caar records) t))
      (setq records (cdr records)))
    (bbdb-display-records new-records)))

One of the other things I'd like to smooth over is keeping track of who owes whom e-mail... <laugh>

On Technorati: , , , , , ,