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 */