/*-- AutoRev header do NOT edit!
*
*   Program         :   MenuLock.c
*   Copyright       :   © Copyright 1991 Jaba Development
*   Author          :   Jan van den Baard
*   Creation Date   :   11-Sep-91
*   Current version :   1.01
*   Translator      :   DICE v2.6
*
*   REVISION HISTORY
*
*   Date          Version         Comment
*   ---------     -------         ------------------------------------------
*   20-Sep-91     1.01            Now uses the Dos ReadArgs for the Shell.
*   11-Sep-91     1.00            MenuStrip lock utility.
*   11-Sep-91     1.00            Based on code by Stefan Sticht. (thanks!)
*
*-- REV_END --*/

/*
 * --- Include a whole buch of headers...
 */
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <libraries/commodities.h>
#include <workbench/startup.h>
#ifndef abs
#define abs
#endif
#include <stdlib.h>
#include <string.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/commodities_protos.h>
#include <clib/utility_protos.h>

/*
 * --- Macro's to (de)activate the commodity
 */
#define CxOn(b)       ActivateCxObj(b,TRUE);
#define CxOff(b)      ActivateCxObj(b,FALSE);

/*
 * --- Calculate a bit-mask from a signal bit.
 */
#define BitMask(b)    ( 1L << ((ULONG)b) )

#ifndef NOT
#define NOT !
#endif

/*
 * --- Parameters and defaults.
 */
UBYTE *COM_PRIORITY =   "PRIORITY";         /* PRIORITY=<pri>     */
UBYTE *COM_LOCK     =   "LOCK";             /* LOCK=<hotkey>      */
UBYTE *COM_UNLOCK   =   "UNLOCK";           /* UNLOCK=<hotkey>    */
UBYTE *COM_QUIT     =   "QUIT";             /* QUIT=<hotkey>      */

WORD   COM_DEF_PRI  =   0;                  /* default priority   */
UBYTE *COM_DEF_LCK  =   "rcommand down";    /* default lock keys  */
UBYTE *COM_DEF_ULC  =   "rcommand up";      /* default unlock keys*/
UBYTE *COM_DEF_QUI  =   "lshift control q"; /* default quit       */

#define ML_QUIT         1L                  /* event ID           */

/*
 * --- Commodity information
 */
#define ML_VERSION      "v1.01"
#define ML_NAME         "MenuLock"
#define ML_DESCR        "Locks the menu-strip."
#define ML_COPY         "© 1991 Jaba Development"
#define ML_TITLE        ML_NAME " " ML_VERSION ", " ML_COPY


/*
 * --- Minimum library version required
 */
#define MIN_LIB         36L

/*
 * --- Non autoinit libraries required
 */
struct CxBase           *CxBase     = NULL;
struct IconBase         *IconBase   = NULL;

extern struct WBStartup *_WBMsg;

struct MsgPort          *ML_port    = NULL;    /* Commodity MsgPort */
char                   **ML_tool    = NULL;    /* ToolType array    */
struct RDArgs           *ML_args    = NULL;    /* Shell args        */
struct RDArgs            ML_iargs   = { 0,0,0,0,0,0,0,RDAF_NOPROMPT };

ULONG                    ML_arg[4];

UBYTE                   *ML_temp    = "PRIORITY/n,LOCK/k,UNLOCK/k,QUIT/k";

struct InputEvent       *ML_event;             /* RawMouse event    */
struct InputEvent       *ML_uevent;            /* RawMouse event    */

CxObj                   *ML_brok    = NULL;    /* The broker        */

/*
 * --- The broker data
 */
struct NewBroker         ML_nbrok = {
    NB_VERSION,ML_NAME,ML_TITLE,ML_DESCR,
    NBU_NOTIFY|NBU_UNIQUE,0,NULL,0
};

ULONG                    ML_smask   = NULL;    /* MsgPort signal mask */
UBYTE                   *ML_lstr;              /* lock HotKey string  */
UBYTE                   *ML_ustr;              /* unlock HotKey string*/
UBYTE                   *ML_qstr;              /* quit HotKey string  */

/*
 * --- Identification string for the Version CLI-command
 */
UBYTE                   *ML_ver = "\0$VER: MenuLock © 1991 Jaba Development -- v1.01";

/*
 * --- Program function proto-types
 */
CxObj  *HotTranslate( UBYTE *, struct InputEvent * );
void    CloseML( long );
void    OpenML( void );
void    CheckML( void );

/*
 * --- This might be usefull in your commodities.
 * ---
 * --- This routine set's up a filter using CxFilter and then
 * --- it set's up a translator using CxTranslate. This setup
 * --- allows to directly translate a certan input event into
 * --- another. It's something like "HotKey()" without a Sender
 * --- object and a programmable Translate object.
 * ---
 * --- object = HotTranslate( description, ievent )
 * ---
 * --- CxObj             *object;
 * --- UBYTE             *description;
 * --- struct InputEvent *ievent;
 */
CxObj *HotTranslate( UBYTE *desc, struct InputEvent *ie )
{
    CxObj   *filt, *trans;

    if ( NOT( filt  = CxFilter( desc )))
        return( NULL );
    if ( NOT( trans = CxTranslate( ie ))) {
        DeleteCxObj( filt );
        return( NULL );
    }

    AttachCxObj( filt, trans );

    return( filt );
}

/*
 * --- Open up and allocate the resources required
 */
void OpenML( void )
{
    CxObj   *lock, *unlock, *quit;
    WORD     pri;

   /*
    * --- Open up non autoinit libraries
    */
    if ( NOT( IconBase = (struct IconBase *)OpenLibrary( "icon.library", MIN_LIB )))
        CloseML( 20L );
    if ( NOT( CxBase = (struct CxBase *)OpenLibrary( "commodities.library", MIN_LIB )))
        CloseML( 20L );

    if ( _WBMsg ) {
       /*
        * --- Initialize the ToolTypes array
        */
        ML_tool = (char **)ArgArrayInit( 0L, (char **)_WBMsg );

       /*
        * Get new or default priority.
        */
        pri = ArgInt( ML_tool, COM_PRIORITY, COM_DEF_PRI );

       /*
        * --- Get new or default HotKey strings
        */
        ML_lstr = ArgString( ML_tool, COM_LOCK, COM_DEF_LCK );
        ML_ustr = ArgString( ML_tool, COM_UNLOCK, COM_DEF_ULC );
        ML_qstr = ArgString( ML_tool, COM_QUIT, COM_DEF_QUI );
    } else {
        if ( ML_arg[0] )    pri = (WORD)ML_arg[0];
        else                pri = COM_DEF_PRI;
        if ( ML_arg[1] )    ML_lstr = (UBYTE *)ML_arg[1];
        else                ML_lstr = COM_DEF_LCK;
        if ( ML_arg[2] )    ML_ustr = (UBYTE *)ML_arg[2];
        else                ML_ustr = COM_DEF_ULC;
        if ( ML_arg[3] )    ML_qstr = (UBYTE *)ML_arg[3];
        else                ML_qstr = COM_DEF_QUI;
    }

   /*
    * --- Get a rawmouse input event
    */
    if ( NOT( ML_event = InvertString( "<rawmouse rbutton>", NULL )))
        CloseML( 25L );
    if ( NOT( ML_uevent = InvertString( "<rawmouse rbutton>", NULL )))
        CloseML( 25L );

    ML_event->ie_Code  = IECODE_RBUTTON;
    ML_uevent->ie_Code = IECODE_RBUTTON | IECODE_UP_PREFIX;

   /*
    * --- commodities.library V36.180 it's InvertString seem's to contain
    * --- a bug which inverts the class "rawmouse" as "event".
    */
    ML_event->ie_Class = ML_uevent->ie_Class = IECLASS_RAWMOUSE;

   /*
    * --- Set broker priority
    */
    ML_nbrok.nb_Pri = pri;

   /*
    * --- Create a MsgPort
    */
    if ( NOT( ML_port = CreateMsgPort()))
        CloseML( 21L );

   /*
    * --- Get the port signalmask and set the port in the broker
    */
    ML_smask         = BitMask(ML_port->mp_SigBit );
    ML_nbrok.nb_Port = ML_port;

   /*
    * --- Setup the broker
    */
    if ( NOT( ML_brok = CxBroker( &ML_nbrok, NULL )))
        CloseML( 22L );

   /*
    * --- Setup the HotKey filters and attach them to the broker
    */
    if ( NOT( lock = HotTranslate( ML_lstr, ML_event )))
        CloseML( 26L );
    AttachCxObj( ML_brok, lock );

    if ( NOT( unlock = HotTranslate( ML_ustr, ML_uevent )))
        CloseML( 26L );
    AttachCxObj( ML_brok, unlock );

   /*
    * --- Set up the quit HotKey filter
    */
    if (NOT ( quit = HotKey( ML_qstr, ML_port, ML_QUIT )))
        CloseML( 23L );
    AttachCxObj( ML_brok, quit );

   /*
    * --- Check for occured errors
    */
    if ( CxObjError( lock ) || CxObjError( unlock ) || CxObjError( quit ))
        CloseML( 24L );

   /*
    * --- If Workbench clear ArgArray
    */
    if ( _WBMsg )
        ArgArrayDone();

   /*
    * --- Activate the broker
    */
    CxOn( ML_brok );
}

/*
 * --- Close up and de-allocate the used resources
 */
void CloseML( long code )
{
    struct Message  *tmp; /* to clear the MsgPort */

   /*
    * --- Delete the broker
    */
    if ( ML_brok )          DeleteCxObjAll( ML_brok );

   /*
    * --- Clear and delete the MsgPort
    */
    if ( ML_port ) {
        while (( tmp = GetMsg( ML_port ))) ReplyMsg( tmp );
        DeleteMsgPort( ML_port );
    }

   /*
    * --- Free the rawmouse input events
    */
    if ( ML_event )
        FreeIEvents( ML_event );
    if ( ML_uevent )
        FreeIEvents( ML_uevent );

   /*
    * --- Free the Shell arguments
    */
    if ( ML_args )
        FreeArgs( ML_args );

   /*
    * --- Close the non autoinit libraries
    */
    if ( CxBase )           CloseLibrary( CxBase );
    if ( IconBase )         CloseLibrary( IconBase );

   /*
    * --- bye bye
    */
    exit( code );
}

/*
 * --- Process the messages coming through the MsgPort
 */
void CheckML( void )
{
    struct Message      *msg;
    struct IntuiMessage *imsg;
    ULONG                sig, type, id;
    BOOL                 running = TRUE;

    do {
        sig = Wait( SIGBREAKF_CTRL_C | ML_smask );

        if (( sig & SIGBREAKF_CTRL_C ) == SIGBREAKF_CTRL_C ) {
           /*
            * --- Break signal received. Shutting down...
            */
            running = FALSE;
        } else if (( sig & ML_smask) == ML_smask ) {
           /*
            * --- Got a message on the MsgPort. Examine it
            */
            while (( msg = (struct Message *)GetMsg( ML_port ))) {

               /*
                * Get the message type and id
                */
                id   = CxMsgID((CxMsg *)msg);
                type = CxMsgType((CxMsg *)msg);

                ReplyMsg(msg);

                switch( type ) {

                    case    CXM_IEVENT:
                        switch( id ) {

                            case    ML_QUIT:
                                running = FALSE;
                                break;
                        }
                        break;

                    case    CXM_COMMAND:
                       /*
                        * --- They want us to do something...
                        */
                        switch( id ) {

                            case    CXCMD_UNIQUE:
                               /*
                                * --- They tried to run a commodity
                                * --- using our name.
                                */
                            case    CXCMD_KILL:
                               /*
                                * --- They want us dead....
                                */
                                running = FALSE;
                                break;

                            case    CXCMD_DISABLE:
                               /*
                                * --- They want us disabled...
                                */
                                CxOff( ML_brok );
                                break;

                            case    CXCMD_ENABLE:
                               /*
                                * --- They want us enabled...
                                */
                                CxOn( ML_brok );
                                break;
                        }
                        break;
                }
            }
        }
    } while( running == TRUE );

   /*
    * --- The end, Fin, Einde, Finito....
    */
    CxOff( ML_brok );
}

/*
 * --- Simple main which set's things in motion
 */
void _main( void )
{
    if ( NOT _WBMsg ) {
        setmem( (void *)&ML_arg[0], 16L, 0L );
        if (( ML_args = ReadArgs( ML_temp, &ML_arg[0], &ML_iargs ))) {
            OpenML();
            CheckML();
            CloseML( 0L );
        }
        CloseML(27L);
    } else {
        if ( _WBMsg->sm_ArgList->wa_Lock )
            CurrentDir( _WBMsg->sm_ArgList->wa_Lock );

        OpenML();
        CheckML();
        CloseML( 0L );
    }
    atoi(""); /*** otherwise we get a link error and we don't want that ***/
    _waitwbmsg();
}
