mirror of
git://git.acid.vegas/unrealircd.git
synced 2025-02-17 09:49:06 +00:00
482 lines
11 KiB
C
482 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)))
|
|
{
|
|
unreal_log(ULOG_ERROR, "module", "MOD_DATA_OUT_OF_SPACE", NULL,
|
|
"ModDataAdd: out of space!!!");
|
|
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->remote_write = req.remote_write;
|
|
m->self_write = req.self_write;
|
|
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.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(const 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, const char *varname, const 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) */
|
|
const char *moddata_client_get(Client *client, const char *varname)
|
|
{
|
|
ModDataInfo *md;
|
|
|
|
md = findmoddata_byname(varname, MODDATATYPE_CLIENT);
|
|
|
|
if (!md)
|
|
return NULL;
|
|
|
|
return md->serialize(&moddata_client(client, md)); /* can be NULL */
|
|
}
|
|
|
|
/** Get ModData for client (via variable name) */
|
|
ModData *moddata_client_get_raw(Client *client, const char *varname)
|
|
{
|
|
ModDataInfo *md;
|
|
|
|
md = findmoddata_byname(varname, MODDATATYPE_CLIENT);
|
|
|
|
if (!md)
|
|
return NULL;
|
|
|
|
return &moddata_client(client, md); /* can be NULL */
|
|
}
|
|
|
|
/** Set ModData for LocalClient (via variable name, string value) */
|
|
int moddata_local_client_set(Client *client, const char *varname, const 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) */
|
|
const char *moddata_local_client_get(Client *client, const 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(const char *varname, const 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(const char *varname, const 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
|
|
*/
|