;: pronet-handler.s
;:
;:
;: 19.07.1994	started..

;: 17-04-1995	READ-Transfer umgebaut v34.0
;: 29-04-1995	EXAMINE-Packets neu programmiert v34.1
;: 18-06-1995	"+"-Exansion -> Unitnumber v34.2

DEBUG		equ	0

		include	"exec/exec.i"
		include	"dos/dos.i"
		include	"dos/dosextens.i"
		include	"dos/filehandler.i"
		include	"devices/timer.i"
		include	"devices/input.i"
		include	"devices/inputevent.i"
		include	"A:ProNET/include/devices/pronet.i"
		include	"A:OSmacros.i"

		include	"A:ProNET/source/network.i"

		include	"exec_lib.i"
		include	"dos_lib.i"

; -- Convert given BPTR to FileLock in FL->fl_Key data or NULL if FL=0
; -- Changes d0 !!
GETsFL		macro		;GETsFL dp_Arg1(a2),a0
		GETBPTR	\1,\2
		move.l	\2,d0
		beq.s	.\@getsfl
		move.l	fl_Key(\2),\2
.\@getsfl
		endm

; -- Struktur zum Speichern der Volumes
	      STRUCTURE	PHVolNode,0
		STRUCT	phvn_node,MLN_SIZE	;zur Verkettung
		APTR	phvn_doslist		;*VolumeNode
		BPTR	phvn_locklist		;BPTR->LockList
		BPTR	phvn_srvdoslist		;BPTR->VolNode beim Server
		LABEL	phvn_SIZEOF

j
		IFNE	DEBUG
		bsr	dinit
		ENDC

		move.l	4.w,a6
		move.l	ThisTask(a6),d0
		move.l	d0,ourprocess
		move.l	d0,a0
		lea	pr_MsgPort(a0),a0
		move.l	a0,ourport
		move.b	MP_SIGBIT(a0),Signal.packet

		move.l	ourport(pc),a0
		LIBCALL	WaitPort
		bsr	GetPacket
		move.l	d0,startuppacket
		move.l	d0,a0
		move.l	dp_Arg3(a0),a0
		add.l	a0,a0
		add.l	a0,a0
		move.l	a0,devnode

		GETBPTR	dol_Startup(a0),a0
		move.l	fssm_Unit(a0),d0
		GETBPTR	fssm_Environ(a0),a0
		tst.l	de_HighCyl(a0)
		beq.s	.ok1
		add.b	#"0",d0
		move.b	d0,plusflag

.ok1		lea	dosname(pc),a1
		moveq	#36,d0
		jsr	-552(a6)
		move.l	d0,dosbase
		beq	nodos

		bsr	startpronet
		tst.w	d0
		bne	nopronet

; jetzt neuen Handler anmelden.
		move.l	pronetio(pc),a4
		lea	sendbuf,a3
		move.l	#ACTION_NEWHANDLER,(a3)+
		move.l	IO_DEVICE(a4),a6
		move.l	devnode(pc),a0
		move.l	dn_Name(a0),a0
		add.l	a0,a0
		add.l	a0,a0
		addq.l	#1,a0
		lea	localbuf,a1
.copyloc1	move.b	(a0)+,(a1)+
		bne.s	.copyloc1
		move.b	#":",-1(a1)
		clr.b	(a1)
		lea	localbuf,a0
		LIBCALL	GetConfigString
		move.l	d0,a1
		move.l	d0,a0
.cc1		move.b	(a0)+,(a3)+
		bne.s	.cc1
		move.l	a1,a0
		LIBCALL	FreeConfigString
		bsr	sendpnpacket

		move.l	pronetmsgport(pc),a0
		move.l	4.w,a6
		LIBCALL	WaitPort
		move.l	pronetmsgport(pc),a0
		LIBCALL	GetMsg
		move.l	d0,actpronetmsg
		move.l	d0,a2
		lea	MN_SIZE+2(a2),a2
		move.l	4(a2),d0
		beq.s	.cc0
		move.l	actpronetmsg(pc),a1
		LIBCALL	ReplyMsg
		bra	noserver
.cc0		move.l	actpronetmsg(pc),a1
		LIBCALL	ReplyMsg

; alles klar jetzt..
		move.l	devnode(pc),a0
		move.l	ourport(pc),dol_Task(a0)
		move.l	startuppacket(pc),a0
		moveq	#DOSTRUE,d0
		moveq	#0,d1
		bsr	ReturnPacket	;Startuppacket zurückgeben
	IFNE	DEBUG
	st	debok
	ENDC

		bsr	Wait4Message

		clr.l	startuppacket	;damit es nicht nochmal zurückgeht

noserver	bsr	stoppronet

nopronet	move.l	dosbase(pc),a1
		move.l	4.w,a6
		jsr	-414(a6)
nodos		move.l	startuppacket(pc),d0
		beq.s	.0
		move.l	d0,a0
		move.l	#DOSFALSE,d0
		move.l	#ERROR_NO_FREE_STORE,d1
		bsr	ReturnPacket
.0		moveq	#0,d0
		rts

		dc.b	"$VER: pronet-handler 34.2 (18-06-95)",13,10,0
		even

startpronet	moveq	#pnr_Size,d0
		bsr	GetIORequest
		move.l	d0,pronetio
		beq	spnoioreq
		bsr	CreatePort
		move.l	d0,pronetmsgport
		beq	spnomsgport

		move.l	devnode(pc),a1		;Device, Unit und Flags
		move.l	dn_Startup(a1),a1	;aus der Mountlist nehmen!!
		add.l	a1,a1
		add.l	a1,a1
		move.l	fssm_Unit(a1),d0
		move.l	fssm_Flags(a1),d1
		move.l	fssm_Device(a1),a0
		add.l	a0,a0
		add.l	a0,a0
		addq.w	#1,a0
		move.l	pronetio(pc),a1
		move.w	#PNP_NEXTFREE,pnr_NetSourcePort(a1)
		move.l	pronetmsgport(pc),pnr_MsgPort(a1)
		move.l	4.w,a6
		LIBCALL	OpenDevice
		tst.l	d0
		bne	spnodev
		move.l	pronetio(pc),a1
		move.w	#CMD_WRITE,IO_COMMAND(a1)
		clr.l	pnr_Length2(a1)
		clr.w	pnr_NetDestPort(a1)
		move.l	pronetmsgport(pc),a0
		move.b	MP_SIGBIT(a0),Signal.pronet
		moveq	#0,d0
		rts

stoppronet	move.l	4.w,a6
		move.l	pronetio(pc),a1
		LIBCALL	CloseDevice
spnodev		move.l	pronetmsgport(pc),a0
		bsr	DeletePort
spnomsgport	move.l	pronetio(pc),a0
		bsr	FreeIORequest
spnoioreq	moveq	#-1,d0
		rts

w4mquitflag	dc.w	0
Wait4Message	tst.w	w4mquitflag
		bne	.quit
		clr.w	w4mquitflag

		lea	Signals(pc),a3	* auf die Messages
		moveq	#0,d0		* an allen möglichen
		moveq	#numports-1,d1	* Ports warten
.loop1		move.b	(a3),d2
		bmi.s	.0
		bset	d2,d0
.0		addq.w	#6,a3
		dbra	d1,.loop1
		move.l	4.w,a6
		LIBCALL	Wait
					* entsprechende Routinen
		moveq	#31,d7		* aufrufen
.00		rol.l	d0
		bcc.s	.notthisbit
		lea	Signals(pc),a3
		moveq	#numports-1,d4
.01		cmp.b	(a3),d7
		bne.s	.notthisport
		movem.l	d0/d4/d7/a3,-(sp)
		move.l	2(a3),a3
		jsr	(a3)
		movem.l	(sp)+,d0/d4/d7/a3
.notthisport	addq.w	#6,a3
		dbra	d4,.01
.notthisbit	dbra	d7,.00	

		bra	Wait4Message
.quit		rts
Signals:
Signal.pronet	dc.b	-1,0			;Signalbit
		dc.l	GetProNETMsg		;entsprechende Routine
Signal.packet	dc.b	-1,0
		dc.l	GetPacketMsg
numports	equ	2

GetProNETMsg	move.l	pronetmsgport(pc),a0
		move.l	4.w,a6
		LIBCALL	GetMsg
		move.l	d0,actpronetmsg
		beq.s	GetPacketMsg	;Ende !!
		move.l	d0,a3
		lea	MN_SIZE+2(a3),a3
		move.l	(a3)+,d2
		move.l	actpacket(pc),a2
		cmp.l	#ACTION_DISKINS,d2
		beq	ACT_DISKINS
		cmp.l	#ACTION_DISKREM,d2
		beq	ACT_DISKREM
		move.l	actanswerroutine(pc),a0
		jsr	(a0)
		clr.l	actpacket

		move.l	actpronetmsg(pc),d0
		beq.s	.0

		move.l	d0,a1
		move.l	4.w,a6
		LIBCALL	ReplyMsg
.0		bra.s	GetProNETMsg

; -- hier wird immer nur ein Packet geholt, dann auf die Abarbeitung ge-
; wartet und nachdem alle ProNETMsgs erledigt sind, wird nochmal versucht,
; ob hier Messages anliegen. Erst wenn beide Ports leer sind, wird der
; Task in Sleepstatus gelegt.
GetPacketMsg
		move.l	actpacket(pc),d0	;Wird ein anderes Packet
		bne.s	.ende		;gerade bearbeitet ? --> Warten
		move.l	4.w,a6
		bsr	GetPacket
		move.l	d0,actpacket
		beq.s	.ende
		move.l	d0,a2		;[a2] DosPacket
		move.l	dp_Action(a2),d0
	IFNE	DEBUG
	bsr	dcr
	bsr	dtypedec
	ENDC
		lea	sendbuf,a3	;[a3] sendbuf
		move.l	d0,(a3)+
		move.l	pronetio(pc),a4	;[a4] PNRequest
		lea	at(pc),a0
		moveq	#atl-1,d1
.findroutloop	cmp.l	(a0),d0
		bcs.s	.next
		cmp.l	4(a0),d0
		bls.s	.jsrroutine
.next		lea	12(a0),a0
		dbra	d1,.findroutloop
		bsr	ACT_NIL
		bra.s	GetPacketMsg
.jsrroutine	sub.l	(a0),d0
		add.l	d0,d0
		move.l	8(a0),a0
		lea	at(pc),a1
		add.w	(a0,d0.l),a1
		jsr	(a1)
		bra.s	GetPacketMsg
.ende		rts

		cnop	0,4
at		;dc.l	lowerbound,upperbound,tableaddress
		dc.l	7,34,actiontable1
		dc.l	40,40,actiontable2
		dc.l	82,82,actiontable3
		dc.l	87,87,actiontable4
		dc.l	1004,1008,actiontable5
		dc.l	1020,1034,actiontable6
		dc.l	2008,2009,actiontable7
		dc.l	4097,4098,actiontable8
		dc.l	4200,4200,actiontable9
atl		equ	(*-at)/12

actiontable1	dc.w	ACT_CURRENT_VOLUME-at
		dc.w	ACT_LOCATE_OBJECT-at,ACT_RENAME_DISK-at,ACT_NIL-at,ACT_NIL-at
		dc.w	ACT_NIL-at,ACT_NIL-at,ACT_NIL-at,ACT_FREE_LOCK-at,ACT_DELETE_OBJECT-at
		dc.w	ACT_RENAME_OBJECT-at,ACT_MORE_CACHE-at,ACT_COPY_DIR-at,ACT_NIL-at
		dc.w	ACT_SET_PROTECT-at,ACT_CREATE_DIR-at,ACT_EXAMINE_OBJECT-at,ACT_EXAMINE_OBJECT-at
		dc.w	ACT_DISK_INFO-at,ACT_INFO-at,ACT_FLUSH-at,ACT_SET_COMMENT-at
		dc.w	ACT_PARENT-at,ACT_NIL-at,ACT_INHIBIT-at,ACT_NIL-at
		dc.w	ACT_NIL-at,ACT_SET_DATE-at
actiontable2	dc.w	ACT_SAME_LOCK-at
actiontable3	dc.w	ACT_READ-at
actiontable4	dc.w	ACT_WRITE-at
actiontable5	dc.w	ACT_FINDxxx-at
		dc.w	ACT_FINDxxx-at,ACT_FINDxxx-at,ACT_END-at,ACT_SEEK-at
actiontable6	dc.w	ACT_FORMAT-at,ACT_MAKE_LINK-at,ACT_SET_FILE_SIZE-at,ACT_WRITE_PROTECT-at
		dc.w	ACT_READ_LINK-at,ACT_NIL-at,ACT_FH_FROM_LOCK-at,ACT_IS_FILESYSTEM-at
		dc.w	ACT_CHANGE_MODE-at,ACT_NIL-at,ACT_COPY_DIR_FH-at,ACT_PARENT_FH-at
		dc.w	ACT_NIL-at,ACT_NIL-at,ACT_EXAMINE_FH-at
actiontable7	dc.w	ACT_LOCK_RECORD-at,ACT_FREE_RECORD-at
actiontable8	dc.w	ACT_ADD_NOTIFY-at,ACT_REMOVE_NOTIFY-at
actiontable9	dc.w	ACT_SERIALIZE_DISK-at

** The routines will be called with the registers containing following:
** a6 Execbase
** a4 PNRequest (pnr_NetDestPort is ready !)
** a3 sendbuf+4 (first long already contains dp_Action..)
** a2 DosPacket

** Answerroutine will be called with:
** a6 Execbase
** a3 data received from server (without dp_Action -> Res1,Res2,Data..)
** a2 DosPacket to be returned
** d2 dp_Action

ACT_LOCATE_OBJECT
		GETsFL	dp_Arg1(a2),a0
		move.l	a0,(a3)+
		move.l	dp_Arg3(a2),(a3)+
		clr.w	(a3)+	;muß beim Server LongWord-aligned
		move.l	dp_Arg2(a2),a0	;ankommen..
		bsr	copybfname
		lea	.ret(pc),a0
		bra	sendpnpacket
.ret
		moveq	#0,d0
		move.l	(a3)+,d2
		beq	.return

		move.l	4(a3),d1
		bsr	FindCorrVolume
		move.l	d0,d3
		move.l	a1,a4
		move.l	#fl_SIZEOF,d0	;neuen FileLock erstellen
		bsr	AllocVec
		move.l	d0,a0
		move.l	dp_Arg3(a2),fl_Access(a0)
		move.l	ourport(pc),fl_Task(a0)
		move.l	d3,fl_Volume(a0)
		move.l	d2,fl_Key(a0)	;WICHTIG! um den FL auf dem
				;Server wiederzufinden..
		lsr.l	#2,d0
		move.l	a4,a1
		bsr	RememberLock

		; BPTR auf Lock in d0 (first Result..)
.return		move.l	(a3),d1
		move.l	a2,a0
		bra	ReturnPacket

ACT_RENAME_DISK
		clr.w	(a3)+
		move.l	dp_Arg1(a2),a0
		bsr	copybstr
		lea	.ret(pc),a0
		bra	sendpnpacket
.ret
		move.l	(a3),d0
		beq.s	.return
		move.l	curvolume(pc),d2
		beq.s	.return
		move.l	4.w,a6
		LIBCALL	Forbid
		move.l	d2,a4
		move.l	dol_Name(a4),a1
		add.l	a1,a1
		add.l	a1,a1
		bsr	FreeVec
		move.l	dp_Arg1(a2),a5
		add.l	a5,a5
		add.l	a5,a5
		moveq	#0,d0
		move.b	(a5),d0
		addq.l	#2,d0
		bsr	AllocVec
		move.l	d0,a1
		moveq	#0,d1
		move.b	(a5),d1

		tst.w	plusflag
		beq.s	.copyname
		addq.w	#1,d1
		move.b	d0,(a1)+
		move.b	plusflag(pc),(a1)+
		subq.w	#2,d1
		addq.w	#1,a5

.copyname	move.b	(a5)+,(a1)+
		dbra	d1,.copyname
		clr.b	(a1)+
		lsr.l	#2,d0
		move.l	d0,dol_Name(a4)
		LIBCALL	Permit
.return		bra	normalret

ACT_FREE_LOCK
		move.l	dp_Arg1(a2),d1	;ZERO-Lock ? -> gleich zurück
		beq.s	.return
		bsr	ForgetLock
		tst.l	d1
		beq.s	.error
		move.l	fl_Key(a5),(a3)+
		bsr	sendpnpacket	;auch auf dem Server löschen !
		clr.l	fl_Task(a5)
		move.l	a5,a1
		bsr	FreeVec
.return		moveq	#DOSTRUE,d0
		bra.s	.ret2
.error		moveq	#DOSFALSE,d0
		move.l	#ERROR_INVALID_LOCK,d1
.ret2		move.l	a2,a0
		clr.l	actpacket
		bra	ReturnPacket

ACT_DELETE_OBJECT
		GETsFL	dp_Arg1(a2),a0
		move.l	a0,(a3)+
		clr.w	(a3)+
		move.l	dp_Arg2(a2),a0
		bsr	copybfname
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_RENAME_OBJECT
		GETsFL	dp_Arg1(a2),a0
		move.l	a0,(a3)+
		GETsFL	dp_Arg3(a2),a0
		move.l	a0,(a3)+
		clr.w	(a3)+
		lea	256(a3),a5
		move.l	dp_Arg2(a2),a0
		bsr	copybfname
		move.l	a5,a3
		move.l	dp_Arg4(a2),a0
		bsr	copybfname
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_MORE_CACHE
		move.l	dp_Arg1(a2),(a3)+
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_COPY_DIR
		GETsFL	dp_Arg1(a2),a0
		move.l	a0,(a3)+
		lea	copydir_ret(pc),a0
		bra	sendpnpacket
copydir_ret
		moveq	#0,d0
		move.l	(a3)+,d2
		beq.s	.return

		move.l	4(a3),d1
		bsr	FindCorrVolume
		move.l	d0,d3
		move.l	a1,a4
		moveq	#fl_SIZEOF,d0	;neuen FileLock erstellen
		bsr	AllocVec
		move.l	d0,a0
		move.l	8(a3),fl_Access(a0)
		move.l	ourport(pc),fl_Task(a0)
		move.l	d3,fl_Volume(a0)
		move.l	d2,fl_Key(a0)	;WICHTIG! um den FL auf dem
				;Server wiederzufinden..
		lsr.l	#2,d0
		move.l	a4,a1
		bsr	RememberLock

.return		move.l	(a3),d1
		move.l	a2,a0
		bra	ReturnPacket

ACT_SET_PROTECT
		GETsFL	dp_Arg2(a2),a0
		move.l	a0,(a3)+
		move.l	dp_Arg4(a2),(a3)+
		clr.w	(a3)+
		move.l	dp_Arg3(a2),a0
		bsr	copybfname
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_CREATE_DIR
		GETsFL	dp_Arg1(a2),a0
		move.l	a0,(a3)+
		clr.w	(a3)+
		move.l	dp_Arg2(a2),a0
		bsr	copybfname
		lea	copydir_ret(pc),a0
		bra	sendpnpacket

ACT_EXAMINE_OBJECT	;EXAMINEs neu 29-04-95
		GETsFL	dp_Arg1(a2),a0
act_ex_entry	move.l	a0,(a3)+
		GETBPTR	dp_Arg2(a2),a0
		move.l	(a0)+,(a3)+	;fib_DiskKey übertragen
		addq.l	#4,a0
		move.w	#32/4-1,d0
.copyname	move.l	(a0)+,(a3)+
		dbra	d0,.copyname	;fib_fileName übertragen
		lea	act_ex_ret(pc),a0
		bra	sendpnpacket

act_ex_ret	movem.l	(a3)+,d0/d1
		GETBPTR	dp_Arg2(a2),a0
		move.w	#fib_SIZEOF/4-1,d2
.copyfib	move.l	(a3)+,(a0)+
		dbra	d2,.copyfib
		move.l	a2,a0
		bra	ReturnPacket

ACT_EXAMINE_FH
		move.l	dp_Arg1(a2),a0
		bra.s	act_ex_entry

ACT_FLUSH
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_SET_COMMENT
		GETsFL	dp_Arg2(a2),a0
		move.l	a0,(a3)+
		clr.w	(a3)+	;LW-Alignment..
		move.l	dp_Arg4(a2),a0
		add.l	a0,a0
		add.l	a0,a0
		moveq	#80/4-1,d2
.1		move.l	(a0)+,(a3)+
		dbra	d2,.1
		move.l	dp_Arg3(a2),a0
		bsr	copybfname
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_PARENT
		bra	ACT_COPY_DIR

ACT_SET_DATE
		GETsFL	dp_Arg2(a2),a0
		move.l	a0,(a3)+
		move.l	dp_Arg4(a2),a0
		move.l	(a0)+,(a3)+
		move.l	(a0)+,(a3)+
		move.l	(a0)+,(a3)+
		clr.w	(a3)+
		move.l	dp_Arg3(a2),a0
		bsr	copybfname
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_SAME_LOCK
		GETBPTR	dp_Arg1(a2),a0
		GETBPTR	dp_Arg2(a2),a1
		cmp.l	a0,a1
		beq.s	.equal
		move.l	fl_Volume(a0),d0
		cmp.l	fl_Volume(a1),d0
		bne.s	.not_equal
		GETsFL	dp_Arg1(a2),a0
		move.l	a0,(a3)+
		GETsFL	dp_Arg2(a2),a0
		move.l	a0,(a3)+
		lea	normalret(pc),a0
		bra	sendpnpacket
.not_equal	moveq	#DOSFALSE,d0
		moveq	#0,d1
.return		move.l	a2,a0
		clr.l	actpacket
		bra	ReturnPacket
.equal		moveq	#DOSTRUE,d0
		bra.s	.return

ACT_READ	** new routine 17-04-95
		move.l	dp_Arg1(a2),(a3)+
		move.l	dp_Arg3(a2),(a3)+
		lea	.ret(pc),a0
		bra	sendpnpacket
.ret
		move.l	dp_Arg2(a2),a4	* Destination Buffer
		move.l	dp_Arg3(a2),d7	* Bytes to be read
		moveq	#0,d6		* Bytes already read

		move.l	actpronetmsg(pc),d5 *current pronetmsg
		bra.s	.jump_in

.loop		move.l	pronetmsgport(pc),a0	*Get the Message
		LIBCALL	WaitPort
		move.l	pronetmsgport(pc),a0
		LIBCALL	GetMsg
		move.l	d0,d5
.jump_in	move.l	d5,a3
		lea	MN_SIZE+6(a3),a3
		move.l	(a3),d4
		bmi.s	.ERROR			*Error?

		lea	8(a3),a0		*Copy
		move.l	a4,a1
		move.l	d4,d0
		LIBCALL	CopyMem

		move.l	d5,a1
		LIBCALL	ReplyMsg
		clr.l	actpronetmsg

		tst.l	d4
		beq.s	.EOF

		add.l	d4,d6
		add.l	d4,a4
		sub.l	d4,d7
		bgt.s	.loop

.EOF		move.l	a2,a0
		move.l	d6,d0
		moveq	#0,d1
		bra	ReturnPacket

.ERROR		movem.l	(a3),d2/d3
		move.l	d5,a1
		LIBCALL	ReplyMsg
		clr.l	actpronetmsg
		move.l	d2,d0
		move.l	d3,d1
		move.l	a2,a0
		bra	ReturnPacket


ACT_WRITE
	IFNE	DEBUG
	lea	dwritet(pc),a0
	bsr	dtype
	move.l	dp_Arg1(a2),d0
	bsr	dtypehex
	move.l	dp_Arg2(a2),d0
	bsr	dtypehex
	move.l	dp_Arg3(a2),d0
	bsr	dtypehex
	bsr	dcr
	ENDC
		move.l	dp_Arg1(a2),(a3)+
		move.l	dp_Arg3(a2),(a3)+
		lea	.ret(pc),a0
		bra	sendpnpacket
.ret
		movem.l	(a3)+,d0/d1
		cmp.l	#-1,d0
		beq.s	.return

		move.l	dp_Arg3(a2),d4	;Number of Bytes to be transferred
		move.l	4.w,a6
		move.l	pronetio(pc),a3
		move.l	dp_Arg2(a2),a4

.sendloop	move.l	a4,pnr_Data1(a3)	;Split chunk in parts
		move.l	#MAXPACKETSIZE,d0	;and send them..
		cmp.l	d0,d4
		bcc.s	.0
		move.l	d4,d0
.0		move.l	d0,pnr_Length1(a3)
		add.l	d0,a4
		sub.l	d0,d4
		move.l	a3,a1
		LIBCALL	DoIO
	IFNE	DEBUG
	move.l	pnr_Length1(a3),d0
	bsr	dtypehex
	bsr	dcr
	ENDC
		tst.l	d4
		bgt.s	.sendloop

		move.l	pronetmsgport(pc),a0
		LIBCALL	WaitPort
		move.l	pronetmsgport(pc),a0
		LIBCALL	GetMsg
		move.l	d0,d6
		move.l	d0,a0
		move.l	MN_SIZE+2+4(a0),d2
		move.l	MN_SIZE+2+8(a0),d3
		move.l	d6,a1
		LIBCALL	ReplyMsg
		move.l	d2,d0
		move.l	d3,d1

.return		move.l	a2,a0
		bra	ReturnPacket

ACT_FINDxxx
		GETsFL	dp_Arg2(a2),a0
		move.l	a0,(a3)+
		clr.w	(a3)+
		move.l	dp_Arg3(a2),a0
		bsr	copybfname
		lea	.ret(pc),a0
		bra	sendpnpacket
.ret
		movem.l	(a3)+,d0/d1
		tst.w	d0
		beq.s	.return
		GETBPTR	dp_Arg1(a2),a0
		move.l	(a3),fh_Arg1(a0)
		move.l	#DOSTRUE,fh_Interactive(a0)
		move.l	ourport(pc),fh_Type(a0)
.return		move.l	a2,a0
		bra	ReturnPacket

ACT_END
		move.l	dp_Arg1(a2),(a3)+
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_SEEK
		move.l	dp_Arg1(a2),(a3)+
		move.l	dp_Arg2(a2),(a3)+
		move.l	dp_Arg3(a2),(a3)+
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_FORMAT
		move.l	dp_Arg2(a2),(a3)+
		clr.w	(a3)+
		move.l	dp_Arg1(a2),a0
		bsr	copybstr
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_MAKE_LINK
		move.l	dp_Arg4(a2),d2
		move.l	d2,(a3)+
		GETsFL	dp_Arg1(a2),a0
		move.l	a0,(a3)+
		cmp.l	#LINK_HARD,d2
		beq.s	.hardlink
.softlink	lea	256+2(a3),a5
		move.l	dp_Arg3(a2),a0
		bsr	copycstr
		move.l	a5,a3
		bra.s	.doit
.hardlink	GETsFL	dp_Arg3(a2),a0
		move.l	a0,(a3)+
		clr.w	(a3)+
.doit		move.l	dp_Arg2(a2),a0
		bsr	copybfname
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_SET_FILE_SIZE
		move.l	dp_Arg1(a2),(a3)+
		move.l	dp_Arg2(a2),(a3)+
		move.l	dp_Arg3(a2),(a3)+
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_WRITE_PROTECT
		move.l	dp_Arg1(a2),(a3)+
		move.l	dp_Arg2(a2),(a3)+
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_READ_LINK
		GETsFL	dp_Arg1(a2),a0
		move.l	a0,(a3)+
		move.l	dp_Arg4(a2),(a3)+
		move.l	dp_Arg2(a2),a0
		bsr	copycstr
		lea	.ret(pc),a0
		bra	sendpnpacket
.ret
		movem.l	(a3)+,d0/d1
		move.l	dp_Arg4(a2),d2
		subq.w	#1,d2
		move.l	dp_Arg3(a2),a1
.copy		move.b	(a3)+,(a1)+
		dbra	d2,.copy
		move.l	a2,a0
		bra	ReturnPacket

ACT_FH_FROM_LOCK
		GETsFL	dp_Arg2(a2),a0
		move.l	a0,(a3)+
		lea	.ret(pc),a0
		bra	sendpnpacket
.ret
		movem.l	(a3),d0/d1
		tst.w	d0
		beq.s	.return
		GETBPTR	dp_Arg1(a2),a0
		move.l	8(a3),fh_Arg1(a0)
		move.l	#DOSTRUE,fh_Interactive(a0)
		move.l	ourport(pc),fh_Type(a0)
		GETBPTR	dp_Arg2(a2),a0
		clr.l	fl_Task(a0)
		move.l	a0,d1
		bsr	ForgetLock
		move.l	a5,a1
		bsr	FreeVec
		movem.l	(a3),d0/d1
.return		move.l	a2,a0
		bra	ReturnPacket

ACT_CHANGE_MODE
		move.l	dp_Arg1(a2),d0
		move.l	d0,(a3)+
		cmp.l	#CHANGE_LOCK,d0
		beq.s	.change_lock
.change_fh	GETBPTR	dp_Arg2(a2),a0
		move.l	fh_Arg1(a0),(a3)+
		bra.s	.cont
.change_lock	GETsFL	dp_Arg2(a2),a0
		move.l	a0,(a3)+
.cont		move.l	dp_Arg3(a2),(a3)+
		lea	.ret(pc),a0
		bra	sendpnpacket
.ret
		move.l	dp_Arg1(a2),d2
		cmp.l	#CHANGE_LOCK,d2
		bne.s	.0
		GETBPTR	dp_Arg2(a2),a0
		move.l	8(a3),fl_Access(a0)
.0		bra	normalret


ACT_COPY_DIR_FH
		bra	ACT_PARENT_FH

ACT_PARENT_FH
		move.l	dp_Arg1(a2),(a3)+
		lea	copydir_ret(pc),a0
		bra	sendpnpacket

ACT_LOCK_RECORD
		move.l	dp_Arg1(a2),(a3)+
		move.l	dp_Arg2(a2),(a3)+
		move.l	dp_Arg3(a2),(a3)+
		move.l	dp_Arg4(a2),(a3)+
		move.l	dp_Arg5(a2),(a3)+
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_FREE_RECORD
		move.l	dp_Arg1(a2),(a3)+
		move.l	dp_Arg2(a2),(a3)+
		move.l	dp_Arg3(a2),(a3)+
		lea	normalret(pc),a0
		bra	sendpnpacket
		bra	ACT_NIL

ACT_ADD_NOTIFY
		bra	ACT_NIL

ACT_REMOVE_NOTIFY
		bra	ACT_NIL

ACT_SERIALIZE_DISK
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_INHIBIT
		move.l	dp_Arg1(a2),(a3)+
		lea	normalret(pc),a0
		bra	sendpnpacket

ACT_INFO
		GETsFL	dp_Arg1(a2),a0
		move.l	a0,(a3)+
		lea	.ret(pc),a0
		bra	sendpnpacket
.ret
		movem.l	(a3)+,d0/d1
		tst.w	d0
		beq.s	.return
		GETBPTR	dp_Arg2(a2),a0
		move.l	a0,a4
		moveq	#8,d0
.copyl		move.l	(a3)+,(a0)+
		dbra	d0,.copyl
		move.l	id_VolumeNode(a4),d1
		bsr	FindCorrVolume
		move.l	d0,id_VolumeNode(a4)
		moveq	#DOSTRUE,d0
.return		move.l	a2,a0
		bra	ReturnPacket

ACT_DISK_INFO
		lea	.ret(pc),a0
		bra	sendpnpacket
.ret
		movem.l	(a3)+,d0/d1
		tst.w	d0
		beq.s	.return
		GETBPTR	dp_Arg1(a2),a0
		move.l	a0,a4
		moveq	#8,d0
.copyl		move.l	(a3)+,(a0)+
		dbra	d0,.copyl
		move.l	id_VolumeNode(a4),d1
		bsr	FindCorrVolume
		move.l	d0,id_VolumeNode(a4)
		moveq	#DOSTRUE,d0
.return		move.l	a2,a0
		bra	ReturnPacket

ACT_CURRENT_VOLUME
		move.l	dp_Arg1(a2),(a3)+
		beq.s	.shortcut
		lea	.ret(pc),a0
		bra	sendpnpacket
.shortcut	move.l	curvolume(pc),d0
		lsr.l	#2,d0
		moveq	#7,d1
		move.l	a2,a0
		clr.l	actpacket
		bra	ReturnPacket
.ret
		move.l	(a3),d1
		bsr	FindCorrVolume
		move.l	a2,a0
		moveq	#7,d1
		bra	ReturnPacket

; -- zu einem BPTR auf die VolNode auf dem Server die passende VolNode
; -- auf dem Handler finden. Wenn sie nicht gefunden wird, wird 0 returnt
FindCorrVolume	; d1 BPTR->ServerVolNode or NULL
		; RETURNS d0 BPTR->VolNode or NULL
		;         a1 APTR->Corresponding PHVN
		movem.l	a2/a3,-(sp)
		moveq	#0,d0
		tst.l	d1
		beq.s	.end
		lea	PHVNList(pc),a3
		move.l	LH_HEAD(a3),a2
		addq.w	#4,a3
.nextphvn	cmp.l	a2,a3
		beq.s	.end
		move.l	a2,a1
		move.l	LN_SUCC(a2),a2
		cmp.l	phvn_srvdoslist(a1),d1
		bne.s	.nextphvn
		move.l	phvn_doslist(a1),d0
		lsr.l	#2,d0
.end		movem.l	(sp)+,a2/a3
		rts

; -- Lock in der Lockliste merken.
RememberLock	; d0 BPTR->Lock
		; a0 APTR->Lock
		; a1 APTR->corresponding PHVN
		; destroys a3 and a1
		move.l	a3,-(sp)
		move.l	a1,a3			;Lock in die interne
		lea	phvn_locklist(a3),a3	;Lockliste eintragen
		move.l	(a3),a1
		move.l	a1,fl_Link(a0)
		move.l	d0,(a3)
		move.l	(sp)+,a3
		rts

; -- Lock aus der Lockliste streichen - und zwar alle PHVN's durchsehen !!
; -- außerdem VolumeNode entfernen, falls LockListe leer und Volume entfernt!
ForgetLock	; d1 BPTR->Lock
		; RETURNS d1 Lock removed from List or 0 if not in List
		;         a5 APTR->Lock or undefined if not in List
		; DESTROYS a0,a1,d0,d1,a5
		movem.l	a2/a3/a4/d2/d3,-(sp)
		lea	PHVNList(pc),a3
		move.l	LH_HEAD(a3),a2
		addq.w	#4,a3
.nextphvn	cmp.l	a2,a3
		beq.s	.error
		move.l	a2,a4
		move.l	LN_SUCC(a2),a2
						;Ist dieser Lock in unserer
		lea	phvn_locklist(a4),a0	;Liste ??
.searchlock	move.l	a0,a1
		move.l	(a0),a0
		move.l	a0,d0
		beq.s	.nextphvn  ;nicht in dieser Liste -> nächste Volume
		cmp.l	d1,d0
		beq.s	.lockok
		add.l	a0,a0
		add.l	a0,a0
		bra.s	.searchlock
.lockok		move.l	d1,a5
		add.l	a5,a5
		add.l	a5,a5
		move.l	(a5),(a1)	;Lock aus der Liste löschen

		tst.l	phvn_locklist(a4)	;VolumeNode löschen ???
		bne.s	.ende
		move.l	phvn_doslist(a4),a0
		tst.l	dol_Task(a0)
		bne.s	.ende
		move.l	d1,-(sp)		;jo.
		move.l	a4,a2
		bsr	RemoveVolNode
		move.l	(sp)+,d1
		bra.s	.ende

.error		moveq	#0,d1
.ende		movem.l	(sp)+,a2/a3/a4/d2/d3
		rts

; -- Normale Abschlußsequenz - nur Results werden zurückgeliefert.
normalret	movem.l	(a3)+,d0/d1
		move.l	a2,a0
		bra	ReturnPacket

; -- Kopiert BSTR nach (a3)+, dabei wird Filename bis ':' abgeschnitten
; -- (Wenn kein ':' existiert, wird alles so belassen..)
copybfname	; a0 BPTR to BSTR
		; a3 *space
		move.l	a0,d0
		beq.s	.empty
		move.l	a0,a1
		add.l	a0,a0
		add.l	a0,a0
		moveq	#0,d0
		move.b	(a0)+,d0
		subq.w	#1,d0
		bmi.s	.empty
.0		move.b	(a0)+,d1
		cmp.b	#":",d1
		dbeq	d0,.0
		bne.s	.normalcopy
		move.b	d0,(a3)+
		beq.s	.ende
.1		move.b	(a0)+,(a3)+
		dbra	d0,.1
.ende		rts
.normalcopy	move.l	a1,a0
		bra.s	copybstr
.empty		clr.b	(a3)+
		rts

; -- Kopiert BSTR nach (a3)+
copybstr	; a0 BPTR to BSTR
		; a3 *space
		move.l	a0,d0
		beq.s	.empty
		add.l	a0,a0
		add.l	a0,a0
		moveq	#0,d1
		move.b	(a0),d1
.copybstr	move.b	(a0)+,(a3)+
		dbra	d1,.copybstr
		rts
.empty		clr.b	(a3)+
		rts

; -- Kopiert C-String nach (a3)+
copycstr	; a0 APTR to C-String
		; a3 *space
		move.b	(a0)+,(a3)+
		bne.s	copycstr
		rts

; -- Sendet Packet zum Server
sendpnpacket	; a3 end of sendbuf
		; a4 *PNRequest
		; a0 Routine, die angesprungen wird, wenn Antwort vom
		;    Server kommt.
		move.l	4.w,a6
		move.l	a0,actanswerroutine
		lea	sendbuf,a0
		sub.l	a0,a3
		move.l	a4,a1
		move.l	a0,pnr_Data1(a1)
		move.l	a3,pnr_Length1(a1)
		LIBJMP	DoIO

; === Packets, die ohne den Server erledigt werden:

ACT_NIL
	IFNE	DEBUG
	lea	dunknownt(pc),a0
	bsr	dtype
	ENDC
		move.l	a2,a0
		move.l	#DOSFALSE,d0
		move.l	#ERROR_ACTION_NOT_KNOWN,d1
		clr.l	actpacket
		bra	ReturnPacket

ACT_IS_FILESYSTEM
		move.l	a2,a0
		moveq	#DOSTRUE,d0
		moveq	#0,d1
		clr.l	actpacket
		bra	ReturnPacket

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; === Wird angesprungen, wenn DiskChange-Message vom Server kommt:
; a3 *data nach dp_Action
ACT_DISKINS
		;erstmal prüfen, ob wir diese Disk schon irgendwo
		;gespeichert haben in der PHVNList..
		move.l	(a3)+,d7
		move.l	d7,d1
		bsr	FindCorrVolume
		tst.l	d0
		beq.s	.newvol

		;wenn ja, dann keine neue VolumeNode, sondern nur
		;dol_Task und dol_LockList, curvolume und curphvn
		;wiederherstellen !!!
		move.l	a1,curphvn
		move.l	phvn_doslist(a1),a2
		move.l	a2,curvolume
		move.l	4.w,a6
		LIBCALL	Forbid
		clr.l	dol_LockList(a2)
		move.l	ourport(pc),dol_Task(a2)
		LIBCALL	Permit
		move.b	#IECLASS_DISKINSERTED,d2
		bra	SendInputEvent

.newvol		moveq	#44,d0		;neue VolumeNode erstellen..
		bsr	AllocVec
		move.l	d0,curvolume
		move.l	d0,a2
		lea	dol_VolumeDate(a2),a0
		move.l	(a3)+,(a0)+
		move.l	(a3)+,(a0)+
		move.l	(a3)+,(a0)
		moveq	#0,d0
		move.b	(a3),d0
		addq.l	#3,d0
		bsr	AllocVec
		move.l	d0,a0
		lsr.l	#2,d0
		move.l	d0,dol_Name(a2)
		moveq	#0,d0
		move.b	(a3),d0

		tst.w	plusflag
		beq.s	.copyname
		addq.w	#1,d0
		move.b	d0,(a0)+
		move.b	plusflag(pc),(a0)+
		subq.w	#2,d0
		addq.w	#1,a3

.copyname	move.b	(a3)+,(a0)+
		dbra	d0,.copyname
		move.l	#DLT_VOLUME,dol_Type(a2)
		move.l	ourport(pc),dol_Task(a2)
		move.l	#ID_DOS_DISK,dl_DiskType(a2)
		move.l	4.w,a6
		LIBCALL	Forbid
		move.l	dosbase(pc),a1
		move.l	dl_Root(a1),a1
		move.l	rn_Info(a1),a1
		add.l	a1,a1
		add.l	a1,a1
		addq.w	#di_DevInfo,a1
		move.l	(a1),(a2)
		move.l	a2,d0
		lsr.l	#2,d0
		move.l	d0,(a1)
		LIBCALL	Permit
		moveq	#phvn_SIZEOF,d0
		bsr	AllocVec
		move.l	d0,curphvn
		move.l	d0,a2
		move.l	curvolume(pc),phvn_doslist(a2)
		move.l	d7,phvn_srvdoslist(a2)
		move.l	a2,a1
		lea	PHVNList(pc),a0
		LIBCALL	AddTail
		move.b	#IECLASS_DISKINSERTED,d2
		bra	SendInputEvent

ACT_DISKREM
		move.l	4.w,a6
		move.l	curvolume(pc),d2
		tst.l	d2
		beq.s	.ende	;falscher Alarm..
		move.l	curphvn(pc),a2
		; [d2] *doslist [a2] *phvn
		; Wenn LockList = 0, dann rausschmeißen + VolNode löschen
		; Wenn nicht, dann dol_Task löschen und dol_LockList setzen.
		; Auf jeden Fall curvolume löschen.
		clr.l	curvolume
		clr.l	curphvn
		move.l	phvn_locklist(a2),d3
		beq.s	.clearall
		LIBCALL	Forbid
		move.l	d2,a3
		clr.l	dol_Task(a3)
		move.l	d3,dol_LockList(a3)
		LIBCALL	Permit
		bra.s	.return

.clearall	bsr	RemoveVolNode

.return		move.b	#IECLASS_DISKREMOVED,d2
		bra	SendInputEvent
.ende		rts

; -- VolumeNode und PHVN entfernen.
RemoveVolNode	; a2 *corresponding PHVN
		movem.l	a4/a6/d2/d3,-(sp)
		move.l	4.w,a6
		move.l	phvn_doslist(a2),d2
		LIBCALL	Forbid
		move.l	dosbase(pc),a1
		move.l	dl_Root(a1),a1
		move.l	rn_Info(a1),a1
		add.l	a1,a1
		add.l	a1,a1
		addq.w	#di_DevInfo,a1
.removeloop	move.l	a1,a4		;letztes Element merken
		move.l	(a1),a1
		add.l	a1,a1
		add.l	a1,a1
		cmp.l	d2,a1
		bne.s	.removeloop
		;gefunden
		move.l	a1,d3
		move.l	(a1),(a4)	;Node rausnehmen.
		LIBCALL	Permit
		move.l	d3,a1
		bsr	FreeVec
		move.l	a2,a1		;PHVolumeNode rausnehmen.
		LIBCALL	Remove
		move.l	a2,a1
		bsr	FreeVec
		movem.l	(sp)+,a4/a6/d2/d3
		rts

; -- Compare two null-terminated strings. Case-insensitive
CompareStrings	; a0 *String1
		; a1 *String2
		; RETURNS d0 = 0 --> Strings equal
		move.l	d2,-(sp)
		moveq	#-1,d0
.loop		move.b	(a0)+,d1
		move.b	(a1)+,d2
		bclr	#5,d1
		bclr	#5,d2
		cmp.b	d1,d2
		bne.s	.ende
		tst.b	d1
		bne.s	.loop
		moveq	#0,d0
.ende		move.l	(sp)+,d2
		rts

		include	"A:ProNET/source/dospackets.s"
		include	"A:ProNET/source/devio.s"

; -- Sends an Input Event.
SendInputEvent	; d2.b IECLASS
		movem.l	d2-d7/a2-a6,-(sp)
		moveq	#IOTV_SIZE,d0
		bsr	GetIORequest
		move.l	d0,a4	;TimerRequest
		moveq	#IOSTD_SIZE,d0
		bsr	GetIORequest
		move.l	d0,a5	;InputRequest
		move.l	4.w,a6
		lea	timername(pc),a0
		moveq	#0,d0
		moveq	#0,d1
		move.l	a4,a1
		LIBCALL	OpenDevice
		lea	inputname(pc),a0
		moveq	#0,d0
		moveq	#0,d1
		move.l	a5,a1
		LIBCALL	OpenDevice

		move.l	a4,a1
		move.w	#TR_GETSYSTIME,IO_COMMAND(a1)
		LIBCALL	DoIO

		lea	localbuf,a3
		clr.l	ie_NextEvent(a3)
		move.b	d2,ie_Class(a3)
		clr.b	ie_SubClass(a3)
		clr.w	ie_Code(a3)
		move.w	#IEQUALIFIER_MULTIBROADCAST,ie_Qualifier(a3)
		clr.l	ie_EventAddress(a3)
		move.l	IOTV_TIME(a4),ie_TimeStamp(a3)
		move.l	IOTV_TIME+4(a4),ie_TimeStamp+4(a3)
		move.w	#IND_WRITEEVENT,IO_COMMAND(a5)
		move.w	#ie_SIZEOF,IO_LENGTH(a5)
		move.l	a3,IO_DATA(a5)
		move.l	a5,a1
		LIBCALL	DoIO		;InputEvent abschicken..

		move.l	a5,a1
		LIBCALL	CloseDevice
		move.l	a4,a1
		LIBCALL	CloseDevice
		move.l	a5,a0
		bsr	FreeIORequest
		move.l	a4,a0
		bsr	FreeIORequest
		movem.l	(sp)+,d2-d7/a2-a6
		rts

; -- AllocVec stub - requirements fixed to PUBLIC|CLEAR
AllocVec	; d0 bytesize
		move.l	a6,-(sp)
		move.l	4.w,a6
		move.l	#MEMF_PUBLIC!MEMF_CLEAR,d1
		LIBCALL	AllocVec
		move.l	(sp)+,a6
		rts

; -- FreeVec stub
FreeVec		; a1 memory-block
		move.l	a6,-(sp)
		move.l	4.w,a6
		LIBCALL	FreeVec
		move.l	(sp)+,a6
		rts

	IFNE	DEBUG
	include "A:OSdebugging.s"
dunknownt	dc.b	"Unknown Dos Packet Type !",0
dwritet		dc.b	"ACTION_WRITE: ",0
	even
debok	dc.w	0
	ENDC

;----------------------------------------------------------------------------

dosname		dc.b	"dos.library",0
inputname	dc.b	"input.device",0
timername	dc.b	"timer.device",0
		even

curvolume	dc.l	0	;aktuelle Volumenode..
curphvn		dc.l	0	;aktuelle PHVolumeNode..

plusflag	dc.w	0
dosbase		dc.l	0
pronetio	dc.l	0
pronetmsgport	dc.l	0
actpronetmsg	dc.l	0
ourprocess	dc.l	0
ourport		dc.l	0
devnode		dc.l	0
startuppacket	dc.l	0
actpacket	dc.l	0
actanswerroutine dc.l	0

; -- ExecList; speichert alle Volumes und dazugehörige FileLocks.
PHVNList	dc.l	*+4,0,PHVNList



		section	b,bss

sendbuf		ds.b	$400
localbuf	ds.b	128	;kann benutzen wer will, nur temporäre Daten!
