]> git.sur5r.net Git - openldap/blob - libraries/libldap/result.c
Minor bug fix in ldap_parse_extended_result.
[openldap] / libraries / libldap / result.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*  Portions
7  *  Copyright (c) 1990 Regents of the University of Michigan.
8  *  All rights reserved.
9  *
10  *  result.c - wait for an ldap result
11  */
12
13 /*
14  * LDAPv3 (RFC2251)
15  *      LDAPResult ::= SEQUENCE {
16  *              resultCode              ENUMERATED { ... },
17  *              matchedDN               LDAPDN,
18  *              errorMessage    LDAPString,
19  *              referral                Referral OPTIONAL
20  *      }
21  *      Referral ::= SEQUENCE OF LDAPURL        (one or more)
22  *      LDAPURL ::= LDAPString                          (limited to URL chars)
23  */
24
25 #include "portable.h"
26
27 #include <stdio.h>
28
29 #include <ac/stdlib.h>
30
31 #include <ac/errno.h>
32 #include <ac/socket.h>
33 #include <ac/string.h>
34 #include <ac/time.h>
35 #include <ac/unistd.h>
36
37 #include "ldap-int.h"
38
39
40 static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid ));
41 static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid ));
42 static int wait4msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout,
43         LDAPMessage **result ));
44 static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid,
45         int all, Sockbuf *sb, LDAPConn *lc, LDAPMessage **result ));
46 static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr ));
47 static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ));
48
49
50 /*
51  * ldap_result - wait for an ldap result response to a message from the
52  * ldap server.  If msgid is -1, any message will be accepted, otherwise
53  * ldap_result will wait for a response with msgid.  If all is 0 the
54  * first message with id msgid will be accepted, otherwise, ldap_result
55  * will wait for all responses with id msgid and then return a pointer to
56  * the entire list of messages.  This is only useful for search responses,
57  * which can be of two message types (zero or more entries, followed by an
58  * ldap result).  The type of the first message received is returned.
59  * When waiting, any messages that have been abandoned are discarded.
60  *
61  * Example:
62  *      ldap_result( s, msgid, all, timeout, result )
63  */
64 int
65 ldap_result(
66         LDAP *ld,
67         int msgid,
68         int all,
69         struct timeval *timeout,
70         LDAPMessage **result )
71 {
72         LDAPMessage     *lm, *lastlm, *nextlm;
73
74         assert( ld != NULL );
75         assert( result != NULL );
76
77         Debug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 );
78
79         if( ld == NULL ) {
80                 return -1;
81         }
82
83         if( result == NULL ) {
84                 ld->ld_errno = LDAP_PARAM_ERROR;
85                 return -1;
86         }
87
88         /*
89          * First, look through the list of responses we have received on
90          * this association and see if the response we're interested in
91          * is there.  If it is, return it.  If not, call wait4msg() to
92          * wait until it arrives or timeout occurs.
93          */
94
95         *result = NULL;
96         lastlm = NULL;
97         for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
98                 nextlm = lm->lm_next;
99
100                 if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
101                         ldap_mark_abandoned( ld, lm->lm_msgid );
102
103                         if ( lastlm == NULL ) {
104                                 ld->ld_responses = lm->lm_next;
105                         } else {
106                                 lastlm->lm_next = nextlm;
107                         }
108
109                         ldap_msgfree( lm );
110
111                         continue;
112                 }
113
114                 if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
115                         LDAPMessage     *tmp;
116
117                         if ( all == 0
118                             || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
119                             && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE      /* LDAPv3 */
120                             && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
121                                 break;
122
123                         for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
124                                 if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
125                                         break;
126                         }
127
128                         if ( tmp == NULL ) {
129                                 lm = NULL;
130                         }
131
132                         break;
133                 }
134                 lastlm = lm;
135         }
136         if ( lm == NULL ) {
137                 return( wait4msg( ld, msgid, all, timeout, result ) );
138         }
139
140         if ( lastlm == NULL ) {
141                 ld->ld_responses = (all == 0 && lm->lm_chain != NULL
142                     ? lm->lm_chain : lm->lm_next);
143         } else {
144                 lastlm->lm_next = (all == 0 && lm->lm_chain != NULL
145                     ? lm->lm_chain : lm->lm_next);
146         }
147         if ( all == 0 )
148                 lm->lm_chain = NULL;
149         lm->lm_next = NULL;
150
151         *result = lm;
152         ld->ld_errno = LDAP_SUCCESS;
153         return( lm->lm_msgtype );
154 }
155
156 static int
157 wait4msg(
158         LDAP *ld,
159         ber_int_t msgid,
160         int all,
161         struct timeval *timeout,
162         LDAPMessage **result )
163 {
164         int             rc;
165         struct timeval  tv, *tvp;
166         time_t          start_time = 0;
167         time_t          tmp_time;
168         LDAPConn        *lc, *nextlc;
169
170         assert( ld != NULL );
171         assert( result != NULL );
172
173 #ifdef LDAP_DEBUG
174         if ( timeout == NULL ) {
175                 Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n",
176                     0, 0, 0 );
177         } else {
178                 Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n",
179                        (long) timeout->tv_sec, (long) timeout->tv_usec, 0 );
180         }
181 #endif /* LDAP_DEBUG */
182
183         if ( timeout == NULL ) {
184                 tvp = NULL;
185         } else {
186                 tv = *timeout;
187                 tvp = &tv;
188                 start_time = time( NULL );
189         }
190                     
191         rc = -2;
192         while ( rc == -2 ) {
193 #ifdef LDAP_DEBUG
194                 if ( ldap_debug & LDAP_DEBUG_TRACE ) {
195                         ldap_dump_connection( ld, ld->ld_conns, 1 );
196                         ldap_dump_requests_and_responses( ld );
197                 }
198 #endif /* LDAP_DEBUG */
199                 for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
200                         if ( ber_pvt_sb_data_ready(lc->lconn_sb) ) {
201                                 rc = try_read1msg( ld, msgid, all, lc->lconn_sb,
202                                     lc, result );
203                                 break;
204                         }
205                 }
206
207                 if ( lc == NULL ) {
208                         rc = do_ldap_select( ld, tvp );
209
210
211 #ifdef LDAP_DEBUG
212                         if ( rc == -1 ) {
213                             Debug( LDAP_DEBUG_TRACE,
214                                     "do_ldap_select returned -1: errno %d\n",
215                                     errno, 0, 0 );
216                         }
217 #endif
218
219                         if ( rc == 0 || ( rc == -1 && (
220                                 !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART)
221                                 || errno != EINTR )))
222                         {
223                                 ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
224                                     LDAP_TIMEOUT);
225                                 return( rc );
226                         }
227
228                         if ( rc == -1 ) {
229                                 rc = -2;        /* select interrupted: loop */
230                         } else {
231                                 rc = -2;
232                                 for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
233                                     lc = nextlc ) {
234                                         nextlc = lc->lconn_next;
235                                         if ( lc->lconn_status ==
236                                             LDAP_CONNST_CONNECTED &&
237                                             ldap_is_read_ready( ld,
238                                             lc->lconn_sb )) {
239                                                 rc = try_read1msg( ld, msgid, all,
240                                                     lc->lconn_sb, lc, result );
241                                         }
242                                 }
243                         }
244                 }
245
246                 if ( rc == -2 && tvp != NULL ) {
247                         tmp_time = time( NULL );
248                         if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
249                                 rc = 0; /* timed out */
250                                 ld->ld_errno = LDAP_TIMEOUT;
251                                 break;
252                         }
253
254                         Debug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
255                                (long) tv.tv_sec, 0, 0 );
256                         start_time = tmp_time;
257                 }
258         }
259
260         return( rc );
261 }
262
263
264 static ber_tag_t
265 try_read1msg(
266         LDAP *ld,
267         ber_int_t msgid,
268         int all,
269         Sockbuf *sb,
270     LDAPConn *lc,
271         LDAPMessage **result )
272 {
273         BerElement      *ber;
274         LDAPMessage     *new, *l, *prev, *tmp;
275         ber_int_t       id;
276         ber_tag_t       tag;
277         ber_len_t       len;
278         int             foundit = 0;
279         LDAPRequest     *lr;
280         BerElement      tmpber;
281         int             rc, refer_cnt, hadref, simple_request;
282         ber_int_t       lderr;
283
284         assert( ld != NULL );
285         assert( lc != NULL );
286         
287         Debug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );
288
289     if ( lc->lconn_ber == NULL ) {
290                 lc->lconn_ber = ldap_alloc_ber_with_options(ld);
291
292                 if( lc->lconn_ber == NULL ) {
293                         return -1;
294                 }
295     }
296
297         ber = lc->lconn_ber;
298         assert( BER_VALID (ber) );
299
300         /* get the next message */
301         errno = 0;
302         if ( (tag = ber_get_next( sb, &len, ber ))
303             != LDAP_TAG_MESSAGE ) {
304                 if ( tag == LBER_DEFAULT) {
305 #ifdef LDAP_DEBUG                  
306                         Debug( LDAP_DEBUG_CONNS,
307                               "ber_get_next failed.\n", 0, 0, 0 );
308 #endif             
309 #ifdef EWOULDBLOCK                      
310                         if (errno==EWOULDBLOCK) return -2;
311 #endif
312 #ifdef EAGAIN
313                         if (errno == EAGAIN) return -2;
314 #endif
315                         ld->ld_errno = LDAP_SERVER_DOWN;
316                         return -1;
317                 }
318                 ld->ld_errno = LDAP_LOCAL_ERROR;
319                 return -1;
320         }
321
322         /*
323      * We read a complete message.
324          * The connection should no longer need this ber.
325          */
326     lc->lconn_ber = NULL;
327
328         /* message id */
329         if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
330                 ber_free( ber, 1 );
331                 ld->ld_errno = LDAP_DECODING_ERROR;
332                 return( -1 );
333         }
334
335         /* if it's been abandoned, toss it */
336         if ( ldap_abandoned( ld, id ) ) {
337                 ber_free( ber, 1 );
338                 return( -2 );   /* continue looking */
339         }
340
341         if (( lr = ldap_find_request_by_msgid( ld, id )) == NULL ) {
342                 Debug( LDAP_DEBUG_ANY,
343                     "no request for response with msgid %ld (tossing)\n",
344                     (long) id, 0, 0 );
345                 ber_free( ber, 1 );
346                 return( -2 );   /* continue looking */
347         }
348
349         /* the message type */
350         if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
351                 ld->ld_errno = LDAP_DECODING_ERROR;
352                 ber_free( ber, 1 );
353                 return( -1 );
354         }
355
356         Debug( LDAP_DEBUG_TRACE, "ldap_read: %s msgid %ld, original id %ld\n",
357             ( tag == LDAP_RES_SEARCH_ENTRY ) ? "entry" : 
358                 ( tag == LDAP_RES_SEARCH_REFERENCE ) ? "reference" : "result",
359                 (long) id, (long) lr->lr_origid );
360
361         id = lr->lr_origid;
362         refer_cnt = 0;
363         hadref = simple_request = 0;
364         rc = -2;        /* default is to keep looking (no response found) */
365         lr->lr_res_msgtype = tag;
366
367         if ( tag != LDAP_RES_SEARCH_ENTRY ) {
368                 if ( ld->ld_version >= LDAP_VERSION2 &&
369                         ( lr->lr_parent != NULL ||
370                         LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ) )
371                 {
372                         tmpber = *ber;  /* struct copy */
373                         if ( ber_scanf( &tmpber, "{iaa}", &lderr,
374                             &lr->lr_res_matched, &lr->lr_res_error )
375                             != LBER_ERROR ) {
376                                 if ( lderr != LDAP_SUCCESS ) {
377                                         /* referrals are in error string */
378                                         refer_cnt = ldap_chase_referrals( ld, lr,
379                                             &lr->lr_res_error, &hadref );
380                                 }
381
382                                 /* save errno, message, and matched string */
383                                 if ( !hadref || lr->lr_res_error == NULL ) {
384                                         lr->lr_res_errno = ( lderr ==
385                                         LDAP_PARTIAL_RESULTS ) ? LDAP_SUCCESS
386                                         : lderr;
387                                 } else if ( ld->ld_errno != LDAP_SUCCESS ) {
388                                         lr->lr_res_errno = ld->ld_errno;
389                                 } else {
390                                         lr->lr_res_errno = LDAP_PARTIAL_RESULTS;
391                                 }
392 Debug( LDAP_DEBUG_TRACE,
393     "new result:  res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
394     lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
395     lr->lr_res_matched ? lr->lr_res_matched : "" );
396                         }
397                 }
398
399                 Debug( LDAP_DEBUG_TRACE,
400                     "read1msg:  %d new referrals\n", refer_cnt, 0, 0 );
401
402                 if ( refer_cnt != 0 ) { /* chasing referrals */
403                         ber_free( ber, 1 );
404                         ber = NULL;
405                         if ( refer_cnt < 0 ) {
406                                 return( -1 );   /* fatal error */
407                         }
408                         lr->lr_status = LDAP_REQST_CHASINGREFS;
409                 } else {
410                         if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
411                                 /* request without any referrals */
412                                 simple_request = ( hadref ? 0 : 1 );
413                         } else {
414                                 /* request with referrals or child request */
415                                 ber_free( ber, 1 );
416                                 ber = NULL;
417                         }
418
419                         while ( lr->lr_parent != NULL ) {
420                                 merge_error_info( ld, lr->lr_parent, lr );
421
422                                 lr = lr->lr_parent;
423                                 if ( --lr->lr_outrefcnt > 0 ) {
424                                         break;  /* not completely done yet */
425                                 }
426                         }
427
428                         if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
429                                 id = lr->lr_msgid;
430                                 tag = lr->lr_res_msgtype;
431                                 Debug( LDAP_DEBUG_ANY, "request %ld done\n",
432                                     (long) id, 0, 0 );
433 Debug( LDAP_DEBUG_TRACE,
434 "res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
435 lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
436 lr->lr_res_matched ? lr->lr_res_matched : "" );
437                                 if ( !simple_request ) {
438                                         ber_free( ber, 1 );
439                                         ber = NULL;
440                                         if ( build_result_ber( ld, &ber, lr )
441                                             == LBER_ERROR ) {
442                                                 rc = -1; /* fatal error */
443                                         }
444                                 }
445
446                                 ldap_free_request( ld, lr );
447                         }
448
449                         if ( lc != NULL ) {
450                                 ldap_free_connection( ld, lc, 0, 1 );
451                         }
452                 }
453         }
454
455         if ( ber == NULL ) {
456                 return( rc );
457         }
458
459         /* make a new ldap message */
460         if ( (new = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) ))
461             == NULL ) {
462                 ld->ld_errno = LDAP_NO_MEMORY;
463                 return( -1 );
464         }
465         new->lm_msgid = (int)id;
466         new->lm_msgtype = tag;
467         new->lm_ber = ber;
468
469 #ifndef LDAP_NOCACHE
470                 if ( ld->ld_cache != NULL ) {
471                         ldap_add_result_to_cache( ld, new );
472                 }
473 #endif /* LDAP_NOCACHE */
474
475         /* is this the one we're looking for? */
476         if ( msgid == LDAP_RES_ANY || id == msgid ) {
477                 if ( all == 0
478                     || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT
479                     && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) {
480                         *result = new;
481                         ld->ld_errno = LDAP_SUCCESS;
482                         return( tag );
483                 } else if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
484                         foundit = 1;    /* return the chain later */
485                 }
486         }
487
488         /* 
489          * if not, we must add it to the list of responses.  if
490          * the msgid is already there, it must be part of an existing
491          * search response.
492          */
493
494         prev = NULL;
495         for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
496                 if ( l->lm_msgid == new->lm_msgid )
497                         break;
498                 prev = l;
499         }
500
501         /* not part of an existing search response */
502         if ( l == NULL ) {
503                 if ( foundit ) {
504                         *result = new;
505                         ld->ld_errno = LDAP_SUCCESS;
506                         return( tag );
507                 }
508
509                 new->lm_next = ld->ld_responses;
510                 ld->ld_responses = new;
511                 return( -2 );   /* continue looking */
512         }
513
514         Debug( LDAP_DEBUG_TRACE, "adding response id %ld type %ld:\n",
515             (long) new->lm_msgid, (long) new->lm_msgtype, 0 );
516
517         /* part of a search response - add to end of list of entries */
518         for ( tmp = l; tmp->lm_chain != NULL &&
519             tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY;
520             tmp = tmp->lm_chain )
521                 ;       /* NULL */
522         tmp->lm_chain = new;
523
524         /* return the whole chain if that's what we were looking for */
525         if ( foundit ) {
526                 if ( prev == NULL )
527                         ld->ld_responses = l->lm_next;
528                 else
529                         prev->lm_next = l->lm_next;
530                 *result = l;
531                 ld->ld_errno = LDAP_SUCCESS;
532 #ifdef LDAP_WORLD_P16
533                 /*
534                  * XXX questionable fix; see text for [P16] on
535                  * http://www.critical-angle.com/ldapworld/patch/
536                  *
537                  * inclusion of this patch causes searchs to hang on
538                  * multiple platforms
539                  */
540                 return( l->lm_msgtype );
541 #else   /* LDAP_WORLD_P16 */
542                 return( tag );
543 #endif  /* !LDAP_WORLD_P16 */
544         }
545
546         return( -2 );   /* continue looking */
547 }
548
549
550 static ber_tag_t
551 build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr )
552 {
553         ber_len_t       len;
554         ber_int_t       tag;
555         ber_int_t       along;
556         BerElement *ber;
557
558         *bp = NULL;
559         ber = ldap_alloc_ber_with_options( ld );
560
561         if( ber == NULL ) {
562                 ld->ld_errno = LDAP_NO_MEMORY;
563                 return LBER_ERROR;
564         }
565
566         if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
567             lr->lr_res_msgtype, lr->lr_res_errno,
568             lr->lr_res_matched ? lr->lr_res_matched : "",
569             lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {
570
571                 ld->ld_errno = LDAP_ENCODING_ERROR;
572                 ber_free(ber, 1);
573                 return( LBER_ERROR );
574         }
575
576         ber_reset( ber, 1 );
577
578         if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
579                 ld->ld_errno = LDAP_DECODING_ERROR;
580                 ber_free(ber, 1);
581                 return( LBER_ERROR );
582         }
583
584         if ( ber_get_int( ber, &along ) == LBER_ERROR ) {
585                 ld->ld_errno = LDAP_DECODING_ERROR;
586                 ber_free(ber, 1);
587                 return( LBER_ERROR );
588         }
589
590         tag = ber_peek_tag( ber, &len );
591
592         if ( tag == LBER_ERROR ) {
593                 ld->ld_errno = LDAP_DECODING_ERROR;
594                 ber_free(ber, 1);
595                 return( LBER_ERROR );
596         }
597
598         *bp = ber;
599         return tag;
600 }
601
602
603 static void
604 merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
605 {
606 /*
607  * Merge error information in "lr" with "parentr" error code and string.
608  */
609         if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
610                 parentr->lr_res_errno = lr->lr_res_errno;
611                 if ( lr->lr_res_error != NULL ) {
612                         (void)ldap_append_referral( ld, &parentr->lr_res_error,
613                             lr->lr_res_error );
614                 }
615         } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
616             parentr->lr_res_errno == LDAP_SUCCESS ) {
617                 parentr->lr_res_errno = lr->lr_res_errno;
618                 if ( parentr->lr_res_error != NULL ) {
619                         LDAP_FREE( parentr->lr_res_error );
620                 }
621                 parentr->lr_res_error = lr->lr_res_error;
622                 lr->lr_res_error = NULL;
623                 if ( LDAP_NAME_ERROR( lr->lr_res_errno )) {
624                         if ( parentr->lr_res_matched != NULL ) {
625                                 LDAP_FREE( parentr->lr_res_matched );
626                         }
627                         parentr->lr_res_matched = lr->lr_res_matched;
628                         lr->lr_res_matched = NULL;
629                 }
630         }
631
632         Debug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
633             parentr->lr_msgid, 0, 0 );
634         Debug( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n",
635             parentr->lr_res_errno, parentr->lr_res_error ?
636             parentr->lr_res_error : "", parentr->lr_res_matched ?
637             parentr->lr_res_matched : "" );
638 }
639
640
641
642 int
643 ldap_msgtype( LDAPMessage *lm )
644 {
645         assert( lm != NULL );
646         return ( lm != NULL ) ? lm->lm_msgtype : -1;
647 }
648
649
650 int
651 ldap_msgid( LDAPMessage *lm )
652 {
653         assert( lm != NULL );
654
655         return ( lm != NULL ) ? lm->lm_msgid : -1;
656 }
657
658
659 int
660 ldap_msgfree( LDAPMessage *lm )
661 {
662         LDAPMessage     *next;
663         int             type = 0;
664
665         assert( lm != NULL );
666
667         Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
668
669         for ( ; lm != NULL; lm = next ) {
670                 next = lm->lm_chain;
671                 type = lm->lm_msgtype;
672                 ber_free( lm->lm_ber, 1 );
673                 LDAP_FREE( (char *) lm );
674         }
675
676         return( type );
677 }
678
679 /*
680  * ldap_msgdelete - delete a message.  It returns:
681  *      0       if the entire message was deleted
682  *      -1      if the message was not found, or only part of it was found
683  */
684 int
685 ldap_msgdelete( LDAP *ld, int msgid )
686 {
687         LDAPMessage     *lm, *prev;
688
689         assert( ld != NULL );
690
691         Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
692
693         prev = NULL;
694         for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
695                 if ( lm->lm_msgid == msgid )
696                         break;
697                 prev = lm;
698         }
699
700         if ( lm == NULL )
701                 return( -1 );
702
703         if ( prev == NULL )
704                 ld->ld_responses = lm->lm_next;
705         else
706                 prev->lm_next = lm->lm_next;
707
708         if ( ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY )
709                 return( -1 );
710
711         return( 0 );
712 }
713
714
715 /*
716  * return 1 if message msgid is waiting to be abandoned, 0 otherwise
717  */
718 static int
719 ldap_abandoned( LDAP *ld, ber_int_t msgid )
720 {
721         int     i;
722
723         if ( ld->ld_abandoned == NULL )
724                 return( 0 );
725
726         for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
727                 if ( ld->ld_abandoned[i] == msgid )
728                         return( 1 );
729
730         return( 0 );
731 }
732
733
734 static int
735 ldap_mark_abandoned( LDAP *ld, ber_int_t msgid )
736 {
737         int     i;
738
739         if ( ld->ld_abandoned == NULL )
740                 return( -1 );
741
742         for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
743                 if ( ld->ld_abandoned[i] == msgid )
744                         break;
745
746         if ( ld->ld_abandoned[i] == -1 )
747                 return( -1 );
748
749         for ( ; ld->ld_abandoned[i] != -1; i++ ) {
750                 ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
751         }
752
753         return( 0 );
754 }
755
756
757 #ifdef LDAP_CONNECTIONLESS
758 int
759 cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber )
760 {
761         int     rc;
762         ber_tag_t       tag;
763         ber_len_t       len;
764
765         if ( ! ber_pvt_sb_data_ready(&ld->ld_sb) ) {
766                 /* restored from ldap_select1() in result.c version 1.24 */
767                 fd_set  readfds;
768                 if ( ldap_int_tblsize == 0 )
769                         ldap_int_ip_init();
770                 FD_ZERO( &readfds );
771                 FD_SET( ber_pvt_sb_get_desc(&ld->ld_sb), &readfds );
772                 rc = select( ldap_int_tblsize, &readfds, 0, 0, timeout );
773
774                 if ( rc == -1 || rc == 0 ) {
775                         ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
776                             LDAP_TIMEOUT);
777                         return( rc );
778                 }
779         }
780
781         /* get the next message */
782         if ( (tag = ber_get_next( &ld->ld_sb, &len, ber ))
783             != LDAP_TAG_MESSAGE ) {
784                 ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
785                     LDAP_LOCAL_ERROR);
786                 return( -1 );
787         }
788
789         return( 0 );
790 }
791 #endif /* LDAP_CONNECTIONLESS */