#include <stdio.h>
#include <stdlib.h>
#include <DirectoryService/DirectoryService.h>

#ifndef bool
typedef enum    { false = 0, true = 1 } bool;
#endif  /* bool */

// 32k buffer
#define BUFFERSIZE  32 * 1024  

int main( int argc, char *argv[] )
{
    int                       ret = 0 ;
    long                dirStatus = eDSNoErr ;

    tDirReference          dirRef = 0 ;
    tDirNodeReference     nodeRef = 0 ;

    const char          *nodePath = (argc > 1 ? argv[1] : "/Local/Default" );
    tDataListPtr         nodeName = NULL ;

    tDataList          recNames, recTypes, attrTypes ;

    tDataBufferPtr     dataBuffer = NULL;

    unsigned long        recCount = 0 ;
    tContextData       recContext = NULL  ;

  // open OD
    dirStatus = dsOpenDirService( &dirRef );
    if( dirStatus != eDSNoErr ) goto errexit ;

  // open node
    nodeName = dsBuildFromPath( dirRef, nodePath, "/" );
    if( nodeName == NULL )
    {
        fprintf( stderr, "name buffer allocate error\n") ;
        ret = 1; 
        goto toexit;
    }
    dirStatus = dsOpenDirNode( dirRef, nodeName, &nodeRef );
    if( dirStatus != eDSNoErr ) goto errexit ;

  // allocate buffer
    dataBuffer = dsDataBufferAllocate( dirRef, BUFFERSIZE );
    if( dataBuffer == NULL ) // allocate error
    {
        fprintf( stderr, "data buffer allocate error\n") ;
        ret = 1; 
        goto toexit;
    }

  // make query 
    dirStatus = dsBuildListFromStringsAlloc( dirRef, &recNames, "me", NULL );
    if( dirStatus != eDSNoErr ) goto errexit ;

    dirStatus = dsBuildListFromStringsAlloc( dirRef, &recTypes, kDSStdRecordTypeUsers, NULL );
    if( dirStatus != eDSNoErr ) goto errexit ;

    dirStatus = dsBuildListFromStringsAlloc( dirRef, &attrTypes, kDSAttributesAll, NULL );
    if( dirStatus != eDSNoErr ) goto errexit ;


    do {
        int                     i, j, k;
        tAttributeListRef         attrListRef =  0 ;
        tRecordEntry             *recEntryPtr = NULL ;

        tAttributeValueListRef   valueListRef =  0 ;
        tAttributeEntry         *attrEntryPtr = NULL ;

        tAttributeValueEntry   *valueEntryPtr = NULL ;

        dirStatus = dsGetRecordList(    nodeRef, 
                                     dataBuffer, 
                                      &recNames,
                                       eDSExact,
                                      &recTypes,
                                     &attrTypes,
                                          false,
                                      &recCount,
                                    &recContext );
        if( dirStatus != eDSNoErr ) goto errexit ;

        for( i = 1 ; i <= recCount; i++ )
        {
            dirStatus = dsGetRecordEntry( nodeRef, dataBuffer, i, &attrListRef, &recEntryPtr );
            if( dirStatus != eDSNoErr ) goto errexit ; // BUG: has memory-leak

            printf("RecordNumber: %d\n\n", i );
            for( j = 1 ; j <= recEntryPtr->fRecordAttributeCount ; j ++ )
            {
                dirStatus = dsGetAttributeEntry( nodeRef, dataBuffer, attrListRef, j, &valueListRef, &attrEntryPtr );
                if( dirStatus != eDSNoErr ) goto errexit ; // BUG: has memory-leak

                printf("  --------------------------------------------\n" );
                printf("  Attribute %d : %s:\n", j, attrEntryPtr->fAttributeSignature.fBufferData );
                for( k = 1 ; k <= attrEntryPtr->fAttributeValueCount ; k ++ )
                {
                    dirStatus = dsGetAttributeValue( nodeRef, dataBuffer, k, valueListRef, &valueEntryPtr );
                    printf("         Value %d : %s \n", k,valueEntryPtr->fAttributeValueData.fBufferData );
                    dsDeallocAttributeValueEntry( dirRef, valueEntryPtr );
                }
                dsDeallocAttributeEntry( dirRef, attrEntryPtr );
            }
            dsDeallocRecordEntry( dirRef, recEntryPtr );
            printf("\n------------------------------------------------\n" );
        }

    }while( recContext != NULL );

    goto toexit;

errexit:
    ret = 1;
    fprintf( stderr, "errocode = %d\n", dirStatus );
toexit:
    if( recContext != NULL )
        dsReleaseContinueData( dirRef, recContext );
    if( dataBuffer != NULL )
        dsDataBufferDeAllocate( dirRef, dataBuffer );
    if( nodeRef != 0 )
        dsCloseDirNode( nodeRef );
    if( dirRef != 0 )
        dsCloseDirService( dirRef );
    exit(ret);
}