/**
 **
 ** INCLUDE FILE FOR THE NETWORK FILE SYSTEM - DOS FILE SYSTEM END
 **                   INTERNAL STUFF MAINLY
 **          ALL STRUCTURES SHOUILD BE LONG WORD ALIGNED
 **/

#include <dos/filehandler.h>
#include <exec/alerts.h>
#include <st/st_proto.h>
#include <st/gadsetup.h>
#include "/srv/nfsthings.h"


/** COMPATIBLE WITH THE STANDARD AMIGA DOS LOCK */
struct OurLock {
    BPTR		fl_Link;	/* bcpl pointer to next lock */
	union {
	    LONG		fl_Key;		/* disk block number */
		struct	LockKey *lk;	/* back pointer */
	};
    LONG		fl_Access;	/* exclusive or shared */
    struct MsgPort *	fl_Task;	/* handler task's port */
    BPTR		fl_Volume;	/* bptr to DLT_VOLUME DosList entry */
};



/** NOTE: the lock.fl_Key MUST point back to the start of the LockKey structure
 ** in case someone makes a home made copy of the lock */
struct LockKey {
	struct	LockKey		*next, *prev;	/* keep track of alloc'd locks */
	struct	OurLock		lock;			/* fl_Key MUST point back to LockKey */
	long	Type;						/* type of lock */
	union {
		struct {
			long	nothing;
		} root;							/* ACTUALLY EQUIV TO THE zero LOCK */
		struct {
			short	netserver;			/* index into our array of msg port ptrs */
			short	machine;			/* send to that machine */
			short	service;			/* "service" on the dest machine */
			short	pad;				/* keep long word aligned */
			long	remote_il;			/* remote internal file lock */
			long	majic;				/* the "majic code" sent to us */
		} remote;						/* LOCK IS ON ANOTHER MACHINE */
		struct {
			struct FileLock *lock;		/* other filesystem's lock */
			struct MsgPort *fsys;
		} local;						/* LOCK IS ON OUR AMIGA */
		struct {
			short	netserver;			/* same as that for LockKey.remote */
			short	machine;			/* ditto */
			short	service;			/* ditto */
			short	pad;				/* ditto */
		} machine;						/* LOCK REFERS TO ANOTHER MACHINE */
	};
	void	*stuff1;					/* for expansion (not currently used) */
	void	*stuff2;
	struct	Remember *mem;				/* extras may be alloc'd on this (usually NULL) */
};
#define LK_SIZE (sizeof(struct LockKey))


/** LOCK KEY TYPES (AND ALSO FILEARG1.Type TYPES) */
#define LK_NONEXIST	0x0000		/* nothing! - not lock'd or open'd yet */
#define LK_ROOT		0x0001		/* ROOT lock on OUR filesys */
#define LK_LOCAL	0x0002		/* lock refers to a local file */
#define LK_REMOTE	0x0003		/* lock is on another machine */
#define LK_MACHINE	0x0004		/* lock refers to a machine */

/* heirarchy -
	root (LK_ROOT) == ZERO lock
		machine1 (eg 0A, 3Z etc which refer to entire machines)
			remoteroot (eg df0, "ram disk")
				normal remote filesystem from here on
		machine2
			remoteroot
				etc
		.
		.
*/

/**
 **
 ** THIS IS WHAT fh_Arg1 of *OUR* FILEHANDLE POINTS TO
 **
 **/

struct FileArg1 {
	struct	FileArg1   *next, *prev;	/* keep track of open files */
	struct	FileHandle *fh;				/* as per dp_Arg1 when opening (which points back here) */
	struct	OurLock	   *parent_lock;	/* as per dp_Arg2 when opening */
	long	Type;						/* type */
	union {
		struct {
			short	netserver;			/* index into our array of msg port ptrs */
			short	machine;			/* send to that machine */
			short	service;			/* "service" on the dest machine */
			short	pad;				/* keep long word aligned */

			long	remote_ifh;			/* remote file handle */
			long	majic;				/* the "majic code" sent to us */
		} remote;
		struct {
			struct FileHandle *fh;		/* local file handle */
		} local;
	};

	void	*stuff1;					/* for expansion (not currently used) */
	void	*stuff2;

	struct	Remember *mem;				/* extras may be alloc'd on this - eg
										  * every interactive file gets its own
										  * softinterrupt & message port,
										  * so that is alloc'd on here */
};


#define FA1_SIZE (sizeof(struct FileArg1))


/**
 ** array in globs.c - use this macro to find where the msgport of the net-server
 ** task associated with this remote lock or file
 **/

#define NET_SERV_PORT(a)  netservport[a->remote.netserver]


/** INTERNAL-INTERACTIVE-INTERRUPT-FILE MESSAGE PORT (used for CON: types) */
struct InterPort {
	struct MsgPort		mp;				/* message port */
	struct Interrupt	i;				/* interrupt code */
	struct FileArg1		*fa1;			/* pointer to the first "open" fh */
	struct MsgPort		*pass;			/* message port to pass packets onto */
	long   opencount;					/* when this reaches 0 we quit */
};
#define INTER_MSGPORT_SIZE (sizeof(struct InterPort))



/** ALL NETWORK & LOCAL PKT MSGS SENT OUT ARE IN THIS FORM! */

/** since there is usually no overlap between those messages which are sent
 ** locally and those sent over the network then we can use the same structure
 ** for both originated dos-messages and originated net-packets, of course
 ** not at the same time on the same DoofusPktMsg!
 **/

struct DoofusPktMsg {
	union {
		struct {
			struct	PktMsg	pm;				/* packet msg (original) */
		} net;								/* network packet? */
		struct {
			struct	StandardPacket	sp;
		} dos;								/* local "dos" type packet */
	};
	long	(*code)(struct DoofusPktMsg *);
	long	type;							/* see below - filled but not used */
	struct	DosPacket	*dp_original;		/* original dosmsgpkt sent to us */
	struct	MsgPort		*dp_returnport;		/* return port for dp_original */
	long	allocmem;						/* memory allocated */
};

#define	DPM_TYPE_NETPKTMSG		0			/* represents a network packet */
#define DPM_TYPE_DOS			1			/* represents a dos packet */


/** INIT the "doofus" message as a NETWORK message */
#define INIT_DOOFPKTMSG(dpm, code_o, \
			ourport_o, \
			dporig_o, dp_returnport_o, \
			memallocd_o, \
			destmachine_o, \
			service_o, \
			req_o, reqlen_o, sendmem_o, sendlen_o, \
			recv_o, recvlen_o, res_o, reslen_o) \
		\
		\
		((dpm)->type		= DPM_TYPE_NETPKTMSG,\
		(dpm)->code			= code_o,\
		(dpm)->dp_original	= dporig_o,\
		(dpm)->dp_returnport= dp_returnport_o,\
		(dpm)->allocmem		= memallocd_o,\
		INIT_PKTMSG_ORIGINAL(&(dpm)->net.pm, ourport_o, destmachine_o, service_o, \
			req_o, reqlen_o, sendmem_o, sendlen_o,\
			recv_o, recvlen_o, res_o, reslen_o))

#define FREE_DOOFPKTMSG(dpm_o) FreeMem(dpm_o, (dpm_o)->allocmem)

#define MAXFILENAMELEN 108

#define AR_FLAG_RETURNDOSMSG	0x0001		/* return the original dosmsg */
#define AR_FLAG_FREEDOOF		0x0002		/* main; free the doof msg */

/**
 **
 ** INIT & SEND OFF A PACKET THEN WAIT FOR A REPLY
 ** RETURNS THE VALUE OF RES1 
 **
 **/

#define DO_DOSPKT(sp_o, dest_o, replyport_o, action_o, a_o, b_o, c_o) \
			\
			(STD_PKT_ARGS3(sp_o, replyport_o, action_o, a_o, b_o, c_o),\
			PutMsg(dest_o, &(sp_o)->sp_Msg),\
			Wait(1<<(replyport_o)->mp_SigBit),\
			GetMsg(replyport_o),\
			(sp_o)->sp_Pkt.dp_Res1)


/** RETURN (REPLY TO) A DOS MSG (NO RETURN I'M AFRAID) */

#define RETURN_DOS_PKT(dos_pkt, our_port) \
	{\
	struct MsgPort *replyport_o = (dos_pkt)->dp_Port;\
		(dos_pkt)->dp_Port = (our_port);\
		PutMsg(replyport_o, (dos_pkt)->dp_Link);\
	}


/** USEFUL LITTLE MACROS */

#ifndef BTOC
#define BTOC(bp)    ((void *)(((long)(bp)) << 2))
#endif
#ifndef CTOB
#define CTOB(cp)    ((BPTR)(((long)(cp)) >> 2))
#endif
#ifndef MIN
#define MIN(a,b) (((a)<(b))? (a): (b))
#endif
#ifndef MAX
#define MAX(a,b) (((a)>(b))? (a): (b))
#endif
#define PacketsQueued(a) (!IsMsgPortEmpty(a))


