Navigation: Table of Contents, Index, next: Oracle Performance Tuning, prev: List of Colors for Emacs, up: Emacs

BBDB Elisp Code

Overview:

Writing a .mailrc from BBDB

The following will export a very primitive version of your BBDB information into a .mailrc file which is used for normal mail(1) and Emacs Rmail.

Usually the main problem when exporting BBDB to other formats is the creation of an ALIAS name. In my example below I just use LASTNAME. The following function tries to write your BBDB into a .mailrc file, like this:

alias LASTNAME "FULL_NAME <NETADDRESS>"

mail-groups defined via the mail-alias field are not supported, but see Matt McClure's code further down the page for an example on how to do this.

I used the same code as bbdb-print for the file-name. Unfortunately this very simple code must have a bug somewhere. It only occurs if you test it a lot: When you are prompted for a file-name, "~/bbdb.tex" or "~/.mailrc" is the default. Press RET. Sometimes this will find-file the correct file, and sometimes you will overwrite your selected buffer instead. I haven't looked into this, however. :(

(defvar bbdb-mailrc-file-name ".mailrc"
  "Filename to write mail aliases to.")

(defun bbdb-write-mailrc (visible-records to-file)
  (interactive (list (bbdb-do-all-records-p)
                     (read-file-name "Export To File: " bbdb-mailrc-file-name)))
  (setq bbdb-mailrc-file-name (expand-file-name to-file))
  ;; `good' are people with netaddresses, `bad' are people without.  The
  ;; people are taken of the list records and put on either the good or
  ;; the bad list.
  (let ((good '()) (bad '())
        (records (if (not visible-records)
                     (bbdb-records)
                   (set-buffer bbdb-buffer-name)
                   (mapcar 'car bbdb-records))))
    ;; Open .mailrc file
    (find-file bbdb-mailrc-file-name)
    (widen) 
    (erase-buffer)
    ;; Loop through records to print.
    (while records
      (if (bbdb-record-net (car records))
          (setq good (cons (car records) good))
        (setq bad (cons (car records) bad)))
      (setq records (cdr records)))
    ;; write all net-addresses into .mailrc
    (insert (mapconcat (function (lambda (x)
                                   (let ((name (bbdb-dwim-net-address x))
                                         (alias (bbdb-record-lastname x)))
                                     (concat "alias "
                                             alias 
                                             " \""
                                             (if (string-match "\"\\(.*\\)\"\\(.*\\)" name)
                                                 (format "%s%s" (match-string 1 name)
                                                         (match-string 2 name))
                                               name)
                                             "\""))))
                       (nreverse good)
                       "\n"))
    ;; Mail groups

    ;;   not implemented, yet

    ;; Feedback on the output quality.
    (if bad
        (message "There were %d people with bad or missing net addresses."
                 (length bad))
      (message "Done."))))

Writing a Pine addressbook from BBDB, by Matt McClure

From: Matt McClure <matthew.mcclure.es.99@aya.yale.edu>
Subject: Re: conversion to pine addressbook?
Date: Wed, 25 Aug 1999 10:12:50 -0400 (EDT)

It isn't pretty, but this will create a pine addressbook.  
It also supports the mail-alias field (inefficiently, but it works).
I don't think it should be too difficult to modify to create mailrc
files instead.

Thanks to Alex for the start.

Matt

;;;;;

(defvar bbdb-mailrc-file-name "~/.addressbook"
  "Filename to write mail aliases to.")

(defun bbdb-write-dot-addressbook (to-file)
  (interactive (list (read-file-name "Export To File: " "" nil nil bbdb-mailrc-file-name)))
  (setq bbdb-mailrc-file-name (expand-file-name to-file))
  ;; `good' are people with netaddresses, `bad' are people without.  The
  ;; people are taken of the list records and put on either the good or
  ;; the bad list.
  (let ((good '()) (bad '())
        (records (bbdb-records))
        (grouped-good '()) (grouped-bad '())
        (grouped-records (bbdb-records))
        (mail-groups-alist '()))
    ;; Open .mailrc file
    (find-file bbdb-mailrc-file-name)
    (widen) 
    (erase-buffer)
    ;; Loop through records to print.
    (while records
      (if (bbdb-record-net (car records))
          (setq good (cons (car records) good))
        (setq bad (cons (car records) bad)))
      (setq records (cdr records)))
    ;; write all net-addresses into .mailrc
    (insert (mapconcat 
             (function (lambda (x)
                         (let ((alias (concat (bbdb-record-firstname x)
                                              " "
                                              (bbdb-record-lastname x)))
                               (name (concat (bbdb-record-lastname x)
                                             ", "
                                             (bbdb-record-firstname x)))
                               (email (car (bbdb-record-net x)))
                               )
                           (concat alias 
                                   "\t"
                                   name
                                   "\t"
                                   email
                                   )
                           )))
             (nreverse good)
             "\n"))
    ;; Mail groups
    ;; get the mail-aliases
    (while grouped-records
      (if (and
           (bbdb-record-net (car grouped-records))
           (assoc 'mail-alias (bbdb-record-raw-notes (car grouped-records))))
           (setq grouped-good (cons (car grouped-records) grouped-good))
        (setq grouped-bad (cons (car grouped-records) grouped-bad)))
      (setq grouped-records (cdr grouped-records)))

    (while grouped-good
      (let ((aliases (split-string
                      (cdr (assoc 'mail-alias 
                                  (bbdb-record-raw-notes (car grouped-good))))
                      "[, \f\t\n\r\v]+")))
        (while aliases
          ;; store the name associated with alias somehow
          (setq mail-groups-alist 
                (cons (cons (car aliases)
                            (concat "\""
                                    (bbdb-record-firstname (car grouped-good))
                                    " "
                                    (bbdb-record-lastname (car grouped-good))
                                    "\""))
                      mail-groups-alist))
          (setq aliases (cdr aliases))))
      (setq grouped-good (cdr grouped-good)))

    (setq mail-groups-alist (sort mail-groups-alist
                                  (lambda (x y)
                                    (string< (car x) (car y)))))

    ;; put each name from mail-groups-alist into the appropriate mail aliases
    (setq assn '("" . ""))
    (while mail-groups-alist
      (let ((assn-new (car mail-groups-alist)))
        (if (string= (car assn) "")
            (insert (concat "\n" (car assn-new) "\t\t("))
          (if (not (string= (car assn) (car assn-new)))
              (insert (concat ")\n" (car assn-new) "\t\t("))))
        (insert (concat (cdr assn-new) ","))
        (setq mail-groups-alist (cdr mail-groups-alist))
        (setq assn assn-new)))

    (if (not (string= (car assn) ""))
        (insert ")\n"))
    
    ;; Feedback on the output quality.
    (if bad
        (message "There were %d people with bad or missing net addresses."
                 (length bad))
      (message "Done."))))

Editing and formatting addresses with newer version of the BBDB

If you are using version of BBDB greater than 2.00.06, you might want to use a different address editing function or add new address formating functions. The following shows you how to go about doing that.

A new address editing function with German prompts

You can only have one active input function at the time. The name of the active input function is stored in the variable `bbdb-address-editing-function'. Therefore, you will have to write a new address editing function and you will have to set `bbdb-address-editing-function'.

The easiest way to go about this, is using paste and copy: use `bbdb-address-edit-default' as a starting point.

(defun bbdb-address-edit-continental-german (addr)
  "Function to use for address editing.  
The sub-fields are queried using the continental order and using German
prompts.  This is an alternate value for `bbdb-address-editing-function'.
It is used by German speaking users.

The sub-fields and the prompts used are:
Strasse, Zeile 1: street1  
Strasse, Zeile 2: street2
Strasse, Zeile 3: street3
PLZ:              zip
Stadt:            city
Region/Staat:     state
Land:             country"
  (let* ((str (let ((l) (s) (n 0))
                (while (not (string= "" (setq s (bbdb-read-string
                                                 (format "Strasse, Zeile %d: " (+ 1 n))
                                                 (nth n (bbdb-address-streets addr))))))
                  (setq l (append l (list s)))
                  (setq n (1+ n)))
                l))
         (zip (bbdb-error-retry
               (bbdb-parse-zip-string
                (bbdb-read-string "PLZ: " (bbdb-address-zip-string addr)))))
         (cty (bbdb-read-string "Stadt: " (bbdb-address-city addr)))
         (ste (bbdb-read-string "Region/Staat: " (bbdb-address-state addr)))
         (country (bbdb-read-string "Land: " (bbdb-address-country addr))))
    (bbdb-address-set-streets addr str)
    (bbdb-address-set-city addr cty)
    (bbdb-address-set-state addr ste)
    (bbdb-address-set-zip addr zip)
    (bbdb-address-set-country addr country)
    nil))

(setq bbdb-address-editing-function 'bbdb-address-edit-continental-german)
; (setq bbdb-address-editing-function 'bbdb-address-edit-default)

Adding a new formatting function for Japanese addresses

You will have to add a new entry to `bbdb-address-formatting-alist'. The new entry must be a cons cell consisting of an identifying function and a formatting function.

I'll use a Japanese format as an example. Please note that I don't really know how Japanese mail is formatted in Japan. The following reflects international standards for mail from outside Japan being sent to a Japanese address.

First we'll start by adding the identifying function and the formatting function to `bbdb-address-formatting-alist'. This will controll address formatting in the *BBDB* buffer.

(add-to-list 'bbdb-address-formatting-alist 
             '(bbdb-address-is-japanese . bbdb-format-address-japanese))

The identifying function for Japanese addresses

The function can do any testing it likes with the address received. In this case we just test for the country name "Japan".

(defun bbdb-address-is-japanese (addr)
  "Return non-nil if the address ADDR is a japanese address.

This is a possible identifying function for
`bbdb-address-formatting-alist' and
`bbdb-address-print-formatting-alist'."
  (string= (upcase (bbdb-address-country addr)) "JAPAN"))

Instead of checking for the string JAPAN, you might as well check for the Kanji used in Japanese.

The formatting function for Japanese addresses

Another paste and copy event: use `bbdb-format-address-default' as a starting point.

(defun bbdb-format-address-japanese (addr)
  "Insert formated Japanese address ADDR in current buffer.

This is what it looks like:
       location: street1
                 street2
                 street3
                 city
                 state
                 zip country"
  (insert (format " %14s: " (bbdb-address-location addr)))
  (bbdb-format-streets addr)
  (let ((c (bbdb-address-city addr))
        (s (bbdb-address-state addr))
        (z (bbdb-address-zip-string addr))
        (y (bbdb-address-country addr)))
    (if (or (> (length c) 0)
            (> (length s) 0)
            (> (length z) 0)
            (> (length y) 0))
        (progn
          (if (> (length c) 0)
              (progn
                (indent-to 17)
                (insert c "\n")))
          (if (> (length s) 0)
              (progn
                (indent-to 17)
                (insert s "\n")))
          (if (or (> (length z) 0)
                  (> (length y) 0))
              (progn
                (indent-to 17)
                (if (> (length z) 0)
                    (insert z (if (> (length y) 0) " " "")))
                (if (> (length y) 0)
                    (insert y))
                (insert "\n" "")))))))

Print formatting of Japanese addresses

In order to set the variable bbdb-address-formatting-alist, you will have to load the library bbdb-print. This is what I have at the beginning of my BBDB code:

(load-library "bbdb")
(load-library "bbdb-print")

The printing of addresses works just like the example above. Instead of adding the identifying and formatting functions to `bbdb-address-formatting-alist', you add the two functions to `bbdb-address-print-formatting-alist'. You can use the same identifying function that you used in `bbdb-address-formatting-alist'. The only thing you will have to code up is a print formatting function. It will be very similar to the normal formatting function. Use `bbdb-print-format-address-default' as a starting point. The details are left as an exercise to the reader.

Just kidding. Here is the code:

(add-to-list 'bbdb-address-print-formatting-alist
             '(bbdb-address-is-japanese . bbdb-print-format-address-japanese))

(defun bbdb-print-format-address-japanese (addr)
  "Insert formated address ADDR in current buffer for printing.

This function is a possible formatting function for
`bbdb-address-print-formatting-alist'.

The result looks like this:
                 street
                 street
                 ...
                 city
                 state
                 zip country"
  (insert
   (format 
    "\\address{%s}\n"
    (bbdb-print-tex-quote 
     (if addr
         (concat 
          (mapconcat (function (lambda(str) 
                                 (if (= 0 (length (bbdb-string-trim str)))
                                     ()
                                   (concat str "\\\\\n"))))
                     (bbdb-address-streets addr)
                     "")
          (bbdb-print-if-not-blank (bbdb-address-city addr) "\\\\\n")
          (bbdb-print-if-not-blank (bbdb-address-state addr) "\\\\\n")
          (bbdb-print-if-not-blank
           (let ((z (bbdb-address-zip-string addr))
                 (y (bbdb-address-country addr)))
             (if (or (> (length z) 0)
                     (> (length y) 0))
                 (concat z 
                         (if (and (> (length z) 0)
                                  (> (length y) 0))
                             " ")
                         y))) "\\\\\n"))
       "")))))

Navigation: Top, Table of Contents, Index, next: Oracle Performance Tuning, prev: List of Colors for Emacs, up: Emacs


http://www.geocities.com/kensanata/bbdb-funcs.html / Alex Schroeder <kensanata@yahoo.com> / updated: 2001-02-24 / significant changes: 2000-10-30

1