unrealircd

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

api-moddata.c (11698B)

      1 /************************************************************************
      2  *   IRC - Internet Relay Chat, src/api-moddata.c
      3  *   (C) 2003-2019 Bram Matthys (Syzop) 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 #include "unrealircd.h"
     24 
     25 MODVAR ModDataInfo *MDInfo = NULL;
     26 
     27 MODVAR ModData local_variable_moddata[MODDATA_MAX_LOCAL_VARIABLE];
     28 MODVAR ModData global_variable_moddata[MODDATA_MAX_GLOBAL_VARIABLE];
     29 
     30 ModDataInfo *ModDataAdd(Module *module, ModDataInfo req)
     31 {
     32 	int slotav = 0; /* highest available slot */
     33 	ModDataInfo *m;
     34 	int new_struct = 0;
     35 	
     36 	/* Hunt for highest available slot */
     37 	for (m = MDInfo; m ; m = m->next)
     38 		if (m->type == req.type)
     39 		{
     40 			/* Does an entry already exist with this name? */
     41 			if (!strcmp(m->name, req.name))
     42 			{
     43 				/* If old module is unloading (so reloading), then OK to take this slot */
     44 				if (m->unloaded)
     45 				{
     46 					slotav = m->slot;
     47 					m->unloaded = 0;
     48 					goto moddataadd_isok;
     49 				}
     50 				/* Otherwise, name collision */
     51 				if (module)
     52 					module->errorcode = MODERR_EXISTS;
     53 				return NULL;
     54 			}
     55 			/* Update next available slot */
     56 			slotav = MAX(slotav, m->slot+1);
     57 		}
     58 
     59 	/* Now check if we are within bounds (if we really have a free slot available) */
     60 	if (((req.type == MODDATATYPE_LOCAL_VARIABLE) && (slotav >= MODDATA_MAX_LOCAL_VARIABLE)) ||
     61 	    ((req.type == MODDATATYPE_GLOBAL_VARIABLE) && (slotav >= MODDATA_MAX_GLOBAL_VARIABLE)) ||
     62 	    ((req.type == MODDATATYPE_CLIENT) && (slotav >= MODDATA_MAX_CLIENT)) ||
     63 	    ((req.type == MODDATATYPE_LOCAL_CLIENT) && (slotav >= MODDATA_MAX_LOCAL_CLIENT)) ||
     64 	    ((req.type == MODDATATYPE_CHANNEL) && (slotav >= MODDATA_MAX_CHANNEL)) ||
     65 	    ((req.type == MODDATATYPE_MEMBER) && (slotav >= MODDATA_MAX_MEMBER)) ||
     66 	    ((req.type == MODDATATYPE_MEMBERSHIP) && (slotav >= MODDATA_MAX_MEMBERSHIP)))
     67 	{
     68 		unreal_log(ULOG_ERROR, "module", "MOD_DATA_OUT_OF_SPACE", NULL,
     69 		           "ModDataAdd: out of space!!!");
     70 		if (module)
     71 			module->errorcode = MODERR_NOSPACE;
     72 		return NULL;
     73 	}
     74 
     75 	new_struct = 1;
     76 	m = safe_alloc(sizeof(ModDataInfo));
     77 	safe_strdup(m->name, req.name);
     78 	m->slot = slotav;
     79 	m->type = req.type;
     80 moddataadd_isok:
     81 	m->free = req.free;
     82 	m->serialize = req.serialize;
     83 	m->unserialize = req.unserialize;
     84 	m->sync = req.sync;
     85 	m->remote_write = req.remote_write;
     86 	m->self_write = req.self_write;
     87 	m->owner = module;
     88 	
     89 	if (new_struct)
     90 		AddListItem(m, MDInfo);
     91 
     92 	if (module)
     93 	{
     94 		ModuleObject *mobj = safe_alloc(sizeof(ModuleObject));
     95 		mobj->object.moddata = m;
     96 		mobj->type = MOBJ_MODDATA;
     97 		AddListItem(mobj, module->objects);
     98 		module->errorcode = MODERR_NOERROR;
     99 	}
    100 	
    101 	return m;
    102 }
    103 
    104 void moddata_free_client(Client *client)
    105 {
    106 	ModDataInfo *md;
    107 
    108 	for (md = MDInfo; md; md = md->next)
    109 		if (md->type == MODDATATYPE_CLIENT)
    110 		{
    111 			if (md->free && moddata_client(client, md).ptr)
    112 				md->free(&moddata_client(client, md));
    113 		}
    114 
    115 	memset(client->moddata, 0, sizeof(client->moddata));
    116 }
    117 
    118 void moddata_free_local_client(Client *client)
    119 {
    120 	ModDataInfo *md;
    121 
    122 	for (md = MDInfo; md; md = md->next)
    123 		if (md->type == MODDATATYPE_LOCAL_CLIENT)
    124 		{
    125 			if (md->free && moddata_local_client(client, md).ptr)
    126 				md->free(&moddata_local_client(client, md));
    127 		}
    128 
    129 	memset(client->moddata, 0, sizeof(client->moddata));
    130 }
    131 
    132 void moddata_free_channel(Channel *channel)
    133 {
    134 	ModDataInfo *md;
    135 
    136 	for (md = MDInfo; md; md = md->next)
    137 		if (md->type == MODDATATYPE_CHANNEL)
    138 		{
    139 			if (md->free && moddata_channel(channel, md).ptr)
    140 				md->free(&moddata_channel(channel, md));
    141 		}
    142 
    143 	memset(channel->moddata, 0, sizeof(channel->moddata));
    144 }
    145 
    146 void moddata_free_member(Member *m)
    147 {
    148 	ModDataInfo *md;
    149 
    150 	for (md = MDInfo; md; md = md->next)
    151 		if (md->type == MODDATATYPE_MEMBER)
    152 		{
    153 			if (md->free && moddata_member(m, md).ptr)
    154 				md->free(&moddata_member(m, md));
    155 		}
    156 
    157 	memset(m->moddata, 0, sizeof(m->moddata));
    158 }
    159 
    160 void moddata_free_membership(Membership *m)
    161 {
    162 ModDataInfo *md;
    163 
    164 	for (md = MDInfo; md; md = md->next)
    165 		if (md->type == MODDATATYPE_MEMBERSHIP)
    166 		{
    167 			if (md->free && moddata_membership(m, md).ptr)
    168 				md->free(&moddata_membership(m, md));
    169 		}
    170 
    171 	memset(m->moddata, 0, sizeof(m->moddata));
    172 }
    173 
    174 /** Actually free all the ModData from all objects */
    175 void unload_moddata_commit(ModDataInfo *md)
    176 {
    177 	switch(md->type)
    178 	{
    179 		case MODDATATYPE_LOCAL_VARIABLE:
    180 			if (md->free && moddata_local_variable(md).ptr)
    181 				md->free(&moddata_local_variable(md));
    182 			memset(&moddata_local_variable(md), 0, sizeof(ModData));
    183 			break;
    184 		case MODDATATYPE_GLOBAL_VARIABLE:
    185 			if (md->free && moddata_global_variable(md).ptr)
    186 				md->free(&moddata_global_variable(md));
    187 			memset(&moddata_global_variable(md), 0, sizeof(ModData));
    188 			break;
    189 		case MODDATATYPE_CLIENT:
    190 		{
    191 			Client *client;
    192 			list_for_each_entry(client, &client_list, client_node)
    193 			{
    194 				if (md->free && moddata_client(client, md).ptr)
    195 					md->free(&moddata_client(client, md));
    196 				memset(&moddata_client(client, md), 0, sizeof(ModData));
    197 			}
    198 			break;
    199 		}
    200 		case MODDATATYPE_LOCAL_CLIENT:
    201 		{
    202 			Client *client;
    203 			list_for_each_entry(client, &lclient_list, lclient_node)
    204 			{
    205 				if (md->free && moddata_local_client(client, md).ptr)
    206 					md->free(&moddata_local_client(client, md));
    207 				memset(&moddata_local_client(client, md), 0, sizeof(ModData));
    208 			}
    209 			break;
    210 		}
    211 		case MODDATATYPE_CHANNEL:
    212 		{
    213 			Channel *channel;
    214 			for (channel = channels; channel; channel=channel->nextch)
    215 			{
    216 				if (md->free && moddata_channel(channel, md).ptr)
    217 					md->free(&moddata_channel(channel, md));
    218 				memset(&moddata_channel(channel, md), 0, sizeof(ModData));
    219 			}
    220 			break;
    221 		}
    222 		case MODDATATYPE_MEMBER:
    223 		{
    224 			Channel *channel;
    225 			Member *m;
    226 			for (channel = channels; channel; channel=channel->nextch)
    227 			{
    228 				for (m = channel->members; m; m = m->next)
    229 				{
    230 					if (md->free && moddata_member(m, md).ptr)
    231 						md->free(&moddata_member(m, md));
    232 					memset(&moddata_member(m, md), 0, sizeof(ModData));
    233 				}
    234 			}
    235 			break;
    236 		}
    237 		case MODDATATYPE_MEMBERSHIP:
    238 		{
    239 			Client *client;
    240 			Membership *m;
    241 			list_for_each_entry(client, &lclient_list, lclient_node)
    242 			{
    243 				if (!client->user)
    244 					continue;
    245 				for (m = client->user->channel; m; m = m->next)
    246 				{
    247 					if (md->free && moddata_membership(m, md).ptr)
    248 						md->free(&moddata_membership(m, md));
    249 					memset(&moddata_membership(m, md), 0, sizeof(ModData));
    250 				}
    251 			}
    252 			break;
    253 		}
    254 	}
    255 	
    256 	DelListItem(md, MDInfo);
    257 	safe_free(md->name);
    258 	safe_free(md);
    259 }
    260 
    261 void ModDataDel(ModDataInfo *md)
    262 {
    263 	/* Delete the reference to us first */
    264 	if (md->owner)
    265 	{
    266 		ModuleObject *mdobj;
    267 		for (mdobj = md->owner->objects; mdobj; mdobj = mdobj->next)
    268 		{
    269 			if ((mdobj->type == MOBJ_MODDATA) && (mdobj->object.moddata == md))
    270 			{
    271 				DelListItem(mdobj, md->owner->objects);
    272 				safe_free(mdobj);
    273 				break;
    274 			}
    275 		}
    276 		md->owner = NULL;
    277 	}
    278 
    279 	if (loop.rehashing)
    280 		md->unloaded = 1;
    281 	else
    282 		unload_moddata_commit(md);
    283 }
    284 
    285 void unload_all_unused_moddata(void)
    286 {
    287 ModDataInfo *md, *md_next;
    288 
    289 	for (md = MDInfo; md; md = md_next)
    290 	{
    291 		md_next = md->next;
    292 		if (md->unloaded)
    293 			unload_moddata_commit(md);
    294 	}
    295 }
    296 
    297 ModDataInfo *findmoddata_byname(const char *name, ModDataType type)
    298 {
    299 ModDataInfo *md;
    300 
    301 	for (md = MDInfo; md; md = md->next)
    302 		if ((md->type == type) && !strcmp(name, md->name))
    303 			return md;
    304 
    305 	return NULL;
    306 }
    307 
    308 int module_has_moddata(Module *mod)
    309 {
    310 	ModDataInfo *md;
    311 
    312 	for (md = MDInfo; md; md = md->next)
    313 		if (md->owner == mod)
    314 			return 1;
    315 
    316 	return 0;
    317 }
    318 
    319 /** Set ModData for client (via variable name, string value) */
    320 int moddata_client_set(Client *client, const char *varname, const char *value)
    321 {
    322 	ModDataInfo *md;
    323 
    324 	md = findmoddata_byname(varname, MODDATATYPE_CLIENT);
    325 
    326 	if (!md)
    327 		return 0;
    328 
    329 	if (value)
    330 	{
    331 		/* SET */
    332 		md->unserialize(value, &moddata_client(client, md));
    333 	}
    334 	else
    335 	{
    336 		/* UNSET */
    337 		md->free(&moddata_client(client, md));
    338 		memset(&moddata_client(client, md), 0, sizeof(ModData));
    339 	}
    340 
    341 	/* If 'sync' field is set and the client is not in pre-registered
    342 	 * state then broadcast the new setting.
    343 	 */
    344 	if (md->sync && (IsUser(client) || IsServer(client) || IsMe(client)))
    345 		broadcast_md_client_cmd(NULL, &me, client, md->name, value);
    346 
    347 	return 1;
    348 }
    349 
    350 /** Get ModData for client (via variable name) */
    351 const char *moddata_client_get(Client *client, const char *varname)
    352 {
    353 	ModDataInfo *md;
    354 
    355 	md = findmoddata_byname(varname, MODDATATYPE_CLIENT);
    356 
    357 	if (!md)
    358 		return NULL;
    359 
    360 	return md->serialize(&moddata_client(client, md)); /* can be NULL */
    361 }
    362 
    363 /** Get ModData for client (via variable name) */
    364 ModData *moddata_client_get_raw(Client *client, const char *varname)
    365 {
    366 	ModDataInfo *md;
    367 
    368 	md = findmoddata_byname(varname, MODDATATYPE_CLIENT);
    369 
    370 	if (!md)
    371 		return NULL;
    372 
    373 	return &moddata_client(client, md); /* can be NULL */
    374 }
    375 
    376 /** Set ModData for LocalClient (via variable name, string value) */
    377 int moddata_local_client_set(Client *client, const char *varname, const char *value)
    378 {
    379 	ModDataInfo *md;
    380 
    381 	if (!MyConnect(client))
    382 		abort();
    383 
    384 	md = findmoddata_byname(varname, MODDATATYPE_LOCAL_CLIENT);
    385 
    386 	if (!md)
    387 		return 0;
    388 
    389 	if (value)
    390 	{
    391 		/* SET */
    392 		md->unserialize(value, &moddata_local_client(client, md));
    393 	}
    394 	else
    395 	{
    396 		/* UNSET */
    397 		md->free(&moddata_local_client(client, md));
    398 		memset(&moddata_local_client(client, md), 0, sizeof(ModData));
    399 	}
    400 
    401 	/* If 'sync' field is set and the client is not in pre-registered
    402 	 * state then broadcast the new setting.
    403 	 */
    404 	if (md->sync && (IsUser(client) || IsServer(client) || IsMe(client)))
    405 		broadcast_md_client_cmd(NULL, &me, client, md->name, value);
    406 
    407 	return 1;
    408 }
    409 
    410 /** Get ModData for LocalClient (via variable name) */
    411 const char *moddata_local_client_get(Client *client, const char *varname)
    412 {
    413 	ModDataInfo *md;
    414 
    415 	if (!MyConnect(client))
    416 		abort();
    417 
    418 	md = findmoddata_byname(varname, MODDATATYPE_LOCAL_CLIENT);
    419 
    420 	if (!md)
    421 		return NULL;
    422 
    423 	return md->serialize(&moddata_local_client(client, md)); /* can be NULL */
    424 }
    425 
    426 /** Set local variable moddata (via variable name, string value) */
    427 int moddata_local_variable_set(const char *varname, const char *value)
    428 {
    429 	ModDataInfo *md;
    430 
    431 	md = findmoddata_byname(varname, MODDATATYPE_LOCAL_VARIABLE);
    432 
    433 	if (!md)
    434 		return 0;
    435 
    436 	if (value)
    437 	{
    438 		/* SET */
    439 		md->unserialize(value, &moddata_local_variable(md));
    440 	}
    441 	else
    442 	{
    443 		/* UNSET */
    444 		md->free(&moddata_local_variable(md));
    445 		memset(&moddata_local_variable(md), 0, sizeof(ModData));
    446 	}
    447 
    448 	return 1;
    449 }
    450 
    451 /** Set global variable moddata (via variable name, string value) */
    452 int moddata_global_variable_set(const char *varname, const char *value)
    453 {
    454 	ModDataInfo *md;
    455 
    456 	md = findmoddata_byname(varname, MODDATATYPE_GLOBAL_VARIABLE);
    457 
    458 	if (!md)
    459 		return 0;
    460 
    461 	if (value)
    462 	{
    463 		/* SET */
    464 		md->unserialize(value, &moddata_global_variable(md));
    465 	}
    466 	else
    467 	{
    468 		/* UNSET */
    469 		md->free(&moddata_global_variable(md));
    470 		memset(&moddata_global_variable(md), 0, sizeof(ModData));
    471 	}
    472 
    473 	if (md->sync)
    474 		broadcast_md_globalvar_cmd(NULL, &me, md->name, value);
    475 
    476 	return 1;
    477 }
    478 
    479 /* The rest of the MD related functions, the send/receive functions,
    480  * are in src/modules/md.c
    481  */