/************************************************************
* MultiUser - MultiUser Task/File Support System				*
* ---------------------------------------------------------	*
* Protect Clone															*
* ---------------------------------------------------------	*
* © Copyright 1993-1994 Geert Uytterhoeven						*
* All Rights Reserved.													*
************************************************************/


#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dosasl.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <libraries/multiuser.h>
#include <proto/multiuser.h>

#include "MProtect_rev.h"

#include "Locale.h"

char __VersTag__[] = VERSTAG;


#define FLAGS_OWNER	1
#define FLAGS_GROUP	2
#define FLAGS_OTHER	3


static BOOL __regargs ProcessFlags(char *str, ULONG *flags, ULONG type,
											  struct DosLibrary *DOSBase,
                                   struct LocaleInfo *li,
											  struct ExecBase *SysBase);


int __saveds Start(char *arg)
{
	struct ExecBase *SysBase;
	struct DosLibrary *DOSBase;
	struct muBase *muBase = NULL;
	struct RDArgs *args;
	LONG argarray[] = {
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
	};
	ULONG mask, flags = NULL;
	struct AnchorPath *anchor;
	BPTR dir;
	LONG error = NULL;
	int rc = RETURN_OK;
	struct LocaleInfo li;

	SysBase = *(struct ExecBase **)4;
	
	if ((!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 37))) ||
		 (!(muBase = (struct muBase *)OpenLibrary("multiuser.library", 39)))) {
		rc = ERROR_INVALID_RESIDENT_LIBRARY;
		goto Exit;
	}

	OpenLoc(&li);

	args = ReadArgs("FILE/A,FLAGS,GROUP/K,OTHER/K,ADD/S,SUB/S,ALL/S,QUIET/S",
						 argarray, NULL);
	if (!args)
		error = IoErr();
	else if (argarray[4] && argarray[5]) {
		PutStr(GetLocS(&li,MSG_BOTH_ADDSUB));
		rc = RETURN_ERROR;
	} else if ((argarray[1] && !ProcessFlags((char *)argarray[1], &flags,
														  FLAGS_OWNER, DOSBase, &li, SysBase)) ||
				  (argarray[2] && !ProcessFlags((char *)argarray[2], &flags,
														  FLAGS_GROUP, DOSBase, &li, SysBase)) ||
				  (argarray[3] && !ProcessFlags((char *)argarray[3], &flags,
														  FLAGS_OTHER, DOSBase, &li, SysBase)))
		rc = RETURN_ERROR;
	else if (anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath)+1024,
																	MEMF_CLEAR)) {
		anchor->ap_BreakBits = SIGBREAKF_CTRL_C;
		anchor->ap_Flags = APF_DOWILD;
		anchor->ap_Strlen = 1024;
		if (!(error = MatchFirst((char *)argarray[0], anchor))) {
			do
				if (anchor->ap_Flags & APF_DIDDIR)
					anchor->ap_Flags &= ~APF_DIDDIR;
				else {
					if (argarray[6] && (anchor->ap_Info.fib_DirEntryType > 0))
						anchor->ap_Flags |= APF_DODIR;
					mask = anchor->ap_Info.fib_Protection;
					mask ^= FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE;
					if (argarray[4])
						mask |= flags;
					else if (argarray[5])
						mask &= (~flags);
					else
						mask = flags;
					mask ^= FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE;
					dir = CurrentDir(DupLock(anchor->ap_Last->an_Lock));
					if ((mask & muFIBF_SET_UID) &&
						 (mask & (FIBF_GRP_WRITE | FIBF_OTR_WRITE)))
						PutStr(GetLocS(&li,MSG_WARN_UW));
					if (!muSetProtection(anchor->ap_Info.fib_FileName, mask)) {
						PutStr(anchor->ap_Buf);
						PrintFault(IoErr(), " ");
					} else if (!argarray[7]) {
						PutStr(anchor->ap_Buf);
						if (anchor->ap_Info.fib_DirEntryType > 0)
							PutStr("(Dir)");
						PutStr(GetLocS(&li,MSG_DONE));
					}
					UnLock(CurrentDir(dir));
				}
			while (!(error = MatchNext(anchor)));
			if (error == ERROR_NO_MORE_ENTRIES)
				error = NULL;
		} else if (error == ERROR_NO_MORE_ENTRIES)
			error = ERROR_OBJECT_NOT_FOUND;
		MatchEnd(anchor);
		FreeVec(anchor);
	} else
		error = IoErr();


	FreeArgs(args);
	if (error) {
		PrintFault(error, NULL);
		rc = RETURN_ERROR;
	}

	CloseLoc(&li);

Exit:
	CloseLibrary((struct Library *)muBase);
	CloseLibrary((struct Library *)DOSBase);

	return(rc);
}	


static BOOL __regargs ProcessFlags(char *str, ULONG *flags, ULONG type,
											  struct DosLibrary *DOSBase,
											  struct LocaleInfo *li,
											  struct ExecBase *SysBase)
{
	int i;
	BOOL rc = TRUE;

	for (i = 0; str[i] && rc; i++) {
		switch(str[i]) {
			case 'u':
			case 'U':
				if (type == FLAGS_OWNER)
					*flags |= muFIBF_SET_UID;
				else
					goto Error;
				break;

			case 's':
			case 'S':
				if (type == FLAGS_OWNER)
					*flags |= FIBF_SCRIPT;
				else
					goto Error;
				break;

			case 'p':
			case 'P':
				if (type == FLAGS_OWNER)
					*flags |= FIBF_PURE;
				else
					goto Error;
				break;

			case 'a':
			case 'A':
				if (type == FLAGS_OWNER)
					*flags |= FIBF_ARCHIVE;
				else
					goto Error;
				break;

			case 'r':
			case 'R':
				if (type == FLAGS_OWNER)
					*flags |= FIBF_READ;
				else if (type == FLAGS_GROUP)
					*flags |= FIBF_GRP_READ;
				else
					*flags |= FIBF_OTR_READ;
				break;

			case 'w':
			case 'W':
				if (type == FLAGS_OWNER)
					*flags |= FIBF_WRITE;
				else if (type == FLAGS_GROUP)
					*flags |= FIBF_GRP_WRITE;
				else
					*flags |= FIBF_OTR_WRITE;
				break;

			case 'e':
			case 'E':
				if (type == FLAGS_OWNER)
					*flags |= FIBF_EXECUTE;
				else if (type == FLAGS_GROUP)
					*flags |= FIBF_GRP_EXECUTE;
				else
					*flags |= FIBF_OTR_EXECUTE;
				break;

			case 'd':
			case 'D':
				if (type == FLAGS_OWNER)
					*flags |= FIBF_DELETE;
				else if (type == FLAGS_GROUP)
					*flags |= FIBF_GRP_DELETE;
				else
					*flags |= FIBF_OTR_DELETE;
				break;

			default:
Error:
				rc = FALSE;
				PutStr(GetLocS(li,MSG_INVALID_FLAG));
				PutStr(" ");
				if (type == FLAGS_OWNER)
					PutStr("USPARWED\n");
				else
					PutStr("RWED\n");
				break;
		}
	}

	return(rc);
}
