AmiTimeKeeper/broker.c

415 lines
12 KiB
C

/*-
* Copyright (c) 2017-2019 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 "message.h"
#include "mem.h"
#include "win.h"
#define EVT_HOTKEY 1L
static void ProcessMsg(void);
static void InitBroker(void);
static void CleanupBroker(void);
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};
void StartBroker(void)
{
LONG error;
struct Message *msg;
CxObj *filter, *sender, *translate;
InitBroker();
Globals->Broker->BrokerPort = CreateMsgPort();
if (Globals->Broker->BrokerPort == NULL)
{
LogError("Could not allocate broker port");
return;
}
Globals->Broker->UserPort = CreateMsgPort();
if (Globals->Broker->UserPort == NULL)
{
LogError("Could not allocate broker user port");
CleanupBroker();
return;
}
Globals->Broker->ReplyPort = CreateMsgPort();
if (Globals->Broker->ReplyPort == NULL)
{
LogError("Could not allocate broker reply port");
CleanupBroker();
return;
}
Globals->Broker->ShutdownSigBit = AllocSignal(-1);
if (Globals->Broker->ShutdownSigBit == -1)
{
SendErrorMessage("Could not allocate signal for broker");
CleanupBroker();
return;
}
newBroker.nb_Port = Globals->Broker->BrokerPort;
newBroker.nb_Pri = Globals->Settings->Priority;
Globals->Broker->Object = CxBroker(&newBroker, &error);
if (!Globals->Broker->Object)
{
switch (error)
{
case CBERR_SYSERR:
LogError("System problems (CBERR_SYSERR). Could not allocate broker object");
break;
case CBERR_DUP:
LogWarning(APP_SHORT_NAME " is already running");
break;
default:
LogError("Could not allocate broker object (error code: %ld)", error);
break;
}
CleanupBroker();
return;
}
filter = CxFilter(Globals->Settings->PopKey);
if (filter == NULL)
{
LogError("Could not allocate broker filter object");
CleanupBroker();
return;
}
AttachCxObj(Globals->Broker->Object, filter);
sender = CxSender(Globals->Broker->BrokerPort, EVT_HOTKEY);
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();
return;
}
AttachCxObj(filter, translate);
error = CxObjError(filter);
if (error != 0)
{
switch (error)
{
case CBERR_SYSERR:
LogWarning("Commodity filter problems (CBERR_SYSERR)");
break;
case COERR_BADFILTER:
LogWarning("Commodity HOTKEY error");
break;
default:
LogWarning("Commodity filter error (error code: %ld)", error);
break;
}
}
Globals->Broker->Task = FindTask(NULL);
StartCom();
ProcessMsg();
while ((msg = GetMsg(Globals->Broker->BrokerPort)))
ReplyMsg(msg);
while ((msg = GetMsg(Globals->Broker->UserPort)))
ReplyMsg(msg);
while ((msg = GetMsg(Globals->Broker->ReplyPort)))
ReplyMsg(msg);
CleanupBroker();
}
void ShutdownBroker(void)
{
Signal((struct Task *)Globals->Broker->Task,
(1 << Globals->Broker->ShutdownSigBit));
}
void SetBrokerPriority(int priority)
{
SetCxObjPri(Globals->Broker->Object, priority);
}
static void Activate(void)
{
LogWarning("ACTIVE changed: 1 -> 0");
ActivateCxObj(Globals->Broker->Object, 0);
Globals->Active = false;
StopComAsync();
while (!CheckComClosed())
Delay(1);
}
static void Deactivate(void)
{
LogWarning("ACTIVE changed: 0 -> 1");
ActivateCxObj(Globals->Broker->Object, 1);
Globals->Active = true;
StartCom();
}
static void StopSubProcesses(void)
{
Forbid();
Globals->ShuttingDown = true;
Permit();
HideSettingWindow();
while (!CheckSettingWindowClosed())
Delay(10);
StopComAsync();
while (!CheckComClosed())
Delay(10);
}
static void ProcessMsg(void)
{
bool run = true;
ULONG sigmask = SIGBREAKF_CTRL_C |
(1 << Globals->Broker->ShutdownSigBit) |
(1 << Globals->Broker->BrokerPort->mp_SigBit) |
(1 << Globals->Broker->UserPort->mp_SigBit) |
(1 << Globals->Broker->ReplyPort->mp_SigBit);
ActivateCxObj(Globals->Broker->Object, 1);
Globals->Active = true;
if (Globals->Settings->Popup)
{
ShowSettingWindow();
}
do
{
ULONG sigrcvd = Wait(sigmask);
if (sigrcvd & (1 << Globals->Broker->BrokerPort->mp_SigBit))
{
CxMsg *msg;
while ((msg = (CxMsg *)GetMsg(Globals->Broker->BrokerPort)))
{
LONG msgid = CxMsgID(msg);
ULONG msgtype = CxMsgType(msg);
ReplyMsg((struct Message *)msg);
switch (msgtype)
{
case CXM_IEVENT:
switch (msgid)
{
case EVT_HOTKEY:
LogTrace("Show window");
ShowSettingWindow();
break;
}
break;
case CXM_COMMAND:
switch (msgid)
{
case CXCMD_DISABLE:
Activate();
break;
case CXCMD_ENABLE:
Deactivate();
break;
case CXCMD_KILL:
LogInfo("Received shut down from commodity");
StopSubProcesses();
run = false;
break;
case CXCMD_UNIQUE:
LogWarning("Commodity duplicate detected");
LogTrace("Show window");
ShowSettingWindow();
break;
case CXCMD_APPEAR:
LogTrace("Show window");
ShowSettingWindow();
break;
case CXCMD_DISAPPEAR:
LogTrace("Hide window");
HideSettingWindow();
break;
}
}
}
}
if (sigrcvd & (1 << Globals->Broker->UserPort->mp_SigBit))
{
struct AppWindowMessage *msg;
while ((msg = (struct AppWindowMessage *)GetMsg(Globals->Broker->UserPort)))
{
switch (msg->Type)
{
case ATK_LOGERROR:
LogError(msg->Text);
break;
case ATK_LOGWARN:
LogWarning(msg->Text);
break;
case ATK_LOGINFO:
LogInfo(msg->Text);
break;
case ATK_LOGTRACE:
LogTrace(msg->Text);
break;
case ATK_STORE:
SaveSettings(true);
SaveSettings(false);
break;
case ATK_APPLY:
SaveSettings(false);
break;
case ATK_UNDO:
ApplyAppSettings(Globals->Window->Settings, true);
break;
case ATK_RESTART:
RestartSntpAsync();
break;
case ATK_REFRESH:
// Broker cannot refresh
break;
case ATK_DISABLE:
Activate();
break;
case ATK_ENABLE:
Deactivate();
break;
case ATK_READONLY:
LogWarning("READONLY changed: 1 -> 0");
break;
case ATK_READWRITE:
LogWarning("READONLY changed: 0 -> 1");
break;
default:
break;
}
ReplyMsg((struct Message *)msg);
}
}
if (sigrcvd & (1 << Globals->Broker->ReplyPort->mp_SigBit))
{
struct AppWindowMessage *msg;
while ((msg = (struct AppWindowMessage *)GetMsg(Globals->Broker->ReplyPort)))
{
if (msg->Text != NULL)
{
FreeMemSafe(msg->Text);
}
FreeMemSafe(msg);
}
}
if (sigrcvd & (1 << Globals->Broker->ShutdownSigBit))
{
LogInfo("Received shut down from setting window");
StopSubProcesses();
run = false;
}
if (sigrcvd & SIGBREAKF_CTRL_C)
{
LogInfo("Received CTRL + C");
StopSubProcesses();
run = false;
}
} while (run);
}
static void InitBroker(void)
{
Globals->Broker->Object = NULL;
Globals->Broker->ShutdownSigBit = -1;
Globals->Broker->Task = NULL;
Globals->Broker->BrokerPort = NULL;
Globals->Broker->UserPort = NULL;
Globals->Broker->ReplyPort = NULL;
}
static void CleanupBroker(void)
{
if (Globals->Broker->Object != NULL)
{
DeleteCxObjAll(Globals->Broker->Object);
Globals->Broker->Object = NULL;
}
if (Globals->Broker->ShutdownSigBit != -1)
{
FreeSignal(Globals->Broker->ShutdownSigBit);
Globals->Broker->ShutdownSigBit = -1;
}
if (Globals->Broker->BrokerPort != NULL)
{
DeleteMsgPort(Globals->Broker->BrokerPort);
Globals->Broker->BrokerPort = NULL;
}
if (Globals->Broker->UserPort != NULL)
{
DeleteMsgPort(Globals->Broker->UserPort);
Globals->Broker->UserPort = NULL;
}
if (Globals->Broker->ReplyPort != NULL)
{
DeleteMsgPort(Globals->Broker->ReplyPort);
Globals->Broker->ReplyPort = NULL;
}
}