AmiTimeKeeper/broker.c

559 lines
14 KiB
C
Raw Permalink Normal View History

2018-11-24 21:39:18 +00:00
/*-
2021-01-12 22:16:18 +00:00
* Copyright (c) 2017-2021 Carsten Sonne Larsen <cs@innolan.net>
2018-11-24 21:39:18 +00:00
* 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.
2021-01-12 22:00:49 +00:00
*
2018-11-24 21:39:18 +00:00
*/
#include "config.h"
2021-01-12 22:02:29 +00:00
#include "global.h"
#include "notify.h"
2018-11-24 21:39:18 +00:00
#include "message.h"
2021-01-12 22:02:29 +00:00
#include "setting.h"
#include "shutdown.h"
2021-01-12 22:16:18 +00:00
#include "text.h"
2021-01-12 22:02:29 +00:00
#include "sync.h"
2018-11-24 21:39:18 +00:00
#include "mem.h"
#include "win.h"
2021-01-12 22:02:29 +00:00
#include "tz.h"
2018-11-24 21:39:18 +00:00
2021-01-12 22:16:18 +00:00
#if defined(SCREENNOTIFY)
2021-01-12 22:02:29 +00:00
#include "libraries/screennotify.h"
2021-01-12 22:16:18 +00:00
#endif
2021-01-12 22:02:29 +00:00
#include "logmod.h"
#define MODULENAME "Main"
2021-01-12 21:53:12 +00:00
#define EVT_HOTKEY 1L
2021-01-12 22:02:29 +00:00
static void MsgLoop(void);
2021-01-12 21:53:12 +00:00
static void CleanupBroker(void);
2018-11-24 21:39:18 +00:00
2021-01-12 22:02:29 +00:00
struct AppBroker
{
CxObj *Object;
2021-01-12 22:16:18 +00:00
struct MsgPort *CommodityPort;
2021-01-12 22:02:29 +00:00
struct MsgPort *NotifyPort;
struct MsgPort *ScreenPort;
APTR screenNotifyWB;
APTR screenNotifyPub;
};
2018-11-24 21:39:18 +00:00
static struct NewBroker newBroker = {
NB_VERSION,
(STRPTR)APP_SHORT_NAME,
(STRPTR)APP_TITLE_VERSION,
(STRPTR) "Synchronize Clock With Internet Servers",
NBU_UNIQUE | NBU_NOTIFY,
COF_SHOW_HIDE,
0, 0, 0};
2021-01-12 22:16:18 +00:00
static struct AppBroker Broker = {NULL, NULL, NULL, NULL, NULL, NULL};
2021-01-12 22:02:29 +00:00
static volatile bool BrokerRunning = false;
2018-11-24 21:39:18 +00:00
void StartBroker(void)
{
LONG error;
2021-01-12 21:53:12 +00:00
CxObj *filter, *sender, *translate;
2021-01-12 22:16:18 +00:00
bool init = SetupPorts();
if (!init)
2018-11-24 21:39:18 +00:00
{
return;
}
2021-01-12 22:16:18 +00:00
LogInfo(TextInitComponent, "commodity");
Broker.CommodityPort = CreateMsgPort();
if (Broker.CommodityPort == NULL)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:16:18 +00:00
LogError(TextPortInitError, "commodity");
2021-01-12 21:53:12 +00:00
CleanupBroker();
2018-11-24 21:39:18 +00:00
return;
}
2021-01-12 22:02:29 +00:00
Broker.NotifyPort = CreateMsgPort();
if (Broker.NotifyPort == NULL)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:16:18 +00:00
LogError(TextPortInitError, "notify");
2021-01-12 21:53:12 +00:00
CleanupBroker();
2018-11-24 21:39:18 +00:00
return;
}
2021-01-12 22:02:29 +00:00
Broker.ScreenPort = CreateMsgPort();
if (Broker.ScreenPort == NULL)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:16:18 +00:00
LogError(TextPortInitError, "screen");
2021-01-12 22:02:29 +00:00
CleanupBroker();
return;
}
2021-01-12 22:16:18 +00:00
newBroker.nb_Port = Broker.CommodityPort;
2021-01-12 22:02:29 +00:00
newBroker.nb_Pri = Settings->Priority;
2018-11-24 21:39:18 +00:00
2021-01-12 22:02:29 +00:00
Broker.Object = CxBroker(&newBroker, &error);
if (!Broker.Object)
2018-11-24 21:39:18 +00:00
{
switch (error)
{
case CBERR_SYSERR:
LogError("System problems (CBERR_SYSERR). Could not allocate broker object");
break;
case CBERR_DUP:
2021-01-31 19:10:59 +00:00
LogWarn(Text2P, APP_SHORT_NAME, TextAlreadyRunning);
2018-11-24 21:39:18 +00:00
break;
default:
LogError("Could not allocate broker object (error code: %ld)", error);
break;
}
2021-01-12 21:53:12 +00:00
CleanupBroker();
return;
}
2021-01-12 22:02:29 +00:00
filter = CxFilter(Settings->PopKey);
2021-01-12 21:53:12 +00:00
if (filter == NULL)
{
LogError("Could not allocate broker filter object");
CleanupBroker();
return;
}
2021-01-12 22:02:29 +00:00
AttachCxObj(Broker.Object, filter);
2021-01-12 21:53:12 +00:00
2021-01-12 22:16:18 +00:00
sender = CxSender(Broker.CommodityPort, EVT_HOTKEY);
2021-01-12 21:53:12 +00:00
if (sender == NULL)
{
LogError("Could not allocate broker sender object");
CleanupBroker();
return;
}
AttachCxObj(filter, sender);
translate = CxTranslate(NULL);
if (translate == NULL)
{
LogError("Could not allocate broker translate object");
CleanupBroker();
2018-11-24 21:39:18 +00:00
return;
}
2021-01-12 21:53:12 +00:00
AttachCxObj(filter, translate);
error = CxObjError(filter);
if (error != 0)
{
switch (error)
{
case CBERR_SYSERR:
2021-01-12 22:02:29 +00:00
LogWarn("Commodity filter problems (CBERR_SYSERR)");
2021-01-12 21:53:12 +00:00
break;
case COERR_BADFILTER:
2021-01-12 22:02:29 +00:00
LogWarn("Commodity HOTKEY error");
2021-01-12 21:53:12 +00:00
break;
default:
2021-01-12 22:02:29 +00:00
LogWarn("Commodity filter error (error code: %ld)", error);
2021-01-12 21:53:12 +00:00
break;
}
}
2021-01-12 22:16:18 +00:00
#if defined(SCREENNOTIFY)
2021-01-12 22:02:29 +00:00
if (ScreenNotifyBase != NULL)
{
Broker.screenNotifyWB = AddWorkbenchClient(Broker.ScreenPort, 0);
Broker.screenNotifyPub = AddPubScreenClient(Broker.ScreenPort, 0);
LogTrace("AddWorkbenchClient");
}
2021-01-12 22:16:18 +00:00
#endif
2018-11-24 21:39:18 +00:00
2021-01-12 22:02:29 +00:00
ActivateNotifyPort(Broker.NotifyPort);
2021-01-31 19:10:59 +00:00
if (Settings->Active)
{
ActivateCxObj(Broker.Object, 1);
StartSynchronizer();
}
2018-11-24 21:39:18 +00:00
2021-01-12 22:02:29 +00:00
MsgLoop();
2018-11-24 21:39:18 +00:00
2021-01-12 21:53:12 +00:00
CleanupBroker();
2021-01-12 22:16:18 +00:00
CleanupPorts();
2018-11-24 21:39:18 +00:00
}
2021-01-12 22:02:29 +00:00
bool IsBrokerRunning(void)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:02:29 +00:00
return BrokerRunning;
2018-11-24 21:39:18 +00:00
}
void SetBrokerPriority(int priority)
{
2021-01-12 22:02:29 +00:00
SetCxObjPri(Broker.Object, priority);
}
2021-01-12 22:16:18 +00:00
void Deactivate(void)
2021-01-12 22:02:29 +00:00
{
2021-01-12 22:16:18 +00:00
if (SynchronizerRunning)
{
2021-01-31 19:10:59 +00:00
LogNotice(KEYWORD_ACTIVE " changed: 1 -> 0");
2021-01-12 22:16:18 +00:00
LogWarn("Disabling time synchronization");
SendMessageWait(MSGPORT_SYNCER, ATK_DISABLE);
ActivateCxObj(Broker.Object, 0);
}
else
{
2021-01-31 19:10:59 +00:00
LogError(TextSyncAlreadyOff);
2021-01-12 22:16:18 +00:00
}
2018-11-24 21:39:18 +00:00
}
2021-01-12 22:16:18 +00:00
void Activate(void)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:16:18 +00:00
if (!SynchronizerRunning)
{
2021-01-31 19:10:59 +00:00
LogNotice(KEYWORD_ACTIVE " changed: 0 -> 1");
2021-01-12 22:16:18 +00:00
LogWarn("Enabling time synchronization");
ActivateCxObj(Broker.Object, 1);
StartSynchronizer();
}
else
{
2021-01-31 19:10:59 +00:00
LogError(TextSyncAlreadyOn);
2021-01-12 22:16:18 +00:00
}
2018-11-24 21:39:18 +00:00
}
2021-01-12 22:02:29 +00:00
static void ChangeTimezone(void)
{
InitTimezone();
2021-01-12 22:16:18 +00:00
SendWindowMessage(ATK_TZ_CHANGED);
2021-01-12 22:02:29 +00:00
}
static void ChangeTimezoneDelayedProc(void)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:02:29 +00:00
Delay(15 * 50);
ChangeTimezone();
2021-01-12 22:16:18 +00:00
SendWindowMessage(ATK_TZ_CHANGED);
2018-11-24 21:39:18 +00:00
}
2021-01-12 22:02:29 +00:00
static void ChangeTimezoneDelayed(void)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:02:29 +00:00
CreateNewProcTags(
NP_Entry, (IPTR)ChangeTimezoneDelayedProc,
NP_StackSize, 16 * 1024,
NP_Name, 0,
NP_Input, 0,
NP_Output, 0,
NP_Error, 0,
NP_CloseInput, FALSE,
NP_CloseOutput, FALSE,
NP_CloseError, FALSE,
NP_WindowPtr, 0,
NP_ConsoleTask, 0,
NP_Cli, FALSE,
TAG_DONE);
}
2018-11-24 21:39:18 +00:00
2021-01-12 22:02:29 +00:00
static bool HandleBrokerMessage(LONG msgid, ULONG msgtype)
{
switch (msgtype)
{
case CXM_IEVENT:
switch (msgid)
{
case EVT_HOTKEY:
LogDebug("Show window");
ShowSettingWindow();
break;
default:
break;
}
break;
case CXM_COMMAND:
switch (msgid)
{
case CXCMD_DISABLE:
Deactivate();
break;
case CXCMD_ENABLE:
Activate();
break;
case CXCMD_KILL:
2021-01-12 22:16:18 +00:00
LogWarn("Received shutdown from commodity");
2021-01-12 22:02:29 +00:00
return false;
break;
case CXCMD_UNIQUE:
LogWarn("Commodity duplicate detected");
LogDebug("Show window");
ShowSettingWindow();
break;
case CXCMD_APPEAR:
LogDebug("Show window");
ShowSettingWindow();
break;
case CXCMD_DISAPPEAR:
LogDebug("Hide window");
2021-01-12 22:16:18 +00:00
SendWindowMessage(ATK_SHUTDOWN);
2021-01-12 22:02:29 +00:00
break;
default:
break;
}
}
2018-11-24 21:39:18 +00:00
2021-01-12 22:02:29 +00:00
return true;
2018-11-24 21:39:18 +00:00
}
2021-01-12 22:02:29 +00:00
static bool HandleUserMessage(long msg)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:02:29 +00:00
switch (msg)
{
case ATK_STORE:
SaveSettings(true);
SaveSettings(false);
2021-01-12 22:16:18 +00:00
SendWindowMessage(ATK_SHUTDOWN);
2021-01-12 22:02:29 +00:00
break;
case ATK_APPLY:
SaveSettings(false);
2021-01-12 22:16:18 +00:00
SendWindowMessage(ATK_SHUTDOWN);
2021-01-12 22:02:29 +00:00
break;
case ATK_UNDO:
ApplyAppSettings(WindowSettings, true);
2021-01-12 22:16:18 +00:00
SendWindowMessage(ATK_SHUTDOWN);
2021-01-12 22:02:29 +00:00
break;
case ATK_RESTART:
2021-01-12 22:16:18 +00:00
SendMessageWait(MSGPORT_SYNCER, ATK_RESTART);
2021-01-12 22:02:29 +00:00
break;
case ATK_DISABLE:
Activate();
break;
case ATK_ENABLE:
Deactivate();
break;
case ATK_READONLY:
LogDebug("READONLY changed: 1 -> 0");
LogWarn("Entering read only mode. Clock is not adjusted in read-only mode");
break;
case ATK_READWRITE:
LogDebug("READONLY changed: 0 -> 1");
LogWarn("Leaving read only mode. Clock is adjusted again");
break;
case ATK_SHUTDOWN:
return false;
break;
default:
break;
}
2018-11-24 21:39:18 +00:00
2021-01-12 22:02:29 +00:00
return true;
}
2018-11-24 21:39:18 +00:00
2021-01-12 22:02:29 +00:00
static void MsgLoop(void)
{
bool loop = true;
long shutdown = LOOP_RUNNING;
2021-01-12 22:16:18 +00:00
ULONG notifySigMask = 0;
ULONG commoditySigMask = (1 << Broker.CommodityPort->mp_SigBit);
2021-01-12 22:02:29 +00:00
ULONG screenSigMask = (1 << Broker.ScreenPort->mp_SigBit);
2021-01-12 22:16:18 +00:00
#if defined(SCREENNOTIFY)
bool reopenWindow = false;
notifySigMask = (1 << Broker.NotifyPort->mp_SigBit);
#endif
ULONG brokerSigMask = GetPortSignalMask(MSGPORT_BROKER);
ULONG memorySigMask = GetPortSignalMask(MSGPORT_MEMORY);
ULONG controlSigMask = GetPortSignalMask(MSGPORT_CONTROL);
ULONG arexxSigMask = GetPortSignalMask(MSGPORT_AREXX);
ULONG sigMask = commoditySigMask | screenSigMask | notifySigMask | brokerSigMask |
memorySigMask | controlSigMask | arexxSigMask | SIGBREAKF_CTRL_C;
2021-01-12 22:02:29 +00:00
BrokerRunning = true;
LogTrace("Loop started");
2021-01-31 19:10:59 +00:00
if (Settings->Popup || Settings->PopupOnStart)
2021-01-12 21:53:12 +00:00
{
ShowSettingWindow();
}
2018-11-24 21:39:18 +00:00
do
{
2021-01-12 22:02:29 +00:00
ULONG sigrcvd = Wait(sigMask);
2021-01-12 22:16:18 +00:00
if (sigrcvd & commoditySigMask)
2018-11-24 21:39:18 +00:00
{
CxMsg *msg;
2021-01-12 22:16:18 +00:00
while ((msg = (CxMsg *)GetMsg(Broker.CommodityPort)))
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:02:29 +00:00
bool cont;
LONG msgId = CxMsgID(msg);
ULONG msgType = CxMsgType(msg);
2018-11-24 21:39:18 +00:00
ReplyMsg((struct Message *)msg);
2021-01-12 22:02:29 +00:00
cont = HandleBrokerMessage(msgId, msgType);
if (!cont)
shutdown = SHUTDOWN_REQUEST;
2018-11-24 21:39:18 +00:00
}
}
2021-01-12 22:16:18 +00:00
if (sigrcvd & brokerSigMask)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:02:29 +00:00
struct ApplicationMesage *msg;
2021-01-12 22:16:18 +00:00
while ((msg = (struct ApplicationMesage *)GetNewMessage(MSGPORT_BROKER)))
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:02:29 +00:00
bool cont;
long msgId = msg->MsgId;
ReplyMsg((struct Message *)msg);
cont = HandleUserMessage(msgId);
if (!cont)
2021-01-12 22:16:18 +00:00
loop = false; // Now exit loop safely
2021-01-12 22:02:29 +00:00
}
}
2021-01-12 22:16:18 +00:00
if (sigrcvd & controlSigMask)
{
bool cont = HandleControlMessages();
if (!cont)
shutdown = SHUTDOWN_REQUEST;
}
if (sigrcvd & arexxSigMask)
{
bool cont = HandleARexxMessages();
if (!cont)
shutdown = SHUTDOWN_REQUEST;
}
2021-01-12 22:02:29 +00:00
if (sigrcvd & notifySigMask)
{
struct NotifyMessage *msg;
while ((msg = (struct NotifyMessage *)GetMsg(Broker.NotifyPort)))
{
long msgType = msg->nm_NReq->nr_UserData;
ReplyMsg((struct Message *)msg);
switch (msgType)
{
case ATK_TZ_CHANGED:
LogDebug("TZ changed");
ChangeTimezone();
2018-11-24 21:39:18 +00:00
break;
2021-01-12 22:02:29 +00:00
case ATK_TZONE_CHANGED:
LogDebug("TZONE changed");
ChangeTimezone();
2018-11-24 21:39:18 +00:00
break;
2021-01-12 22:02:29 +00:00
case ATK_LOCALE_CHANGED:
LogError("Locale changed");
ChangeTimezoneDelayed();
2018-11-24 21:39:18 +00:00
break;
}
2021-01-12 22:02:29 +00:00
break;
2018-11-24 21:39:18 +00:00
}
}
2021-01-12 22:16:18 +00:00
#if defined(SCREENNOTIFY)
2021-01-12 22:02:29 +00:00
if (sigrcvd & screenSigMask)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:02:29 +00:00
struct ScreenNotifyMessage *msg;
while ((msg = (struct ScreenNotifyMessage *)GetMsg(Broker.ScreenPort)))
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:02:29 +00:00
LogDebug("ScreenNotifyMessage");
if (msg->snm_Type == SCREENNOTIFY_TYPE_WORKBENCH)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:02:29 +00:00
if (msg->snm_Value == NULL)
{
LogDebug("WB Close");
LogDebug("Hide window");
2021-01-12 22:16:18 +00:00
SendWindowMessage(ATK_DISABLE);
2021-01-12 22:02:29 +00:00
reopenWindow = WindowProcRunning;
}
else
{
LogDebug("WB Open");
if (reopenWindow)
{
ShowSettingWindow();
}
ChangeTimezone();
reopenWindow = false;
}
2018-11-24 21:39:18 +00:00
}
2021-01-12 22:02:29 +00:00
ReplyMsg((struct Message *)msg);
2018-11-24 21:39:18 +00:00
}
}
2021-01-12 22:16:18 +00:00
#endif
2018-11-24 21:39:18 +00:00
2021-01-12 22:16:18 +00:00
if (sigrcvd & memorySigMask)
2018-11-24 21:39:18 +00:00
{
2021-01-12 22:16:18 +00:00
HandleMemoryMessages();
2018-11-24 21:39:18 +00:00
}
if (sigrcvd & SIGBREAKF_CTRL_C)
{
2021-01-12 22:16:18 +00:00
LogWarn("Received CTRL + C");
2021-01-12 22:02:29 +00:00
shutdown = SHUTDOWN_REQUEST;
2018-11-24 21:39:18 +00:00
}
2021-01-12 21:53:12 +00:00
2021-01-12 22:02:29 +00:00
if (shutdown == SHUTDOWN_REQUEST)
{
shutdown = SHUTTING_DOWN;
2021-01-12 22:16:18 +00:00
StartShutdown();
2021-01-12 22:02:29 +00:00
}
} while (loop);
BrokerRunning = false;
LogTrace("Loop exited");
2021-01-12 21:53:12 +00:00
}
static void CleanupBroker(void)
{
2021-01-12 22:16:18 +00:00
#if defined(SCREENNOTIFY)
2021-01-12 22:02:29 +00:00
if (Broker.screenNotifyWB != NULL)
2021-01-12 21:53:12 +00:00
{
2021-01-12 22:02:29 +00:00
LogTrace("ScreenNotify WB cleared");
while (!RemWorkbenchClient(Broker.screenNotifyWB))
{
Delay(10);
}
2021-01-12 21:53:12 +00:00
}
2021-01-12 22:02:29 +00:00
if (Broker.screenNotifyPub != NULL)
2021-01-12 21:53:12 +00:00
{
2021-01-12 22:02:29 +00:00
LogTrace("ScreenNotify PubScreen cleared");
while (!RemPubScreenClient(Broker.screenNotifyPub))
{
Delay(10);
}
2021-01-12 21:53:12 +00:00
}
2021-01-12 22:16:18 +00:00
#endif
2021-01-12 21:53:12 +00:00
2021-01-12 22:02:29 +00:00
CleanupNotifications();
if (Broker.Object != NULL)
2021-01-12 21:53:12 +00:00
{
2021-01-12 22:02:29 +00:00
DeleteCxObjAll(Broker.Object);
Broker.Object = NULL;
LogTrace("CxObj cleared");
2021-01-12 21:53:12 +00:00
}
2021-01-12 22:16:18 +00:00
CleanupMsgPort(&Broker.CommodityPort);
LogTrace(TextPortCleaned, "Commodity");
2021-01-12 22:02:29 +00:00
CleanupMsgPort(&Broker.NotifyPort);
2021-01-12 22:16:18 +00:00
LogTrace(TextPortCleaned, "Notify");
2021-01-12 22:02:29 +00:00
CleanupMsgPort(&Broker.ScreenPort);
2021-01-12 22:16:18 +00:00
LogTrace(TextPortCleaned, "Screen");
2021-01-12 21:53:12 +00:00
}