;;;; -*- emacs-lisp -*-
;;;; bbdb-ipod.el
;;;;
;;;; COPYRIGHT (C) 2002 Edward Marco Baringer
;;;; This code is in the public domain.
;;;;
;;;; sync bbdb database to iPod (version 1.1 or higher)

(require 'bbdb)

(defun bbdb-to-ipod (ipod-contacts-dir)
  "Writes your bbdb database to you iPod. the IPOD-CONTACTS-DIR is the
Contacts directory of the iPod partition. on OSX it should be
something like /Volumes/<ipod name>/Contacts"
  (interactive "DIpod Contacts directory: ")
  (dolist (record (bbdb-records))
    (with-temp-buffer
      (insert (bbdb-record->vcard-string record))
      (write-file (concat ipod-contacts-dir "/"
                          (bbdb-record-firstname record) " "
                          (bbdb-record-lastname record) ".vcf")
                  nil))))

(defun bbdb-flatten-concat (&rest things)
  (let ((ret ""))
    (dolist (thing things ret)
      (setq ret (concat ret (if (listp thing)
                                (apply 'bbdb-flatten-concat thing)
                              thing))))))

(defun bbdb-record->vcard-string (record)
  "Given a bbdb record convert it a string following (to the best of
my knowledge) the vcard standard. telephone location names are
converted to lower case. (ipod note: you need to use 'home' and 'cell'
for telephone locations)"
  (let ((first-name (bbdb-record-firstname record))
        (last-name (bbdb-record-lastname record))
        (aka (bbdb-record-aka record))
        (company (bbdb-record-company record))
        (phones (bbdb-record-phones record))
        (addresses (bbdb-record-addresses record))
        (net (bbdb-record-net record))
        (notes (bbdb-record-notes record)))
    (bbdb-flatten-concat
     ;; general header stuff
     "begin:vCard\n"
     "version:2.1\n"
     ;; FN and N fields. These two fields seem to have the same
     ;; purpose, all i can figure out (and all i really care about)
     ;; is that this make the iPod happy
     "fn:" first-name " " last-name "\n"
     "n:" last-name ";" first-name "\n"
     ;; bbdb doesn't know about titles, so we don't put any in
     ;; only put in a org field if the bbdb record has a company value
     (when company
       (list "org:" company "\n"))
     ;; telephones
     (mapcar (lambda (phone)
               (list "tel;type=" (downcase (bbdb-phone-location phone)) ":" (bbdb-phone-string phone) "\n"))
             phones)
     ;; addresses
     (mapcar (lambda (address)               
               (let ((location (bbdb-address-location address))
                     (streets (bbdb-address-streets address))
                     (city (bbdb-address-city address))
                     (zip (bbdb-address-zip address))
                     (state (bbdb-address-state address))
                     (country (bbdb-address-country address)))
                 (list "adr;type=" location ":"                       
                       ;; street 1
                       (car streets) ";"
                       ;; street 2
                       (car (cdr streets)) ";"
                       ;; city
                       city ";"
                       ;; state
                       state ";"
                       ;; zip
                       zip ";"
                       ;; country
                       country
                       "\n")))
             addresses)
     ;; net (emails)
     (mapcar (lambda (net)
               (list "email:" net "\n"))
             (bbdb-record-net record))
     ;; notes
     (when notes
       (list "note:" notes "\n"))
     "end:vcard\n")))
