mirror of
git://git.acid.vegas/unrealircd.git
synced 2024-12-26 00:06:38 +00:00
186 lines
5.4 KiB
C
186 lines
5.4 KiB
C
/************************************************************************
|
|
* UnrealIRCd - Unreal Internet Relay Chat Daemon - src/api-mtag.c
|
|
* (c) 2019- Bram Matthys and The UnrealIRCd team
|
|
*
|
|
* See file AUTHORS in IRC package for additional names of
|
|
* the programmers.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 1, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
/** @file
|
|
* @brief Message tag API
|
|
*/
|
|
#include "unrealircd.h"
|
|
|
|
/** This is the message tags API (message-tags).
|
|
* For an overview of message tags in general (not the API)
|
|
* see https://www.unrealircd.org/docs/Message_tags
|
|
* @defgroup MessagetagAPI Message tag API
|
|
* @{
|
|
*/
|
|
|
|
/** List of message tag handlers */
|
|
MODVAR MessageTagHandler *mtaghandlers = NULL;
|
|
|
|
/* Forward declarations */
|
|
static void unload_mtag_handler_commit(MessageTagHandler *m);
|
|
|
|
/** Adds a new message tag handler.
|
|
* @param module The module which owns this message-tag handler.
|
|
* @param mreq The details of the request such as which message tag, the handler, etc.
|
|
* @return Returns the handle to the new token if successful, otherwise NULL.
|
|
* The module's error code contains specific information about the
|
|
* error.
|
|
*/
|
|
MessageTagHandler *MessageTagHandlerAdd(Module *module, MessageTagHandlerInfo *mreq)
|
|
{
|
|
MessageTagHandler *m;
|
|
|
|
/* Some consistency checks to avoid a headache for module devs later on: */
|
|
if ((mreq->flags & MTAG_HANDLER_FLAGS_NO_CAP_NEEDED) && mreq->clicap_handler)
|
|
{
|
|
unreal_log(ULOG_ERROR, "module", "MESSAGETAGHANDLERADD_API_ERROR", NULL,
|
|
"MessageTagHandlerAdd() from module $module_name: "
|
|
".flags is set to MTAG_HANDLER_FLAGS_NO_CAP_NEEDED "
|
|
"but a .clicap_handler is passed as well. These options are mutually "
|
|
"exclusive, choose one or the other.",
|
|
log_data_string("module_name", module->header->name));
|
|
abort();
|
|
} else if (!(mreq->flags & MTAG_HANDLER_FLAGS_NO_CAP_NEEDED) && !mreq->clicap_handler)
|
|
{
|
|
unreal_log(ULOG_ERROR, "module", "MESSAGETAGHANDLERADD_API_ERROR", NULL,
|
|
"MessageTagHandlerAdd() from module $module_name: "
|
|
"no .clicap_handler is passed. If the "
|
|
"message tag really does not require a cap then you must "
|
|
"set .flags to MTAG_HANDLER_FLAGS_NO_CAP_NEEDED",
|
|
log_data_string("module_name", module->header->name));
|
|
abort();
|
|
}
|
|
|
|
m = MessageTagHandlerFind(mreq->name);
|
|
if (m)
|
|
{
|
|
if (m->unloaded)
|
|
{
|
|
m->unloaded = 0;
|
|
} else {
|
|
if (module)
|
|
module->errorcode = MODERR_EXISTS;
|
|
return NULL;
|
|
}
|
|
} else {
|
|
/* New message tag handler */
|
|
m = safe_alloc(sizeof(MessageTagHandler));
|
|
safe_strdup(m->name, mreq->name);
|
|
AddListItem(m, mtaghandlers);
|
|
}
|
|
/* Add or update the following fields: */
|
|
m->owner = module;
|
|
m->flags = mreq->flags;
|
|
m->is_ok = mreq->is_ok;
|
|
m->should_send_to_client = mreq->should_send_to_client;
|
|
m->clicap_handler = mreq->clicap_handler;
|
|
|
|
/* Update reverse dependency (if any) */
|
|
if (m->clicap_handler)
|
|
m->clicap_handler->mtag_handler = m;
|
|
|
|
if (module)
|
|
{
|
|
ModuleObject *mobj = safe_alloc(sizeof(ModuleObject));
|
|
mobj->type = MOBJ_MTAG;
|
|
mobj->object.mtag = m;
|
|
AddListItem(mobj, module->objects);
|
|
module->errorcode = MODERR_NOERROR;
|
|
}
|
|
|
|
return m;
|
|
}
|
|
|
|
/** Returns the message tag handler for the given name.
|
|
* @param name The message-tag name to search for.
|
|
* @return Returns the handle to the message tag handler,
|
|
* or NULL if not found.
|
|
*/
|
|
MessageTagHandler *MessageTagHandlerFind(const char *name)
|
|
{
|
|
MessageTagHandler *m;
|
|
|
|
for (m = mtaghandlers; m; m = m->next)
|
|
{
|
|
if (!strcasecmp(name, m->name))
|
|
return m;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/** Remove the specified message tag handler - modules should not call this.
|
|
* This is done automatically for modules on unload, so is only called internally.
|
|
* @param m The message tag handler to remove.
|
|
*/
|
|
void MessageTagHandlerDel(MessageTagHandler *m)
|
|
{
|
|
if (m->owner)
|
|
{
|
|
ModuleObject *mobj;
|
|
for (mobj = m->owner->objects; mobj; mobj = mobj->next) {
|
|
if (mobj->type == MOBJ_MTAG && mobj->object.mtag == m)
|
|
{
|
|
DelListItem(mobj, m->owner->objects);
|
|
safe_free(mobj);
|
|
break;
|
|
}
|
|
}
|
|
m->owner = NULL;
|
|
}
|
|
|
|
if (loop.rehashing)
|
|
m->unloaded = 1;
|
|
else
|
|
unload_mtag_handler_commit(m);
|
|
}
|
|
|
|
/** @} */
|
|
|
|
static void unload_mtag_handler_commit(MessageTagHandler *m)
|
|
{
|
|
/* This is an unusual operation, I think we should log it. */
|
|
unreal_log(ULOG_INFO, "module", "UNLOAD_MESSAGE_TAG", NULL,
|
|
"Unloading message-tag handler for '$token'",
|
|
log_data_string("token", m->name));
|
|
|
|
/* Remove reverse dependency, if any */
|
|
if (m->clicap_handler)
|
|
m->clicap_handler->mtag_handler = NULL;
|
|
|
|
/* Destroy the object */
|
|
DelListItem(m, mtaghandlers);
|
|
safe_free(m->name);
|
|
safe_free(m);
|
|
}
|
|
|
|
void unload_all_unused_mtag_handlers(void)
|
|
{
|
|
MessageTagHandler *m, *m_next;
|
|
|
|
for (m = mtaghandlers; m; m = m_next)
|
|
{
|
|
m_next = m->next;
|
|
if (m->unloaded)
|
|
unload_mtag_handler_commit(m);
|
|
}
|
|
}
|