/*
 * FUNCTION: pkix_pl_LdapCertStore_GetCertContinue
 *  (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
 */
PKIX_Error *
pkix_pl_LdapCertStore_GetCertContinue(
        PKIX_CertStore *store,
        PKIX_CertSelector *selector,
        PKIX_VerifyNode *verifyNode,
        void **pNBIOContext,
        PKIX_List **pCertList,
        void *plContext)
{
        PKIX_Boolean cacheFlag = PKIX_FALSE;
        PKIX_PL_LdapCertStoreContext *lcs = NULL;
        void *pollDesc = NULL;
        PKIX_List *responses = NULL;
        PKIX_List *unfilteredCerts = NULL;
        PKIX_List *filteredCerts = NULL;

        PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCertContinue");
        PKIX_NULLCHECK_THREE(store, selector, pCertList);

        PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
                (store, (PKIX_PL_Object **)&lcs, plContext),
                PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);

        PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
                ((PKIX_PL_LdapClient *)lcs, &pollDesc, &responses, plContext),
                PKIX_LDAPCLIENTRESUMEREQUESTFAILED);

        if (pollDesc != NULL) {
                /* client is waiting for non-blocking I/O to complete */
                *pNBIOContext = (void *)pollDesc;
                *pCertList = NULL;
                goto cleanup;
        }
        /* LdapClient has given us a response! */

        if (responses) {
                PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
                        (store, &cacheFlag, plContext),
                        PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);

                PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
                        (responses, &unfilteredCerts, plContext),
                        PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);

                PKIX_CHECK(pkix_CertSelector_Select
                        (selector, unfilteredCerts, &filteredCerts, plContext),
                        PKIX_CERTSELECTORSELECTFAILED);
        }

        *pNBIOContext = NULL;
        *pCertList = filteredCerts;

cleanup:

        PKIX_DECREF(responses);
        PKIX_DECREF(unfilteredCerts);
        PKIX_DECREF(lcs);

        PKIX_RETURN(CERTSTORE);
}
/*
 * FUNCTION: pkix_pl_LdapCertStore_GetCRLContinue
 *  (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
 */
PKIX_Error *
pkix_pl_LdapCertStore_GetCRLContinue(
        PKIX_CertStore *store,
        PKIX_CRLSelector *selector,
        void **pNBIOContext,
        PKIX_List **pCrlList,
        void *plContext)
{
        void *nbio = NULL;
        PKIX_PL_CRL *candidate = NULL;
        PKIX_List *responses = NULL;
        PKIX_PL_LdapCertStoreContext *lcs = NULL;
        PKIX_List *filteredCRLs = NULL;
        PKIX_List *unfilteredCRLs = NULL;

        PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCRLContinue");
        PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCrlList);

        PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
                (store, (PKIX_PL_Object **)&lcs, plContext),
                PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);

        PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
                ((PKIX_PL_LdapClient *)lcs, &nbio, &responses, plContext),
                PKIX_LDAPCLIENTRESUMEREQUESTFAILED);

        if (nbio != NULL) {
                /* client is waiting for non-blocking I/O to complete */
                *pNBIOContext = (void *)nbio;
                *pCrlList = NULL;
                goto cleanup;
        }
        /* client has finished! */

        if (responses) {

                /*
                 * We have a List of LdapResponse objects that still have to be
                 * turned into Crls.
                 */
                PKIX_CHECK(pkix_pl_LdapCertStore_BuildCrlList
                        (responses, &unfilteredCRLs, plContext),
                        PKIX_LDAPCERTSTOREBUILDCRLLISTFAILED);

                PKIX_CHECK(pkix_CRLSelector_Select
                        (selector, unfilteredCRLs, &filteredCRLs, plContext),
                        PKIX_CRLSELECTORSELECTFAILED);

                PKIX_CHECK(PKIX_List_SetImmutable(filteredCRLs, plContext),
                        PKIX_LISTSETIMMUTABLEFAILED);

        }

        /* Don't throw away the list if one CRL was bad! */
        pkixTempErrorReceived = PKIX_FALSE;

        *pCrlList = filteredCRLs;

cleanup:
        if (PKIX_ERROR_RECEIVED) {
                PKIX_DECREF(filteredCRLs);
        }

        PKIX_DECREF(candidate);
        PKIX_DECREF(responses);
        PKIX_DECREF(unfilteredCRLs);
        PKIX_DECREF(lcs);

        PKIX_RETURN(CERTSTORE);
}
PKIX_Error *
pkix_pl_AIAMgr_GetLDAPCerts(
        PKIX_PL_AIAMgr *aiaMgr,
	PKIX_PL_InfoAccess *ia,
	void **pNBIOContext,
	PKIX_List **pCerts,
        void *plContext)
{
        PKIX_List *result = NULL;
        PKIX_PL_GeneralName *location = NULL;
        PKIX_PL_LdapClient *client = NULL;
        LDAPRequestParams request;
        PLArenaPool *arena = NULL;
        char *domainName = NULL;
	void *nbio = NULL;

        PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetLDAPCerts");
        PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts);

        nbio = *pNBIOContext;
        *pNBIOContext = NULL;
        *pCerts = NULL;

        if (nbio == NULL) { /* a new request */

                /* Initiate an LDAP request */

                request.scope = WHOLE_SUBTREE;
                request.derefAliases = NEVER_DEREF;
                request.sizeLimit = 0;
                request.timeLimit = 0;

                PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
                        (ia, &location, plContext),
                        PKIX_INFOACCESSGETLOCATIONFAILED);

                /*
                 * Get a short-lived arena. We'll be done with
                 * this space once the request is encoded.
                 */
                arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
                if (!arena) {
                        PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
                }

                PKIX_CHECK(pkix_pl_InfoAccess_ParseLocation
                        (location, arena, &request, &domainName, plContext),
                        PKIX_INFOACCESSPARSELOCATIONFAILED);

                PKIX_DECREF(location);

                /* Find or create a connection to LDAP server */
                PKIX_CHECK(pkix_pl_AiaMgr_FindLDAPClient
                        (aiaMgr, domainName, &client, plContext),
                        PKIX_AIAMGRFINDLDAPCLIENTFAILED);

                aiaMgr->client.ldapClient = client;

                PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
                        (aiaMgr->client.ldapClient,
			&request,
			&nbio,
			&result,
			plContext),
                        PKIX_LDAPCLIENTINITIATEREQUESTFAILED);

                PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));

        } else {

                PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
                        (aiaMgr->client.ldapClient, &nbio, &result, plContext),
                        PKIX_LDAPCLIENTRESUMEREQUESTFAILED);

        }

        if (nbio != NULL) { /* WOULDBLOCK */
                *pNBIOContext = nbio;
                *pCerts = NULL;
                goto cleanup;
        }

	PKIX_DECREF(aiaMgr->client.ldapClient);

	if (result == NULL) {
		*pCerts = NULL;
	} else {
		PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
			(result, pCerts, plContext),
			PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
	}

	*pNBIOContext = nbio;

cleanup:

        if (arena && (PKIX_ERROR_RECEIVED)) {
                PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));
        }

        if (PKIX_ERROR_RECEIVED) {
	        PKIX_DECREF(aiaMgr->client.ldapClient);
	}

        PKIX_DECREF(location);

        PKIX_RETURN(AIAMGR);
}