; /*
CatComp Reboot.cd CFILE Reboot_strings.h NOARRAY NOBLOCK NOCODE
CatComp Reboot.cd CTFILE Reboot_blank.ct
CatComp Reboot.cd Reboot_deutsch.ct CATALOG Catalogs/Deutsch/Reboot.catalog

; DICE
dcc Reboot.c -r -mS -mi -proto -v -oReboot

; SAS
; SC RESOPT PARM=REGISTERS UCHAR CONSTLIB STREQ ANSI NOSTKCHK NOICONS OPT OPTPEEP Reboot.c
; Slink LIB:c.o Reboot.o TO Reboot LIB LIB:sc.lib SC SD

Quit
*/

/*
**
**  $VER: Reboot.c 1.3 (6.1.96)
**  Reboot 1.0
**
**  main file
**
**  (C) Copyright 1994-96 by Roland 'Gizzy' Mainz
**          All Rights Reserved
**
*/

/* We did not want any names before V36 */
#define INTUI_V36_NAMES_ONLY 1

/* amiga includes */
#include <exec/types.h>
#include <utility/utility.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <workbench/startup.h>
#include <workbench/icon.h>
#include <libraries/locale.h>

/* amiga prototypes */
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/icon_protos.h>
#include <clib/locale_protos.h>

/* DICE inline stuff */
#ifdef __DICE_INLINE
#define UtilityBase_DECLARED 1
#define IntuitionBase_DECLARED 1
#define IconBase_DECLARED 1
#define LocaleBase_DECLARED 1

#include <proto/exec_protos.h>
#include <proto/utility_protos.h>
#include <proto/dos_protos.h>
#include <proto/intuition_protos.h>
#include <proto/icon_protos.h>
#include <proto/locale_protos.h>
#endif /* __DICE_INLINE */

/* ansi includes */
#include <string.h>

/* version string */
#include "Reboot_rev.h"

/* locale */
#define CATCOMP_NUMBERS
#define CATCOMP_STRINGS
#include "Reboot_strings.h"

/* misc defines */
#define NAME "Reboot"

/* prototypes */
                void                  chkabort( void );

#ifdef _DCC
                long                  wbmain( struct WBStartup * );
#endif /* _DCC */

                long                  main( long, STRPTR * );
        static  void                  DefaultSettings( void );
        static  void                  FreeInitProjectResult( void );
        static  void                  ReadENVPrefs( void );

        static  void                  ClearRDA( void );
        static  void                  ScanRDA( void );
        static  void                  ScanToolTypes( STRPTR * );

        static  void                  RunTool( void );
        static  BOOL                  OpenLibStuff( void );
        static  void                  CloseLibStuff( void );
        static  BOOL                  CreateBasicResources( void );
        static  void                  DeleteBasicResources( void );
                void                  AttemptOpenLibrary( struct Library **, STRPTR, STRPTR, ULONG );
        static  void                  RunTool( void );
        static  void                  MyReboot( void );
                STRPTR                SafeGetCatalogStr( struct Catalog *, LONG, STRPTR );



/* version_string */
STRPTR versionstring = VERSTAG;

long main_retval,
     main_retval2;

static struct RDArgs  *startuprda;

/* shared libraries */
struct Library *UtilityBase,
               *IntuitionBase,
               *IconBase,
               *LocaleBase;

/* locale support */
struct Catalog *ct;

/* templates for ReadArgs() */
#define STARTUP_TEMPLATE "REBOOTDELAY/K/N,QUIET=NOREQ/S,OFF/S"
#define ENV_TEMPLATE     STARTUP_TEMPLATE


static
struct
{
    long *rebootdelay;
    long *noreq;
    long *off;
} result;

static
struct
{
    ULONG rebootdelay;
    BOOL  noreq;
    BOOL  off;
} project;


/* disable CTRL_C break support (DICE CTRL_C abort function) */
void chkabort( void )
{
}


/* DICE workbench entry */
#ifdef _DCC
long wbmain( struct WBStartup *wbstartup )
{
    /* Call main like SAS-C */
    return( main( 0L, (STRPTR *)wbstartup ) );
}
#endif /* _DCC */


long main( long ac, STRPTR *av )
{
    LONG               numArgs,
                       x;
    struct WBStartup  *wbstartup;
    struct WBArg      *wbarg;
    struct DiskObject *tooldobj,
                      *projectdobj;
    BPTR               oldToolLock,
                       oldProjectLock;

    x = main_retval2 = 0L;
    main_retval = RETURN_OK;

    if( CreateBasicResources() )
    {
      DefaultSettings();

/* Workbench */
      if( ac == 0L )
      {
        wbstartup = (struct WBStartup *)av;

        numArgs = wbstartup -> sm_NumArgs;
        wbarg   = wbstartup -> sm_ArgList;

        if( *(wbarg[ 0 ] . wa_Name) )
        {
          if( wbarg[ 0 ] . wa_Lock )
          {
            oldToolLock = CurrentDir( (wbarg[ 0 ] . wa_Lock) );
          }

          if( tooldobj = GetDiskObjectNew( (wbarg[ 0 ] . wa_Name) ) )
          {
            /* two possible cases when started from workbench ... */
            if( numArgs < 2L )
            {
              /* ... first case, only our tool icon is given, create one project here */

              ScanToolTypes( (STRPTR *)(tooldobj -> do_ToolTypes) );

              RunTool();

              FreeInitProjectResult();
            }
            else
            {
              /* ... second case, a couple of project icons are given, multiple projects will start from here */
              for( x = 1L ; x < numArgs ; x++ )
              {
                if( wbarg[ x ] . wa_Lock )
                {
                  oldProjectLock = CurrentDir( (wbarg[ x ] . wa_Lock) );
                }

                if( *(wbarg[ x ] . wa_Name) )
                {
                  if( projectdobj = GetDiskObject( (wbarg[ x ] . wa_Name) ) )
                  {
                    ScanToolTypes( (STRPTR *)(tooldobj -> do_ToolTypes) );
                    ScanToolTypes( (STRPTR *)(projectdobj -> do_ToolTypes) );

                    RunTool();

                    FreeInitProjectResult();
                    DefaultSettings();

                    FreeDiskObject( projectdobj );
                  }
                }

                if( wbarg[ x ] . wa_Lock )
                {
                  CurrentDir( oldProjectLock );
                }
              }
            }

            FreeDiskObject( tooldobj );
          }

          if( wbarg[ 0 ] . wa_Lock )
          {
            CurrentDir( oldToolLock );
          }
        }
      }
      else
      {
/* CLI/Shell */
        if( startuprda = ReadArgs( STARTUP_TEMPLATE, (LONG *)(&result), NULL ) )
        {
          /* did we get a CTRL_C signal ? */
          if( !CheckSignal( SIGBREAKF_CTRL_C ) )
          {
            ScanRDA();

            RunTool();

            FreeInitProjectResult();
          }
          else
          {
            main_retval2 = ERROR_BREAK;
            main_retval  = RETURN_WARN;
          }

          FreeArgs( startuprda );
        }
        else
        {
          main_retval2 = IoErr();
          main_retval  = RETURN_ERROR;
        }

        PrintFault( main_retval2, NAME );
      }

      DeleteBasicResources();
    }

    SetIoErr( main_retval2 );

    return( main_retval );
}


void DefaultSettings( void )
{
    ClearRDA();

    memset( (&project), 0, sizeof(project) );

    project . rebootdelay = 2UL;

    ReadENVPrefs();
}


static
void ReadENVPrefs( void )
{
    TEXT  varbuff[ 258 ];
    ULONG varlen;

    struct RDArgs envvarrda =
    {
      varbuff,
      256L,
      0L,
      0L,
      NULL,
      0L,
      NULL,
      RDAF_NOPROMPT
    };

    if( varlen = GetVar( NAME, varbuff, 256L, 0UL ) )
    {
      varbuff[ varlen ]       = '\n';
      varbuff[ (varlen + 1) ] = '\0';

      if( ReadArgs( ENV_TEMPLATE, (LONG *)(&result), (&envvarrda) ) )
      {
        ScanRDA();

        FreeArgs( (&envvarrda) );
      }
    }
}


void ClearRDA( void )
{
    memset( (&result), 0, sizeof(result) );
}


void ScanRDA( void )
{
    if( result . rebootdelay )
    {
      project . rebootdelay = (ULONG)(*(result . rebootdelay));
    }

    if( result . noreq )
    {
      project . noreq = TRUE;
    }

    if( result . off )
    {
      project . off = TRUE;
    }

    ClearRDA();
}


void ScanToolTypes( STRPTR *tt )
{
    STRPTR s;

    if( s = FindToolType( tt, "REBOOTDELAY" ) )
      (void)StrToLong( s, (LONG *)(&(project . rebootdelay)) ); /* note: result ignored */

    if( s = FindToolType( tt, "NOREQ" ) )
      result . noreq = (long *)s;

    if( s = FindToolType( tt, "QUIET" ) )
      result . noreq = (long *)s;

    if( s = FindToolType( tt, "OFF" ) )
      result . off = (long *)s;

    ScanRDA();
}

static
void FreeInitProjectResult( void )
{
    /* NOP */
}


BOOL CreateBasicResources( void )
{
    return( OpenLibStuff() );
}


void DeleteBasicResources( void )
{
    CloseLibStuff();
}


BOOL OpenLibStuff( void )
{
    UtilityBase = IconBase = LocaleBase = NULL;

    if( IntuitionBase = OpenLibrary( "intuition.library", 37UL ) )
    {
      AttemptOpenLibrary( (&UtilityBase),  NAME, UTILITYNAME,      37UL );
      AttemptOpenLibrary( (&IconBase),     NAME, ICONNAME,         37UL );
      AttemptOpenLibrary( (&LocaleBase),   NAME, "locale.library", 38UL );

      if( LocaleBase )
      {
        ct = OpenCatalogA( NULL, NAME ".catalog", NULL );
      }

      if( IconBase )
      {
        return( TRUE );
      }
    }

    CloseLibStuff();

    return( FALSE );
}


void CloseLibStuff( void )
{
    if( LocaleBase )
    {
      CloseCatalog( ct );

      CloseLibrary( LocaleBase );
    }

    CloseLibrary( IconBase );
    CloseLibrary( UtilityBase );
    CloseLibrary( IntuitionBase );
}


void AttemptOpenLibrary( struct Library **library, STRPTR title, STRPTR libname, ULONG libversion )
{
    struct EasyStruct LibNotFoundES =
    {
      sizeof(struct EasyStruct),
      0UL,
      title,
      SafeGetCatalogStr( ct, MSG_LIB_NOT_FOUND_REQTEXT, MSG_LIB_NOT_FOUND_REQTEXT_STR ),
      SafeGetCatalogStr( ct, MSG_LIB_NOT_FOUND_REQGAD,  MSG_LIB_NOT_FOUND_REQGAD_STR )
    };

    struct EasyStruct LibWrongVersionES =
    {
      sizeof(struct EasyStruct),
      0UL,
      title,
      SafeGetCatalogStr( ct, MSG_LIB_WRONG_VERSION_REQTEXT, MSG_LIB_WRONG_VERSION_REQTEXT_STR ),
      SafeGetCatalogStr( ct, MSG_LIB_WRONG_VERSION_REQGAD,  MSG_LIB_WRONG_VERSION_REQGAD_STR )
    };

    if( (*library) == NULL )
    {
      for( ;; )
      {
        /* attemp to open shared library */
        (*library) = OpenLibrary( libname, 0UL );

        if( *library )
        {         
          if( ((*library) -> lib_Version) < libversion )
          {
            EasyRequest( NULL, (&LibWrongVersionES), NULL, libname, libversion );

            CloseLibrary( (*library) );
            (*library) = NULL;
          }

          break;
        }

        /* prompt the user */
        if( EasyRequest( NULL, (&LibNotFoundES), NULL, libname ) == 0L )
        {
          /* user canceled */
          break;
        }
      }
    }
}


void RunTool( void )
{
    struct EasyStruct RebootES =
    {
      sizeof(struct EasyStruct),
      0UL,
      NAME,
      SafeGetCatalogStr( ct, MSG_REBOOT_REQTEXT, MSG_REBOOT_REQTEXT_STR ),
      SafeGetCatalogStr( ct, MSG_REBOOT_REQGAD,  MSG_REBOOT_REQGAD_STR )
    };

    if( project . noreq )
    {
      MyReboot();
    }
    else
    {
      if( EasyRequest( NULL, (&RebootES), NULL ) == 1L )
      {
        /* user wants to reboot */
        MyReboot();
      }
      else
      {
        main_retval2 = ERROR_BREAK;
        main_retval  = RETURN_WARN;
      }
    }
}


void MyReboot( void )
{
    struct Window *abortreqwindow;
    ULONG          delay,
                   x;
    BOOL           abort;
    ULONG          abortreqsignal,
                   sigmask,
                   signals;

    abort = FALSE;

    struct EasyStruct AbortRebootES =
    {
      sizeof(struct EasyStruct),
      0UL,
      NAME,
      SafeGetCatalogStr( ct, MSG_ABORTREBOOT_REQTEXT, MSG_ABORTREBOOT_REQTEXT_STR )
      SafeGetCatalogStr( ct, MSG_ABORTREBOOT_REQGAD,  MSG_ABORTREBOOT_REQGAD_STR )
    };

    if( (project . rebootdelay) < 1UL )
    {
      project . rebootdelay = 1UL;
    }

    if( project . noreq )
    {
      abortreqwindow = NULL;
    }
    else
    {
      /* Here we must check if we got the "low mem" return value (see BuildEasyRequestArgs autodoc)
       * which may be 0 or 1
       * For 0, I cannot determinate if this is a result from alert or a 'real' low mem failure
       */
      abortreqwindow = BuildEasyRequestArgs( NULL, (&AbortRebootES), 0UL, NULL );

      if( (abortreqwindow == ((struct Window *)1UL)) || (abortreqwindow == NULL) )
      {
        main_retval2 = ERROR_NO_FREE_STORE;
        main_retval  = RETURN_FAIL;

        return;
      }
    }

    abortreqsignal = ((abortreqwindow)?(1UL << abortreqwindow -> UserPort -> mp_SigBit):(0UL));

    sigmask = SIGBREAKF_CTRL_C | abortreqsignal;

    delay = (project . rebootdelay) * 2UL;

    /* for each cycle we'll check if any abort signal arrived (CTRL_C or requester) */
    for( x = 0UL ; x <= delay ; x++ )
    {
      /* check if user aborts countdown */
      signals = CheckSignal( sigmask );

      if( signals & SIGBREAKF_CTRL_C )
      {
        abort = TRUE;
      }

      /* no window, no signal, no event processing ... */
      if( abortreqsignal )
      {
        if( signals & abortreqsignal )
        {
          if( SysReqHandler( abortreqwindow, NULL, FALSE ) == 0L )
          {
            abort = TRUE;
          }
        }
      }

      if( abort )
      {
        break;
      }

      /* wait a little bit */
      Delay( (TICKS_PER_SECOND / 2UL) );
    }

    if( abort == FALSE )
    {
      if( abortreqwindow )
      {
        /* if we got no abort msg, check the requester for any outstanding msg */
        if( SysReqHandler( abortreqwindow, NULL, FALSE ) == 0L )
        {
          abort = TRUE;
        }
      }
    }


    /* Check if user send us CTRL-C or has selected test mode using something like "Setenv Reboot OFF" */
    if( abort || (project . off) )
    {
      main_retval2 = ERROR_BREAK;
      main_retval  = RETURN_WARN;
    }
    else
    {
      /* bite in the dust */
      ColdReboot();
    }

    /* user has aborted the rebooting sequence */
    FreeSysRequest( abortreqwindow );
}


STRPTR SafeGetCatalogStr( struct Catalog *ct, LONG id, STRPTR s )
{
    if( LocaleBase )
    {
      s = GetCatalogStr( ct, id, s );
    }

    return( s );
}



