]> git.sur5r.net Git - openldap/blob - clients/rcpt500/query.c
Merge in all devel changes since 2.0-alpha2.
[openldap] / clients / rcpt500 / query.c
1 /* $OpenLDAP$ */
2 /*
3  * query.c: for rcpt500 (X.500 email query responder)
4  *
5  * 18 June 1992 by Mark C Smith
6  * Copyright (c) 1992 The Regents of The University of Michigan
7  * All Rights Reserved
8  */
9
10 #include "portable.h"
11
12 #include <ac/stdlib.h>
13
14 #include <ac/ctype.h>
15 #include <ac/string.h>
16 #include <ac/syslog.h>
17 #include <ac/time.h>
18
19 #include <stdio.h>
20
21 #include <ldap.h>
22 #include <disptmpl.h>
23
24 #include "rcpt500.h"
25 #include "ldap_defaults.h"
26
27 static char buf[ MAXSIZE ];
28 static char *errpreface = "Your query failed: ";
29
30 static void close_ldap(LDAP *ld);
31 static void append_entry_list(char *rep, char *qu, LDAP *ld, LDAPMessage *msg);
32 static int  append_text(void *reply, char *text, ber_len_t len);
33 static int  do_read (LDAP *ld, char *dn, char *rep, struct ldap_disptmpl *tmp);
34 static void report_ldap_err (LDAP *ldp, char *reply);
35 static void remove_trailing_space (char *s);
36
37
38 int
39 query_cmd( struct msginfo *msgp, char *reply )
40 {
41     LDAP                        *ldp;
42     LDAPMessage                 *ldmsgp, *entry;
43     char                        *dn;
44     int                         matches, rc, ld_errno, ufn;
45     LDAPFiltDesc                *lfdp;
46     LDAPFiltInfo                *lfi;
47     struct ldap_disptmpl        *tmpllist = NULL;
48     static char *attrs[] = { "cn", "title",
49 #ifdef RCPT500_SORT_ATTR
50                         RCPT500_SORT_ATTR,
51 #endif
52                         NULL };
53
54     ufn = 0;
55
56     if ( msgp->msg_arg == NULL ) {
57         return( help_cmd( msgp, reply ));
58     }
59
60     remove_trailing_space( msgp->msg_arg );
61     if ( *msgp->msg_arg == '\0' ) {
62         return( help_cmd( msgp, reply ));
63     }
64
65     if (( lfdp = ldap_init_getfilter( filterfile )) == NULL ) {
66         strcat( reply, errpreface );
67         strcat( reply, "filter file configuration error.  Try again later." );
68         return( 0 );
69     }
70
71     /*
72      * open connection to LDAP server and bind as dapuser
73      */
74 #ifdef LDAP_CONNECTIONLESS
75     if ( do_cldap )
76         ldp = cldap_open( ldaphost, ldapport );
77     else
78 #endif /* LDAP_CONNECTIONLESS */
79         ldp = ldap_init( ldaphost, ldapport );
80
81     if ( ldp == NULL ) {
82         strcat( reply, errpreface );
83         strcat( reply, "X.500 service unavailable.  Try again later." );
84         ldap_getfilter_free( lfdp );
85         return( 0 );
86     }
87
88 #ifdef LDAP_CONNECTIONLESS
89     if ( !do_cldap )
90 #endif /* LDAP_CONNECTIONLESS */
91         if ( ldap_simple_bind_s( ldp, dapuser, NULL ) != LDAP_SUCCESS ) {
92             report_ldap_err( ldp, reply );
93             close_ldap( ldp );
94             ldap_getfilter_free( lfdp );
95             return( 0 );
96         }
97
98     /*
99      * set options for search and build filter
100      */
101         ldap_set_option(ldp, LDAP_OPT_DEREF, &derefaliases);
102         ldap_set_option(ldp, LDAP_OPT_SIZELIMIT, &sizelimit);
103
104     matches = 0;
105
106 #ifdef RCPT500_UFN
107 #ifdef LDAP_CONNECTIONLESS
108     if ( !do_cldap && strchr( msgp->msg_arg, ',' ) != NULL ) {
109 #else /* LDAP_CONNECTIONLESS */
110     if ( strchr( msgp->msg_arg, ',' ) != NULL ) {
111 #endif /* LDAP_CONNECTIONLESS */
112         struct timeval  tv;
113
114         ldap_ufn_setprefix( ldp, searchbase );
115         if (( rc = ldap_ufn_search_s( ldp, msgp->msg_arg, attrs, 0, &ldmsgp ))
116                 != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
117                 && rc != LDAP_TIMELIMIT_EXCEEDED ) {
118             report_ldap_err( ldp, reply );
119             close_ldap( ldp );
120             ldap_getfilter_free( lfdp );
121             return( 0 );
122         }
123         matches = ldap_count_entries( ldp, ldmsgp );
124         ufn = 1;
125     } else {
126 #endif /* RCPT500_UFN */
127     
128         for ( lfi = ldap_getfirstfilter( lfdp, "rcpt500", msgp->msg_arg );
129                 lfi != NULL; lfi = ldap_getnextfilter( lfdp )) {
130 #ifdef LDAP_CONNECTIONLESS
131             if ( do_cldap )
132                 rc = cldap_search_s( ldp, searchbase, LDAP_SCOPE_SUBTREE,
133                         lfi->lfi_filter, attrs, 0, &ldmsgp, dapuser );
134             else 
135 #endif /* LDAP_CONNECTIONLESS */
136                 rc = ldap_search_s( ldp, searchbase, LDAP_SCOPE_SUBTREE,
137                         lfi->lfi_filter, attrs, 0, &ldmsgp );
138
139             if ( rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
140                     && rc != LDAP_TIMELIMIT_EXCEEDED ) {
141                 report_ldap_err( ldp, reply );
142                 close_ldap( ldp );
143                 ldap_getfilter_free( lfdp );
144                 return( 0 );
145             }
146
147             if (( matches = ldap_count_entries( ldp, ldmsgp )) != 0 ) {
148                 break;
149             }
150
151             if ( ldmsgp != NULL ) {
152                 ldap_msgfree( ldmsgp );
153             }
154         }
155 #ifdef RCPT500_UFN
156     }
157 #endif /* RCPT500_UFN */
158
159     if ( matches == 0 ) {
160         sprintf( buf, "No matches were found for '%s'\n", msgp->msg_arg );
161         strcat( reply, buf );
162         close_ldap( ldp );
163         ldap_getfilter_free( lfdp );
164         return( 0 );
165     }
166
167         ld_errno = 0;
168         ldap_get_option(ldp, LDAP_OPT_ERROR_NUMBER, &ld_errno);
169
170     if ( ld_errno == LDAP_TIMELIMIT_EXCEEDED
171             || ld_errno == LDAP_SIZELIMIT_EXCEEDED ) {
172         strcat( reply, "(Partial results only - a limit was exceeded)\n" );
173     }
174
175     if ( matches <= RCPT500_LISTLIMIT ) {
176         sprintf( buf, "%d %s match%s found for '%s':\n\n", matches,
177                 ufn ? "UFN" : lfi->lfi_desc,
178                 ( matches > 1 ) ? "es" : "", msgp->msg_arg );
179         strcat( reply, buf );
180
181         if (( rc = ldap_init_templates( templatefile, &tmpllist )) != 0 ) {
182             sprintf( buf, "%s ldap_init_templates( %s ) failed (error %d)\n",
183                 errpreface, templatefile, rc );
184             strcat( reply, buf );
185         }
186
187         for ( entry = ldap_first_entry( ldp, ldmsgp ); entry != NULL; ) {
188             dn = ldap_get_dn( ldp, entry );
189             if ( do_read( ldp, dn, reply, tmpllist ) != LDAP_SUCCESS ) {
190                 report_ldap_err( ldp, reply );
191             }
192             free( dn );
193             if (( entry = ldap_next_entry( ldp, entry )) != NULL ) {
194                 strcat( reply, "\n-------\n\n" );
195             }
196         }
197
198         if ( tmpllist != NULL ) {
199             ldap_free_templates( tmpllist );
200         }
201         ldap_msgfree( ldmsgp );
202
203     } else {
204         sprintf( buf, "%d %s matches were found for '%s':\n",
205                 matches, ufn ? "UFN" : lfi->lfi_desc, msgp->msg_arg );
206         strcat( reply, buf );
207         append_entry_list( reply, msgp->msg_arg, ldp, ldmsgp );
208         ldap_msgfree( ldmsgp );
209     }
210
211     close_ldap( ldp );
212     ldap_getfilter_free( lfdp );
213     return( 0 );
214 }
215
216
217 static void
218 close_ldap( LDAP *ld )
219 {
220 #ifdef LDAP_CONNECTIONLESS
221     if ( do_cldap )
222         cldap_close( ld );
223     else
224 #endif /* LDAP_CONNECTIONLESS */
225         ldap_unbind( ld );
226 }
227
228
229 static void
230 append_entry_list( char *reply, char *query, LDAP *ldp, LDAPMessage *ldmsgp )
231 {
232     LDAPMessage *e;
233     char        *dn, *rdn, *s, **title;
234     int         free_rdn = 0;
235
236 #ifdef RCPT500_SORT_ATTR
237     ldap_sort_entries( ldp, &ldmsgp, RCPT500_SORT_ATTR, strcasecmp );
238 #endif
239
240     for ( e = ldap_first_entry( ldp, ldmsgp ); e != NULL;
241                 e = ldap_next_entry( ldp, e )) {
242         dn = ldap_get_dn( ldp, e );
243         if (( s = strchr( dn, ',' )) != NULL ) {
244             *s = '\0';
245         }
246         if (( s = strchr( dn, '=' )) == NULL ) {
247             rdn = dn;
248         } else {
249             rdn = s + 1;
250         }
251
252 #ifdef UOFM
253         /*
254          * if this entry's rdn is an exact match for the thing looked up, we
255          * return the CN that has a digit after it, so that the user is
256          * returned something guaranteed to yield exactly one match if they
257          * pick it from the list and query it
258          */
259
260         if ( strcasecmp( rdn, query ) == 0 ) {
261             char        **cn;
262             int         i;
263
264             if (( cn = ldap_get_values( ldp, e, "cn" )) != NULL ) {
265                 for ( i = 0; cn[i] != NULL; i++ ) {
266                     if ( isdigit((unsigned char) cn[i][strlen( cn[i] ) - 1])) {
267                         rdn = strdup( cn[i] );
268                         free_rdn = 1;
269                         break;
270                     }
271                 }
272                 ldap_value_free( cn );
273             }
274         }
275 #endif /* UOFM */
276
277         title = ldap_get_values( ldp, e, "title" );
278         sprintf( buf, "  %-20s    %s\n", rdn, title ? title[0] : "" );
279         strcat( reply, buf );
280         if ( title != NULL ) {
281             ldap_value_free( title );
282         }
283         free( dn );
284         if ( free_rdn ) {
285             free( rdn );
286         }
287     }
288 }
289
290
291 static int
292 append_text( void *reply, char *text, ber_len_t len )
293 {
294     strcat( (char *) reply, text );
295     return( len );
296 }
297     
298
299 static int
300 do_read( LDAP *ldp, char *dn, char *reply, struct ldap_disptmpl *tmpll )
301 {
302     int                         rc;
303     static char *maildefvals[] = { "None registered in this service", NULL };
304     static char *defattrs[] = { "mail", NULL };
305     static char **defvals[] = { maildefvals, NULL };
306
307
308     rc = ldap_entry2text_search( ldp, dn, searchbase, NULL, tmpll,
309             defattrs, defvals, append_text, (void *)reply, "\n",
310             rdncount, LDAP_DISP_OPT_DOSEARCHACTIONS );
311
312     return( rc );
313 }
314
315
316 static void
317 report_ldap_err( LDAP *ldp, char *reply )
318 {
319         int ld_errno = 0;
320         ldap_get_option(ldp, LDAP_OPT_ERROR_NUMBER, &ld_errno);
321
322     strcat( reply, errpreface );
323     strcat( reply, ldap_err2string( ld_errno ));
324     strcat( reply, "\n" );
325 }
326
327
328 static void
329 remove_trailing_space( char *s )
330 {
331     char        *p = s + strlen( s ) - 1;
332
333     while ( isspace( (unsigned char) *p ) && p > s ) {
334         --p;
335     }
336     *(++p) = '\0';
337 }