/*- * Copyright (c) 2020-2021 Carsten Sonne Larsen * 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 #include #include #include #include #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; }