
/*
**
**  $VER: Reboot.c 1.11 (27.9.1998)
**  Reboot 1.11
**
**  main file
**
**  (C) Copyright 1994-1998 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>

/* amiga pragmas */
#include <pragmas/exec_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/icon_pragmas.h>
#include <pragmas/locale_pragmas.h>
#include <pragmas/alib_pragmas.h> /* tagcall stubs, see datatypes.library V45 includes */

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

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

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

/* misc defines */
#ifndef NAME
#define NAME "Reboot"
#endif /* !NAME */

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

                int                   main( int, char ** );
        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 );
        static  STRPTR                SafeGetCatalogStr( struct Catalog *, LONG, STRPTR );
        static  STRPTR                SafeGetLocaleStr( struct Locale *, LONG, STRPTR );

        static  struct DiskObject    *GetToolDiskObject( STRPTR );



/* version_string */
STRPTR versionstring = VERSTAG;

long main_retval,
     main_retval2;

static struct RDArgs  *startuprda;

/* shared libraries */
extern struct Library *SysBase,
                      *DOSBase;

struct Library *UtilityBase,
               *IntuitionBase,
               *IconBase,
               *LocaleBase;

/* locale support */
struct Locale  *loc;
struct Catalog *ct;

/* templates for ReadArgs */
#define STARTUP_TEMPLATE "REBOOTDELAY/K/N,QUIET=NOREQ/S,OFF/S,NOGUI/S"
#define ENV_TEMPLATE     STARTUP_TEMPLATE /* no /A switches */


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

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


#ifdef _DCC
/* disable CTRL_C break support (DICE CTRL_C abort function) */
void chkabort( void )
{
}
#endif /* _DCC */


/****** Reboot/Reboot ********************************************************
*
*    NAME
*       Reboot -- rebooting utility
*
*    FORMAT
*       Reboot [REBOOTDELAY <seconds>] [QUIET|NOREQ] [OFF] [NOGUI]
*
*    TEMPLATE
*       REBOOTDELAY/K/N,QUIET=NOREQ/S,OFF/S,NOGUI/S
*
*    TOOLTYPES
*       REBOOTDELAY/N
*       QUIET/S
*       NOREQ/S
*       OFF/S
*       NOGUI/S
*
*    PURPOSE
*       To reboot the computer.
*
*    INTRODUCTION
*       A simple tool to be used with Kickstart 2.x/3.x, written by
*       Roland 'Gizzy' Mainz, freeware, all rights reserved.
*       No guarantee of any kind is made that  the programm described below
*       in this document is 100% reliable. You use this material on your own
*       risk.
*
*       (The story:)
*       While playing with ENVOY 1.6, I need a program which allows to reboot
*       another AMIGA through the network (by my own "RemoteNetShell") or
*       after a given time.
*       First I wrote a little script (using WAIT) and a C program calling
*       exec.library/ColdReboot() to solve this problem.
*       Switching to IAM's ENVOY 2.0 I replaced this script by this tool,
*       adding some features (WB (including multiselect), SHELL ReadArgs,
*       locale support and test mode).
*
*    DESCRIPTION
*       Reboot is used to reboot the whole computer like a "cold"
*       system start.
*
*       Unless you specify otherwise (through REBOOTDELAY option), reboot
*       will wait 2 seconds before rebooting the system.
*       This is used to let the system (and it's disk drives) settle.
*       This delay time can't be less than 1 second, a REBOOTDELAY=0
*       will also wait this minimum time.
*
*       Whenever the QUIET (or NOREQ) switch is set, the verify requesters
*       ("Are you sure#?" etc.) will be suppressed.
*
*       If the OFF switch is set, the tool act like when a CTRL-C signal
*       has been send to the tool.
*
*       Variable support:
*         The environment REBOOT variable (either LOCAL or GLOBAL) can be
*         used for default settings. The parsing template for this
*         variable is the same like the shell template (see above).
*
*       Reboot supports workbench multiselect (e.g. project icons) !
*
*       The NOGUI option disables the requester and makes a simple
*       console query. Currently, the NOGUI option should not be used
*       if launched from WB.
*
*       If requesters have been disabled in a shell (using tools like DICE's
*       "noreq" tool), the NOGUI option is on per default.
*
*    BUGS
*       - Shell variables longer than 255 are currently not supported.
*
*       - Any errors during tooltype processing are ignored.
*
*       - The usage of the NOGUI option is not recommned to be used from
*         WB.
*
*       - Does not work properly with my Apollo 2030 accerlator board.
*         The system reboots, then hangs. Cause known,
*         comments very welcome.
*
*    NOTES
*       "Set Reboot OFF" (e.g. use of a local variable) is only valid if
*       you start Reboot from this shell.
*
*    HISTORY
*       V1.1:
*         - First release
*
*       V1.2:
*         - The "Abort reboot" requester couldn't be canceld 1 second before
*           the given time.
*           Fixed.
*
*         - I did not read the autodocs exactly:
*           The function BuildEasyRequest might return 0 or 1 at low mem time.
*           Now Reboot simply fails with ERROR_NO_FREE_STORE for both 0 or 1.
*           If 1 was returned, an enforcer hit would occur.
*           Never happed, but
*           fixed.
*
*         - AttemptOpenLibrary could return (sometimes) random pointers.
*           In fact, this never happened by me, but maybe ...
*           Fixed.
*
*         - While getting Reboot's environment variable, the "Abort reboot"
*           requester might be canceled. Now we check this:
*           Fixed.
*
*         - Additional, there was some code cleanup which adds support for
*           DICE INLINE calls.
*
*         - The executable is now PURE and can be made resident.
*
*         - The time between the program checks the "Abort reboot" requester
*           has been decrased down to a half second.
*
*       V1.3
*         - Starting with V1.3 environment variables are supported.
*           Things set in var "REBOOT" (local or global) will be parsed after
*           built-in default settings and before any user-given arguments
*           (shell args or project icons), which can overide those ENV
*           settings given there.
*
*           This feature may cause Enforcer hits (I think so, I've never seen
*           one).
*
*       V1.4
*         - Starting with V1.4, ENV parsing should be safe.
*           For Bug reports, I've included a Reboot.ld, which includes the
*           debugging info used by Enforcer/FindHit.
*
*         - Running CPU FASTROM causes sometimes problems: The system reboots,
*           but then hang atfer a while... ???
*
*       V1.5
*         - Now I fully support SAS/C for all my projects (SMakefile
*           included). A matching DMakefile is on the way.
*
*       V1.6
*         - Unused utility.library code has been removed
*
*       V1.7
*         - Recompiled with SAS/C 6.57
*
*         - Minor code cleanup.
*
*         - Moved contents of the #?.guide to this autodoc
*
*       V1.8
*         - Added français catalog file
*           Thanks to Julien Wilk (wilkj@esiee.fr).
*
*         - Added NOGUI option, e.g. localized console prompt :-)
*
*       V1.9
*         - Silly mistake: I forgot to update the version string in V1.8.
*           (Now the version string shows correctly V1.9).
*
*         - Recompiled with SAS/C 6.58 to get rid of some mc68060 problems.
*
*         - Fixed the longstanding bug that project icons did only work if
*           Reboot's full path was given in "Default Tool".
*
*       V1.10
*         - Added Croatia (hrvatski) catalog file.
*           Thanks to Sinisa Lolic (vegi@usa.net).
*
*         - If a (required) shared library  cannot be opened,
*           "Reboot" returns now ERROR_INVALID_RESIDENT_LIBRARY instead
*           of ERROR_OBJECT_NOT_FOUND.
*
*         - The NOGUI option is now on per default if requesters have been
*           disabled in the current shell (e..g if (thisproc -> pr_WindowPtr)
*           is -1L).
*
*         - Added "SmallReboot" project for those people who said that
*           "Reboot" is too big.
*           The small sister of "Reboot" is only ~124 bytes small and still
*           includes a version string...
*
*       V1.11
*         - Added Svenska catalog file written by Harry Samwel
*           (samwel@algonet.se). Thanx !
*
*         - Each function has now a short comment about it's job to do...
*
*         - Minor other code changes...
*
*    INSTALLATION
*       After unpacking this archieve:
*
*       Workbench:
*         - Drop the 'Reboot' icon in your favorite drawer (like
*            "SYS:Utilities/").
*           See SHELL for copying the catalog files.
*
*       Shell:
*         - Unpack this archieve at "SYS:Utilities/"
*           and add the following statements at your "S:user-startup" startup
*           file:
*
*           Assign Reboot: SYS:Utilities/Reboot
*           path Reboot: ADD
*         OR
*         - Drop/Copy the 'Reboot' file in your favorite directory
*           (like "Sys:Utilities").
*           To copy the (german) catalog files, type
*           Copy Catalogs/#? TO="LOCALE:Catalogs/" ALL QUIET CLONE
*
*       SAS:
*         - Type 'smake install' in shell
*
*    SOURCE
*       DICE users may use DMakefile (if included).
*       GNU-C support will be done in one future version.
*
*       All:
*       If you like to include a new language (like Français or Nederlands
*       etc.), send me a filled "Reboot_blank.ct" file named "Reboot_#?.ct"
*       (#? for your language). As an example, see "Reboot_deutsch.ct".
*       Note that I can currently only process "Reboot_#?.ct" files whose
*       language is supported by AmigaOS 3.1 (e.g. a AmigaDOS Locale language
*       driver exists).
*
*       SAS/C:
*       Use SMakefile to create the executable.
*       Note that the français locale file cannot be build with SAS/C SMake
*       because it does not support the 'ç' character.
*
*    AUTHOR's REQUEST
*        By  releasing  this program I do  not  place any obligations on you,
*        feel free to share this program with your  friends (and enemies).
*
*        If you want to blame me, report any bugs, or wants a new version
*        send your letter to:
*                        Roland Mainz
*                        Hohenstaufenstraße 8
*                        52388 Nörvenich
*                        GERMANY
*
*        Phone: (+49)(0)2426/901568
*        Fax:   (+49)(0)2426/901569
*
*        EMAIL is also available:
*        GISBURN@w-specht.rhein-ruhr.de
*
*        If you want to send me attachments larger than 1MB (up to 5MB,
*        more with my permission):
*        Up to November 1998 I'm reachable using this email address, too:
*        Reinhold.A.Mainz@KBV.DE
*
*        | Please put your name and address in your mails !
*        | German mailers should add their phone numbers.
*        | See BUGS section above when submitting bug reports.
*
*        Sorry, but I can only look once a week for mails.
*        If you don't hear something from me within three weeks, please
*        send your mail again (but watch about new releases) (problems with
*        this email port are caused by reconfigurations, hackers, network
*        problems etc.).
*
*        The  entire  "Reboot"  package may  be  noncommercially
*        redistributed, provided  that  the package  is always  distributed
*        in it's complete  form (including it's documentation).  A small copy
*        fee for media costs is okay but any kind of commercial distribution
*        is strictly forbidden! Comments  and  suggestions  how  to  improve
*        this program  are generally appreciated!
*
*        Thanks to Matt Dillon for his DICE, and Olaf 'Olsen'
*        Barthel for his help, ideas and some text clips from his
*        documentations.
*
*    SEE ALSO
*        exec.library/ColdReboot
*
******************************************************************************
*
*/


/* DICE workbench entry (what about Storm-C or vbcc ??) */
#ifdef _DCC
long wbmain( struct WBStartup *wbstartup )
{
    /* Call main like SAS-C */
    return( (long)main( 0L, (char **)wbstartup ) );
}
#endif /* _DCC */


/* main program entry */
int main( int ac, char **av )
{
    LONG               numArgs,
                       x;
    struct WBStartup  *wbstartup;
    struct WBArg      *wbarg;
    struct DiskObject *tooldobj,
                      *projectdobj;
    BPTR               oldToolLock    = NULL,
                       oldProjectLock = NULL;

    main_retval  = RETURN_OK;
    main_retval2 = 0L;

    if( CreateBasicResources() )
    {
      DefaultSettings();

      /* check if something goes wrong (ENV error etc.) */
      if( main_retval == RETURN_OK )
      {
/* 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 = GetToolDiskObject( (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) );

                /* check if something goes wrong (parsing error, etc.) */
                if( main_retval == RETURN_OK )
                {
                  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) );

                      /* check if something goes wrong (parsing error, etc.) */
                      if( main_retval == RETURN_OK )
                      {
                        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();

              /* check if something goes wrong (parsing error, etc.) */
              if( main_retval == RETURN_OK )
              {
                RunTool();
              }

              FreeInitProjectResult();
            }
            else
            {
              /* SIGBREAKF_CTRL_C found */
              main_retval  = RETURN_WARN;
              main_retval2 = ERROR_BREAK;
            }

            FreeArgs( startuprda );
          }
          else
          {
            /* ReadArgs failed */
            main_retval  = RETURN_FAIL;
            main_retval2 = IoErr();
          }
        }
      }

      DeleteBasicResources();
    }

    PrintFault( main_retval2, NAME );

    SetIoErr( main_retval2 );

    return( (int)main_retval );
}


/* set the "project" array (arguments) to their default values */
static
void DefaultSettings( void )
{
    struct Process *ThisProcess = (struct Process *)FindTask( NULL );

    ClearRDA();
    memset( (void *)(&project), 0, sizeof( project ) );

    /* Default values */
    project . rebootdelay = 2UL;

    /* In the case that (ThisProcess -> pr_WindowPtr) is -1L the OS aborts requesters automatically.
     * If we were launched from shell, we fore the NOGUI option that the user can be promped.
     */
    if( (ThisProcess -> pr_CLI) && ((ThisProcess -> pr_WindowPtr) == (APTR)-1L) )
    {
      project . nogui = TRUE;
    }

    /* read prefs */
    ReadENVPrefs();
}


/* read preferences */
static
void ReadENVPrefs( void )
{
    struct RDArgs envvarrda =
    {
      NULL,
      256L,
      0L,
      0L,
      NULL,
      0L,
      NULL,
      RDAF_NOPROMPT
    };

    TEXT varbuff[ 258 ];

    envvarrda . RDA_Source . CS_Buffer = varbuff;

    if( GetVar( NAME, varbuff, 256L, 0UL ) != (-1L) )
    {
      strcat( varbuff, "\n" );

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

        FreeArgs( (&envvarrda) );
      }
      else
      {
        /* Can't parse ENV variable */
        main_retval  = RETURN_FAIL;
        main_retval2 = IoErr();
      }
    }
}


/* clear array used by ReadArgs (argument parsing) */
static
void ClearRDA( void )
{
    memset( (void *)(&result), 0, sizeof( result ) );
}


/* process arguments */
static
void ScanRDA( void )
{
    if( result . rebootdelay )
    {
      project . rebootdelay = (ULONG)(*(result . rebootdelay));
    }

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

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

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

    ClearRDA();
}


/* process WB arguments */
static
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;

    if( s = FindToolType( tt, "NOGUI" ) )
      result . nogui = (long *)s;

    ScanRDA();
}


/* free resources opened by argument parsing */
static
void FreeInitProjectResult( void )
{
    /* NOP */
}


/* open/create basic resources (libraries/devices)... */
static
BOOL CreateBasicResources( void )
{
    return( OpenLibStuff() );
}


/* close/delete baseic resources obtained during CreateBasicResources */
static
void DeleteBasicResources( void )
{
    CloseLibStuff();
}


/* open libraries */
static
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 )
      {
        loc = OpenLocale( NULL );
        ct  = OpenCatalogA( NULL, (NAME ".catalog"), NULL );
      }

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

    CloseLibStuff();

    /* Can't open requires libraries */
    main_retval  = RETURN_FAIL;
    main_retval2 = ERROR_INVALID_RESIDENT_LIBRARY;

    return( FALSE );
}


/* close libraries */
static
void CloseLibStuff( void )
{
    if( LocaleBase )
    {
      CloseCatalog( ct );
      CloseLocale( loc );

      CloseLibrary( LocaleBase );
    }

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


/* Attempt to open a library. If this failes, bring out a requester 
 * (like the example in the Amiga Style Guide book (Addison-Wesley))
 */
void AttemptOpenLibrary( struct Library **library, STRPTR title, STRPTR libname, ULONG libversion )
{
    struct EasyStruct LibNotFoundES,
                      LibWrongVersionES;

    LibNotFoundES . es_StructSize   = sizeof( struct EasyStruct );
    LibNotFoundES . es_Flags        = 0UL;
    LibNotFoundES . es_Title        = title;
    LibNotFoundES . es_TextFormat   = SafeGetCatalogStr( ct, MSG_LIB_NOT_FOUND_REQTEXT, MSG_LIB_NOT_FOUND_REQTEXT_STR );
    LibNotFoundES . es_GadgetFormat = SafeGetCatalogStr( ct, MSG_LIB_NOT_FOUND_REQGAD,  MSG_LIB_NOT_FOUND_REQGAD_STR );

    LibWrongVersionES . es_StructSize   = sizeof( struct EasyStruct );
    LibWrongVersionES . es_Flags        = 0UL;
    LibWrongVersionES . es_Title        = title;
    LibWrongVersionES . es_TextFormat   = SafeGetCatalogStr( ct, MSG_LIB_WRONG_VERSION_REQTEXT, MSG_LIB_WRONG_VERSION_REQTEXT_STR );
    LibWrongVersionES . es_GadgetFormat = 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;
        }
      }
    }
}


/* main functionality */
static
void RunTool( void )
{
    if( project . noreq )
    {
      MyReboot();
    }
    else
    {
      if( project . nogui )
      {
        TEXT   buffer[ 8 ] = { 0 };
        STRPTR yes = SafeGetLocaleStr( loc, YESSTR, "Yes" ),
               no  = SafeGetLocaleStr( loc, NOSTR,  "No"  );

        Printf( "%s (%lc/%lc)\n", SafeGetCatalogStr( ct, MSG_REBOOT_REQTEXT, MSG_REBOOT_REQTEXT_STR ),
                                  (ULONG)(*yes),
                                  (ULONG)(*no) );

        Flush( Input()  ); /* Remove outstanding rubbish             */
        Flush( Output() ); /* Be sure that the user got the message */

        FGets( Input(), buffer, (sizeof( buffer ) - 1UL) );

        /* Simple RETURN for yes or 'Y' (english) for ok) */
        if( (*buffer == '\n') || (ToUpper( (ULONG)(*buffer) ) == ToUpper( (ULONG)(*yes) ) ) )
        {
          /* user wants to reboot */
          MyReboot();
        }
        else
        {
          /* cancelled */
          main_retval2 = ERROR_BREAK;
          main_retval  = RETURN_WARN;
        }
      }
      else
      {
        struct EasyStruct RebootES;

        RebootES . es_StructSize   = sizeof( struct EasyStruct );
        RebootES . es_Flags        = 0UL;
        RebootES . es_Title        = NAME;
        RebootES . es_TextFormat   = SafeGetCatalogStr( ct, MSG_REBOOT_REQTEXT, MSG_REBOOT_REQTEXT_STR );
        RebootES . es_GadgetFormat = SafeGetCatalogStr( ct, MSG_REBOOT_REQGAD,  MSG_REBOOT_REQGAD_STR );

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


/* reboot the computer */
static
void MyReboot( void )
{
    struct Window *abortreqwindow  = NULL;
    ULONG          delay,
                   x;
    BOOL           abort           = FALSE;
    ULONG          abortreqsignal,
                   sigmask,
                   signals;

    /* 1 second is the minimum reboot delay... */
    if( (project . rebootdelay) < 1UL )
    {
      project . rebootdelay = 1UL;
    }

    /* Prompt user ? */
    if( !(project . noreq) )
    {
      if( project . nogui )
      {
        Printf( "%s\n", SafeGetCatalogStr( ct, MSG_ABORTREBOOT_REQTEXT, MSG_ABORTREBOOT_REQTEXT_STR ) );

        Flush( Input()  ); /* Remove outstanding rubbish            */
        Flush( Output() ); /* Be sure that the user got the message */
      }
      else
      {
        struct EasyStruct AbortRebootES;

        AbortRebootES . es_StructSize   = sizeof( struct EasyStruct );
        AbortRebootES . es_Flags        = 0UL;
        AbortRebootES . es_Title        = NAME;
        AbortRebootES . es_TextFormat   = SafeGetCatalogStr( ct, MSG_ABORTREBOOT_REQTEXT, MSG_ABORTREBOOT_REQTEXT_STR );
        AbortRebootES . es_GadgetFormat = SafeGetCatalogStr( ct, MSG_ABORTREBOOT_REQGAD,  MSG_ABORTREBOOT_REQGAD_STR );

        /* 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) )
        {
          /* Can't open abort requester */
          main_retval2 = ERROR_NO_FREE_STORE;
          main_retval  = RETURN_FAIL;

          return;
        }
      }
    }

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

    sigmask = SIGBREAKF_CTRL_C | abortreqsignal;

#define CHECKS_PER_SEC (2UL)
    delay = (project . rebootdelay) * CHECKS_PER_SEC;

    /* 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;
      }

      if( project . nogui )
      {
        /* Did user hit key for abort ? */
        if( WaitForChar( Input(), 10L ) )
        {
          abort = TRUE;
        }
      }
      else
      {
        /* 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 / CHECKS_PER_SEC) );
    }

    /* No abort ? */
    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) )
    {
      /* Aborted by requester or user-setup */
      main_retval2 = ERROR_BREAK;
      main_retval  = RETURN_WARN;
    }
    else
    {
      /* bite in the dust */
      ColdReboot();
    }

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


/* get a catalog string if possible (e.g. if locale.library is available) */
static
STRPTR SafeGetCatalogStr( struct Catalog *ct, LONG id, STRPTR s )
{
    if( LocaleBase )
    {
      s = GetCatalogStr( ct, id, s );
    }

    return( s );
}


/* get a locale string if possible (e.g. if locale.library and a struct Locate are available) */
static
STRPTR SafeGetLocaleStr( struct Locale *loc, LONG id, STRPTR s )
{
    if( LocaleBase && loc )
    {
      s = GetLocaleStr( loc, id );
    }

    return( s );
}


/* get the tool's tool icon, ignoring the WB bug that the current dir in WBArgs is not the dobj's one... */
static
struct DiskObject *GetToolDiskObject( STRPTR name )
{
    struct DiskObject *dobj;
    struct Process    *ThisProc = (struct Process *)FindTask( NULL );
    BPTR               olddir   = CurrentDir( (ThisProc -> pr_HomeDir) );

    dobj = GetDiskObjectNew( name );

    (void)CurrentDir( olddir );

    return( dobj );
}




