aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2015-01-23 17:20:19 -0500
committerStefan Monnier2015-01-23 17:20:19 -0500
commitac5475dacb20d240db27d56199910d8a6fcc90e8 (patch)
tree2f18fd1d40f2ba65122636bf81730ccb614a166b
parentfd62486e819056bc9d0f00c09731a45a7f837997 (diff)
parente56e1b924d23a358a14ab069237db35a1c76d6a9 (diff)
downloademacs-ac5475dacb20d240db27d56199910d8a6fcc90e8.tar.gz
emacs-ac5475dacb20d240db27d56199910d8a6fcc90e8.zip
lisp/net/{eudc,ldap}: Merge branch streamline-eudc-configuration
-rw-r--r--doc/misc/ChangeLog9
-rw-r--r--doc/misc/eudc.texi130
-rw-r--r--lisp/ChangeLog85
-rw-r--r--lisp/net/eudc-vars.el97
-rw-r--r--lisp/net/eudc.el71
-rw-r--r--lisp/net/eudcb-ldap.el29
-rw-r--r--lisp/net/ldap.el136
7 files changed, 425 insertions, 132 deletions
diff --git a/doc/misc/ChangeLog b/doc/misc/ChangeLog
index 2baa13cea8c..e75589f92ec 100644
--- a/doc/misc/ChangeLog
+++ b/doc/misc/ChangeLog
@@ -1,3 +1,8 @@
12015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
2
3 * eudc.texi (LDAP Configuration): Rename from LDAP Requirements
4 and provide configuration examples.
5
12015-01-17 Stefan Monnier <monnier@iro.umontreal.ca> 62015-01-17 Stefan Monnier <monnier@iro.umontreal.ca>
2 7
3 * eieio.texi (Slot Options): Document :protection as unsupported. 8 * eieio.texi (Slot Options): Document :protection as unsupported.
@@ -28,8 +33,8 @@
28 33
292014-12-18 Eric Abrahamsen <eric@ericabrahamsen.net> 342014-12-18 Eric Abrahamsen <eric@ericabrahamsen.net>
30 35
31 * gnus.texi (Gnus Registry Setup): Explain pruning changes. Mention 36 * gnus.texi (Gnus Registry Setup): Explain pruning changes.
32 gnus-registry-prune-factor. Explain sorting changes and 37 Mention gnus-registry-prune-factor. Explain sorting changes and
33 gnus-registry-default-sort-function. Correct file extension. 38 gnus-registry-default-sort-function. Correct file extension.
34 39
352014-12-17 Jay Belanger <jay.p.belanger@gmail.com> 402014-12-17 Jay Belanger <jay.p.belanger@gmail.com>
diff --git a/doc/misc/eudc.texi b/doc/misc/eudc.texi
index b5a4e3aae40..9757c82fe7e 100644
--- a/doc/misc/eudc.texi
+++ b/doc/misc/eudc.texi
@@ -137,7 +137,7 @@ location, etc@enddots{} More information about LDAP can be found at
137@url{http://www.openldap.org/}. 137@url{http://www.openldap.org/}.
138 138
139EUDC requires external support to access LDAP directory servers 139EUDC requires external support to access LDAP directory servers
140(@pxref{LDAP Requirements}) 140(@pxref{LDAP Configuration})
141 141
142 142
143@node CCSO PH/QI 143@node CCSO PH/QI
@@ -213,17 +213,131 @@ email composition buffers (@pxref{Inline Query Expansion})
213@end lisp 213@end lisp
214 214
215@menu 215@menu
216* LDAP Requirements:: EUDC needs external support for LDAP 216* LDAP Configuration:: EUDC needs external support for LDAP
217@end menu 217@end menu
218 218
219@node LDAP Requirements 219@node LDAP Configuration
220@section LDAP Requirements 220@section LDAP Configuration
221 221
222LDAP support is added by means of @file{ldap.el}, which is part of Emacs. 222LDAP support is added by means of @file{ldap.el}, which is part of
223@file{ldap.el} needs an external command line utility named 223Emacs. @file{ldap.el} needs an external command line utility named
224@file{ldapsearch}, available as part of Open LDAP 224@file{ldapsearch}, available as part of OpenLDAP
225(@url{http://www.openldap.org/}). 225(@url{http://www.openldap.org/}). The configurations in this section
226were tested with OpenLDAP 2.4.23.
226 227
228The following examples use a base of
229@code{ou=people,dc=example,dc=com} and the host name
230@code{directory.example.com}, a server that supports LDAP-over-SSL
231(the @code{ldaps} protocol, with default port @code{636}) and which
232requires authentication by the user @code{emacsuser} with password
233@code{s3cr3t}.
234
235These configurations are meant to be self-contained; that is, each
236provides everything required for sensible TAB-completion of email
237fields. BBDB lookups are attempted first; if a matching BBDB entry is
238found then EUDC will not attempt any LDAP lookups.
239
240Wildcard LDAP lookups are supported using the @code{*} character. For
241example, attempting to TAB-complete the following:
242
243@example
244To: * Smith
245@end example
246
247will return all LDAP entries with surnames that begin with
248@code{Smith}. In every LDAP query it makes, EUDC implicitly appends
249the wildcard character to the end of the last word.
250
251@subsection Emacs-only Configuration
252
253Emacs can pass most required configuration options via the
254@file{ldapsearch} command-line. One exception is certificate
255configuration for LDAP-over-SSL, which must be specified in
256@file{/etc/openldap/ldap.conf}. On systems that provide such
257certificates as part of the @code{OpenLDAP} installation, this can be
258as simple as one line:
259
260@example
261TLS_CACERTDIR /etc/openldap/certs
262@end example
263
264In @file{.emacs}, these expressions suffice to configure EUDC for
265LDAP:
266
267@lisp
268(eval-after-load "message"
269 '(define-key message-mode-map (kbd "TAB") 'eudc-expand-inline))
270(customize-set-variable 'eudc-server-hotlist
271 '(("" . bbdb)
272 ("ldaps://directory.example.com" . ldap)))
273(customize-set-variable 'ldap-host-parameters-alist
274 '(("ldaps://directory.example.com"
275 base "ou=people,dc=example,dc=com"
276 binddn "example\\emacsuser"
277 passwd ldap-password-read)))
278@end lisp
279
280Specifying the function @code{ldap-password-read} for @code{passwd}
281will cause Emacs to prompt interactively for the password. The
282password will then be validated and cached, unless
283@code{password-cache} is nil. You can customize
284@code{password-cache-expiry} to control the duration for which the
285password is cached. If you want to clear the cache, call
286@code{password-reset}.
287
288@subsection External Configuration
289
290Your system may already be configured for a default LDAP server. For
291example, @file{/etc/openldap/ldap.conf} might contain:
292
293@example
294BASE ou=people,dc=example,dc=com
295URI ldaps://directory.example.com
296TLS_CACERTDIR /etc/openldap/certs
297@end example
298
299To authenticate, the @dfn{bind distinguished name (binddn)} is
300required, in this case, @code{example\emacsuser}, along with the
301password. These can be specified in @file{~/.authinfo.gpg} with the
302following line:
303
304@example
305machine ldaps://directory.example.com binddn example\emacsuser password s3cr3t
306@end example
307
308Then in the @file{.emacs} init file, these expressions suffice to
309configure EUDC for LDAP:
310
311@lisp
312(eval-after-load "message"
313 '(define-key message-mode-map (kbd "TAB") 'eudc-expand-inline))
314(customize-set-variable 'eudc-server-hotlist
315 '(("" . bbdb)
316 ("ldaps://directory.example.com" . ldap)))
317(customize-set-variable 'ldap-host-parameters-alist
318 '(("ldaps://directory.example.com"
319 auth-source t)))
320@end lisp
321
322For this example where we only care about one server, the server name
323can be omitted in @file{~/.authinfo.gpg} and @file{.emacs}, in which
324case @file{ldapsearch} defaults to the host name in
325@file{/etc/openldap/ldap.conf}.
326
327The @file{~/.authinfo.gpg} line becomes:
328
329@example
330binddn example\emacsuser password s3cr3t
331@end example
332
333and the @file{.emacs} expressions become:
334
335@lisp
336(eval-after-load "message"
337 '(define-key message-mode-map (kbd "TAB") 'eudc-expand-inline))
338(customize-set-variable 'eudc-server-hotlist '(("" . bbdb) ("" . ldap)))
339(customize-set-variable 'ldap-host-parameters-alist '(("" auth-source t)))
340@end lisp
227 341
228@node Usage 342@node Usage
229@chapter Usage 343@chapter Usage
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index ed4e1ab1e15..15518a73eb1 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,88 @@
12015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
2
3 * net/ldap.el (ldap-search-internal): Mention binddn in invalid
4 credentials error message.
5
62015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
7
8 * net/ldap.el (ldap-password-read): Validate password before
9 caching it.
10 (ldap-search-internal): Handle ldapsearch error conditions.
11
122015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
13
14 * net/ldap.el (ldap-password-read): Handle password-cache being nil.
15
162015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
17
18 * net/eudc.el (eudc-expand-inline): Always restore former server
19 and protocol.
20
212015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
22
23 * net/eudcb-ldap.el: Don't nag the user in case a default base is
24 provided by the LDAP system configuration file.
25
262015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
27
28 * net/eudc.el (eudc-format-query): Preserve the
29 eudc-inline-query-format ordering of attributes in the returned list.
30 * net/eudcb-ldap.el (eudc-ldap-format-query-as-rfc1558):
31 Append the LDAP wildcard character to the last attribute value.
32
332015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
34
35 * net/eudcb-ldap.el (eudc-ldap-cleanup-record-simple):
36 Downcase field names of LDAP results.
37 (eudc-ldap-cleanup-record-filtering-addresses): Likewise.
38
392015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
40
41 * net/ldap.el (ldap-ldapsearch-password-prompt): New defcustom.
42 (ldap-search-internal): Send password to ldapsearch through a pipe
43 instead of via the command line.
44
452015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
46
47 * net/ldap.el: Require password-cache.
48 (ldap-password-read): New function.
49 (ldap-search-internal): Call ldap-password-read when it is
50 configured to be called.
51
522015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
53
54 * net/eudc-vars.el (eudc-expansion-overwrites-query):
55 Change default to nil.
56
572015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
58
59 * net/eudc.el (eudc-expand-inline): Ignore text properties of
60 string-to-expand.
61
622015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
63
64 * net/eudc-vars.el (eudc-inline-expansion-format): Default to a
65 format that includes first name and surname.
66
672015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
68
69 * net/eudc-vars.el (eudc-inline-query-format): Change default to
70 query email and first name instead of surname.
71
722015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
73
74 * net/ldap.el (ldap-search-internal): Support new-style LDAP URIs.
75
762015-01-23 Thomas Fitzsimmons <fitzsim@fitzsim.org>
77
78 * net/eudc-vars.el (eudc-server): Adjust docstring to mention
79 eudc-server-hotlist.
80 (eudc-server-hotlist): Move from eudc.el and make defcustom.
81 * net/eudc.el (eudc-server-hotlist): Move to eudc-vars.el.
82 (eudc-set-server): Allow setting protocol to nil.
83 (eudc-expand-inline): Support hotlist-only expansions when server
84 is not set.
85
12015-01-23 Stefan Monnier <monnier@iro.umontreal.ca> 862015-01-23 Stefan Monnier <monnier@iro.umontreal.ca>
2 87
3 * emacs-lisp/cl-generic.el (cl-no-primary-method): New fun and error. 88 * emacs-lisp/cl-generic.el (cl-no-primary-method): New fun and error.
diff --git a/lisp/net/eudc-vars.el b/lisp/net/eudc-vars.el
index 6bc0337f958..29ddf613376 100644
--- a/lisp/net/eudc-vars.el
+++ b/lisp/net/eudc-vars.el
@@ -41,14 +41,36 @@
41 "The name or IP address of the directory server. 41 "The name or IP address of the directory server.
42A port number may be specified by appending a colon and a 42A port number may be specified by appending a colon and a
43number to the name of the server. Use `localhost' if the directory 43number to the name of the server. Use `localhost' if the directory
44server resides on your computer (BBDB backend)." 44server resides on your computer (BBDB backend).
45 :type '(choice (string :tag "Server") (const :tag "None" nil)) 45
46 :group 'eudc) 46To specify multiple servers, customize eudc-server-hotlist
47instead."
48 :type '(choice (string :tag "Server") (const :tag "None" nil)))
47 49
48;; Known protocols (used in completion) 50;; Known protocols (used in completion)
49;; Not to be mistaken with `eudc-supported-protocols' 51;; Not to be mistaken with `eudc-supported-protocols'
50(defvar eudc-known-protocols '(bbdb ph ldap)) 52(defvar eudc-known-protocols '(bbdb ph ldap))
51 53
54(defcustom eudc-server-hotlist nil
55 "Directory servers to query.
56This is an alist of the form (SERVER . PROTOCOL). SERVER is the
57host name or URI of the server, PROTOCOL is a symbol representing
58the EUDC backend with which to access the server.
59
60The BBDB backend ignores SERVER; `localhost' can be used as a
61placeholder string."
62 :tag "Directory Servers to Query"
63 :type `(repeat (cons :tag "Directory Server"
64 (string :tag "Server Host Name or URI")
65 (choice :tag "Protocol"
66 :menu-tag "Protocol"
67 ,@(mapcar (lambda (s)
68 (list 'const
69 ':tag (symbol-name s) s))
70 eudc-known-protocols)
71 (const :tag "None" nil))))
72 :version "25.1")
73
52(defvar eudc-supported-protocols nil 74(defvar eudc-supported-protocols nil
53 "Protocols currently supported by EUDC. 75 "Protocols currently supported by EUDC.
54This variable is updated when protocol-specific libraries 76This variable is updated when protocol-specific libraries
@@ -61,15 +83,13 @@ Supported protocols are specified by `eudc-supported-protocols'."
61 ,@(mapcar (lambda (s) 83 ,@(mapcar (lambda (s)
62 (list 'const ':tag (symbol-name s) s)) 84 (list 'const ':tag (symbol-name s) s))
63 eudc-known-protocols) 85 eudc-known-protocols)
64 (const :tag "None" nil)) 86 (const :tag "None" nil)))
65 :group 'eudc)
66 87
67 88
68(defcustom eudc-strict-return-matches t 89(defcustom eudc-strict-return-matches t
69 "Ignore or allow entries not containing all requested return attributes. 90 "Ignore or allow entries not containing all requested return attributes.
70If non-nil, such entries are ignored." 91If non-nil, such entries are ignored."
71 :type 'boolean 92 :type 'boolean)
72 :group 'eudc)
73 93
74(defcustom eudc-default-return-attributes nil 94(defcustom eudc-default-return-attributes nil
75 "A list of default attributes to extract from directory entries. 95 "A list of default attributes to extract from directory entries.
@@ -82,8 +102,7 @@ server."
82 (repeat :menu-tag "Attribute list" 102 (repeat :menu-tag "Attribute list"
83 :tag "Attribute name" 103 :tag "Attribute name"
84 :value (nil) 104 :value (nil)
85 (symbol :tag "Attribute name"))) 105 (symbol :tag "Attribute name"))))
86 :group 'eudc)
87 106
88(defcustom eudc-multiple-match-handling-method 'select 107(defcustom eudc-multiple-match-handling-method 'select
89 "What to do when multiple entries match an inline expansion query. 108 "What to do when multiple entries match an inline expansion query.
@@ -102,8 +121,7 @@ Possible values are:
102 (const :menu-tag "Abort Operation" 121 (const :menu-tag "Abort Operation"
103 :tag "Abort Operation" abort) 122 :tag "Abort Operation" abort)
104 (const :menu-tag "Default (Use First)" 123 (const :menu-tag "Default (Use First)"
105 :tag "Default (Use First)" nil)) 124 :tag "Default (Use First)" nil)))
106 :group 'eudc)
107 125
108(defcustom eudc-duplicate-attribute-handling-method '((email . duplicate)) 126(defcustom eudc-duplicate-attribute-handling-method '((email . duplicate))
109 "A method to handle entries containing duplicate attributes. 127 "A method to handle entries containing duplicate attributes.
@@ -130,10 +148,10 @@ different values."
130 (const :menu-tag "List" list) 148 (const :menu-tag "List" list)
131 (const :menu-tag "First" first) 149 (const :menu-tag "First" first)
132 (const :menu-tag "Concat" concat) 150 (const :menu-tag "Concat" concat)
133 (const :menu-tag "Duplicate" duplicate))))) 151 (const :menu-tag "Duplicate" duplicate))))))
134 :group 'eudc)
135 152
136(defcustom eudc-inline-query-format '((name) 153(defcustom eudc-inline-query-format '((email)
154 (firstname)
137 (firstname name)) 155 (firstname name))
138 "Format of an inline expansion query. 156 "Format of an inline expansion query.
139This is a list of FORMATs. A FORMAT is itself a list of one or more 157This is a list of FORMATs. A FORMAT is itself a list of one or more
@@ -160,14 +178,16 @@ must be set in a protocol/server-local fashion, see `eudc-server-set' and
160 (const :menu-tag "Email Address" :tag "Email Address" email) 178 (const :menu-tag "Email Address" :tag "Email Address" email)
161 (const :menu-tag "Phone" :tag "Phone" phone) 179 (const :menu-tag "Phone" :tag "Phone" phone)
162 (symbol :menu-tag "Other" :tag "Attribute name")))) 180 (symbol :menu-tag "Other" :tag "Attribute name"))))
163 :group 'eudc) 181 :version "25.1")
164 182
165(defcustom eudc-expansion-overwrites-query t 183;; Default to nil so that the most common use of eudc-expand-inline,
184;; where replace is nil, does not affect the kill ring.
185(defcustom eudc-expansion-overwrites-query nil
166 "If non-nil, expanding a query overwrites the query string." 186 "If non-nil, expanding a query overwrites the query string."
167 :type 'boolean 187 :type 'boolean
168 :group 'eudc) 188 :version "25.1")
169 189
170(defcustom eudc-inline-expansion-format '("%s" email) 190(defcustom eudc-inline-expansion-format '("%s %s <%s>" firstname name email)
171 "A list specifying the format of the expansion of inline queries. 191 "A list specifying the format of the expansion of inline queries.
172This variable controls what `eudc-expand-inline' actually inserts in 192This variable controls what `eudc-expand-inline' actually inserts in
173the buffer. First element is a string passed to `format'. Remaining 193the buffer. First element is a string passed to `format'. Remaining
@@ -185,7 +205,7 @@ are passed as additional arguments to `format'."
185 (const :menu-tag "Phone" :tag "Phone" phone) 205 (const :menu-tag "Phone" :tag "Phone" phone)
186 (symbol :menu-tag "Other") 206 (symbol :menu-tag "Other")
187 (symbol :tag "Attribute name")))) 207 (symbol :tag "Attribute name"))))
188 :group 'eudc) 208 :version "25.1")
189 209
190(defcustom eudc-inline-expansion-servers 'server-then-hotlist 210(defcustom eudc-inline-expansion-servers 'server-then-hotlist
191 "Which servers to contact for the expansion of inline queries. 211 "Which servers to contact for the expansion of inline queries.
@@ -198,8 +218,7 @@ Possible values are:
198 :menu-tag "Servers" 218 :menu-tag "Servers"
199 (const :menu-tag "Current server" current-server) 219 (const :menu-tag "Current server" current-server)
200 (const :menu-tag "Servers in the hotlist" hotlist) 220 (const :menu-tag "Servers in the hotlist" hotlist)
201 (const :menu-tag "Current server then hotlist" server-then-hotlist)) 221 (const :menu-tag "Current server then hotlist" server-then-hotlist)))
202 :group 'eudc)
203 222
204(defcustom eudc-max-servers-to-query nil 223(defcustom eudc-max-servers-to-query nil
205 "Maximum number of servers to query for an inline expansion. 224 "Maximum number of servers to query for an inline expansion.
@@ -213,8 +232,7 @@ If nil, query all servers available from `eudc-inline-expansion-servers'."
213 (const :menu-tag "3" 3) 232 (const :menu-tag "3" 3)
214 (const :menu-tag "4" 4) 233 (const :menu-tag "4" 4)
215 (const :menu-tag "5" 5) 234 (const :menu-tag "5" 5)
216 (integer :menu-tag "Set")) 235 (integer :menu-tag "Set")))
217 :group 'eudc)
218 236
219(defcustom eudc-query-form-attributes '(name firstname email phone) 237(defcustom eudc-query-form-attributes '(name firstname email phone)
220 "A list of attributes presented in the query form." 238 "A list of attributes presented in the query form."
@@ -226,8 +244,7 @@ If nil, query all servers available from `eudc-inline-expansion-servers'."
226 (const :menu-tag "Surname" :tag "Surname" name) 244 (const :menu-tag "Surname" :tag "Surname" name)
227 (const :menu-tag "Email Address" :tag "Email Address" email) 245 (const :menu-tag "Email Address" :tag "Email Address" email)
228 (const :menu-tag "Phone" :tag "Phone" phone) 246 (const :menu-tag "Phone" :tag "Phone" phone)
229 (symbol :menu-tag "Other" :tag "Attribute name"))) 247 (symbol :menu-tag "Other" :tag "Attribute name"))))
230 :group 'eudc)
231 248
232(defcustom eudc-user-attribute-names-alist '((url . "URL") 249(defcustom eudc-user-attribute-names-alist '((url . "URL")
233 (callsign . "HAM Call Sign") 250 (callsign . "HAM Call Sign")
@@ -257,15 +274,13 @@ at `_' characters and capitalizing the individual words."
257 :tag "User-defined Names of Directory Attributes" 274 :tag "User-defined Names of Directory Attributes"
258 :type '(repeat (cons :tag "Field" 275 :type '(repeat (cons :tag "Field"
259 (symbol :tag "Directory attribute") 276 (symbol :tag "Directory attribute")
260 (string :tag "User friendly name "))) 277 (string :tag "User friendly name "))))
261 :group 'eudc)
262 278
263(defcustom eudc-use-raw-directory-names nil 279(defcustom eudc-use-raw-directory-names nil
264 "If non-nil, use attributes names as defined in the directory. 280 "If non-nil, use attributes names as defined in the directory.
265Otherwise, directory query/response forms display the user attribute 281Otherwise, directory query/response forms display the user attribute
266names defined in `eudc-user-attribute-names-alist'." 282names defined in `eudc-user-attribute-names-alist'."
267 :type 'boolean 283 :type 'boolean)
268 :group 'eudc)
269 284
270(defcustom eudc-attribute-display-method-alist nil 285(defcustom eudc-attribute-display-method-alist nil
271 "An alist specifying methods to display attribute values. 286 "An alist specifying methods to display attribute values.
@@ -277,8 +292,7 @@ attribute values for display."
277 :tag "Attribute Decoding Functions" 292 :tag "Attribute Decoding Functions"
278 :type '(repeat (cons :tag "Attribute" 293 :type '(repeat (cons :tag "Attribute"
279 (symbol :tag "Name") 294 (symbol :tag "Name")
280 (symbol :tag "Display Function"))) 295 (symbol :tag "Display Function"))))
281 :group 'eudc)
282 296
283(defcustom eudc-external-viewers '(("ImageMagick" "display" "-") 297(defcustom eudc-external-viewers '(("ImageMagick" "display" "-")
284 ("ShowAudio" "showaudio")) 298 ("ShowAudio" "showaudio"))
@@ -295,18 +309,15 @@ arguments that should be passed to the program."
295 (repeat 309 (repeat
296 :tag "Arguments" 310 :tag "Arguments"
297 :inline t 311 :inline t
298 (string :tag "Argument")))) 312 (string :tag "Argument")))))
299 :group 'eudc)
300 313
301(defcustom eudc-options-file "~/.eudc-options" 314(defcustom eudc-options-file "~/.eudc-options"
302 "A file where the `servers' hotlist is stored." 315 "A file where the `servers' hotlist is stored."
303 :type '(file :Tag "File Name:") 316 :type '(file :Tag "File Name:"))
304 :group 'eudc)
305 317
306(defcustom eudc-mode-hook nil 318(defcustom eudc-mode-hook nil
307 "Normal hook run on entry to EUDC mode." 319 "Normal hook run on entry to EUDC mode."
308 :type '(repeat (sexp :tag "Hook definition")) 320 :type 'hook)
309 :group 'eudc)
310 321
311;;}}} 322;;}}}
312 323
@@ -341,8 +352,7 @@ BBDB fields. SPECs are sexps which are evaluated:
341 :tag "BBDB to PH Field Name Mapping" 352 :tag "BBDB to PH Field Name Mapping"
342 :type '(repeat (cons :tag "Field Name" 353 :type '(repeat (cons :tag "Field Name"
343 (symbol :tag "BBDB Field") 354 (symbol :tag "BBDB Field")
344 (sexp :tag "Conversion Spec"))) 355 (sexp :tag "Conversion Spec"))))
345 :group 'eudc-ph)
346 356
347;;}}} 357;;}}}
348 358
@@ -376,8 +386,7 @@ BBDB fields. SPECs are sexps which are evaluated:
376 :tag "BBDB to LDAP Attribute Names Mapping" 386 :tag "BBDB to LDAP Attribute Names Mapping"
377 :type '(repeat (cons :tag "Field Name" 387 :type '(repeat (cons :tag "Field Name"
378 (symbol :tag "BBDB Field") 388 (symbol :tag "BBDB Field")
379 (sexp :tag "Conversion Spec"))) 389 (sexp :tag "Conversion Spec"))))
380 :group 'eudc-ldap)
381 390
382;;}}} 391;;}}}
383 392
@@ -391,14 +400,12 @@ BBDB fields. SPECs are sexps which are evaluated:
391 "If non-nil, BBDB address and phone locations are used as attribute names. 400 "If non-nil, BBDB address and phone locations are used as attribute names.
392This has no effect on queries (you can't search for a specific location) 401This has no effect on queries (you can't search for a specific location)
393but influences the way records are displayed." 402but influences the way records are displayed."
394 :type 'boolean 403 :type 'boolean)
395 :group 'eudc-bbdb)
396 404
397(defcustom eudc-bbdb-enable-substring-matches t 405(defcustom eudc-bbdb-enable-substring-matches t
398 "If non-nil, authorize substring match in the same way BBDB does. 406 "If non-nil, authorize substring match in the same way BBDB does.
399Otherwise records must match queries exactly." 407Otherwise records must match queries exactly."
400 :type 'boolean 408 :type 'boolean)
401 :group 'eudc-bbdb)
402 409
403;;}}} 410;;}}}
404 411
diff --git a/lisp/net/eudc.el b/lisp/net/eudc.el
index 0f2fc0be7bd..4dd80972e3f 100644
--- a/lisp/net/eudc.el
+++ b/lisp/net/eudc.el
@@ -76,10 +76,6 @@
76 76
77(defvar mode-popup-menu) 77(defvar mode-popup-menu)
78 78
79;; List of known servers
80;; Alist of (SERVER . PROTOCOL)
81(defvar eudc-server-hotlist nil)
82
83;; List of variables that have server- or protocol-local bindings 79;; List of variables that have server- or protocol-local bindings
84(defvar eudc-local-vars nil) 80(defvar eudc-local-vars nil)
85 81
@@ -688,7 +684,8 @@ server for future sessions."
688 (cons (symbol-name elt) 684 (cons (symbol-name elt)
689 elt)) 685 elt))
690 eudc-known-protocols))))) 686 eudc-known-protocols)))))
691 (unless (or (member protocol 687 (unless (or (null protocol)
688 (member protocol
692 eudc-supported-protocols) 689 eudc-supported-protocols)
693 (load (concat "eudcb-" (symbol-name protocol)) t)) 690 (load (concat "eudcb-" (symbol-name protocol)) t))
694 (error "Unsupported protocol: %s" protocol)) 691 (error "Unsupported protocol: %s" protocol))
@@ -766,7 +763,6 @@ otherwise a list of symbols is returned."
766 format (cdr format))) 763 format (cdr format)))
767 ;; If the same attribute appears more than once, merge 764 ;; If the same attribute appears more than once, merge
768 ;; the corresponding values 765 ;; the corresponding values
769 (setq query-alist (nreverse query-alist))
770 (while query-alist 766 (while query-alist
771 (setq key (eudc-caar query-alist) 767 (setq key (eudc-caar query-alist)
772 val (eudc-cdar query-alist) 768 val (eudc-cdar query-alist)
@@ -812,19 +808,29 @@ If REPLACE is non-nil, then this expansion replaces the name in the buffer.
812Multiple servers can be tried with the same query until one finds a match, 808Multiple servers can be tried with the same query until one finds a match,
813see `eudc-inline-expansion-servers'" 809see `eudc-inline-expansion-servers'"
814 (interactive) 810 (interactive)
815 (if (memq eudc-inline-expansion-servers 811 (cond
816 '(current-server server-then-hotlist)) 812 ((eq eudc-inline-expansion-servers 'current-server)
817 (or eudc-server 813 (or eudc-server
818 (call-interactively 'eudc-set-server)) 814 (call-interactively 'eudc-set-server)))
815 ((eq eudc-inline-expansion-servers 'server-then-hotlist)
816 (or eudc-server
817 ;; Allow server to be nil if hotlist is set.
818 eudc-server-hotlist
819 (call-interactively 'eudc-set-server)))
820 ((eq eudc-inline-expansion-servers 'hotlist)
819 (or eudc-server-hotlist 821 (or eudc-server-hotlist
820 (error "No server in the hotlist"))) 822 (error "No server in the hotlist")))
823 (t
824 (error "Wrong value for `eudc-inline-expansion-servers': %S"
825 eudc-inline-expansion-servers)))
821 (let* ((end (point)) 826 (let* ((end (point))
822 (beg (save-excursion 827 (beg (save-excursion
823 (if (re-search-backward "\\([:,]\\|^\\)[ \t]*" 828 (if (re-search-backward "\\([:,]\\|^\\)[ \t]*"
824 (point-at-bol) 'move) 829 (point-at-bol) 'move)
825 (goto-char (match-end 0))) 830 (goto-char (match-end 0)))
826 (point))) 831 (point)))
827 (query-words (split-string (buffer-substring beg end) "[ \t]+")) 832 (query-words (split-string (buffer-substring-no-properties beg end)
833 "[ \t]+"))
828 query-formats 834 query-formats
829 response 835 response
830 response-string 836 response-string
@@ -840,18 +846,17 @@ see `eudc-inline-expansion-servers'"
840 ((eq eudc-inline-expansion-servers 'hotlist) 846 ((eq eudc-inline-expansion-servers 'hotlist)
841 eudc-server-hotlist) 847 eudc-server-hotlist)
842 ((eq eudc-inline-expansion-servers 'server-then-hotlist) 848 ((eq eudc-inline-expansion-servers 'server-then-hotlist)
843 (cons (cons eudc-server eudc-protocol) 849 (if eudc-server
844 (delete (cons eudc-server eudc-protocol) servers))) 850 (cons (cons eudc-server eudc-protocol)
851 (delete (cons eudc-server eudc-protocol) servers))
852 eudc-server-hotlist))
845 ((eq eudc-inline-expansion-servers 'current-server) 853 ((eq eudc-inline-expansion-servers 'current-server)
846 (list (cons eudc-server eudc-protocol))) 854 (list (cons eudc-server eudc-protocol)))))
847 (t
848 (error "Wrong value for `eudc-inline-expansion-servers': %S"
849 eudc-inline-expansion-servers))))
850 (if (and eudc-max-servers-to-query 855 (if (and eudc-max-servers-to-query
851 (> (length servers) eudc-max-servers-to-query)) 856 (> (length servers) eudc-max-servers-to-query))
852 (setcdr (nthcdr (1- eudc-max-servers-to-query) servers) nil)) 857 (setcdr (nthcdr (1- eudc-max-servers-to-query) servers) nil))
853 858
854 (condition-case signal 859 (unwind-protect
855 (progn 860 (progn
856 (setq response 861 (setq response
857 (catch 'found 862 (catch 'found
@@ -887,14 +892,15 @@ see `eudc-inline-expansion-servers'"
887 892
888 ;; Process response through eudc-inline-expansion-format 893 ;; Process response through eudc-inline-expansion-format
889 (while response 894 (while response
890 (setq response-string (apply 'format 895 (setq response-string
891 (car eudc-inline-expansion-format) 896 (apply 'format
892 (mapcar (function 897 (car eudc-inline-expansion-format)
893 (lambda (field) 898 (mapcar (function
894 (or (cdr (assq field (car response))) 899 (lambda (field)
895 ""))) 900 (or (cdr (assq field (car response)))
896 (eudc-translate-attribute-list 901 "")))
897 (cdr eudc-inline-expansion-format))))) 902 (eudc-translate-attribute-list
903 (cdr eudc-inline-expansion-format)))))
898 (if (> (length response-string) 0) 904 (if (> (length response-string) 0)
899 (setq response-strings 905 (setq response-strings
900 (cons response-string response-strings))) 906 (cons response-string response-strings)))
@@ -916,15 +922,10 @@ see `eudc-inline-expansion-servers'"
916 (delete-region beg end) 922 (delete-region beg end)
917 (insert (mapconcat 'identity response-strings ", "))) 923 (insert (mapconcat 'identity response-strings ", ")))
918 ((eq eudc-multiple-match-handling-method 'abort) 924 ((eq eudc-multiple-match-handling-method 'abort)
919 (error "There is more than one match for the query")))) 925 (error "There is more than one match for the query")))))
920 (or (and (equal eudc-server eudc-former-server) 926 (or (and (equal eudc-server eudc-former-server)
921 (equal eudc-protocol eudc-former-protocol)) 927 (equal eudc-protocol eudc-former-protocol))
922 (eudc-set-server eudc-former-server eudc-former-protocol t))) 928 (eudc-set-server eudc-former-server eudc-former-protocol t)))))
923 (error
924 (or (and (equal eudc-server eudc-former-server)
925 (equal eudc-protocol eudc-former-protocol))
926 (eudc-set-server eudc-former-server eudc-former-protocol t))
927 (signal (car signal) (cdr signal))))))
928 929
929;;;###autoload 930;;;###autoload
930(defun eudc-query-form (&optional get-fields-from-server) 931(defun eudc-query-form (&optional get-fields-from-server)
diff --git a/lisp/net/eudcb-ldap.el b/lisp/net/eudcb-ldap.el
index 4c9b2490ee3..92972c5f99e 100644
--- a/lisp/net/eudcb-ldap.el
+++ b/lisp/net/eudcb-ldap.el
@@ -70,16 +70,17 @@
70 ("mail" . eudc-display-mail) 70 ("mail" . eudc-display-mail)
71 ("url" . eudc-display-url)) 71 ("url" . eudc-display-url))
72 'ldap) 72 'ldap)
73(eudc-protocol-set 'eudc-switch-to-server-hook
74 '(eudc-ldap-check-base)
75 'ldap)
76 73
77(defun eudc-ldap-cleanup-record-simple (record) 74(defun eudc-ldap-cleanup-record-simple (record)
78 "Do some cleanup in a RECORD to make it suitable for EUDC." 75 "Do some cleanup in a RECORD to make it suitable for EUDC."
79 (mapcar 76 (mapcar
80 (function 77 (function
81 (lambda (field) 78 (lambda (field)
82 (cons (intern (car field)) 79 ;; Some servers return case-sensitive names (e.g. givenName
80 ;; instead of givenname); downcase the field's name so that it
81 ;; can be matched against
82 ;; eudc-ldap-attributes-translation-alist.
83 (cons (intern (downcase (car field)))
83 (if (cdr (cdr field)) 84 (if (cdr (cdr field))
84 (cdr field) 85 (cdr field)
85 (car (cdr field)))))) 86 (car (cdr field))))))
@@ -95,7 +96,7 @@
95 (mapcar 96 (mapcar
96 (function 97 (function
97 (lambda (field) 98 (lambda (field)
98 (let ((name (intern (car field))) 99 (let ((name (intern (downcase (car field))))
99 (value (cdr field))) 100 (value (cdr field)))
100 (if (memq name '(postaladdress registeredaddress)) 101 (if (memq name '(postaladdress registeredaddress))
101 (setq value (mapcar 'eudc-filter-$ value))) 102 (setq value (mapcar 'eudc-filter-$ value)))
@@ -170,14 +171,16 @@ attribute names are returned. Default to `person'"
170 171
171(defun eudc-ldap-format-query-as-rfc1558 (query) 172(defun eudc-ldap-format-query-as-rfc1558 (query)
172 "Format the EUDC QUERY list as a RFC1558 LDAP search filter." 173 "Format the EUDC QUERY list as a RFC1558 LDAP search filter."
173 (format "(&%s)" 174 (let ((formatter (lambda (item &optional wildcard)
174 (apply 'concat 175 (format "(%s=%s)"
175 (mapcar (lambda (item) 176 (car item)
176 (format "(%s=%s)" 177 (concat
177 (car item) 178 (eudc-ldap-escape-query-special-chars
178 (eudc-ldap-escape-query-special-chars (cdr item)))) 179 (cdr item)) (if wildcard "*" ""))))))
179 query)))) 180 (format "(&%s)"
180 181 (concat
182 (mapconcat formatter (butlast query) "")
183 (funcall formatter (car (last query)) t)))))
181 184
182;;}}} 185;;}}}
183 186
diff --git a/lisp/net/ldap.el b/lisp/net/ldap.el
index eb1b7589b48..a77fc3c6514 100644
--- a/lisp/net/ldap.el
+++ b/lisp/net/ldap.el
@@ -34,6 +34,7 @@
34;;; Code: 34;;; Code:
35 35
36(require 'custom) 36(require 'custom)
37(require 'password-cache)
37 38
38(autoload 'auth-source-search "auth-source") 39(autoload 'auth-source-search "auth-source")
39 40
@@ -47,15 +48,13 @@
47A TCP port number can be appended to that name using a colon as 48A TCP port number can be appended to that name using a colon as
48a separator." 49a separator."
49 :type '(choice (string :tag "Host name") 50 :type '(choice (string :tag "Host name")
50 (const :tag "Use library default" nil)) 51 (const :tag "Use library default" nil)))
51 :group 'ldap)
52 52
53(defcustom ldap-default-port nil 53(defcustom ldap-default-port nil
54 "Default TCP port for LDAP connections. 54 "Default TCP port for LDAP connections.
55Initialized from the LDAP library at build time. Default value is 389." 55Initialized from the LDAP library at build time. Default value is 389."
56 :type '(choice (const :tag "Use library default" nil) 56 :type '(choice (const :tag "Use library default" nil)
57 (integer :tag "Port number")) 57 (integer :tag "Port number")))
58 :group 'ldap)
59 58
60(defcustom ldap-default-base nil 59(defcustom ldap-default-base nil
61 "Default base for LDAP searches. 60 "Default base for LDAP searches.
@@ -63,8 +62,7 @@ This is a string using the syntax of RFC 1779.
63For instance, \"o=ACME, c=US\" limits the search to the 62For instance, \"o=ACME, c=US\" limits the search to the
64Acme organization in the United States." 63Acme organization in the United States."
65 :type '(choice (const :tag "Use library default" nil) 64 :type '(choice (const :tag "Use library default" nil)
66 (string :tag "Search base")) 65 (string :tag "Search base")))
67 :group 'ldap)
68 66
69 67
70(defcustom ldap-host-parameters-alist nil 68(defcustom ldap-host-parameters-alist nil
@@ -144,35 +142,35 @@ Valid properties include:
144 :tag "Size Limit" 142 :tag "Size Limit"
145 :inline t 143 :inline t
146 (const :tag "Size Limit" sizelimit) 144 (const :tag "Size Limit" sizelimit)
147 (integer :tag "(number of records)"))))) 145 (integer :tag "(number of records)"))))))
148 :group 'ldap)
149 146
150(defcustom ldap-ldapsearch-prog "ldapsearch" 147(defcustom ldap-ldapsearch-prog "ldapsearch"
151 "The name of the ldapsearch command line program." 148 "The name of the ldapsearch command line program."
152 :type '(string :tag "`ldapsearch' Program") 149 :type '(string :tag "`ldapsearch' Program"))
153 :group 'ldap)
154 150
155(defcustom ldap-ldapsearch-args '("-LL" "-tt") 151(defcustom ldap-ldapsearch-args '("-LL" "-tt")
156 "A list of additional arguments to pass to `ldapsearch'." 152 "A list of additional arguments to pass to `ldapsearch'."
157 :type '(repeat :tag "`ldapsearch' Arguments" 153 :type '(repeat :tag "`ldapsearch' Arguments"
158 (string :tag "Argument")) 154 (string :tag "Argument")))
159 :group 'ldap) 155
156(defcustom ldap-ldapsearch-password-prompt-regexp "Enter LDAP Password: "
157 "A regular expression used to recognize the `ldapsearch'
158program's password prompt."
159 :type 'regexp
160 :version "25.1")
160 161
161(defcustom ldap-ignore-attribute-codings nil 162(defcustom ldap-ignore-attribute-codings nil
162 "If non-nil, do not encode/decode LDAP attribute values." 163 "If non-nil, do not encode/decode LDAP attribute values."
163 :type 'boolean 164 :type 'boolean)
164 :group 'ldap)
165 165
166(defcustom ldap-default-attribute-decoder nil 166(defcustom ldap-default-attribute-decoder nil
167 "Decoder function to use for attributes whose syntax is unknown." 167 "Decoder function to use for attributes whose syntax is unknown."
168 :type 'symbol 168 :type 'symbol)
169 :group 'ldap)
170 169
171(defcustom ldap-coding-system 'utf-8 170(defcustom ldap-coding-system 'utf-8
172 "Coding system of LDAP string values. 171 "Coding system of LDAP string values.
173LDAP v3 specifies the coding system of strings to be UTF-8." 172LDAP v3 specifies the coding system of strings to be UTF-8."
174 :type 'symbol 173 :type 'symbol)
175 :group 'ldap)
176 174
177(defvar ldap-attribute-syntax-encoders 175(defvar ldap-attribute-syntax-encoders
178 [nil ; 1 ACI Item N 176 [nil ; 1 ACI Item N
@@ -476,6 +474,47 @@ Additional search parameters can be specified through
476 (mapcar 'ldap-decode-attribute record)) 474 (mapcar 'ldap-decode-attribute record))
477 result)))) 475 result))))
478 476
477(defun ldap-password-read (host)
478 "Read LDAP password for HOST.
479If the password is cached, it is read from the cache, otherwise the user
480is prompted for the password. If `password-cache' is non-nil the password
481is verified and cached. The `password-cache-expiry' variable
482controls for how long the password is cached.
483
484This function can be specified for the `passwd' property in
485`ldap-host-parameters-alist' when interactive password prompting
486is desired for HOST."
487 ;; Add ldap: namespace to allow empty string for default host.
488 (let* ((host-key (concat "ldap:" host))
489 (password (password-read
490 (format "Enter LDAP Password%s: "
491 (if (equal host "")
492 ""
493 (format " for %s" host)))
494 host-key)))
495 (when (and password-cache
496 (not (password-in-cache-p host-key))
497 ;; Confirm the password is valid before adding it to
498 ;; the password cache. ldap-search-internal will throw
499 ;; an error if the password is invalid.
500 (not (ldap-search-internal
501 `(host ,host
502 ;; Specify an arbitrary filter that should
503 ;; produce no results, since only
504 ;; authentication success is of interest.
505 filter "emacs-test-password="
506 attributes nil
507 attrsonly nil
508 withdn nil
509 ;; Preempt passwd ldap-password-read
510 ;; setting in ldap-host-parameters-alist.
511 passwd ,password
512 ,@(cdr
513 (assoc
514 host
515 ldap-host-parameters-alist))))))
516 (password-cache-add host-key password))
517 password))
479 518
480(defun ldap-search-internal (search-plist) 519(defun ldap-search-internal (search-plist)
481 "Perform a search on a LDAP server. 520 "Perform a search on a LDAP server.
@@ -531,7 +570,11 @@ an alist of attribute/value pairs."
531 (passwd (or (plist-get search-plist 'passwd) 570 (passwd (or (plist-get search-plist 'passwd)
532 (plist-get asfound :secret))) 571 (plist-get asfound :secret)))
533 ;; convert the password from a function call if needed 572 ;; convert the password from a function call if needed
534 (passwd (if (functionp passwd) (funcall passwd) passwd)) 573 (passwd (if (functionp passwd)
574 (if (eq passwd 'ldap-password-read)
575 (funcall passwd host)
576 (funcall passwd))
577 passwd))
535 ;; get the binddn from the search-list or from the 578 ;; get the binddn from the search-list or from the
536 ;; auth-source user or binddn tokens 579 ;; auth-source user or binddn tokens
537 (binddn (or (plist-get search-plist 'binddn) 580 (binddn (or (plist-get search-plist 'binddn)
@@ -550,7 +593,7 @@ an alist of attribute/value pairs."
550 (sizelimit (plist-get search-plist 'sizelimit)) 593 (sizelimit (plist-get search-plist 'sizelimit))
551 (withdn (plist-get search-plist 'withdn)) 594 (withdn (plist-get search-plist 'withdn))
552 (numres 0) 595 (numres 0)
553 arglist dn name value record result) 596 arglist dn name value record result proc)
554 (if (or (null filter) 597 (if (or (null filter)
555 (equal "" filter)) 598 (equal "" filter))
556 (error "No search filter")) 599 (error "No search filter"))
@@ -559,7 +602,13 @@ an alist of attribute/value pairs."
559 (erase-buffer) 602 (erase-buffer)
560 (if (and host 603 (if (and host
561 (not (equal "" host))) 604 (not (equal "" host)))
562 (setq arglist (nconc arglist (list (format "-h%s" host))))) 605 (setq arglist (nconc arglist
606 (list (format
607 ;; Use -H if host is a new-style LDAP URI.
608 (if (string-match "^[a-zA-Z]+://" host)
609 "-H%s"
610 "-h%s")
611 host)))))
563 (if (and attrsonly 612 (if (and attrsonly
564 (not (equal "" attrsonly))) 613 (not (equal "" attrsonly)))
565 (setq arglist (nconc arglist (list "-A")))) 614 (setq arglist (nconc arglist (list "-A"))))
@@ -575,9 +624,9 @@ an alist of attribute/value pairs."
575 (if (and auth 624 (if (and auth
576 (equal 'simple auth)) 625 (equal 'simple auth))
577 (setq arglist (nconc arglist (list "-x")))) 626 (setq arglist (nconc arglist (list "-x"))))
578 (if (and passwd 627 ;; Allow passwd to be set to "", representing a blank password.
579 (not (equal "" passwd))) 628 (if passwd
580 (setq arglist (nconc arglist (list (format "-w%s" passwd))))) 629 (setq arglist (nconc arglist (list "-W"))))
581 (if (and deref 630 (if (and deref
582 (not (equal "" deref))) 631 (not (equal "" deref)))
583 (setq arglist (nconc arglist (list (format "-a%s" deref))))) 632 (setq arglist (nconc arglist (list (format "-a%s" deref)))))
@@ -587,14 +636,43 @@ an alist of attribute/value pairs."
587 (if (and sizelimit 636 (if (and sizelimit
588 (not (equal "" sizelimit))) 637 (not (equal "" sizelimit)))
589 (setq arglist (nconc arglist (list (format "-z%s" sizelimit))))) 638 (setq arglist (nconc arglist (list (format "-z%s" sizelimit)))))
590 (apply #'call-process ldap-ldapsearch-prog 639 (if passwd
591 ;; Ignore stderr, which can corrupt results 640 (let* ((process-connection-type nil)
592 nil (list buf nil) nil 641 (proc-args (append arglist ldap-ldapsearch-args
593 (append arglist ldap-ldapsearch-args filter)) 642 filter))
643 (proc (apply #'start-process "ldapsearch" buf
644 ldap-ldapsearch-prog
645 proc-args)))
646 (while (null (progn
647 (goto-char (point-min))
648 (re-search-forward
649 ldap-ldapsearch-password-prompt-regexp
650 (point-max) t)))
651 (accept-process-output proc 1))
652 (process-send-string proc passwd)
653 (process-send-string proc "\n")
654 (while (not (memq (process-status proc) '(exit signal)))
655 (sit-for 0.1))
656 (let ((status (process-exit-status proc)))
657 (when (not (eq status 0))
658 ;; Handle invalid credentials exit status specially
659 ;; for ldap-password-read.
660 (if (eq status 49)
661 (error (concat "Incorrect LDAP password or"
662 " bind distinguished name (binddn)"))
663 (error "Failed ldapsearch invocation: %s \"%s\""
664 ldap-ldapsearch-prog
665 (mapconcat 'identity proc-args "\" \""))))))
666 (apply #'call-process ldap-ldapsearch-prog
667 ;; Ignore stderr, which can corrupt results
668 nil (list buf nil) nil
669 (append arglist ldap-ldapsearch-args filter)))
594 (insert "\n") 670 (insert "\n")
595 (goto-char (point-min)) 671 (goto-char (point-min))
596 672
597 (while (re-search-forward "[\t\n\f]+ " nil t) 673 (while (re-search-forward (concat "[\t\n\f]+ \\|"
674 ldap-ldapsearch-password-prompt-regexp)
675 nil t)
598 (replace-match "" nil nil)) 676 (replace-match "" nil nil))
599 (goto-char (point-min)) 677 (goto-char (point-min))
600 678