/*
 * UserTool - A Tool for managing users in a MuFS environment.
 *
 * $VER: parse.c 37.1 (10.1.94)
 */

#include <exec/memory.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>
#include <clib/reqtools_protos.h>

#include <stdio.h>
#include <string.h>

#include "parse.h"
#include "funcs.h"

extern LONG Tags[], Startup, PasswdFileDirty, GroupFileDirty;
extern UBYTE PasswdName[], GroupName[];
extern struct List *Users, *Groups;

struct Node *AllocAndReturnNext( FILE *PassFile )
{
	UserStruct *New;
	LONG rv;
	UBYTE Null[256];
	
	if( New = AllocVec( sizeof( UserStruct ), MEMF_CLEAR )) {
		if( !feof( PassFile )) {
			rv = fscanf( PassFile, "%[^|]|%[^|]|%ld|%ld|%[^|]|%[^|]|%[^\n]\n",
						New->us_UserName, New->us_Password,
						&( New->us_UserID ), &( New->us_GroupID ),
						New->us_RealName, New->us_HomeDir, New->us_Port );
			New->us_Node.ln_Name = New->us_UserName;
			NewList( &New->us_Groups );
			if( !strcmp( New->us_Password, "" ) && Startup ) {
				Tags[7] = ( LONG )"Password Warning";
				rtEZRequest( "Warning. User %s has an empty password.", "_Ok",
							0L, ( struct TagItem * )Tags, New->us_UserName );
			}
			
			if( rv == 7 )
				return ( struct Node * )New;
			else {
				fscanf( PassFile, "%[^\n]\n", Null );
				Tags[7] = ( LONG )"Password File Information";
				rtEZRequest( "Error reading password entry.", "_Ok", 0L,
							( struct TagItem * )Tags);
			}
		}
		FreeVec( New );
	}

	return 0L;
}			

struct List *ParsePasswdFile( VOID )
{
	static struct List UserList;
	FILE *PassFile;
	struct Node *User;
	
	NewList( &UserList );

	if( PassFile = fopen( PasswdName, "r" )) {
		while( !feof( PassFile )) {
			if( User = AllocAndReturnNext( PassFile ))
				AddTail( &UserList, User );
		}
		fclose( PassFile );
	} else {
		Tags[7] = ( LONG )"Password File Information";
		rtEZRequest( "Error opening password file: %s\n", "_Ok", 0L,
					( struct TagItem * )Tags, PasswdName );
	}

	PasswdFileDirty = 0;
	
	return &UserList;
}	

/* If User is non-null, then that user's password will be copied as null,
   useful for changing her password since MuFS doesn't support changing of
   passwords without the old password (even if you're root...). */

VOID WritePasswdFile( UserStruct *User )
{
	UBYTE PasswdBack[1024];
	FILE *PassFile;
	UserStruct *SaveUser;
	
	strcpy( PasswdBack, PasswdName );
	strcat( PasswdBack, ".bak" );

	DeleteFile( PasswdBack );
	if( !Rename( PasswdName, PasswdBack )) {
		Tags[7] = ( LONG )"Password File Information";
		rtEZRequest( "Cannot delete backup password file.", "_Ok", 0L,
					( struct TagItem * )Tags );
		return;
	}
	
	if( PassFile = fopen( PasswdName, "w" )) {
		for( SaveUser = ( UserStruct * )Users->lh_Head;
			SaveUser->us_Node.ln_Succ;
			SaveUser = ( UserStruct * )SaveUser->us_Node.ln_Succ )
			fprintf( PassFile, "%s|%s|%ld|%ld|%s|%s|%s\n",
					SaveUser->us_UserName,
					SaveUser == User ? "" :	( char * )SaveUser->us_Password,
					SaveUser->us_UserID, SaveUser->us_GroupID,
					SaveUser->us_RealName, SaveUser->us_HomeDir,
					SaveUser->us_Port );
		fclose( PassFile );
	} else {
		Rename( PasswdBack, PasswdName );
		Tags[7] = ( LONG )"Password File Information";
		rtEZRequest( "Error opening password file: %s\n", "_Ok", 0L,
					( struct TagItem * )Tags, PasswdName );
	}

	PasswdFileDirty = 0;

}

struct Node *AllocAndReturnNextG( FILE *GroupFile )
{
	GroupStruct *New;
	UBYTE Line[256];
	LONG rv;
	int c;
	
	if(( c = fgetc( GroupFile )) == '\n' )
		return 0L;
	else
		ungetc( c, GroupFile );
	
	if( New = AllocVec( sizeof( GroupStruct ), MEMF_CLEAR )) {
		if( !feof( GroupFile )) {
			if( fgets( Line, 256, GroupFile )) {
				rv = sscanf( Line, "%[^|]|%ld|%ld|%[^\n]\n", New->gs_GroupID,
							&( New->gs_GID ), &( New->gs_MgrID ),
							New->gs_Name );
				New->gs_Node.ln_Name = New->gs_GroupID;
				
				if( rv == 4 )
					return ( struct Node * )New;
				else {
					Tags[7] = ( LONG )"Group File Information";
					rtEZRequest( "Error parsing group entry.", "_Ok", 0L,
								( struct TagItem * )Tags );
				}
			} else {
				Tags[7] = ( LONG )"Group File Information";
				rtEZRequest( "Error reading group entry.", "_Ok", 0L,
							( struct TagItem * )Tags );
			}
		}
		FreeVec( New );
	}

	return 0L;
}			

struct List *ParseGroupFile( VOID )
{
	static struct List GroupList;
	struct Node *Group;
	FILE *GroupFile;
	LONG GID, UID;
	UBYTE GroupLine[1024];
	
	NewList( &GroupList );

	if( GroupFile = fopen( GroupName, "r" )) {
		while( Group = AllocAndReturnNextG( GroupFile ))
			AddTail( &GroupList, Group );
		while( !feof( GroupFile )) {
			if( fgets( GroupLine, 1024, GroupFile )) {
				LONG GLPos = 0;
				if(( UID = GetNextNumber( GroupLine, &GLPos )) >= 0 ) {
						do {	
							if(( GID = GetNextNumber( GroupLine, &GLPos ))> 0 )
								if( AddGroupToUser( UID, GID ))
									break;
						} while( GID >= 0 );
				} else {
					Tags[7] = ( LONG )"Group File Information";
					rtEZRequest( "Error parsing GID and first UID from group"
								" file.", "_Ok", 0L,
								( struct TagItem * )Tags );
				}
			} else if( !feof( GroupFile )) {
				Tags[7] = ( LONG )"Group File Information";
				rtEZRequest( "Error reading group entry from group file.",
							"_Ok", 0L, ( struct TagItem * )Tags );
			}
		}
		fclose( GroupFile );
	} else {
		Tags[7] = ( LONG )"Group File Information";
		rtEZRequest( "Error opening Group file: %s\n", "_Ok", 0L,
					( struct TagItem * )Tags, GroupName );
	}

	GroupFileDirty = 0;

	return &GroupList;
}

VOID WriteGroupFile( VOID )
{
	UBYTE GroupBack[1024];
	FILE *GroupFile;
	GroupStruct *SaveGroup;
	UserStruct *SaveUser;
	struct Node *SaveNode;
	
	strcpy( GroupBack, GroupName );
	strcat( GroupBack, ".bak" );

	DeleteFile( GroupBack );
	if( !Rename( GroupName, GroupBack )) {
		Tags[7] = ( LONG )"Group File Information";
		rtEZRequest( "Cannot delete backup group file.", "_Ok", 0L,
					( struct TagItem * )Tags );
		return;
	}
	
	if( GroupFile = fopen( GroupName, "w" )) {
		for( SaveGroup = ( GroupStruct * )Groups->lh_Head;
			SaveGroup->gs_Node.ln_Succ;
			SaveGroup = ( GroupStruct * )SaveGroup->gs_Node.ln_Succ )
			fprintf( GroupFile, "%s|%ld|%ld|%s\n", SaveGroup->gs_GroupID,
					SaveGroup->gs_GID, SaveGroup->gs_MgrID,
					SaveGroup->gs_Name );
		fprintf( GroupFile, "\n" );
		for( SaveUser = ( UserStruct * )Users->lh_Head;
			SaveUser->us_Node.ln_Succ;
			SaveUser = ( UserStruct * )SaveUser->us_Node.ln_Succ ) {	
			if( SaveUser->us_Groups.lh_Head->ln_Succ ) {
				fprintf( GroupFile, "%ld:", SaveUser->us_UserID );
				for( SaveNode = SaveUser->us_Groups.lh_Head; SaveNode->ln_Succ;
					SaveNode = SaveNode->ln_Succ )
					fprintf( GroupFile, "%ld%s", SaveNode->ln_Pri,
							SaveNode->ln_Succ->ln_Succ ? "," : "\n" );
			}
		}
		fclose( GroupFile );
	} else {
		Rename( GroupBack, GroupName );
		Tags[7] = ( LONG )"Group File Information";
		rtEZRequest( "Error opening group file: %s\n", "_Ok", 0L,
					( struct TagItem * )Tags, GroupName );
	}
}
