unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

api-messagetag.c (5548B)

      1 /************************************************************************
      2  *   UnrealIRCd - Unreal Internet Relay Chat Daemon - src/api-mtag.c
      3  *   (c) 2019- Bram Matthys and The UnrealIRCd team
      4  *
      5  *   See file AUTHORS in IRC package for additional names of
      6  *   the programmers. 
      7  *
      8  *   This program is free software; you can redistribute it and/or modify
      9  *   it under the terms of the GNU General Public License as published by
     10  *   the Free Software Foundation; either version 1, or (at your option)
     11  *   any later version.
     12  *
     13  *   This program is distributed in the hope that it will be useful,
     14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *   GNU General Public License for more details.
     17  *
     18  *   You should have received a copy of the GNU General Public License
     19  *   along with this program; if not, write to the Free Software
     20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     21  */
     22 
     23 /** @file
     24  * @brief Message tag API
     25  */
     26 #include "unrealircd.h"
     27 
     28 /** This is the message tags API (message-tags).
     29  * For an overview of message tags in general (not the API)
     30  * see https://www.unrealircd.org/docs/Message_tags
     31  * @defgroup MessagetagAPI Message tag API
     32  * @{
     33  */
     34 
     35 /** List of message tag handlers */
     36 MODVAR MessageTagHandler *mtaghandlers = NULL;
     37 
     38 /* Forward declarations */
     39 static void unload_mtag_handler_commit(MessageTagHandler *m);
     40 
     41 /** Adds a new message tag handler.
     42  * @param module The module which owns this message-tag handler.
     43  * @param mreq   The details of the request such as which message tag, the handler, etc.
     44  * @return Returns the handle to the new token if successful, otherwise NULL.
     45  *         The module's error code contains specific information about the
     46  *         error.
     47  */
     48 MessageTagHandler *MessageTagHandlerAdd(Module *module, MessageTagHandlerInfo *mreq)
     49 {
     50 	MessageTagHandler *m;
     51 
     52 	/* Some consistency checks to avoid a headache for module devs later on: */
     53 	if ((mreq->flags & MTAG_HANDLER_FLAGS_NO_CAP_NEEDED) && mreq->clicap_handler)
     54 	{
     55 		unreal_log(ULOG_ERROR, "module", "MESSAGETAGHANDLERADD_API_ERROR", NULL,
     56 			   "MessageTagHandlerAdd() from module $module_name: "
     57 			   ".flags is set to MTAG_HANDLER_FLAGS_NO_CAP_NEEDED "
     58 			   "but a .clicap_handler is passed as well. These options are mutually "
     59 			   "exclusive, choose one or the other.",
     60 			   log_data_string("module_name", module->header->name));
     61 		abort();
     62 	} else if (!(mreq->flags & MTAG_HANDLER_FLAGS_NO_CAP_NEEDED) && !mreq->clicap_handler)
     63 	{
     64 		unreal_log(ULOG_ERROR, "module", "MESSAGETAGHANDLERADD_API_ERROR", NULL,
     65 			   "MessageTagHandlerAdd() from module $module_name: "
     66 			   "no .clicap_handler is passed. If the "
     67 		           "message tag really does not require a cap then you must "
     68 		           "set .flags to MTAG_HANDLER_FLAGS_NO_CAP_NEEDED",
     69 		           log_data_string("module_name", module->header->name));
     70 		abort();
     71 	}
     72 
     73 	m = MessageTagHandlerFind(mreq->name);
     74 	if (m)
     75 	{
     76 		if (m->unloaded)
     77 		{
     78 			m->unloaded = 0;
     79 		} else {
     80 			if (module)
     81 				module->errorcode = MODERR_EXISTS;
     82 			return NULL;
     83 		}
     84 	} else {
     85 		/* New message tag handler */
     86 		m = safe_alloc(sizeof(MessageTagHandler));
     87 		safe_strdup(m->name, mreq->name);
     88 		AddListItem(m, mtaghandlers);
     89 	}
     90 	/* Add or update the following fields: */
     91 	m->owner = module;
     92 	m->flags = mreq->flags;
     93 	m->is_ok = mreq->is_ok;
     94 	m->should_send_to_client = mreq->should_send_to_client;
     95 	m->clicap_handler = mreq->clicap_handler;
     96 
     97 	/* Update reverse dependency (if any) */
     98 	if (m->clicap_handler)
     99 		m->clicap_handler->mtag_handler = m;
    100 
    101 	if (module)
    102 	{
    103 		ModuleObject *mobj = safe_alloc(sizeof(ModuleObject));
    104 		mobj->type = MOBJ_MTAG;
    105 		mobj->object.mtag = m;
    106 		AddListItem(mobj, module->objects);
    107 		module->errorcode = MODERR_NOERROR;
    108 	}
    109 
    110 	return m;
    111 }
    112 
    113 /** Returns the message tag handler for the given name.
    114  * @param name The message-tag name to search for.
    115  * @return Returns the handle to the message tag handler,
    116  *         or NULL if not found.
    117  */
    118 MessageTagHandler *MessageTagHandlerFind(const char *name)
    119 {
    120 	MessageTagHandler *m;
    121 
    122 	for (m = mtaghandlers; m; m = m->next)
    123 	{
    124 		if (!strcasecmp(name, m->name))
    125 			return m;
    126 	}
    127 	return NULL;
    128 }
    129 
    130 /** Remove the specified message tag handler - modules should not call this.
    131  * This is done automatically for modules on unload, so is only called internally.
    132  * @param m The message tag handler to remove.
    133  */
    134 void MessageTagHandlerDel(MessageTagHandler *m)
    135 {
    136 	if (m->owner)
    137 	{
    138 		ModuleObject *mobj;
    139 		for (mobj = m->owner->objects; mobj; mobj = mobj->next) {
    140 			if (mobj->type == MOBJ_MTAG && mobj->object.mtag == m)
    141 			{
    142 				DelListItem(mobj, m->owner->objects);
    143 				safe_free(mobj);
    144 				break;
    145 			}
    146 		}
    147 		m->owner = NULL;
    148 	}
    149 
    150 	if (loop.rehashing)
    151 		m->unloaded = 1;
    152 	else
    153 		unload_mtag_handler_commit(m);
    154 }
    155 
    156 /** @} */
    157 
    158 static void unload_mtag_handler_commit(MessageTagHandler *m)
    159 {
    160 	/* This is an unusual operation, I think we should log it. */
    161 	unreal_log(ULOG_INFO, "module", "UNLOAD_MESSAGE_TAG", NULL,
    162 	           "Unloading message-tag handler for '$token'",
    163 	           log_data_string("token", m->name));
    164 
    165 	/* Remove reverse dependency, if any */
    166 	if (m->clicap_handler)
    167 		m->clicap_handler->mtag_handler = NULL;
    168 
    169 	/* Destroy the object */
    170 	DelListItem(m, mtaghandlers);
    171 	safe_free(m->name);
    172 	safe_free(m);
    173 }
    174 
    175 void unload_all_unused_mtag_handlers(void)
    176 {
    177 	MessageTagHandler *m, *m_next;
    178 
    179 	for (m = mtaghandlers; m; m = m_next)
    180 	{
    181 		m_next = m->next;
    182 		if (m->unloaded)
    183 			unload_mtag_handler_commit(m);
    184 	}
    185 }