1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-30 20:46:37 +02:00
Files
unrealircd/src/api-moddata.c
T
Bram Matthys b8d4cf7763 Actually call moddata_free_channel(channel);
This was a FIXME item that should have been addressed earlier.
We didn't use any MODDATATYPE_CHANNEL in the core up to now so
this was overlooked. We do use it from now on, though, and it
may very well have been used in 3rd party modules already.
2020-05-06 09:04:43 +02:00

465 lines
11 KiB
C

/************************************************************************
* IRC - Internet Relay Chat, src/api-moddata.c
* (C) 2003-2019 Bram Matthys (Syzop) 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.
*/
#include "unrealircd.h"
MODVAR ModDataInfo *MDInfo = NULL;
MODVAR ModData local_variable_moddata[MODDATA_MAX_LOCAL_VARIABLE];
MODVAR ModData global_variable_moddata[MODDATA_MAX_GLOBAL_VARIABLE];
ModDataInfo *ModDataAdd(Module *module, ModDataInfo req)
{
int slotav = 0; /* highest available slot */
ModDataInfo *m;
int new_struct = 0;
/* Hunt for highest available slot */
for (m = MDInfo; m ; m = m->next)
if (m->type == req.type)
{
/* Does an entry already exist with this name? */
if (!strcmp(m->name, req.name))
{
/* If old module is unloading (so reloading), then OK to take this slot */
if (m->unloaded)
{
slotav = m->slot;
m->unloaded = 0;
goto moddataadd_isok;
}
/* Otherwise, name collision */
if (module)
module->errorcode = MODERR_EXISTS;
return NULL;
}
/* Update next available slot */
slotav = MAX(slotav, m->slot+1);
}
/* Now check if we are within bounds (if we really have a free slot available) */
if (((req.type == MODDATATYPE_LOCAL_VARIABLE) && (slotav >= MODDATA_MAX_LOCAL_VARIABLE)) ||
((req.type == MODDATATYPE_GLOBAL_VARIABLE) && (slotav >= MODDATA_MAX_GLOBAL_VARIABLE)) ||
((req.type == MODDATATYPE_CLIENT) && (slotav >= MODDATA_MAX_CLIENT)) ||
((req.type == MODDATATYPE_LOCAL_CLIENT) && (slotav >= MODDATA_MAX_LOCAL_CLIENT)) ||
((req.type == MODDATATYPE_CHANNEL) && (slotav >= MODDATA_MAX_CHANNEL)) ||
((req.type == MODDATATYPE_MEMBER) && (slotav >= MODDATA_MAX_MEMBER)) ||
((req.type == MODDATATYPE_MEMBERSHIP) && (slotav >= MODDATA_MAX_MEMBERSHIP)))
{
if (module)
module->errorcode = MODERR_NOSPACE;
return NULL;
}
new_struct = 1;
m = safe_alloc(sizeof(ModDataInfo));
safe_strdup(m->name, req.name);
m->slot = slotav;
m->type = req.type;
moddataadd_isok:
m->free = req.free;
m->serialize = req.serialize;
m->unserialize = req.unserialize;
m->sync = req.sync;
m->owner = module;
if (new_struct)
AddListItem(m, MDInfo);
if (module)
{
ModuleObject *mobj = safe_alloc(sizeof(ModuleObject));
mobj->object.moddata = m;
mobj->type = MOBJ_MODDATA;
AddListItem(mobj, module->objects);
module->errorcode = MODERR_NOERROR;
}
return m;
}
void moddata_free_client(Client *client)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if (md->type == MODDATATYPE_CLIENT)
{
if (md->free && moddata_client(client, md).ptr)
md->free(&moddata_client(client, md));
}
memset(client->moddata, 0, sizeof(client->moddata));
}
void moddata_free_local_client(Client *client)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if (md->type == MODDATATYPE_LOCAL_CLIENT)
{
if (md->free && moddata_local_client(client, md).ptr)
md->free(&moddata_local_client(client, md));
}
memset(client->moddata, 0, sizeof(client->moddata));
}
void moddata_free_channel(Channel *channel)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if (md->type == MODDATATYPE_CHANNEL)
{
if (md->free && moddata_channel(channel, md).ptr)
md->free(&moddata_channel(channel, md));
}
memset(channel->moddata, 0, sizeof(channel->moddata));
}
void moddata_free_member(Member *m)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if (md->type == MODDATATYPE_MEMBER)
{
if (md->free && moddata_member(m, md).ptr)
md->free(&moddata_member(m, md));
}
memset(m->moddata, 0, sizeof(m->moddata));
}
void moddata_free_membership(Membership *m)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if (md->type == MODDATATYPE_MEMBERSHIP)
{
if (md->free && moddata_membership(m, md).ptr)
md->free(&moddata_membership(m, md));
}
memset(m->moddata, 0, sizeof(m->moddata));
}
/** Actually free all the ModData from all objects */
void unload_moddata_commit(ModDataInfo *md)
{
switch(md->type)
{
case MODDATATYPE_LOCAL_VARIABLE:
if (md->free && moddata_local_variable(md).ptr)
md->free(&moddata_local_variable(md));
memset(&moddata_local_variable(md), 0, sizeof(ModData));
break;
case MODDATATYPE_GLOBAL_VARIABLE:
if (md->free && moddata_global_variable(md).ptr)
md->free(&moddata_global_variable(md));
memset(&moddata_global_variable(md), 0, sizeof(ModData));
break;
case MODDATATYPE_CLIENT:
{
Client *client;
list_for_each_entry(client, &client_list, client_node)
{
if (md->free && moddata_client(client, md).ptr)
md->free(&moddata_client(client, md));
memset(&moddata_client(client, md), 0, sizeof(ModData));
}
break;
}
case MODDATATYPE_LOCAL_CLIENT:
{
Client *client;
list_for_each_entry(client, &lclient_list, lclient_node)
{
if (md->free && moddata_local_client(client, md).ptr)
md->free(&moddata_local_client(client, md));
memset(&moddata_local_client(client, md), 0, sizeof(ModData));
}
break;
}
case MODDATATYPE_CHANNEL:
{
Channel *channel;
for (channel = channels; channel; channel=channel->nextch)
{
if (md->free && moddata_channel(channel, md).ptr)
md->free(&moddata_channel(channel, md));
memset(&moddata_channel(channel, md), 0, sizeof(ModData));
}
break;
}
case MODDATATYPE_MEMBER:
{
Channel *channel;
Member *m;
for (channel = channels; channel; channel=channel->nextch)
{
for (m = channel->members; m; m = m->next)
{
if (md->free && moddata_member(m, md).ptr)
md->free(&moddata_member(m, md));
memset(&moddata_member(m, md), 0, sizeof(ModData));
}
}
break;
}
case MODDATATYPE_MEMBERSHIP:
{
Client *client;
Membership *m;
list_for_each_entry(client, &lclient_list, lclient_node)
{
if (!client->user)
continue;
for (m = client->user->channel; m; m = m->next)
{
if (md->free && moddata_membership(m, md).ptr)
md->free(&moddata_membership(m, md));
memset(&moddata_membership(m, md), 0, sizeof(ModData));
}
}
break;
}
}
DelListItem(md, MDInfo);
safe_free(md->name);
safe_free(md);
}
void ModDataDel(ModDataInfo *md)
{
/* Delete the reference to us first */
if (md->owner)
{
ModuleObject *mdobj;
for (mdobj = md->owner->objects; mdobj; mdobj = mdobj->next)
{
if ((mdobj->type == MOBJ_MODDATA) && (mdobj->object.moddata == md))
{
DelListItem(mdobj, md->owner->objects);
safe_free(mdobj);
break;
}
}
md->owner = NULL;
}
if (loop.ircd_rehashing)
md->unloaded = 1;
else
unload_moddata_commit(md);
}
void unload_all_unused_moddata(void)
{
ModDataInfo *md, *md_next;
for (md = MDInfo; md; md = md_next)
{
md_next = md->next;
if (md->unloaded)
unload_moddata_commit(md);
}
}
ModDataInfo *findmoddata_byname(char *name, ModDataType type)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if ((md->type == type) && !strcmp(name, md->name))
return md;
return NULL;
}
int module_has_moddata(Module *mod)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if (md->owner == mod)
return 1;
return 0;
}
/** Set ModData for client (via variable name, string value) */
int moddata_client_set(Client *client, char *varname, char *value)
{
ModDataInfo *md;
md = findmoddata_byname(varname, MODDATATYPE_CLIENT);
if (!md)
return 0;
if (value)
{
/* SET */
md->unserialize(value, &moddata_client(client, md));
}
else
{
/* UNSET */
md->free(&moddata_client(client, md));
memset(&moddata_client(client, md), 0, sizeof(ModData));
}
/* If 'sync' field is set and the client is not in pre-registered
* state then broadcast the new setting.
*/
if (md->sync && (IsUser(client) || IsServer(client) || IsMe(client)))
broadcast_md_client_cmd(NULL, &me, client, md->name, value);
return 1;
}
/** Get ModData for client (via variable name) */
char *moddata_client_get(Client *client, char *varname)
{
ModDataInfo *md;
md = findmoddata_byname(varname, MODDATATYPE_CLIENT);
if (!md)
return NULL;
return md->serialize(&moddata_client(client, md)); /* can be NULL */
}
/** Set ModData for LocalClient (via variable name, string value) */
int moddata_local_client_set(Client *client, char *varname, char *value)
{
ModDataInfo *md;
if (!MyConnect(client))
abort();
md = findmoddata_byname(varname, MODDATATYPE_LOCAL_CLIENT);
if (!md)
return 0;
if (value)
{
/* SET */
md->unserialize(value, &moddata_local_client(client, md));
}
else
{
/* UNSET */
md->free(&moddata_local_client(client, md));
memset(&moddata_local_client(client, md), 0, sizeof(ModData));
}
/* If 'sync' field is set and the client is not in pre-registered
* state then broadcast the new setting.
*/
if (md->sync && (IsUser(client) || IsServer(client) || IsMe(client)))
broadcast_md_client_cmd(NULL, &me, client, md->name, value);
return 1;
}
/** Get ModData for LocalClient (via variable name) */
char *moddata_local_client_get(Client *client, char *varname)
{
ModDataInfo *md;
if (!MyConnect(client))
abort();
md = findmoddata_byname(varname, MODDATATYPE_LOCAL_CLIENT);
if (!md)
return NULL;
return md->serialize(&moddata_local_client(client, md)); /* can be NULL */
}
/** Set local variable moddata (via variable name, string value) */
int moddata_local_variable_set(char *varname, char *value)
{
ModDataInfo *md;
md = findmoddata_byname(varname, MODDATATYPE_LOCAL_VARIABLE);
if (!md)
return 0;
if (value)
{
/* SET */
md->unserialize(value, &moddata_local_variable(md));
}
else
{
/* UNSET */
md->free(&moddata_local_variable(md));
memset(&moddata_local_variable(md), 0, sizeof(ModData));
}
return 1;
}
/** Set global variable moddata (via variable name, string value) */
int moddata_global_variable_set(char *varname, char *value)
{
ModDataInfo *md;
md = findmoddata_byname(varname, MODDATATYPE_GLOBAL_VARIABLE);
if (!md)
return 0;
if (value)
{
/* SET */
md->unserialize(value, &moddata_global_variable(md));
}
else
{
/* UNSET */
md->free(&moddata_global_variable(md));
memset(&moddata_global_variable(md), 0, sizeof(ModData));
}
if (md->sync)
broadcast_md_globalvar_cmd(NULL, &me, md->name, value);
return 1;
}
/* The rest of the MD related functions, the send/receive functions,
* are in src/modules/md.c
*/