
/*
 * All command functions have the same set of arguments.  An
 * integer (the socket FD) followed by a string.  The "real"
 * arguments are contained in the string.  Command functions
 * are free to treat this string any way they want to.  Many
 * commands simply ignore it.  If however you need to pass
 * floating point, string or integer data to your command
 * here is an example of how to do it.  Notice in the example
 * below the nere paranoiia about error checking and logging.
 * You cannot do to much of this.  Clients can and will send
 * abusive data and without such nere paranoiia the server
 * can crash.  Also when it is 3:00am and you are trying to
 * debug a program, having a log message that points to the
 * souce code file and line number and prints the suspect bad
 * data can be a real help.
 * 
 * Command functions do not need to send any data back to thier
 * client.  If they choose to they must use the sl_Send2Client()
 * function to send newline terminated lines of test.  Binary
 * data is not allowed.
 * 
 * Succues or failure of the command function is normally
 * communicated back to the client by the command function's
 * return code.  The Mk4d server will look at the value returned
 * and send the required protocol.  You may also send informative
 * text to the client but remember that ssome clients are programs
 * that do not pass this test on to the user.  A failure is
 * caused b a programming error and should be uncommon after
 * the software is operational.  But still "bugs happen" and
 * crashing a server process is unacceptable.
 */ 
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include "MLog.h"
#include "server_lib.h"
#include "commands.h"
#include "tasks.h"
#include "time_funct.h"

/* Common string used in lots of places */
static const char    LocMsg[] = "        %s:%d <%s>\n";

/********************************************************************/
/*                                                                  */
/*  cmd_example_arguments                                           */
/*                                                                  */
/*                                                                  */
/*  PURPOSE:    To show by example how to parse arguments.  One of  */
/*              each type is passed in an ASCII string.  Commands   */
/*              must parse tier argument strings themselves.        */
/*              Here is a test example.                             */
/*                                                                  */
/*  ARGUMENTS:  A string with the following fields                  */
/*                1) float                                          */
/*                2) doublet                                        */
/*                3) int                                            */
/*                4) string                                         */
/*                                                                  */
/********************************************************************/
int cmd_example_arguments(int sd, char args[])
{
    /* These are the argument expected in the args[] string */
    /* they must appear in the order shown.                 */
    float   fee;
    double  fie;
    int     foe;
    char    fum[80];

    /* Used internally */
    char    FaiureMsg1[] =
        "WARNING invalid argument passed to cmd_example_arguments\n";
    int     nargs;
    char    line[80];
    int     res;
    

    /* convert the args[] string to values.  First check for sanity */
    if ( !args )
    {
        /* null pointer */
        ml_print (ML_MANDATORY, ML_ERROR, FaiureMsg1);
        ml_printf(ML_MANDATORY, ML_ERROR, LocMsg,
            __FILE__, __LINE__, "(null pointer)");
        return CMD_FAIL;
    }
    if ( strlen(args) < 7 )
    {
        /* to short to be valid */
        ml_print (ML_MANDATORY, ML_ERROR, FaiureMsg1);
        ml_printf(ML_MANDATORY, ML_ERROR, LocMsg,
            __FILE__, __LINE__, args);
        return CMD_FAIL;
    }

    /* convert string and return count of arguments */
    nargs = sscanf(args, "%f %lf %d %s", &fee, &fie, &foe, fum);
  
    if (nargs != 4)
    {
        /* Some error in args string detected */
        ml_print (ML_MANDATORY, ML_ERROR, FaiureMsg1);
        ml_printf(ML_MANDATORY, ML_ERROR, LocMsg,
            __FILE__, __LINE__, args);
        return CMD_FAIL;
    }

    /* If we get to this point we know the arguments are  */
    /* converted with no errors.  We still need to do a   */
    /* range check                                        */

    if ( (fee > 10000.0) || (fee < -10000.0) )
    {
         /* fee is out of it's valid range */
        ml_print (ML_MANDATORY, ML_ERROR, FaiureMsg1);
        ml_printf(ML_MANDATORY, ML_ERROR, LocMsg,
            __FILE__, __LINE__, args);
        return CMD_FAIL;
    }

    /* Finally, we know we have good input and can proceed     */
    /* As this is just an example all we do here is send a     */
    /* back to the client saying what the parameter values are */

    snprintf(line, sizeof(line), 
       "fee: %f, fie: %f, foe: %d, fum: %s\n", fee, fie, foe, fum);

    /* send line to client and check for error */
    res = sl_Send2Client(sd, line);
    if (res < 0)
    {
        /* error sending command.  Client died? */
        ml_printf(ML_MANDATORY, ML_ERROR,
            "ERROR: Send to client failed on socket %d\n", sd);
        ml_printf(ML_MANDATORY, ML_ERROR, LocMsg,
            __FILE__, __LINE__, line);
        return CMD_FAIL;
    }

    /* We are done.  Send positive return code. */
    return CMD_OK;
}    


/********************************************************************/
int cmd_example_task(int sd, char args[])
{
    int res;
    char    line[80];
    
    /* send line to client and check for error */
    res = sl_Send2Client(sd, "example task is started\n");
    if (res < 0)
    {
        /* error sending command.  Client died? */
        ml_printf(ML_MANDATORY, ML_ERROR,
            "ERROR: Send to client failed on socket %d\n", sd);
        ml_printf(ML_MANDATORY, ML_ERROR, LocMsg,
            __FILE__, __LINE__, line);
        return CMD_FAIL;
    }
    
    /* We will ask that _this_ command be run again in 15 second */
    res = AddTask(cmd_example_task, "example_task", " ", sd, get_epoc()+15.0);
    if (res < 0)
    {
        /* error sending command.  Client died? */
        ml_printf(ML_MANDATORY, ML_ERROR,
            "ERROR: Could not add task to task table\n");
        ml_printf(ML_MANDATORY, ML_ERROR, LocMsg,
            __FILE__, __LINE__, line);
        return CMD_FAIL;
    }
    
    /* send line to client and check for error */
    res = sl_Send2Client(sd, "example task is ending\n");
    if (res < 0)
    {
        /* error sending command.  Client died? */
        ml_printf(ML_MANDATORY, ML_ERROR,
            "ERROR: Send to client failed on socket %d\n", sd);
        ml_printf(ML_MANDATORY, ML_ERROR, LocMsg,
            __FILE__, __LINE__, line);
        return CMD_FAIL;
    }
    
    /* No errors detected so must be OK */
    return CMD_OK;
}
