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


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

#include "MList_rev.h"


char __VersTag__[] = VERSTAG;


static void __regargs DumpInfo(struct FileInfoBlock *fib,
										 struct muUserInfo *uinfo,
										 struct muGroupInfo *ginfo, BOOL groups,
										 struct ExecBase *SysBase,
										 struct DosLibrary *DOSBase,
										 struct muBase *muBase);


	/*
	 *		This table makes it easier to set the Protection Flags the right way
	 */

struct ProtectionEntry {
	ULONG Bit;
	ULONG ActiveLow;		/* NULL, or the same as Bit above */
};


int __saveds Start(char *arg)
{
	struct ExecBase *SysBase;
	struct DosLibrary *DOSBase;
	struct muBase *muBase = NULL;
	struct RDArgs *rdargs;
	struct muUserInfo *uinfo;
	struct muGroupInfo *ginfo;
	LONG argarray[] = {
#define argDIR		0
#define argGROUPS	1
		NULL, NULL
	};
	struct AnchorPath *anchor;
	ULONG files, dirs, blocks;
	ULONG tfiles = 0, tdirs = 0, tblocks = 0;
	LONG args[3];
	char **name;
	static char *defaultname[] = {
		"", NULL
	};
	int numdirs = 0;
	LONG error;
	int rc = RETURN_OK;

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

	rdargs = ReadArgs("DIR/M,GROUPS/S", argarray, NULL);
	if (!rdargs)
		error = IoErr();
	else
		if (uinfo = muAllocUserInfo()) {
			if (ginfo = muAllocGroupInfo()) {
				if (anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath),
																		 MEMF_CLEAR)) {
					anchor->ap_BreakBits = SIGBREAKF_CTRL_C;
					anchor->ap_Flags = APF_DOWILD;
					if (argarray[argDIR])
						name = (char **)argarray[argDIR];
					else
						name = defaultname;
					do {
						files = dirs = blocks = 0;
						if (!(error = MatchFirst(name[0], anchor))) {
							if (IsFileSystem(name[0]))
								if (!(anchor->ap_Flags & APF_ITSWILD) &&
									 (anchor->ap_Info.fib_DirEntryType > 0)) {
									if (strlen(name[0])) {
										args[0] = (LONG)name[0];
										VPrintf("Directory \"%s\"\n", args);
									}
									anchor->ap_Flags |= APF_DODIR;
									error = MatchNext(anchor);
								} else {}
							else					
								error = ERROR_OBJECT_WRONG_TYPE;
							if (!error)
								do
									if (anchor->ap_Flags & APF_DIDDIR)
										anchor->ap_Flags &= ~APF_DIDDIR;
									else {
										DumpInfo(&anchor->ap_Info, uinfo, ginfo,
													argarray[argGROUPS], SysBase, DOSBase,
													muBase);
										if (anchor->ap_Info.fib_DirEntryType < 0)
											files++;
										else
											dirs++;
										blocks += anchor->ap_Info.fib_NumBlocks+1;
									}
								while (!(error = MatchNext(anchor)));
							if (error == ERROR_NO_MORE_ENTRIES)
								error = NULL;
						} else if (error == ERROR_NO_MORE_ENTRIES)
							error = ERROR_OBJECT_NOT_FOUND;
						if (!error) {
							args[0] = files;
							args[1] = dirs;
							args[2] = blocks;
							VPrintf("%ld files - %ld directories - %ld blocks used\n\n",
									  args);
							tfiles += files;
							tdirs += dirs;
							tblocks += blocks;
							numdirs++;
						}
						MatchEnd(anchor);
					} while (!error && *(name = &name[1]));
					if (!error && (numdirs > 1)) {
						PutStr("TOTAL: ");
						args[0] = tfiles;
						args[1] = tdirs;
						args[2] = tblocks;
						VPrintf("%ld files - %ld directories - %ld blocks used\n",
								  args);
					}
					FreeVec(anchor);
				} else
					error = IoErr();
				muFreeGroupInfo(ginfo);
			} else
				error = IoErr();
			muFreeUserInfo(uinfo);
		} else
			error = IoErr();
	FreeArgs(rdargs);
	if (error) {
		PrintFault(error, NULL);
		rc = RETURN_ERROR;
	}

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

	return(rc);
}	


	/*
	 *		Dump the Information for a Directory Entry
	 */

static void __regargs DumpInfo(struct FileInfoBlock *fib,
										 struct muUserInfo *uinfo,
										 struct muGroupInfo *ginfo, BOOL groups,
										 struct ExecBase *SysBase,
										 struct DosLibrary *DOSBase,
										 struct muBase *muBase)
{
	ULONG stream[6];
	char protection[17];
	char *fmt;
	int i = 0;
	struct DateTime dt;
	char date[LEN_DATSTRING];

	static struct ProtectionEntry pe[] = {
		muFIBF_SET_UID, FALSE,
		FIBF_SCRIPT, FALSE,
		FIBF_PURE, FALSE,
		FIBF_ARCHIVE, FALSE,
		FIBF_READ, FIBF_READ,
		FIBF_WRITE, FIBF_WRITE,
		FIBF_EXECUTE, FIBF_EXECUTE,
		FIBF_DELETE, FIBF_DELETE,
		FIBF_GRP_READ, FALSE,
		FIBF_GRP_WRITE, FALSE,
		FIBF_GRP_EXECUTE, FALSE,
		FIBF_GRP_DELETE, FALSE,
		FIBF_OTR_READ, FALSE,
		FIBF_OTR_WRITE, FALSE,
		FIBF_OTR_EXECUTE, FALSE,
		FIBF_OTR_DELETE, FALSE,
};
	static char ProtectionTemplate[] = "usparwedrwedrwed";

	stream[i++] = (ULONG)&fib->fib_FileName;
	if (fib->fib_DirEntryType < 0)
		stream[i++] = fib->fib_Size;
	dt.dat_Stamp = fib->fib_Date;
	dt.dat_Format = FORMAT_DOS;
	dt.dat_Flags = NULL;
	dt.dat_StrDay = NULL;
	dt.dat_StrDate = date;
	dt.dat_StrTime = NULL;
	DateToStr(&dt);
	stream[i++] = (ULONG)protection;
	stream[i++] = (ULONG)date;
	if (fib->fib_OwnerUID == muNOBODY_UID) {
		strcpy(uinfo->UserID, "\b");
		groups = FALSE;
	} else {
		uinfo->uid = fib->fib_OwnerUID;
		if (!muGetUserInfo(uinfo, muKeyType_uid))
			strcpy(uinfo->UserID, "???");
	}
	stream[i++] = (LONG)&uinfo->UserID;

	if (groups) {
		ginfo->gid = fib->fib_OwnerGID;
		if (!muGetGroupInfo(ginfo, muKeyType_gid))
			strcpy(ginfo->GroupID, "???");
		stream[i] = (LONG)&ginfo->GroupID;
	}

	for (i = 0; i < 16; i++)
		if ((fib->fib_Protection & pe[i].Bit) ^ pe[i].ActiveLow)
			protection[i] = ProtectionTemplate[i];
		else
			protection[i] = '-';
	protection[i] = '\0';

	if (fib->fib_DirEntryType < 0)
		if (groups)
			fmt = "%-30s %8ld %s %s %s [%s]\n";
		else
			fmt = "%-30s %8ld %s %s %s\n";
	else
		if (groups)
			fmt = "%-30s      DIR %s %s %s [%s]\n";
		else
			fmt = "%-30s      DIR %s %s %s\n";
	VPrintf(fmt, stream);
}
