result.c 29.3 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 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
650
651
				/* V3 search reference or V3 referral successfully chased */
				refer_cnt = 0;
652
			} else if ( ber_scanf( &tmpber, "{iaa}", &lderr,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
653
654
655
656
			    &lr->lr_res_matched, &lr->lr_res_error )
			    != LBER_ERROR ) {
				if ( lderr != LDAP_SUCCESS ) {
					/* referrals are in error string */
657
658
659
660
661
662
663
664
665
666
667
668
					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
669
670
671
672
673
674
675
676
677
678
679
680
				}

				/* 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;
				}
681
682
683
684
685
686
#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
687
688
689
690
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 : "" );
691
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
692
693
694
			}
		}

695
696
697
698
#ifdef NEW_LOGGING
		LDAP_LOG (( "result", LDAP_LEVEL_DETAIL1, 
			"read1msg: %d new referrals\n", refer_cnt ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
699
700
		Debug( LDAP_DEBUG_TRACE,
		    "read1msg:  %d new referrals\n", refer_cnt, 0, 0 );
701
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
702
703

		if ( refer_cnt != 0 ) {	/* chasing referrals */
704
705
			ber_free( ber, 1 );
			ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
706
707
708
			if ( refer_cnt < 0 ) {
				return( -1 );	/* fatal error */
			}
709
			lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
710
711
712
713
714
715
		} 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 */
716
717
				ber_free( ber, 1 );
				ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
718
719
			}

720
721
722
723
724
725
726
727
			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
728
729
730
731
732
733
734
735
736
			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 */
				}
			}

737
738
739
740
741
742
743
744
745
746
747
748
			/* 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
749
750
				id = lr->lr_msgid;
				tag = lr->lr_res_msgtype;
751
752
753
754
755
756
757
758
#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
759
				Debug( LDAP_DEBUG_ANY, "request %ld done\n",
760
				    (long) id, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
761
762
763
764
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 : "" );
765
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
766
				if ( !simple_request ) {
767
768
					ber_free( ber, 1 );
					ber = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
769
770
771
772
773
774
					if ( build_result_ber( ld, &ber, lr )
					    == LBER_ERROR ) {
						rc = -1; /* fatal error */
					}
				}

775
				ldap_free_request( ld, lr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
776
777
778
			}

			if ( lc != NULL ) {
779
				ldap_free_connection( ld, lc, 0, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
780
781
782
783
			}
		}
	}

784
	if ( ber == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
785
786
787
788
		return( rc );
	}

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

798
#ifndef LDAP_NOCACHE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
799
		if ( ld->ld_cache != NULL ) {
800
			ldap_add_result_to_cache( ld, new );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
801
		}
802
#endif /* LDAP_NOCACHE */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
803
804
805

	/* is this the one we're looking for? */
	if ( msgid == LDAP_RES_ANY || id == msgid ) {
806
		if ( all == LDAP_MSG_ONE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
807
		    || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT
808
809
		    && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY
		    && new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
810
811
812
813
814
815
816
817
818
819
820
821
822
823
			*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.
	 */

824
825
	prev = NULL;
	for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
826
827
828
829
830
831
		if ( l->lm_msgid == new->lm_msgid )
			break;
		prev = l;
	}

	/* not part of an existing search response */
832
	if ( l == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
833
834
835
836
837
838
839
840
841
842
843
		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 */
	}

844
845
846
847
848
849
850
851
#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
852
853

	/* part of a search response - add to end of list of entries */
854
855
856
857
	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
858
859
860
861
862
863
	    tmp = tmp->lm_chain )
		;	/* NULL */
	tmp->lm_chain = new;

	/* return the whole chain if that's what we were looking for */
	if ( foundit ) {
864
		if ( prev == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
865
866
867
868
869
			ld->ld_responses = l->lm_next;
		else
			prev->lm_next = l->lm_next;
		*result = l;
		ld->ld_errno = LDAP_SUCCESS;
870
871
872
873
874
875
876
877
878
879
#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
880
		return( tag );
881
#endif	/* !LDAP_WORLD_P16 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
882
883
884
885
886
887
	}

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


888
889
static ber_tag_t
build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
890
{
891
892
893
894
895
896
897
898
899
900
901
902
	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
903
904

	if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
905
	    lr->lr_res_msgtype, lr->lr_res_errno,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
906
	    lr->lr_res_matched ? lr->lr_res_matched : "",
907
908
909
910
	    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
911
912
913
914
		return( LBER_ERROR );
	}

	ber_reset( ber, 1 );
915

Kurt Zeilenga's avatar
Kurt Zeilenga committed
916
	if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
917
918
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free(ber, 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
919
920
921
922
		return( LBER_ERROR );
	}

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

928
929
930
931
932
933
934
935
936
937
	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
938
939
940
941
942
943
944
945
946
947
948
949
}


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 ) {
950
			(void)ldap_append_referral( ld, &parentr->lr_res_error,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
951
952
953
954
955
956
			    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 ) {
957
			LDAP_FREE( parentr->lr_res_error );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
958
959
960
		}
		parentr->lr_res_error = lr->lr_res_error;
		lr->lr_res_error = NULL;
961
		if ( LDAP_NAME_ERROR( lr->lr_res_errno )) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
962
			if ( parentr->lr_res_matched != NULL ) {
963
				LDAP_FREE( parentr->lr_res_matched );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
964
965
966
967
968
969
			}
			parentr->lr_res_matched = lr->lr_res_matched;
			lr->lr_res_matched = NULL;
		}
	}

970
971
972
973
974
975
976
977
#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
978
979
980
981
982
983
	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 : "" );
984
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
985
986
987
988
}



989
990
int
ldap_msgtype( LDAPMessage *lm )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
991
{
992
993
	assert( lm != NULL );
	return ( lm != NULL ) ? lm->lm_msgtype : -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
994
995
996
}


997
998
int
ldap_msgid( LDAPMessage *lm )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
999
{
1000
	assert( lm != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1001

1002
	return ( lm != NULL ) ? lm->lm_msgid : -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1003
1004
1005
}


1006
char * ldap_int_msgtype2str( ber_tag_t tag )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1007
{
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
	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
1020
	}
1021
	return "unknown";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1022
1023
1024
1025
1026
1027
1028
1029
}

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

1030
1031
1032
#ifdef NEW_LOGGING
	LDAP_LOG (( "result", LDAP_LEVEL_ENTRY, "ldap_msgfree\n" ));
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1033
	Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
1034
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1035

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

	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;

1056
1057
1058
1059
1060
	assert( ld != NULL );

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

1064
1065
	prev = NULL;
	for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1066
1067
1068
1069
1070
		if ( lm->lm_msgid == msgid )
			break;
		prev = lm;
	}

1071
	if ( lm == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1072
1073
		return( -1 );

1074
	if ( prev == NULL )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
		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
1090
ldap_abandoned( LDAP *ld, ber_int_t msgid )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
{
	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
1106
ldap_mark_abandoned( LDAP *ld, ber_int_t msgid )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
{
	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 );
}