////
//  UnPacker.c v1.2, 1993-09-22
//  Utility for extracting archives from the WB.
//
//  This code is Copyright © 1993 Erik Sagalara.
//  I supplied it as an example of programming
//  Appicons, Tooltypes and other V37+ stuff.
//
//  You should be able to compile it easily with
//  SASC, and with some tweaking with GCC.  
///

#include <intuition/intuition.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <clib/intuition_protos.h>
#include <clib/icon_protos.h>
#include <clib/wb_protos.h>
#include <clib/dos_protos.h>

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

#ifdef LATTICE
int CXBRK(void) { return (0); }
int chkabort(void) { return (0); }
#endif

struct IntuitionBase* IntuitionBase;
struct DosBase* DosBase;
struct Library* WorkbenchBase;
struct Library* IconBase;


// Global variables

BPTR OldDir=NULL, DestDir=NULL;
UBYTE* version = "$VER: UnPacker 1.2; 93-09-22";
UBYTE* OK = "OK!";
UBYTE *alertMsg =
	"\x00\x90\x14" "UnPacker requires AmigaDos 2.04 or higher!" "\x00\x01"
	"\x00\x20\x26" "Left=OK!" "\x00\x01"
	"\x02\x15\x26" "Right=OK!" "\x00";

struct MsgPort* myport=NULL;
struct AppIcon* appicon=NULL;

char* SuffixList[32];
char* MethodList[32];
UBYTE NumItems=0; 

// Local protos

void handletool (char*, char*, char*);
void handlefile (BPTR, char*);
int easyreq (char*, char*, char*, char*);
void cleanexit (char*, int);


////
//  Main
////

void main (int argc, char **argv)
{
	struct DiskObject* diskobj;
	struct AppMessage* appmsg;
	struct WBStartup* argmsg;
	struct WBArg* wbarg;
	char tlab[80], tval[80];
	UBYTE i, j;
	BOOL ok=TRUE;

	if (!(IntuitionBase = (struct IntuitionBase*) OpenLibrary("intuition.library", 0)))
		cleanexit ("", 20);

	if (!(DosBase = (struct Library*) OpenLibrary("dos.library", 37)))
		cleanexit ("", 20);

	if (!(WorkbenchBase = (struct Library*) OpenLibrary("workbench.library", 37)))
		cleanexit ("", 20);

	if (!(IconBase = (struct Library*) OpenLibrary("icon.library", 37)))
		cleanexit ("", 20);

	// CLI Startup if argc>0
	if (argc)
		cleanexit ("This program must be started\nfrom the workbench!", 10);

	// Otherwise wb startup
	argmsg = (struct WBStartup*) argv;
	wbarg = argmsg->sm_ArgList;

	if (wbarg->wa_Lock) {
		OldDir = CurrentDir (wbarg->wa_Lock);
		diskobj = GetDiskObject (wbarg->wa_Name);
	}
	else cleanexit ("Can't access the program icon!\n", 10);

	diskobj->do_Type = NULL;
	diskobj->do_CurrentX = -2147483648L;
	diskobj->do_CurrentY = -2147483648L;

	for (i=0; diskobj->do_ToolTypes[i] != NULL; i++) {
		handletool (diskobj->do_ToolTypes[i], tlab, tval);
		if (strlen (tlab) > 0) {
			char* errstr="Error in tooltype entry: ";
			j = strlen (tval);

			if (strcmp (tlab, "XPOS") == 0) {
				if (j > 0)
					diskobj->do_CurrentX = atol (tval);
				else
					easyreq (errstr, diskobj->do_ToolTypes[i], OK, OK);
			}

			else if (strcmp (tlab, "YPOS") == 0) {
				if (j > 0)
					diskobj->do_CurrentY = atol (tval);
				else
					easyreq (errstr, diskobj->do_ToolTypes[i], OK, OK);
			}

			else if (strcmp (tlab, "DESTDIR") == 0) {
				if (j > 0) {
					if (NULL == (DestDir = Lock (tval, ACCESS_READ)))
						cleanexit ("Can't lock to dest dir!", 10);
				}
				else
					easyreq (errstr, diskobj->do_ToolTypes[i], OK, OK);
			}

			else if (strlen (tlab) <= 3) {
				if (j > 0 && NumItems < 32) {
					SuffixList[NumItems] = strdup (tlab);
					MethodList[NumItems] = strdup (tval);
					NumItems++;
				}
				else easyreq (errstr, diskobj->do_ToolTypes[i], OK, OK);
			}
		}
	}	

	// ToolManager startup
	if (argmsg->sm_NumArgs > 1) {
		for (i=1; i<argmsg->sm_NumArgs; i++)
			handlefile (argmsg->sm_ArgList[i].wa_Lock, argmsg->sm_ArgList[i].wa_Name);
		cleanexit ("", 0);
	}

	// Otherwise use appicon
	if (!(myport = (struct MsgPort *) CreateMsgPort ()))
		cleanexit ("Can't create message port!", 10);

	if (!(appicon = AddAppIconA (0L, 0L, "UnPacker", myport, NULL, diskobj, NULL)))
		cleanexit ("Can't create appicon!", 10);

	while (ok) {
		WaitPort (myport);

		while (appmsg = (struct AppMessage *) GetMsg (myport)) {
			if (appmsg->am_NumArgs == 0) {
				if (easyreq ("UnPacker v1.2, 93-09-22.\nCopyright ©1993 Erik Sagalara.\n",
								 "This program is FreeWare!", "QUIT!", "Continue"))
					ok = FALSE;
			}
			else {
				UBYTE i;
				for (i=0; i<appmsg->am_NumArgs; i++)
					handlefile (appmsg->am_ArgList[i].wa_Lock, appmsg->am_ArgList[i].wa_Name);
			}

			ReplyMsg ((struct Message *) appmsg);
		}
	}
        
	RemoveAppIcon (appicon);

	while (appmsg = (struct AppMessage *) GetMsg(myport))
		ReplyMsg ((struct Message *) appmsg);

	FreeDiskObject (diskobj);
	DeleteMsgPort (myport);

	cleanexit ("", 0);
}


////
//  Process a tooltype assignment string (XYZ=123)
////

void handletool (char* instr, char* label, char* value)
{
	UBYTE i, j, len;

	len = strlen(instr);

	for (i=0; (i<len) && (instr[i]!='='); i++) label[i] = toupper (instr[i]);

	label[i] = '\0';

	if (instr[i] != '=' && i >= len) {
		value[0] = '\0';
	}
	else {
		i++;
		for (j=0; j+i<=len; j++) value[j] = instr[j+i];
		value[j] = '\0';
	}
}	


////
//  Process an archive file
////

void handlefile (BPTR lock, char* name)
{
	UBYTE i, j;
	BOOL found=FALSE;
	char *buf1,* buf2, *method1, *method2, suffix[4]="   ";

	for (i=strlen(name)-1; i>0 && (name[i] != '.'); i--);
	if (name[i] != '.') goto err;

	if (strlen (&name[i+1]) > 3) goto err;
	for (j=0; suffix[j]!='\0'; j++) suffix[j] = toupper(name[i+j+1]);

	for (i=0; i<NumItems && SuffixList[i]!=NULL; i++)
		if (strcmp (suffix, SuffixList[i]) == 0) {
			found = TRUE;
			break;
		}
	if (!found) goto err;

	method1 = strdup (MethodList[i]);
	for (j=0; j<strlen(method1) && method1[j]!='?'; j++);
	if (method1[j]=='?') {
		if (strlen (method1) > j)
			method2 = strdup (&method1[j+1]);
		else
			method2 = strdup ("");
		method1[j] = '\0';
	}
	else
		method2 = strdup ("");

	buf2 = (char*) malloc (256);
	NameFromLock (lock, buf2, 255);
	AddPart (buf2, name, 255);
	
	buf1 = (char*) malloc (strlen(method1) + strlen(buf2) + strlen(method2) + 40);
	sprintf (buf1, "%s \"%s\" %s >CON:0/25/640/150/UnPacking.../CLOSE/AUTO/WAIT",
				method1, buf2, method2);

	CurrentDir (DestDir);
	system (buf1);

	free (buf1);
	free (buf2);
	free (method1);
	free (method2);
	return;
	err: easyreq ("Unknown suffix for file:\n", name, OK, OK);
}


////
//  Easy requester
////

int easyreq (char* bodystr, char* extra, char* yesstr, char* nostr)
{
    static struct EasyStruct myES = {
        sizeof(struct EasyStruct),
        0,
        "UnPacker requester:",
        "%s%s",
        "%s|%s",
    };

    return (EasyRequest(NULL, &myES, NULL, bodystr, extra, yesstr, nostr));
}


////
//  Exits cleanly closing librarys and leaving a message
////

void cleanexit (char* exitstr, int stat)
{
	UBYTE i;

	if (stat)
		if (stat == 20)
			DisplayAlert(RECOVERY_ALERT, alertMsg, 52);
		else
			easyreq (exitstr, "", OK, OK);

	for (i=0; i<NumItems; i++) {
		if (SuffixList[i]) free (SuffixList[i]);
		if (MethodList[i]) free (MethodList[i]);
	}

	if (DestDir) UnLock (DestDir);
	if (OldDir) CurrentDir (OldDir);
	
	if (IntuitionBase) CloseLibrary (IntuitionBase);
	if (WorkbenchBase) CloseLibrary (WorkbenchBase);
	if (IconBase) CloseLibrary (IconBase);
	if (DosBase) CloseLibrary (DosBase);

	exit (stat);
}
