;Cancel! V1.0  Copyright 1987 Bryce Nesbitt.  Free, revokable license
;granted to use this code in any way provided all copyright notices remain
;intact and it is NOT used by or for or by any entity that has been commonly
;referred to as Robert W. Skyles, Skyles Electric Works, Jim Drew, Regie
;Warren or by any organization founded by, controlled, employing or
;profiting any such entity.  FISH use ok.  Send bugs (or bug reports :-),
;threats, suggestions or requests for permanent license to:
;       1712 Marin Ave.
;       Berkeley, Ca 94707-2902
;       bryce@cogsci.berkeley.EDU -or- ucbvax!cogsci!bryce
;
;USAGE
;       CLI - Cancel!   	;Disable *ALL* system requesters & alerts.
;           - Cancel! off       ;Enable requesters.
;       WB  - Brings up requester
;
;       Sometimes there is no human available to push "Cancel" on a
;       requester that might be generated.  Imagine a "disk full"
;       requester while running a unattended system!
;       This "Auto Human" sits dormant until it gets it's big chance
;       to press "Cancel" for you.
;
;BUGS
;       Cancel! refuses to install itself multiple times.  However, since
;       there is no such thing as a SetFunction() lock, OTHER tasks can
;       muddle things considerably.
;
;       This program features intellegent multitasking arbitration.  You,
;       the intellegent human, must not try to run two copies of this
;       program simultaneously.
;
;       "Software error, Task held" requesters may cause headaches.
;
;       Alerts really should be handled also.
;
;ADDITIONS
;       It would be useful in some cases to have a log of the text of
;       all the aborted requesters.  Perhaps allocate a `N' byte
;       file in a recoverable ram disk and record the latest `N' bytes
;       of requester messages.
;
;IMPLEMENTATION
;       Uses SetFunction to lobotomize AutoRequest() and BuildSysRequest(),
;
;NOTES
;       Should come to 812 bytes when assembled with Metacomco and Blink'ed
;       with the NODEBUG option set.
********************
	NOLIST
	INCLUDE 'exec/types.i'
;       INCLUDE 'exec/memory.i'
	BITDEF  MEM,PUBLIC,0
	BITDEF  MEM,CHIP,1
	BITDEF  MEM,FAST,2
	BITDEF  MEM,CLEAR,16
	IFND    EXEC_ABLES_I
	INCLUDE 'exec/ables.i'
	ENDC
	IFND    EXEC_DOSEXTENS_I
	INCLUDE 'libraries/dosextens.i'
	ENDC
;       INCLUDE 'intuition/intuitionbase.i'
ib_ActiveWindow EQU $34
ib_ActiveScreen EQU $38
ib_FirstScreen  EQU $3C
	LIST
 STRUCTURE      SetFunctionLock,0
		BYTE   sfl_Start	;Must be set to $60. BRA.S in 68000
		BYTE   sfl_Branch       ;Branch offset, value will vary
		WORD   sfl_Magic_Cookie ;Must be $4AFC
		APTR   sfl_OldVector    ;Function this lock displaced
		APTR   sfl_Semaphore    ;Used to arbitrate this structure
		WORD   sfl_MSize	;Size to use with FreeMem()
		WORD   sfl_Flags	;See bit definitions...
		BYTE   sfl_IDString     ;The actual string, *NOT* a pointer
		;No SIZEOF because it keeps going...
jsrlib  MACRO
	xref _LVO\1
	jsr  _LVO\1(a6)
	ENDM
jmplib  MACRO
	xref _LVO\1
	jmp  _LVO\1(a6)
	ENDM
blink   MACRO
	bchg.b #1,$bfe001
	ENDM
********************
		xref    _LVOAutoRequest
		xref    _LVOBuildSysRequest

IBase   	equr    d6
DOSBase 	equr    d5
linelen 	equr    d4

		CODE
startup:	move.l  d0,linelen
		move.l  4,a6
		move.l  ThisTask(a6),a5
		moveq   #0,d0   	;Set zero for later
		move.l  pr_CLI(a5),d1   ;Pointer to CLI only structure
		bne.s   fromCLI 	;If not zero, then flag zero...
		lea.l   pr_MsgPort(a5),a0
		jsrlib  WaitPort	;Wait for Workbench's Message
fromCLI 	move.l  d0,-(a7)	;Save message/flag for later...
******************* [A6=ExecBase][a5=this task]

		moveq   #20,d7
		lea.l   DOSName(pc),a1
		jsrlib  OldOpenLibrary  ;V1.0 Compatible :-)
		move.l  d0,DOSBase
		beq     e_dos
		lea.l   IntuiName(pc),a1
		jsrlib  OldOpenLibrary  ;V1.0 Compatible :-)
		move.l  d0,IBase
		beq     e_intui

		tst.l   (a7)    	;Test CLI flag on stack
		beq.s   fromtheCLI
;---Do Workbench user interface---
		FORBID
		bsr     CHECKIF
		move.l  d0,-(a7)	;save flag
		jsrlib  Permit
		bsr     REMOVEIT	;We wanna put up a requester
		moveq   #0,d0
		moveq   #0,d1
		move.l  #320,d2
		moveq   #68,d3
		suba.l  a0,a0
		suba.l  a2,a2
		lea.l   ITextOk(pc),a3
		tst.l   (a7)
		bne.s   sayremove
		lea.l   ITextId(pc),a1
		bra.s   displayit
sayremove       lea.l   ITextRemoved(pc),a1
displayit       move.l  IBase,a6
		jsrlib  AutoRequest
		move.l  4,a6
		move.l  (a7)+,d0
		bne.s   RemoveIt
		beq.s   DoItDude

;---Do CLI UI---
fromtheCLI:     subq.l  #1,linelen
		beq.s   DoItDude

;---Do the actual work---
RemoveIt:       bsr     REMOVEIT
		tst.l   (a7)    	;check CLI flag
		bne.s   ExitOk
		lea.l   Sremoved(pc),a0
		moveq   #Eremoved-Sremoved,d3
		bsr     WRITEIT
		bra.s   ExitOk

DoItDude:       bsr     ADDIT
		beq.s   e_nomem
		tst.l   (a7)    	;check CLI flag
		bne.s   ExitOk
		lea.l   Sinstall(pc),a0
		moveq   #Einstall-Sinstall,d3
		bsr.s   WRITEIT
		bne.s   ExitOk

;--no memory, no fun--
e_nomem 	move.l  ThisTask(a6),a1
		moveq   #ERROR_NO_FREE_STORE,d0
		move.l  d0,pr_Result2(a1)
ExitError       moveq   #20,d7      ;return code of "fail"
		bra.s   Exit

ExitOk  	moveq   #0,d7
Exit    	move.l  IBase,a1
		jsrlib  CloseLibrary
e_intui 	move.l  DOSBase,a1
		jsrlib  CloseLibrary
e_dos
******************************* (a7)+=message d7=return code a6=exec
ExitToDOS:      move.l  (a7)+,d2
		beq.s   NotWB       ;If saved pointer is zero, exit to CLI...
		FORBID
		move.l  d2,a1       ;Return message to WB.  Use FORBID so
		jsrlib  ReplyMsg    ;we won't be UnLoadSeg()'ed too early.
NotWB   	move.l  d7,d0       ;Set "failat" code
		rts
*******************

;SYNOPSIS
;   error=WRITEIT(string,length),anything
;   z   	  a0     d3      a6
;
;GLOBALS
;   DOSBase

WRITEIT:	move.l  a6,-(a7)
		move.l  DOSBase,a6
		move.l  a0,d2
		jsrlib  Output
		move.l  d0,d1
		move.l  d1,-(a7)
		jsrlib  Write
		lea.l   linefeed(pc),a0
		move.l  (a7)+,d1
		move.l  a0,d2
		moveq   #1,d3
		jsrlib  Write
		move.l  (a7)+,a6
		cmp.l   d0,d3
		rts

;SYNOPSIS
;   result=ADDIT(),exec
;   z
;
;FUNCTION
;   Add the functions, if they are not already added
;
;NOTES
;    Since the handler code is SHARED by any process that cares to call
;    the requester function, it must be copied to PUBLIC memory.  It must
;    also be re-entrant.

ADDIT   	bsr     CHECKIF
		beq     InPlace     ;Already there...
		move.l  #HandlersEnd-HandlersStart,d0
		move.l  #MEMF_PUBLIC+MEMF_CLEAR,d1
		jsrlib  AllocMem
		tst.l   d0      	;grumble.
		bne.s   ok_mem
		rts

;---Copy to new location---
ok_mem  	;[d0=memblock]
		move.l  a2,-(a7)
		move.l  d0,a1
		lea.l   HandlersStart(pc),a0
		moveq   #((HandlersEnd-HandlersStart)/4)-1,d1
copylp  	move.l  (a0)+,(a1)+     ;Copy handler to PUBLIC Memory
		dbra    d1,copylp

;---Try to add the newly prepared request ---
		;[d0=memblock]
		move.l  d0,a2

;--Add the new ones--
		lea.l   NewAutoRequest-HS(a2),a0 ;our new function
		move.l  a0,d0
		move.w  #_LVOAutoRequest,a0     ;offset
		move.l  IBase,a1		;library
		jsrlib  SetFunction
		move.l  d0,NewAutoRequest+sfl_OldVector-HS(a2)

		lea.l   NewBuildSysRequest-HS(a2),a0 ;our new function
		move.l  a0,d0
		move.w  #_LVOBuildSysRequest,a0 ;offset
		move.l  IBase,a1		;library
		jsrlib  SetFunction
		move.l  d0,NewBuildSysRequest+sfl_OldVector-HS(a2)

		move.l  (a7)+,a2
InPlace 	moveq   #-1,d0
		rts


;SYNOPSIS
;   result=REMOVEIT(),exec
;   z   	      a6
;
;FUNCTION
;   Remove the handlers if they are not already gone

REMOVEIT	FORBID
		move.w  #_LVOBuildSysRequest,a0 ;offset
		move.l  IBase,a1		;library
		bsr     ISIT
		bne.s   notthere1
		jsrlib  SetFunction

notthere1       move.w  #_LVOAutoRequest,a0     ;offset
		move.l  IBase,a1		;library
		bsr     ISIT
		bne.s   notthere2
		move.l  d1,-(a7)
		jsrlib  SetFunction

;There is a finite chance that some code is still running in my
;SetFunction'ed code.  Oh, well.

		jsrlib  Permit
		move.l  (a7)+,a1
		move.l  #HandlersEnd-HandlersStart,d0
		jmplib  FreeMem
nothingtofree   rts
notthere2       jmplib  Permit

;SYNOPSIS
;   result,offset,library,OldVector,Vector=ISIT(offset,library),exec
;   z      a0     a1      d0        d1  	a0     a1      a6
;
;FUNCTION
;   Check if we are already installed.  CALL WHILE FORBID'ed
;
;RESULT
;   Z=1 if found
;   d0=OldVector, if found.  zero otherwise.
;   d1=Vector, if found.  Garbage otherwise.

CHECKIF 	move.w  #_LVOAutoRequest,a0     ;offset
		move.l  IBase,a1		;library
ISIT    	movem.l a0/a1/d2,-(a7)
		move.l  2(a1,a0.w),a0
		move.l  a0,d1   	;Get Vector
		addq.l  #4,a0   	;Skip branch & cookie
		move.l  (a0)+,d0	;Get OldVector
		addq.l  #8,a0   	;Skip Semaphore, etc.
		lea.l   HandlersStart+16(pc),a1
		moveq   #compareend-comparestart-1,d2
namechk 	cmpm.b  (a0)+,(a1)+
		dbne    d2,namechk
		beq.s   foundit
		moveq   #0,d0
		moveq   #-1,d1
foundit 	movem.l (a7)+,a0/a1/d2
		rts

**************************** text area *************************************

ITextId:	dc.b 0,1,1,0         ;pens, drawmode and filler
		dc.w 20,6            ;XY
		dc.l 0  	     ;NULL for default font
		dc.l Sid	     ;pointer to text
		dc.l ITextId2        ;next IntuitText structure
ITextId2	dc.b 0,1,1,0
		dc.w 20,17
		dc.l 0
		dc.l Sinstall
		dc.l 0

ITextRemoved:   dc.b 0,1,1,0
		dc.w 20,6
		dc.l 0
		dc.l Sid
		dc.l ITextId3
ITextId3	dc.b 0,1,1,0
		dc.w 20,17
		dc.l 0
		dc.l Sremoved
		dc.l 0

ITextOk:	dc.b 0,1,1,0
		dc.w 6,3
		dc.l 0
		dc.l SOk
		dc.l 0

Sid     	dc.b 'Cancel!, ',$a9,'1987 Bryce Nesbitt',0
	       ;dc.b 'Cancel!, +1987 Bryce Nesbitt',0
Sinstall	dc.b 'Requesters will be Canceled!',0
Einstall
Sremoved	dc.b 'Requesters are now enabled.',0
Eremoved
SOk     	dc.b 'Ok',0
IntuiName       dc.b 'intuition.library',0
DOSName 	dc.b 'dos.library',0
linefeed	dc.b 10

****************************** handlers ************************************

;These are the parts that gets installed to do the actual 'dirty work'.
;The header provides a format for the name of this module, the pointer
;to the old function, and information on how to remove it.

		cnop    0,4
HandlersStart:
HS:
NewAutoRequest: bra.s   TheCode1
		dc.w    $4afc
		dc.l    0
		dc.l    0
		dc.w    0
		dc.w    1
comparestart
		dc.b    'Cancel!',0
		cnop    0,2
compareend
NewBuildSysRequest: bra.s   TheCode1
		dc.w    $4afc
		dc.l    0
		dc.l    0
		dc.w    0
		dc.w    1
		dc.b    'Cancel!',0

		cnop   0,2
TheCode1:       moveq   #0,d0       ;FALSE
		rts

		cnop    0,4
HandlersEnd:
********************
		END

----
    Craig Norborg
    comp.sources.amiga moderator


