February 13, 2008

Bulk view

BBDB: Show an address list

I sometimes feel like bringing out my stationery, my fountain pen, and a coil of stamps, and writing cards to random people in my address book. When I travel, I also enjoy writing quick postcards to people who live in the country I'm visiting. That's why I wrote this code to filter my address book so that I could see only the contacts with snail-mail addresses, or only the contacts whose snail-mail addresses match a regular expression.

You can call M-x wicked/bbdb-find-people-with-addresses to filter the displayed BBDB records. Press RET at the "Regexp: " prompt in order to show all records with addresses, or type in a regular expression that matches anything in the addresses field. By default, wicked/bbdb-find-people-with-addresses works on the BBDB records already shown in the *BBDB* window, or all records if none are shown. This allows you to successively filter BBDB records. (Combined with the other BBDB projects I'll blog about, you'll be able to get a list of all the people you haven't talked to in three months but who you've talked to within the year, who are interested in Emacs and cooking but not social networking, and who have a phone number in your contact database! How's that for targeted mail? ;) ) Anyway, if you want to start your search from scratch and you don't want to call M-x bbdb with . as the regular expression, use the universal prefix argument (C-u M-x wicked/bbdb-find-people-with-addresses) and it will search your entire contact database.

Have fun! =)

(defun wicked/bbdb-find-people-with-addresses (&optional regexp records)
  "Filter the displayed BBDB records to those with addresses."
  (interactive "MRegexp: ")
  (let ((records (if current-prefix-arg (bbdb-records)
           (or records bbdb-records (bbdb-records))))
        filtered
        cons next)
    (while records
      (when (and (bbdb-record-get-field-internal (if (arrayp (car records))
                            (car records)
                                                 (caar records)) 'address)
         (or (null regexp)
             (string= regexp "")
             (delq nil
               (mapcar
                (lambda (address)
                  (string-match regexp (wicked/bbdb-address-string address)))
                (bbdb-record-get-field-internal
                 (if (arrayp (car records))
                 (car records)
                   (caar records)) 'address)))))
        (setq filtered (cons (if (arrayp (car records))
                                 (car records)
                               (caar records)) filtered)))
      (setq records (cdr records)))
    (bbdb-display-records (nreverse filtered))))

(defun wicked/bbdb-address-string (address)
  "Return ADDRESS as a string."
  (mapconcat
   'identity
   (delq nil
         (list
          (mapconcat 'identity (bbdb-address-streets address) ", ")
          (let ((s (bbdb-address-city address))) (and (not (string= s "")) s))
      (let ((s (bbdb-address-state address))) (and (not (string= s "")) s))
      (let ((s (bbdb-address-zip address))) (and (not (string= s "")) s))
      (let ((s (bbdb-address-country address))) (and (not (string= s "")) s))))
   ", "))

(defun wicked/bbdb-yank-addresses ()
  "Copy displayed addresses to the kill ring."
  (interactive)
  (kill-new
   (mapconcat
    (lambda (record)
      (concat
       (bbdb-record-name (car record)) "\n"
       (mapconcat
    (lambda (address)
      (concat (bbdb-address-location address) ": " (wicked/bbdb-address-string address)))
    (bbdb-record-get-field-internal (car record) 'address)
    "\n")))
    bbdb-records
    "\n\n")))

Chapter 6: Being Big Brother (plan)

I haven't been writing about Emacs lately. Here's my outline so that you can help keep me honest. =) My next chapter is about the Big Brother Database (BBDB) and contact management in Emacs, which is one of the things that made people laugh when I showed my Emacs configuration at DemoCamp in Toronto. Anyway, here's what I'm planning to write about: Chapter 6: Being Big Brother (30 pages)
  • Why use Emacs to manage your contacts? What is BBDB?
  • Project xxx: Set up BBDB Project xxx: Import contacts: CSV, card Project xxx: Create a record Project xxx: Search records
  • Mail Project xxx: Integrate BBDB with Mail Project xxx: Notice e-mail changes Project xxx: Filter mail according to record Project xxx: Categorize contacts with mail aliases Project xxx: Personalize greetings Project xxx: Personalize signatures Project xxx: Mail merge Project xxx: Track last contact
  • Filtering records Project xxx: Show a phone list Project xxx: Show an address list Project xxx: Show no contact since Project xxx: Show tag queries Project xxx: Remember birthdays
  • More data Project xxx: Snarf records Project xxx: Add pictures Project xxx: Export contacts Project xxx: Synchronize contacts Project xxx: Synchronize with LinkedIn