/********************************************************************
 ** 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
 **
 ** OPEN (ACTION_FINDINPUT | ACTION_FINDOUTPUT | ACTION_UPDATE)
 **
 ** Actions are sent to the network device
 **
 ** NOW supports shells on CON: type devices, 
 ** passes on the first "Open", consequent ones are simply ignored
 ** and returned with the same fh_Arg1. See interactive.s
 **
 ** TABS to 4
 ********************************************************************/

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

#define OPEN_PKTMSG_SIZE sizeof(struct OpenPktMsg)

/** this is just a variation of the "doofus" format */
struct OpenPktMsg {
	struct	DoofusPktMsg	dpm;

	struct	NFSOpenFile			openreq;	/* request structure */
	struct	NFSOpenFileReturn	openret;	/* return structure */
	struct	FileArg1			*fa1;
};



/********************************************************************/
	short extract_name(
			unsigned char *name, unsigned char *dest, short name_len,
				struct	LockKey *offs_lk,	/* offset lock key (or NULL for none) */
				long	*type,				/* return of the type of lock */
				short	*netserver,			/* return */
				short 	*machine,			/* return */
				short	*service)			/* return */
/********************************************************************
returns the type of file this name actually refers to
ie - if the final file should reside on a remote file system then
     LK_REMOTE is returned
  fsys is a pointer to your pointer to a message port of the assoc.
       file system or network handler program.
 ********************************************************************/
{
short tmp;

/** THROW AWAY EVERYTHING BEFORE THE ':' ie MAJ:xxx becomes xxx */
	if((tmp = find_char(name, ':', name_len) + 1) > 0)
		{ name += tmp; name_len -= tmp; }

/** STRIP A TRAILING '/' ie thing/ becomes thing */
	if(name_len>0 && name[name_len-1] == '/') name_len--;

/** TYPE == LK_ROOT? LOOK FOR A MACHINE ID NAME */
	if(!offs_lk || offs_lk->Type == LK_ROOT) {

		/* nothing after the ':' means a root lock */
		if(name_len == 0) { *type = LK_ROOT; return(name_len); }

		/* look for a '/' as in "MAJ:0A/" */
		tmp = find_char(name, '/', name_len) + 1;

	/** NOT A MACHINE - PERHAPS A LOCAL FILE */
		if(tmp == 0 && name_len != 2) {
			CopyMem(name, dest, name_len);
			return(name_len);
		}

	/** UPDATE THE STATS - IF NO OTHER FILE FOLLOWS THEN RETURN */
		*netserver = name[0] - '0';
		*machine = name[1];
		*service = SERV_FILE;
		if(tmp == 0) { *type = LK_MACHINE; return(0); }
		*type = LK_REMOTE;
		name += tmp; name_len -= tmp;

	/** LOOK FOR THE NEXT '/' - IF NOT FOUND TRUNCATE IN A ':' ELSE */
		CopyMem(name, dest, name_len);
		tmp = find_char(name, '/', name_len) + 1;
		if(tmp == 0)
			dest[name_len++] = ':';
		else
			dest[tmp-1] = ':';
		return(name_len);
	}

/** TYPE == LK_MACHINE? LOOK FOR MORE */
	else if(offs_lk->Type == LK_MACHINE) {
		*netserver = offs_lk->remote.netserver;
		*machine = offs_lk->remote.machine;
		*service = offs_lk->remote.service;
		if(name_len == 0) { *type = LK_MACHINE; return(0); }

		tmp = find_char(name, '/', name_len) + 1;
		name += tmp; name_len -= tmp;
		CopyMem(name, dest, name_len);

	}
/** TYPE == LK_REMOTE? PUT BACK THE FILE NAME AND EVERYTHING */
	else if(offs_lk->Type == LK_REMOTE) {
		*netserver = offs_lk->remote.netserver;
		*machine = offs_lk->remote.machine;
		*service = offs_lk->remote.service;
		CopyMem(name, dest, name_len);
		return(name_len);
	}
}


/********************************************************************/
static long handle_openfile_net(struct OpenPktMsg *opm)
/********************************************************************/
{
struct DosPacket *dosmsg = opm->dpm.dp_original;
struct FileHandle *fh = BTOC(dosmsg->dp_Arg1);
struct FileArg1	*fa1 = opm->fa1;
{ unsigned char tt[100]; spf(tt, 100, "open: res1=%ld, res2=%ld",
		opm->openret.remote_res1, opm->openret.remote_res2); MyPrint(win1, tt); }

/** CHECK OUT THE RESULT */
	dosmsg->dp_Res2 = opm->openret.remote_res2;
	if(opm->dpm.net.pm.smsg.result == PAR_OK &&
		(dosmsg->dp_Res1 = opm->openret.remote_res1) ) {

		fa1->remote.remote_ifh	= opm->openret.remote_ifh;
		fa1->remote.majic 		= opm->openret.remote_majic;

	/** IS THE FILE INTERACTIVE?? IF SO, MAKE A SOFTWARE INTERRUPT & PORT */
		if(*(long *)&fh->fh_Port = opm->openret.remote_ifh_Port) {
		struct InterPort *imp;
			if(imp = AllocRemember(&fa1->mem,
						INTER_MSGPORT_SIZE, MEMF_PUBLIC | MEMF_CLEAR)) {
				imp->i.is_Code 			= handle_interactive_stuff;
				imp->i.is_Data 			= imp;
				imp->mp.mp_Node.ln_Type	= NT_MSGPORT;
				imp->mp.mp_Flags		= PA_SOFTINT;
				imp->mp.mp_SigTask		= (struct Task *)&imp->i;
				NewList(&imp->mp.mp_MsgList);
				imp->fa1 = fa1;
				imp->pass = localrepport;
				imp->opencount = 1;
				dosmsg->dp_Port = imp;			/* new port for every interactive */
			}
		}
		fh->fh_Type = dosmsg->dp_Port;			/* already contains "OurPort" */
		fh->fh_Arg1 = (long)fa1;
	}

/** ERROR ??? */
	else {
		REMOVE_FROM_LIST(fa1, first_fa1);		/* no longer open */
		FreeMem(fa1, FA1_SIZE);					/* gone */
		dosmsg->dp_Res1 = 0;
		if(opm->dpm.net.pm.smsg.result != PAR_OK) dosmsg->dp_Res2 = ERROR_NO_DISK;
	}
	return(AR_FLAG_RETURNDOSMSG | AR_FLAG_FREEDOOF);
}







/********************************************************************/
long action_openfile(struct DosPacket *dosmsg,
							struct MsgPort *dm_retport)
/********************************************************************/
{
struct FileHandle	*fh = BTOC(dosmsg->dp_Arg1);
struct OurLock		*fl = BTOC(dosmsg->dp_Arg2);
struct LockKey		*lk = NULL;
unsigned char		*fname = BTOC(dosmsg->dp_Arg3),	/* note, BCPL style string */
					newname[MAXFILENAMELEN+4];		/* BCPL also */
long	type;
short	netserver, machine, service, newname_len;
struct	FileArg1	*fa1;

	if(fl) lk = fl->lk;
{ unsigned char tt[60];
	CopyMem(fname+1, tt, fname[0]);
	spf(tt+fname[0],60-fname[0]," fh=%lx, lock=%lx, task=%lx",
							fh, fl, dosmsg->dp_Port->mp_SigTask);
	MyPrint(win1, tt); }
	newname[0] = newname_len =
		extract_name(&fname[1], &newname[1], fname[0],		/* filename stuff */
				lk,											/* offset lock key */
				&type, &netserver, &machine, &service);		/* things returned */



/** WHAT WAS THAT FILE?? */
	if(type == LK_REMOTE) {

	/** MAKE SURE WE HAVE A NETWORK PORT TO SEND TO */
		if(netserver >=0 && netserver <=7 && netservport[netserver]) {
		struct	OpenPktMsg	*opm;
		short	sendname_len = newname_len + 4;
		unsigned char *sendname;

			if(!(fa1 = AllocMem(FA1_SIZE, MEMF_PUBLIC | MEMF_CLEAR)) ||
			   !(opm = AllocMem(OPEN_PKTMSG_SIZE + sendname_len, MEMF_PUBLIC)) ) {
				if(fa1) FreeMem(fa1, FA1_SIZE);
				dosmsg->dp_Res1 = 0; dosmsg->dp_Res2 = ERROR_NO_FREE_STORE;
				return(AR_FLAG_RETURNDOSMSG);
			}

			opm->fa1 = fa1;
			sendname = (unsigned char *)&opm[1];
			CopyMem(newname, sendname, newname_len+1);		/* copy the new filename */
			sendname[newname_len+2] = '\0';					/* NULL terminate too */

			opm->openreq.request 	= REQUEST_OPENFILE;
			opm->openreq.action 	= dosmsg->dp_Type;
			if(lk) opm->openreq.internallock = lk->remote.remote_il;
			  else opm->openreq.internallock = NULL;

			ADD_HEAD(fa1, first_fa1);						/* add into the list */
			fa1->Type		= LK_REMOTE;
			fa1->fh 		= fh;							/* (don't really use it tho) */
			fa1->parent_lock = fl;							/* lock we came from */
			fa1->remote.netserver = netserver;

			INIT_DOOFPKTMSG(&opm->dpm,
						handle_openfile_net,
						netrepport,
						dosmsg,
						dm_retport,
						OPEN_PKTMSG_SIZE + sendname_len,
						fa1->remote.machine = machine,
						fa1->remote.service = service,
						&opm->openreq, sizeof(struct NFSOpenFile),	/* request */
						sendname, sendname_len,						/* send-body */
						NULL, 0,									/* result-body */
						&opm->openret, sizeof(struct NFSOpenFileReturn));
																	/* return codes */
	{ unsigned char tt[100]; spf(tt, 100, "port=%lx", NET_SERV_PORT(fa1)); MyPrint(win1, tt); }

			PutMsg(NET_SERV_PORT(fa1), opm);
			return(0);
		}
	}


	dosmsg->dp_Res1 = 0; dosmsg->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
	return(AR_FLAG_RETURNDOSMSG);
}
