Files
lobbs/apps/Config/ConfigCommands.cpp
T

201 lines
6.8 KiB
C++

#if !MESHTASTIC_EXCLUDE_LOBBS
#include "ConfigCommands.h"
#include "../../LoBBSCommandRegistry.h"
#include "../../LoBBSHooks.h"
#include "../../LoBBSModule.h"
#include "../../LoBBSReplyCache.h"
#include "../../LoBBSResponse.h"
#include "../AppUtil.h"
#include "ConfigCommon.h"
#include "ConfigDal.h"
#include "ConfigRecords.h"
#include <cstdio>
#include <cstring>
#include <strings.h>
#include "LoBBSStackGuard.h"
static uint32_t gLobbsPagerTtlSec = LOBBS_REPLY_CACHE_TTL_SEC;
uint32_t lobbsReplyCacheTtlSec()
{
return gLobbsPagerTtlSec;
}
static void filterConfigKeysPager(LoBBSCommandCtx *ctx, std::vector<LoScalar> &keys, const LoScalar &args)
{
(void)ctx;
(void)args;
lobbsConfigPushKey(keys, "pager.ttl", LOBBS_REPLY_CACHE_TTL_SEC, 60, 3600, "Seconds /pN cache lasts");
}
static void filterConfigValidateRange(LoBBSCommandCtx *ctx, LoScalar &value, const LoScalar &args)
{
(void)ctx;
std::string existing;
if (value.getString(LODB_F_ERROR, existing) && !existing.empty())
return;
uint32_t proposed = 0;
uint32_t minV = 0;
uint32_t maxV = 0;
if (!value.getUint32(ConfigValidateField::FIELD_VALUE, proposed))
return;
if (!args.getUint32(ConfigKeyField::FIELD_MIN, minV) || !args.getUint32(ConfigKeyField::FIELD_MAX, maxV))
return;
if (proposed < minV || proposed > maxV) {
char buf[48];
snprintf(buf, sizeof(buf), "Must be %u-%u.", (unsigned)minV, (unsigned)maxV);
value.setString(LODB_F_ERROR, buf);
}
}
static void actionConfigChangedPager(LoBBSCommandCtx *ctx, const LoScalar &args)
{
(void)ctx;
std::string key;
if (!args.getString(LODB_F_TITLE, key) || key != "pager.ttl")
return;
uint32_t ttl = LOBBS_REPLY_CACHE_TTL_SEC;
args.getUint32(ConfigValidateField::FIELD_VALUE, ttl);
gLobbsPagerTtlSec = ttl;
}
static void handleConfig(LoBBSCommandCtx &ctx)
{
if (!lobbsCommandRequireSysop(ctx))
return;
ConfigDal &cfg = ctx.mod->config().dal();
const char *key = lobbsArgShift(ctx);
if (!key) {
LoBBSResponse resp;
lobbsRecordPush(resp.records, "Use /help config key for details");
for (const LoScalar &def : cfg.keyDefs(ctx)) {
std::string name;
if (!def.getString(LODB_F_TITLE, name))
continue;
uint32_t minV = 0;
uint32_t maxV = 0;
def.getUint32(ConfigKeyField::FIELD_MIN, minV);
def.getUint32(ConfigKeyField::FIELD_MAX, maxV);
uint32_t val = cfg.effectiveValue(ctx, name.c_str());
char line[96];
snprintf(line, sizeof(line), "%s %u (%u-%u)", name.c_str(), (unsigned)val, (unsigned)minV, (unsigned)maxV);
lobbsRecordPush(resp.records, line);
}
lobbsCommandReplyResponse(ctx, resp);
return;
}
const char *next = lobbsArgPeek(ctx);
if (!next) {
cfg.ensureRegistry(ctx);
const LoScalar *def = cfg.findKeyDef(key);
if (!def) {
lobbsCommandReplyError(ctx, "Unknown setting.");
return;
}
uint32_t val = cfg.effectiveValue(ctx, key);
uint32_t defV = 0;
uint32_t minV = 0;
uint32_t maxV = 0;
std::string help;
def->getUint32(ConfigKeyField::FIELD_DEFAULT, defV);
def->getUint32(ConfigKeyField::FIELD_MIN, minV);
def->getUint32(ConfigKeyField::FIELD_MAX, maxV);
def->getString(LODB_F_DESCRIPTION, help);
char line[128];
snprintf(line, sizeof(line), "%s = %u (default %u, %u-%u). %s", key, (unsigned)val, (unsigned)defV, (unsigned)minV,
(unsigned)maxV, help.c_str());
lobbsCommandReply(ctx, line);
return;
}
if (strcasecmp(next, "reset") == 0) {
lobbsArgShift(ctx);
if (lobbsArgHasMore(ctx)) {
lobbsCommandReplyError(ctx, "Usage: /config key reset");
return;
}
if (const char *err = cfg.resetKey(ctx, key)) {
lobbsCommandReplyError(ctx, err);
return;
}
char reply[64];
snprintf(reply, sizeof(reply), "%s reset.", key);
lobbsCommandReply(ctx, reply);
return;
}
uint32_t value = 0;
if (!lobbsArgShiftUint(ctx, value) || lobbsArgHasMore(ctx)) {
lobbsCommandReplyError(ctx, "Usage: /config key value");
return;
}
if (const char *err = cfg.validateAndSet(ctx, key, value)) {
lobbsCommandReplyError(ctx, err);
return;
}
char reply[64];
snprintf(reply, sizeof(reply), "%s = %u.", key, (unsigned)value);
lobbsCommandReply(ctx, reply);
}
static void slashConfig(LoBBSCommandCtx *ctx, const LoScalar &args)
{
if (!ctx || !lobbsSlashVerbIs(args, "config"))
return;
handleConfig(*ctx);
}
static const LoBBSVerb configHelpVerbs[] = {
{"config", nullptr, LOBBS_V_SYSOP, "config — sysop: list/get/set/reset settings (/help config key explains one)"},
};
static void filterConfigHelpTopics(LoBBSCommandCtx *ctx, std::vector<LoScalar> &topics, const LoScalar &args)
{
(void)ctx;
(void)args;
lobbsRecordPush(topics, "config", "sysop settings");
}
static void filterConfigHelpForTopic(LoBBSCommandCtx *ctx, LoScalar &value, const LoScalar &args)
{
lobbsHelpForTable(ctx, value, args, "config", configHelpVerbs, sizeof(configHelpVerbs) / sizeof(configHelpVerbs[0]));
if (!ctx || !ctx->mod || value.has(LODB_F_DESCRIPTION) || !lobbsCtxIsSysop(*ctx))
return;
std::string query;
if (!args.getString(LODB_F_TITLE, query) || strncasecmp(query.c_str(), "config ", 7) != 0)
return;
const char *key = query.c_str() + 7;
ConfigDal &cfg = ctx->mod->config().dal();
cfg.ensureRegistry(*ctx);
const LoScalar *def = cfg.findKeyDef(key);
if (!def)
return;
std::string help;
uint32_t defV = 0;
uint32_t minV = 0;
uint32_t maxV = 0;
def->getString(LODB_F_DESCRIPTION, help);
def->getUint32(ConfigKeyField::FIELD_DEFAULT, defV);
def->getUint32(ConfigKeyField::FIELD_MIN, minV);
def->getUint32(ConfigKeyField::FIELD_MAX, maxV);
char buf[128];
snprintf(buf, sizeof(buf), "%s: %s. Default %u, range %u-%u.", key, help.c_str(), (unsigned)defV, (unsigned)minV,
(unsigned)maxV);
value.setString(LODB_F_DESCRIPTION, buf);
}
void lobbsConfigRegisterCommands()
{
lobbsAddFilter("config_keys", filterConfigKeysPager, LOBBS_HOOK_PRIORITY_HELP);
lobbsAddFilter("config_validate", filterConfigValidateRange, LOBBS_HOOK_PRIORITY_HELP);
lobbsAddAction("config_changed", actionConfigChangedPager, LOBBS_HOOK_PRIORITY_HELP);
lobbsAddAction("slash_cmd", slashConfig, LOBBS_HOOK_PRIORITY_FEATURE);
lobbsAddFilter("help_topics", filterConfigHelpTopics, LOBBS_HOOK_PRIORITY_FEATURE);
lobbsAddFilter("help_for_topic", filterConfigHelpForTopic, LOBBS_HOOK_PRIORITY_FEATURE);
}
#endif