00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] = "$Id: script.c,v 1.27 2007-04-14 15:21:12 sven Exp $";
00022 #endif
00023
00024 #include <eggdrop/eggdrop.h>
00025
00026 #define EVENT_VAR 1
00027 #define EVENT_CMD 2
00028
00029 typedef struct {
00030 int event;
00031 void *data;
00032 void *key;
00033 } journal_event_t;
00034
00035 typedef struct {
00036 script_callback_t *callback;
00037 int id;
00038 unsigned char *text;
00039 int len;
00040 } script_dns_callback_data_t;
00041
00042 static journal_event_t *journal_events = NULL;
00043 static int njournal_events = 0;
00044
00045 static script_module_t **script_modules = NULL;
00046 static int nscript_modules = 0;
00047
00048 static void *journal_del(int event, void *key);
00049 static void journal_add(int event, void *data, void *key);
00050
00051 static script_command_t script_cmds[] = {
00052 {"", "loadscript", script_load, NULL, 1, "s", "filename", SCRIPT_INTEGER, 0},
00053 {0}
00054 };
00055
00056 int script_init(void)
00057 {
00058 script_create_commands(script_cmds);
00059
00060 return(0);
00061 }
00062
00063 int script_shutdown(void)
00064 {
00065 int i;
00066
00067 script_delete_commands(script_cmds);
00068
00069
00070
00071
00072 if (nscript_modules > 0) {
00073 for (i = nscript_modules - 1; i >= 0; i--) {
00074 script_unregister_module(script_modules[i]);
00075 }
00076 }
00077 if (script_modules) free(script_modules); script_modules = NULL;
00078
00079
00080 if (njournal_events > 0) {
00081 for (i = njournal_events - 1; i >= 0; i--) {
00082 journal_del(
00083 journal_events[i].event,
00084 journal_events[i].key);
00085 }
00086 }
00087 if (journal_events) free(journal_events); journal_events = NULL;
00088
00089 return (0);
00090 }
00091
00107 int script_remove_events_by_owner(egg_module_t *module, void *script)
00108 {
00109 int removed = 0;
00110
00111 removed += botnet_delete_by_owner(module, script);
00112 removed += partymember_delete_by_owner(module, script);
00113 removed += kill_binds_by_owner(module, script);
00114 removed += timer_destroy_by_owner(module, script);
00115 removed += egg_dns_cancel_by_owner(module, script);
00116 removed += egg_ident_cancel_by_owner(module, script);
00117 return removed;
00118 }
00119
00120
00121 int script_register_module(script_module_t *module)
00122 {
00123 script_modules = realloc(script_modules, sizeof(*script_modules) * (nscript_modules+1));
00124 script_modules[nscript_modules] = module;
00125 nscript_modules++;
00126 return(0);
00127 }
00128
00129
00130 int script_unregister_module(script_module_t *module)
00131 {
00132 int i;
00133
00134 for (i = 0; i < nscript_modules; i++) {
00135 if (script_modules[i] == module) break;
00136 }
00137 if (i == nscript_modules) return(-1);
00138 memmove(script_modules+i, script_modules+i+1, sizeof(script_module_t) * (nscript_modules-i-1));
00139 nscript_modules--;
00140 return(0);
00141 }
00142
00143
00144
00145 int script_playback(script_module_t *module)
00146 {
00147 int i;
00148
00149 for (i = 0; i < njournal_events; i++) {
00150 switch (journal_events[i].event) {
00151 case EVENT_VAR:
00152 module->link_var(module->client_data, journal_events[i].data);
00153 break;
00154 case EVENT_CMD:
00155 module->create_command(module->client_data, journal_events[i].data);
00156 break;
00157 }
00158 }
00159 return(0);
00160 }
00161
00162
00163 static void journal_add(int event, void *data, void *key)
00164 {
00165 journal_events = realloc(journal_events, sizeof(*journal_events) * (njournal_events+1));
00166 journal_events[njournal_events].event = event;
00167 journal_events[njournal_events].data = data;
00168 journal_events[njournal_events].key = key;
00169 njournal_events++;
00170 }
00171
00172
00173 static void *journal_del(int event, void *key)
00174 {
00175 int i;
00176 void *data = NULL;
00177
00178 for (i = 0; i < njournal_events; i++) {
00179 if (journal_events[i].event == event && journal_events[i].key == key) break;
00180 }
00181 if (i < njournal_events) {
00182 data = journal_events[i].data;
00183 memmove(journal_events+i, journal_events+i+1, sizeof(*journal_events) * (njournal_events-i-1));
00184 njournal_events--;
00185 }
00186
00187 return(data);
00188 }
00189
00190
00191
00192 int script_linked_var_on_write(script_linked_var_t *var, script_var_t *newval)
00193 {
00194 int r;
00195 char **charptr;
00196
00197
00198 if (var->callbacks && var->callbacks->on_write) {
00199 r = (var->callbacks->on_write)(var, newval);
00200 return(r);
00201 }
00202
00203
00204 switch (var->type & SCRIPT_TYPE_MASK) {
00205 case SCRIPT_UNSIGNED:
00206 case SCRIPT_INTEGER:
00207 *(int *)(var->value) = (int) newval->value;
00208 break;
00209 case SCRIPT_STRING:
00210 charptr = (char **)var->value;
00211 if (*charptr) free(*charptr);
00212 if (newval->type & SCRIPT_FREE) *charptr = newval->value;
00213 else *charptr = strdup(newval->value);
00214 break;
00215 }
00216 return(0);
00217 }
00218
00219
00220
00221
00222 static int my_command_handler(void *client_data, script_args_t *args, script_var_t *retval)
00223 {
00224 script_command_t *cmd = client_data;
00225 void *static_argstack[20], *static_free_args[20];
00226 void **argstack, **free_args;
00227 script_callback_t **callbacks, *static_callbacks[20];
00228 int argstack_len, nfree_args, ncallbacks;
00229 char *syntax;
00230 int i, skip, nopts, err;
00231 void *simple_retval;
00232 script_var_t var;
00233 void *(*callback)();
00234
00235
00236 if (cmd->flags & SCRIPT_VAR_ARGS) err = (cmd->nargs > args->len);
00237 else err = (cmd->nargs != args->len);
00238
00239 if (err) {
00240 retval->type = SCRIPT_STRING | SCRIPT_ERROR;
00241 retval->value = cmd->syntax_error;
00242 return(-1);
00243 }
00244
00245
00246
00247 if (args->len+3 > 20) {
00248 argstack = calloc(args->len+3, sizeof(void *));
00249 free_args = calloc(args->len, sizeof(void *));
00250 callbacks = calloc(args->len, sizeof(*callbacks));
00251 }
00252 else {
00253 memset(static_argstack, 0, sizeof(static_argstack));
00254 argstack = static_argstack;
00255 free_args = static_free_args;
00256 callbacks = static_callbacks;
00257 }
00258 argstack_len = 3;
00259 nfree_args = 0;
00260 ncallbacks = 0;
00261
00262
00263 syntax = cmd->syntax;
00264 if (cmd->flags & SCRIPT_VAR_FRONT) {
00265 skip = strlen(syntax) - args->len;
00266 if (skip < 0) skip = 0;
00267 argstack_len += skip;
00268 syntax += skip;
00269 }
00270 else skip = 0;
00271
00272
00273
00274 for (i = 0; i < args->len; i++) {
00275 err = script_get_arg(args, i, &var, *syntax);
00276 if (err) {
00277 retval->value = cmd->syntax_error;
00278 retval->type = SCRIPT_STRING | SCRIPT_ERROR;
00279 goto cleanup_args;
00280 }
00281 if (var.type & SCRIPT_FREE) free_args[nfree_args++] = var.value;
00282 else if (*syntax == SCRIPT_CALLBACK) callbacks[ncallbacks++] = var.value;
00283 argstack[argstack_len++] = var.value;
00284 syntax++;
00285 }
00286
00287
00288
00289 nopts = 3;
00290 if (cmd->flags & SCRIPT_PASS_COUNT) {
00291 nopts--;
00292 argstack[nopts] = (void *)(argstack_len - 3 - skip);
00293 }
00294 if (cmd->flags & SCRIPT_PASS_RETVAL) {
00295 nopts--;
00296 argstack[nopts] = retval;
00297 }
00298 if (cmd->flags & SCRIPT_PASS_CDATA) {
00299 nopts--;
00300 argstack[nopts] = cmd->client_data;
00301 }
00302
00303
00304 argstack += nopts;
00305 argstack_len -= nopts;
00306
00307
00308 callback = (void *(*)())cmd->callback;
00309 if (cmd->flags & SCRIPT_PASS_ARRAY) {
00310 simple_retval = callback(argstack_len, argstack);
00311 }
00312 else {
00313 simple_retval = callback(argstack[0], argstack[1],
00314 argstack[2], argstack[3], argstack[4], argstack[5],
00315 argstack[6], argstack[7], argstack[8], argstack[9]);
00316 }
00317
00318 argstack -= nopts;
00319 argstack_len += nopts;
00320
00321
00322 if (!(cmd->flags & SCRIPT_PASS_RETVAL)) {
00323 retval->type = cmd->retval_type;
00324 retval->len = -1;
00325 retval->value = simple_retval;
00326 }
00327
00328 cleanup_args:
00329 for (i = 0; i < nfree_args; i++) {
00330 if (free_args[i]) free(free_args[i]);
00331 }
00332 if (err) {
00333 for (i = 0; i < ncallbacks; i++) {
00334 if (callbacks[i] && callbacks[i]->owner && callbacks[i]->owner->on_delete) callbacks[i]->owner->on_delete(callbacks[i]->owner, callbacks[i]);
00335 }
00336 }
00337 if (argstack != static_argstack) {
00338 free(argstack);
00339 free(free_args);
00340 free(callbacks);
00341 }
00342
00343 return(0);
00344 }
00345
00346
00347 int script_load(char *filename)
00348 {
00349 int i, ret;
00350
00351 egg_assert_val (filename != NULL, 0);
00352
00353
00354 if (nscript_modules == 0) {
00355 putlog (LOG_MISC, "*", _("Failed to load script '%s': no script modules loaded."),
00356 filename);
00357 return 0;
00358 }
00359
00360 for (i = 0; i < nscript_modules; i++) {
00361 ret = script_modules[i]->load_script(script_modules[i]->client_data, filename);
00362
00363 switch (ret) {
00364
00365
00366
00367 case (SCRIPT_OK):
00368 putlog (LOG_MISC, "*", _("Script loaded: %s"), filename);
00369 return 1;
00370
00371
00372
00373 case (SCRIPT_ERR_NOT_RESPONSIBLE):
00374 break;
00375
00376
00377
00378 case (SCRIPT_ERR_CODE):
00379 return 0;
00380
00381 }
00382 }
00383
00384 putlog (LOG_MISC, "*", _("Failed to load script '%s': no appropiate script module."), filename);
00385
00386 return 0;
00387 }
00388
00389 int script_link_vars(script_linked_var_t *table)
00390 {
00391 int i;
00392
00393 while (table->class && table->name) {
00394 journal_add(EVENT_VAR, table, table);
00395 for (i = 0; i < nscript_modules; i++) {
00396 script_modules[i]->link_var(script_modules[i]->client_data, table);
00397 }
00398 table++;
00399 }
00400 return(0);
00401 }
00402
00403 int script_unlink_vars(script_linked_var_t *table)
00404 {
00405 int i;
00406
00407 while (table->class && table->name) {
00408 journal_del(EVENT_VAR, table);
00409 for (i = 0; i < nscript_modules; i++) {
00410 script_modules[i]->unlink_var(script_modules[i]->client_data, table);
00411 }
00412 table++;
00413 }
00414 return(0);
00415 }
00416
00417 int script_create_raw_commands(script_raw_command_t *table)
00418 {
00419 int i;
00420
00421 while (table->class && table->name) {
00422 journal_add(EVENT_CMD, table, table);
00423 for (i = 0; i < nscript_modules; i++) {
00424 script_modules[i]->create_command(script_modules[i]->client_data, table);
00425 }
00426 table++;
00427 }
00428 return(0);
00429 }
00430
00431 int script_delete_raw_commands(script_raw_command_t *table)
00432 {
00433 int i;
00434
00435 while (table->class && table->name) {
00436 journal_del(EVENT_CMD, table);
00437 for (i = 0; i < nscript_modules; i++) {
00438 script_modules[i]->delete_command(script_modules[i]->client_data, table);
00439 }
00440 table++;
00441 }
00442 return(0);
00443 }
00444
00445 int script_create_commands(script_command_t *table)
00446 {
00447 int i;
00448 script_raw_command_t *cmd;
00449
00450 while (table->class && table->name) {
00451 cmd = malloc(sizeof(*cmd));
00452 cmd->class = table->class;
00453 cmd->name = table->name;
00454 cmd->callback = my_command_handler;
00455 cmd->client_data = table;
00456
00457 journal_add(EVENT_CMD, cmd, table);
00458 for (i = 0; i < nscript_modules; i++) {
00459 script_modules[i]->create_command(script_modules[i]->client_data, cmd);
00460 }
00461 table++;
00462 }
00463 return(0);
00464 }
00465
00466 int script_delete_commands(script_command_t *table)
00467 {
00468 int i;
00469 script_raw_command_t *cmd;
00470
00471 for (; table->class && table->name; table++) {
00472 cmd = journal_del(EVENT_CMD, table);
00473 if (!cmd)
00474 continue;
00475
00476 for (i = 0; i < nscript_modules; i++) {
00477 script_modules[i]->delete_command(script_modules[i]->client_data, cmd);
00478 }
00479
00480 free(cmd);
00481 }
00482 return(0);
00483 }
00484
00485 int script_get_arg(script_args_t *args, int num, script_var_t *var, int type)
00486 {
00487 script_module_t *module;
00488
00489 module = args->module;
00490 return module->get_arg(module->client_data, args, num, var, type);
00491 }
00492
00493 script_var_t *script_string(char *str, int len)
00494 {
00495 script_var_t *var = malloc(sizeof(*var));
00496
00497 var->type = SCRIPT_STRING | SCRIPT_FREE_VAR;
00498 if (!str) {
00499 str = "";
00500 len = 0;
00501 }
00502 else if (len < 0) len = strlen(str);
00503 var->value = str;
00504 var->len = len;
00505 return(var);
00506 }
00507
00508 script_var_t *script_dynamic_string(char *str, int len)
00509 { script_var_t *var = script_string(str, len);
00510 var->type |= SCRIPT_FREE;
00511 return(var);
00512 }
00513
00514 script_var_t *script_copy_string(char *str, int len)
00515 {
00516 char *copy;
00517
00518 if (!str) {
00519 str = "";
00520 len = 0;
00521 }
00522 else if (len < 0) len = strlen(str);
00523 copy = malloc(len+1);
00524 memcpy(copy, str, len);
00525 copy[len] = 0;
00526 return script_dynamic_string(copy, len);
00527 }
00528
00529 script_var_t *script_int(int val)
00530 {
00531 script_var_t *var = malloc(sizeof(*var));
00532 var->type = SCRIPT_INTEGER | SCRIPT_FREE_VAR;
00533 var->value = (void *)val;
00534 return(var);
00535 }
00536
00537 script_var_t *script_list(int nitems, ...)
00538 {
00539 script_var_t *list;
00540
00541 list = malloc(sizeof(*list));
00542 list->type = SCRIPT_ARRAY | SCRIPT_FREE | SCRIPT_VAR | SCRIPT_FREE_VAR;
00543 list->len = nitems;
00544 if (nitems > 0) {
00545 list->value = malloc(nitems * sizeof(script_var_t *));
00546 memmove(list->value, &nitems + 1, nitems * sizeof(script_var_t *));
00547 }
00548 else list->value = NULL;
00549 return(list);
00550 }
00551
00552 int script_list_append(script_var_t *list, script_var_t *item)
00553 {
00554 list->value = realloc(list->value, sizeof(item) * (list->len+1));
00555 ((script_var_t **)list->value)[list->len] = item;
00556 list->len++;
00557 return(0);
00558 }
00559
00560 static int script_dns_delete(struct event_owner_b *event, void *client_data)
00561 {
00562 script_dns_callback_data_t *data = client_data;
00563
00564 if (data->callback->owner && data->callback->owner->on_delete) data->callback->owner->on_delete(data->callback->owner, data->callback);
00565 if (data->text) free(data->text);
00566 free(data);
00567
00568 free(event);
00569
00570 return 51896;
00571 }
00572
00573 static int script_dns_callback(void *client_data, const char *query, char **result)
00574 {
00575 static unsigned char no_data = 0;
00576 byte_array_t bytes;
00577 script_dns_callback_data_t *data = client_data;
00578
00579 bytes.bytes = data->text;
00580 bytes.len = data->len;
00581 bytes.do_free = 0;
00582
00583 if (!bytes.bytes) bytes.bytes = &no_data;
00584 if (bytes.len <= 0) bytes.len = strlen((char *) bytes.bytes);
00585
00586 data->callback->callback(data->callback, data->id, query, result, &bytes);
00587
00588 return 0;
00589 }
00590
00591 int script_dns_query(dns_function_t *function, const char *host, script_callback_t *callback, char *text, int len)
00592 {
00593 int id;
00594 event_owner_t *event;
00595 script_dns_callback_data_t *data;
00596
00597 event = malloc(sizeof(*event));
00598 memcpy(event, callback->owner, sizeof(*event));
00599 event->on_delete = script_dns_delete;
00600
00601 callback->syntax = strdup("isSb");
00602 data = malloc(sizeof(*data));
00603 data->callback = callback;
00604 data->id = -1;
00605 data->text = text;
00606 data->len = len;
00607 id = function(host, -1, script_dns_callback, data, event);
00608 if (id == -1) {
00609
00610 return -1;
00611 }
00612 data->id = id;
00613 return id;
00614 }
00615