comparison src/eldap.c @ 282:c42ec1d1cded r21-0b39

Import from CVS: tag r21-0b39
author cvs
date Mon, 13 Aug 2007 10:33:18 +0200
parents 7df0dd720c89
children 57709be46d1b
comparison
equal deleted inserted replaced
281:090b52736db2 282:c42ec1d1cded
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */ 19 Boston, MA 02111-1307, USA. */
20 20
21 /* Synched up with: Not in FSF. */ 21 /* Synched up with: Not in FSF. */
22 22
23 /* Author: Oscar Figueiredo */ 23 /* Author: Oscar Figueiredo with lots of support from Hrvoje Niksic */
24 24
25 /* This file provides lisp primitives for access to an LDAP library 25 /* This file provides lisp primitives for access to an LDAP library
26 conforming to the API defined in RFC 1823. 26 conforming to the API defined in RFC 1823.
27 It has been tested with: 27 It has been tested with:
28 - UMich LDAP 3.3 (http://www.umich.edu/~dirsvcs/ldap/) 28 - UMich LDAP 3.3 (http://www.umich.edu/~dirsvcs/ldap/)
38 #include <ldap.h> 38 #include <ldap.h>
39 39
40 #include "eldap.h" 40 #include "eldap.h"
41 41
42 #ifdef HAVE_NS_LDAP 42 #ifdef HAVE_NS_LDAP
43 #define HAVE_LDAP_SET_OPTION 1 43 # define HAVE_LDAP_SET_OPTION 1
44 #define HAVE_LDAP_GET_ERRNO 1 44 # define HAVE_LDAP_GET_ERRNO 1
45 #else 45 #else
46 #undef HAVE_LDAP_SET_OPTION 46 # undef HAVE_LDAP_SET_OPTION
47 #undef HAVE_LDAP_GET_ERRNO 47 # undef HAVE_LDAP_GET_ERRNO
48 #endif 48 #endif
49 49
50 static int ldap_default_port; 50 static int ldap_default_port;
51 static Lisp_Object Vldap_default_base; 51 static Lisp_Object Vldap_default_base;
52
53 /* Needed by the lrecord definition */
54 Lisp_Object Qldapp;
52 55
53 /* ldap-open plist keywords */ 56 /* ldap-open plist keywords */
54 extern Lisp_Object Qport, Qauth, Qbinddn, Qpasswd, Qderef, Qtimelimit, 57 extern Lisp_Object Qport, Qauth, Qbinddn, Qpasswd, Qderef, Qtimelimit,
55 Qsizelimit; 58 Qsizelimit;
56 /* Search scope limits */ 59 /* Search scope limits */
57 extern Lisp_Object Qbase, Qonelevel, Qsubtree; 60 extern Lisp_Object Qbase, Qonelevel, Qsubtree;
58 /* Authentication methods */ 61 /* Authentication methods */
59 #ifdef LDAP_AUTH_KRBV41 62 extern Lisp_Object Qkrbv41, Qkrbv42;
60 extern Lisp_Object Qkrbv41;
61 #endif
62 #ifdef LDAP_AUTH_KRBV42
63 extern Lisp_Object Qkrbv42;
64 #endif
65 /* Deref policy */ 63 /* Deref policy */
66 extern Lisp_Object Qnever, Qalways, Qfind; 64 extern Lisp_Object Qnever, Qalways, Qfind;
67 /* Connection status */
68 extern Lisp_Object Qopen, Qclosed;
69
70 static Lisp_Object Qldapp;
71
72 65
73 /************************************************************************/ 66 /************************************************************************/
74 /* Utility Functions */ 67 /* Utility Functions */
75 /************************************************************************/ 68 /************************************************************************/
76 69
77 static void 70 static void
78 signal_ldap_error (LDAP *ld) 71 signal_ldap_error (LDAP *ld)
79 { 72 {
80 #if HAVE_LDAP_GET_ERRNO 73 #ifdef HAVE_LDAP_GET_ERRNO
81 signal_simple_error 74 signal_simple_error
82 ("LDAP error", 75 ("LDAP error",
83 build_string (ldap_err2string (ldap_get_lderrno (ld, NULL, NULL)))); 76 build_string (ldap_err2string (ldap_get_lderrno (ld, NULL, NULL))));
84 #else 77 #else
85 signal_simple_error ("LDAP error", 78 signal_simple_error ("LDAP error",
102 struct lcrecord_header header; 95 struct lcrecord_header header;
103 /* The LDAP connection handle used by the LDAP API */ 96 /* The LDAP connection handle used by the LDAP API */
104 LDAP *ld; 97 LDAP *ld;
105 /* Name of the host we connected to */ 98 /* Name of the host we connected to */
106 Lisp_Object host; 99 Lisp_Object host;
107 /* Status of the LDAP connection. 100 /* Status of the LDAP connection. */
108 This is a symbol: open or closed */ 101 int livep;
109 Lisp_Object status_symbol;
110 }; 102 };
111 103
112 104
105 static Lisp_Object
106 make_ldap (struct Lisp_LDAP *ldap)
107 {
108 Lisp_Object lisp_ldap;
109 XSETLDAP (lisp_ldap, ldap);
110 return lisp_ldap;
111 }
113 112
114 static Lisp_Object 113 static Lisp_Object
115 mark_ldap (Lisp_Object obj, void (*markobj) (Lisp_Object)) 114 mark_ldap (Lisp_Object obj, void (*markobj) (Lisp_Object))
116 { 115 {
117 struct Lisp_LDAP *ldap = XLDAP (obj); 116 return XLDAP (obj)->host;
118 ((markobj) (ldap->host));
119 return ldap->status_symbol;
120 } 117 }
121 118
122 static void 119 static void
123 print_ldap (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) 120 print_ldap (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
124 { 121 {
125 char buf[16]; 122 char buf[32];
126 123
127 struct Lisp_LDAP *ldap = XLDAP (obj); 124 struct Lisp_LDAP *ldap = XLDAP (obj);
128 125
129 if (print_readably) 126 if (print_readably)
130 error ("printing unreadable object #<ldap %s>", 127 error ("printing unreadable object #<ldap %s>",
131 XSTRING_DATA (ldap->host)); 128 XSTRING_DATA (ldap->host));
132 129
133 write_c_string ("#<ldap ", printcharfun); 130 write_c_string ("#<ldap ", printcharfun);
134 print_internal (ldap->host, printcharfun, 1); 131 print_internal (ldap->host, printcharfun, 1);
135 write_c_string (" state:",printcharfun); 132 if (!ldap->livep)
136 print_internal (ldap->status_symbol, printcharfun, 1); 133 write_c_string ("(dead) ",printcharfun);
137 sprintf (buf, " 0x%x>", ldap); 134 sprintf (buf, " 0x%x>", ldap);
138 write_c_string (buf, printcharfun); 135 write_c_string (buf, printcharfun);
139 } 136 }
140 137
141 static struct Lisp_LDAP * 138 static struct Lisp_LDAP *
142 allocate_ldap (void) 139 allocate_ldap (void)
143 { 140 {
144 struct Lisp_LDAP *ldap = 141 struct Lisp_LDAP *ldap =
145 alloc_lcrecord_type (struct Lisp_LDAP, lrecord_ldap); 142 alloc_lcrecord_type (struct Lisp_LDAP, lrecord_ldap);
146 143
147 ldap->ld = (LDAP *) NULL; 144 ldap->ld = NULL;
148 ldap->host = Qnil; 145 ldap->host = Qnil;
149 ldap->status_symbol = Qnil; 146 ldap->livep = 0;
150 return ldap; 147 return ldap;
151 } 148 }
152 149
153 static void 150 static void
154 finalize_ldap (void *header, int for_disksave) 151 finalize_ldap (void *header, int for_disksave)
155 { 152 {
156 struct Lisp_LDAP *ldap = (struct Lisp_LDAP *) header; 153 struct Lisp_LDAP *ldap = (struct Lisp_LDAP *) header;
157 154
158 if (for_disksave) 155 if (for_disksave)
159 { 156 signal_simple_error ("Can't dump an emacs containing LDAP objects",
160 Lisp_Object obj; 157 make_ldap (ldap));
161 XSETLDAP (obj, ldap); 158
162 signal_simple_error 159 if (ldap->livep)
163 ("Can't dump an emacs containing LDAP objects", obj);
164 }
165 if (EQ (ldap->status_symbol, Qopen))
166 ldap_unbind (ldap->ld); 160 ldap_unbind (ldap->ld);
167 } 161 }
168 162
169 DEFINE_LRECORD_IMPLEMENTATION ("ldap", ldap, 163 DEFINE_LRECORD_IMPLEMENTATION ("ldap", ldap,
170 mark_ldap, print_ldap, finalize_ldap, 164 mark_ldap, print_ldap, finalize_ldap,
183 (object)) 177 (object))
184 { 178 {
185 return LDAPP (object) ? Qt : Qnil; 179 return LDAPP (object) ? Qt : Qnil;
186 } 180 }
187 181
188
189 DEFUN ("ldap-host", Fldap_host, 1, 1, 0, /* 182 DEFUN ("ldap-host", Fldap_host, 1, 1, 0, /*
190 Return the server host of the connection LDAP, as a string. 183 Return the server host of the connection LDAP, as a string.
191 */ 184 */
192 (ldap)) 185 (ldap))
193 { 186 {
194 CHECK_LDAP (ldap); 187 CHECK_LDAP (ldap);
195 return (XLDAP (ldap))->host; 188 return (XLDAP (ldap))->host;
196 } 189 }
197 190
198 191 DEFUN ("ldap-live-p", Fldap_status, 1, 1, 0, /*
199 192 Return t if LDAP is an active LDAP connection.
200 DEFUN ("ldap-status", Fldap_status, 1, 1, 0, /*
201 Return the status of the connection LDAP.
202 This is a symbol, one of these:
203
204 open -- for a LDAP connection that is open.
205 closed -- for a LDAP connection that is closed.
206 */ 193 */
207 (ldap)) 194 (ldap))
208 { 195 {
209 CHECK_LDAP (ldap); 196 CHECK_LDAP (ldap);
210 return (XLDAP (ldap))->status_symbol; 197 return (XLDAP (ldap))->livep ? Qt : Qnil;
211 } 198 }
212
213
214 199
215 /************************************************************************/ 200 /************************************************************************/
216 /* Opening/Closing a LDAP connection */ 201 /* Opening/Closing a LDAP connection */
217 /************************************************************************/ 202 /************************************************************************/
218 203
231 `timelimit' is the timeout limit for the connection in seconds. 216 `timelimit' is the timeout limit for the connection in seconds.
232 `sizelimit' is the maximum number of matches to return. 217 `sizelimit' is the maximum number of matches to return.
233 */ 218 */
234 (host, plist)) 219 (host, plist))
235 { 220 {
236 /* This function can call lisp */ 221 /* This function can GC */
237 222 struct Lisp_LDAP *ldap;
238 struct Lisp_LDAP *lisp_ldap;
239 LDAP *ld; 223 LDAP *ld;
240 int ldap_port = 0; 224 int ldap_port = 0;
241 int ldap_auth = LDAP_AUTH_SIMPLE; 225 int ldap_auth = LDAP_AUTH_SIMPLE;
242 char *ldap_binddn = NULL; 226 char *ldap_binddn = NULL;
243 char *ldap_passwd = NULL; 227 char *ldap_passwd = NULL;
244 int ldap_deref = LDAP_DEREF_NEVER; 228 int ldap_deref = LDAP_DEREF_NEVER;
245 int ldap_timelimit = 0; 229 int ldap_timelimit = 0;
246 int ldap_sizelimit = 0; 230 int ldap_sizelimit = 0;
247 int err; 231 int err;
248 232
249 Lisp_Object ldap, list, keyword, value; 233 Lisp_Object list, keyword, value;
250 struct gcpro gcpro1;
251
252 ldap = Qnil;
253 GCPRO1 (ldap);
254 234
255 CHECK_STRING (host); 235 CHECK_STRING (host);
256 236
257 EXTERNAL_PROPERTY_LIST_LOOP(list, keyword, value, plist) 237 EXTERNAL_PROPERTY_LIST_LOOP (list, keyword, value, plist)
258 { 238 {
259 /* TCP Port */ 239 /* TCP Port */
260 if (EQ (keyword, Qport)) 240 if (EQ (keyword, Qport))
261 { 241 {
262 CHECK_INT (value); 242 CHECK_INT (value);
263 ldap_port = XINT (value); 243 ldap_port = XINT (value);
264 } 244 }
265 /* Authentication method */ 245 /* Authentication method */
266 if (EQ (keyword, Qauth)) 246 if (EQ (keyword, Qauth))
267 { 247 {
268 CHECK_SYMBOL (value);
269
270 if (EQ (value, Qsimple)) 248 if (EQ (value, Qsimple))
271 ldap_auth = LDAP_AUTH_SIMPLE; 249 ldap_auth = LDAP_AUTH_SIMPLE;
272 #ifdef LDAP_AUTH_KRBV41 250 #ifdef LDAP_AUTH_KRBV41
273 else if (EQ (value, Qkrbv41)) 251 else if (EQ (value, Qkrbv41))
274 ldap_auth = LDAP_AUTH_KRBV41; 252 ldap_auth = LDAP_AUTH_KRBV41;
295 strcpy (ldap_passwd, (char *)XSTRING_DATA (value)); 273 strcpy (ldap_passwd, (char *)XSTRING_DATA (value));
296 } 274 }
297 /* Deref */ 275 /* Deref */
298 else if (EQ (keyword, Qderef)) 276 else if (EQ (keyword, Qderef))
299 { 277 {
300 CHECK_SYMBOL (value);
301 if (EQ (value, Qnever)) 278 if (EQ (value, Qnever))
302 ldap_deref = LDAP_DEREF_NEVER; 279 ldap_deref = LDAP_DEREF_NEVER;
303 else if (EQ (value, Qsearch)) 280 else if (EQ (value, Qsearch))
304 ldap_deref = LDAP_DEREF_SEARCHING; 281 ldap_deref = LDAP_DEREF_SEARCHING;
305 else if (EQ (value, Qfind)) 282 else if (EQ (value, Qfind))
356 #else /* not LDAP_REFERRALS */ 333 #else /* not LDAP_REFERRALS */
357 ld->ld_options = 0; 334 ld->ld_options = 0;
358 #endif /* not LDAP_REFERRALS */ 335 #endif /* not LDAP_REFERRALS */
359 #endif /* not HAVE_LDAP_SET_OPTION */ 336 #endif /* not HAVE_LDAP_SET_OPTION */
360 337
361 /* ldap_bind_s calls select and may be wedged by spurious signals */ 338 /* ldap_bind_s calls select and may be wedged by SIGIO. */
362 slow_down_interrupts (); 339 slow_down_interrupts ();
363 err = ldap_bind_s (ld, ldap_binddn, ldap_passwd, ldap_auth); 340 err = ldap_bind_s (ld, ldap_binddn, ldap_passwd, ldap_auth);
364 speed_up_interrupts (); 341 speed_up_interrupts ();
365 if (err != LDAP_SUCCESS) 342 if (err != LDAP_SUCCESS)
366 signal_simple_error ("Failed binding to the server", 343 signal_simple_error ("Failed binding to the server",
367 build_string (ldap_err2string (err))); 344 build_string (ldap_err2string (err)));
368 345
369 lisp_ldap = allocate_ldap (); 346 ldap = allocate_ldap ();
370 lisp_ldap->ld = ld; 347 ldap->ld = ld;
371 lisp_ldap->host = host; 348 ldap->host = host;
372 lisp_ldap->status_symbol = Qopen; 349 ldap->livep = 1;
373 XSETLDAP (ldap,lisp_ldap); 350
374 351 return make_ldap (ldap);
375 UNGCPRO;
376 return ldap;
377 } 352 }
378 353
379 354
380 355
381 DEFUN ("ldap-close", Fldap_close, 1, 1, 0, /* 356 DEFUN ("ldap-close", Fldap_close, 1, 1, 0, /*
385 { 360 {
386 struct Lisp_LDAP *lldap; 361 struct Lisp_LDAP *lldap;
387 CHECK_LIVE_LDAP (ldap); 362 CHECK_LIVE_LDAP (ldap);
388 lldap = XLDAP (ldap); 363 lldap = XLDAP (ldap);
389 ldap_unbind (lldap->ld); 364 ldap_unbind (lldap->ld);
390 lldap->status_symbol = Qclosed; 365 lldap->livep = 0;
391 return Qnil; 366 return Qnil;
392 } 367 }
393 368
394 369
395 370
406 static Lisp_Object 381 static Lisp_Object
407 ldap_search_unwind (Lisp_Object unwind_obj) 382 ldap_search_unwind (Lisp_Object unwind_obj)
408 { 383 {
409 struct ldap_unwind_struct *unwind = 384 struct ldap_unwind_struct *unwind =
410 (struct ldap_unwind_struct *) get_opaque_ptr (unwind_obj); 385 (struct ldap_unwind_struct *) get_opaque_ptr (unwind_obj);
411 if (unwind->res != (LDAPMessage *)NULL) 386 if (unwind->res)
412 ldap_msgfree (unwind->res); 387 ldap_msgfree (unwind->res);
413 if (unwind->vals != (char **)NULL) 388 if (unwind->vals)
414 ldap_value_free (unwind->vals); 389 ldap_value_free (unwind->vals);
415 } 390 }
416 391
417 DEFUN ("ldap-search-internal", Fldap_search_internal, 2, 6, 0, /* 392 DEFUN ("ldap-search-internal", Fldap_search_internal, 2, 6, 0, /*
418 Perform a search on an open LDAP connection. 393 Perform a search on an open LDAP connection.
429 The function returns a list of matching entries. Each entry is itself 404 The function returns a list of matching entries. Each entry is itself
430 an alist of attribute/values. 405 an alist of attribute/values.
431 */ 406 */
432 (ldap, filter, base, scope, attrs, attrsonly)) 407 (ldap, filter, base, scope, attrs, attrsonly))
433 { 408 {
434 /* This function can call lisp */ 409 /* This function can GC */
435 410
436 /* Vars for query */ 411 /* Vars for query */
437 LDAP *ld; 412 LDAP *ld;
438 LDAPMessage *e; 413 LDAPMessage *e;
439 BerElement *ptr; 414 BerElement *ptr;
449 424
450 Lisp_Object list, entry, result; 425 Lisp_Object list, entry, result;
451 struct gcpro gcpro1, gcpro2, gcpro3; 426 struct gcpro gcpro1, gcpro2, gcpro3;
452 427
453 list = entry = result = Qnil; 428 list = entry = result = Qnil;
454 GCPRO3(list, entry, result); 429 GCPRO3 (list, entry, result);
455 430
456 unwind.res = (LDAPMessage *)NULL; 431 unwind.res = NULL;
457 unwind.vals = (char **)NULL; 432 unwind.vals = NULL;
458 433
459 /* Do all the parameter checking */ 434 /* Do all the parameter checking */
460 CHECK_LIVE_LDAP (ldap); 435 CHECK_LIVE_LDAP (ldap);
461 ld = (XLDAP (ldap))->ld; 436 ld = XLDAP (ldap)->ld;
462 437
463 /* Filter */ 438 /* Filter */
464 CHECK_STRING (filter); 439 CHECK_STRING (filter);
465 440
466 /* Search base */ 441 /* Search base */
474 } 449 }
475 450
476 /* Search scope */ 451 /* Search scope */
477 if (!NILP (scope)) 452 if (!NILP (scope))
478 { 453 {
479 CHECK_SYMBOL (scope);
480 if (EQ (scope, Qbase)) 454 if (EQ (scope, Qbase))
481 ldap_scope = LDAP_SCOPE_BASE; 455 ldap_scope = LDAP_SCOPE_BASE;
482 else if (EQ (scope, Qonelevel)) 456 else if (EQ (scope, Qonelevel))
483 ldap_scope = LDAP_SCOPE_ONELEVEL; 457 ldap_scope = LDAP_SCOPE_ONELEVEL;
484 else if (EQ (scope, Qsubtree)) 458 else if (EQ (scope, Qsubtree))
508 } 482 }
509 483
510 /* Attributes only ? */ 484 /* Attributes only ? */
511 CHECK_SYMBOL (attrsonly); 485 CHECK_SYMBOL (attrsonly);
512 486
513
514 /* Perform the search */ 487 /* Perform the search */
515 if (ldap_search (ld, 488 if (ldap_search (ld,
516 NILP (base) ? "" : (char *) XSTRING_DATA (base), 489 NILP (base) ? "" : (char *) XSTRING_DATA (base),
517 ldap_scope, 490 ldap_scope,
518 NILP (filter) ? "" : (char *) XSTRING_DATA (filter), 491 NILP (filter) ? "" : (char *) XSTRING_DATA (filter),
530 /* Build the results list */ 503 /* Build the results list */
531 matches = 0; 504 matches = 0;
532 505
533 /* ldap_result calls select() and can get wedged by EINTR signals */ 506 /* ldap_result calls select() and can get wedged by EINTR signals */
534 slow_down_interrupts (); 507 slow_down_interrupts ();
535 rc = ldap_result (ld, LDAP_RES_ANY, 0, NULL, &(unwind.res)); 508 rc = ldap_result (ld, LDAP_RES_ANY, 0, NULL, &unwind.res);
536 speed_up_interrupts (); 509 speed_up_interrupts ();
537 while ( rc == LDAP_RES_SEARCH_ENTRY ) 510 while (rc == LDAP_RES_SEARCH_ENTRY)
538 { 511 {
539 QUIT; 512 QUIT;
540 matches ++; 513 matches ++;
541 e = ldap_first_entry (ld, unwind.res); 514 e = ldap_first_entry (ld, unwind.res);
542 message ("Parsing results... %d", matches); 515 /* #### This call to message() is pretty fascist, because it
516 destroys the current echo area contents, even when invoked
517 from Lisp. It should use echo_area_message() instead, and
518 restore the old echo area contents later. */
519 message ("Parsing ldap results... %d", matches);
543 entry = Qnil; 520 entry = Qnil;
544 for (a= ldap_first_attribute (ld, e, &ptr); 521 for (a= ldap_first_attribute (ld, e, &ptr);
545 a != NULL; 522 a != NULL;
546 a= ldap_next_attribute (ld, e, ptr) ) 523 a= ldap_next_attribute (ld, e, ptr) )
547 { 524 {
548 list = Fcons (build_string (a), Qnil); 525 list = Fcons (build_string (a), Qnil);
549 unwind.vals = ldap_get_values (ld, e, a); 526 unwind.vals = ldap_get_values (ld, e, a);
550 if (unwind.vals != NULL) 527 if (unwind.vals != NULL)
551 { 528 {
552 for (i=0; unwind.vals[i]!=NULL; i++) 529 for (i = 0; unwind.vals[i] != NULL; i++)
553 { 530 {
554 list = Fcons (build_string (unwind.vals[i]), 531 list = Fcons (build_string (unwind.vals[i]),
555 list); 532 list);
556 } 533 }
557 } 534 }
558 entry = Fcons (Fnreverse (list), 535 entry = Fcons (Fnreverse (list),
559 entry); 536 entry);
560 ldap_value_free (unwind.vals); 537 ldap_value_free (unwind.vals);
561 unwind.vals = (char **)NULL; 538 unwind.vals = NULL;
562 } 539 }
563 result = Fcons (Fnreverse (entry), 540 result = Fcons (Fnreverse (entry),
564 result); 541 result);
565 ldap_msgfree (unwind.res); 542 ldap_msgfree (unwind.res);
566 unwind.res = (LDAPMessage *)NULL; 543 unwind.res = NULL;
567 544
568 slow_down_interrupts (); 545 slow_down_interrupts ();
569 rc = ldap_result (ld, LDAP_RES_ANY, 0, NULL, &(unwind.res)); 546 rc = ldap_result (ld, LDAP_RES_ANY, 0, NULL, &(unwind.res));
570 speed_up_interrupts (); 547 speed_up_interrupts ();
571 } 548 }
581 signal_ldap_error (ld); 558 signal_ldap_error (ld);
582 } 559 }
583 560
584 ldap_msgfree (unwind.res); 561 ldap_msgfree (unwind.res);
585 unwind.res = (LDAPMessage *)NULL; 562 unwind.res = (LDAPMessage *)NULL;
586 message ("Done."); 563 /* #### See above for calling message(). */
587 564 message ("Parsing ldap results... done");
588 result = Fnreverse (result);
589 clear_message ();
590 565
591 unbind_to (speccount, Qnil); 566 unbind_to (speccount, Qnil);
592 UNGCPRO; 567 UNGCPRO;
593 return result; 568 return Fnreverse (result);
594 } 569 }
595 570
596 571
597 void 572 void
598 syms_of_eldap (void) 573 syms_of_eldap (void)
599 { 574 {
600 defsymbol (&Qldapp, "ldapp"); 575 defsymbol (&Qldapp, "ldapp");
601
602 DEFSUBR (Fldapp); 576 DEFSUBR (Fldapp);
603 DEFSUBR (Fldap_host); 577 DEFSUBR (Fldap_host);
604 DEFSUBR (Fldap_status); 578 DEFSUBR (Fldap_status);
605 DEFSUBR (Fldap_open); 579 DEFSUBR (Fldap_open);
606 DEFSUBR (Fldap_close); 580 DEFSUBR (Fldap_close);