/************************************************************************/
/*	Copyright (C) 2004  Michael C. Shultz				*/
/*									*/
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License, or (at*/
/* your option) any later version.					*/
/*									*/
/* This program is distributed in the hope that it will be useful,	*/
/* but WITHOUT ANY WARRANTY; without even the implied warranty of	*/
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the	*/
/* GNU General Public License for more details. 			*/
/*									*/
/* You should have received a copy of the GNU General Public License	*/
/* along with this program; if not, write to the Free Software		*/
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA		*/
/*  02111-1307, USA.							*/
/* 									*/
/* Michael C. Shultz							*/
/* ringworm@inbox.lv							*/
/* Box 3238 Landers, CA 92285						*/
/************************************************************************/
/*
variable index:

in	PMGRrDbCreate.h

PKG_DBDIR		also in bsd.port.mk
PORTS_INSTALLED_DB
PORT_DEPENDENCIES_DB
*/
#include	<PMGRrDbCreate.h>

typedef struct
{
	DIR*			dir;
	DIR*			portDir;
	char*			fileName;
	char*			portDirName;
	unsigned	int	portDirNameLen;
	struct dirent*		entry;
} struc_pkg;

int	pkgDirEntryFilter( struc_pkg* );

int	PMGRrDbCreate( void )
{
	FILE*			portIPStream		= NULL;
	FILE*			portIStream		= NULL;
	FILE*			portStream		= NULL;
	char			id[]			= "PMGRrDbCreate";
	char*			buffPtr 		= NULL;
	char*			portBuffer		= NULL;
	char*			portDependency		= NULL;
	char*			portDependencyDir	= NULL;
	char*			portDir 		= NULL;
	char*			portName		= NULL;
	int			errorCode		= 0;
	int			idx			= 0;
	int			portDependencyDirLen	= 0;
	int			portDependencyLen	= 0;
	int			portDirLen 		= 0;
	int			portNameLen		= 0;
	struc_pkg		pkg;
	unsigned	int	size			= 0;

	/* set pkg structure initial values */
	MGmSetString( pkg.fileName, PKG_DBDIR )
	if( errorCode )
	{
		fprintf( stderr, "%s %s error: mSetString returned code 1\n", id, ver );
		perror( "system message" );
		return( 1 );
	}
	if( !( portIStream = fopen( DATADIR PORTS_INSTALLED_DB, "w" ) ) )
	{
		fprintf( stderr, "%s %s error: unable to open %s%s for write\n",
			id,  ver, DATADIR, PORTS_INSTALLED_DB );
		fprintf( stderr, "you must run this program as root and path %s must exist and be writable\n",
			DATADIR );
		perror( "system message" );
		return( 1 );
	}
	if( !( portIPStream = fopen( DATADIR PORT_DEPENDENCIES_DB, "w" ) ) )
	{
		fprintf( stderr, "%s %s error: unable to open %s%s for write\n",
		id,  ver, DATADIR, PORT_DEPENDENCIES_DB );
		fprintf( stderr, "you must run this program as root and path %s must exist and be writable\n",
			DATADIR );
		perror( "system message" );
		return( 1 );
	}

	/********************************************************/
	/*	1 Get the directory entries in /var/db/pkg	*/
	/*	2 Filter out ".", ".."				*/
	/*	3 Filter out any entry that is not a directory	*/
	/*		3.1 This should be an effective work	*/
	/*		around for those who have portupgrade	*/
	/*		installed and therefore a "pkgdb.db" in */
	/*		their /var/db/pkg directory		*/
	/********************************************************/
	if( !( pkg.dir = opendir( pkg.fileName ) ) )
	{
		fprintf( stderr, "%s %s error: could not open dir %s\n", id, ver, pkg.fileName );
		perror( "system message" );
		return( 1 );
	}
	
	/* print /var/db/pkg directory entries */ 
	while( ( pkg.entry = readdir( pkg.dir ) ) )
	{
		pkg.portDirNameLen	= 
			strlen( pkg.fileName ) + strlen( pkg.entry->d_name ) + strlen( "/+CONTENTS" ) + 2;
		pkg.portDirName		= ( char* )malloc( pkg.portDirNameLen );
		strcpy( pkg.portDirName, pkg.fileName );
		strcat( pkg.portDirName, "/" );
		strcat( pkg.portDirName, pkg.entry->d_name );
		if( pkgDirEntryFilter( &pkg ) )
		{
			/* if entry matches filter then get next entry */
			free( pkg.portDirName );
			continue;
		}
		strcat( pkg.portDirName, "/+CONTENTS" );
		if( !( portStream = fopen( pkg.portDirName, "r" ) ) )
		{
			fprintf( stderr, "%s %s error: could not open %s\n", id, ver, pkg.portDirName );
			perror( "system message" );
			return( 1 );
		}
		size	= MGrFileSize( pkg.portDirName );
		if( !( portBuffer = ( char* )malloc( size ) ) )
		{
			fprintf( stderr, 
				"%s %s error: could allocate %d bytes for %s buffer\n",
				 id, ver, size, pkg.portDirName );
			perror( "system message" );
			return( 1 );
		}
		fread( portBuffer, 1, size, portStream );
		portBuffer[size+1]	= 0;
		portName		= strstr( portBuffer, "@name " ) + strlen( "@name " );
		portNameLen		= strstr( portName, "\n" ) - portName;
		portDir			= strstr( portBuffer, "@comment ORIGIN:" ) + strlen( "@comment ORIGIN:" );
		portDirLen		= strstr( portDir, "\n" ) - portDir;
		portName[portNameLen] 	= 0;
		portDir[portDirLen] 	= 0;
		fprintf( portIStream, "%s%c%s%c\n", portName, NULL, portDir, NULL );
		portName[portNameLen] 	= 10;
		portDir[portDirLen] 	= 10;
		/************************************************************************/
		/* dependencies								*/
		/************************************************************************/
		buffPtr =	portDir + portDirLen + 1;
		size	= strlen( portBuffer ) - ( buffPtr - portBuffer );
		portName[portNameLen] 	= 0;
		while( ( portDependency = strstr( buffPtr, "@pkgdep " ) ) )
		{
			portDependency		+= strlen( "@pkgdep " ); 
			portDependencyLen	= strstr( portDependency, "\n" ) - portDependency;
			portDependency[portDependencyLen] = 0;
			
			buffPtr 		= portDependency + portDependencyLen + 1;

			portDependencyDir	= strstr( buffPtr, "@comment DEPORIGIN:" );
			portDependencyDir	+= strlen( "@comment DEPORIGIN:" );
			portDependencyDirLen	= strstr( portDependencyDir, "\n" ) - portDependencyDir;
			portDependencyDir[portDependencyDirLen]	= 0;

			buffPtr 		= portDependencyDir + portDependencyDirLen + 1;

			if( portDependencyDir && portDependency )
			{
				fprintf( portIPStream,
					"%s%c%s%c%s%c\n",
					portName, NULL,
					portDependency, NULL,
					portDependencyDir, NULL );
			}
			else
			{
				fprintf( stderr, "%s %s error: error in dependency section\n", id, ver ); 
				return( 1 );
			}
		}

		/************************************************************************/
		free( portBuffer );
		free( pkg.portDirName );
		idx++;
	}
	if( closedir( pkg.dir ) == -1 )
	{
		fprintf( stderr, "%s %s error: could not close dir %s\n", id, ver, pkg.fileName );
		perror( "system message" );
		return( 1 );
	}
	fflush( portIStream );
	fflush( portIPStream );
	fclose( portIStream );
	fclose( portIPStream );
	free( pkg.fileName );
	return( 0 );
}

/************************************************************************/
/*	1 Filter out ".", ".."						*/
/*		2 Filter out any entry that is not a dirctory		*/
/*			2.1 This should be an effective work around for */
/*			those who have portupgrade installed and	*/
/*			therefore a "pkgdb.db" in their /var/db/pkg	*/ 		
/************************************************************************/
int	pkgDirEntryFilter(  struc_pkg* pkg  )
{
	FILE*	testStream	= 0;

	/* filter #1 */
	/* filter out . and .. entries */
	if( strcmp( pkg->entry->d_name, "." ) == 0 || strcmp( pkg->entry->d_name, ".." ) == 0 )
	{
		if( strlen( pkg->entry->d_name ) < 3 )
		{
			return( 1 );
		}
	}

	/* filter #2 */
	/* make sure pkg->entry->d_name is a directory and not a file */
	/* if it can be opened for append "a" then it is a file! */
	if( ( testStream	= fopen( pkg->portDirName, "a" ) ) )
	{
		fclose( testStream );
		return( 1 );	
	}
	return( 0 );
}