/*
	AddAssignInstall V1.04e
	
	(c) 1991 Alexander Rawass

	Alexander Rawass
	Wilhelminenstr. 44
	6700 Ludwigshafen 15
	Germany
	0621/57 75 98
*/

#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <exec/memory.h>
#include <pragmas.h>
#include <libraries/arp.h>
#include <stdio.h>

#define	AR_USE_ARP
#include "ar_defs.h"

#include "addassign.h"

#define	COM_MOVEQ	112
#define	COM_BRA		24576
#define	COM_JMP		0x4ef9

struct	vectentry {
	BYTE	com_moveq;
	BYTE	var_d0;
	WORD	com_bra;
	WORD	var_offset;
}
;

struct	jumpvectentry {
	UWORD	com_jmp;
	ULONG	var_adress;
}
;

LONG	_stack=4000;	/* for detaching from current cli process */
LONG	_priority=0;
LONG	_BackGroundIO=FALSE;
STRPTR	_procname="AddAssignProcess V1.04e";

STRPTR	CLI_Help="\x1b[1mAddAssign Install V1.04e\x1b[0m - (c) 1991 Alexander Rawass\n";

struct	ArpBase		*ArpBase;
struct	DosLibrary	*DosBase;
struct	commandmessage	*waitmsg;
struct	commandmessage	sendmsg;
struct	MsgPort		*sendport,*waitport;
struct	List		malist;
struct	FileLock	*myout;
struct	Process		*myproc;

BOOL	jmp_Lock,jmp_Open,jmp_LoadSeg;

CPTR	oldLock,oldOpen,oldCreateDir,oldLoadSeg;

LONG	oldLockd0,oldOpend0,oldCreateDird0,oldLoadSegd0;

LONG	Lockoffset=-84;
LONG	Openoffset=-30;
LONG	LoadSegoffset=-150;

extern int	xLock();
extern int	xOpen();
extern int	xLoadSeg();

extern int	dosLock();
extern int	dosOpen();
extern int	dosLoadSeg();

CPTR			NewLoadSeg(STRPTR name);
struct	FileLock	*NewLock(STRPTR name,LONG mode);
struct	FileHandle	*NewOpen(STRPTR name,LONG mode);

#pragma	regcall(NewLock(d1,d2))
#pragma	regcall(NewOpen(d1,d2))
#pragma	regcall(NewLoadSeg(d1))

#include "ar_funcs.c"

/**************************************************************/

struct	MoreAssign	*findmanode(assign,node)
STRPTR			assign;
struct	MoreAssign	*node;
{
	REG struct	MoreAssign	*manode;

	if(node==NULL){
		manode=malist.lh_Head;
	}
	else{
		manode=node;
		manode=manode->ma_node.ln_Succ;
	}
	
	while((manode!=(struct MoreAssign *)&malist.lh_Tail) && (!STREQU(assign,&(manode->ma_assignname)))){
		manode=manode->ma_node.ln_Succ;
	}
	
	if(manode==(struct MoreAssign *)&malist.lh_Tail){
		return(NULL);
	}
	else{
		return(manode);
	}
}

/**************************************************************/

struct	MoreAssign	*checklock(curlock,node)
struct	FileLock	*curlock;
struct	MoreAssign	*node;
{
	REG struct	MoreAssign	*manode;

	if(node==NULL){
		manode=malist.lh_Head;
	}
	else{
		manode=node;
		manode=manode->ma_node.ln_Succ;
	}

	while((manode!=(struct MoreAssign *)&malist.lh_Tail) && (CompareLock(curlock,manode->ma_assignlock)!=LCK_EQUAL)){
		manode=manode->ma_node.ln_Succ;
	}

	if(manode==(struct MoreAssign *)&malist.lh_Tail){
		return(NULL);
	}
	else{
		return(manode);
	}
}

/**************************************************************/

struct	FileLock	*NewLock(name,mode)
STRPTR				name;
LONG				mode;
{
	struct	FileLock		*block;
	struct	FileLock		*curlock;
	struct	MoreAssign		*manode;
	char	volume[256];
	char	pathname[256];
	STRPTR	basename,path;

	block=dosLock(name,mode);
	
	if(block){
		return(block);
	}
	else {
		path=name;
		VolumeName(path,volume);
		
		if(volume[0]!=EOS){
			curlock=dosLock(volume,SHARED_LOCK);
		}
		else{
			curlock=dosLock(volume,SHARED_LOCK);
		}
		
		manode=NULL;
		do{
			manode=checklock(curlock,manode);
			if(manode){
				basename=BaseName(path);
				strcpy(pathname,manode->ma_pathname);
				TackOn(pathname,basename);
				block=dosLock(pathname,mode);
			}
		}
		while(block==NULL && manode!=NULL);

		UNLOCKC(curlock);	
		return(block);
	}
}

/**************************************************************/

struct	FileHandle	*NewOpen(name,mode)
STRPTR	name;
LONG	mode;
{
	struct	FileHandle		*bhandle;
	struct	MoreAssign		*manode;
	char	volume[256];
	char	pathname[256];
	STRPTR	basename,path;
	struct	FileLock	*curlock;
	
	bhandle=dosOpen(name,mode);
	
	if(bhandle){
		return(bhandle);
	}
	else {
		path=name;
		VolumeName(path,volume);
		
		if(volume[0]!=EOS){
			curlock=dosLock(volume,SHARED_LOCK);
		}
		else{
			curlock=dosLock(volume,SHARED_LOCK);
		}
		
		manode=NULL;
		do{
			manode=checklock(curlock,manode);
			if(manode){
				basename=BaseName(path);
				strcpy(pathname,manode->ma_pathname);
				TackOn(pathname,basename);
				bhandle=dosOpen(pathname,mode);
			}
		}
		while(bhandle==NULL && manode!=NULL);

		UNLOCKC(curlock);	
		return(bhandle);
	}
}

/**************************************************************/

CPTR	NewLoadSeg(name)
STRPTR	name;
{
	CPTR	ok;
	struct	MoreAssign		*manode;
	char	volume[256];
	char	pathname[256];
	STRPTR	basename,path;
	struct	FileLock	*curlock;

	ok=dosLoadSeg(name);
	
	if(ok){
		return(ok);
	}
	else {
		path=name;
		VolumeName(path,volume);
		
		if(volume[0]!=EOS){
			curlock=dosLock(volume,SHARED_LOCK);
		}
		else{
			curlock=dosLock(volume,SHARED_LOCK);
		}
		
		manode=NULL;
		do{
			manode=checklock(curlock,manode);
			if(manode){
				basename=BaseName(path);
				strcpy(pathname,manode->ma_pathname);
				TackOn(pathname,basename);
				ok=dosLoadSeg(pathname);
			}
		}
		while(ok==NULL && manode!=NULL);

		UNLOCKC(curlock);	
		return(ok);
	}

}

/**************************************************************/

VOID	installvector(oldptr,oldd0ptr,offset,x,jmp_flag)
CPTR	*oldptr;
LONG	*oldd0ptr;
LONG	offset;
APTR	x;
BOOL	*jmp_flag;
{
	struct	vectentry	*vectadr;
	struct	jumpvectentry	*jve;

	vectadr=(LONG)DosBase+(LONG)offset;
	jve=vectadr;
	if(jve->com_jmp==COM_JMP){
		*oldd0ptr=0;
		*oldptr=jve->var_adress;
		*jmp_flag=TRUE;
	}
	else{
		*oldd0ptr=vectadr->var_d0;
		*oldptr=(LONG)(&(vectadr->com_bra))+(LONG)(vectadr->var_offset)+2;
		*jmp_flag=FALSE;
	}
	SetFunction(DosBase,offset,x);
}

/**************************************************************/

VOID	removevector(old,oldd0,offset,x,jmp_flag)
CPTR	old;
LONG	oldd0,offset;
APTR	x;
BOOL	jmp_flag;
{
	struct	vectentry	*vectadr;
	struct	jumpvectentry	*jve;

	vectadr=(LONG)DosBase+(LONG)offset;
	jve=vectadr;
	if(jmp_flag){
		jve->com_jmp=COM_JMP;
		jve->var_adress=old;
	}
	else{
		vectadr->var_d0=oldd0;
		vectadr->var_offset=old-(LONG)(&(vectadr->com_bra))-2;
		vectadr->com_moveq=COM_MOVEQ;
		vectadr->com_bra=COM_BRA;
	}
}

/**************************************************************/

VOID installpatch()
{
	struct	vectentry	*vectadr;
	
	DosBase=OpenLibrary(DOSNAME,0);
	
	MultiOff();

	installvector(&oldLock,&oldLockd0,Lockoffset,xLock,&jmp_Lock);
	installvector(&oldOpen,&oldOpend0,Openoffset,xOpen,&jmp_Open);
	installvector(&oldLoadSeg,&oldLoadSegd0,LoadSegoffset,xLoadSeg,&jmp_LoadSeg);

	MultiOn();
	
	CloseLibrary(DosBase);
	
	NewList(&malist);
}

/**************************************************************/

VOID	removepatch()
{
	struct	vectentry	*vectadr;
	struct	MoreAssign	*manode;	
	
	DosBase=OpenLibrary(DOSNAME,0);
	
	manode=RemTail(&malist);
	while(manode){
		UNLOCKC(manode->ma_assignlock);
		FreeMem(manode,sizeof(struct MoreAssign));
		manode=RemTail(&malist);
	}
	;
	
	MultiOff();
	
	removevector(oldLock,oldLockd0,Lockoffset,xLock,jmp_Lock);
	removevector(oldOpen,oldOpend0,Openoffset,xOpen,jmp_Open);
	removevector(oldLoadSeg,oldLoadSegd0,LoadSegoffset,xLoadSeg,jmp_LoadSeg);
	
	DosBase->lib_Flags=LIBF_CHANGED;
	SumLibrary(DosBase);
	
	MultiOn();
	
	CloseLibrary(DosBase);
}

/**************************************************************/

VOID	addassign(assign,path,lock)
STRPTR	assign,path;
struct	FileLock	*lock;
{
	struct	MoreAssign	*manode;

	if(manode=AllocMem(sizeof(struct MoreAssign),MEMF_CLEAR)){
		strncpy(&manode->ma_assignname,assign,10);
		strncpy(&manode->ma_pathname,path,256);
		manode->ma_assignlock=lock;
		AddHead(&malist,manode);
	}
	else{
		/* und was jetzt? */
	}
}

/**************************************************************/

VOID	closeall()
{
	if(myout){
		CLOSEC(myout);
		myproc=FindTask(NULL);
		myproc->pr_COS=NULL;
		myproc->pr_CIS=NULL;
	}
	exit(NULL);
}

/**************************************************************/

VOID	openall()
{
	if(!(myout=Open("*",MODE_NEWFILE))){
		closeall();
	}
}

/**************************************************************/

VOID main(argc,argv)
int	argc;
STRPTR	argv[];
{
	struct	FileLock	*block;

	openall();
	
	fprintf(myout,"\x1b[1mAddAssign Install V1.04e\x1b[0m - (c) 1991 Alexander Rawass\n");
	
	if(argc==2 && *argv[1]=='?'){
		fprintf(myout,"Usage : %s [REMOVE]\n",argv[0]);
		closeall();
	}
	
	if(FindPort(waitportname)){
		if(argc==1){
			fprintf(myout,"\nERROR :  AddAssign V1.04e already installed\n");
			closeall();
		}
		else if(argc==2){
			StrUpper(argv[1]);
			waitport=FindPort(waitportname);
			sendport=CreatePort(sendportname,0);
			sendmsg.cmsg_message.mn_Node.ln_Type=NT_MESSAGE;
			sendmsg.cmsg_message.mn_ReplyPort=sendport;
			sendmsg.cmsg_message.mn_Length=sizeof(struct commandmessage);
			if(STREQU(argv[1],"REMOVE")){
				fprintf(myout,"\nremoving AddAssign V1.04e\n");
			}
			sendmsg.cmsg_command="remove";
			PutMsg(waitport,&sendmsg);
			waitmsg=WaitPort(sendport);
			waitmsg=GetMsg(sendport);
			DeletePort(sendport);
			closeall();
		}
	}
	else{
		fprintf(myout,"\ninstalling AddAssign V1.04e\n");

		installpatch();
		
		waitport=CreatePort(waitportname,0);

		CLOSEC(myout);
/*		myproc=FindTask(NULL);
		myproc->pr_COS=NULL;
		myproc->pr_CIS=NULL;
*/
		do{
			waitmsg=WaitPort(waitport);
			GetMsg(waitport);
			if(STREQU(waitmsg->cmsg_command,"addassign")){
				addassign(waitmsg->cmsg_assign,waitmsg->cmsg_path,waitmsg->cmsg_lock);
			}
			else if(STREQU(waitmsg->cmsg_command,"list")){
				waitmsg->cmsg_assign=(STRPTR)&malist;
			}
			ReplyMsg(waitmsg);
		}
		while(!STREQU(waitmsg->cmsg_command,"remove"));

		removepatch();
		
		DeletePort(waitport);
		
		closeall();
	}
}

