/*************************************************************************
 *
 *  SPUDclock - This program does a nice little talking alarm clock
 *  
 *  This was written by Robert E. Beaty and H. Bret Young and
 *  are Copyright (C) 1987 by R.E.Beaty and H. Bret Young and
 *  The Man From S.P.U.D.
 *
 *  v1.2
 *************************************************************************/

/* Get the necessary include files for this program */
#include <exec/types.h>
#include <exec/exec.h>
#include <devices/narrator.h>
#include <devices/timer.h>
#include <libraries/translator.h>
#include <libraries/dos.h>
#include <intuition/intuition.h>
#include <string.h>

/*
 * Here are some necessary defines for processing needs
 */
#define REVISION	1
#define TASK_PRIORITY	0

/*
 * Here are some necessary return codes for various routines
 */
#define NORMAL_EXIT		0
#define NORMAL_START		0
#define QUICK_EXIT		-10
#define QUICK_START		-20
#define CANT_OPEN_INTUITION	-100
#define CANT_OPEN_TRANSLATOR	-200
#define CANT_OPEN_NARRATOR	-300
#define CANT_OPEN_TIMER		-400
#define CREATE_PORT_PROBLEMS	-500
#define CREATE_IO_PROBLEMS	-600
#define TRANSLATOR_NOT_WORKING	-700

/* 
 * Here are the variable values that come in handy
 */
#define QUARTER_HOUR		1
#define HALF_HOUR		2
#define HOUR			4
#define LITTLE			1
#define BIG			2

#define	AM_BIT			(1<<0)
#define PS_BIT			(1<<1)
#define	SA_BIT			(1<<2)
#define	EA_BIT			(1<<3)
#define	AV_BIT			(1<<4)
#define	S_BIT			(1<<5)

/* 
 * Here are the global structures
 */
struct timerequest timeReq;	/* this is my conduit to the timer */
struct MsgPort *clockPort = NULL, *writePort = NULL, 
               *replyPort = NULL, *timerPort = NULL;
struct narrator_rb *writeNarrator = NULL;
struct IntuitionBase *IntuitionBase = NULL;
struct Library *TranslatorBase = NULL;
struct DateStamp now;
struct PacketMessage {
	struct Message packet_message;		/* this is for DOS */
	int alarm_mode,		/* this will tell us how often to alarm */
	    prestart,		/* this will tell if we prestart the speakers */
	    start_alarm,	/* this is the starting time */
	    end_alarm,		/* this is the ending time */
	    alarm_volume,	/* this is how loud to make it */
	    quit_flag;		/* this will tell when to quit */
	char salutation[80];	/* this is a little saying before the time */
        int change_flags,
            changing,
            listing;
	};

/* 
 * Here are the global variables
 */
UBYTE *sampleInput, outputString[500];	/* these are for the translator */
SHORT rtnCode, error;
BYTE audChanMasks[4] = { 3, 5, 10, 12 };	/* which channels to use */
int signal, timer_signal, port_signal;	/* where the message came from */
int alarm_mode, quit_flag, prestart, alarm_volume;
int start_alarm, end_alarm, alarm_time;
int hours_24, hours_12, minutes;
char *cp, salutation[80], alarm[120];
struct PacketMessage *incoming, *outgoing;



/************************************************************************
 *
 *  cprintf( why ) - This routine does simple string printing to
 *  		     the console, and so saves us loading the printf
 *  		     routines.
 *
 *  This code section was written by Robert E. Beaty and
 *  are Copyright (C) 1987 by R.E.Beaty and The Man From S.P.U.D.
 *
 ************************************************************************/
cprintf( arg )
char *arg;
{
    int length;

    length = Write( Output(), arg, strlen(arg) );
    return( length );
}   /* end of cprintf(); */



/************************************************************************
 *
 *  itoa( string, value ) - This routine does simple integer to ascii
 *  			    conversion. NOTE: value < 9999 !!
 *
 *  This code section was written by Robert E. Beaty and
 *  are Copyright (C) 1987 by R.E.Beaty and The Man From S.P.U.D.
 *
 ************************************************************************/
void itoa( carg, varg )
char *carg;
int varg;
{
    int place;

    /* reset where I am putting this stuff */
    place = 0;

    if ( varg > 999 ) {
        /* do the most thousands digit */
        carg[place++] = '0' + (varg/1000);
        varg = varg - (1000*(varg/1000));
    }
    if ( (varg > 99) || (place != 0) ) {
        /* do the hundreds digit */
        carg[place++] = '0' + (varg/100);
        varg = varg - (100*(varg/100));
    }
    if ( (varg > 9) || (place != 0) ) {
        /* do the tens digit */
        carg[place++] = '0' + (varg/10);
        varg = varg - (10*(varg/10));
    }
    /* always do the ones digit */
    carg[place++] = '0' + varg;

    /* null terminate this string */
    carg[place] = '\0';
}   /* end of itoa(); */



/************************************************************************
 *
 *  CloseNarrator( why ) - This routine closes up the narrator and
 *  		           translator devices nicely.
 *
 *  This code section was written by Robert E. Beaty and
 *  are Copyright (C) 1987 by R.E.Beaty and The Man From S.P.U.D.
 *
 ************************************************************************/
void CloseNarrator( why )
int why;
{
    /* Check to see if this was called by OpenNarrator() */
    if ( why != CANT_OPEN_NARRATOR ) {
        if ( writeNarrator != NULL )
            CloseDevice( writeNarrator );
    }
    /* Just start deleting things if they exist */
    if ( writeNarrator != NULL )
        DeleteExtIO( writeNarrator, sizeof(struct narrator_rb) );
    if ( writePort != NULL )
        DeletePort( writePort );
    if ( TranslatorBase != NULL )
        CloseLibrary( TranslatorBase );
}   /* end of CloseNarrator(); */



/************************************************************************
 *
 *  OpenNarrator() - This routine opens up the narrator and translator
 *  		     devices nicely. It will return non-FALSE if an error
 *  		     occured.
 *
 *  This code section was written by Robert E. Beaty and
 *  are Copyright (C) 1987 by R.E.Beaty and The Man From S.P.U.D.
 *
 ************************************************************************/
OpenNarrator( )
{
    int error;

    /* Open up the translator first */
    TranslatorBase = (struct Library *) OpenLibrary( "translator.library", REVISION );
    if ( TranslatorBase == NULL )
        return( CANT_OPEN_TRANSLATOR );
        
    /* test it */
    sampleInput = "this is a test.";
    rtnCode = Translate( sampleInput, strlen(sampleInput), outputString, 500 );
    if ( rtnCode != 0 ) {
        CloseLibrary( TranslatorBase );		/* this is open, so close */
        return( TRANSLATOR_NOT_WORKING );
    }   /* end of error checking the translator */

    /* Create the port to the Narrator */
    writePort = (struct MsgPort *) CreatePort( "SPUDclock.narrator", TASK_PRIORITY );
    if ( writePort == NULL ) {
        CloseLibrary( TranslatorBase );		/* this is open, so close */
        return( CREATE_PORT_PROBLEMS );
    }   /* end of error checking the port creation */

    /* Open an I/O channel to the Narrator */
    writeNarrator = (struct narrator_rb *) CreateExtIO( writePort, sizeof(struct narrator_rb) );
    if ( writeNarrator == NULL ) {
        DeletePort( writePort );		/* this port is open */
        CloseLibrary( TranslatorBase );		/* this is open, so close */
        return( CREATE_IO_PROBLEMS );
    }   /* end of error checking I/O creation */

    /* Now set up the defaults for the narrator port */
    writeNarrator->ch_masks = audChanMasks;	/* ... the channel masks */
    writeNarrator->nm_masks = sizeof(audChanMasks);	/* ... the size */
    writeNarrator->message.io_Data = (APTR)outputString;	/* data */
    writeNarrator->mouths = 0;		/* we don't want shapes computed */
    writeNarrator->message.io_Command = CMD_WRITE;	/* output command */

    /* Finally, open the narrator device */
    error = OpenDevice( "narrator.device", 0, writeNarrator, TASK_PRIORITY );
    if ( error != 0 ) {
        CloseNarrator( CANT_OPEN_NARRATOR );	/* close it all up */
        return( CANT_OPEN_NARRATOR );
    }   /* end of checking narrator device opening */
    
    /* no errors so return FALSE */
    return( FALSE );
}   /* end of OpenNarrator(); */



/************************************************************************
 *
 *  init( how ) - This routine opens everything up and returns non-FALSE
 *  	          if something went wrong.
 *
 *  This code section was written by Robert E. Beaty and
 *  are Copyright (C) 1987 by R.E.Beaty and The Man From S.P.U.D.
 *
 ************************************************************************/
init( how )
int how;
{
    int error;

    /* Open up Intuition first */
    if ( IntuitionBase == NULL ) {
        IntuitionBase = (struct IntuitionBase *) OpenLibrary( "intuition.library", REVISION );
        if ( IntuitionBase == NULL )
            return( CANT_OPEN_INTUITION );
    }   /* end of opening intuition if needed */
    /* if this is a quick start, then only open up intuition */
    if ( how == QUICK_START ) return( FALSE );

    /* Open the communication port to other copies of SPUDclock */
    clockPort = (struct MsgPort *) CreatePort( "SPUDclock", TASK_PRIORITY );
    if ( clockPort == NULL ) {
        CloseLibrary( IntuitionBase );		/* this is open, so close */
        return( CREATE_PORT_PROBLEMS );
    }   /* end of error checking the port creation */

    /* Now open the narrator */
    error = OpenNarrator();
    if ( error ) {
        DeletePort( clockPort );
        CloseLibrary( IntuitionBase );
        return( error );
    }   /* end of error checking the narrator opening */
    
    /* Now create the timer */
    timerPort = (struct MsgPort *) CreatePort( "SPUDclock.timer", TASK_PRIORITY );
    if ( timerPort == NULL ) {
        CloseNarrator( CANT_OPEN_TIMER );
        DeletePort( clockPort );
        CloseLibrary( IntuitionBase );		/* this is open, so close */
        return( CREATE_PORT_PROBLEMS );
    }   /* end of error checking the port creation */

    error = OpenDevice( TIMERNAME, UNIT_VBLANK, (char *) &timeReq, TASK_PRIORITY );    
    if ( error != 0 ) {
        DeletePort( timerPort );
        CloseNarrator( CANT_OPEN_TIMER );
        DeletePort( clockPort );
        CloseLibrary( IntuitionBase );		/* this is open, so close */
        return( CANT_OPEN_TIMER );
    }

    /* Everything is open O.K., so get the signal bits */
    timer_signal = 1 << timerPort->mp_SigBit;
    port_signal = 1 << clockPort->mp_SigBit;
    
    /* ... and set up the timer request structure */
    timeReq.tr_node.io_Message.mn_ReplyPort = timerPort;
    timeReq.tr_node.io_Command = TR_ADDREQUEST;
    timeReq.tr_node.io_Flags = 0;
    timeReq.tr_node.io_Error = 0;

    /* no errors, so return FALSE */
    return( FALSE );
}   /* end of init(); */



/************************************************************************
 *
 *  clean( why ) - This routine cleans everything up.
 *
 *  This code section was written by Robert E. Beaty and
 *  are Copyright (C) 1987 by R.E.Beaty and The Man From S.P.U.D.
 *
 ************************************************************************/
void clean( why )
int why;
{
    /* Abort the timer request pending */
    if ( timeReq.tr_node.io_Message.mn_ReplyPort != NULL )
        AbortIO( (char *) &timeReq.tr_node );

    /* if we want a quick exit then skip this stuff */
    if ( why == QUICK_EXIT ) goto quick;

    /* just call the clean up routines */
    if ( timerPort != NULL ) DeletePort( timerPort );
    CloseNarrator( why );
    if ( clockPort != NULL ) DeletePort( clockPort );
    quick:
    if ( IntuitionBase != NULL ) CloseLibrary( IntuitionBase );
}   /* end of clean(); */



/************************************************************************
 *
 *  bed_bye( how_much ) - This routine submits a timer event for us
 *
 *  This code section was written by Robert E. Beaty and
 *  are Copyright (C) 1987 by R.E.Beaty and The Man From S.P.U.D.
 *
 ************************************************************************/
void bed_bye( how_much )
int how_much;
{
    /* See how long the sleep is for */
    if ( how_much == LITTLE ) {
        timeReq.tr_time.tv_secs = 5;		/* little is 5 sec. */
        timeReq.tr_time.tv_micro = 0;
    }
    else {
        timeReq.tr_time.tv_secs = 885;		/* big is 14 min 45 sec. */
        timeReq.tr_time.tv_micro = 0;
    }
    /* ... and send it out to be done */
    SendIO( (char *) &timeReq.tr_node ); 
}   /* end of bed_bye(); */



/************************************************************************
 *
 *  speak_time( hrs, mins ) - This routine formats and speaks the time.
 *
 *  This code section was written by Robert E. Beaty and
 *  are Copyright (C) 1987 by R.E.Beaty and The Man From S.P.U.D.
 *
 ************************************************************************/
void speak_time( hrs, mins )
int hrs, mins;
{
    /* 
     * First, see if we need to prestart the speakers 
     */
    if ( prestart )
        cp = stpcpy( alarm, "t,," );
    else
        cp = alarm;

    /*
     * Build up the string to speak
     */
    /* start with the salutation */
    cp = stpcpy( cp, salutation );
    /* ... add the time is stuff */
    cp = stpcpy( cp, ", It is now " );
    /* check for quarter till */
    if ( (alarm_mode == QUARTER_HOUR) && (mins == 45) ) {
        cp = stpcpy( cp, "quarter till " );
        /* check to see that it makes sense */
        if ( (++hrs) == 13 ) hrs = 1;
    }
    /*
     * always add the hour
     */
    switch( hrs ) {
        case 1 : cp = stpcpy( cp, "1 " );  break;
        case 2 : cp = stpcpy( cp, "2 " );  break;
        case 3 : cp = stpcpy( cp, "3 " );  break;
        case 4 : cp = stpcpy( cp, "4 " );  break;
        case 5 : cp = stpcpy( cp, "5 " );  break;
        case 6 : cp = stpcpy( cp, "6 " );  break;
        case 7 : cp = stpcpy( cp, "7 " );  break;
        case 8 : cp = stpcpy( cp, "8 " );  break;
        case 9 : cp = stpcpy( cp, "9 " );  break;
        case 10 : cp = stpcpy( cp, "ten " );  break;
        /* the number 11 sounds better spelled 'eelaven' */
        case 11 : cp = stpcpy( cp, "eelaven " );  break;
        case 12 : cp = stpcpy( cp, "twelve " );  break;
    }   /* end of decoding the hours */
    /*
     * decode the different modes
     */
    switch( alarm_mode ) {
        case QUARTER_HOUR :
            switch( mins ) {
                case 0 : cp = stpcpy( cp, "o'clock." );  break;
                case 15 : cp = stpcpy( cp, "fifteen." );  break;
                case 30 : cp = stpcpy( cp, "thirty." );  break;
                case 45 : cp = stpcpy( cp, "." );  break;
                /* if we aren't where we are supposed to be, NULL it out */
                default : cp = NULL;  break;
            }
            break;
        case HALF_HOUR :
            switch( mins ) {
                case 0 : cp = stpcpy( cp, "o'clock." );  break;
                case 30 : cp = stpcpy( cp, "thirty." );  break;
                /* if we aren't where we are supposed to be, NULL it out */
                default : cp = NULL;  break;
            }
            break;
        case HOUR :
            if ( mins == 0 )
                cp = stpcpy( cp, "o'clock." );
            else
                /* if we aren't where we are supposed to be, NULL it out */
                cp = NULL;
            break;
    }   /* end of alarm_mode selection */

    /*
     * If the time section is not NULL, do the rest
     */
    if ( cp != NULL ) {
        /*
         * ... add the "Good morning..." or "Good night..."
         */
        if ( start_alarm != end_alarm ) {
            if ( alarm_time == start_alarm )
                cp = stpcpy( cp, ",, Good Morning!" );
            if ( alarm_time == end_alarm )
                cp = stpcpy( cp, ",, Good Night." );
        }   /* end of special salutation */

        /*
         * translate it and speak it
         */
        rtnCode = Translate( alarm, strlen(alarm), outputString, 500 );
        writeNarrator->sex = MALE;
        writeNarrator->pitch = DEFPITCH;
        writeNarrator->mode = ROBOTICF0;
        writeNarrator->volume = alarm_volume;
        writeNarrator->message.io_Data = (APTR)outputString;
        writeNarrator->message.io_Length = strlen( outputString );
        DoIO( writeNarrator );
    }   /* end of finishing it up and speaking it */
}   /* end of speak_time(); */



/************************************************************************
 *
 *  usage() - This routine helps the user.
 *
 *  This code section was written by Robert E. Beaty and
 *  are Copyright (C) 1987 by R.E.Beaty and The Man From S.P.U.D.
 *  
 *  minimal additions by H. Bret Young 
 *
 ************************************************************************/
usage( how_much )
int how_much;
{
    cprintf( "Usage:\n" );
    cprintf( "  run SPUDclock [-m greeting message] [-f] [-t] [-h] [-q] [-p] [-s ####] [-e ####] [-v ##]\n" );
    if ( how_much == LITTLE ) return( FALSE );
    cprintf( "Where:\n" );
    cprintf( "  -m greeting message  - this will be spoken before the time\n" );
    cprintf( "  -f  - this will cause the alarm to sound every quarter hour\n" );
    cprintf( "  -t  - this will cause the alarm to sound every half hour\n" );
    cprintf( "  -h  - this will cause the alarm to sound every hour\n" );
    cprintf( "  -p  - this will make the alarm contain a 't' to start speakers\n" );
    cprintf( "  -s #### - this will set the starting time to this time (2400 hr.)\n" );
    cprintf( "  -e #### - this will set the ending time to this time (2400 hr.)\n" );
    cprintf( "  -v ## - this will set the alarm volume to this (>0 and <=64)\n" );
    cprintf( "  -q  - this will remove all copies of SPUDclock from memory\n" );
    cprintf( "  -l  - this will list the current SPUDclock settings\n");
    cprintf( "  -d  - this will cause the parameters not specified on the\n");
    cprintf( "        command line to revert to their defaults\n");
    return( FALSE );
}   /* end of usage(); */

/************************************************************************
 *
 *  print_settings() - This routine prints the current SPUDclock settings
 *
 *  This section was written by H. Bret Young
 *  are Copyright (C) 1987 by H. Bret Young and The Man From S.P.U.D.
 *
 ************************************************************************/
void print_settings()
{
    char out[5];
    
    cprintf("SPUDclock settings \n\n");

    cprintf("  The alarm will sound  ");
    switch (alarm_mode) {
        case QUARTER_HOUR :
            cprintf("every QUARTER HOUR\n");
            break;
        case HALF_HOUR :
            cprintf("every HALF HOUR\n");
            break;
        case HOUR :
            cprintf("every HOUR\n");
            break;
    }

    if (prestart)
        cprintf("  The speakers WILL be prestarted\n");
    else
        cprintf("  The speakers WILL NOT be prestarted\n");

    cprintf("  The clock will begin at ");      
    itoa(out,start_alarm);
    cprintf(out); cprintf("\n");

    cprintf("  The clock will stop at ");    
    itoa(out,end_alarm);
    cprintf(out); cprintf("\n");

    cprintf("  The alarm volume is ");
    itoa(out,alarm_volume);
    cprintf(out); cprintf("\n");

    cprintf("  The alarm salutation is :\n");
    cprintf("   ");
    cprintf(salutation); cprintf("\n");
}

/************************************************************************
 *
 *  Main section of SPUDclock...
 *
 *  This and all code sections were written by Robert E. Beaty and
 *  H. Bret Young are Copyright (C) 1987 by H. Bret Young and R.E.Beaty
 *  and The Man From S.P.U.D.
 *
 ************************************************************************/
main( argc, argv )
int argc;
char *argv[];
{
    int i;
    int change_flags,
        changing,
        listing;

    /*
     *
     *  Set the defaults
     *
     */
    alarm_mode = HALF_HOUR;		/* do it every 30 minutes */
    prestart = FALSE;			/* don't prestart the speakers */
    start_alarm = 830;			/* start at 8:30 am */
    end_alarm = 2300;			/* end at 11:00 pm */
    alarm_volume = 50;			/* not too loud */
    stpcpy( salutation, " " );		/* no salutation to start off */
    cp = salutation;			/* this is for the argument processing */
    quit_flag = FALSE;			/* we aren't stopping yet */
    change_flags = 0;
    changing = FALSE;
    listing = FALSE;

    /*
     *
     *  Decode the arguments
     *
     */
    for ( i=1; i < argc; i++ ) {
        /* check the options */
        if ( argv[i][0] == '-' ) {
            /* decode the options */
            switch( argv[i][1] ) {
                case 'f' :
                    change_flags |= AM_BIT;
                    alarm_mode = QUARTER_HOUR;
                    break;
                case 't' :
                    change_flags |= AM_BIT;
                    alarm_mode = HALF_HOUR;
                    break;
                case 'h' :
                    change_flags |= AM_BIT;
                    alarm_mode = HOUR;
                    break;
                case 'q' :
                    quit_flag = TRUE;
                    break;
                case 'p' :
                    change_flags |= PS_BIT;
                    prestart = TRUE;
                    break;
                case 's' :
                    change_flags |= SA_BIT;
                    i++;	/* move to the next argument, the time */
                    start_alarm = 0;
                    while((*argv[i] >= '0') && (*argv[i] <= '9'))
                        start_alarm = (start_alarm * 10) + *argv[i]++ - '0';
                    break;
                case 'e' :
                    change_flags |= EA_BIT;
                    i++;	/* move to the next argument, the time */
                    end_alarm = 0;
                    while((*argv[i] >= '0') && (*argv[i] <= '9'))
                        end_alarm = (end_alarm * 10) + *argv[i]++ - '0';
                    break;
                case 'v' :
                    change_flags |= AV_BIT;
                    i++;	/* move to the next argument, the volume */
                    alarm_volume = 0;
                    while((*argv[i] >= '0') && (*argv[i] <= '9'))
                        alarm_volume = (alarm_volume * 10) + *argv[i]++ - '0';
                    break;
                case 'm' :
                    change_flags |= S_BIT;
                    /* read in the salutation a word at a time */
                    for ( i=i; (argv[i+1][0] != '-') && (i < argc); i++ ) {
                        cp = stpcpy( cp, argv[i+1] );
                        cp = stpcpy( cp, " ");
                    }    
                    break;
                case 'l' :
                    listing = TRUE;
                    break;
                case 'd' :
                    changing = TRUE;
                    break;
                default :
                    usage( LITTLE );	/* show him the small usage */
                    exit( TRUE );
                    break;
            }   /* end of decoding the options */
        }   /* end of checking the options */
        else {
            usage( BIG );	/* he needs lots of help */
            exit( TRUE );
        }
    }   /* end of decoding the arguments */

    /*
     * 
     *  O.K. all arguments are decoded, so let's see if one copy of
     *  SPUDclock already exists 
     *
     */
    /* Assume one does and do just a quick start */
    if ( (error=init( QUICK_START )) != FALSE ) {
        if ( error == CANT_OPEN_INTUITION ) {
            cprintf( "Sorry, but I cannot open a copy of Intuition!\n" );
            cprintf( "Please check your DEVS: directory or reboot.\n" );
        }    /* end of printing the error message */
        exit( error );
    }   /* end of error checking for the initial start */
    clockPort = (struct MsgPort *) FindPort( "SPUDclock" );
    if ( clockPort != NULL ) {
        /* Allocate the memory for the message to the other SPUDclock */
        outgoing = (struct PacketMessage *) AllocMem( sizeof(struct PacketMessage), MEMF_PUBLIC );
        if ( outgoing == NULL ) {
            cprintf( "Sorry, There is not enough memory to send the message\n" );
            cprintf( "to the running copy of SPUDclock. You will probably\n" );
            cprintf( "have to re-boot the machine to change the running copy\n" );
            cprintf( "of SPUDclock.\n" );
            clean( QUICK_EXIT );
            exit( TRUE );
        }   /* end of error checking the message allocation */

        /* Allocate the reply port for this message */
        replyPort = (struct MsgPort *) CreatePort( "SPUDclock.reply.port", TASK_PRIORITY );
        if ( replyPort == NULL ) {
            cprintf( "Sorry, There are not enough free resources to send the\n" );
            cprintf( "message to the running copy of SPUDclock. You will probably\n" );
            cprintf( "have to re-boot the machine to change the running copy\n" );
            cprintf( "of SPUDclock.\n" );
            /* free everything up */
            FreeMem( outgoing, sizeof(struct PacketMessage) );
            clean( QUICK_EXIT );
            exit( TRUE );
        }   /* end of error checking for port creation */

        /*
         * Now set this message packet so that it will do the job
         */
        outgoing->packet_message.mn_Node.ln_Type = NT_MESSAGE;
        outgoing->packet_message.mn_ReplyPort = replyPort;
        outgoing->packet_message.mn_Length = sizeof( struct PacketMessage );
        /* Get the status from the packet */
        outgoing->alarm_mode = alarm_mode;
        outgoing->prestart = prestart;
        outgoing->start_alarm = start_alarm;
        outgoing->end_alarm = end_alarm;
        outgoing->alarm_volume = alarm_volume;
        stpcpy( outgoing->salutation, salutation );
        outgoing->quit_flag = quit_flag;
        outgoing->change_flags = change_flags;
        outgoing->changing = changing;
        outgoing->listing = listing;
        

        /*
         * Send it, wait for a reply, and then dispose of all of it
         */
        PutMsg( clockPort, outgoing );
        WaitPort( replyPort );
        /* free everything up */
        DeletePort( replyPort );
        FreeMem( outgoing, sizeof(struct PacketMessage) );
        clean( QUICK_EXIT );
        exit( TRUE );
    }   /* end of passing arguments to the running SPUDclock */

    /* Print a copyright notice */
    cprintf( "SPUDclock v1.2 - Copyright 1987 by The Man From S.P.U.D.\n" );
    
    if (listing) print_settings();

    /* If quitting was our only motive, then quit */
    if ( quit_flag ) {
        clean( QUICK_EXIT );
        exit( FALSE );
    }   /* end of quick quit */

    /* We need to do a normal start */
    if ( (error=init( NORMAL_START )) != FALSE ) {
        /* decode the error */
        switch ( error ) {
            case CANT_OPEN_INTUITION :
                cprintf( "Sorry, but I cannot open a copy of Intuition!\n" );
                cprintf( "Please check your DEVS: directory or reboot.\n" );
                break;
            case CANT_OPEN_TRANSLATOR :
                cprintf( "Sorry, but I cannot open a copy of the\n" );
                cprintf( "Translator device! Please check your DEVS:\n" );
                cprintf( "directory for the narrator.device file\n" );
                cprintf( "and/or reboot.\n" );
                break;
            case CANT_OPEN_NARRATOR :
                cprintf( "Sorry, but I cannot open a copy of the\n" );
                cprintf( "Narrator device! Please check your DEVS:\n" );
                cprintf( "directory for the narrator.device file\n" );
                cprintf( "and/or reboot.\n" );
                break;
            case CANT_OPEN_TIMER :
                cprintf( "Sorry, but I cannot open a copy of the\n" );
                cprintf( "Timer device! Please check your DEVS:\n" );
                cprintf( "directory and/or reboot.\n" );
                break;
            case CREATE_PORT_PROBLEMS :
                cprintf( "Sorry, There are not enough free resources to open the\n" );
                cprintf( "message ports required. You will probably have to re-boot\n" );
                cprintf( "the machine to run SPUDclock.\n" );
                break;
            case CREATE_IO_PROBLEMS :
                cprintf( "Sorry, There are not enough free resources to open the\n" );
                cprintf( "I/O ports required. You will probably have to re-boot\n" );
                cprintf( "the machine to run SPUDclock.\n" );
                break;
            case TRANSLATOR_NOT_WORKING :
                cprintf( "Sorry, but the Translator device does not seem to be working\n" );
                cprintf( "at this time. The only suggestion is to re-boot the machine\n" );
                cprintf( "and/or get a fresh copy of narrator.device into DEVS:.\n" );
                break;
            default :
                cprintf( "Sorry, but SPUDclock has returned an error.\n" );
                cprintf( "Please try running it again.\n" );
                break;
        }   /* end of decoding the error and printing the error message */
        exit( error );
    }   /* end of error checking the start-up of the original copy */


    /* Submit a little sleep */
    bed_bye( LITTLE );

    while( TRUE ) {
        /*
         *  Now wait until something wakes us up
         */
        signal = Wait( timer_signal | port_signal );
        /*
         *
         * ... check the timer
         *
         */
        if ( signal & timer_signal ) {
            /* get the message out of the way */
            (void) GetMsg( timerPort );
            /* Get the time now */
            DateStamp( &now );
            /* Get the time into hours and minutes */
            hours_24 = now.ds_Minute / 60;
            hours_12 = ( now.ds_Minute / 60 ) % 12;
            if ( hours_12 == 0 ) hours_12 = 12;		/* make it simple 12 hour */
            minutes = now.ds_Minute % 60;
            /*
             *  See if we are synced up yet
             */
            if ( (minutes == 0) || (minutes == 15) || (minutes == 30) || (minutes == 45) ) {
                /* submit a nice long wake up call */
                bed_bye( BIG );
                /*
                 *  Now see if we need to output this to the speakers
                 */
                alarm_time = hours_24 * 100 + minutes;
                if ( (alarm_time >= start_alarm) && (alarm_time <= end_alarm) )
                    speak_time( hours_12, minutes );
            }   /* end of processing for synced up */
            else {
                /* submit another wake up call soon */
                bed_bye( LITTLE );
            }   /* end of processing for not synced up */
        }   /* end of processing the timer signal */
 
        /*
         *
         * ... check the clock port 
         *
         */
        if ( signal & port_signal ) {
            /* Get the message */
            incoming = (struct PacketMessage *) GetMsg( clockPort );
            /* Get the status from the packet */
            
            changing = incoming->changing;
            change_flags = incoming->change_flags;
            listing = incoming->listing;
            quit_flag = incoming->quit_flag;

            switch (changing) {
                case FALSE :
                    if (change_flags & AM_BIT)
	                alarm_mode = incoming->alarm_mode;
                    if (change_flags & PS_BIT)
                        prestart = incoming->prestart;
                    if (change_flags & SA_BIT)
	                start_alarm = incoming->start_alarm;
                    if (change_flags & EA_BIT)
	                end_alarm = incoming->end_alarm;
                    if (change_flags & AV_BIT)
                        alarm_volume = incoming->alarm_volume;
                    if (change_flags & S_BIT)
	                stpcpy( salutation, incoming->salutation );
	            break;
	        case TRUE :
	            alarm_mode = incoming->alarm_mode;
                    prestart = incoming->prestart;
	            start_alarm = incoming->start_alarm;
	            end_alarm = incoming->end_alarm;
                    alarm_volume = incoming->alarm_volume;
	            stpcpy( salutation, incoming->salutation );
	            break;
	    }

            if (listing) print_settings();

            /* since we didn't allocate this message, we must reply */
            ReplyMsg( incoming );
            
            /*
             * If the quit flag is set then we need to leave
             */
            if ( quit_flag ) {
                clean( NORMAL_EXIT );	/* clean all this up */
                exit( FALSE );
            }   /* end of quitting */

        }   /* end of processing the port signal */
    }   /* end of main loop */    

    /* we need this to keep the compiler happy */
    return( FALSE );
}   /* end of SPUDclock(); */
