/*********************************************************************
   NDSREADA.C
**********************************************************************

   Description:

   Returns the telephone number attribute for a specified object
   taken from the command line.  Call NWDSInitBuf to initialize
   an input buffer for a read operation and NWDSPutAttrName
   to place attribute names into the input buffer.
   Three functions are used to retrieve results:
   NWDSGetAttrCount retrieves the number of attributes,
   NWDSGetAttName retrieves each attr name, the number attr
   values and syntax and NWDSGetAttVal retrieves attribute values

   Syntax:  ndsreada &lt;object name&gt;

   This example requires a valid user object name
   (for example, readobj CN=name.OU=myorgunit.O=myorg).  This example
   also requires that you login as SUPERVISOR (if you haven't
   authenticated to NDS before running the example, the program will
   prompt for user input and perform the authentication).


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

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

#define NUM_OF_ATTRS 3   /* obtain three attributes */

/* functions and globals */
void   ReadBuffer(NWDSContextHandle context, pBuf_T pBuf);
void   FreeInBuf(pBuf_T pBuf, NWDSContextHandle context);
void   FreeContext(NWDSContextHandle context);     
void   FreeUnicodeTables();
nbool8 bbDoLogout = N_FALSE;

void main(int argc, char *argv[])
{
   NWDSCCODE           ccode;
   nuint               i;
   LCONV               lConvInfo;

   if(argc != 2)
   {
      printf("\nUsage   :  NDSREADA object name");
      printf("\nExample :  NDSREADA .CN=MYNAME.O=MYORG");
      exit(1);
   }

		nstr8 strObject[MAX_DN_CHARS+1];
		strcpy(strObject, argv[1]);  /* strObject is object to read */

   /* 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 an NDS Context */
   NWDSContextHandle   context;
	 NWDSCreateContextHandle(&context);
   if(context == (NWDSContextHandle)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())
   {
			nstr8 strUserName[NW_MAX_USER_NAME_LEN];
			nstr8 strUserPassword[50];

      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;
      }
   }

   /* Allocate and initialize input buffer a directory services
      read operation. */
   pBuf_T              pInBuf;
   ccode = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &pInBuf);
   if(ccode)
   {
      printf("\nNWDSAllocBuf returned %X", ccode);
      FreeContext(context);
   }

   ccode = NWDSInitBuf(context, DSV_READ, pInBuf);
   if(ccode)
   {
      printf("\nNWDSInitBuf returned %X", ccode);
      FreeInBuf(pInBuf, context);
   }

   /* Allocate the output buffer to hold returned values */
   pBuf_T pOutBuf;
   ccode = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &pOutBuf);
   if(ccode)
   {
      printf("\nNWDSAllocBuf returned %X", ccode);
      FreeInBuf(pInBuf, context);
   }

   /* To prepare for the read, place the names of the attributes
      into the input buffer */
    pnstr8 strAttrName[] = {"Common Name",
                            "Surname",
                            "Telephone Number"};

   for(i = 0; i < NUM_OF_ATTRS; i++)
   {
      ccode = NWDSPutAttrName(context, pInBuf, strAttrName[i]);
      if(ccode)
      {
         printf("\nNWDSPutAttrName returned %X", ccode);
         NWDSFreeBuf(pOutBuf);
         FreeInBuf(pInBuf, context);
      }
   }

   /* Perform the read.  The second arg to NWDSRead specifies that
      attribute values are to be returned. The third attribute, FALSE,
      indicates that only attribute information is desired. */
   nint32 lIterationHandle = NO_MORE_ITERATIONS;

		do
		{
			ccode = NWDSRead(context, strObject, DS_ATTRIBUTE_VALUES, TRUE,
                    NULL, &lIterationHandle, pOutBuf);
			if(ccode)
			{
				printf("\nNWDSRead returned %d. Can't read object\n", ccode);
				NWDSFreeBuf(pOutBuf);
				FreeInBuf(pInBuf, context);
				break;
			}

			/* Call ReadBuf to get the data out of the output buffer */
			ReadBuffer(context, pOutBuf);
		}
		while(lIterationHandle != NO_MORE_ITERATIONS);
		
		/* Clean up, normal termination */
   NWDSFreeBuf(pOutBuf);
   NWDSFreeBuf(pInBuf);
   if(bbDoLogout)
      NWDSLogout(context);
   NWDSFreeContext(context);
   NWFreeUnicodeTables();
}

void ReadBuffer(NWDSContextHandle context, pBuf_T pBuf)
{
   nuint32      luSyntax;
   NWCCODE      ccode;
   nuint32      luAttrCount;
   nuint32      luAttrValCount=1;
   nstr8        strAttrName[MAX_DN_CHARS+1];
   nstr8        strAttrVal[MAX_DN_CHARS+1];
   nuint        i, j;

   /* Get the number of attributes in pBuf */

   ccode = NWDSGetAttrCount(context, pBuf, &luAttrCount);
   if(ccode)
   {
      printf("\nNWDSGetAttrCount returned %X", ccode);
      return;
   }

   /* Get the name and value for each attribute */
   for(i = 0; i < luAttrCount; i++)
   {
      ccode = NWDSGetAttrName(context, pBuf, strAttrName,
                              &luAttrValCount, &luSyntax);
      if(ccode)
      {
         printf("\nNWDSGetAttrName returned %X", ccode);
         return;
      }
      //printf("\nNWDSGetAttrName returned Count =%d, Name =%s\n",
      //        luAttrValCount, strAttrName);


      for(j=0; j < luAttrValCount; j++)
      {
         ccode = NWDSGetAttrVal(context, pBuf, luSyntax, strAttrVal);
         if(ccode)
         {
            printf("\nNWDSGetAttrVal returned %X", ccode);
            return;
         }
         printf("\n%s: %s",strAttrName, strAttrVal);
      }
   }
}

/* Clean up Functions, called on error condition only */
void FreeInBuf(pBuf_T pBuf, NWDSContextHandle context)
{
   NWDSFreeBuf(pBuf);
   FreeContext(context);
}

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

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

/**
 * \example NDSTree.cpp
 * Пример использования классов Context, NDSObject, String, Exception.
 * Данный пример демонстрирует простейшую программу, которая выводит
 * на консоль заданный строковый атрибут указанного объекта NDS.
 */
/*
#include <stdio.h>
#include "BGDNet.h"

using BGDNet::Context;
using BGDNet::NDSObject;
using BGDNet::String;
using BGDNet::Exception;

int main( int argc, char* argv[] )
{
  if (3 != argc)
  {
    puts("Usage: ReadAttr.exe <object> <attr>");
    return -1;
  }

  try
  {
    Context ctx;
    NDSObject obj(ctx, argv[1]);
    String val;
    if (obj.attr(argv[2], &val))
      printf("%s\n%s = %s\n", obj.dn().ptr(), argv[2], val.ptr());
    else
      printf("%s\n Attribute \"%s\" does not exist\n", obj.dn().ptr(), argv[2]);
  }
  catch (const Exception& e)
  {
    printf("ERROR: %s\n", e.what());
  }
  puts("----------");

  return 0;
}
*/