]> err.no Git - sope/blob - sope-ldap/NGLdap/NGLdapSearchResultEnumerator.m
ab282d0e97438fe8b92403916228ed5746049d4d
[sope] / sope-ldap / NGLdap / NGLdapSearchResultEnumerator.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "NGLdapSearchResultEnumerator.h"
23 #include "NGLdapConnection+Private.h"
24 #include "NGLdapAttribute.h"
25 #include "NGLdapEntry.h"
26 #include "common.h"
27
28 #include <sys/time.h>
29
30 @implementation NGLdapSearchResultEnumerator
31
32 - (id)initWithConnection:(NGLdapConnection *)_con messageID:(int)_mid {
33   self->connection = [_con retain];
34   self->handle     = [_con ldapHandle];
35   self->msgid      = _mid;
36   self->startTime  = [[NSDate date] timeIntervalSince1970];
37   return self;
38 }
39
40 - (void)dealloc {
41   [self->connection release];
42   [super dealloc];
43 }
44
45 /* state */
46
47 - (int)messageID {
48   return self->msgid;
49 }
50
51 - (NSTimeInterval)duration {
52   return [[NSDate date] timeIntervalSince1970] - self->startTime;
53 }
54
55 - (unsigned)index {
56   return self->index;
57 }
58
59 /* enumerator */
60
61 - (void)cancel {
62   if (self->handle) {
63     int res;
64     
65     res = ldap_abandon(self->handle, self->msgid);
66     
67     self->handle = NULL;
68     [self->connection release]; self->connection = nil;
69   }
70 }
71
72 - (NSArray *)_attributesFromResult:(LDAPMessage *)result {
73   NSMutableArray *attributes;
74   char           *attr;
75   BerElement     *ber;
76
77   attributes = [[NSMutableArray alloc] initWithCapacity:32];
78       
79   for (attr = ldap_first_attribute(self->handle, result, &ber);
80        attr != NULL;
81        free(attr), attr = ldap_next_attribute(self->handle, result, ber)) {
82     NSString        *key;
83     NGLdapAttribute *attribute;
84     struct berval   **values;
85     unsigned        valueCount;
86     NSArray         *ovalues;
87
88     if (!(key = [[NSString alloc] initWithCString:attr]))
89       /* missing attribute name */
90       continue;
91
92     /* process values */
93         
94     if ((values = ldap_get_values_len(self->handle, result, attr)) == NULL) {
95       ovalues = [[NSArray alloc] init];
96     }
97     else if ((valueCount = ldap_count_values_len(values)) == 1) {
98       NSData *value;
99           
100       value = [[NSData alloc] initWithBytes:values[0]->bv_val
101                               length:values[0]->bv_len];
102           
103       ovalues = [[NSArray alloc] initWithObjects:&value count:1];
104           
105       [value release];
106     }
107     else {
108       NSMutableArray *a;
109       int j;
110           
111       a = [[NSMutableArray alloc] initWithCapacity:valueCount];
112           
113       for (j = 0; values[j]; j++) {
114         NSData *data;
115
116         data = [[NSData alloc] initWithBytes:values[j]->bv_val
117                                length:values[j]->bv_len];
118         [a addObject:data];
119         [data release];
120       }
121       ovalues = [a copy];
122       [a release];
123     }
124
125     if (values) {
126       ldap_value_free_len(values);
127       values = NULL;
128     }
129         
130     /* create attribute */
131         
132     attribute =
133       [[NGLdapAttribute alloc] initWithAttributeName:key values:ovalues];
134         
135     [key     release]; key    = nil;
136     [ovalues release]; ovalues = nil;
137
138     [attributes addObject:attribute];
139     [attribute release];
140   }
141 #if 0
142   if (first) {
143     ldap_memfree(first);
144   }
145 #endif
146   if (ber) {
147     ber_free(ber, 0);
148   }
149   return attributes;
150 }
151
152 - (id)nextObject {
153   int            res;
154   struct timeval to;
155   struct timeval *top;
156   LDAPMessage *msg;
157   id          record;
158
159   if (self->handle == NULL)
160     return nil;
161
162   msg = NULL;
163   record = nil;
164
165   top = NULL;
166   if (self->timeout > 0) {
167     to.tv_sec = self->timeout;
168     to.tv_sec = (long)(self->timeout * 1000.0) - (to.tv_sec * 1000);
169     top = &to;
170   }
171
172   res = ldap_result(self->handle, self->msgid, 0, top, &msg);
173   
174   if (msg) {
175     switch(res) {
176 #if defined(LDAP_RES_SEARCH_REFERENCE)
177       case LDAP_RES_SEARCH_REFERENCE: {
178         int         rres;
179         char        **rptr;
180         LDAPControl **ctrl;
181
182         rres = ldap_parse_reference(self->handle, msg, &rptr, &ctrl,
183                                     0 /* don't free msg */);
184         if (rres == LDAP_SUCCESS) {
185         }
186         else {
187           /* error */
188           NSLog(@"%s: couldn't parse result reference ..", __PRETTY_FUNCTION__);
189         }
190
191         NSLog(@"WARNING: doesn't support result references yet ..");
192         
193         if (rptr) ldap_value_free(rptr);
194         if (ctrl) ldap_controls_free(ctrl);
195         
196         break;
197       }
198 #endif
199       
200       case LDAP_RES_SEARCH_ENTRY: {
201         int resultCount;
202         
203         if ((resultCount = ldap_count_entries(self->handle, msg)) == -1) {
204           /* failed */
205           int err;
206     
207           err = ldap_result2error(self->handle, msg, 1 /* free msg */);
208           
209           [[self->connection _exceptionForErrorCode:err
210                              operation:@"count-fetch"
211                              userInfo:nil]
212                              raise];
213           return nil;
214         }
215         else if (resultCount == 1) {
216           LDAPMessage *result;
217           NSString    *dn = nil;
218           char        *tmp;
219           NSArray     *attributes;
220           
221           if ((result = ldap_first_entry(self->handle, msg)) == NULL) {
222             /* could not get entry */
223             int err;
224             
225             err = ldap_result2error(self->handle, msg, 1 /* free msg */);
226             
227             [[self->connection _exceptionForErrorCode:resultCount
228                                operation:@"fetch"
229                                userInfo:nil]
230                                raise];
231             
232             return nil;
233           }
234     
235           /* get distinguished name */
236           
237           if ((tmp = ldap_get_dn(self->handle, result))) {
238             NS_DURING {
239               dn = [[[NSString alloc] initWithUTF8String:tmp] autorelease];
240             }
241             NS_HANDLER {
242               fprintf(stderr, "Got exception %s while NSUTF8StringEncoding, "
243                       "use defaultCStringEncoding",
244                       [[localException description] cString]);
245               dn = nil;
246             }
247             NS_ENDHANDLER;
248
249             if (dn == nil)
250               dn = [[[NSString alloc] initWithCString:tmp] autorelease];
251
252             free(tmp);
253           }
254           /* get all attributes */
255           
256           attributes = [self _attributesFromResult:result];
257
258           if (result) {
259             // TODO: ldap_msgfree(result); // do not release result-msg ???
260             result = NULL;
261           }
262           
263           record = [[NGLdapEntry alloc] initWithDN:dn attributes:attributes];
264           
265           [attributes release]; attributes = nil;
266         }
267         else if (resultCount == 0) {
268           /* no more results */
269           record = nil;
270         }
271         break;
272       }
273
274       case LDAP_RES_SEARCH_RESULT:
275         self->handle = NULL;
276         [self->connection release]; self->connection = nil;
277         break;
278
279       default:
280         NSLog(@"unexpected msg-code: %X", res);
281         break;
282     }
283     if (msg)
284       ldap_msgfree(msg);
285   }
286   
287   if (record)
288     self->index++;
289
290   return [record autorelease];
291 }
292
293 /* description */
294
295 - (NSString *)description {
296   NSMutableString *s;
297
298   s = [NSMutableString stringWithCapacity:100];
299   [s appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
300
301   [s appendFormat:@" msgid=%i", [self messageID]];
302   [s appendFormat:@" duration=%.2fs", [self duration]];
303   [s appendFormat:@" index=%i", [self index]];
304   
305   [s appendString:@">"];
306
307   return s;
308 }
309
310 @end /* LDAPResultEnumerator */