00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <ctype.h>
00033 #include "../../route.h"
00034 #include "../../sr_module.h"
00035 #include "../../mem/mem.h"
00036 #include "../../str.h"
00037 #include "../../error.h"
00038 #include "../../config.h"
00039 #include "../../trim.h"
00040 #include "../../select.h"
00041 #include "../../ut.h"
00042 #include "../xlog/xl_lib.h"
00043 #include "../../select_buf.h"
00044
00045 #include "../../globals.h"
00046 #include "../../route.h"
00047 #include "../../parser/msg_parser.h"
00048 #include "../../action.h"
00049 #include "../../script_cb.h"
00050 #include "../../dset.h"
00051 #include "../../usr_avp.h"
00052
00053 MODULE_VERSION
00054
00055 #define MODULE_NAME "eval"
00056
00057 enum {evtVoid=0, evtInt, evtStr};
00058
00059 struct eval_str {
00060 str s;
00061 int cnt;
00062 };
00063
00064 struct eval_value {
00065 union {
00066 long n;
00067 struct eval_str *s;
00068 } u;
00069 int type;
00070 };
00071
00072 struct register_item {
00073 char *name;
00074 struct eval_value value;
00075 struct register_item *next;
00076 };
00077
00078 struct stack_item {
00079 struct eval_value value;
00080 struct stack_item *prev;
00081 struct stack_item *next;
00082 };
00083
00084 static int stack_no = 0;
00085 static struct stack_item *stack_head = 0;
00086 static struct stack_item *stack_tail = 0;
00087
00088 static struct register_item* registers = 0;
00089
00090
00091 #define destroy_value(val) { \
00092 if ((val).type == evtStr && (val).u.s && (val).u.s->cnt > 0) { \
00093 (val).u.s->cnt--; \
00094 if ((val).u.s->cnt == 0) \
00095 pkg_free((val).u.s); \
00096 } \
00097 (val).type = evtVoid; \
00098 }
00099
00100 #define assign_value(dest, src) { \
00101 if (&(dest) != &(src)) { \
00102 destroy_value(dest); \
00103 dest = src; \
00104 if ((dest).type == evtStr && (dest).u.s && (dest).u.s->cnt > 0) \
00105 (dest).u.s->cnt++; \
00106 } \
00107 }
00108
00109 static int get_as_int(struct eval_value *value, long* val) {
00110 switch (value->type) {
00111 case evtInt:
00112 *val = value->u.n;
00113 return 1;
00114 case evtStr:
00115 if (value->u.s->s.s && value->u.s->s.len && value->u.s->s.len <= 25) {
00116 char *err;
00117 char buf[25+1];
00118 memcpy(buf, value->u.s->s.s, value->u.s->s.len);
00119 buf[value->u.s->s.len] = '\0';
00120 *val = strtol(buf, &err, 10);
00121 if (*err == 0)
00122 return 1;
00123 }
00124 ERR(MODULE_NAME": cannot convert '%.*s' as int\n", value->u.s->s.len, value->u.s->s.s);
00125 return -1;
00126 default:
00127 BUG("Bad value type %d\n", value->type);
00128 return -1;
00129 }
00130 }
00131
00132 static void get_as_str(struct eval_value *value, str *s) {
00133 static char buf[25];
00134 switch (value->type) {
00135 case evtInt:
00136 s->len = snprintf(buf, sizeof(buf)-1, "%ld", value->u.n);
00137 s->s = buf;
00138 break;
00139 case evtStr:
00140 *s = value->u.s->s;
00141 break;
00142 default:
00143 s->s = 0;
00144 s->len = 0;
00145 break;
00146 }
00147 }
00148
00149 static int get_as_bool(struct eval_value *value) {
00150 switch (value->type) {
00151 case evtVoid:
00152 return 0;
00153 case evtInt:
00154 return value->u.n != 0;
00155 case evtStr:
00156 return (value->u.s->s.s && value->u.s->s.len > 0);
00157 default:
00158 BUG("Bad value type %d\n", value->type);
00159 return -1;
00160 }
00161 }
00162
00163 static struct eval_str* eval_str_malloc(str* s) {
00164 struct eval_str* p;
00165 p = pkg_malloc(sizeof(*p)+s->len);
00166 if (p) {
00167 p->s.s = (char*)p+sizeof(*p);
00168 if (s->len && s->s != 0)
00169 memcpy(p->s.s, s->s, s->len);
00170 if (s->s == 0 && s->len)
00171 s->s = p->s.s;
00172 p->s.len = s->len;
00173 p->cnt = 1;
00174 }
00175 return p;
00176 }
00177
00178
00179 #define is_space(_p) ((_p) == '\t' || (_p) == '\n' || (_p) == '\r' || (_p) == ' ')
00180
00181 static void get_uri_and_skip_until_params(str *param_area, str *uri) {
00182 int i, quoted, uri_pos, uri_done;
00183
00184 uri->len = 0;
00185 uri->s = 0;
00186 uri_done = 0;
00187 for (i=0; i<param_area->len && param_area->s[i]!=';'; ) {
00188
00189
00190 for (quoted=0, uri_pos=i; i<param_area->len; i++) {
00191 if (!quoted) {
00192 if (param_area->s[i] == '\"') {
00193 quoted = 1;
00194 uri_pos = -1;
00195 }
00196 else if (param_area->s[i] == '<' || param_area->s[i] == ';' || is_space(param_area->s[i])) break;
00197 }
00198 else if (param_area->s[i] == '\"' && param_area->s[i-1] != '\\') quoted = 0;
00199 }
00200 if (uri_pos >= 0 && !uri_done) {
00201 uri->s = param_area->s+uri_pos;
00202 uri->len = param_area->s+i-uri->s;
00203 }
00204
00205 while (i<param_area->len && is_space(param_area->s[i])) i++;
00206 if (i<param_area->len && param_area->s[i]=='<') {
00207 uri->s = param_area->s+i;
00208 uri->len = 0;
00209 for (quoted=0; i<param_area->len; i++) {
00210 if (!quoted) {
00211 if (param_area->s[i] == '\"') quoted = 1;
00212 else if (param_area->s[i] == '>') {
00213 uri->len = param_area->s+i-uri->s+1;
00214 uri_done = 1;
00215 break;
00216 }
00217 }
00218 else if (param_area->s[i] == '\"' && param_area->s[i-1] != '\\') quoted = 0;
00219 }
00220 }
00221 }
00222 param_area->s+= i;
00223 param_area->len-= i;
00224 }
00225
00226 static int find_next_value(char** start, char* end, str* val, str* lump_val) {
00227 int quoted = 0;
00228 lump_val->s = *start;
00229 while (*start < end && is_space(**start) ) (*start)++;
00230 val->s = *start;
00231 while ( *start < end && (**start != ',' || quoted) ) {
00232 if (**start == '\"' && (!quoted || (*start)[-1]!='\\') )
00233 quoted = ~quoted;
00234 (*start)++;
00235 }
00236 val->len = *start - val->s;
00237 while (val->len > 0 && is_space(val->s[val->len-1])) val->len--;
00238
00239
00240
00241
00242
00243
00244 while (*start < end && **start != ',') (*start)++;
00245 if (*start < end) {
00246 (*start)++;
00247 }
00248 lump_val->len = *start - lump_val->s;
00249 return (*start < end);
00250 }
00251
00252 #define MAX_HF_VALUES 30
00253
00254 static int parse_hf_values(str s, int* n, str** vals) {
00255 static str values[MAX_HF_VALUES];
00256 char *start, *end;
00257 str lump_val;
00258 *n = 0;
00259 *vals = values;
00260 if (!s.s) return 1;
00261 start = s.s;
00262 end = start+s.len;
00263 while (start < end) {
00264 find_next_value(&start, end, &values[*n], &lump_val);
00265 if (*n >= MAX_HF_VALUES) {
00266 ERR(MODULE_NAME": too many values\n");
00267 return -1;
00268 }
00269 (*n)++;
00270 }
00271 return 1;
00272 }
00273
00274 static void destroy_stack() {
00275 struct stack_item *p;
00276 while (stack_head) {
00277 destroy_value(stack_head->value);
00278 p = stack_head;
00279 stack_head = stack_head->next;
00280 pkg_free(p);
00281 }
00282 stack_tail = stack_head;
00283 stack_no = 0;
00284 }
00285
00286 static void destroy_register_values() {
00287 struct register_item *p;
00288 for (p=registers; p; p=p->next) {
00289 destroy_value(p->value);
00290 }
00291 }
00292
00293 static void remove_stack_item(struct stack_item *s) {
00294 if (s->prev)
00295 s->prev->next = s->next;
00296 else
00297 stack_head = s->next;
00298 if (s->next)
00299 s->next->prev = s->prev;
00300 else
00301 stack_tail = s->prev;
00302 destroy_value(s->value);
00303 pkg_free(s);
00304 stack_no--;
00305 }
00306
00307 static void insert_stack_item(struct stack_item *s, struct stack_item *pivot, int behind) {
00308 if (stack_head == NULL) {
00309 s->prev = s->next = 0;
00310 }
00311 else if (behind) {
00312 if (pivot) {
00313 s->next = pivot->next;
00314 s->prev = pivot;
00315 }
00316 else {
00317 s->next = 0;
00318 s->prev = stack_tail;
00319 }
00320 }
00321 else {
00322 if (pivot) {
00323 s->prev = pivot->prev;
00324 s->next = pivot;
00325 }
00326 else {
00327 s->next = stack_head;
00328 s->prev = 0;
00329 }
00330 }
00331 if (!s->prev)
00332 stack_head = s;
00333 else
00334 s->prev->next = s;
00335 if (!s->next)
00336 stack_tail = s;
00337 else
00338 s->next->prev = s;
00339 stack_no++;
00340 }
00341
00342 static int declare_register(modparam_t type, char* param) {
00343 struct register_item **p;
00344 char *c;
00345 for (c=param; *c; c++) {
00346 if ( (*c >= 'a' && *c <= 'z') ||
00347 (*c >= 'A' && *c <= 'Z') ||
00348 (*c >= '0' && *c <= '9') ||
00349 (*c == '_') ) {
00350 ;
00351 } else {
00352 ERR(MODULE_NAME": illegal register name\n");
00353 return E_CFG;
00354 }
00355 }
00356 for (p = ®isters; *p!= 0; p = &(*p)->next);
00357 *p = pkg_malloc(sizeof(**p));
00358 if (!*p) return E_OUT_OF_MEM;
00359
00360 memset(*p, 0, sizeof(**p));
00361 (*p)->name = param;
00362 return 0;
00363 }
00364
00365 static int mod_pre_script_cb(struct sip_msg *msg, unsigned int flags, void *param) {
00366 destroy_stack();
00367 destroy_register_values();
00368 return 1;
00369 }
00370
00371 static struct register_item* find_register(char* s, int len) {
00372 struct register_item *p;
00373 for (p=registers; p; p=p->next) {
00374 if (strlen(p->name) == len && strncasecmp(p->name, s, len) == 0)
00375 break;
00376 }
00377 return p;
00378 }
00379
00380 static struct stack_item* find_stack_item(int n) {
00381 struct stack_item *p;
00382 if ((n >= 0 && n >= stack_no) || (n<0 && -n > stack_no)) {
00383 return NULL;
00384 }
00385 p = NULL;
00386 if (n >= 0) {
00387 for (p = stack_head; p && n>0; p=p->next, n--);
00388 }
00389 else {
00390 for (p = stack_tail, n=-n-1; p && n>0; p=p->prev, n--);
00391 }
00392 return p;
00393 }
00394
00395
00396 static void print_eval_value(struct eval_value* v) {
00397 switch (v->type) {
00398 case evtStr:
00399 if (v->u.s)
00400 fprintf(stderr, "s:'%.*s', cnt:%d\n", v->u.s->s.len, v->u.s->s.s, v->u.s->cnt);
00401 else
00402 fprintf(stderr, "s:<null>\n");
00403 break;
00404 case evtInt:
00405 fprintf(stderr, "i:%ld\n", v->u.n);
00406 break;
00407 default:;
00408 fprintf(stderr, "type:%d\n", v->type);
00409 break;
00410 }
00411 }
00412
00413 static int eval_dump_func(struct sip_msg *msg, char *param1, char *param2) {
00414 struct stack_item *si;
00415 struct register_item *ri;
00416 int i;
00417 fprintf(stderr, "Stack (no=%d):\n", stack_no);
00418 for (si=stack_head, i=0; si; si=si->next, i++) {
00419 fprintf(stderr, "# %.2d ", i);
00420 print_eval_value(&si->value);
00421 }
00422 for (si=stack_tail, i=-1; si; si=si->prev, i--) {
00423 fprintf(stderr, "#%.2d ", i);
00424 print_eval_value(&si->value);
00425 }
00426 fprintf(stderr, "Registers:\n");
00427 for (ri=registers; ri; ri=ri->next) {
00428 fprintf(stderr, "%s: ", ri->name);
00429 print_eval_value(&ri->value);
00430 }
00431 return 1;
00432 }
00433
00434
00435 static int xlbuf_size = 4096;
00436 static xl_print_log_f* xl_print = NULL;
00437 static xl_parse_format_f* xl_parse = NULL;
00438 #define NO_SCRIPT -1
00439
00440
00441 enum {esotAdd, esotInsert, esotXchg, esotPut, esotGet, esotPop, esotAddValue, esotInsertValue};
00442 enum {esovtInt, esovtStr, esovtAvp, esovtXStr, esovtRegister, esovtFunc, esovtSelect};
00443 enum {esofNone=0, esofTime, esofUuid, esofStackNo};
00444
00445 struct eval_location_func {
00446 int type;
00447 char *name;
00448 };
00449
00450 static struct eval_location_func loc_functions[] = {
00451 {esofTime, "time"},
00452 {esofUuid, "uuid"},
00453 {esofStackNo, "stackno"},
00454
00455 {esofNone, NULL}
00456 };
00457
00458 struct eval_location {
00459 int value_type;
00460 union {
00461 int n;
00462 struct eval_str s;
00463 xl_elog_t* xl;
00464 struct register_item *reg;
00465 avp_ident_t avp;
00466 select_t* select;
00467 struct eval_location_func *func;
00468 } u;
00469 };
00470
00471 struct eval_stack_oper {
00472 int oper_type;
00473 struct eval_location loc;
00474 };
00475
00476 static int parse_location(str s, struct eval_location *p) {
00477 if (s.len >= 2 && s.s[1] == ':') {
00478 switch (s.s[0]) {
00479 case 'r':
00480 p->u.reg = find_register(s.s+2, s.len-2);
00481 if (!p->u.reg) {
00482 ERR(MODULE_NAME": register '%.*s' not found\n", s.len-2, s.s+2);
00483 return E_CFG;
00484 }
00485 p->value_type = esovtRegister;
00486 break;
00487 case 'x':
00488 if (!xl_print) {
00489 xl_print=(xl_print_log_f*)find_export("xprint", NO_SCRIPT, 0);
00490 if (!xl_print) {
00491 ERR(MODULE_NAME": cannot find \"xprint\", is module xlog loaded?\n");
00492 return E_UNSPEC;
00493 }
00494 }
00495
00496 if (!xl_parse) {
00497 xl_parse=(xl_parse_format_f*)find_export("xparse", NO_SCRIPT, 0);
00498
00499 if (!xl_parse) {
00500 ERR(MODULE_NAME": cannot find \"xparse\", is module xlog loaded?\n");
00501 return E_UNSPEC;
00502 }
00503 }
00504
00505 if(xl_parse(s.s+2, &p->u.xl) < 0) {
00506 ERR(MODULE_NAME": wrong xl_lib format '%s'\n", s.s+2);
00507 return E_UNSPEC;
00508 }
00509 p->value_type = esovtXStr;
00510 break;
00511 case 'f': {
00512 struct eval_location_func* f;
00513 s.s += 2;
00514 s.len -= 2;
00515 for (f=loc_functions; f->type != esofNone; f++) {
00516 if (strlen(f->name)==s.len && strncasecmp(s.s, f->name, s.len) == 0) {
00517 p->value_type = esovtFunc;
00518 p->u.func = f;
00519 break;
00520 }
00521 }
00522 if (!f) {
00523 ERR(MODULE_NAME": unknown function '%.*s'\n", s.len, s.s);
00524 return E_CFG;
00525 }
00526 break;
00527 }
00528 case 's':
00529 s.s += 2;
00530 s.len -= 2;
00531
00532 default:
00533 p->u.s.s = s;
00534 p->u.s.cnt = 0;
00535 p->value_type = esovtStr;
00536 break;
00537 }
00538 }
00539 else {
00540 char *err;
00541 if (s.len > 1 && s.s[0]=='$') {
00542 s.s++;
00543 s.len--;
00544 if (parse_avp_ident(&s, &p->u.avp) == 0) {
00545 if (p->u.avp.flags & AVP_NAME_RE) {
00546 ERR(MODULE_NAME": avp regex not allowed\n");
00547 return E_CFG;
00548 }
00549 p->value_type = esovtAvp;
00550 return 1;
00551 }
00552 s.s--;
00553 s.len++;
00554 }
00555 else if (s.len > 1 && s.s[0]=='@') {
00556 if (parse_select(&s.s, &p->u.select) >= 0) {
00557 p->value_type = esovtSelect;
00558 return 1;
00559 }
00560 }
00561 p->u.n = strtol(s.s, &err, 10);
00562 if (*err) {
00563 p->u.s.s = s;
00564 p->u.s.cnt = 0;
00565 p->value_type = esovtStr;
00566 }
00567 else {
00568 p->value_type = esovtInt;
00569 }
00570 }
00571 return 1;
00572 }
00573
00574 static int eval_xl(struct sip_msg *msg, xl_elog_t* xl, str* s) {
00575 static char *xlbuf=NULL;
00576 int xllen = 0;
00577
00578 if (!xlbuf) {
00579 xlbuf = (char*) pkg_malloc((xlbuf_size+1)*sizeof(char));
00580 if (!xlbuf) {
00581 ERR(MODULE_NAME": eval_xl: No memory left for format buffer\n");
00582 return E_OUT_OF_MEM;
00583 }
00584 }
00585 xllen = xlbuf_size;
00586 if (xl_print(msg, xl, xlbuf, &xllen) < 0) {
00587 ERR(MODULE_NAME": eval_xl: Error while formatting result\n");
00588 return E_UNSPEC;
00589 }
00590 s->s = xlbuf;
00591 s->len = xllen;
00592 return 1;
00593 }
00594
00595 SELECT_F(select_sys_unique)
00596
00597 static int eval_location(struct sip_msg *msg, struct eval_location* so, struct eval_value* v, int get_static_str) {
00598 static struct eval_str ss;
00599
00600 v->type = evtVoid;
00601 switch (so->value_type) {
00602 case esovtInt:
00603 v->type = evtInt;
00604 v->u.n = so->u.n;
00605 break;
00606 case esovtStr:
00607 v->type = evtStr;
00608 v->u.s = &so->u.s;
00609 break;
00610 case esovtXStr: {
00611 str s;
00612 int ret;
00613 ret = eval_xl(msg, so->u.xl, &s);
00614 if (ret < 0) return ret;
00615 if (get_static_str) {
00616 ss.s = s;
00617 ss.cnt = 0;
00618 v->u.s = &ss;
00619 }
00620 else {
00621 v->u.s = eval_str_malloc(&s);
00622 if (!v->u.s) {
00623 ERR(MODULE_NAME": out of memory to allocate xl string\n");
00624 return E_OUT_OF_MEM;
00625 }
00626 }
00627 v->type = evtStr;
00628 break;
00629 }
00630 case esovtRegister:
00631 if (get_static_str)
00632 *v = so->u.reg->value;
00633 else
00634 assign_value(*v, so->u.reg->value);
00635 break;
00636 case esovtAvp: {
00637 avp_t* avp;
00638 avp_value_t val;
00639
00640 if (so->u.avp.flags & AVP_INDEX_ALL)
00641 avp = search_first_avp(so->u.avp.flags & ~AVP_INDEX_ALL, so->u.avp.name, &val, NULL);
00642 else
00643 avp = search_avp_by_index(so->u.avp.flags, so->u.avp.name, &val, so->u.avp.index);
00644 if (!avp) {
00645 ERR(MODULE_NAME": avp '%.*s'[%d] not found\n", so->u.avp.name.s.len, so->u.avp.name.s.s, so->u.avp.index);
00646 return -1;
00647 }
00648 if (avp->flags & AVP_VAL_STR) {
00649 if (get_static_str) {
00650 ss.s = val.s;
00651 ss.cnt = 0;
00652 v->u.s = &ss;
00653 }
00654 else {
00655 v->u.s = eval_str_malloc(&val.s);
00656 if (!v->u.s) {
00657 ERR(MODULE_NAME": out of memory to allocate avp string\n");
00658 return E_OUT_OF_MEM;
00659 }
00660 }
00661 v->type = evtStr;
00662 }
00663 else {
00664 v->type = evtInt;
00665 v->u.n = val.n;
00666 }
00667 break;
00668 }
00669 case esovtSelect: {
00670 str s;
00671 int ret = run_select(&s, so->u.select, msg);
00672 if (ret < 0 || ret > 0) return -1;
00673 if (get_static_str) {
00674 ss.s = s;
00675 ss.cnt = 0;
00676 v->u.s = &ss;
00677 }
00678 else {
00679 v->u.s = eval_str_malloc(&s);
00680 if (!v->u.s) {
00681 ERR(MODULE_NAME": out of memory to allocate select string\n");
00682 return E_OUT_OF_MEM;
00683 }
00684 }
00685 v->type = evtStr;
00686 break;
00687 }
00688 case esovtFunc: {
00689 switch (so->u.func->type) {
00690 case esofTime: {
00691 time_t stamp;
00692 stamp = time(NULL);
00693 v->type = evtInt;
00694 v->u.n = stamp;
00695 break;
00696 }
00697 case esofUuid: {
00698 str s;
00699 select_sys_unique(&s, 0, msg);
00700 if (get_static_str) {
00701 ss.s = s;
00702 ss.cnt = 0;
00703 v->u.s = &ss;
00704 }
00705 else {
00706 v->u.s = eval_str_malloc(&s);
00707 if (!v->u.s) {
00708 ERR(MODULE_NAME": out of memory to allocate uuid string\n");
00709 return E_OUT_OF_MEM;
00710 }
00711 }
00712 v->type = evtStr;
00713 break;
00714 }
00715 case esofStackNo:
00716 v->type = evtInt;
00717 v->u.n = stack_no;
00718 break;
00719 default:
00720 BUG("bad func type (%d)\n", so->u.func->type);
00721 return -1;
00722 }
00723 break;
00724 }
00725 default:
00726 BUG("Bad value type (%d)\n", so->value_type);
00727 return -1;
00728 }
00729 return 1;
00730 }
00731
00732 static int fixup_location_12( void** param, int param_no) {
00733 struct eval_location *so;
00734 str s;
00735 s.s = *param;
00736 s.len = strlen(s.s);
00737 so = pkg_malloc(sizeof(*so));
00738 if (!so) return E_OUT_OF_MEM;
00739 if (parse_location(s, so) < 0) {
00740 ERR(MODULE_NAME": parse location error '%s'\n", s.s);
00741 return E_CFG;
00742 }
00743 *param = so;
00744 return 0;
00745 }
00746
00747 static int fixup_stack_oper(void **param, int param_no, int oper_type) {
00748 str s;
00749 struct eval_stack_oper *p;
00750 int ret;
00751
00752 if (param_no == 2) {
00753 return fixup_location_12(param, param_no);
00754 }
00755 p = pkg_malloc(sizeof(*p));
00756 if (!p) return E_OUT_OF_MEM;
00757 p->oper_type = oper_type;
00758 s.s = *param;
00759 s.len = strlen(s.s);
00760 *param = p;
00761 ret = parse_location(s, &p->loc);
00762 if (ret < 0) return ret;
00763
00764 switch (p->oper_type) {
00765 case esotXchg:
00766 if (p->loc.value_type == esovtAvp || p->loc.value_type == esovtSelect) {
00767 ERR(MODULE_NAME": avp non supported for xchg\n");
00768 return E_CFG;
00769 }
00770
00771 case esotPop:
00772 case esotGet:
00773 if (p->loc.value_type != esovtRegister && p->loc.value_type != esovtAvp) {
00774 ERR(MODULE_NAME": non supported read only location\n");
00775 return E_CFG;
00776 }
00777 break;
00778 default:;
00779 }
00780 return 0;
00781 }
00782
00783 static int eval_stack_oper_func(struct sip_msg *msg, char *param1, char *param2) {
00784 int ret, idx;
00785 struct stack_item *pivot;
00786 struct eval_stack_oper *so;
00787 struct run_act_ctx ra_ctx;
00788
00789 so = (struct eval_stack_oper *)param1;
00790 if (param2) {
00791 long l;
00792 struct eval_value v;
00793 eval_location(msg, (struct eval_location*) param2, &v, 1);
00794 ret = get_as_int(&v, &l);
00795 if (ret < 0) return ret;
00796 idx = l;
00797 }
00798 else {
00799 switch (so->oper_type) {
00800 case esotAdd:
00801 case esotAddValue:
00802 idx = -1;
00803 break;
00804 default:
00805 idx = 0;
00806 break;
00807 }
00808 }
00809
00810 pivot = find_stack_item(idx);
00811 if ( !(pivot!=NULL || ((so->oper_type == esotAdd || so->oper_type == esotAddValue) && idx == -1) || ((so->oper_type == esotInsert || so->oper_type == esotInsertValue) && idx == 0)) )
00812 return -1;
00813
00814 switch (so->oper_type) {
00815 case esotGet:
00816 case esotPop:
00817 switch (so->loc.value_type) {
00818 case esovtRegister:
00819 assign_value(so->loc.u.reg->value, pivot->value);
00820 if (so->oper_type == esotPop)
00821 remove_stack_item(pivot);
00822 return 1;
00823 case esovtAvp: {
00824 struct action a;
00825 avp_spec_t attr;
00826
00827 a.type = ASSIGN_T;
00828 a.count = 2;
00829 a.val[0].type = AVP_ST;
00830 attr.type = so->loc.u.avp.flags;
00831 attr.name = so->loc.u.avp.name;
00832 attr.index = so->loc.u.avp.index;
00833 a.val[0].u.attr = &attr;
00834 switch (pivot->value.type) {
00835 case evtInt:
00836 a.val[1].type = NUMBER_ST;
00837 a.val[1].u.number = pivot->value.u.n;
00838 break;
00839 case evtStr:
00840 if (pivot->value.u.s)
00841 a.val[1].u.str = pivot->value.u.s->s;
00842 else
00843 a.val[1].u.str.len = 0;
00844 a.val[1].type = STRING_ST;
00845 break;
00846 default:
00847 return -1;
00848 }
00849 a.next = 0;
00850 init_run_actions_ctx(&ra_ctx);
00851 ret = do_action(&ra_ctx, &a, msg);
00852 if (so->oper_type == esotPop)
00853 remove_stack_item(pivot);
00854 return ret<0?-1:1;
00855 }
00856 default:
00857 BUG("Bad value type (%d) for get/pop\n", so->loc.value_type);
00858 return -1;
00859 }
00860 break;
00861 case esotXchg:
00862 switch (so->loc.value_type) {
00863 case esovtRegister: {
00864 struct eval_value v;
00865
00866 v = so->loc.u.reg->value;
00867 so->loc.u.reg->value = pivot->value;
00868 pivot->value = v;
00869 return 1;
00870 }
00871 default:
00872 BUG("Bad value type (%d) for xchg\n", so->loc.value_type);
00873 return -1;
00874 }
00875 break;
00876 case esotInsert:
00877 case esotAdd:
00878 case esotPut: {
00879 struct eval_value v;
00880 eval_location(msg, &so->loc, &v, 0);
00881
00882 if (so->oper_type == esotInsert || so->oper_type == esotAdd) {
00883 struct stack_item *si;
00884 si = pkg_malloc(sizeof(*si));
00885 if (!si) {
00886 ERR(MODULE_NAME": out of memory\n");
00887 destroy_value(v);
00888 return -1;
00889 }
00890 si->value = v;
00891 insert_stack_item(si, pivot, so->oper_type == esotAdd);
00892 return 1;
00893 }
00894 else {
00895 destroy_value(pivot->value);
00896 pivot->value = v;
00897 return 1;
00898 }
00899 break;
00900 }
00901 case esotInsertValue:
00902 case esotAddValue: {
00903 struct eval_value v;
00904 str s, *vals;
00905 int i, n;
00906 struct eval_str* es;
00907 struct stack_item *si;
00908 eval_location(msg, &so->loc, &v, 0);
00909 get_as_str(&v, &s);
00910 if ((parse_hf_values(s, &n, &vals) < 0) || n == 0) {
00911 destroy_value(v);
00912 return -1;
00913 }
00914 si = pkg_malloc(sizeof(*si));
00915 if (!si) {
00916 ERR(MODULE_NAME": out of memory\n");
00917 destroy_value(v);
00918 return -1;
00919 }
00920 si->value.type = evtInt;
00921 si->value.u.n = n;
00922 insert_stack_item(si, pivot, so->oper_type == esotAddValue);
00923 pivot = si;
00924 for (i=0; i<n; i++) {
00925 si = pkg_malloc(sizeof(*si));
00926 if (!si) {
00927 ERR(MODULE_NAME": out of memory\n");
00928 destroy_value(v);
00929 return -1;
00930 }
00931 es = eval_str_malloc(vals+i);
00932 if (!es) {
00933 ERR(MODULE_NAME": out of memory\n");
00934 destroy_value(v);
00935 return -1;
00936 }
00937 si->value.type = evtStr;
00938 si->value.u.s = es;
00939 insert_stack_item(si, pivot, 1);
00940 pivot = si;
00941 }
00942 destroy_value(v);
00943 return 1;
00944 }
00945 default:
00946 BUG("Unexpected operation (%d)\n", so->oper_type);
00947 return -1;
00948 }
00949 }
00950
00951 static int eval_add_fixup( void** param, int param_no) {
00952 return fixup_stack_oper(param, param_no, esotAdd);
00953 }
00954
00955 static int eval_insert_fixup( void** param, int param_no) {
00956 return fixup_stack_oper(param, param_no, esotInsert);
00957 }
00958
00959 static int eval_put_fixup( void** param, int param_no) {
00960 return fixup_stack_oper(param, param_no, esotPut);
00961 }
00962
00963 static int eval_get_fixup( void** param, int param_no) {
00964 return fixup_stack_oper(param, param_no, esotGet);
00965 }
00966
00967 static int eval_pop_fixup( void** param, int param_no) {
00968 return fixup_stack_oper(param, param_no, esotPop);
00969 }
00970
00971 static int eval_xchg_fixup( void** param, int param_no) {
00972 return fixup_stack_oper(param, param_no, esotXchg);
00973 }
00974
00975 static int eval_add_value_fixup( void** param, int param_no) {
00976 return fixup_stack_oper(param, param_no, esotAddValue);
00977 }
00978
00979 static int eval_insert_value_fixup( void** param, int param_no) {
00980 return fixup_stack_oper(param, param_no, esotInsertValue);
00981 }
00982
00983
00984 static int eval_remove_func(struct sip_msg *msg, char *param1, char *param2) {
00985 struct stack_item *p, *p2;
00986 int ret, len, start;
00987 struct eval_value v;
00988
00989 if (param1) {
00990 long l;
00991 eval_location(msg, (struct eval_location*) param1, &v, 1);
00992 ret = get_as_int(&v, &l);
00993 if (ret < 0) return ret;
00994 start = l;
00995 }
00996 else
00997 start = 0;
00998 p = find_stack_item(start);
00999 if (p) {
01000 if (param2) {
01001 long l;
01002 eval_location(msg, (struct eval_location*) param2, &v, 1);
01003 ret = get_as_int(&v, &l);
01004 if (ret < 0) return ret;
01005 len = l;
01006 }
01007 else
01008 len = 1;
01009
01010 if (start < 0) {
01011 start = stack_no + start;
01012 if (start < 0) start = 0;
01013 }
01014 else {
01015 if (start > stack_no) start = stack_no;
01016 }
01017 if (len < 0) {
01018 len = stack_no - start + len;
01019 if (len < 0)
01020 len = 0;
01021 }
01022 else {
01023 if (start + len > stack_no)
01024 len = stack_no - start;
01025 }
01026
01027 for (; len > 0 && p; len--) {
01028 p2 = p;
01029 p = p->next;
01030 remove_stack_item(p2);
01031 }
01032 return 1;
01033 }
01034 else
01035 return -1;
01036 }
01037
01038 static int eval_clear_func(struct sip_msg *msg, char *param1, char *param2) {
01039 int n;
01040 if (get_int_fparam(&n, msg, (fparam_t*)param1)<0) {
01041 ERR(MODULE_NAME": eval_clear: Invalid number specified\n");
01042 return -1;
01043 }
01044 if (n & 1)
01045 destroy_stack();
01046 if (n & 2)
01047 destroy_register_values();
01048 return 1;
01049 }
01050
01051 enum {esftNone=0, esftAdd, esftSub, esftMultiplication, esftDivision, esftModulo, esftNeg, esftAbs, esftSgn, esftDec, esftInc,
01052 esftConcat, esftSubstr, esftStrLen, esftStrStr, esftStrDel, esftStrUpper, esftStrLower,
01053 esftCastAsInt, esftCastAsStr,
01054 esftValueAt, esftValueUris, esftValueRev, esftSubValue, esftValueCount, esftValueConcat, esftStrValueAt,
01055 esftGetUri,
01056 esftAnd, esftOr, esftNot, esftBitAnd, esftBitOr, esftBitNot, esftBitXor, esftEQ, esftNE, esftGT, esftGE, esftLW, esftLE};
01057
01058 struct eval_function_def {
01059 int type;
01060 char *name;
01061 int arg_no;
01062 };
01063
01064 static struct eval_function_def eval_functions[] = {
01065 {esftAdd, "+", 2},
01066 {esftSub, "-", 2},
01067 {esftMultiplication, "*", 2},
01068 {esftDivision, "/", 2},
01069 {esftModulo, "%", 2},
01070 {esftNeg, "neg", 1},
01071 {esftAbs, "abs", 1},
01072 {esftDec, "dec", 1},
01073 {esftInc, "inc", 1},
01074 {esftSgn, "sgn", 1},
01075 {esftConcat, "concat", 2},
01076 {esftSubstr, "substr", 3},
01077 {esftStrLen, "strlen", 1},
01078 {esftStrStr, "strstr", 2},
01079 {esftStrDel, "strdel", 3},
01080 {esftStrUpper, "strupper", 1},
01081 {esftStrLower, "strlower", 1},
01082 {esftCastAsInt, "(int)", 1},
01083 {esftCastAsStr, "(str)", 1},
01084 {esftValueAt, "valat", 2},
01085 {esftValueUris, "valuris", 1},
01086 {esftValueRev, "valrev", 1},
01087 {esftSubValue, "subval", 3},
01088 {esftValueCount, "valcount", 1},
01089 {esftValueConcat, "valconcat", 1},
01090 {esftStrValueAt, "strvalat", 2},
01091 {esftGetUri, "geturi", 1},
01092 {esftAnd, "&&", 2},
01093 {esftOr, "||", 2},
01094 {esftNot, "!", 1},
01095 {esftBitAnd, "&", 2},
01096 {esftBitOr, "|", 2},
01097 {esftBitNot, "~", 1},
01098 {esftBitXor, "^", 2},
01099
01100 {esftEQ, "==", 2},
01101 {esftNE, "!=", 2},
01102 {esftGT, ">", 2},
01103 {esftGE, ">=", 2},
01104 {esftLW, "<", 2},
01105 {esftLE, "<=", 2},
01106
01107 {esftNone, NULL}
01108 };
01109
01110 struct eval_function {
01111 int resolved;
01112 union {
01113 struct eval_function_def *d;
01114 struct eval_location loc;
01115 } oper;
01116 struct eval_function* next;
01117 };
01118
01119 static int eval_stack_func_fixup( void** param, int param_no) {
01120 char *c, *c2;
01121 struct eval_function_def* d;
01122 struct eval_function **p, *head;
01123 if (param_no == 2) {
01124 return fixup_location_12(param, param_no);
01125 }
01126
01127 head = 0;
01128 p = &head;
01129 c = *param;
01130 while (*c) {
01131 str s;
01132 struct eval_location so;
01133 while( (*c<=' ' || *c == ',') && *c ) c++;
01134 if (*c == '\0')
01135 break;
01136 c2 = c;
01137 while (*c && *c!=',') c++;
01138 while (c > c2 && *(c-1) <= ' ') c--;
01139
01140 s.s = c2;
01141 s.len = c-c2;
01142
01143 if (parse_location(s, &so) < 0) {
01144 ERR(MODULE_NAME": parse operation error near '%s'\n", c2);
01145 return E_CFG;
01146 }
01147 *p = pkg_malloc(sizeof(**p));
01148 if (!*p) return E_OUT_OF_MEM;
01149 (*p)->next = 0;
01150 switch (so.value_type) {
01151 case esovtStr:
01152 for (d=eval_functions; d->type; d++) {
01153 if (strlen(d->name) == so.u.s.s.len && strncasecmp(d->name, so.u.s.s.s, so.u.s.s.len)==0) {
01154 (*p)->oper.d = d;
01155 break;
01156 }
01157 }
01158 if (!d->type) {
01159 ERR(MODULE_NAME": unknown eval function near '%s'\n", so.u.s.s.s);
01160 return E_CFG;
01161 }
01162 (*p)->resolved = 1;
01163 break;
01164 case esovtAvp:
01165 case esovtXStr:
01166 case esovtRegister:
01167 case esovtSelect:
01168 case esovtFunc:
01169 (*p)->oper.loc = so;
01170 (*p)->resolved = 0;
01171 break;
01172 default:
01173 ERR(MODULE_NAME": location %d not allowed\n", so.value_type);
01174 return E_CFG;
01175 }
01176 p = &(*p)->next;
01177
01178 }
01179 *param = head;
01180 return 0;
01181 }
01182
01183 #ifndef _GNU_SOURCE
01184 void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
01185 #endif
01186
01187 static int eval_stack_func_func(struct sip_msg *msg, char *param1, char *param2) {
01188 struct eval_function *f;
01189 struct stack_item *pivot;
01190 struct eval_function_def *d;
01191 int stack_idx = 0;
01192 int ret = -1;
01193
01194 if (param2) {
01195 long l;
01196 int ret;
01197 struct eval_value v;
01198 eval_location(msg, (struct eval_location*) param2, &v, 1);
01199 ret = get_as_int(&v, &l);
01200 if (ret < 0) return ret;
01201 stack_idx = l;
01202 }
01203
01204 for (f = (struct eval_function*) param1; f; f=f->next, ret = 1) {
01205 if (f->resolved) {
01206 d = f->oper.d;
01207 }
01208 else {
01209 str fn;
01210 struct eval_value v;
01211 eval_location(msg, &f->oper.loc, &v, 1);
01212 get_as_str(&v, &fn);
01213 for (d=eval_functions; d->type; d++) {
01214 if (strlen(d->name) == fn.len && strncasecmp(d->name, fn.s, fn.len)==0) {
01215 break;
01216 }
01217 }
01218 if (!d->type) {
01219 ERR(MODULE_NAME": unknown eval function '%.*s'\n", fn.len, fn.s);
01220 return -1;
01221 }
01222 }
01223 DEBUG(MODULE_NAME": eval_oper: %s, stack_idx: %d, stack_no: %d\n", d->name, stack_idx, stack_no);
01224 if ( ((stack_idx >= 0) && (stack_idx+d->arg_no > stack_no)) ||
01225 ((stack_idx < 0) && (stack_no+stack_idx < 0 || stack_no+stack_idx+d->arg_no > stack_no)) ) {
01226 ERR(MODULE_NAME": operation out of stack range\n");
01227 return -1;
01228 }
01229 pivot = find_stack_item(stack_idx);
01230 if (!pivot) {
01231 BUG("stack test error\n");
01232 return -1;
01233 }
01234 switch (d->type) {
01235
01236 case esftAdd:
01237 case esftSub:
01238 case esftMultiplication:
01239 case esftDivision:
01240 case esftModulo:
01241 case esftAnd:
01242 case esftOr:
01243 case esftBitAnd:
01244 case esftBitOr:
01245 case esftBitXor: {
01246 long a, b;
01247 if (get_as_int(&pivot->value, &a) < 0) return -1;
01248 if (get_as_int(&pivot->next->value, &b) < 0) return -1;
01249 switch (d->type) {
01250 case esftAdd:
01251 a = a + b;
01252 break;
01253 case esftSub:
01254 a = a - b;
01255 break;
01256 case esftMultiplication:
01257 a = a * b;
01258 break;
01259 case esftDivision:
01260 if (b == 0) {
01261 ERR(MODULE_NAME": division by zero\n");
01262 return -1;
01263 }
01264 a = a / b;
01265 break;
01266 case esftModulo:
01267 if (b == 0) {
01268 ERR(MODULE_NAME": division by zero\n");
01269 return -1;
01270 }
01271 a = a % b;
01272 break;
01273 case esftAnd:
01274 a = a && b;
01275 break;
01276 case esftOr:
01277 a = a || b;
01278 break;
01279 case esftBitAnd:
01280 a = a & b;
01281 break;
01282 case esftBitOr:
01283 a = a | b;
01284 break;
01285 case esftBitXor:
01286 a = a ^ b;
01287 break;
01288 }
01289 destroy_value(pivot->value);
01290 pivot->value.type = evtInt;
01291 pivot->value.u.n = a;
01292 remove_stack_item(pivot->next);
01293 break;
01294 }
01295 case esftNeg:
01296 case esftAbs:
01297 case esftSgn:
01298 case esftDec:
01299 case esftInc:
01300 case esftNot:
01301 case esftBitNot:
01302 case esftCastAsInt: {
01303 long a;
01304 if (get_as_int(&pivot->value, &a) < 0) return -1;
01305 switch (d->type) {
01306 case esftNeg:
01307 a = -a;
01308 break;
01309 case esftAbs:
01310 a = abs(a);
01311 break;
01312 case esftSgn:
01313 if (a < 0)
01314 a = -1;
01315 else if (a > 0)
01316 a = 1;
01317 else
01318 a = 0;
01319 break;
01320 case esftDec:
01321 a--;
01322 break;
01323 case esftInc:
01324 a++;
01325 break;
01326 case esftNot:
01327 a = !a;
01328 break;
01329 case esftBitNot:
01330 a = ~a;
01331 break;
01332 case esftCastAsInt:
01333 break;
01334 }
01335 destroy_value(pivot->value);
01336 pivot->value.type = evtInt;
01337 pivot->value.u.n = a;
01338 break;
01339 }
01340 case esftCastAsStr:
01341 if (pivot->value.type != evtStr) {
01342 str s;
01343 get_as_str(&pivot->value, &s);
01344 destroy_value(pivot->value);
01345 pivot->value.u.s = eval_str_malloc(&s);
01346 if (!pivot->value.u.s) {
01347 ERR(MODULE_NAME": out of memory\n");
01348 return -1;
01349 }
01350 pivot->value.type = evtStr;
01351 }
01352 break;
01353 case esftEQ:
01354 case esftNE:
01355 case esftGT:
01356 case esftGE:
01357 case esftLW:
01358 case esftLE: {
01359 long a;
01360 if (pivot->value.type == evtStr || pivot->next->value.type == evtStr) {
01361 str s1, s2;
01362 int l;
01363 get_as_str(&pivot->value, &s1);
01364 get_as_str(&pivot->next->value, &s2);
01365 l = (s1.len < s2.len)?s1.len:s2.len;
01366 if (l > 0)
01367 a = strncasecmp(s1.s, s2.s, l);
01368 else
01369 a = 0;
01370 switch (d->type) {
01371 case esftEQ:
01372 a = a == 0 && s1.len == s2.len;
01373 break;
01374 case esftNE:
01375 a = a != 0 || s1.len != s2.len;
01376 break;
01377 case esftGT:
01378 a = a > 0 || (a == 0 && s1.len > s2.len);
01379 break;
01380 case esftGE:
01381 a = a > 0 || (a == 0 && s1.len >= s2.len);
01382 break;
01383 case esftLW:
01384 a = a < 0 || (a == 0 && s1.len < s2.len);
01385 break;
01386 case esftLE:
01387 a = a < 0 || (a == 0 && s1.len <= s2.len);
01388 break;
01389 }
01390 }
01391 else {
01392 long b;
01393 if (get_as_int(&pivot->value, &a) < 0) return -1;
01394 if (get_as_int(&pivot->next->value, &b) < 0) return -1;
01395 switch (d->type) {
01396 case esftEQ:
01397 a = a == b;
01398 break;
01399 case esftNE:
01400 a = a != b;
01401 break;
01402 case esftGT:
01403 a = a > b;
01404 break;
01405 case esftGE:
01406 a = a >= b;
01407 break;
01408 case esftLW:
01409 a = a < b;
01410 break;
01411 case esftLE:
01412 a = a <= b;
01413 break;
01414 }
01415 }
01416 destroy_value(pivot->value);
01417 pivot->value.type = evtInt;
01418 pivot->value.u.n = a;
01419 remove_stack_item(pivot->next);
01420 break;
01421 }
01422 case esftConcat: {
01423 char buf[25];
01424 str s, s1, s2;
01425 struct eval_str* es;
01426 get_as_str(&pivot->value, &s1);
01427 if (pivot->value.type == evtInt && pivot->next->value.type == evtInt) {
01428 memcpy(buf, s1.s, s1.len);
01429 s1.s = buf;
01430 }
01431 get_as_str(&pivot->next->value, &s2);
01432 s.len = s1.len + s2.len;
01433 s.s = 0;
01434 es = eval_str_malloc(&s);
01435 if (!es) {
01436 ERR(MODULE_NAME": out of memory\n");
01437 return -1;
01438 }
01439 memcpy(s.s, s1.s, s1.len);
01440 memcpy(s.s+s1.len, s2.s, s2.len);
01441 destroy_value(pivot->value);
01442 pivot->value.type = evtStr;
01443 pivot->value.u.s = es;
01444 remove_stack_item(pivot->next);
01445 break;
01446 }
01447 case esftSubstr: {
01448 long start, len;
01449 str s1;
01450 struct eval_str* es;
01451 get_as_str(&pivot->value, &s1);
01452 if (get_as_int(&pivot->next->value, &start) < 0) return -1;
01453 if (get_as_int(&pivot->next->next->value, &len) < 0) return -1;
01454
01455 if (start < 0) {
01456 start = s1.len + start;
01457 if (start < 0) start = 0;
01458 }
01459 else {
01460 if (start > s1.len) start = s1.len;
01461 }
01462 if (len < 0) {
01463 len = s1.len - start + len;
01464 if (len < 0)
01465 len = 0;
01466 }
01467 else {
01468 if (start + len > s1.len)
01469 len = s1.len - start;
01470 }
01471 s1.s += start;
01472 s1.len = len;
01473 es = eval_str_malloc(&s1);
01474 if (!es) {
01475 ERR(MODULE_NAME": out of memory\n");
01476 return -1;
01477 }
01478 destroy_value(pivot->value);
01479 pivot->value.type = evtStr;
01480 pivot->value.u.s = es;
01481 remove_stack_item(pivot->next);
01482 remove_stack_item(pivot->next);
01483 break;
01484 }
01485 case esftStrLen: {
01486 long len;
01487 str s1;
01488 get_as_str(&pivot->value, &s1);
01489 len = s1.len;
01490 destroy_value(pivot->value);
01491 pivot->value.type = evtInt;
01492 pivot->value.u.n = len;
01493 break;
01494 }
01495 case esftStrStr: {
01496 char buf[25], *p;
01497 str s1, s2;
01498
01499 get_as_str(&pivot->value, &s1);
01500 if (pivot->value.type == evtInt && pivot->next->value.type == evtInt) {
01501 memcpy(buf, s1.s, s1.len);
01502 s1.s = buf;
01503 }
01504 get_as_str(&pivot->next->value, &s2);
01505 p = (char *) memmem(s1.s, s1.len, s2.s, s2.len);
01506 destroy_value(pivot->value);
01507 pivot->value.type = evtInt;
01508 pivot->value.u.n = p?p-s1.s:-1;
01509 remove_stack_item(pivot->next);
01510 break;
01511 }
01512 case esftStrDel: {
01513 long start, len;
01514 str s1, s;
01515 struct eval_str* es;
01516 get_as_str(&pivot->value, &s1);
01517 if (get_as_int(&pivot->next->value, &start) < 0) return -1;
01518 if (get_as_int(&pivot->next->next->value, &len) < 0) return -1;
01519
01520 if (start < 0) {
01521 start = s1.len + start;
01522 if (start < 0) start = 0;
01523 }
01524 else {
01525 if (start > s1.len) start = s1.len;
01526 }
01527 if (len < 0) {
01528 len = s1.len - start + len;
01529 if (len < 0)
01530 len = 0;
01531 }
01532 else {
01533 if (start + len > s1.len)
01534 len = s1.len - start;
01535 }
01536 s.s = 0;
01537 s.len = s1.len - len;
01538 es = eval_str_malloc(&s);
01539 if (!es) {
01540 ERR(MODULE_NAME": out of memory\n");
01541 return -1;
01542 }
01543 if (start > 0)
01544 memcpy(s.s, s1.s, start);
01545 memcpy(s.s+start, s1.s+start+len, s1.len-(start+len));
01546 destroy_value(pivot->value);
01547 pivot->value.type = evtStr;
01548 pivot->value.u.s = es;
01549 remove_stack_item(pivot->next);
01550 remove_stack_item(pivot->next);
01551 break;
01552 }
01553 case esftStrUpper:
01554 case esftStrLower: {
01555 str s1;
01556 int i;
01557 struct eval_str* es;
01558 get_as_str(&pivot->value, &s1);
01559
01560 es = eval_str_malloc(&s1);
01561 if (!es) {
01562 ERR(MODULE_NAME": out of memory\n");
01563 return -1;
01564 }
01565 for (i=0; i<es->s.len; i++)
01566 es->s.s[i] = (d->type == esftStrUpper) ? toupper(es->s.s[i]) : tolower(es->s.s[i]);
01567 destroy_value(pivot->value);
01568 pivot->value.type = evtStr;
01569 pivot->value.u.s = es;
01570 break;
01571 }
01572 case esftValueAt: {
01573 str s1, *vals;
01574 long idx;
01575 int n;
01576 struct eval_str* es;
01577
01578 get_as_str(&pivot->value, &s1);
01579 if (get_as_int(&pivot->next->value, &idx) < 0) return -1;
01580 if (parse_hf_values(s1, &n, &vals) < 0) return -1;
01581 if (idx < 0|| idx >= n) {
01582 ERR(MODULE_NAME": index (%ld) of of range (%d)\n", idx, n);
01583 return -1;
01584 }
01585 es = eval_str_malloc(vals+idx);
01586 if (!es) {
01587 ERR(MODULE_NAME": out of memory\n");
01588 return -1;
01589 }
01590 destroy_value(pivot->value);
01591 pivot->value.type = evtStr;
01592 pivot->value.u.s = es;
01593 remove_stack_item(pivot->next);
01594 break;
01595 }
01596 case esftStrValueAt: {
01597 char buf[25];
01598 str s1, s2, *vals;
01599 int i, n;
01600
01601 get_as_str(&pivot->value, &s1);
01602 if (pivot->value.type == evtInt && pivot->next->value.type == evtInt) {
01603 memcpy(buf, s1.s, s1.len);
01604 s1.s = buf;
01605 }
01606 get_as_str(&pivot->next->value, &s2);
01607 if (parse_hf_values(s1, &n, &vals) < 0) return -1;
01608 for (i=0; i<n; i++) {
01609 if (s2.len == vals[i].len && strncmp(s2.s, vals[i].s, s2.len) == 0)
01610 break;
01611 }
01612 destroy_value(pivot->value);
01613 pivot->value.type = evtInt;
01614 pivot->value.u.n = (i>=n)?-1:i;
01615 remove_stack_item(pivot->next);
01616 break;
01617 }
01618 case esftValueCount: {
01619 str s1, *vals;
01620 int n;
01621
01622 get_as_str(&pivot->value, &s1);
01623 if (parse_hf_values(s1, &n, &vals) < 0) return -1;
01624 destroy_value(pivot->value);
01625 pivot->value.type = evtInt;
01626 pivot->value.u.n = n;
01627 break;
01628 }
01629 case esftSubValue: {
01630 long start, len;
01631 int i, n, pos;
01632 str s1, s, *vals;
01633 struct eval_str* es;
01634 get_as_str(&pivot->value, &s1);
01635 if (get_as_int(&pivot->next->value, &start) < 0) return -1;
01636 if (get_as_int(&pivot->next->next->value, &len) < 0) return -1;
01637 if (parse_hf_values(s1, &n, &vals) < 0) return -1;
01638
01639 if (start < 0) {
01640 start = n + start;
01641 if (start < 0) start = 0;
01642 }
01643 else {
01644 if (start > n) start = n;
01645 }
01646 if (len < 0) {
01647 len = n - start + len;
01648 if (len < 0)
01649 len = 0;
01650 }
01651 else {
01652 if (start + len > n)
01653 len = n - start;
01654 }
01655 s.len = 0;
01656 for (i=0; i<len; i++) {
01657 s.len += vals[start+i].len+1;
01658 }
01659 if (s.len)
01660 s.len--;
01661 s.s = 0;
01662 es = eval_str_malloc(&s);
01663 if (!es) {
01664 ERR(MODULE_NAME": out of memory\n");
01665 return -1;
01666 }
01667 for (i=0, pos=0; i<len; i++) {
01668 if (pos > 0)
01669 s.s[pos++] = ',';
01670 memcpy(s.s+pos, vals[start+i].s, vals[start+i].len);
01671 pos += vals[start+i].len;
01672 }
01673
01674 destroy_value(pivot->value);
01675 pivot->value.type = evtStr;
01676 pivot->value.u.s = es;
01677 remove_stack_item(pivot->next);
01678 remove_stack_item(pivot->next);
01679 break;
01680 }
01681 case esftValueConcat: {
01682 long n;
01683 int i, pos;
01684 str s1, s;
01685 struct eval_str* es;
01686 struct stack_item *si;
01687
01688 if (get_as_int(&pivot->value, &n) < 0) return -1;
01689 for (si=pivot->next, s.len=0, i=0; i<n && si; i++, si=si->next) {
01690 get_as_str(&si->value, &s1);
01691 s.len += s1.len+1;
01692 }
01693 if (s.len)
01694 s.len--;
01695 s.s = 0;
01696 es = eval_str_malloc(&s);
01697 if (!es) {
01698 ERR(MODULE_NAME": out of memory\n");
01699 return -1;
01700 }
01701 for (si=pivot->next, i=0, pos=0; i<n && si; i++, si=si->next) {
01702 if (pos > 0)
01703 s.s[pos++] = ',';
01704 get_as_str(&si->value, &s1);
01705 memcpy(s.s+pos, s1.s, s1.len);
01706 pos += s1.len;
01707 }
01708
01709 destroy_value(pivot->value);
01710 pivot->value.type = evtStr;
01711 pivot->value.u.s = es;
01712 for (si=pivot->next, i=0; i<n && si; i++) {
01713 struct stack_item *si2;
01714 si2 = si;
01715 si=si->next;
01716 remove_stack_item(si2);
01717 }
01718 break;
01719
01720 }
01721 case esftValueRev: {
01722 int i, n, pos;
01723 str s1, s, *vals;
01724 struct eval_str* es;
01725 get_as_str(&pivot->value, &s1);
01726 if (parse_hf_values(s1, &n, &vals) < 0) return -1;
01727
01728 s.len = 0;
01729 for (i=0; i<n; i++) {
01730 s.len += vals[i].len+1;
01731 }
01732 if (s.len)
01733 s.len--;
01734 s.s = 0;
01735 es = eval_str_malloc(&s);
01736 if (!es) {
01737 ERR(MODULE_NAME": out of memory\n");
01738 return -1;
01739 }
01740 for (i=n-1, pos=0; i>=0; i--) {
01741 if (pos > 0)
01742 s.s[pos++] = ',';
01743 memcpy(s.s+pos, vals[i].s, vals[i].len);
01744 pos += vals[i].len;
01745 }
01746
01747 destroy_value(pivot->value);
01748 pivot->value.type = evtStr;
01749 pivot->value.u.s = es;
01750 break;
01751 }
01752 case esftValueUris: {
01753 int i, n, pos;
01754 str s1, s, *vals;
01755 struct eval_str* es;
01756 get_as_str(&pivot->value, &s1);
01757 if (parse_hf_values(s1, &n, &vals) < 0) return -1;
01758
01759 s.len = 0;
01760 for (i=0; i<n; i++) {
01761 s.len += vals[i].len+1;
01762 }
01763 if (s.len)
01764 s.len--;
01765 s.s = 0;
01766 es = eval_str_malloc(&s);
01767 if (!es) {
01768 ERR(MODULE_NAME": out of memory\n");
01769 return -1;
01770 }
01771 for (i=0, pos=0; i<n; i++) {
01772 str hval1, huri;
01773 if (pos > 0)
01774 s.s[pos++] = ',';
01775 hval1 = *(vals+i);
01776 get_uri_and_skip_until_params(&hval1, &huri);
01777 if (huri.len) {
01778
01779 memcpy(s.s+pos, huri.s, huri.len);
01780 pos += huri.len;
01781 }
01782 }
01783 es->s.len = pos;
01784
01785 destroy_value(pivot->value);
01786 pivot->value.type = evtStr;
01787 pivot->value.u.s = es;
01788 break;
01789 }
01790 case esftGetUri: {
01791 str s1, huri;
01792 struct eval_str* es;
01793 get_as_str(&pivot->value, &s1);
01794 get_uri_and_skip_until_params(&s1, &huri);
01795 if (huri.len && *(huri.s) == '<') {
01796 huri.s++;
01797 huri.len-=2;
01798 }
01799 es = eval_str_malloc(&huri);
01800 if (!es) {
01801 ERR(MODULE_NAME": out of memory\n");
01802 return -1;
01803 }
01804 destroy_value(pivot->value);
01805 pivot->value.type = evtStr;
01806 pivot->value.u.s = es;
01807 break;
01808 }
01809 default:
01810 BUG("Bad operation %d\n", d->type);
01811 return -1;
01812 }
01813 }
01814 return ret;
01815 }
01816
01817 static int eval_while_fixup(void **param, int param_no) {
01818
01819 if (param_no == 2) {
01820 return fixup_location_12(param, param_no);
01821 }
01822 else if (param_no == 1) {
01823 int n;
01824 n = route_get(&main_rt, (char*) *param);
01825 if (n == -1) {
01826 ERR(MODULE_NAME": eval_while: bad route\n");
01827 return E_CFG;
01828 }
01829 pkg_free(*param);
01830 *param=(void*) (intptr_t) n;
01831 }
01832 return 0;
01833 }
01834
01835 static int eval_while_func(struct sip_msg *msg, char *route_no, char *param2) {
01836 int ret, idx;
01837 struct stack_item *pivot;
01838 struct run_act_ctx ra_ctx;
01839
01840 if (param2) {
01841 long l;
01842 struct eval_value v;
01843 eval_location(msg, (struct eval_location*) param2, &v, 1);
01844 ret = get_as_int(&v, &l);
01845 if (ret < 0) return ret;
01846 idx = l;
01847 }
01848 else {
01849 idx = 0;
01850 }
01851
01852 ret = -1;
01853 while (1) {
01854 pivot = find_stack_item(idx);
01855 if (!pivot) break;
01856 if (get_as_bool(&pivot->value) <= 0) break;
01857 if ((intptr_t)route_no >= main_rt.idx) {
01858 BUG("invalid routing table number #%d of %d\n", (int)(intptr_t) route_no, main_rt.idx);
01859 return -1;
01860 }
01861 if (!main_rt.rlist[(intptr_t) route_no]) {
01862 WARN(MODULE_NAME": route not declared (hash:%d)\n", (int)(intptr_t) route_no);
01863 return -1;
01864 }
01865
01866 init_run_actions_ctx(&ra_ctx);
01867 ret = run_actions(&ra_ctx, main_rt.rlist[(intptr_t) route_no], msg);
01868 if (ret <= 0) break;
01869 }
01870 return ret;
01871 }
01872
01873 static int eval_while_stack_func(struct sip_msg *msg, char *route_no, char *param2) {
01874 int ret, count;
01875 struct run_act_ctx ra_ctx;
01876
01877 if (param2) {
01878 long l;
01879 struct eval_value v;
01880 eval_location(msg, (struct eval_location*) param2, &v, 1);
01881 ret = get_as_int(&v, &l);
01882 if (ret < 0) return ret;
01883 count = l;
01884 }
01885 else {
01886 count = 0;
01887 }
01888 ret = -1;
01889 while ((count >= 0 && stack_no > count) || (count < 0 && stack_no < -count)) {
01890 if ((intptr_t)route_no >= main_rt.idx) {
01891 BUG("invalid routing table number #%d of %d\n", (int)(intptr_t) route_no, main_rt.idx);
01892 return -1;
01893 }
01894 if (!main_rt.rlist[(intptr_t) route_no]) {
01895 WARN(MODULE_NAME": route not declared (hash:%d)\n", (int)(intptr_t) route_no);
01896 return -1;
01897 }
01898
01899 init_run_actions_ctx(&ra_ctx);
01900 ret = run_actions(&ra_ctx, main_rt.rlist[(intptr_t) route_no], msg);
01901 if (ret <= 0) break;
01902 }
01903 return ret;
01904 }
01905
01906
01907 static int sel_value2str(str* res, struct eval_value *v, int force_copy) {
01908 res->len = 0;
01909 switch (v->type) {
01910 case evtInt: {
01911 char buf[30];
01912 res->len = snprintf(buf, sizeof(buf)-1, "%ld", v->u.n);
01913 res->s = get_static_buffer(res->len);
01914 if (res->s)
01915 memcpy(res->s, buf, res->len);
01916 else
01917 res->len = 0;
01918 break;
01919 }
01920 case evtStr:
01921 if (v->u.s) {
01922 *res = v->u.s->s;
01923 if (force_copy && res->len) {
01924 res->s = get_static_buffer(res->len);
01925 if (res->s)
01926 memcpy(res->s, v->u.s->s.s, res->len);
01927 else
01928 res->len = 0;
01929 }
01930 }
01931 break;
01932 }
01933 return 0;
01934 }
01935
01936 static int sel_eval(str* res, select_t* s, struct sip_msg* msg) {
01937 return 0;
01938 }
01939
01940 static int sel_register(str* res, select_t* s, struct sip_msg* msg) {
01941 if (msg == 0) {
01942 struct register_item *p = find_register(s->params[2].v.s.s, s->params[2].v.s.len);
01943 if (p == 0) {
01944 ERR(MODULE_NAME": select: register '%.*s' not found\n", s->params[2].v.s.len, s->params[2].v.s.s);
01945 return E_CFG;
01946 }
01947 s->params[2].v.p = p;
01948 s->params[2].type = SEL_PARAM_PTR;
01949 }
01950 else {
01951 return sel_value2str(res, &((struct register_item *)s->params[2].v.p)->value, 0);
01952 }
01953 return 0;
01954 }
01955
01956 static int sel_get_and_remove(str* res, select_t* s, struct sip_msg* msg) {
01957 struct stack_item* p;
01958 res->len = 0;
01959 p = find_stack_item(s->params[2].v.i);
01960 if (p) {
01961 sel_value2str(res, &p->value, 1);
01962 remove_stack_item(p);
01963 }
01964 return 0;
01965 }
01966
01967 static int sel_get(str* res, select_t* s, struct sip_msg* msg) {
01968 struct stack_item* p;
01969 res->len = 0;
01970 p = find_stack_item(s->params[2].v.i);
01971 if (p) {
01972 sel_value2str(res, &p->value, 0);
01973 }
01974 return 0;
01975 }
01976
01977 SELECT_F(select_any_nameaddr)
01978 SELECT_F(select_any_uri)
01979 SELECT_F(select_anyheader_params)
01980
01981 select_row_t sel_declaration[] = {
01982 { NULL, SEL_PARAM_STR, STR_STATIC_INIT(MODULE_NAME), sel_eval, SEL_PARAM_EXPECTED},
01983
01984 { sel_eval, SEL_PARAM_STR, STR_STATIC_INIT("pop"), sel_get_and_remove, CONSUME_NEXT_INT },
01985 { sel_eval, SEL_PARAM_STR, STR_STATIC_INIT("get"), sel_get, CONSUME_NEXT_INT },
01986 { sel_eval, SEL_PARAM_STR, STR_STATIC_INIT("reg"), sel_register, CONSUME_NEXT_STR|FIXUP_CALL },
01987
01988 { sel_get, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED | CONSUME_NEXT_STR},
01989 { sel_get, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_any_uri, NESTED | CONSUME_NEXT_STR},
01990 { sel_get, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_anyheader_params, NESTED},
01991 { sel_register, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED | CONSUME_NEXT_STR},
01992 { sel_register, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_any_uri, NESTED | CONSUME_NEXT_STR},
01993 { sel_register, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_anyheader_params, NESTED},
01994
01995
01996 { sel_eval, SEL_PARAM_STR, STR_STATIC_INIT("uuid"), select_sys_unique, 0},
01997
01998 { NULL, SEL_PARAM_INT, STR_NULL, NULL, 0}
01999 };
02000
02001
02002 static int mod_init() {
02003
02004 register_script_cb(mod_pre_script_cb, REQUEST_CB | ONREPLY_CB | PRE_SCRIPT_CB, 0);
02005 register_select_table(sel_declaration);
02006 return 0;
02007 }
02008
02009 static int child_init(int rank) {
02010
02011 return 0;
02012 }
02013
02014 static void destroy_mod(void) {
02015 struct register_item *p;
02016 destroy_stack();
02017 destroy_register_values();
02018 while (registers) {
02019 p = registers;
02020 registers = registers->next;
02021 pkg_free(p);
02022 }
02023 }
02024
02025
02026
02027
02028 static cmd_export_t cmds[] = {
02029 {MODULE_NAME"_add", eval_stack_oper_func, 2, eval_add_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02030 {MODULE_NAME"_add", eval_stack_oper_func, 1, eval_add_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02031 {MODULE_NAME"_push", eval_stack_oper_func, 2, eval_add_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02032 {MODULE_NAME"_push", eval_stack_oper_func, 1, eval_add_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02033 {MODULE_NAME"_insert", eval_stack_oper_func, 2, eval_insert_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02034 {MODULE_NAME"_insert", eval_stack_oper_func, 1, eval_insert_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02035 {MODULE_NAME"_xchg", eval_stack_oper_func, 2, eval_xchg_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02036 {MODULE_NAME"_xchg", eval_stack_oper_func, 1, eval_xchg_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02037 {MODULE_NAME"_get", eval_stack_oper_func, 2, eval_get_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02038 {MODULE_NAME"_get", eval_stack_oper_func, 1, eval_get_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02039 {MODULE_NAME"_put", eval_stack_oper_func, 2, eval_put_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02040 {MODULE_NAME"_put", eval_stack_oper_func, 1, eval_put_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02041 {MODULE_NAME"_pop", eval_stack_oper_func, 2, eval_pop_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02042 {MODULE_NAME"_pop", eval_stack_oper_func, 1, eval_pop_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02043 {MODULE_NAME"_add_value", eval_stack_oper_func, 2, eval_add_value_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02044 {MODULE_NAME"_add_value", eval_stack_oper_func, 1, eval_add_value_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02045 {MODULE_NAME"_insert_value", eval_stack_oper_func, 2, eval_insert_value_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02046 {MODULE_NAME"_insert_value", eval_stack_oper_func, 1, eval_insert_value_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02047
02048 {MODULE_NAME"_remove", eval_remove_func, 0, fixup_location_12, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02049 {MODULE_NAME"_remove", eval_remove_func, 1, fixup_location_12, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02050 {MODULE_NAME"_remove", eval_remove_func, 2, fixup_location_12, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02051 {MODULE_NAME"_clear", eval_clear_func, 1, fixup_int_12, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02052
02053 {MODULE_NAME"_oper", eval_stack_func_func, 2, eval_stack_func_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02054 {MODULE_NAME"_oper", eval_stack_func_func, 1, eval_stack_func_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02055
02056 {MODULE_NAME"_while", eval_while_func, 1, eval_while_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02057 {MODULE_NAME"_while", eval_while_func, 2, eval_while_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02058 {MODULE_NAME"_while_stack", eval_while_stack_func, 1, eval_while_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02059 {MODULE_NAME"_while_stack", eval_while_stack_func, 2, eval_while_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02060
02061 {MODULE_NAME"_dump", eval_dump_func, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
02062
02063 {0, 0, 0, 0, 0}
02064 };
02065
02066
02067
02068
02069 static param_export_t params[] = {
02070 {"declare_register", PARAM_STRING|PARAM_USE_FUNC, (void*) declare_register},
02071 {"xlbuf_size", PARAM_INT, &xlbuf_size},
02072 {0, 0, 0}
02073 };
02074
02075
02076 struct module_exports exports = {
02077 MODULE_NAME,
02078 cmds,
02079 0,
02080 params,
02081 mod_init,
02082 0,
02083 destroy_mod,
02084 0,
02085 child_init
02086 };