#if defined( UNICODE ) || defined( _UNICODE )
#error Sorry -- please compile as an ANSI program.
#endif

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#pragma hdrstop



#define MAXLEN 256



// type declarations, same for each OS
typedef DWORD (__stdcall *NetApiBufferFree_t)( void *buf );



// more type declarations, different for each OS
typedef DWORD (__stdcall *NetGetDCNameNT_t)( wchar_t *server, wchar_t *domain, byte **buf );
typedef DWORD (__stdcall *NetGetDCName95_t)( char *domain, byte **buf );

typedef DWORD (__stdcall *NetGroupEnumNT_t)( wchar_t *server, DWORD level, byte **buf,
	DWORD prefmaxlen, DWORD *entriesread, DWORD *totalentries, DWORD *resume );
typedef DWORD (__stdcall *NetGroupEnum95_t)( char *server, DWORD level, byte **buf,
	DWORD prefmaxlen, DWORD *entriesread, DWORD *totalentries, DWORD *resume );

typedef struct _GROUP_INFO_1_NT
{
	wchar_t *grpi1_name;
	wchar_t *grpi1_comment;
} GROUP_INFO_1_NT;
typedef struct _GROUP_INFO_1_95
{
	char *grpi1_name;
	char *grpi1_comment;
} GROUP_INFO_1_95;



int main( int argc, char *argv[] )
{
	if ( argc > 2 )
	{
		puts( "usage: nge [\\\\server]" );
		puts( "If \\\\server is not specified, the program looks for and asks the PDC." );
		return 1;
	}

	bool isNT = true;
	OSVERSIONINFO ovi = { sizeof ovi };

	// determine OS and load appropriate library

	GetVersionEx( &ovi );
	if ( ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
		isNT = false;

	HINSTANCE hNet = 0, hLoc = 0;

	if ( isNT )
		hNet = LoadLibrary( "netapi32.dll" );
	else
	{
		hLoc = LoadLibrary( "rlocal32.dll" );
		hNet = LoadLibrary( "radmin32.dll" );
	}

	if ( hNet == 0 )
	{
		printf( "LoadLibrary( %s ) failed, gle = %lu\n",
			isNT? "netapi32.dll": "radmin32.dll", GetLastError() );
		return 1;
	}

	// locate needed functions
	NetApiBufferFree_t NetApiBufferFree = 0;
	NetGetDCNameNT_t NetGetDCNameNT = 0;
	NetGetDCName95_t NetGetDCName95 = 0;
	NetGroupEnumNT_t NetGroupEnumNT = 0;
	NetGroupEnum95_t NetGroupEnum95 = 0;

	NetApiBufferFree = (NetApiBufferFree_t) GetProcAddress( hNet, "NetApiBufferFree" );
	if ( NetApiBufferFree == 0 )
	{
		printf( "Oops! GetProcAddress() failed\n" );
		return 1;
	}
	
	if ( isNT )
	{
		NetGetDCNameNT = (NetGetDCNameNT_t) GetProcAddress( hNet, "NetGetDCName" );
		NetGroupEnumNT = (NetGroupEnumNT_t) GetProcAddress( hNet, "NetGroupEnum" );
		if ( NetGetDCNameNT == 0 || NetGroupEnumNT == 0 )
		{
			printf( "Oops! Some functions not found ...\n" );
			return 1;
		}
	}
	else
	{
		NetGetDCName95 = (NetGetDCName95_t) GetProcAddress( hLoc, "LocalNetGetDCName" );
		NetGroupEnum95 = (NetGroupEnum95_t) GetProcAddress( hNet, "NetGroupEnumA" );
		if ( NetGetDCName95 == 0 || NetGroupEnum95 == 0 )
		{
			printf( "Oops! Some functions not found ...\n" );
			return 1;
		}
	}

	// find PDC if necessary; else set up server name for call

	byte *buf = 0;
	DWORD rc;
	char server[MAXLEN * sizeof wchar_t];

	if ( argc >= 2 ) // server was specified
	{
		if ( isNT )
			mbstowcs( (wchar_t *) server, argv[1], MAXLEN );
		else
			strcpy( server, argv[1] );
	}
	else // no server specified, find PDC
	{
		if ( isNT )
		{
			rc = NetGetDCNameNT( 0, 0, &buf );
			if ( rc )
			{
				printf( "NetGetDCNameNT() returned %lu\n", rc );
				return 1;
			}
			wcscpy( (wchar_t *) server, (wchar_t *) buf );
		}
		else
		{
			rc = NetGetDCName95( 0, &buf );
			if ( rc )
			{
				printf( "NetGetDCName95() returned %lu\n", rc );
				return 1;
			}
			strcpy( server, (char *) buf );
		}
		NetApiBufferFree( buf );
	}

	// now we know where to ask. Set up the call to NetGroupEnum().

	DWORD resumehandle = 0, read, total, i;
	char groupname[MAXLEN], groupcomment[MAXLEN];

	do
	{
		buf = 0;
		if ( isNT )
			rc = NetGroupEnumNT( (wchar_t *) server, 1, &buf, 2048, &read, &total, &resumehandle );
		else
			rc = NetGroupEnum95( server, 1, &buf, 2048, &read, &total, &resumehandle );

		if ( rc != ERROR_MORE_DATA && rc != ERROR_SUCCESS )
			break;

		printf( "\ngot %lu entries out of %lu\n", read, total );
		for ( i = 0; i < read; ++ i )
		{
			if ( isNT )
			{
				wcstombs( groupname, ((GROUP_INFO_1_NT *) buf)[i].grpi1_name, MAXLEN );
				wcstombs( groupcomment, ((GROUP_INFO_1_NT *) buf)[i].grpi1_comment, MAXLEN );
			}
			else
			{
				strncpy( groupname, ((GROUP_INFO_1_95 *) buf)[i].grpi1_name, MAXLEN );
				strncpy( groupcomment, ((GROUP_INFO_1_95 *) buf)[i].grpi1_comment, MAXLEN );
			}

			groupname[MAXLEN - 1] = '\0'; // because strncpy won't do this if overflow
			groupcomment[MAXLEN - 1] = '\0'; // because strncpy won't do this if overflow

			printf( "%-30.30s %.48s\n", groupname, groupcomment );
		}

		NetApiBufferFree( buf );

	} while ( rc == ERROR_MORE_DATA );

	if ( rc != ERROR_SUCCESS )
		printf( "NGE() returned %lu\n", rc );


	if ( hNet != 0 )
		FreeLibrary( hNet );
	if ( hLoc != 0 )
		FreeLibrary( hLoc );

	return 0;
}

