summaryrefslogtreecommitdiff
path: root/lisp/net/eudcb-bbdb.el
diff options
context:
space:
mode:
authorGerd Moellmann <gerd@gnu.org>2000-01-12 20:50:20 +0000
committerGerd Moellmann <gerd@gnu.org>2000-01-12 20:50:20 +0000
commitfc0a70695c48fd5129c3958fe26ff9a94e766eba (patch)
tree0600e70817d5f7a490f381dd514f4e68a93e2eca /lisp/net/eudcb-bbdb.el
parent60dca34390c119193f31fab4758359f91a0066c2 (diff)
downloademacs-fc0a70695c48fd5129c3958fe26ff9a94e766eba.tar.gz
*** empty log message ***
Diffstat (limited to 'lisp/net/eudcb-bbdb.el')
-rw-r--r--lisp/net/eudcb-bbdb.el234
1 files changed, 234 insertions, 0 deletions
diff --git a/lisp/net/eudcb-bbdb.el b/lisp/net/eudcb-bbdb.el
new file mode 100644
index 00000000000..a7441c2c295
--- /dev/null
+++ b/lisp/net/eudcb-bbdb.el
@@ -0,0 +1,234 @@
+;;; eudcb-bbdb.el --- Emacs Unified Directory Client - BBDB Backend
+
+;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+;; Author: Oscar Figueiredo <oscar@xemacs.org>
+;; Maintainer: Oscar Figueiredo <oscar@xemacs.org>
+;; Keywords: help
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+;; This library provides an interface to use BBDB as a backend of
+;; the Emacs Unified Directory Client.
+
+;;; Code:
+
+(require 'eudc)
+(if (not (featurep 'bbdb))
+ (load-library "bbdb"))
+(if (not (featurep 'bbdb-com))
+ (load-library "bbdb-com"))
+
+;;{{{ Internal cooking
+
+;; I don't like this but mapcar does not accept a parameter to the function and
+;; I don't want to use mapcar*
+(defvar eudc-bbdb-current-query nil)
+(defvar eudc-bbdb-current-return-attributes nil)
+
+(defvar eudc-bbdb-attributes-translation-alist
+ '((name . lastname)
+ (email . net)
+ (phone . phones))
+ "Alist mapping EUDC attribute names to BBDB names.")
+
+(eudc-protocol-set 'eudc-query-function 'eudc-bbdb-query-internal 'bbdb)
+(eudc-protocol-set 'eudc-list-attributes-function nil 'bbdb)
+(eudc-protocol-set 'eudc-protocol-attributes-translation-alist
+ 'eudc-bbdb-attributes-translation-alist 'bbdb)
+(eudc-protocol-set 'eudc-bbdb-conversion-alist nil 'bbdb)
+(eudc-protocol-set 'eudc-protocol-has-default-query-attributes nil 'bbdb)
+
+(defun eudc-bbdb-format-query (query)
+ "Format a EUDC query alist into a list suitable to `bbdb-search'."
+ (let* ((firstname (cdr (assq 'firstname query)))
+ (lastname (cdr (assq 'lastname query)))
+ (name (or (and firstname lastname
+ (concat firstname " " lastname))
+ firstname
+ lastname))
+ (company (cdr (assq 'company query)))
+ (net (cdr (assq 'net query)))
+ (notes (cdr (assq 'notes query)))
+ (phone (cdr (assq 'phone query))))
+ (list name company net notes phone)))
+
+
+(defun eudc-bbdb-filter-non-matching-record (record)
+ "Return RECORD if it matches `eudc-bbdb-current-query', nil otherwise."
+ (catch 'unmatch
+ (progn
+ (mapcar
+ (function
+ (lambda (condition)
+ (let ((attr (car condition))
+ (val (cdr condition))
+ (case-fold-search t)
+ bbdb-val)
+ (or (and (memq attr '(firstname lastname aka company phones addresses net))
+ (progn
+ (setq bbdb-val
+ (eval (list (intern (concat "bbdb-record-"
+ (symbol-name attr)))
+ 'record)))
+ (if (listp bbdb-val)
+ (if eudc-bbdb-enable-substring-matches
+ (eval `(or ,@(mapcar '(lambda (subval)
+ (string-match val
+ subval))
+ bbdb-val)))
+ (member (downcase val)
+ (mapcar 'downcase bbdb-val)))
+ (if eudc-bbdb-enable-substring-matches
+ (string-match val bbdb-val)
+ (string-equal (downcase val) (downcase bbdb-val))))))
+ (throw 'unmatch nil)))))
+ eudc-bbdb-current-query)
+ record)))
+
+(defun eudc-bbdb-extract-phones (record)
+ (mapcar (function
+ (lambda (phone)
+ (if eudc-bbdb-use-locations-as-attribute-names
+ (cons (intern (bbdb-phone-location phone))
+ (bbdb-phone-string phone))
+ (cons 'phones (format "%s: %s"
+ (bbdb-phone-location phone)
+ (bbdb-phone-string phone))))))
+ (bbdb-record-phones record)))
+
+(defun eudc-bbdb-extract-addresses (record)
+ (let (s c val)
+ (mapcar (function
+ (lambda (address)
+ (setq val (concat (unless (= 0 (length (setq s (bbdb-address-street1 address))))
+ (concat s "\n"))
+ (unless (= 0 (length (setq s (bbdb-address-street2 address))))
+ (concat s "\n"))
+ (unless (= 0 (length (setq s (bbdb-address-street3 address))))
+ (concat s "\n"))
+ (progn
+ (setq c (bbdb-address-city address))
+ (setq s (bbdb-address-state address))
+ (if (and (> (length c) 0) (> (length s) 0))
+ (concat c ", " s " ")
+ (concat c " ")))
+ (bbdb-address-zip-string address)))
+ (if eudc-bbdb-use-locations-as-attribute-names
+ (cons (intern (bbdb-address-location address)) val)
+ (cons 'addresses (concat (bbdb-address-location address) "\n" val)))))
+ (bbdb-record-addresses record))))
+
+(defun eudc-bbdb-format-record-as-result (record)
+ "Format the BBDB RECORD as a EUDC query result record.
+The record is filtered according to `eudc-bbdb-current-return-attributes'"
+ (let ((attrs (or eudc-bbdb-current-return-attributes
+ '(firstname lastname aka company phones addresses net notes)))
+ attr
+ eudc-rec
+ val)
+ (while (prog1
+ (setq attr (car attrs))
+ (setq attrs (cdr attrs)))
+ (cond
+ ((eq attr 'phones)
+ (setq val (eudc-bbdb-extract-phones record)))
+ ((eq attr 'addresses)
+ (setq val (eudc-bbdb-extract-addresses record)))
+ ((memq attr '(firstname lastname aka company net notes))
+ (setq val (eval
+ (list (intern
+ (concat "bbdb-record-"
+ (symbol-name attr)))
+ 'record))))
+ (t
+ (setq val "Unknown BBDB attribute")))
+ (if val
+ (cond
+ ((memq attr '(phones addresses))
+ (setq eudc-rec (append val eudc-rec)))
+ ((and (listp val)
+ (= 1 (length val)))
+ (setq eudc-rec (cons (cons attr (car val)) eudc-rec)))
+ ((> (length val) 0)
+ (setq eudc-rec (cons (cons attr val) eudc-rec)))
+ (t
+ (error "Unexpected attribute value")))))
+ (nreverse eudc-rec)))
+
+
+
+(defun eudc-bbdb-query-internal (query &optional return-attrs)
+ "Query BBDB with QUERY.
+QUERY is a list of cons cells (ATTR . VALUE) where ATTRs should be valid
+BBDB attribute names.
+RETURN-ATTRS is a list of attributes to return, defaulting to
+`eudc-default-return-attributes'."
+
+ (let ((eudc-bbdb-current-query query)
+ (eudc-bbdb-current-return-attributes return-attrs)
+ (query-attrs (eudc-bbdb-format-query query))
+ bbdb-attrs
+ (records (bbdb-records))
+ result
+ filtered)
+ ;; BBDB ORs its query attributes while EUDC ANDs them, hence we need to
+ ;; call bbdb-search iteratively on the returned records for each of the
+ ;; requested attributes
+ (while (and records (> (length query-attrs) 0))
+ (setq bbdb-attrs (append bbdb-attrs (list (car query-attrs))))
+ (if (car query-attrs)
+ (setq records (eval `(bbdb-search ,(quote records) ,@bbdb-attrs))))
+ (setq query-attrs (cdr query-attrs)))
+ (mapcar (function
+ (lambda (record)
+ (setq filtered (eudc-filter-duplicate-attributes record))
+ ;; If there were duplicate attributes reverse the order of the
+ ;; record so the unique attributes appear first
+ (if (> (length filtered) 1)
+ (setq filtered (mapcar (function
+ (lambda (rec)
+ (reverse rec)))
+ filtered)))
+ (setq result (append result filtered))))
+ (delq nil
+ (mapcar 'eudc-bbdb-format-record-as-result
+ (delq nil
+ (mapcar 'eudc-bbdb-filter-non-matching-record
+ records)))))
+ result))
+
+;;}}}
+
+;;{{{ High-level interfaces (interactive functions)
+
+(defun eudc-bbdb-set-server (dummy)
+ "Set the EUDC server to BBDB."
+ (interactive)
+ (eudc-set-server dummy 'bbdb)
+ (message "BBDB server selected"))
+
+;;;}}}
+
+
+(eudc-register-protocol 'bbdb)
+
+(provide 'eudcb-bbdb)
+
+;;; eudcb-bbdb.el ends here