/************************************************************
* MultiUser - MultiUser Task/File Support System				*
* ---------------------------------------------------------	*
* List Clone- Support Command											*
* ---------------------------------------------------------	*
* © Copyright 1993 by 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;


void __regargs DumpInfo(struct FileInfoBlock *fib, struct muUserInfo *info,
								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 *args;
	struct muUserInfo *info;
	LONG argarray[] = {
		NULL
	};
	struct AnchorPath *anchor;
	ULONG files, dirs, blocks;
	ULONG tfiles = 0, tdirs = 0, tblocks = 0;
	LONG stream[3];
	char **name;
	static char *defaultargs[] = {
		"", 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 = RETURN_FAIL;
		goto Exit;
	}

	args = ReadArgs("DIR/M", argarray, NULL);
	if (!args)
		error = IoErr();
	else
		if (info = muAllocUserInfo()) {
			if (anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath),
																	 MEMF_CLEAR)) {
				anchor->ap_BreakBits = SIGBREAKF_CTRL_C;
				anchor->ap_Flags = APF_DOWILD;
				if (argarray[0])
					name = (char **)argarray[0];
				else
					name = defaultargs;
				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])) {
									stream[0] = (LONG)name[0];
									VPrintf("Directory \"%s\"\n", stream);
								}
								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, info, 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;
					if (!error) {
						stream[0] = files;
						stream[1] = dirs;
						stream[2] = blocks;
						VPrintf("%ld files - %ld directories - %ld blocks used\n\n",
								  stream);
						tfiles += files;
						tdirs += dirs;
						tblocks += blocks;
						numdirs++;
					}
					MatchEnd(anchor);
				} while (!error && *(name = &name[1]));
				if (!error && (numdirs > 1)) {
					PutStr("TOTAL: ");
					stream[0] = tfiles;
					stream[1] = tdirs;
					stream[2] = tblocks;
					VPrintf("%ld files - %ld directories - %ld blocks used\n",
							  stream);
				}
				FreeVec(anchor);
			} else
				error = IoErr();
			muFreeUserInfo(info);
		} else
			error = IoErr();
	FreeArgs(args);
	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
	 */

void __regargs DumpInfo(struct FileInfoBlock *fib, struct muUserInfo *info,
								struct ExecBase *SysBase, struct DosLibrary *DOSBase,
								struct muBase *muBase)
{
	ULONG stream[5];
	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)
		strncpy(info->UserID, "", muUSERIDSIZE);
	else {
		info->uid = fib->fib_OwnerUID;
		if (!muGetUserInfo(info, muKeyType_uid))
			strncpy(info->UserID, "<UNKNOWN>", muUSERIDSIZE);
	}
	stream[i] = (LONG)&info->UserID;

	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)
		fmt = "%-30s %8ld %s %s %s\n";
	else
		fmt = "%-30s      DIR %s %s %s\n";
	VPrintf(fmt, stream);
}
