Merge from origin/emacs-24
[emacs.git] / lisp / net / eudcb-ldap.el
blob1d426a7b7b04fb5db2941fdaa4f7e18ec62f040f
1 ;;; eudcb-ldap.el --- Emacs Unified Directory Client - LDAP Backend -*- coding: utf-8 -*-
3 ;; Copyright (C) 1998-2015 Free Software Foundation, Inc.
5 ;; Author: Oscar Figueiredo <oscar@cpe.fr>
6 ;; Pavel Janík <Pavel@Janik.cz>
7 ;; Maintainer: Thomas Fitzsimmons <fitzsim@fitzsim.org>
8 ;; Keywords: comm
9 ;; Package: eudc
11 ;; This file is part of GNU Emacs.
13 ;; GNU Emacs is free software: you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation, either version 3 of the License, or
16 ;; (at your option) any later version.
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
26 ;;; Commentary:
27 ;; This library provides specific LDAP protocol support for the
28 ;; Emacs Unified Directory Client package
30 ;;; Installation:
31 ;; Install EUDC first. See EUDC documentation.
33 ;;; Code:
35 (require 'eudc)
36 (require 'ldap)
39 ;;{{{ Internal cooking
41 (eval-and-compile
42 (if (fboundp 'ldap-get-host-parameter)
43 (fset 'eudc-ldap-get-host-parameter 'ldap-get-host-parameter)
44 (defun eudc-ldap-get-host-parameter (host parameter)
45 "Get the value of PARAMETER for HOST in `ldap-host-parameters-alist'."
46 (plist-get (cdr (assoc host ldap-host-parameters-alist))
47 parameter))))
49 (defvar eudc-ldap-attributes-translation-alist
50 '((name . sn)
51 (firstname . givenname)
52 (email . mail)
53 (phone . telephonenumber))
54 "Alist mapping EUDC attribute names to LDAP names.")
56 (eudc-protocol-set 'eudc-query-function 'eudc-ldap-simple-query-internal
57 'ldap)
58 (eudc-protocol-set 'eudc-list-attributes-function 'eudc-ldap-get-field-list
59 'ldap)
60 (eudc-protocol-set 'eudc-protocol-attributes-translation-alist
61 'eudc-ldap-attributes-translation-alist 'ldap)
62 (eudc-protocol-set 'eudc-bbdb-conversion-alist
63 'eudc-ldap-bbdb-conversion-alist
64 'ldap)
65 (eudc-protocol-set 'eudc-protocol-has-default-query-attributes nil 'ldap)
66 (eudc-protocol-set 'eudc-attribute-display-method-alist
67 '(("jpegphoto" . eudc-display-jpeg-inline)
68 ("labeledurl" . eudc-display-url)
69 ("audio" . eudc-display-sound)
70 ("labeleduri" . eudc-display-url)
71 ("mail" . eudc-display-mail)
72 ("url" . eudc-display-url))
73 'ldap)
75 (defun eudc-ldap-cleanup-record-simple (record)
76 "Do some cleanup in a RECORD to make it suitable for EUDC."
77 (mapcar
78 (function
79 (lambda (field)
80 ;; Some servers return case-sensitive names (e.g. givenName
81 ;; instead of givenname); downcase the field's name so that it
82 ;; can be matched against
83 ;; eudc-ldap-attributes-translation-alist.
84 (cons (intern (downcase (car field)))
85 (if (cdr (cdr field))
86 (cdr field)
87 (car (cdr field))))))
88 record))
90 (defun eudc-filter-$ (string)
91 (mapconcat 'identity (split-string string "\\$") "\n"))
93 ;; Cleanup a LDAP record to make it suitable for EUDC:
94 ;; Make the record a cons-cell instead of a list if it is single-valued
95 ;; Filter the $ character in addresses into \n if not done by the LDAP lib
96 (defun eudc-ldap-cleanup-record-filtering-addresses (record)
97 (mapcar
98 (function
99 (lambda (field)
100 (let ((name (intern (downcase (car field))))
101 (value (cdr field)))
102 (if (memq name '(postaladdress registeredaddress))
103 (setq value (mapcar 'eudc-filter-$ value)))
104 (cons name
105 (if (cdr value)
106 value
107 (car value))))))
108 record))
110 (defun eudc-ldap-simple-query-internal (query &optional return-attrs)
111 "Query the LDAP server with QUERY.
112 QUERY is a list of cons cells (ATTR . VALUE) where ATTRs should be valid
113 LDAP attribute names.
114 RETURN-ATTRS is a list of attributes to return, defaulting to
115 `eudc-default-return-attributes'."
116 (let ((result (ldap-search (eudc-ldap-format-query-as-rfc1558 query)
117 eudc-server
118 (if (listp return-attrs)
119 (mapcar 'symbol-name return-attrs))))
120 final-result)
121 (if (or (not (boundp 'ldap-ignore-attribute-codings))
122 ldap-ignore-attribute-codings)
123 (setq result
124 (mapcar 'eudc-ldap-cleanup-record-filtering-addresses result))
125 (setq result (mapcar 'eudc-ldap-cleanup-record-simple result)))
127 (if (and eudc-strict-return-matches
128 return-attrs
129 (not (eq 'all return-attrs)))
130 (setq result (eudc-filter-partial-records result return-attrs)))
131 ;; Apply eudc-duplicate-attribute-handling-method
132 (if (not (eq 'list eudc-duplicate-attribute-handling-method))
133 (mapc
134 (function (lambda (record)
135 (setq final-result
136 (append (eudc-filter-duplicate-attributes record)
137 final-result))))
138 result))
139 final-result))
141 (defun eudc-ldap-get-field-list (_dummy &optional objectclass)
142 "Return a list of valid attribute names for the current server.
143 OBJECTCLASS is the LDAP object class for which the valid
144 attribute names are returned. Default to `person'"
145 (interactive)
146 (or eudc-server
147 (call-interactively 'eudc-set-server))
148 (let ((ldap-host-parameters-alist
149 (list (cons eudc-server
150 '(scope subtree sizelimit 1)))))
151 (mapcar 'eudc-ldap-cleanup-record-simple
152 (ldap-search
153 (eudc-ldap-format-query-as-rfc1558
154 (list (cons "objectclass"
155 (or objectclass
156 "person"))))
157 eudc-server nil t))))
159 (defun eudc-ldap-escape-query-special-chars (string)
160 "Value is STRING with characters forbidden in LDAP queries escaped."
161 ;; Note that * should also be escaped but in most situations I suppose
162 ;; the user doesn't want this
163 (eudc-replace-in-string
164 (eudc-replace-in-string
165 (eudc-replace-in-string
166 (eudc-replace-in-string
167 string
168 "\\\\" "\\5c")
169 "(" "\\28")
170 ")" "\\29")
171 (char-to-string ?\0) "\\00"))
173 (defun eudc-ldap-format-query-as-rfc1558 (query)
174 "Format the EUDC QUERY list as a RFC1558 LDAP search filter."
175 (let ((formatter (lambda (item &optional wildcard)
176 (format "(%s=%s)"
177 (car item)
178 (concat
179 (eudc-ldap-escape-query-special-chars
180 (cdr item)) (if wildcard "*" ""))))))
181 (format "(&%s)"
182 (concat
183 (mapconcat formatter (butlast query) "")
184 (funcall formatter (car (last query)) t)))))
186 ;;}}}
188 ;;{{{ High-level interfaces (interactive functions)
190 (defun eudc-ldap-customize ()
191 "Customize the EUDC LDAP support."
192 (interactive)
193 (customize-group 'eudc-ldap))
195 (defun eudc-ldap-check-base ()
196 "Check if the current LDAP server has a configured search base."
197 (unless (or (eudc-ldap-get-host-parameter eudc-server 'base)
198 ldap-default-base
199 (null (y-or-n-p "No search base defined. Configure it now? ")))
200 ;; If the server is not in ldap-host-parameters-alist we add it for the
201 ;; user
202 (if (null (assoc eudc-server ldap-host-parameters-alist))
203 (setq ldap-host-parameters-alist
204 (cons (list eudc-server) ldap-host-parameters-alist)))
205 (customize-variable 'ldap-host-parameters-alist)))
207 ;;}}}
210 (eudc-register-protocol 'ldap)
212 (provide 'eudcb-ldap)
214 ;;; eudcb-ldap.el ends here