/********************************************************************
 ** NETWORK FILESYSTEM - DOS HANDLER
 **
 ** (c) Spak, Darrell Tam, c9107253@ee.newcastle.edu.au (1994)
 ** phone (Australia) 049-829-710
 **                   +49-829-710
 ** (c) SST 1994
 **
 ** LOCATE OBJECT & COPYDIR (ACTUALLY COPY_LOCK)
 ** the copy_di function isn't really passed through, but cloned
 ** locally
 **
 ** Note that when these routines are called, res1 & res2 already = -1
 **
 ** TABS to 4
 ********************************************************************/

#include "/snd/everything.h"
#include "deadheads.h"
#include "root_protos.h"
#include "globs_protos.h"
#include "xtra_protos.h"
#include "lowest_protos.h"

#define LOCK_PKTMSG_SIZE sizeof(struct LockPktMsg)
/** this is just a variation of the "doofus" format */
struct LockPktMsg {
	struct	DoofusPktMsg	dpm;

	struct	NFSLock				lockreq;	/* request structure */
	struct	NFSLockReturn		lockret;	/* return structure */
	struct	LockKey				*lk;
};




/********************************************************************/
static void lock_free_mem(struct DosPacket *dosmsg,
							long erro, struct LockKey *lk)
/********************************************************************/
{
	REMOVE_FROM_LIST(lk, first_lk);
	FreeRemember(&lk->mem, TRUE);				/* appendages */
	FreeMem(lk, LK_SIZE);						/* lock key struct */
	dosmsg->dp_Res1 = 0;
	if(erro) dosmsg->dp_Res2 = erro;
}

/********************************************************************/
static long handle_lock_net(struct LockPktMsg *lpm)
/********************************************************************/
{
struct DosPacket *dosmsg = lpm->dpm.dp_original;
struct LockKey *lk = lpm->lk;

	dosmsg->dp_Res1 = CTOB(&lk->lock);
	dosmsg->dp_Res2 = lpm->lockret.remote_res2;

/** OK?? */
	if(lpm->dpm.net.pm.smsg.result == PAR_OK &&
		(lk->remote.remote_il = lpm->lockret.remote_il) ) {
			lk->remote.majic = lpm->lockret.remote_majic;
			lk->Type = LK_REMOTE;
		}

/** NOPE, BAD - FREE THE LOCK MEMORY */
	else {
		if(lpm->dpm.net.pm.smsg.result != PAR_OK)
				lock_free_mem(dosmsg, ERROR_NO_DISK, lk);
		else	lock_free_mem(dosmsg, 0, lk);

	}
	return(AR_FLAG_RETURNDOSMSG | AR_FLAG_FREEDOOF);
}







/********************************************************************/
	long action_locate_object(struct DosPacket *dosmsg,
									struct MsgPort *dm_retport)
/********************************************************************
 steps - always strip off the device name
  see if there is a lock
   yes? is it remote? get machine & service from this and send filename
                machine or root? have to strip and put in a ':'
 ********************************************************************/
{
struct OurLock
	*offset_fl = BTOC(dosmsg->dp_Arg1);

unsigned char
	*name = BTOC(dosmsg->dp_Arg2),		/* look at name_len, really */
	*file_name;

struct LockKey *lk, *offset_lk;
struct LockPktMsg *lpm;

short
	name_len = *name++,					/* BCPL style string */
	alloc_size, tmp;
		dosmsg->dp_Res1 = 0; dosmsg->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
		return(AR_FLAG_RETURNDOSMSG);


/** THROW AWAY EVERYTHING BEFORE THE ':' eg maj: or xxx: if assign'd */
	if((tmp = find_char(name, ':', name_len) + 1) > 0)
		{ name += tmp; name_len -= tmp; }
	if(name_len>0 && name[name_len-1] == '/') name_len--;	/* remove trailing '/' */

{ unsigned char tt[100], t1[200], *n = BTOC(dosmsg->dp_Arg2);
		CopyMem(&n[1], t1, n[0]); t1[n[0]] = 0;
		spf(tt, 100, "lock: offs=%lx, name=(%s), len:=%ld",
			offset_fl, t1, name_len); MyPrint(win1, tt); }


/** MEMORY FOR THE LOCK (WITH BUILT IN LOCK KEY) */
	if(!(lk = AllocMem(LK_SIZE, MEMF_PUBLIC | MEMF_CLEAR)) ) {
		dosmsg->dp_Res1 = 0; dosmsg->dp_Res2 = ERROR_NO_FREE_STORE;
		return(AR_FLAG_RETURNDOSMSG);
	}
	ADD_HEAD(lk, first_lk);							/* add into the list */
	lk->lock.lk = lk;								/* MUST BACK POINT */
	lk->lock.fl_Access = dosmsg->dp_Arg3;
	lk->lock.fl_Task   = dosmsg->dp_Port;			/* already contains "OurPort" */
	lk->lock.fl_Volume = CTOB(DevList); 			/* our volume */
	dosmsg->dp_Res1 = CTOB(&lk->lock);

/** OFFSET LOCK IS A ROOT LOCK ??? (eg lock=0 or MAJ:) */
	if(!offset_fl ||
		((offset_lk = offset_fl->lk)->Type == LK_ROOT)) {
		short net_server;

	/** ANOTHER LOCK OF THE ROOT DIR ?? */
		if(name_len == 0) {
			MyPrint(win1, "lock: locked root");
			lk->Type = LK_ROOT;
			return(AR_FLAG_RETURNDOSMSG);
		}

		tmp = find_char(name, '/', name_len) + 1; 	/* look for maj:0A/ */
		if((tmp == 3 || (tmp == 0 && name_len == 2)) &&
				(lk->remote.netserver=net_server=name[0]-'0') >= 0 && net_server <= 7 &&
								netservport[net_server]) {

			lk->remote.service = SERV_FILE;
			lk->remote.machine = name[1];

		/** RETURN THE LOCK ??? (on eg MAJ:0A) */
			if(tmp == 0) {
				MyPrint(win1, "lock: locked machine");
				lk->Type = LK_MACHINE;
				return(AR_FLAG_RETURNDOSMSG);
			}

		/** SKIP OVER TO THE FIRST '/' eg [MAJ:]0A/dh0... */
			name += tmp; name_len -= tmp;
		}

	/** TRY ANOTHER FILE SYSTEM */
		else {
			MyPrint(win1, "lock: locked nothing");
			lock_free_mem(dosmsg, ERROR_OBJECT_NOT_FOUND, lk);
			return(AR_FLAG_RETURNDOSMSG);
		}
	}

/** OFFSET LOCK A MACHINE ??? */
	else if(offset_lk->Type == LK_MACHINE) {
		lk->remote.machine = offset_lk->remote.machine;
		lk->remote.service = offset_lk->remote.service;
		lk->remote.netserver = offset_lk->remote.netserver;
		if(name_len == 0) {
			lk->Type = LK_MACHINE;
			return(AR_FLAG_RETURNDOSMSG);
		}
	}

/** ANOTHER FILE SYSTEM ?? */
	else if(offset_lk->Type == LK_LOCAL) {
		MyPrint(win1, "lock: local lock??");
		lock_free_mem(dosmsg, ERROR_OBJECT_NOT_FOUND, lk);
		return(AR_FLAG_RETURNDOSMSG);
	}

/** OK - THIS IS FOR ANOTHER MACHINE */
	alloc_size = LOCK_PKTMSG_SIZE + name_len + 8;
	if(!(lpm = AllocMem(alloc_size, MEMF_PUBLIC)) ) {
		lock_free_mem(dosmsg, ERROR_NO_FREE_STORE, lk);
		return(AR_FLAG_RETURNDOSMSG);
	}
	file_name	= (unsigned char *)&lpm[1];
	file_name[0] = name_len;
	CopyMem(name, &file_name[1], name_len); file_name[name_len+1] = 0;
	lpm->lk = lk;

/** WAS THAT OFFSET LOCK A REMOTE TYPE?? */
	if(offset_fl && offset_lk->Type == LK_REMOTE) {
		lk->remote.netserver = offset_lk->remote.netserver;
		lk->remote.machine = offset_lk->remote.machine;
		lk->remote.service = offset_lk->remote.service;
		lpm->lockreq.internallock = offset_lk->remote.remote_il;
		lpm->lockreq.remote_majic = offset_lk->remote.majic;
	}
/** OTHERWISE PUT A ':' in place of the next '/' so [net:0A/]dh0/prefs becomes
 ** [net:0A/]dh0:prefs  where the [] part has already been stripped */
	else {
		lpm->lockreq.internallock = 0;
		if((tmp = find_char(&file_name[1], '/', name_len)) < 0) {
			file_name[file_name[0] = ++name_len] = ':';
			file_name[name_len+1] = 0;
		}
		else
			file_name[tmp+1] = ':';				/* replace the '/' with ':' */
	}
	lpm->lockreq.request = REQUEST_LOCK;
	lpm->lockreq.mode = dosmsg->dp_Arg3;

{ unsigned char tt[100], t1[200];
		CopyMem(&file_name[1], t1, file_name[0]); t1[file_name[0]] = 0;
		spf(tt, 100, "lock: lock=%ld, name=(%s)\n", offset_fl, t1); MyPrint(win1, tt); }

/** send off the net-pkt-msg */
	INIT_DOOFPKTMSG(&lpm->dpm,
			handle_lock_net,						/* our routine to call */
			netrepport,								/* net reply port */
			dosmsg, dm_retport,						/* dos msg & reply port */
			alloc_size,
			lk->remote.machine, lk->remote.service,
			&lpm->lockreq, sizeof(struct NFSLock),	/* net-service-request */
			file_name, name_len+2,					/* send-body */
			NULL, 0,								/* result-body */
			&lpm->lockret, sizeof(struct NFSLockReturn));
													/* return stuff */
	PutMsg(NET_SERV_PORT(lk), lpm);
	return(0);

}




/********************************************************************/
	long action_copy_dir(struct DosPacket *dosmsg,
									struct MsgPort *dm_retport)
/********************************************************************

 ********************************************************************/
{
struct OurLock *orig_fl = BTOC(dosmsg->dp_Arg1);
struct LockKey *orig_lk, *lk;

	if(!orig_fl) {
		dosmsg->dp_Res1 = 0; dosmsg->dp_Res2 = 0;
		return(AR_FLAG_RETURNDOSMSG);
	}
	orig_lk = orig_fl->lk;



/** MEMORY FOR THE LOCK (WITH BUILT IN LOCK KEY) */

	if(!(lk = AllocMem(LK_SIZE, MEMF_PUBLIC | MEMF_CLEAR)) ) {
		dosmsg->dp_Res1 = 0; dosmsg->dp_Res2 = ERROR_NO_FREE_STORE;
		return(AR_FLAG_RETURNDOSMSG);
	}
	CopyMem(orig_lk, lk, sizeof(*lk));				/* default everything */
	ADD_HEAD(lk, first_lk);							/* add into the list */
	lk->lock.lk = lk;								/* MUST BACK POINT */
	lk->Type = 0;
	dosmsg->dp_Res1 = CTOB(&lk->lock);


/** SEE WHAT KIND OF LOCK WE ARE CLONING */
	switch(orig_lk->Type) {

	/** CLONE A REMOTE LOCK */

		case LK_REMOTE: {
		struct LockPktMsg *lpm;
			if(!(lpm = AllocMem(LOCK_PKTMSG_SIZE, MEMF_PUBLIC)) ) {
				lock_free_mem(dosmsg, ERROR_NO_FREE_STORE, lk);
				return(AR_FLAG_RETURNDOSMSG);
			}
			lpm->lockreq.request = REQUEST_LOCK;
			lpm->lockreq.internallock	= orig_lk->remote.remote_il;
			lpm->lockreq.remote_majic	= orig_lk->remote.majic;

		/** send off the net-pkt-msg */
			INIT_DOOFPKTMSG(&lpm->dpm,
				handle_lock_net,						/* our routine to call */
				netrepport,								/* net reply port */
				dosmsg, dm_retport,						/* dos msg & reply port */
				LOCK_PKTMSG_SIZE,
				lk->remote.machine, lk->remote.service,
				&lpm->lockreq, sizeof(struct NFSLock),	/* net-service-request */
				NULL, 0,								/* send-body */
				NULL, 0,								/* result-body */
				&lpm->lockret, sizeof(struct NFSLockReturn));
														/* return stuff */
			PutMsg(NET_SERV_PORT(lk), lpm);
			return(0);
		}

	/** ALREADY CLONED! */
		default:
			break;
	}

	return(AR_FLAG_RETURNDOSMSG);
}

