/*
 * FUNCTION: PKIX_PL_AIAMgr_GetAIACerts (see description in pkix_pl_pki.h)
 */
PKIX_Error *
PKIX_PL_AIAMgr_GetAIACerts(
        PKIX_PL_AIAMgr *aiaMgr,
        PKIX_PL_Cert *prevCert,
        void **pNBIOContext,
        PKIX_List **pCerts,
        void *plContext)
{
        PKIX_UInt32 numAias = 0;
        PKIX_UInt32 aiaIndex = 0;
        PKIX_UInt32 iaType = PKIX_INFOACCESS_LOCATION_UNKNOWN;
        PKIX_List *certs = NULL;
        PKIX_PL_InfoAccess *ia = NULL;
        void *nbio = NULL;

        PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_GetAIACerts");
        PKIX_NULLCHECK_FOUR(aiaMgr, prevCert, pNBIOContext, pCerts);

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

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

                /* Does this Cert have an AIA extension? */
                PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess
                        (prevCert, &aiaMgr->aia, plContext),
                        PKIX_CERTGETAUTHORITYINFOACCESSFAILED);

                if (aiaMgr->aia != NULL) {
                        PKIX_CHECK(PKIX_List_GetLength
                                (aiaMgr->aia, &numAias, plContext),
                                PKIX_LISTGETLENGTHFAILED);
                }

                /* And if so, does it have any entries? */
                if ((aiaMgr->aia == NULL) || (numAias == 0)) {
                        *pCerts = NULL;
                        goto cleanup;
                }

                aiaMgr->aiaIndex = 0;
                aiaMgr->numAias = numAias;
                aiaMgr->results = NULL;

        }

        for (aiaIndex = aiaMgr->aiaIndex;
                aiaIndex < aiaMgr->numAias;
                aiaIndex ++) {
                PKIX_UInt32 method = 0;

                PKIX_CHECK(PKIX_List_GetItem
                        (aiaMgr->aia,
                        aiaIndex,
                        (PKIX_PL_Object **)&ia,
                        plContext),
                        PKIX_LISTGETITEMFAILED);

                PKIX_CHECK(PKIX_PL_InfoAccess_GetMethod
                        (ia, &method, plContext),
                        PKIX_INFOACCESSGETMETHODFAILED);

                if (method != PKIX_INFOACCESS_CA_ISSUERS &&
                    method != PKIX_INFOACCESS_CA_REPOSITORY) {
                    PKIX_DECREF(ia);
                    continue;
                }
                
                PKIX_CHECK(PKIX_PL_InfoAccess_GetLocationType
                        (ia, &iaType, plContext),
                        PKIX_INFOACCESSGETLOCATIONTYPEFAILED);

                if (iaType == PKIX_INFOACCESS_LOCATION_HTTP) {
			PKIX_CHECK(pkix_pl_AIAMgr_GetHTTPCerts
				(aiaMgr, ia, &nbio, &certs, plContext),
				PKIX_AIAMGRGETHTTPCERTSFAILED);
                } else if (iaType == PKIX_INFOACCESS_LOCATION_LDAP) {
			PKIX_CHECK(pkix_pl_AIAMgr_GetLDAPCerts
				(aiaMgr, ia, &nbio, &certs, plContext),
				PKIX_AIAMGRGETLDAPCERTSFAILED);
                } else {
                        /* We only support http and ldap requests. */
                        PKIX_DECREF(ia);
                        continue;
                }

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

                /*
                 * We can't just use and modify the List we received.
                 * Because it's cached, it's set immutable.
                 */
                if (aiaMgr->results == NULL) {
                        PKIX_CHECK(PKIX_List_Create
                                (&(aiaMgr->results), plContext),
                                PKIX_LISTCREATEFAILED);
                }
                PKIX_CHECK(pkix_List_AppendList
                        (aiaMgr->results, certs, plContext),
                        PKIX_APPENDLISTFAILED);
                PKIX_DECREF(certs);

                PKIX_DECREF(ia);
        }

        PKIX_DECREF(aiaMgr->aia);

        *pNBIOContext = NULL;
        *pCerts = aiaMgr->results;
        aiaMgr->results = NULL;

cleanup:

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

        PKIX_DECREF(certs);
        PKIX_DECREF(ia);

        PKIX_RETURN(AIAMGR);
}
int test_subjectinfoaccess(int argc, char *argv[]) {

        PKIX_PL_Cert *cert = NULL;
        PKIX_PL_Cert *certDiff = NULL;
        PKIX_List *aiaList = NULL;
        PKIX_List *siaList = NULL;
        PKIX_PL_InfoAccess *sia = NULL;
        PKIX_PL_InfoAccess *siaDup = NULL;
        PKIX_PL_InfoAccess *siaDiff = NULL;
        PKIX_PL_GeneralName *location = NULL;
        char *certPathName = NULL;
        char *dirName = NULL;
        PKIX_UInt32 method = 0;
        PKIX_UInt32 actualMinorVersion;
        PKIX_UInt32 size, i;
        PKIX_UInt32 j = 0;
        char *expectedAscii = "[method:caRepository, "
                "location:http://betty.nist.gov/pathdiscoverytestsuite/"
                "p7cfiles/IssuedByTrustAnchor1.p7c]";

        PKIX_TEST_STD_VARS();

        startTests("SubjectInfoAccess");

        PKIX_TEST_EXPECT_NO_ERROR(
            PKIX_PL_NssContext_Create(0, PKIX_FALSE, NULL, &plContext));

        if (argc < 5+j) {
                printf("Usage: %s <test-purpose> <cert> <diff-cert>\n", argv[0]);
        }

        dirName = argv[2+j];
        certPathName = argv[3+j];

        subTest("Creating Cert with Subject Info Access");
        cert = createCert(dirName, certPathName, plContext);

        certPathName = argv[4+j];

        subTest("Creating Cert with Subject Info Access");
        certDiff = createCert(dirName, certPathName, plContext);

        subTest("Getting Subject Info Access");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetSubjectInfoAccess
                (cert, &siaList, plContext));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetLength
                (siaList, &size, plContext));

        if (size != 1) {
                pkixTestErrorMsg = "unexpected number of AIA";
                goto cleanup;
        }
 
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetItem
                (siaList, 0, (PKIX_PL_Object **) &sia, plContext));

        subTest("PKIX_PL_InfoAccess_GetMethod");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_InfoAccess_GetMethod
                (sia, &method, plContext));
        if (method != PKIX_INFOACCESS_CA_REPOSITORY) {
                pkixTestErrorMsg = "unexpected method of AIA";
                goto cleanup;
        }

        subTest("PKIX_PL_InfoAccess_GetLocation");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_InfoAccess_GetLocation
                (sia, &location, plContext));
        if (!location) {
                pkixTestErrorMsg = "Cannot get AIA location";
                goto cleanup;
        }

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetItem
                (siaList, 0, (PKIX_PL_Object **) &siaDup, plContext));

        subTest("Getting Authority Info Access as difference comparison");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetAuthorityInfoAccess
                (certDiff, &aiaList, plContext));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetLength
                (aiaList, &size, plContext));

        if (size != 1) {
                pkixTestErrorMsg = "unexpected number of AIA";
                goto cleanup;
        }
 
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetItem
                (aiaList, 0, (PKIX_PL_Object **) &siaDiff, plContext));

        subTest("Checking: Equal, Hash and ToString");
        PKIX_TEST_EQ_HASH_TOSTR_DUP
                (sia, siaDup, siaDiff, expectedAscii, InfoAccess, PKIX_FALSE);



cleanup:

        PKIX_TEST_DECREF_AC(location);
        PKIX_TEST_DECREF_AC(sia);
        PKIX_TEST_DECREF_AC(siaDup);
        PKIX_TEST_DECREF_AC(siaDiff);
        PKIX_TEST_DECREF_AC(aiaList);
        PKIX_TEST_DECREF_AC(siaList);
        PKIX_TEST_DECREF_AC(cert);
        PKIX_TEST_DECREF_AC(certDiff);
     
        PKIX_Shutdown(plContext);

        PKIX_TEST_RETURN();

        endTests("Subjectinfoaccess");

        return (0);
}