/********************************************************************
 ** NETWORK FILE SYSTEM SERVICE v0.5
 **
 ** (c) Spak, Darrell Tam, c9107253@ee.newcastle.edu.au (1994)
 ** phone (Australia) 049-829-710
 **                    49-829-710
 ** (c) SST Jan-Feb-Mar 1994
 **
 ** A NETWORK FILE SYSTEM SERVICE WHICH REGISTERS WITH ParServer or
 ** compatible servers
 ** 
 ** the format of the messages sent/received are as shown in parstuff.h 
 ** which is a "generic" format
 **
 ** features:
 ** - all operations are totally asynchronous
 ** - reading is double buffered for best performance (hence the code!)
 **
 ** bugs:
 ** - writing is not double buffered
 **
 **
 ** TABS to 4
 ********************************************************************/

#include "/snd/everything.h"
#include <st/st_proto.h>
#include <string.h>
#include "nfsinternal.h"

#include "nfsglobs_protos.h"
#include "nfsopen_protos.h"
#include "nfsclose_protos.h"
#include "nfsread_protos.h"
#include "nfswrite_protos.h"
#include "nfsseek_protos.h"
#include "nfslock_protos.h"
#include "nfsfreelock_protos.h"
#include "nfswaitchar_protos.h"
#include "nfsexamine_protos.h"

short	netport = SERV_FILE;				/* network "port" number */
char	*netregname = "ParRegister";		/* server to "register" with */


/********************************************************************/
	void CleanUp(void)
/********************************************************************/
{
/** REMOVE US AS A SERVER FROM THE THING */
	if(registered) {
	struct RegisterMsg rm;
	struct Message *maj;

		INIT_REGISTERMSG(&rm, ourport, RM_REMOVE_SERVER, netport, NULL, NULL); 
		for(PutMsg(parport, &rm); (WaitPort(ourport), (maj = GetMsg(ourport)) != &rm);)
					ReplyMsg(maj); /* important to return all messages but ours */
	}
	if(ourport) DeletePort(ourport);
	if(dosport) DeletePort(dosport);
	if(GfxBase) CloseLibrary((struct Library *)GfxBase);
	if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);

}


/********************************************************************/
	short InitStuff(void)
/********************************************************************/
{
	out = Output();
	if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0))
	|| !(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0)) )
		return(0);
	if(!(ourport = CreatePort(0,0)) ||			/* port to send packs to */
	   !(dosport = CreatePort(0,0))) {			/* comms with dos */
		fpf(out, "No ports\n");
		return(0);
	}
	if(!(parport = FindPort(netregname)) ) {
		fpf(out, "Couldn't find '%s'\n", netregname);
		return(0);
	}

/** REGISTER WITH THE PARALLEL THING */
{
struct RegisterMsg rm;
	INIT_REGISTERMSG(&rm, ourport, RM_ADD_SERVER, netport, ourport, NULL); 
	PutMsg(parport, &rm); WaitPort(ourport); GetMsg(ourport);

	if(rm.smsg.result != (long)ourport) {
		fpf(out, "Netport (%ld) is already in use ('%s')\n",
			netport,
			((struct MsgPort *)rm.smsg.result)->mp_Node.ln_Name);
		return(0);
	}
	registered = 1;
	fpf(out, "Registered ok (netport=%ld)\n", netport);
}
	return(1);
}


/********************************************************************/
	void DoMajic(void)
/********************************************************************/
{

unsigned long mask, waitmask, pmask, dmask;
register struct PktMsgRecv *pmr;

	waitmask =	(pmask = 1<<ourport->mp_SigBit) |
				(dmask = 1<<dosport->mp_SigBit) |
				SIGBREAKF_CTRL_C;

	fpf(out, "Waiting for requests\n");
	while(/* packets outstanding && */ 
		stillgoing && !((mask = Wait(waitmask)) & SIGBREAKF_CTRL_C)) {

	/** THIS PORT IS ONLY MEANT FOR DIRECT-COMMS WITH THE SERVER */
		if(mask & pmask) while(pmr = (struct PktMsgRecv *)GetMsg(ourport) ) {

#ifdef DEBUG
			fpf(out,"nfs: recv (msg=%lx, type=%ld, alloclen=%ld)\n",
				pmr, pmr->pm.smsg.type, pmr->pm.smsg.alloclen);
#endif
			switch(pmr->pm.smsg.type) {
				case TYPE_RECEIVED: {
				struct NFSDummy *nfs_req = (void *)pmr->req_body;

				/* the action table with action numbers shown */
				static void *(* action[])(struct PktMsgRecv *) = {
					srv_examinelock,		/* 0 */
					srv_openfile,			/* 1 */
					srv_closefile,			/* 2 */
					srv_read,				/* 3 */
					srv_write,				/* 4 */
					srv_seek,				/* 5 */
					srv_lock,				/* 6 */
					srv_freelock,			/* 7 */
					srv_waitchar,			/* 8 */
					srv_copylock,			/* 9 */
					srv_examinenext,		/* 10 */
				};

				register void *err_mem;
				register long request;
#ifdef DEBUG
					fpf(out, "nfs: action=%ld\n", nfs_req->request);
#endif

				/** CHANGE THE NET-SERVER-MESSAGE INTO ONE FOR US */
					INIT_MSG(&pmr->pm.smsg.msg,  ourport, sizeof(*pmr));

					if((request = nfs_req->request) < (sizeof(action)/sizeof(void *)))
						err_mem = action[request](pmr);
					else
						err_mem = &nfs_res_fail;

				/** IF THERE WAS A BAD ERROR RETURN THE PACKET IMMEDIATELY */
					if(err_mem) {
						if(nfs_req->sr.return_len) {
							pmr->user.user1 = NULL;			/* free on return */
							INTERNAL_PREP_PKTMSG_DMA(&pmr->pm,
								EMEM_RETURNMSG,
								SERV_RETURN,
								err_mem, nfs_req->sr.return_len);
							PUT_STDMSG(&pmr->pm.smsg,
										pmr->dmaport, TYPE_INTERNAL_SEND);
						}
						else FREE_PKTMSGRECV(pmr);
					}
				}
				break;

			/** DMA PACKET RETURNED (FREE MEM IF NO ROUTINE) */
				case  TYPE_RETURN: {
					/* for the moment ignore send-errors ... */
					if((long)pmr->user.user1)
							pmr->user.user1(pmr);
								else
							FREE_PKTMSGRECV(pmr);		/* free the message */
				}
				break;

			/** SERVER TRYING TO KILL US ? */
				case TYPE_QUIT: {
					stillgoing = 0;
					ReplyMsg(pmr);
				}
				break;

			/** DUNNO WHAT THIS IS BUT REPLY TO IT ANYWAY */
				default:
					ReplyMsg(pmr);
			}
		}

	/** GET RETURN PACKET FROM DOS (call the function contained in the dosmsg) */
		if(mask & dmask) {
		struct DosMsg *dm;
			while(dm = (struct DosMsg *)GetMsg(dosport))
				if(dm->code) dm->code(dm);
		}
	}
}




/********************************************************************/
	int main(int argc, char *argv[])
/********************************************************************/
{
struct Process *pr = (void *)FindTask(NULL);
void *olddoswindow;
/*	if(argc >= 1) {
		netregname = argv[1];					/* eg "ParServer" */
		if(argc >= 2) 
			netport = atoi(argv[2]);
	} */
	olddoswindow = pr->pr_WindowPtr;
	pr->pr_WindowPtr = (void *)-1;					/* turn off dos-request windows */
	if(InitStuff()) DoMajic();
	CleanUp();
	pr->pr_WindowPtr = olddoswindow;
}

