pissircd/src/api-apicallback.c

186 lines
4.8 KiB
C

/************************************************************************
* UnrealIRCd - Unreal Internet Relay Chat Daemon - src/api-apicallback.c
* (c) 2022- Bram Matthys and The UnrealIRCd Team
* License: GPLv2 or later
*/
/** @file
* @brief APICallback API
*/
#include "unrealircd.h"
/** This is for API callbacks like RegisterWebCallback.
*/
/** List of API Callbacks */
MODVAR APICallback *apicallbacks = NULL;
/* Forward declarations */
static void unload_apicallback_commit(APICallback *m);
#ifdef APICALLBACKDEBUG
static void print_apicallbacks(void);
#endif
/** Adds a new API Callback.
* @param module The module which owns this API callback.
* @param mreq The details of the request such as the name and callback
* @return Returns the handle to the API callback if successful, otherwise NULL.
* The module's error code contains specific information about the
* error.
*/
APICallback *APICallbackAdd(Module *module, APICallback *mreq)
{
APICallback *m;
ModuleObject *mobj;
/* Some consistency checks to avoid a headache for module devs later on: */
if (!mreq->callback_type)
{
unreal_log(ULOG_ERROR, "module", "API_CALLBACK_ADD_API_ERROR", NULL,
"APICallbackAdd() from module $module_name: "
"Missing required fields.",
log_data_string("module_name", module->header->name));
abort();
}
m = APICallbackFind(mreq->name, mreq->callback_type);
if (m)
{
if (m->unloaded)
{
m->unloaded = 0;
} else {
if (module)
module->errorcode = MODERR_EXISTS;
return NULL;
}
} else {
/* New API callback */
m = safe_alloc(sizeof(APICallback));
safe_strdup(m->name, mreq->name);
AddListItem(m, apicallbacks);
}
/* Add or update the following fields: */
m->owner = module;
m->callback_type = mreq->callback_type;
memcpy(&m->callback, &mreq->callback, sizeof(m->callback));
/* Add module object */
mobj = safe_alloc(sizeof(ModuleObject));
mobj->type = MOBJ_API_CALLBACK;
mobj->object.apicallback = m;
AddListItem(mobj, module->objects);
module->errorcode = MODERR_NOERROR;
#ifdef APICALLBACKDEBUG
unreal_log(ULOG_DEBUG, "module", "API_CALLBACK_DEBUG", NULL, "APICallbackAdd()");
print_apicallbacks();
#endif
return m;
}
/** Returns the API callback for the given name and callback type.
* @param name The method to search for.
* @param callback_type To which callback_type this belongs (scope)
* @return Returns the handle to the API callback,
* or NULL if not found.
*/
APICallback *APICallbackFind(const char *name, APICallbackType callback_type)
{
APICallback *m;
#ifdef APICALLBACKDEBUG
unreal_log(ULOG_DEBUG, "module", "API_CALLBACK_DEBUG", NULL, "APICallbackFind()");
print_apicallbacks();
#endif
for (m = apicallbacks; m; m = m->next)
{
if ((m->callback_type == callback_type) &&
!strcasecmp(name, m->name))
{
return m;
}
}
return NULL;
}
/** Remove the specified API callback - modules should not call this.
* This is done automatically for modules on unload, so is only called internally.
* @param m The API Callback to remove.
*/
void APICallbackDel(APICallback *m)
{
if (m->owner)
{
ModuleObject *mobj;
for (mobj = m->owner->objects; mobj; mobj = mobj->next)
{
if (mobj->type == MOBJ_API_CALLBACK && mobj->object.apicallback == m)
{
DelListItem(mobj, m->owner->objects);
safe_free(mobj);
break;
}
}
m->owner = NULL;
}
if (loop.rehashing)
m->unloaded = 1;
else
unload_apicallback_commit(m);
}
/** @} */
static void unload_apicallback_commit(APICallback *m)
{
/* This is an unusual operation, I think we should log it. */
unreal_log(ULOG_INFO, "module", "UNLOAD_API_CALLBACK", NULL,
"Unloading API callback for '$object_name'",
log_data_string("object_name", m->name));
/* Destroy the object */
DelListItem(m, apicallbacks);
safe_free(m->name);
safe_free(m);
}
void unload_all_unused_apicallbacks(void)
{
APICallback *m, *m_next;
#ifdef APICALLBACKDEBUG
unreal_log(ULOG_DEBUG, "module", "API_CALLBACK_DEBUG", NULL, "unload_all_unused_apicallbacks() BEFORE");
print_apicallbacks();
#endif
for (m = apicallbacks; m; m = m_next)
{
m_next = m->next;
if (m->unloaded)
unload_apicallback_commit(m);
}
#ifdef APICALLBACKDEBUG
unreal_log(ULOG_DEBUG, "module", "API_CALLBACK_DEBUG", NULL, "unload_all_unused_apicallbacks() AFTER");
print_apicallbacks();
#endif
}
#ifdef APICALLBACKDEBUG
void print_apicallbacks(void)
{
APICallback *m, *m_next;
unreal_log(ULOG_DEBUG, "module", "API_CALLBACK_LIST", NULL, "----");
for (m = apicallbacks; m; m = m_next)
{
m_next = m->next;
unreal_log(ULOG_DEBUG, "module", "API_CALLBACK_LIST", NULL,
"$name ($deleted)",
log_data_string("name", m->name),
log_data_string("deleted", m->unloaded ? "deleted" : ""));
}
unreal_log(ULOG_DEBUG, "module", "API_CALLBACK_LIST", NULL, "----");
}
#endif