Keep your time right
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

832 lines
24 KiB

/*-
* Copyright (c) 2020-2021 Carsten Sonne Larsen <cs@innolan.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#include "global.h"
#include "string.h"
#include "message.h"
#include "setting.h"
#include "text.h"
#include "sync.h"
#include "conv.h"
#include "mem.h"
#include "win.h"
#include "val.h"
#include "tz.h"
#include <proto/rexxsyslib.h>
#include <proto/alib.h>
#include <rexx/errors.h>
#include <rexx/storage.h>
#include <rexx/rxslib.h>
#include "logmod.h"
#define MODULENAME "ARexx"
static char *arexxHelpText = NULL;
typedef void (*ARexxCommand)(struct RexxMsg *, char **);
struct ARexxCommandDef
{
/* Unique numeric command identifier */
const int Identifier;
/* Command name as exposed in ARexx interface */
const char *Name;
/* Short description of command purpose */
const char *Description;
/* Function pointer to action code */
ARexxCommand Command;
/* True if command only return a result. False is command is an action */
bool ResultCommand;
/* Number of parameters / arguments */
int Parameters;
};
struct ARexxParameterDef
{
const int Identifier;
const char *Keyword;
};
static void ARexxIdentifierCommand(struct RexxMsg *, char **);
static void ARexxVersionCommand(struct RexxMsg *, char **);
static void ARexxHelpCommand(struct RexxMsg *, char **);
static void ARexxStatusCommand(struct RexxMsg *, char **);
static void ARexxTimezoneCommand(struct RexxMsg *msg, char **);
static void ARexxLastSyncCommand(struct RexxMsg *msg, char **);
static void ARexxLastAdjustCommand(struct RexxMsg *msg, char **);
static void ARexxGetValueCommand(struct RexxMsg *, char **);
static void ARexxSetValueCommand(struct RexxMsg *, char **);
static void ARexxNowCommand(struct RexxMsg *, char **);
static void ARexxShowCommand(struct RexxMsg *, char **);
static void ARexxHideCommand(struct RexxMsg *, char **);
static void ARexxStartCommand(struct RexxMsg *, char **);
static void ARexxStopCommand(struct RexxMsg *, char **);
static void ARexxShutdownCommand(struct RexxMsg *, char **);
static void ARexxLogTransitionsCommand(struct RexxMsg *, char **);
#define AREXX_COMMAND_COUNT 16
static struct ARexxCommandDef arexxCommands[] = {
{1, "ID", "Get application identifier", ARexxIdentifierCommand, true, 0},
{2, "VERSION", "Get application version number", ARexxVersionCommand, true, 0},
{3, "HELP", "Get a list of ARexx commands and a short description", ARexxHelpCommand, true, 0},
{4, "STATUS", "Get current synchronization status", ARexxStatusCommand, true, 1},
{5, "TIMEZONE", "Get current time zone", ARexxTimezoneCommand, true, 1},
{6, "LASTSYNC", "Get time of last synchronization operation", ARexxLastSyncCommand, true, 2},
{7, "LASTADJ", "Get time of last clock adjustment", ARexxLastAdjustCommand, true, 2},
{8, "GET", "Get a runtime configuration value", ARexxGetValueCommand, true, 1},
{9, "SET", "Set a runtime configuration value", ARexxSetValueCommand, false, 2},
{10, "NOW", "Get current time and date", ARexxNowCommand, false, 2},
{11, "SHOW", "Show settings window", ARexxShowCommand, false, 0},
{12, "HIDE", "Hide settings window", ARexxHideCommand, false, 0},
{13, "START", "Start the time synchronization process", ARexxStartCommand, false, 0},
{14, "STOP", "Stop the time synchronization process", ARexxStopCommand, false, 0},
{15, "SHUTDOWN", "Shutdown " APP_SHORT_NAME, ARexxShutdownCommand, false, 0},
{16, "LOGTRANS", "Emit time zone transition map to log", ARexxLogTransitionsCommand, false, 0}};
#define AREXX_PARAMETER_SERVER 1
#define AREXX_PARAMETER_PORT 2
#define AREXX_PARAMETER_THRESHOLD 3
#define AREXX_PARAMETER_INTERVAL 4
#define AREXX_PARAMETER_PRIORITY 5
#define AREXX_PARAMETER_POPKEY 6
#define AREXX_PARAMETER_POPUP 7
#define AREXX_PARAMETER_READONLY 8
#define AREXX_PARAMETER_EXPERT 9
#define AREXX_PARAMETER_TIMEOUT 10
#define AREXX_PARAMETER_ACTIVE 11
#define AREXX_PARAMETER_NOLOG 12
#define AREXX_PARAMETER_TZ 13
#define AREXX_PARAMETER_TZD 14
#define AREXX_PARAMETER_TZNAME 15
#define AREXX_PARAMETER_TZVALUE 16
#define AREXX_PARAMETER_TZDST 17
#define AREXX_PARAMETER_LAST 17
#define AREXX_PARAMETER_UNKNOWN 90
#define AREXX_PARAMETER_MISSING 91
#define AREXX_PARAMETER_SHUTDOWN 92
#define AREXX_PARAMETER_COUNT AREXX_PARAMETER_LAST
static struct ARexxParameterDef arexxParameters[] = {
{AREXX_PARAMETER_SERVER, KEYWORD_SERVER},
{AREXX_PARAMETER_PORT, KEYWORD_PORT},
{AREXX_PARAMETER_THRESHOLD, KEYWORD_THRESHOLD},
{AREXX_PARAMETER_INTERVAL, KEYWORD_INTERVAL},
{AREXX_PARAMETER_PRIORITY, KEYWORD_PRIORITY},
{AREXX_PARAMETER_POPKEY, KEYWORD_POPKEY},
{AREXX_PARAMETER_POPUP, KEYWORD_POPUP},
{AREXX_PARAMETER_READONLY, KEYWORD_READONLY},
{AREXX_PARAMETER_EXPERT, KEYWORD_EXPERT},
{AREXX_PARAMETER_TIMEOUT, KEYWORD_TIMEOUT},
{AREXX_PARAMETER_ACTIVE, KEYWORD_ACTIVE},
{AREXX_PARAMETER_NOLOG, KEYWORD_NOLOG},
{AREXX_PARAMETER_TZ, KEYWORD_TZ},
{AREXX_PARAMETER_TZD, KEYWORD_TZD},
{AREXX_PARAMETER_TZNAME, KEYWORD_TZNAME},
{AREXX_PARAMETER_TZVALUE, KEYWORD_TZVALUE},
{AREXX_PARAMETER_TZDST, KEYWORD_TZDST}};
#define AREXX_MAX_ARGS_COUNT 8
struct ARexxErrorDef
{
const long Code;
const char **Text;
};
#define AREXX_ERROR_UNKNOWN_CMD 10 /* Unknown ARexx command */
#define AREXX_ERROR_UNKNOWN_PARM 11 /* Unknown parameter */
#define AREXX_ERROR_PARM_MISS 12 /* Parameter is missing */
#define AREXX_ERROR_PARM_INV 13 /* Invalid parameter value */
#define AREXX_ERROR_CLOCK_INV 18 /* Clock has not been adjusted */
#define AREXX_ERROR_SYNC_INV 19 /* No responses from NTP server */
#define AREXX_ERROR_SYNC_ON 20 /* Synchronization is already active */
#define AREXX_ERROR_SYNC_OFF 21 /*Synchronization is already deactivated */
#define AREXX_ERROR_COUNT 8
static struct ARexxErrorDef arexxErrors[] = {
{AREXX_ERROR_UNKNOWN_CMD, &TextARexxCmdUnknown},
{AREXX_ERROR_UNKNOWN_PARM, &TextARexxParmUnknown},
{AREXX_ERROR_PARM_MISS, &TextARexxParmMiss},
{AREXX_ERROR_PARM_INV, &TextARexxParmInvalid},
{AREXX_ERROR_CLOCK_INV, &TextNoClockAdjust},
{AREXX_ERROR_SYNC_INV, &TextNoResponses},
{AREXX_ERROR_SYNC_ON, &TextSyncAlreadyOn},
{AREXX_ERROR_SYNC_OFF, &TextSyncAlreadyOff}};
static void SplitAndTerminate(char *string, char **res)
{
char *p = string;
char **q = res;
int count = 1;
while (*p != '\0')
{
if (*p == ' ')
{
// Terminate
*p = '\0';
p++;
// Skip trailing spaces
while (*p == ' ')
p++;
*q = p;
q++;
count++;
// Bail out
if (count >= AREXX_MAX_ARGS_COUNT)
return;
}
else
{
p++;
}
}
}
static void BuildARexxHelpText(void)
{
char *p;
int i, line, len = 0;
if (arexxHelpText != NULL)
return;
len += 26; // Header
len += 71 * 2; // Spacer
len += StrLen(AREXX_ERROR_VAR_CODE) + StrLen(AREXX_ERROR_VAR_TEXT) + 32; // Footer
for (i = 0; i < AREXX_COMMAND_COUNT; i++)
{
len += StrLen(arexxCommands[i].Description) + 14;
}
arexxHelpText = (char *)AllocStringSafe(len);
if (arexxHelpText == NULL)
return;
p = AppendText(arexxHelpText, " Command | Description\n");
p = AppendChar(p, '-', 70);
p = AppendChar(p, '\n', 1);
for (i = 0; i < AREXX_COMMAND_COUNT; i++)
{
line = 10 - StrLen(arexxCommands[i].Name);
p = AppendChar(p, ' ', 1);
p = AppendText(p, arexxCommands[i].Name);
p = AppendChar(p, ' ', line);
p = AppendChar(p, '|', 1);
p = AppendChar(p, ' ', 1);
p = AppendText(p, arexxCommands[i].Description);
p = AppendChar(p, '\n', 1);
}
p = AppendChar(p, '-', 70);
p = AppendChar(p, '\n', 1);
p = AppendText(p, "Error status is set in ");
p = AppendText(p, AREXX_ERROR_VAR_CODE);
p = AppendText(p, " and ");
p = AppendText(p, AREXX_ERROR_VAR_TEXT);
}
void CleanupARexx(void)
{
if (arexxHelpText != NULL)
{
FreeMemSafe(arexxHelpText);
arexxHelpText = NULL;
}
}
static void SetARexxVar(struct RexxMsg *msg, const char *var, const char *text)
{
LONG error = SetRexxVar(msg, (CONST_STRPTR)var, (CONST_STRPTR)text, (LONG)StrLen(text));
if (error != 0)
{
LogWarn(TextARexxVarError, (long)error);
LogWarn(TextARexxVarValue, var, text);
}
else
{
LogTrace(TextARexxVarValue, var, text);
}
}
static void ARexxErrorClear(struct RexxMsg *msg)
{
SetARexxVar(msg, AREXX_ERROR_VAR_CODE, "0");
SetARexxVar(msg, AREXX_ERROR_VAR_TEXT, "");
}
static void ARexxError(struct RexxMsg *msg, long code)
{
char errorCode[MAXLONGCHARSIZE];
LongToStr(code, errorCode);
SetARexxVar(msg, AREXX_ERROR_VAR_CODE, errorCode);
int i;
for (i = 0; i < AREXX_ERROR_COUNT; i++)
{
if (arexxErrors[i].Code == code)
{
const char *text = *(arexxErrors[i].Text);
SetARexxVar(msg, AREXX_ERROR_VAR_TEXT, text);
break;
}
}
}
static void ARexxResult(struct RexxMsg *msg, const char *text)
{
if (msg->rm_Action & RXFF_RESULT)
{
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)text, (LONG)StrLen(text));
}
LogTrace(TextARexxResult, text);
ARexxErrorClear(msg);
}
static void ARexxResultLong(struct RexxMsg *msg, long value)
{
char text[MAXLONGCHARSIZE];
SNPrintf(text, MAXLONGCHARSIZE, "%ld", value);
ARexxResult(msg, text);
}
static void ARexxResultBool(struct RexxMsg *msg, char *parm, long value)
{
char text[MAXBOOLCHARSIZE];
if (Stricmp((STRPTR)parm, (STRPTR)KEYWORD_NUMBER) == 0)
BoolToStrNum(value, text);
else
BoolToStr(value, text);
ARexxResult(msg, text);
}
static void ARexxTimeResult(struct RexxMsg *msg, char **parms, struct timeval *utv, long error)
{
if (utv->tv_secs == 0 && utv->tv_micro == 0)
{
ARexxError(msg, error);
return;
}
bool utc;
STRPTR format = (STRPTR)*parms++;
if (Stricmp((STRPTR)*parms, (STRPTR)KEYWORD_UTC) == 0)
{
utc = true;
}
else if (*parms == NULL || Stricmp((STRPTR)*parms, (STRPTR)KEYWORD_LOCAL) == 0)
{
utc = false;
}
else
{
ARexxError(msg, AREXX_ERROR_PARM_INV);
return;
}
char result[DATETIME_TEXT_LEN + 1];
if (format == NULL || Stricmp(format, (STRPTR)KEYWORD_DOS) == 0)
Utc2DOS(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_ASCII) == 0)
Utc2ASCII(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_DATE) == 0)
Utc2ARexxDate(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_TIME) == 0)
Utc2ARexxTime(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_RFC850) == 0)
Utc2RFC850(utv, result);
else if (Stricmp(format, (STRPTR)KEYWORD_RFC1123) == 0)
Utc2RFC1123(utv, result);
else if (Stricmp(format, (STRPTR)KEYWORD_RFC2822) == 0)
Utc2RFC2822(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_RFC3339) == 0)
Utc2RFC3339(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_ISO8601) == 0)
Utc2ISO8601(utv, result, utc);
else
{
ARexxError(msg, AREXX_ERROR_PARM_INV);
return;
}
ARexxResult(msg, result);
}
static void ARexxIdentifierCommand(struct RexxMsg *msg, char **parms)
{
ARexxResult(msg, APP_TITLE);
}
static void ARexxVersionCommand(struct RexxMsg *msg, char **parms)
{
ARexxResult(msg, APP_VERSION);
}
static void ARexxHelpCommand(struct RexxMsg *msg, char **parms)
{
BuildARexxHelpText();
ARexxResult(msg, arexxHelpText);
}
static void ARexxStatusCommand(struct RexxMsg *msg, char **parms)
{
if (Stricmp((STRPTR)*parms, (STRPTR)KEYWORD_NUMBER) == 0)
{
char buf[4];
BoolToStrNum(SynchronizerRunning, buf);
ARexxResult(msg, buf);
}
else if (*parms == NULL)
{
const char *result = SynchronizerRunning ? TextSyncOn : TextSyncOff;
ARexxResult(msg, result);
}
else
{
ARexxError(msg, AREXX_ERROR_PARM_INV);
}
}
static void ARexxTimezoneCommand(struct RexxMsg *msg, char **parms)
{
long val;
if (parms == NULL)
{
ARexxError(msg, AREXX_ERROR_PARM_MISS);
}
else if (!TryParseLong(*parms, &val))
{
ARexxError(msg, AREXX_ERROR_PARM_INV);
}
else if (val < 1 || val > 12)
{
ARexxError(msg, AREXX_ERROR_PARM_INV);
}
else
{
char buf[TIMEZONE_TEXT_LEN];
GetTimezoneText(buf, val);
ARexxResult(msg, buf);
}
}
static void ARexxNowCommand(struct RexxMsg *msg, char **parms)
{
struct timeval tv;
GetTimeOfDay(&tv);
ARexxTimeResult(msg, parms, &tv, AREXX_ERROR_SYNC_INV);
}
static void ARexxLastSyncCommand(struct RexxMsg *msg, char **parms)
{
struct timeval tv = LastSync;
ARexxTimeResult(msg, parms, &tv, AREXX_ERROR_SYNC_INV);
}
static void ARexxLastAdjustCommand(struct RexxMsg *msg, char **parms)
{
struct timeval tv = LastAdjust;
ARexxTimeResult(msg, parms, &tv, AREXX_ERROR_CLOCK_INV);
}
static int ARexxFindParameter(char **parms)
{
int i;
char *parm = parms[0];
if (parm == NULL || *parm == '\0')
{
return AREXX_PARAMETER_MISSING;
}
for (i = 0; i < AREXX_PARAMETER_COUNT; i++)
{
if (Stricmp((STRPTR)parm, (STRPTR)arexxParameters[i].Keyword) == 0)
{
return arexxParameters[i].Identifier;
}
}
return AREXX_PARAMETER_UNKNOWN;
}
static void ARexxGetValueCommand(struct RexxMsg *msg, char **parms)
{
int param = ARexxFindParameter(parms++);
switch (param)
{
case AREXX_PARAMETER_UNKNOWN:
ARexxError(msg, AREXX_ERROR_UNKNOWN_PARM);
break;
case AREXX_PARAMETER_MISSING:
ARexxError(msg, AREXX_ERROR_PARM_MISS);
break;
case AREXX_PARAMETER_SERVER:
ARexxResult(msg, Settings->DestinationAddress);
break;
case AREXX_PARAMETER_PORT:
ARexxResult(msg, Settings->DestinationPort);
break;
case AREXX_PARAMETER_INTERVAL:
ARexxResultLong(msg, Settings->Interval);
break;
case AREXX_PARAMETER_PRIORITY:
ARexxResultLong(msg, Settings->Priority);
break;
case AREXX_PARAMETER_POPKEY:
ARexxResult(msg, Settings->PopKey);
break;
case AREXX_PARAMETER_POPUP:
ARexxResultBool(msg, *parms, Settings->Popup);
break;
case AREXX_PARAMETER_READONLY:
ARexxResultBool(msg, *parms, Settings->Readonly);
break;
case AREXX_PARAMETER_EXPERT:
ARexxResultBool(msg, *parms, Settings->Expert);
break;
case AREXX_PARAMETER_TIMEOUT:
ARexxResultLong(msg, Settings->Timeout);
break;
case AREXX_PARAMETER_ACTIVE:
ARexxResultBool(msg, *parms, SynchronizerRunning);
break;
case AREXX_PARAMETER_NOLOG:
ARexxResultBool(msg, *parms, Settings->NoLog);
break;
case AREXX_PARAMETER_TZ:
ARexxResult(msg, Settings->TZ);
break;
case AREXX_PARAMETER_TZD:
ARexxResultLong(msg, Settings->TimeZoneDisplay);
break;
case AREXX_PARAMETER_TZNAME:
ARexxResult(msg, Settings->TimeZoneName);
break;
case AREXX_PARAMETER_TZVALUE:
if (Settings->TimeZoneValue != TZVALUE_DEF)
ARexxResultLong(msg, Settings->TimeZoneValue);
else
ARexxResult(msg, "");
break;
case AREXX_PARAMETER_TZDST:
ARexxResultLong(msg, Settings->TimeZoneDst);
break;
case AREXX_PARAMETER_THRESHOLD:
{
char buf[MAXLONGLONGCHARSIZE];
LongLongToStr(Settings->Threshold, buf);
ARexxResult(msg, buf);
}
break;
default:
ARexxError(msg, AREXX_ERROR_UNKNOWN_PARM);
break;
}
}
static void ARexxSetValueCommand(struct RexxMsg *msg, char **parms)
{
int param = ARexxFindParameter(parms++);
char *valueString = *parms;
long long longlongValue;
long longValue;
bool boolValue;
switch (param)
{
case AREXX_PARAMETER_UNKNOWN:
ARexxError(msg, AREXX_ERROR_UNKNOWN_PARM);
break;
case AREXX_PARAMETER_MISSING:
ARexxError(msg, AREXX_ERROR_PARM_MISS);
break;
case AREXX_PARAMETER_SERVER:
SetServer(valueString, APPLY_VALUE);
ARexxErrorClear(msg);
break;
case AREXX_PARAMETER_PORT:
SetPort(valueString, APPLY_VALUE);
ARexxErrorClear(msg);
break;
case AREXX_PARAMETER_THRESHOLD:
if (TryParseLongLong(valueString, &longlongValue))
{
SetThreshold(valueString, APPLY_VALUE);
ARexxErrorClear(msg);
}
else
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_INTERVAL:
if (TryParseLong(valueString, &longValue))
{
SetInterval(longValue, APPLY_VALUE);
ARexxErrorClear(msg);
}
else
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_PRIORITY:
if (TryParseLong(valueString, &longValue))
{
SetPriority(valueString, APPLY_VALUE);
ARexxErrorClear(msg);
}
else
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_POPKEY:
// TODO: Remove CX filter object and add new filter (Settings->PopKey)
// http://amigadev.elowar.com/read/ADCD_2.1/Libraries_Manual_guide/node0587.html
ARexxError(msg, AREXX_ERROR_UNKNOWN_PARM);
break;
case AREXX_PARAMETER_POPUP:
if (TryParseBoolean(valueString, &boolValue))
{
Settings->Popup = boolValue;
ARexxErrorClear(msg);
}
else
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_READONLY:
if (TryParseBoolean(valueString, &boolValue))
{
Settings->Readonly = boolValue;
ARexxErrorClear(msg);
}
else
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_EXPERT:
if (TryParseBoolean(valueString, &boolValue))
{
Settings->Expert = boolValue;
SendWindowMessage(ATK_SHUTDOWN);
ShowSettingWindow();
ARexxErrorClear(msg);
}
else
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_TIMEOUT:
if (TryParseLong(valueString, &longValue))
{
SetTimeout(longValue, APPLY_VALUE);
ARexxErrorClear(msg);
}
else
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_ACTIVE:
if (TryParseBoolean(valueString, &boolValue))
{
if (boolValue)
ARexxStartCommand(msg, NULL);
else
ARexxStopCommand(msg, NULL);
}
else
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_NOLOG:
if (TryParseBoolean(valueString, &boolValue))
{
Settings->NoLog = boolValue;
ARexxErrorClear(msg);
}
else
ARexxError(msg, AREXX_ERROR_PARM_INV);
case AREXX_PARAMETER_TZ:
SetTimeZoneSetting(SettingKeys->TZ, &Settings->TZ, valueString, APPLY_VALUE);
break;
case AREXX_PARAMETER_TZD:
SetTimeZoneSettingLong(SettingKeys->TimeZoneDisplay, &Settings->TimeZoneDisplay, valueString, APPLY_VALUE);
break;
case AREXX_PARAMETER_TZNAME:
SetTimeZoneSetting(SettingKeys->TimeZoneName, &Settings->TimeZoneName, valueString, APPLY_VALUE);
break;
case AREXX_PARAMETER_TZVALUE:
SetTimeZoneSettingLong(SettingKeys->TimeZoneValue, &Settings->TimeZoneValue, valueString, APPLY_VALUE);
break;
case AREXX_PARAMETER_TZDST:
SetTimeZoneSettingLong(SettingKeys->TimeZoneDst, &Settings->TimeZoneDst, valueString, APPLY_VALUE);
break;
default:
ARexxError(msg, AREXX_ERROR_UNKNOWN_PARM);
break;
}
}
static void ARexxShowCommand(struct RexxMsg *msg, char **parms)
{
ShowSettingWindow();
ARexxErrorClear(msg);
}
static void ARexxHideCommand(struct RexxMsg *msg, char **parms)
{
SendWindowMessage(ATK_SHUTDOWN);
ARexxErrorClear(msg);
}
static void ARexxStartCommand(struct RexxMsg *msg, char **parms)
{
if (!SynchronizerRunning)
{
Activate();
ARexxErrorClear(msg);
}
else
{
ARexxError(msg, AREXX_ERROR_SYNC_ON);
}
}
static void ARexxStopCommand(struct RexxMsg *msg, char **parms)
{
if (SynchronizerRunning)
{
Deactivate();
ARexxErrorClear(msg);
}
else
{
ARexxError(msg, AREXX_ERROR_SYNC_OFF);
}
}
static void ARexxShutdownCommand(struct RexxMsg *msg, char **parms)
{
LogWarn(TextARexxShutdown);
msg->rm_Result1 = AREXX_PARAMETER_SHUTDOWN;
ARexxErrorClear(msg);
}
static void ARexxLogTransitionsCommand(struct RexxMsg *msg, char **parms)
{
LogTransitionMap();
ARexxErrorClear(msg);
}
static void ExecuteARexxCommand(struct RexxMsg *msg, struct ARexxCommandDef *cmd, char **parms)
{
LogNotice(TextARexxReceived, cmd->Name);
bool execute = !cmd->ResultCommand || (cmd->ResultCommand && (msg->rm_Action & RXFF_RESULT));
if (execute)
{
if (parms == NULL)
LogTrace(TextARexxExecute1, cmd->Name);
else
LogTrace(TextARexxExecute2, cmd->Name, *parms);
cmd->Command(msg, parms);
}
}
static bool HandleARexxMessage(struct RexxMsg *msg)
{
int i;
bool found = false;
bool cont = true;
for (i = 0; i < AREXX_COMMAND_COUNT; i++)
{
struct ARexxCommandDef *cmd = &arexxCommands[i];
if (cmd->Parameters == 0 && Stricmp((STRPTR)msg->rm_Args[0], (STRPTR)cmd->Name) == 0)
{
ExecuteARexxCommand(msg, cmd, NULL);
found = true;
break;
}
}
if (!found)
{
char *args[AREXX_MAX_ARGS_COUNT];
char *buf = AllocStringSafe(StrLen(msg->rm_Args[0]) + 1);
StrCopy(buf, msg->rm_Args[0]);
for (i = 0; i < AREXX_MAX_ARGS_COUNT; i++)
{
args[i] = NULL;
}
SplitAndTerminate(buf, args);
for (i = 0; i < AREXX_COMMAND_COUNT; i++)
{
struct ARexxCommandDef *cmd = &arexxCommands[i];
if (cmd->Parameters > 0 && Stricmp((STRPTR)buf, (STRPTR)cmd->Name) == 0)
{
ExecuteARexxCommand(msg, cmd, args);
found = true;
break;
}
}
FreeMemSafe(buf);
}
if (!found)
{
ARexxError(msg, AREXX_ERROR_UNKNOWN_CMD);
}
else if (msg->rm_Result1 == AREXX_PARAMETER_SHUTDOWN)
{
cont = false;
}
return cont;
}
bool HandleARexxMessages(void)
{
bool cont = true;
struct RexxMsg *msg;
while ((msg = (struct RexxMsg *)GetNewMessage(MSGPORT_AREXX)))
{
if (CheckRexxMsg(msg))
{
cont &= HandleARexxMessage(msg);
msg->rm_Result1 = RC_OK;
}
ReplyMsg((struct Message *)msg);
}
return cont;
}