
; FAME EasyDoorStartup.i
;
; Asm door examples by BLOODROCK/tRSi © 1996 Oliver Lange

	IFND	EXEC_EXEC_LIB_I
	INCLUDE	"Exec/Exec_lib.i"
	ENDC

	IFND	DOS_DOS_LIB_I
	INCLUDE	"Dos/Dos_lib.i"
	ENDC

	IFND	EXEC_MEMORY_I
	INCLUDE	"Exec/Memory.i"
	ENDC

	IFND	DOS_DOSEXTENS_I
	INCLUDE	"Dos/DosExtens.i"
	ENDC

	IFND	FAME_FAME_I
	INCLUDE "FAME/FAME.i"
	ENDC

MinKickVer	EQU	37		; The minimum OS version number needed

send	Macro
		IFGT    128-\1			; This routine checks the
		moveq   #\1,d0			; ReturnCode itself.
		bsr     SendDoorCommand		; If an error occured, the
		ELSE				; door shuts down with an
		move.l  #\1,d0			; error text as "ByeMessage".
		bsr     SendDoorCommand
		ENDC
	EndM

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

EASY_Start:
	move.l	4.w,a6
	cmp.w	#MinKickVer,LIB_VERSION(a6)	; Must be at least V37
	bhs.s	EASY_KickVersionOK		; (OS 2.04) -which SysOp
EASY_Fatal:					; hasn't got it ?
	moveq	#RETURN_FAIL,d0
	rts

EASY_KickVersionOK:			   ; This part gets some memory
	movem.l	d0/a0,-(sp)		   ; for our data segment. This
	move.l	EASY_MyDataSize(pc),d0	   ; is making the door code
	move.l	#MEMF_CLEAR!MEMF_PUBLIC,d1 ; reentrant. There is no fixed
	jsr	_LVOAllocVec(a6)	   ; data area, so the door can be
	tst.l	d0			   ; load resident, saving memory
	bne.s	EASY_StartupMemOK	   ; when running the door more
	movem.l	(sp)+,d0/a0		   ; than once at a time (it also
	bra.s	EASY_Fatal		   ; reduces door loading time).
					   ; Beginners, remember: using
					   ; AllocVec() instead of AllocMem()
					   ; eliminates possible error sources!
EASY_StartupMemOK:
	move.l	d0,a5
	move.l	a6,AbsExecBase(a5)	; Faster then..
	move.b	#RETURN_FAIL,ReturnCode(a5)
	sub.l	a1,a1
	jsr	_LVOFindTask(a6)	; Get our Process structure
	move.l	d0,OwnTask(a5)
	move.l	d0,a3
	tst.l	pr_CLI(a3)		; Started from WorkBench ?
	bne.s	EASY_StartOK

	movem.l	(sp)+,d0/a0		; No longer needed..
	lea	pr_MsgPort(a3),a0
	jsr	_LVOWaitPort(a6)	; Wait for the WorkBench message
	lea	pr_MsgPort(a3),a0
	jsr	_LVOGetMsg(a6)
	move.l	d0,d7
	jsr	_LVOForbid(a6)
	move.l	d7,a1                   ; Reply the WorkBench message
	jsr	_LVOReplyMsg(a6)	; and exit (door must be started
	bra.w	EASY_Finish		; from FAME).

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

EASY_StartOK:
	lea	DosName(pc),a1
	moveq	#MinKickVer,d0		; V37
	jsr	_LVOOpenLibrary(a6)
	move.l	d0,DOSBase(a5)
	beq.w	EASY_Finish

	lea	FAMEName(pc),a1
	moveq	#FAMELibVersion,d0
	jsr	_LVOOpenLibrary(a6)
	move.l	d0,FAMEBase(a5)
	beq.w	EASY_Finish

	move.l	d0,a6
	moveq	#FOBJ_FAMEDoorMsg,d0
	jsr	_LVOFAMEAllocObject(a6)		; allocate our DoorMessage
	move.l	d0,DoorMessage(a5)
	beq.w	EASY_Finish

;-----------------------------------------------------------------------------
; Program init complete
;-----------------------------------------------------------------------------

; Getting the node number from the argument line..

	movem.l	(sp)+,d0/a0
	move.l	DOSBase(a5),a6
	move.l	a0,a3
	subq.b	#2,d0			; At least 1 char passed as argument ?
	bpl.s	EASY_ArgsLenOK
EASY_BadArgs:
	jsr	_LVOOutput(a6)
	move.l	d0,d1
	lea	EASY_NoHandStart(pc),a0
	move.l	a0,d2
	moveq	#EASY_NoHandStartEnd-EASY_NoHandStart,d3
	jsr	_LVOWrite(a6)
	bra.w	EASY_Finish

EASY_ArgsLenOK:
	clr.b	1(a0,d0.w)
	moveq	#0,d1
EASY_ParseArgs:
	moveq	#0,d0
	move.b	(a0)+,d0
	beq.s	EASY_ArgsOK
	sub.b	#48,d0
	bmi.s	EASY_BadArgs	; only digits, please..
	cmp.b	#9,d0
	bhi.s	EASY_BadArgs	;  ""    ""      ""
	add.b	d0,d0		;-\
	move.b	d0,d2		;  \
	add.b	d0,d0		;   \
	add.b	d0,d0		;    \
	add.b	d2,d0		;_____\ same as "mulu #10,d0", but faster :^)
	add.l	d0,d1
	bra.s	EASY_ParseArgs
EASY_ArgsOK:
	move.l	d1,DoorPortNum(a5)
	lea	FAMEDPNameTxt(pc),a0	; Name of the FAMEDoorPort..
	lea	FAMEDoorPortName(a5),a1
EASY_CopyPortName:
	move.b	(a0)+,(a1)+		; ..gets copied to one new string..
	bne.s	EASY_CopyPortName
	subq.l	#1,a1
EASY_CopyPortNumber:
	move.b	(a3)+,(a1)+		; ..together with the door port number.
	bne.s	EASY_CopyPortNumber
	move.l	AbsExecBase(a5),a6
	jsr	_LVOCreateMsgPort(a6)
	move.l	d0,DoorReplyPort(a5)
	beq.w	EASY_Finish		; No error messages possible,
					; because the door communication
					; wasn't established yet.
EASY_DoorPortOK:
	move.l	d0,a0
	moveq	#0,d0
	move.b	MP_SIGBIT(a0),d0	; Get the port's signal bit
	moveq	#1,d1
	lsl.l	d0,d1
	move.l	d1,DoorSigBits(a5)

	move.l	DoorMessage(a5),a0	; Initialize our message structure
	move.b	#NT_MESSAGE,LN_TYPE(a0)	; Normally, exec does this line for you
	move.w	#Fdom_SIZEOF,MN_LENGTH(a0)
	move.l	DoorReplyPort(a5),MN_REPLYPORT(a0)

	jsr	_LVOForbid(a6)
	lea	FAMEDoorPortName(a5),a1
	jsr	_LVOFindPort(a6)	; Search the DoorMsgPort for our node
	move.l	d0,DoorControlPort(a5)
	jsr	_LVOPermit(a6)
	tst.l	DoorControlPort(a5)
	beq.w	EASY_Finish		; Error messages still not possible..

EASY_DCPortFound:

; Now sending the MUST command MC_DoorStart to the node. Refer to the "send"
; macro for further details. The MC_DoorStart command MUST be called as the
; first of all commands.
; General:
; On negative ReturnCodes from the Node we MUST shut down the door program
; IMMEDIATELY, only sending the MUST command MC_ShutDown.
; If the ReturnCode is greater than NULL, it's up to you about what to do.
; In the case below, only FCmdRC_CommandFailed (1) should happen (started from
; CLI passing a number of a door port which really exists -> door access denied.

	moveq	#MC_DoorStart,d0
	bsr	Do_SendCommand
	tst.l	d0			; This time we check it yourself,
	bne.s	EASY_Finish		; because if it fails, MC_ShutDown
					; isn't needed anyway.
;-----------------------------------------------------------------------------

	move.l	sp,InitialStack(a5)	; save the current stack pointer

	bsr.w	EASY_DoorCode		; Finally: start our door code.

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

EASY_Finish:
	move.l	InitialStack(a5),sp	; restore the initial stack pointer

	move.l	AbsExecBase(a5),a6
	move.l	DoorReplyPort(a5),d0
	beq.s	EASY_Quit4
	move.l	d0,a0
	jsr	_LVODeleteMsgPort(a6)
EASY_Quit4:
	move.l	FAMEBase(a5),d0
	beq.s	EASY_Quit2
	move.l	d0,a6
	move.l	DoorMessage(a5),d0
	beq.s	EASY_Quit3
	move.l	d0,a1
	jsr	_LVOFAMEFreeObject(a6)

EASY_Quit3:
	move.l	a6,a1
	move.l	AbsExecBase(a5),a6
	jsr	_LVOCloseLibrary(a6)

EASY_Quit2:
	move.l	DOSBase(a5),d0
	beq.s	EASY_Quit1
	move.l	d0,a1
	jsr	_LVOCloseLibrary(a6)
EASY_Quit1:
	move.b	ReturnCode(a5),d7
	move.l	a5,a1			; No NULL check needed here.
	jsr	_LVOFreeVec(a6)
EASY_Quit:
	moveq	#0,d0
	add.b	d7,d0
	rts				; The end.

;-----------------------------------------------------------------------------
; Several often used routines
;-----------------------------------------------------------------------------

; Next: the code belonging to the send macro function. The error code
; gets checked here and on error codes <>0, ByeMessage is set to a decent
; error text. Then the door shuts down.

SendDoorCommand:
	bsr.w	Do_SendCommand
	tst.l	d0
	bne.s	SDC_Abort
	rts
SDC_Abort:
	bmi.s	SDC_NegativeError

	subq.l	#1,d0
	bne.s	SDC_Abort2
	lea	EASY_CommandExecutionError(pc),a0
	bra.s	SDC_SetError
SDC_Abort2:
	subq.l	#1,d0
	bne.s	SDC_Abort3
SDC_UnknownCmd:
	lea	EASY_CommandNotImplemented(pc),a0
	bra.s	SDC_SetError
SDC_Abort3:
	subq.l	#1,d0
	bne.s	SDC_Abort4
	lea	EASY_CommandDenied(pc),a0
	bra.s	SDC_SetError
SDC_Abort4:
	bra.s	SDC_UnknownCmd		; same error text.

SDC_NegativeError:
	addq.l	#1,d0
	bne.s	SDC_Abort5
	lea	EASY_DoorAbortRequested(pc),a0
	bra.s	SDC_SetError
SDC_Abort5:
	addq.l	#1,d0
	bne.s	SDC_Abort6
	lea	EASY_CarrierLost(pc),a0
	bra.s	SDC_SetError
SDC_Abort6:
	lea	EASY_FatalError(pc),a0

SDC_SetError:
	move.l	a0,ByeMessage(a5)
	bra	Abort

Do_SendCommand:
	move.l	DoorMessage(a5),a0
	move.l	d0,Fdom_Command(a0)	; Set door command

	move.l	a6,-(sp)
	Move.l	AbsExecBase(a5),a6

	jsr	_LVOForbid(a6)
	move.l	DoorControlPort(a5),a0
	move.l	DoorMessage(a5),a1
	jsr	_LVOPutMsg(a6)		; Send the command to our node
	jsr	_LVOPermit(a6)
	moveq	#0,d7
DSC_Wait:
	move.l	DoorSigBits(a5),d0
	jsr	_LVOWait(a6)		; Wait for a message



	; insert additional Signal reactions here



	move.l	DoorReplyPort(a5),a0
	jsr	_LVOGetMsg(a6)		; Get the message back
	tst.l	d0
	beq.s	DSC_Wait		; There was no message.

	move.l	DoorMessage(a5),a0
	move.l	Fdom_ReturnCode(a0),d0	; Put the ReturnCode to d0 for
DSC_Quit:				; easier result checking.
	move.l	(sp)+,a6		; a0 contains the DoorMessage
	rts				; structure on exit.

;-----------------------------------------------------------------------------
; The following routines can be used to copy a String FROM or TO
; the Fdom_IOString field. But these routines became a bit obsolete,
; because the newer AR_SendString commands allow sending strings from any
; APTR. If you find it useful, use it. The routines are called like this:
;
; 	Move.l	AdressOfText,a0		; Pass the APTR to SetIOString
; 	bsr	SetIOString
;-----------------------------------------------------------------------------

GetIOString:
	move.l	DoorMessage(a5),a1
	lea	Fdom_IOString(a1),a1
	move.w	#202-1,d0		; Make sure that we don't copy more
GIO_Loop:				; than 202 bytes..
	move.b	(a1)+,(a0)+
	beq.s	GIO_End
	dbra	d0,GIO_Loop
GIO_End:
	rts

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

SetIOString:
	move.l	DoorMessage(a5),a1
	lea	Fdom_IOString(a1),a1
	move.w	#202-1,d0		; Make sure that we don't copy more
SIO_Loop:				; than 202 bytes..
	move.b	(a0)+,(a1)+
	beq.s	SIO_End
	dbra	d0,SIO_Loop
SIO_End:
	rts

;-----------------------------------------------------------------------------
; Data area
;-----------------------------------------------------------------------------

EASY_MyDataSize:	dc.l	MyData_SIZEOF ; Size of our program data area

EASY_CarrierLost:
	dc.b	13,10,"CARRIER LOST ! Door shut down."
	dc.b	13,10,13,10,0

EASY_CommandDenied:
	dc.b	13,10,"Sorry, but this door can't execute all of it's door"
	dc.b	13,10,"commands, because your SysOp has denied access to"
	dc.b	13,10,"some of 'em."
	dc.b	13,10,"Try making him/her read the door documentations.. :^)"
	dc.b	13,10,13,10,0

EASY_CommandExecutionError:
	dc.b	13,10,"Sorry, but FAME reported an error during the execution"
	dc.b	13,10,"of a door command. Tell your SysOp about the problem."
	dc.b	13,10,13,10,0

EASY_CommandNotImplemented:
	dc.b	13,10,"Sorry, but this door wants to use a door command"
	dc.b	13,10,"which isn't supported by the current FAME version."
	dc.b	13,10,"Seems that you should install a newer version of"
	dc.b	13,10,"FAME BBS to run this door.."
	dc.b	13,10,13,10,0

EASY_DoorAbortRequested
	dc.b	13,10,"Sorry, but your sysop has just shut down the door."
	dc.b	13,10,13,10,0

EASY_FatalError:
	dc.b	13,10,"FATAL ERROR ! A door command couldn't be executed,"
	dc.b	13,10,"because an unknown fatal error occured."
	dc.b	13,10,"Please tell your SysOp about."
	dc.b	13,10,13,10,0

EASY_NoHandStart:	dc.b	10,"Sorry, this is a FAME BBS door program.",10
			dc.b	"It can only be started from FAME itself.",10,10
EASY_NoHandStartEnd:

DosName:	dc.b	"dos.library",0

FAMEDPNameTxt:	dc.b	"FAMEDoorPort",0	; That's it's name. :^)

FAMEName	dc.b	"FAME.library",0

		cnop	0,4

EASY_DoorCode:

