/********************************************************************

   Copyright (c) 1996 Novell, Inc.  All Rights Reserved.

   With respect to this file, Novell hereby grants to Developer a 
   royalty-free, non-exclusive license to include this sample code 
   and derivative binaries in its product. Novell grants to Developer 
   worldwide distribution rights to market, distribute or sell this 
   sample code file and derivative binaries as a component of 
   Developer's product(s).  Novell shall have no obligations to 
   Developer or Developer's customers with respect to this code.

   DISCLAIMER:

   Novell disclaims and excludes any and all express, implied, and 
   statutory warranties, including, without limitation, warranties 
   of good title, warranties against infringement, and the implied 
   warranties of merchantability and fitness for a particular purpose.  
   Novell does not warrant that the software will satisfy customer's 
   requirements or that the licensed works are without defect or error 
   or that the operation of the software will be uninterrupted.  
   Novell makes no warranties respecting any technical services or 
   support tools provided under the agreement, and disclaims all other 
   warranties, including the implied warranties of merchantability and 
   fitness for a particular purpose. */

/*********************************************************************
   NDSSEARC.C
**********************************************************************

   Description:

   Searches for all objects of a specified class and returns the
   name of each object found.  The base object (where the search
   begins) and the object class are passed in.  The search scope
   is set to DS_SEARCH_SUBTREE.  Since only names of the objects
   are needed, no attributes are specified to be returned.
   NWDSGetObjectCount and NWDSGetObjectName extract the results
   from the buffer.

   Syntax:  NDSSEARC <base object> <object class>

   This example requires a valid base name and class already
   defined in Directory Services.

*********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <nwnet.h>
#include <nwcalls.h>
#include <nwlocale.h>

/* cleanup functions and globals */
void   FreeBuf(pBuf_T cBuf, pBuf_T lBuf, NWDSContextHandle bcontext);
void   FreeFilter(pBuf_T cBuf, NWDSContextHandle context);
void   FreeContext(NWDSContextHandle context);
void   FreeUnicodeTables();
nbool8 bbDoLogout = N_FALSE;

void main(int argc, char *argv[])
{
   NWDSContextHandle context;
   nint32            lIterationHandle = NO_MORE_ITERATIONS;
   Object_Info_T     pObjectInfo;
   pBuf_T            pFilter;
   pBuf_T            pBuf;
   pFilter_Cursor_T  pCur;
   nuint32           luObjectCount;
   nuint32           luAttrCount;
   NWDSCCODE         ccode;
   nstr8             strAbbreviatedName[MAX_DN_CHARS+1];
   nstr8             strVal[MAX_DN_CHARS+1];
   nstr8             strObjectName[MAX_DN_CHARS+1];
   nstr8             strUserName[NW_MAX_USER_NAME_LEN];
   nstr8             strUserPassword[50];
   nuint             i;
   LCONV             lConvInfo;

   /* Check arguments */
   if(argc != 3)
   {
      printf("\nUsage   : NDSSEARC <base object> <object class>");
      printf("\nExample : NDSSEARC OU=MYOU.O=MYORG  USER");
      exit(1);
   }

   /* strVal is the class to search for */  
   strcpy(strVal, argv[2]);

   /* Initialize NWCalls and unicode tables */
   ccode = NWCallsInit(NULL,NULL);
   if(ccode)
   {
      printf("\nNWCallsInit returned %X", ccode);
      exit(1);
   }

   NWLlocaleconv(&lConvInfo);
   ccode = NWInitUnicodeTables(lConvInfo.country_id,
                               lConvInfo.code_page);
   if(ccode)
   {
      printf("\nNWInitUnicodeTables returned %X", ccode);
      exit(1);
   }

   /* Create NDS Context */
   context = NWDSCreateContext();
   if(context == ERR_CONTEXT_CREATION)
   {
      printf("\nNWDSCreateContext failed.");
      FreeUnicodeTables();
   }

   /*  Must authenticate if not already authenticated to NDS
       (which will always be the case if this example is 
       compiled and run as an NLM). */
   if(!NWIsDSAuthenticated())
   {
      printf("\nMust authenticate to NDS");
      printf("\nEnter User Name: ");
      gets(strUserName);
      printf("Enter User Password: ");
      gets(strUserPassword);

      ccode = NWDSLogin(context, 0, strUserName, strUserPassword, 0);
      if(ccode)
      {
         printf("\nNWDSLogin returned %X", ccode);
         FreeContext(context);
      }
      else
      {  /* If example logs in, it will also log out */
         bbDoLogout = N_TRUE;
      }
   }

   /* Convert the directory name (passed in as first arg) to its
      shortest form relative to the name context */
   ccode = NWDSAbbreviateName(context, argv[1], strAbbreviatedName);
   if(ccode)
   {
      printf("\nNWDSAbbreviatedName returned %X", ccode);
      FreeContext(context);
   }
   else
      printf("\nbase object being used is %s", strAbbreviatedName);

   /* Allocate the buffer to hold the search filter.  */
   ccode = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &pFilter);
   if(ccode)
   {
      printf("\nNWDSAllocBuf returned %X", ccode);
      FreeContext(context);
   }

   /* Allocate the output buffer.  */
   ccode = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &pBuf);
   if(ccode)
   {
      printf("\nNWDSAllocBuf returned %X", ccode);
      FreeFilter(pFilter, context);
   }

   /* Initialize filter for a DSV_SEARCH_FILTER operation */
   ccode = NWDSInitBuf(context, DSV_SEARCH_FILTER, pFilter);
   if(ccode)
   {
      printf("\nNWDSInitBuf returned %X", ccode);
      FreeBuf(pBuf, pFilter, context);
   }

   /* Allocate space for the search filter - pCur holds the filter
      cursor data.  */
   ccode = NWDSAllocFilter(&pCur);
   if(ccode)
   {
      printf("\nNWDSAllocFilter returned %X", ccode);
      FreeBuf(pBuf, pFilter, context);
   }

   /* Add a node to the search filter expression tree. pCur is the
      filter cursor, FTOK_ANAME indicates that an attribute name is
      being added, the attribute name "Object Class" is next, and the
      syntax for the attribute, SYN_CLASS_NAME is last */
   ccode = NWDSAddFilterToken(pCur, FTOK_ANAME, "Object Class",
                              SYN_CLASS_NAME);
   if(ccode)
   {
      printf("\nNWDSAddFilterToken returned %X", ccode);
      FreeBuf(pBuf, pFilter, context);
   }

   /* Add the equal relational operator next */
   ccode = NWDSAddFilterToken(pCur, FTOK_EQ, NULL,(nuint32)NULL);
   if(ccode)
   {
      printf("\nNWDSAddFilterToken error %x\n", ccode);
      FreeBuf(pBuf, pFilter, context);
   }

   /* USE FTOK_AVAL to indicate that a value token is being placed and
      pass strVal since it contains the class value */
   ccode = NWDSAddFilterToken(pCur, FTOK_AVAL, strVal,
                              SYN_CLASS_NAME);
   if(ccode)
   {
      printf("\nNWDSAddFilterToken returned %X", ccode);
      FreeBuf(pBuf, pFilter, context);
   }

   /* USE FTOK_END to indicate the end of the expression */
   ccode = NWDSAddFilterToken(pCur, FTOK_END, NULL,(nuint32)NULL);
   if(ccode)
   {
      printf("\nNWDSAddFilterToken returned %X", ccode);
      FreeBuf(pBuf, pFilter, context);
   }

   /* Place finished search filter into the search input buffer */
   ccode = NWDSPutFilter(context, pFilter, pCur, NULL);
   if(ccode)
   {
      printf("\nNWDSPutFilter returned %X", ccode);
      FreeBuf(pBuf, pFilter, context);
   }

   printf("\n\"%s\" objects under %s:", strVal, strAbbreviatedName);

   /* Do the search */
   do
   {   
      ccode = NWDSSearch(context,
                    strAbbreviatedName,   /* subtree to search      */
                    DS_SEARCH_SUBTREE,    /* scope is subtree       */
                    FALSE,                /* deref alias false      */
                    pFilter,              /* search filter          */
                    DS_ATTRIBUTE_VALUES,  /* info type to return    */
                    FALSE,                /* scope is false         */
                    NULL,                 /* attribute list is NULL */
                    &lIterationHandle,
                    0,
                    0,
                    pBuf);                /* buf for search result  */
      if(ccode)
      {
         printf("\nNWDSSearch returned  %X", ccode);
         FreeBuf(pBuf, pFilter, context);
      }

      ccode = NWDSGetObjectCount(context, pBuf, &luObjectCount);
      if(ccode)
      {
         printf("\nNWDSGetObjectCount returned %X", ccode);
         FreeBuf(pBuf, pFilter, context);
      }

      if(0 == luObjectCount)
      {
         printf("\nNone found for %s", strVal);
         FreeBuf(pBuf, pFilter, context);
      }

      /* For each object found, extract the name from the buffer */
      for(i = 0; i < luObjectCount; i++)
      {
         ccode = NWDSGetObjectName(context, pBuf, strObjectName,
                                   &luAttrCount, &pObjectInfo);
         if(ccode)
         {
            printf("\nNone found for %s", strVal);
            FreeBuf(pBuf, pFilter, context);
         }
      printf("\n%s", strObjectName);
      }

     /* loop back if more data */
   } while(lIterationHandle != NO_MORE_ITERATIONS);

   /* Clean up, normal termination */
   NWDSFreeBuf(pBuf);
   NWDSFreeBuf(pFilter);
   if(bbDoLogout)
      NWDSLogout(context);
   NWDSFreeContext(context);
   NWFreeUnicodeTables();
}

/* Clean up and exit, called on error condition only */
void FreeBuf(pBuf_T pBuf, pBuf_T pLBuf, NWDSContextHandle context)
{
   NWDSFreeBuf(pBuf);
   FreeFilter(pLBuf, context);
}

void FreeFilter(pBuf_T pFBuf, NWDSContextHandle context)
{
   NWDSFreeBuf(pFBuf);
   FreeContext(context);
}

void FreeContext(NWDSContextHandle context)
{
   if(bbDoLogout)
      NWDSLogout(context);
   NWDSFreeContext(context);
   FreeUnicodeTables();
}

void FreeUnicodeTables()
{
   NWFreeUnicodeTables();
   exit(1);
} 
