result.c 29.4 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
/*
3
4
5
6
 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */
/*  Portions
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
8
 *  Copyright (c) 1990 Regents of the University of Michigan.
 *  All rights reserved.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 */
/*---
 * This notice applies to changes, created by or for Novell, Inc.,
 * to preexisting works for which notices appear elsewhere in this file.
 *
 * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
 *
 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
 * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
 * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
 * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
 * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
 * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
 * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
 * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. 
 *---
 * Modification to OpenLDAP source by Novell, Inc.
 * April 2000 sfs Add code to process V3 referrals and search results
Kurt Zeilenga's avatar
Kurt Zeilenga committed
27
28
29
30
 *
 *  result.c - wait for an ldap result
 */

31
32
33
34
35
36
37
38
39
40
41
/*
 * LDAPv3 (RFC2251)
 *	LDAPResult ::= SEQUENCE {
 *		resultCode		ENUMERATED { ... },
 *		matchedDN		LDAPDN,
 *		errorMessage	LDAPString,
 *		referral		Referral OPTIONAL
 *	}
 *	Referral ::= SEQUENCE OF LDAPURL	(one or more)
 *	LDAPURL ::= LDAPString				(limited to URL chars)
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
42
43

#include "portable.h"
44
45
46
47
48
49
50
51
52
53
54

#include <stdio.h>

#include <ac/stdlib.h>

#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
55
56
#include "ldap-int.h"

57
58
59
60
61
62
63
64
65
66

static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid ));
static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid ));
static int wait4msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout,
	LDAPMessage **result ));
static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid,
	int all, Sockbuf *sb, LDAPConn *lc, LDAPMessage **result ));
static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr ));
static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ));
static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
67
68
69
70


/*
 * ldap_result - wait for an ldap result response to a message from the
71
72
73
74
75
76
77
78
79
80
81
 * ldap server.  If msgid is LDAP_RES_ANY (-1), any message will be
 * accepted.  If msgid is LDAP_RES_UNSOLICITED (0), any unsolicited
 * message is accepted.  Otherwise ldap_result will wait for a response
 * with msgid.  If all is LDAP_MSG_ONE (0) the first message with id
 * msgid will be accepted, otherwise, ldap_result will wait for all
 * responses with id msgid and then return a pointer to the entire list
 * of messages.  In general, this is only useful for search responses,
 * which can be of three message types (zero or more entries, zero or
 * search references, followed by an ldap result).  An extension to
 * LDAPv3 allows partial extended responses to be returned in response
 * to any request.  The type of the first message received is returned.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
82
83
84
85
86
87
 * When waiting, any messages that have been abandoned are discarded.
 *
 * Example:
 *	ldap_result( s, msgid, all, timeout, result )
 */
int
88
89
90
91
92
ldap_result(
	LDAP *ld,
	int msgid,
	int all,
	struct timeval *timeout,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
93
94
	LDAPMessage **result )
{
95
	LDAPMessage	*lm;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
96

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
	assert( ld != NULL );
	assert( result != NULL );

#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_ARGS, "ldap_result msgid %d\n", msgid ));
#else
	Debug( LDAP_DEBUG_TRACE, "ldap_result msgid %d\n", msgid, 0, 0 );
#endif

	if( ld == NULL ) {
		return -1;
	}

	if( result == NULL ) {
		ld->ld_errno = LDAP_PARAM_ERROR;
		return -1;
	}

    lm = chkResponseList(ld, msgid, all);

	if ( lm == NULL ) {
		return( wait4msg( ld, msgid, all, timeout, result ) );
	}

	*result = lm;
	ld->ld_errno = LDAP_SUCCESS;
	return( lm->lm_msgtype );
}

static LDAPMessage *
chkResponseList(
	LDAP *ld,
	int msgid,
	int all)
{
	LDAPMessage	*lm, *lastlm, *nextlm;
    /*
	 * Look through the list of responses we have received on
Kurt Zeilenga's avatar
Kurt Zeilenga committed
135
136
137
138
139
	 * this association and see if the response we're interested in
	 * is there.  If it is, return it.  If not, call wait4msg() to
	 * wait until it arrives or timeout occurs.
	 */

140
141
142
143
144
145
146
147
148
149
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_ARGS, 
		"ldap_chkResponseList for msgid=%d, all=%d\n", msgid, all ));
#else
	Debug( LDAP_DEBUG_TRACE,
		"ldap_chkResponseList for msgid=%d, all=%d\n",
	    msgid, all, 0 );
#endif
	lastlm = NULL;
	for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
150
151
152
		nextlm = lm->lm_next;

		if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
153
154
155
156
157
158
159
160
#ifdef NEW_LOGGING
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
				"ldap_chkResponseList msg abandoned, msgid %d\n", msgid ));
#else
			Debug( LDAP_DEBUG_TRACE,
				"ldap_chkResponseList msg abandoned, msgid %d\n",
			    msgid, 0, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
161
162
			ldap_mark_abandoned( ld, lm->lm_msgid );

163
164
			if ( lastlm == NULL ) {
				/* Remove first entry in list */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
165
166
167
168
169
170
171
172
173
174
175
176
177
				ld->ld_responses = lm->lm_next;
			} else {
				lastlm->lm_next = nextlm;
			}

			ldap_msgfree( lm );

			continue;
		}

		if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
			LDAPMessage	*tmp;

178
			if ( all == LDAP_MSG_ONE || msgid == LDAP_RES_UNSOLICITED ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
179
				break;
180
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
181

182
183
184
185
186
			for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
				if ( tmp->lm_msgtype != LDAP_RES_SEARCH_ENTRY
				    && tmp->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
					&& tmp->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL )
				{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
187
					break;
188
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
189
190
			}

191
192
			if ( tmp == NULL ) {
				lm = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
193
194
195
196
197
198
199
			}

			break;
		}
		lastlm = lm;
	}

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
    if ( lm != NULL ) {
		/* Found an entry, remove it from the list */
	    if ( lastlm == NULL ) {
		    ld->ld_responses = (all == LDAP_MSG_ONE && lm->lm_chain != NULL
		        ? lm->lm_chain : lm->lm_next);
	    } else {
		    lastlm->lm_next = (all == LDAP_MSG_ONE && lm->lm_chain != NULL
		        ? lm->lm_chain : lm->lm_next);
	    }
	    if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) {
		    lm->lm_chain->lm_next = lm->lm_next;
		    lm->lm_chain = NULL;
	    }
	    lm->lm_next = NULL;
    }

#ifdef LDAP_DEBUG
	if( lm == NULL) {
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_RESULTS, 
			"ldap_chkResponseList returns NULL\n" ));
#else
		Debug( LDAP_DEBUG_TRACE,
			"ldap_chkResponseList returns NULL\n", 0, 0, 0);
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
225
	} else {
226
227
228
229
230
231
232
233
234
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_RESULTS, 
			"ldap_chkResponseList returns msgid %d, type 0x02lu\n",
			lm->lm_msgid, (unsigned long) lm->lm_msgtype ));
#else
		Debug( LDAP_DEBUG_TRACE,
			"ldap_chkResponseList returns msgid %d, type 0x%02lu\n",
			lm->lm_msgid, (unsigned long) lm->lm_msgtype, 0);
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
235
	}
236
237
#endif
    return lm;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
238
239
240
}

static int
241
242
243
244
245
wait4msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
	struct timeval *timeout,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
246
247
248
249
	LDAPMessage **result )
{
	int		rc;
	struct timeval	tv, *tvp;
250
251
	time_t		start_time = 0;
	time_t		tmp_time;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
252
	LDAPConn	*lc, *nextlc;
253
254
255

	assert( ld != NULL );
	assert( result != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
256
257
258

#ifdef LDAP_DEBUG
	if ( timeout == NULL ) {
259
260
261
262
263
264
265
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_ARGS,
			"wait4msg (infinite timeout), msgid %d\n", msgid ));
#else
		Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout), msgid %d\n",
		    msgid, 0, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
266
	} else {
267
268
269
270
271
272
273
274
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_ARGS,
			"wait4msg (timeout %ld sec, %ld usec), msgid %d\n", 
			(long) timeout->tv_sec, (long) timeout->tv_usec, msgid ));
#else
		Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec), msgid %d\n",
		       (long) timeout->tv_sec, (long) timeout->tv_usec, msgid );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
275
276
277
278
279
280
281
282
	}
#endif /* LDAP_DEBUG */

	if ( timeout == NULL ) {
		tvp = NULL;
	} else {
		tv = *timeout;
		tvp = &tv;
283
		start_time = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
284
285
286
287
	}
		    
	rc = -2;
	while ( rc == -2 ) {
288
289
290
291
#ifdef LDAP_DEBUG
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_ARGS,
			"wait4msg continue, msgid %d, all %d\n", msgid, all ));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
292
#else
293
294
		Debug( LDAP_DEBUG_TRACE, "wait4msg continue, msgid %d, all %d\n",
		    msgid, all, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
295
296
#endif
		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
297
298
			ldap_dump_connection( ld, ld->ld_conns, 1 );
			ldap_dump_requests_and_responses( ld );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
299
300
301
		}
#endif /* LDAP_DEBUG */

302
303
304
        if( (*result = chkResponseList(ld, msgid, all)) != NULL ) {
            rc = (*result)->lm_msgtype;
        } else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
305

306
307
308
309
310
311
312
313
			for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
				if ( ber_sockbuf_ctrl( lc->lconn_sb,
						LBER_SB_OPT_DATA_READY, NULL ) ) {
					    rc = try_read1msg( ld, msgid, all, lc->lconn_sb,
					        lc, result );
				    break;
				}
	        }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
314

315
316
		    if ( lc == NULL ) {
			    rc = ldap_int_select( ld, tvp );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
317

318
319
320
321
322
323
324

#ifdef LDAP_DEBUG
			    if ( rc == -1 ) {
#ifdef NEW_LOGGING
					LDAP_LOG (( "result", LDAP_LEVEL_ARGS,
						"wait4msg: ldap_int_select returned -1: errno %d\n", 
						errno ));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
325
#else
326
327
328
329
330
			        Debug( LDAP_DEBUG_TRACE,
				        "ldap_int_select returned -1: errno %d\n",
				        errno, 0, 0 );
#endif
			    }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
331
332
#endif

333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
			    if ( rc == 0 || ( rc == -1 && (
				    !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART)
				    || errno != EINTR )))
			    {
				    ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
				        LDAP_TIMEOUT);
				    return( rc );
			    }

			    if ( rc == -1 ) {
				    rc = -2;	/* select interrupted: loop */
			    } else {
				    rc = -2;
				    for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
				        lc = nextlc ) {
					    nextlc = lc->lconn_next;
					    if ( lc->lconn_status ==
					        LDAP_CONNST_CONNECTED &&
					        ldap_is_read_ready( ld,
					        lc->lconn_sb )) {
						    rc = try_read1msg( ld, msgid, all,
						        lc->lconn_sb, lc, result );
					    }
				    }
			    }
		    }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
359
360
361
		}

		if ( rc == -2 && tvp != NULL ) {
362
			tmp_time = time( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
363
364
365
366
367
368
			if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
				rc = 0;	/* timed out */
				ld->ld_errno = LDAP_TIMEOUT;
				break;
			}

369
370
371
372
#ifdef NEW_LOGGING
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1,
				"wait4msg: %ld secs to go\n", (long) tv.tv_sec ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
373
			Debug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
374
375
			       (long) tv.tv_sec, 0, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
376
377
378
379
380
381
382
383
			start_time = tmp_time;
		}
	}

	return( rc );
}


384
385
386
387
388
389
390
391
static ber_tag_t
try_read1msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
	Sockbuf *sb,
	LDAPConn *lc,
	LDAPMessage **result )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
392
{
393
	BerElement	*ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
394
	LDAPMessage	*new, *l, *prev, *tmp;
395
396
397
	ber_int_t	id;
	ber_tag_t	tag;
	ber_len_t	len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
398
	int		foundit = 0;
399
	LDAPRequest	*lr, *tmplr;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
400
401
	BerElement	tmpber;
	int		rc, refer_cnt, hadref, simple_request;
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
	ber_int_t	lderr;
	/*
	 * v3ref = flag for V3 referral / search reference
	 * 0 = not a ref, 1 = sucessfully chased ref, -1 = pass ref to application
	 */
	int     v3ref;

	assert( ld != NULL );
	assert( lc != NULL );
	
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_ARGS, "read1msg: msgid %d, all %d\n",
		msgid, all ));
#else
	Debug( LDAP_DEBUG_TRACE, "read1msg: msgid %d, all %d\n", msgid, all, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
418

419
420
421
422
423
424
425
    if ( lc->lconn_ber == NULL ) {
		lc->lconn_ber = ldap_alloc_ber_with_options(ld);

		if( lc->lconn_ber == NULL ) {
			return -1;
		}
    }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
426

427
428
	ber = lc->lconn_ber;
	assert( LBER_VALID (ber) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
429
430

	/* get the next message */
431
432
433
434
435
436
437
438
	errno = 0;
#ifdef LDAP_CONNECTIONLESS
	if ( LDAP_IS_UDP(ld) ) {
		struct sockaddr from;
		ber_int_sb_read(sb, &from, sizeof(struct sockaddr));
	}
#endif
	if ( (tag = ber_get_next( sb, &len, ber ))
Kurt Zeilenga's avatar
Kurt Zeilenga committed
439
	    != LDAP_TAG_MESSAGE ) {
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
		if ( tag == LBER_DEFAULT) {
#ifdef LDAP_DEBUG		   
#ifdef NEW_LOGGING
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
				"read1msg: ber_get_next failed\n" ));
#else
			Debug( LDAP_DEBUG_CONNS,
			      "ber_get_next failed.\n", 0, 0, 0 );
#endif		   
#endif		   
#ifdef EWOULDBLOCK			
			if (errno==EWOULDBLOCK) return -2;
#endif
#ifdef EAGAIN
			if (errno == EAGAIN) return -2;
#endif
			ld->ld_errno = LDAP_SERVER_DOWN;
			return -1;
		}
		ld->ld_errno = LDAP_LOCAL_ERROR;
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
461
462
	}

463
464
465
466
467
468
	/*
     * We read a complete message.
	 * The connection should no longer need this ber.
	 */
    lc->lconn_ber = NULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
469
	/* message id */
470
471
	if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
472
473
474
475
476
		ld->ld_errno = LDAP_DECODING_ERROR;
		return( -1 );
	}

	/* if it's been abandoned, toss it */
477
478
479
480
481
482
483
484
	if ( ldap_abandoned( ld, id ) ) {
		ber_free( ber, 1 );
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
			"read1msg: abandoned\n" ));
#else
		Debug( LDAP_DEBUG_ANY, "abandoned\n", 0, 0, 0);
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
485
486
487
		return( -2 );	/* continue looking */
	}

488
489
490
491
492
493
	if (( lr = ldap_find_request_by_msgid( ld, id )) == NULL ) {
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
			"read1msg: no request for response with msgid %ld (tossing)\n",
			(long) id ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
494
495
		Debug( LDAP_DEBUG_ANY,
		    "no request for response with msgid %ld (tossing)\n",
496
497
498
		    (long) id, 0, 0 );
#endif
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
499
500
		return( -2 );	/* continue looking */
	}
501
502
503
504
505
506
#ifdef LDAP_CONNECTIONLESS
	if (LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
		struct berval blank;
		ber_scanf(ber, "m{", &blank);
	}
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
507
	/* the message type */
508
	if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
509
		ld->ld_errno = LDAP_DECODING_ERROR;
510
		ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
511
512
513
		return( -1 );
	}

514
515
516
517
518
519
520
521
522
523
524
525
526
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
		"read1msg: ldap_read: message type %s msgid %ld, original id %ld\n",
	    ldap_int_msgtype2str( tag ),
		(long) lr->lr_msgid, (long) lr->lr_origid ));
#else
	Debug( LDAP_DEBUG_TRACE,
		"ldap_read: message type %s msgid %ld, original id %ld\n",
	    ldap_int_msgtype2str( tag ),
		(long) lr->lr_msgid, (long) lr->lr_origid );
#endif

	id = lr->lr_origid;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
527
528
529
530
531
	refer_cnt = 0;
	hadref = simple_request = 0;
	rc = -2;	/* default is to keep looking (no response found) */
	lr->lr_res_msgtype = tag;

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
	/*
	 * This code figures out if we are going to chase a
	 * referral / search reference, or pass it back to the application
	 */
	v3ref = 0;	/* Assume not a V3 search reference or referral */
	if( (tag != LDAP_RES_SEARCH_ENTRY) && (ld->ld_version > LDAP_VERSION2) ) {
		BerElement	tmpber = *ber; 	/* struct copy */
		char **refs = NULL;

		if( tag == LDAP_RES_SEARCH_REFERENCE) {
			/* This is a V3 search reference */
			/* Assume we do not chase the reference, but pass it to application */
			v3ref = -1;
			if( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
					(lr->lr_parent != NULL) )
			{
				/* Get the referral list */
				if ( ber_scanf( &tmpber, "{v}", &refs ) == LBER_ERROR ) {
					rc = LDAP_DECODING_ERROR;
				} else {
					/* Note: refs arrary is freed by ldap_chase_v3referrals */
					refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
					    1, &lr->lr_res_error, &hadref );
					if ( refer_cnt > 0 ) {	/* sucessfully chased reference */
						/* If haven't got end search, set chasing referrals */
						if( lr->lr_status != LDAP_REQST_COMPLETED) {
							lr->lr_status = LDAP_REQST_CHASINGREFS;
#ifdef NEW_LOGGING
							LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
								"read1msg: search ref chased,"
								"mark request chasing refs, id =	%d\n",
								lr->lr_msgid ));
#else
							Debug( LDAP_DEBUG_TRACE,
							    "read1msg:  search ref chased, mark request chasing refs, id = %d\n",
							    lr->lr_msgid, 0, 0);
#endif
						}
						v3ref = 1;	/* We sucessfully chased the reference */
					}
				}
			}
		} else {
			/* Check for V3 referral */
			ber_len_t len;
			if ( ber_scanf( &tmpber, "{iaa",/*}*/ &lderr,
				    &lr->lr_res_matched, &lr->lr_res_error )
				    != LBER_ERROR ) {
				/* Check if V3 referral */
				if( ber_peek_tag( &tmpber, &len) == LDAP_TAG_REFERRAL ) {
					/* We have a V3 referral, assume we cannot chase it */
					v3ref = -1;
					if( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS)
							 || (lr->lr_parent != NULL) )
					{
						v3ref = -1;  /* Assume referral not chased and return it to app */
						/* Get the referral list */
						if( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) {
							rc = LDAP_DECODING_ERROR;
							lr->lr_status = LDAP_REQST_COMPLETED;
#ifdef NEW_LOGGING
							LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
								"read1msg: referral decode error,"
								"mark request completed, id =	%d\n",
								lr->lr_msgid ));
#else
							Debug( LDAP_DEBUG_TRACE,
							    "read1msg: referral decode error, mark request completed, id = %d\n",
								    lr->lr_msgid, 0, 0);
#endif
						} else {
							/* Chase the referral 
							 * Note: refs arrary is freed by ldap_chase_v3referrals
							 */
							refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
							    0, &lr->lr_res_error, &hadref );
							lr->lr_status = LDAP_REQST_COMPLETED;
#ifdef NEW_LOGGING
							LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
								"read1msg: referral chased,"
								"mark request completed, id =	%d\n",
								lr->lr_msgid ));
#else
							Debug( LDAP_DEBUG_TRACE,
							    "read1msg:  referral chased, mark request completed, id = %d\n",
							    lr->lr_msgid, 0, 0);
#endif
							if( refer_cnt > 0) {
								v3ref = 1;  /* Referral successfully chased */
							}
						}
					}
				}

				if( lr->lr_res_matched != NULL ) {
					LDAP_FREE( lr->lr_res_matched );
					lr->lr_res_matched = NULL;
				}
				if( lr->lr_res_error != NULL ) {
					LDAP_FREE( lr->lr_res_error );
					lr->lr_res_error = NULL;
				}
			}
		}
	}

	/* All results that just return a status, i.e. don't return data
	 * go through the following code.  This code also chases V2 referrals
	 * and checks if all referrals have been chased.
	 */
	if ( (tag != LDAP_RES_SEARCH_ENTRY) && (v3ref > -1) ) {
		/* For a v3 search referral/reference, only come here if already chased it */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
644
		if ( ld->ld_version >= LDAP_VERSION2 &&
645
646
647
648
649
			( lr->lr_parent != NULL ||
			LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ) )
		{
			tmpber = *ber;	/* struct copy */
			if ( v3ref == 1 ) {
650
651
652
653
654
655
656
				/* V3 search reference or V3 referral
				 * sucessfully chased. If this message
				 * is a search result, then it has no more
				 * outstanding referrals.
				 */
				if ( tag == LDAP_RES_SEARCH_RESULT )
					refer_cnt = 0;
657
			} else if ( ber_scanf( &tmpber, "{iaa}", &lderr,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
658
659
660
661
			    &lr->lr_res_matched, &lr->lr_res_error )
			    != LBER_ERROR ) {
				if ( lderr != LDAP_SUCCESS ) {
					/* referrals are in error string */
662
663
664
665
666
667
668
669
670
671
672
673
					refer_cnt = ldap_chase_referrals( ld, lr,
						&lr->lr_res_error, -1, &hadref );
					lr->lr_status = LDAP_REQST_COMPLETED;
#ifdef NEW_LOGGING
					LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
						"read1msg: V2 referral chased,"
						"mark request completed, id =	%d\n",
						lr->lr_msgid ));
#else
					Debug( LDAP_DEBUG_TRACE,
					    "read1msg:  V2 referral chased, mark request completed, id = %d\n", lr->lr_msgid, 0, 0);
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
674
675
676
677
678
679
680
681
682
683
684
685
				}

				/* save errno, message, and matched string */
				if ( !hadref || lr->lr_res_error == NULL ) {
					lr->lr_res_errno = ( lderr ==
					LDAP_PARTIAL_RESULTS ) ? LDAP_SUCCESS
					: lderr;
				} else if ( ld->ld_errno != LDAP_SUCCESS ) {
					lr->lr_res_errno = ld->ld_errno;
				} else {
					lr->lr_res_errno = LDAP_PARTIAL_RESULTS;
				}
686
687
688
689
690
691
#ifdef NEW_LOGGING
LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
	"read1msg: new result: res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
    lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
    lr->lr_res_matched ? lr->lr_res_matched : "" ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
692
693
694
695
Debug( LDAP_DEBUG_TRACE,
    "new result:  res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
    lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
    lr->lr_res_matched ? lr->lr_res_matched : "" );
696
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
697
698
699
			}
		}

700
701
702
703
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
			"read1msg: %d new referrals\n", refer_cnt ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
704
705
		Debug( LDAP_DEBUG_TRACE,
		    "read1msg:  %d new referrals\n", refer_cnt, 0, 0 );
706
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
707
708

		if ( refer_cnt != 0 ) {	/* chasing referrals */
709
710
			ber_free( ber, 1 );
			ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
711
712
713
			if ( refer_cnt < 0 ) {
				return( -1 );	/* fatal error */
			}
714
			lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
715
716
717
718
719
720
		} else {
			if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
				/* request without any referrals */
				simple_request = ( hadref ? 0 : 1 );
			} else {
				/* request with referrals or child request */
721
722
				ber_free( ber, 1 );
				ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
723
724
			}

725
726
727
728
729
730
731
732
			lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */
#ifdef NEW_LOGGING
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
				"read1msg: mark request completed, id = %d\n", lr->lr_msgid ));
#else
			Debug( LDAP_DEBUG_TRACE,
			    "read1msg:  mark request completed, id = %d\n", lr->lr_msgid, 0, 0);
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
733
734
735
736
737
738
739
740
741
			while ( lr->lr_parent != NULL ) {
				merge_error_info( ld, lr->lr_parent, lr );

				lr = lr->lr_parent;
				if ( --lr->lr_outrefcnt > 0 ) {
					break;	/* not completely done yet */
				}
			}

742
743
744
745
746
747
748
749
750
751
752
753
			/* Check if all requests are finished, lr is now parent */
			tmplr = lr;
			if (tmplr->lr_status == LDAP_REQST_COMPLETED) {
				for(tmplr=lr->lr_child; tmplr != NULL; tmplr=tmplr->lr_refnext) {
				if( tmplr->lr_status != LDAP_REQST_COMPLETED) {
					break;
					}
				}
			}

			/* This is the parent request if the request has referrals */
			if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL && tmplr == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
754
755
				id = lr->lr_msgid;
				tag = lr->lr_res_msgtype;
756
757
758
759
760
761
762
763
#ifdef NEW_LOGGING
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
				"read1msg: request %ld done\n", (long) id ));
			LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
				"read1msg: res_errno: %d,res_error: <%s>, res_matched: <%s>\n",
				lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
				lr->lr_res_matched ? lr->lr_res_matched : "" ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
764
				Debug( LDAP_DEBUG_ANY, "request %ld done\n",
765
				    (long) id, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
766
767
768
769
Debug( LDAP_DEBUG_TRACE,
"res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
lr->lr_res_matched ? lr->lr_res_matched : "" );
770
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
771
				if ( !simple_request ) {
772
773
					ber_free( ber, 1 );
					ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
774
775
776
777
778
779
					if ( build_result_ber( ld, &ber, lr )
					    == LBER_ERROR ) {
						rc = -1; /* fatal error */
					}
				}

780
				ldap_free_request( ld, lr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
781
782
783
			}

			if ( lc != NULL ) {
784
				ldap_free_connection( ld, lc, 0, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
785
786
787
788
			}
		}
	}

789
	if ( ber == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
790
791
792
793
		return( rc );
	}

	/* make a new ldap message */
794
	if ( (new = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) ))
Kurt Zeilenga's avatar
Kurt Zeilenga committed
795
796
797
798
799
800
	    == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		return( -1 );
	}
	new->lm_msgid = (int)id;
	new->lm_msgtype = tag;
801
	new->lm_ber = ber;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
802

803
#ifndef LDAP_NOCACHE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
804
		if ( ld->ld_cache != NULL ) {
805
			ldap_add_result_to_cache( ld, new );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
806
		}
807
#endif /* LDAP_NOCACHE */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
808
809
810

	/* is this the one we're looking for? */
	if ( msgid == LDAP_RES_ANY || id == msgid ) {
811
		if ( all == LDAP_MSG_ONE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
812
		    || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT
813
814
		    && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY
		    && new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
815
816
817
818
819
820
821
822
823
824
825
826
827
828
			*result = new;
			ld->ld_errno = LDAP_SUCCESS;
			return( tag );
		} else if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
			foundit = 1;	/* return the chain later */
		}
	}

	/* 
	 * if not, we must add it to the list of responses.  if
	 * the msgid is already there, it must be part of an existing
	 * search response.
	 */

829
830
	prev = NULL;
	for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
831
832
833
834
835
836
		if ( l->lm_msgid == new->lm_msgid )
			break;
		prev = l;
	}

	/* not part of an existing search response */
837
	if ( l == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
838
839
840
841
842
843
844
845
846
847
848
		if ( foundit ) {
			*result = new;
			ld->ld_errno = LDAP_SUCCESS;
			return( tag );
		}

		new->lm_next = ld->ld_responses;
		ld->ld_responses = new;
		return( -2 );	/* continue looking */
	}

849
850
851
852
853
854
855
856
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
		"read1msg: adding response id %ld type %ld\n",
		(long) new->lm_msgid, (long) new->lm_msgtype ));
#else
	Debug( LDAP_DEBUG_TRACE, "adding response id %ld type %ld:\n",
	    (long) new->lm_msgid, (long) new->lm_msgtype, 0 );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
857
858

	/* part of a search response - add to end of list of entries */
859
860
861
862
	for ( tmp = l; (tmp->lm_chain != NULL) &&
	    	((tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY) ||
	    	 (tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE) ||
			 (tmp->lm_chain->lm_msgtype == LDAP_RES_EXTENDED_PARTIAL ));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
863
864
865
866
867
868
	    tmp = tmp->lm_chain )
		;	/* NULL */
	tmp->lm_chain = new;

	/* return the whole chain if that's what we were looking for */
	if ( foundit ) {
869
		if ( prev == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
870
871
872
873
874
			ld->ld_responses = l->lm_next;
		else
			prev->lm_next = l->lm_next;
		*result = l;
		ld->ld_errno = LDAP_SUCCESS;
875
876
877
878
879
880
881
882
883
884
#ifdef LDAP_WORLD_P16
		/*
		 * XXX questionable fix; see text for [P16] on
		 * http://www.critical-angle.com/ldapworld/patch/
		 *
		 * inclusion of this patch causes searchs to hang on
		 * multiple platforms
		 */
		return( l->lm_msgtype );
#else	/* LDAP_WORLD_P16 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
885
		return( tag );
886
#endif	/* !LDAP_WORLD_P16 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
887
888
889
890
891
892
	}

	return( -2 );	/* continue looking */
}


893
894
static ber_tag_t
build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
895
{
896
897
898
899
900
901
902
903
904
905
906
907
	ber_len_t	len;
	ber_tag_t	tag;
	ber_int_t	along;
	BerElement *ber;

	*bp = NULL;
	ber = ldap_alloc_ber_with_options( ld );

	if( ber == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		return LBER_ERROR;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
908
909

	if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
910
	    lr->lr_res_msgtype, lr->lr_res_errno,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
911
	    lr->lr_res_matched ? lr->lr_res_matched : "",
912
913
914
915
	    lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {

		ld->ld_errno = LDAP_ENCODING_ERROR;
		ber_free(ber, 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
916
917
918
919
		return( LBER_ERROR );
	}

	ber_reset( ber, 1 );
920

Kurt Zeilenga's avatar
Kurt Zeilenga committed
921
	if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
922
923
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free(ber, 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
924
925
926
927
		return( LBER_ERROR );
	}

	if ( ber_get_int( ber, &along ) == LBER_ERROR ) {
928
929
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free(ber, 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
930
931
932
		return( LBER_ERROR );
	}

933
934
935
936
937
938
939
940
941
942
	tag = ber_peek_tag( ber, &len );

	if ( tag == LBER_ERROR ) {
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free(ber, 1);
		return( LBER_ERROR );
	}

	*bp = ber;
	return tag;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
943
944
945
946
947
948
949
950
951
952
953
954
}


static void
merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
{
/*
 * Merge error information in "lr" with "parentr" error code and string.
 */
	if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
		parentr->lr_res_errno = lr->lr_res_errno;
		if ( lr->lr_res_error != NULL ) {
955
			(void)ldap_append_referral( ld, &parentr->lr_res_error,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
956
957
958
959
960
961
			    lr->lr_res_error );
		}
	} else if ( lr->lr_res_errno != LDAP_SUCCESS &&
	    parentr->lr_res_errno == LDAP_SUCCESS ) {
		parentr->lr_res_errno = lr->lr_res_errno;
		if ( parentr->lr_res_error != NULL ) {
962
			LDAP_FREE( parentr->lr_res_error );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
963
964
965
		}
		parentr->lr_res_error = lr->lr_res_error;
		lr->lr_res_error = NULL;
966
		if ( LDAP_NAME_ERROR( lr->lr_res_errno )) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
967
			if ( parentr->lr_res_matched != NULL ) {
968
				LDAP_FREE( parentr->lr_res_matched );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
969
970
971
972
973
974
			}
			parentr->lr_res_matched = lr->lr_res_matched;
			lr->lr_res_matched = NULL;
		}
	}

975
976
977
978
979
980
981
982
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
		"read1msg: merged parent (id %d) error info: result errno %d, "
		"error <%s>, matched <%s>\n", parentr->lr_msgid,
	    parentr->lr_res_errno, parentr->lr_res_error ?
	    parentr->lr_res_error : "", parentr->lr_res_matched ?
	    parentr->lr_res_matched : "" ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
983
984
985
986
987
988
	Debug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
	    parentr->lr_msgid, 0, 0 );
	Debug( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n",
	    parentr->lr_res_errno, parentr->lr_res_error ?
	    parentr->lr_res_error : "", parentr->lr_res_matched ?
	    parentr->lr_res_matched : "" );
989
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
990
991
992
993
}



994
995
int
ldap_msgtype( LDAPMessage *lm )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
996
{
997
998
	assert( lm != NULL );
	return ( lm != NULL ) ? lm->lm_msgtype : -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
999
1000
1001
}


1002
1003
int
ldap_msgid( LDAPMessage *lm )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1004
{
1005
	assert( lm != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1006

1007
	return ( lm != NULL ) ? lm->lm_msgid : -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1008
1009
1010
}


1011
char * ldap_int_msgtype2str( ber_tag_t tag )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1012
{
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
	switch( tag ) {
	case LDAP_RES_ADD: return "add";
	case LDAP_RES_BIND: return "bind";
	case LDAP_RES_COMPARE: return "compare";
	case LDAP_RES_DELETE: return "delete";
	case LDAP_RES_EXTENDED: return "extended-result";
	case LDAP_RES_EXTENDED_PARTIAL: return "extended-partial";
	case LDAP_RES_MODIFY: return "modify";
	case LDAP_RES_RENAME: return "rename";
	case LDAP_RES_SEARCH_ENTRY: return "search-entry";
	case LDAP_RES_SEARCH_REFERENCE: return "search-reference";
	case LDAP_RES_SEARCH_RESULT: return "search-result";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1025
	}
1026
	return "unknown";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1027
1028
1029
1030
1031
1032
1033
1034
}

int
ldap_msgfree( LDAPMessage *lm )
{
	LDAPMessage	*next;
	int		type = 0;

1035
1036
1037
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_ENTRY, "ldap_msgfree\n" ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1038
	Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
1039
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1040

1041
	for ( ; lm != NULL; lm = next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1042
1043
1044
		next = lm->lm_chain;
		type = lm->lm_msgtype;
		ber_free( lm->lm_ber, 1 );
1045
		LDAP_FREE( (char *) lm );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
	}

	return( type );
}

/*
 * ldap_msgdelete - delete a message.  It returns:
 *	0	if the entire message was deleted
 *	-1	if the message was not found, or only part of it was found
 */
int
ldap_msgdelete( LDAP *ld, int msgid )
{
	LDAPMessage	*lm, *prev;

1061
1062
1063
1064
1065
	assert( ld != NULL );

#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_ENTRY, "ldap_msgdelete\n" ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1066
	Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
1067
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1068

1069
1070
	prev = NULL;
	for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1071
1072
1073
1074
1075
		if ( lm->lm_msgid == msgid )
			break;
		prev = lm;
	}

1076
	if ( lm == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1077
1078
		return( -1 );

1079
	if ( prev == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
		ld->ld_responses = lm->lm_next;
	else
		prev->lm_next = lm->lm_next;

	if ( ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY )
		return( -1 );

	return( 0 );
}


/*
 * return 1 if message msgid is waiting to be abandoned, 0 otherwise
 */
static int
1095
ldap_abandoned( LDAP *ld, ber_int_t msgid )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
{
	int	i;

	if ( ld->ld_abandoned == NULL )
		return( 0 );

	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
		if ( ld->ld_abandoned[i] == msgid )
			return( 1 );

	return( 0 );
}


static int
1111
ldap_mark_abandoned( LDAP *ld, ber_int_t msgid )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
{
	int	i;

	if ( ld->ld_abandoned == NULL )
		return( -1 );

	for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
		if ( ld->ld_abandoned[i] == msgid )
			break;

	if ( ld->ld_abandoned[i] == -1 )
		return( -1 );

	for ( ; ld->ld_abandoned[i] != -1; i++ ) {
		ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
	}

	return( 0 );
}