avp: converted to the new module interface
[sip-router] / src / modules / avp / avp.c
1 /*
2  * Copyright (C) 2004 FhG Fokus
3  *
4  * This file is part of ser, a free SIP server.
5  *
6  * ser is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * For a license to use the ser software under conditions
12  * other than those described here, or to purchase support for this
13  * software, please contact iptel.org by e-mail at the following addresses:
14  *    info@iptel.org
15  *
16  * ser is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24  */
25
26 #include <string.h>
27 #include <stdlib.h>
28 #ifdef EXTRA_DEBUG
29 #include <assert.h>
30 #endif
31 #include "../../core/sr_module.h"
32 #include "../../core/error.h"
33 #include "../../core/lump_struct.h"
34 #include "../../core/data_lump.h"
35 #include "../../core/data_lump_rpl.h"
36 #include "../../core/usr_avp.h"
37 #include "../../core/mem/mem.h"
38 #include "../../core/parser/parse_uri.h"
39 #include "../../core/parser/msg_parser.h"
40 #include "../../core/parser/parse_nameaddr.h"
41 #include "../../core/ut.h"
42 #include "../../core/dset.h"
43 #include "../../core/trim.h"
44 #include "../../core/str.h"
45 #include "../../core/dprint.h"
46 #include "../../core/re.h"
47 #include "../../core/action.h"
48
49 #include "../../core/parser/parse_hname2.h"
50 #include "../xprint/xp_lib.h"
51 #define NO_SCRIPT -1
52
53 MODULE_VERSION
54
55 /* name of attributed used to store flags with command flags2attr */
56 #define HDR_ID 0
57 #define HDR_STR 1
58
59 #define PARAM_DELIM '/'
60 #define VAL_TYPE_INT (1<<0)
61 #define VAL_TYPE_STR (1<<1)
62
63 typedef struct hdr_name {
64         enum {hdrId, hdrStr} kind;
65         union {
66                 int n;
67                 str s;
68         } name;
69         char field_delimiter;
70         char array_delimiter;
71         int val_types;
72 } hdr_name_t;
73
74 static int xlbuf_size=256;
75 static char* xlbuf=NULL;
76 static str* xl_nul=NULL;
77 static xl_print_log_f* xl_print=NULL;
78 static xl_parse_format_f* xl_parse=NULL;
79 static xl_elog_free_all_f* xl_free=NULL;
80 static xl_get_nulstr_f* xl_getnul=NULL;
81
82 static int mod_init();
83 static int set_iattr(struct sip_msg* msg, char* p1, char* p2);
84 static int set_sattr(struct sip_msg* msg, char* p1, char* p2);
85 static int print_attr(struct sip_msg* msg, char* p1, char* p2);
86 static int del_attr(struct sip_msg* msg, char* p1, char* p2);
87 static int subst_attr(struct sip_msg* msg, char* p1, char* p2);
88 static int flags2attr(struct sip_msg* msg, char* p1, char* p2);
89 static int attr2uri(struct sip_msg* msg, char* p1, char* p2);
90 static int dump_attrs(struct sip_msg* msg, char* p1, char* p2);
91 static int attr_equals(struct sip_msg* msg, char* p1, char* p2);
92 static int attr_exists(struct sip_msg* msg, char* p1, char* p2);
93 static int attr_equals_xl(struct sip_msg* msg, char* p1, char* p2);
94 static int xlset_attr(struct sip_msg* msg, char* p1, char* p2);
95 static int xlfix_attr(struct sip_msg* msg, char* p1, char* p2);
96 static int insert_req(struct sip_msg* msg, char* p1, char* p2);
97 static int append_req(struct sip_msg* msg, char* p1, char* p2);
98 static int replace_req(struct sip_msg* msg, char* p1, char* p2);
99 static int append_reply(struct sip_msg* msg, char* p1, char* p2);
100 static int attr_destination(struct sip_msg* msg, char* p1, char* p2);
101 static int xlset_destination(struct sip_msg* msg, char* p1, char* p2);
102 static int attr_hdr_body2attrs(struct sip_msg* msg, char* p1, char* p2);
103 static int attr_hdr_body2attrs2(struct sip_msg* msg, char* p1, char* p2);
104 static int del_attrs(struct sip_msg* msg, char* p1, char* p2);
105
106 static int set_iattr_fixup(void**, int);
107 static int avpid_fixup(void**, int);
108 static int subst_attr_fixup(void**, int);
109 static int fixup_part(void**, int);
110 static int fixup_xl_1(void**, int);
111 static int fixup_attr_1_xl_2(void**, int);
112 static int fixup_str_1_attr_2(void**, int);
113 static int xlfix_attr_fixup(void** param, int param_no);
114 static int attr_hdr_body2attrs_fixup(void**, int);
115 static int attr_hdr_body2attrs2_fixup(void**, int);
116 static int avpgroup_fixup(void**, int);
117
118 /*
119  * Exported functions
120  */
121 static cmd_export_t cmds[] = {
122         {"set_iattr",         set_iattr,            2, set_iattr_fixup,            0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
123         {"set_sattr",         set_sattr,            2, fixup_var_str_12,           0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
124         {"set_attr",          set_sattr,            2, fixup_var_str_12,           0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
125         {"print_attr",        print_attr,           1, avpid_fixup,                0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
126         {"del_attr",          del_attr,             1, avpid_fixup,                0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
127         {"del_attrs",         del_attrs,            1, avpgroup_fixup,             0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
128         {"subst_attr",        subst_attr,           2, subst_attr_fixup,           0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
129         {"flags2attr",        flags2attr,           1, avpid_fixup,                0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
130         {"attr2uri",          attr2uri,             1, fixup_part,                 0, REQUEST_ROUTE | FAILURE_ROUTE},
131         {"attr2uri",          attr2uri,             2, fixup_part,                 0, REQUEST_ROUTE | FAILURE_ROUTE},
132         {"dump_attrs",        dump_attrs,           0, 0,                          0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
133         {"dump_attrs",        dump_attrs,           1, avpgroup_fixup,             0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
134         {"attr_equals",       attr_equals,          2, fixup_var_str_12,           0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
135         {"attr_exists",       attr_exists,          1 , fixup_var_str_1,           0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
136         {"attr_equals_xl",    attr_equals_xl,       2, fixup_attr_1_xl_2,          0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
137         {"xlset_attr",        xlset_attr,           2, fixup_attr_1_xl_2,          0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
138         {"xlfix_attr",        xlfix_attr,           1, xlfix_attr_fixup,           0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
139         {"insert_attr_hf",    insert_req,           2, fixup_str_1_attr_2,         0, REQUEST_ROUTE | FAILURE_ROUTE},
140         {"insert_attr_hf",    insert_req,           1, fixup_str_1_attr_2,         0, REQUEST_ROUTE | FAILURE_ROUTE},
141         {"append_attr_hf",    append_req,           2, fixup_str_1_attr_2,         0, REQUEST_ROUTE | FAILURE_ROUTE},
142         {"append_attr_hf",    append_req,           1, fixup_str_1_attr_2,         0, REQUEST_ROUTE | FAILURE_ROUTE},
143         {"replace_attr_hf",   replace_req,          2, fixup_str_1_attr_2,         0, REQUEST_ROUTE | FAILURE_ROUTE},
144         {"replace_attr_hf",   replace_req,          1, fixup_str_1_attr_2,         0, REQUEST_ROUTE | FAILURE_ROUTE},
145         {"attr_to_reply",     append_reply,         2, fixup_str_1_attr_2,         0, REQUEST_ROUTE | FAILURE_ROUTE},
146         {"attr_to_reply",     append_reply,         1, fixup_str_1_attr_2,         0, REQUEST_ROUTE | FAILURE_ROUTE},
147         {"attr_destination",  attr_destination,     1, avpid_fixup,                0, REQUEST_ROUTE | FAILURE_ROUTE},
148         {"xlset_destination", xlset_destination,    1, fixup_xl_1,                 0, REQUEST_ROUTE},
149         {"hdr_body2attrs",    attr_hdr_body2attrs,  2, attr_hdr_body2attrs_fixup,  0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
150         {"hdr_body2attrs2",   attr_hdr_body2attrs2, 2, attr_hdr_body2attrs2_fixup, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
151         {0, 0, 0, 0, 0, 0}
152 };
153
154
155 /*
156  * Exported parameters
157  */
158 static param_export_t params[] = {
159         {"xlbuf_size", PARAM_INT, &xlbuf_size},
160         {0, 0, 0}
161 };
162
163
164 struct module_exports exports = {
165         "avp",
166         DEFAULT_DLFLAGS, /* dlopen flags */
167         cmds,            /* Exported commands */
168         params,          /* Exported parameters */
169         0,               /* RPC */
170         0,               /* pseudo-variables exports */
171         0,               /* response function*/
172         mod_init,        /* module initialization function */
173         0,               /* per-child init function */
174         0                /* destroy function */
175 };
176
177
178 static int set_iattr_fixup(void** param, int param_no)
179 {
180         if (param_no == 1) {
181                 return fixup_var_str_12(param, param_no);
182         } else {
183                 return fixup_var_int_12(param, param_no);
184         }
185 }
186
187
188 static int get_avp_id(avp_ident_t* id, fparam_t* p, struct sip_msg* msg)
189 {
190         str str_id;
191         avp_t* avp;
192         avp_value_t val;
193         int ret;
194
195         switch(p->type) {
196                 case FPARAM_AVP:
197                         avp = search_avp(p->v.avp, &val, 0);
198                         if (!avp) {
199                                 DBG("get_avp_id: AVP %s does not exist\n", p->orig);
200                                 return -1;
201                         }
202                         if ((avp->flags & AVP_VAL_STR) == 0) {
203                                 DBG("get_avp_id: Not a string AVP\n");
204                                 return -1;
205                         }
206                         str_id = val.s;
207                         break;
208
209                 case FPARAM_SELECT:
210                         ret = run_select(&str_id, p->v.select, msg);
211                         if (ret < 0 || ret > 0) return -1;
212                         break;
213
214                 case FPARAM_STR:
215                         str_id = p->v.str;
216                         break;
217
218                 default:
219                         ERR("Invalid parameter type in get_avp_id\n");
220                         return -1;
221         }
222
223         return parse_avp_ident(&str_id, id);
224 }
225
226
227 static int set_iattr(struct sip_msg* msg, char* p1, char* p2)
228 {
229         avp_ident_t avpid;
230         int_str value;
231
232         if (get_avp_id(&avpid, (fparam_t*)p1, msg) < 0) {
233                 return -1;
234         }
235
236         if (get_int_fparam(&value.n, msg, (fparam_t*)p2) < 0) {
237                 ERR("Error while obtaining attribute value from '%s'\n", ((fparam_t*)p1)->orig);
238                 return -1;
239         }
240
241         if (add_avp(avpid.flags | AVP_NAME_STR, avpid.name, value) != 0) {
242                 ERR("add_avp failed\n");
243                 return -1;
244         }
245         return 1;
246 }
247
248
249 static int set_sattr(struct sip_msg* msg, char* p1, char* p2)
250 {
251         avp_ident_t avpid;
252         int_str value;
253
254         if (get_avp_id(&avpid, (fparam_t*)p1, msg) < 0) {
255                 return -1;
256         }
257
258         if (get_str_fparam(&value.s, msg, (fparam_t*)p2) < 0) {
259                 ERR("Error while obtaining attribute value from '%s'\n", ((fparam_t*)p2)->orig);
260                 return -1;
261         }
262
263         if (add_avp(avpid.flags | AVP_NAME_STR | AVP_VAL_STR, avpid.name, value) != 0) {
264                 ERR("add_avp failed\n");
265                 return -1;
266         }
267
268         return 1;
269 }
270
271
272 static int avpid_fixup(void** param, int param_no)
273 {
274         if (param_no == 1) {
275                 if (fix_param(FPARAM_AVP, param) == 0) return 0;
276                 ERR("Invalid AVP identifier: '%s'\n", (char*)*param);
277                 return -1;
278         }
279         return 0;
280 }
281
282
283 static int print_attr(struct sip_msg* msg, char* p1, char* p2)
284 {
285         fparam_t* fp;
286         int_str value;
287         avp_t *avp;
288
289         fp = (fparam_t*)p1;
290
291         avp = search_avp(fp->v.avp, &value, NULL);
292         if (avp == 0) {
293                 LOG(L_INFO, "AVP '%s' not found\n", fp->orig);
294                 return -1;
295         }
296
297         if (avp->flags & AVP_VAL_STR) {
298                 LOG(L_INFO, "AVP: '%s'='%.*s'\n",
299                                 fp->orig, value.s.len, ZSW(value.s.s));
300         } else {
301                 LOG(L_INFO, "AVP: '%s'=%d\n", fp->orig, value.n);
302         }
303         return 1;
304 }
305
306
307 static int del_attr(struct sip_msg* msg, char* p1, char* p2)
308 {
309         fparam_t* fp;
310         avp_t* avp;
311         struct search_state st;
312
313         fp = (fparam_t*)p1;
314
315         avp = search_avp(fp->v.avp, 0, &st);
316         while (avp) {
317                 destroy_avp(avp);
318                 avp = search_next_avp(&st, 0);
319         }
320         return 1;
321 }
322
323
324 static int del_attrs(struct sip_msg* msg, char* p1, char* p2)
325 {
326         return (reset_avp_list((unsigned long)p1) == 0) ? 1 : -1;
327 }
328
329
330 static int subst_attr_fixup(void** param, int param_no)
331 {
332         if (param_no == 1) {
333                 return avpid_fixup(param, 1);
334         }
335         if (param_no == 2) {
336                 if (fix_param(FPARAM_SUBST, param) != 0) return -1;
337         }
338         return 0;
339 }
340
341
342 static int subst_attr(struct sip_msg* msg, char* p1, char* p2)
343 {
344         avp_t* avp;
345         avp_value_t val;
346         str *res = NULL;
347         int count;
348         avp_ident_t* name = &((fparam_t*)p1)->v.avp;
349
350         if ((avp = search_avp(*name, &val, NULL))) {
351                 if (avp->flags & AVP_VAL_STR) {
352                         res = subst_str(val.s.s, msg, ((fparam_t*)p2)->v.subst, &count);
353                         if (res == NULL) {
354                                 ERR("avp_subst: error while running subst\n");
355                                 goto error;
356                         }
357
358                         DBG("avp_subst: %d, result %.*s\n", count, res->len, ZSW(res->s));
359                         val.s = *res;
360
361                         if (add_avp_before(avp, name->flags | AVP_VAL_STR, name->name, val)) {
362                                 ERR("avp_subst: error while adding new AVP\n");
363                                 goto error;
364                         }
365
366                         destroy_avp(avp);
367                         return 1;
368                 } else {
369                         ERR("avp_subst: AVP has numeric value\n");
370                         goto error;
371                 }
372         } else {
373                 ERR("avp_subst: AVP[%.*s] index %d, flags %x not found\n",
374                                 name->name.s.len, name->name.s.s,
375                                 name->index, name->flags);
376                 goto error;
377         }
378
379 error:
380         if (res) pkg_free(res);
381         return -1;
382 }
383
384
385 static int flags2attr(struct sip_msg* msg, char* p1, char* p2)
386 {
387         avp_ident_t* id;
388         int_str value;
389
390         value.n = msg->flags;
391
392         id = &((fparam_t*)p1)->v.avp;
393
394         if (add_avp(id->flags, id->name, value) != 0) {
395                 ERR("add_avp failed\n");
396                 return -1;
397         }
398
399         return 1;
400 }
401
402
403 static int fixup_part(void** param, int param_no)
404 {
405         int i;
406         fparam_t* fp;
407
408         static struct {
409                 char* s;
410                 int i;
411         } fixup_parse[] = {
412                 {"", SET_URI_T},
413                 {"prefix", PREFIX_T},
414                 {"uri", SET_URI_T},
415                 {"username", SET_USER_T},
416                 {"user", SET_USER_T},
417                 {"usernamepassword", SET_USERPASS_T},
418                 {"userpass", SET_USERPASS_T},
419                 {"domain", SET_HOST_T},
420                 {"host", SET_HOST_T},
421                 {"domainport", SET_HOSTPORT_T},
422                 {"hostport", SET_HOSTPORT_T},
423                 {"port", SET_PORT_T},
424                 {"strip", STRIP_T},
425                 {"strip_tail", STRIP_TAIL_T},
426                 {0, 0}
427         };
428
429         if (param_no == 1) {
430                 return avpid_fixup(param, 1);
431         } else if (param_no == 2) {
432                 /* Create fparam structure */
433                 if (fix_param(FPARAM_STRING, param) != 0) return -1;
434
435                 /* We will parse the string now and store the value
436                  * as int
437                  */
438                 fp = (fparam_t*)*param;
439                 fp->type = FPARAM_INT;
440
441                 for(i = 0; fixup_parse[i].s; i++) {
442                         if (!strcasecmp(fp->orig, fixup_parse[i].s)) {
443                                 fp->v.i = fixup_parse[i].i;
444                                 return 1;
445                         }
446                 }
447
448                 ERR("Invalid parameter value: '%s'\n", fp->orig);
449                 return -1;
450         }
451         return 0;
452 }
453
454
455 static int attr2uri(struct sip_msg* msg, char* p1, char* p2)
456 {
457         int_str value;
458         avp_t* avp_entry;
459         struct action act;
460         struct run_act_ctx ra_ctx;
461         int pnr;
462         unsigned int u;
463
464         if (p2) {
465                 pnr = ((fparam_t*)p2)->v.i;
466         } else {
467                 pnr = SET_URI_T;
468         }
469
470         avp_entry = search_avp(((fparam_t*)p1)->v.avp, &value, NULL);
471         if (avp_entry == 0) {
472                 ERR("attr2uri: AVP '%s' not found\n", ((fparam_t*)p1)->orig);
473                 return -1;
474         }
475
476         memset(&act, 0, sizeof(act));
477
478         if ((pnr == STRIP_T) || (pnr == STRIP_TAIL_T)) {
479                 /* we need integer value for these actions */
480                 if (avp_entry->flags & AVP_VAL_STR) {
481                         if (str2int(&value.s, &u)) {
482                                 ERR("not an integer value: %.*s\n",
483                                                 value.s.len, value.s.s);
484                                 return -1;
485                         }
486                         act.val[0].u.number = u;
487                 } else {
488                         act.val[0].u.number = value.n;
489                 }
490                 act.val[0].type = NUMBER_ST;
491         } else {
492                 /* we need string value */
493                 if ((avp_entry->flags & AVP_VAL_STR) == 0) {
494                         act.val[0].u.string = int2str(value.n, NULL);
495                 } else {
496                         act.val[0].u.string = value.s.s;
497                 }
498                 act.val[0].type = STRING_ST;
499         }
500         act.type = pnr;
501         init_run_actions_ctx(&ra_ctx);
502         if (do_action(&ra_ctx, &act, msg) < 0) {
503                 ERR("failed to change ruri part.\n");
504                 return -1;
505         }
506         return 1;
507 }
508
509
510 /*
511  * sends avp list to log in readable form
512  *
513  */
514 static void dump_avp_reverse(avp_t* avp)
515 {
516         str* name;
517         int_str val;
518
519         if (avp) {
520                 /* AVPs are added to front of the list, reverse by recursion */
521                 dump_avp_reverse(avp->next);
522
523                 name=get_avp_name(avp);
524                 get_avp_val(avp, &val);
525                 switch(avp->flags&(AVP_NAME_STR|AVP_VAL_STR)) {
526                         case 0:
527                                 /* avp type ID, int value */
528                                 LOG(L_INFO,"AVP[%d]=%d\n", avp->id, val.n);
529                                 break;
530
531                         case AVP_NAME_STR:
532                                 /* avp type str, int value */
533                                 name=get_avp_name(avp);
534                                 LOG(L_INFO,"AVP[\"%.*s\"]=%d\n", name->len, name->s, val.n);
535                                 break;
536
537                         case AVP_VAL_STR:
538                                 /* avp type ID, str value */
539                                 LOG(L_INFO,"AVP[%d]=\"%.*s\"\n", avp->id, val.s.len, val.s.s);
540                                 break;
541
542                         case AVP_NAME_STR|AVP_VAL_STR:
543                                 /* avp type str, str value */
544                                 name=get_avp_name(avp);
545                                 LOG(L_INFO,"AVP[\"%.*s\"]=\"%.*s\"\n", name->len, name->s, val.s.len, val.s.s);
546                                 break;
547                 }
548         }
549 }
550
551
552 static int dump_attrs(struct sip_msg* m, char* x, char* y)
553 {
554         avp_list_t avp_list;
555         unsigned long flags;
556
557         if (x) {
558                 flags = (unsigned long)x;
559         } else {
560                 flags = AVP_CLASS_ALL | AVP_TRACK_ALL;
561         }
562
563
564         if (flags & AVP_CLASS_GLOBAL) {
565                 avp_list = get_avp_list(AVP_CLASS_GLOBAL);
566                 INFO("class=GLOBAL\n");
567                 if (!avp_list) {
568                         LOG(L_INFO,"INFO: No AVP present\n");
569                 } else {
570                         dump_avp_reverse(avp_list);
571                 }
572         }
573
574         if (flags & AVP_CLASS_DOMAIN && flags & AVP_TRACK_FROM) {
575                 avp_list = get_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_FROM);
576                 INFO("track=FROM class=DOMAIN\n");
577                 if (!avp_list) {
578                         LOG(L_INFO,"INFO: No AVP present\n");
579                 } else {
580                         dump_avp_reverse(avp_list);
581                 }
582         }
583
584         if (flags & AVP_CLASS_DOMAIN && flags & AVP_TRACK_TO) {
585                 avp_list = get_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO);
586                 INFO("track=TO class=DOMAIN\n");
587                 if (!avp_list) {
588                         LOG(L_INFO,"INFO: No AVP present\n");
589                 } else {
590                         dump_avp_reverse(avp_list);
591                 }
592         }
593
594         if (flags & AVP_CLASS_USER && flags & AVP_TRACK_FROM) {
595                 avp_list = get_avp_list(AVP_CLASS_USER | AVP_TRACK_FROM);
596                 INFO("track=FROM class=USER\n");
597                 if (!avp_list) {
598                         LOG(L_INFO,"INFO: No AVP present\n");
599                 } else {
600                         dump_avp_reverse(avp_list);
601                 }
602         }
603
604         if (flags & AVP_CLASS_USER && flags & AVP_TRACK_TO) {
605                 avp_list = get_avp_list(AVP_CLASS_USER | AVP_TRACK_TO);
606                 INFO("track=TO class=USER\n");
607                 if (!avp_list) {
608                         LOG(L_INFO,"INFO: No AVP present\n");
609                 } else {
610                         dump_avp_reverse(avp_list);
611                 }
612         }
613
614         if (flags & AVP_CLASS_URI && flags & AVP_TRACK_FROM) {
615                 avp_list = get_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM);
616                 INFO("track=FROM class=URI\n");
617                 if (!avp_list) {
618                         LOG(L_INFO,"INFO: No AVP present\n");
619                 } else {
620                         dump_avp_reverse(avp_list);
621                 }
622         }
623
624         if (flags & AVP_CLASS_URI && flags & AVP_TRACK_TO) {
625                 avp_list = get_avp_list(AVP_CLASS_URI | AVP_TRACK_TO);
626                 INFO("track=TO class=URI\n");
627                 if (!avp_list) {
628                         LOG(L_INFO,"INFO: No AVP present\n");
629                 } else {
630                         dump_avp_reverse(avp_list);
631                 }
632         }
633         return 1;
634 }
635
636
637 /*
638  *  returns 1 if msg contains an AVP with the given name and value,
639  *  returns -1 otherwise
640  */
641 static int attr_equals(struct sip_msg* msg, char* p1, char* p2)
642 {
643         avp_ident_t avpid;
644         int_str value, avp_value;
645         avp_t* avp;
646         struct search_state st;
647
648         if (get_avp_id(&avpid, (fparam_t*)p1, msg) < 0) {
649                 return -1;
650         }
651
652         if (p2 && get_str_fparam(&value.s, msg, (fparam_t*)p2) < 0) {
653                 ERR("Error while obtaining attribute value from '%s'\n", ((fparam_t*)p2)->orig);
654                 return -1;
655         }
656
657         avp = search_avp(avpid, &avp_value, &st);
658         if (avp == 0) return -1;
659
660         if (!p2) return 1;
661
662         while (avp != 0) {
663                 if (avp->flags & AVP_VAL_STR) {
664                         if ((avp_value.s.len == value.s.len) &&
665                                         !memcmp(avp_value.s.s, value.s.s, avp_value.s.len)) {
666                                 return 1;
667                         }
668                 } else {
669                         if (avp_value.n == str2s(value.s.s, value.s.len, 0)) {
670                                 return 1;
671                         }
672                 }
673                 avp = search_next_avp(&st, &avp_value);
674         }
675
676         return -1;
677 }
678
679
680 static int attr_exists(struct sip_msg* msg, char* p1, char* p2)
681 {
682         return attr_equals(msg, p1, NULL);
683 }
684
685
686 static int xl_printstr(struct sip_msg* msg, xl_elog_t* format, char** res, int* res_len)
687 {
688         int len;
689
690         if (!format || !res) {
691                 LOG(L_ERR, "xl_printstr: Called with null format or res\n");
692                 return -1;
693         }
694
695         if (!xlbuf) {
696                 xlbuf = pkg_malloc((xlbuf_size+1)*sizeof(char));
697                 if (!xlbuf) {
698                         LOG(L_CRIT, "xl_printstr: No memory left for format buffer\n");
699                         return -1;
700                 }
701         }
702
703         len = xlbuf_size;
704         if (xl_print(msg, format, xlbuf, &len)<0) {
705                 LOG(L_ERR, "xl_printstr: Error while formatting result\n");
706                 return -1;
707         }
708
709         if ((xl_nul) && (xl_nul->len == len) && !strncmp(xl_nul->s, xlbuf, len)) {
710                 return 0;
711         }
712
713         *res = xlbuf;
714         if (res_len) {
715                 *res_len=len;
716         }
717         return len;
718 }
719
720
721 static int attr_equals_xl(struct sip_msg* msg, char* p1, char* format)
722 {
723         avp_ident_t* avpid;
724         avp_value_t avp_val;
725         struct search_state st;
726         str xl_val;
727         avp_t* avp;
728
729         avpid = &((fparam_t*)p1)->v.avp;
730
731         if (xl_printstr(msg, (xl_elog_t*) format, &xl_val.s, &xl_val.len) > 0) {
732                 for (avp = search_avp(*avpid, &avp_val, &st); avp; avp = search_next_avp(&st, &avp_val)) {
733                         if (avp->flags & AVP_VAL_STR) {
734                                 if ((avp_val.s.len == xl_val.len) &&
735                                                 !memcmp(avp_val.s.s, xl_val.s, avp_val.s.len)) return 1;
736                         } else {
737                                 if (avp_val.n == str2s(xl_val.s, xl_val.len, 0)) return 1;
738                         }
739                 }
740                 return -1;
741         }
742
743         ERR("avp_equals_xl:Error while expanding xl_format\n");
744         return -1;
745 }
746
747 /* get the pointer to the xl lib functions */
748 static int get_xl_functions(void)
749 {
750         if (!xl_print) {
751                 xl_print=(xl_print_log_f*)find_export("xprint", NO_SCRIPT, 0);
752
753                 if (!xl_print) {
754                         LOG(L_CRIT,"ERROR: cannot find \"xprint\", is module xprint loaded?\n");
755                         return -1;
756                 }
757         }
758
759         if (!xl_parse) {
760                 xl_parse=(xl_parse_format_f*)find_export("xparse", NO_SCRIPT, 0);
761
762                 if (!xl_parse) {
763                         LOG(L_CRIT,"ERROR: cannot find \"xparse\", is module xprint loaded?\n");
764                         return -1;
765                 }
766         }
767
768         if (!xl_free) {
769                 xl_free=(xl_elog_free_all_f*)find_export("xfree", NO_SCRIPT, 0);
770
771                 if (!xl_free) {
772                         LOG(L_CRIT,"ERROR: cannot find \"xfree\", is module xprint loaded?\n");
773                         return -1;
774                 }
775         }
776
777         if (!xl_nul) {
778                 xl_getnul=(xl_get_nulstr_f*)find_export("xnulstr", NO_SCRIPT, 0);
779                 if (xl_getnul) {
780                         xl_nul=xl_getnul();
781                 }
782
783                 if (!xl_nul){
784                         LOG(L_CRIT,"ERROR: cannot find \"xnulstr\", is module xprint loaded?\n");
785                         return -1;
786                 } else {
787                         LOG(L_INFO,"INFO: xprint null is \"%.*s\"\n", xl_nul->len, xl_nul->s);
788                 }
789
790         }
791
792         return 0;
793 }
794
795 /*
796  * Convert xl format string to xl format description
797  */
798 static int fixup_xl_1(void** param, int param_no)
799 {
800         xl_elog_t* model;
801
802         if (get_xl_functions()) return -1;
803
804         if (param_no == 1) {
805                 if(*param) {
806                         if(xl_parse((char*)(*param), &model)<0) {
807                                 LOG(L_ERR, "ERROR: xl_fixup: wrong format[%s]\n", (char*)(*param));
808                                 return E_UNSPEC;
809                         }
810
811                         *param = (void*)model;
812                         return 0;
813                 } else {
814                         LOG(L_ERR, "ERROR: xl_fixup: null format\n");
815                         return E_UNSPEC;
816                 }
817         }
818
819         return 0;
820 }
821
822 static int fixup_attr_1_xl_2(void** param, int param_no)
823 {
824         if (param_no == 1) {
825                 return avpid_fixup(param, 1);
826         } else  if (param_no == 2) {
827                 return fixup_xl_1(param, 1);
828         }
829         return 0;
830 }
831
832
833 static int xlset_attr(struct sip_msg* msg, char* p1, char* format)
834 {
835         avp_ident_t* avpid;
836         avp_value_t val;
837
838         avpid = &((fparam_t*)p1)->v.avp;
839
840         if (xl_printstr(msg, (xl_elog_t*)format, &val.s.s, &val.s.len) > 0) {
841                 if (add_avp(avpid->flags | AVP_VAL_STR, avpid->name, val)) {
842                         ERR("xlset_attr:Error adding new AVP\n");
843                         return -1;
844                 }
845                 return 1;
846         }
847
848         ERR("xlset_attr:Error while expanding xl_format\n");
849         return -1;
850 }
851
852 /*
853  * get the xl function pointers and fix up the AVP parameter
854  */
855 static int xlfix_attr_fixup(void** param, int param_no)
856 {
857         if (get_xl_functions()) return -1;
858
859         if (param_no == 1)
860                 return avpid_fixup(param, 1);
861
862         return 0;
863 }
864
865 /* fixes an attribute containing xl formatted string to pure string runtime */
866 static int xlfix_attr(struct sip_msg* msg, char* p1, char* p2)
867 {
868         avp_t* avp;
869         avp_ident_t* avpid;
870         avp_value_t val;
871         xl_elog_t* format=NULL;
872         int ret=-1;
873
874         avpid = &((fparam_t*)p1)->v.avp;
875
876         /* search the AVP */
877         avp = search_avp(*avpid, &val, 0);
878         if (!avp) {
879                 DBG("xlfix_attr: AVP does not exist\n");
880                 goto error;
881         }
882         if ((avp->flags & AVP_VAL_STR) == 0) {
883                 DBG("xlfix_attr: Not a string AVP\n");
884                 goto error;
885         }
886
887         /* parse the xl syntax -- AVP values are always zero-terminated */
888         if (xl_parse(val.s.s, &format)<0) {
889                 LOG(L_ERR, "ERROR: xlfix_attr: wrong format[%s]\n", val.s.s);
890                 goto error;
891         }
892
893         if (xl_printstr(msg, format, &val.s.s, &val.s.len) > 0) {
894                 /* we must delete and re-add the AVP again */
895                 destroy_avp(avp);
896                 if (add_avp(avpid->flags | AVP_VAL_STR, avpid->name, val)) {
897                         ERR("xlfix_attr:Error adding new AVP\n");
898                         goto error;
899                 }
900                 /* everything went OK */
901                 ret = 1;
902         }
903
904 error:
905         /* free the parsed xl expression */
906         if (format) xl_free(format);
907
908         return ret;
909 }
910
911
912 static int request_hf_helper(struct sip_msg* msg, str* hf, avp_ident_t* ident, struct lump* anchor, struct search_state* st, int front, int reverse, int reply)
913 {
914         struct lump* new_anchor;
915         static struct search_state state;
916         avp_t* avp;
917         char* s;
918         str fin_val;
919         int len, ret;
920         int_str val;
921         struct hdr_field* pos, *found = NULL;
922
923         if (!anchor && !reply) {
924
925                 if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
926                         LOG(L_ERR, "ERROR: request_hf_helper: Error while parsing message\n");
927                         return -1;
928                 }
929
930                 pos = msg->headers;
931                 while (pos && (pos->type != HDR_EOH_T)) {
932                         if ((hf->len == pos->name.len)
933                                         && (!strncasecmp(hf->s, pos->name.s, pos->name.len))) {
934                                 found = pos;
935                                 if (front) {
936                                         break;
937                                 }
938                         }
939                         pos = pos->next;
940                 }
941
942                 if (found) {
943                         if (front) {
944                                 len = found->name.s - msg->buf;
945                         } else {
946                                 len = found->name.s + found->len - msg->buf;
947                         }
948                 } else {
949                         len = msg->unparsed - msg->buf;
950                 }
951
952                 new_anchor = anchor_lump(msg, len, 0, 0);
953                 if (new_anchor == 0) {
954                         LOG(L_ERR, "ERROR: request_hf_helper: Can't get anchor\n");
955                         return -1;
956                 }
957         } else {
958                 new_anchor = anchor;
959         }
960
961         if (!st) {
962                 st = &state;
963                 avp = search_avp(*ident, NULL, st);
964                 ret = -1;
965         } else {
966                 avp = search_next_avp(st, NULL);
967                 ret = 1;
968         }
969
970         if (avp) {
971                 if (reverse && (request_hf_helper(msg, hf, ident, new_anchor, st, front, reverse, reply) == -1)) {
972                         return -1;
973                 }
974
975                 get_avp_val(avp, &val);
976                 if (avp->flags & AVP_VAL_STR) {
977                         fin_val = val.s;
978                 } else {
979                         fin_val.s = int2str(val.n, &fin_val.len);
980                 }
981
982                 len = hf->len + 2 + fin_val.len + 2;
983                 s = (char*)pkg_malloc(len);
984                 if (!s) {
985                         LOG(L_ERR, "ERROR: request_hf_helper: No memory left for data lump\n");
986                         return -1;
987                 }
988
989                 memcpy(s, hf->s, hf->len);
990                 memcpy(s + hf->len, ": ", 2 );
991                 memcpy(s + hf->len+2, fin_val.s, fin_val.len );
992                 memcpy(s + hf->len + 2 + fin_val.len, CRLF, CRLF_LEN);
993
994                 if (reply) {
995                         if (add_lump_rpl( msg, s, len, LUMP_RPL_HDR | LUMP_RPL_NODUP) == 0) {
996                                 LOG(L_ERR, "ERROR: request_hf_helper: Can't insert RPL lump\n");
997                                 pkg_free(s);
998                                 return -1;
999                         }
1000                 } else {
1001                         if ((front && (insert_new_lump_before(new_anchor, s, len, 0) == 0))
1002                                         || (!front && (insert_new_lump_after(new_anchor, s, len, 0) == 0))) {
1003                                 LOG(L_ERR, "ERROR: request_hf_helper: Can't insert lump\n");
1004                                 pkg_free(s);
1005                                 return -1;
1006                         }
1007                 }
1008                 if (!reverse && (request_hf_helper(msg, hf, ident, new_anchor, st, front, reverse, reply) == -1)) {
1009                         return -1;
1010                 }
1011                 return 1;
1012         };
1013
1014         /* in case of topmost call (st==NULL) return error */
1015         /* otherwise it's OK, no more AVPs found */
1016         return ret;
1017 }
1018
1019
1020 static int fixup_str_1_attr_2(void** param, int param_no)
1021 {
1022         if (param_no == 1) {
1023                 return fixup_var_str_12(param, 1);
1024         } else if (param_no == 2) {
1025                 return avpid_fixup(param, 1);
1026         }
1027         return 0;
1028 }
1029
1030
1031 static int insert_req(struct sip_msg* msg, char* p1, char* p2)
1032 {
1033         avp_ident_t ident, *avp;
1034         str hf;
1035
1036         if (get_str_fparam(&hf, msg, (fparam_t*)p1) < 0) {
1037                 ERR("Error while obtaining attribute value from '%s'\n", ((fparam_t*)p1)->orig);
1038                 return -1;
1039         }
1040
1041         if (p2) {
1042                 avp = &((fparam_t*)p2)->v.avp;
1043         } else {
1044                 ident.name.s = hf;
1045                 ident.flags = AVP_NAME_STR;
1046                 ident.index = 0;
1047                 avp = &ident;
1048         }
1049         return (request_hf_helper(msg, &hf, avp, NULL, NULL, 1, 0, 0));
1050 }
1051
1052
1053 static int append_req(struct sip_msg* msg, char* p1, char* p2)
1054 {
1055         avp_ident_t ident, *avp;
1056         str hf;
1057
1058         if (get_str_fparam(&hf, msg, (fparam_t*)p1) < 0) {
1059                 ERR("Error while obtaining attribute value from '%s'\n", ((fparam_t*)p1)->orig);
1060                 return -1;
1061         }
1062
1063         if (p2) {
1064                 avp = &((fparam_t*)p2)->v.avp;
1065         } else {
1066                 ident.name.s = hf;
1067                 ident.flags = AVP_NAME_STR;
1068                 ident.index = 0;
1069                 avp = &ident;
1070         }
1071         return (request_hf_helper(msg, &hf, avp, NULL, NULL, 0, 1, 0));
1072 }
1073
1074
1075 static int replace_req(struct sip_msg* msg, char* p1, char* p2)
1076 {
1077         struct hdr_field* pos;
1078         str hf;
1079
1080         if (get_str_fparam(&hf, msg, (fparam_t*)p1) < 0) {
1081                 ERR("Error while obtaining attribute value from '%s'\n", ((fparam_t*)p1)->orig);
1082                 return -1;
1083         }
1084
1085         if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
1086                 LOG(L_ERR, "ERROR: replace_req: Error while parsing message\n");
1087                 return -1;
1088         }
1089
1090         pos = msg->headers;
1091         while (pos && (pos->type != HDR_EOH_T)) {
1092                 if (hf.len == pos->name.len
1093                                 && !strncasecmp(hf.s, pos->name.s, pos->name.len)) {
1094                         if (del_lump(msg, pos->name.s - msg->buf, pos->len, 0) == 0) {
1095                                 LOG(L_ERR,"ERROR: Can't insert del lump\n");
1096                                 return -1;
1097                         }
1098                 }
1099                 pos = pos->next;
1100         }
1101         return append_req(msg, p1, p2);
1102 }
1103
1104
1105 static int append_reply(struct sip_msg* msg, char* p1, char* p2)
1106 {
1107         avp_ident_t ident, *avp;
1108         str hf;
1109
1110         if (get_str_fparam(&hf, msg, (fparam_t*)p1) < 0) {
1111                 ERR("Error while obtaining attribute value from '%s'\n", ((fparam_t*)p1)->orig);
1112                 return -1;
1113         }
1114
1115         if (p2) {
1116                 avp = &((fparam_t*)p2)->v.avp;
1117         } else {
1118                 ident.name.s = hf;
1119                 ident.flags = AVP_NAME_STR;
1120                 ident.index = 0;
1121                 avp = &ident;
1122         }
1123         return (request_hf_helper(msg, &hf, avp, NULL, NULL, 0, 1, 1));
1124 }
1125
1126
1127 static int set_destination(struct sip_msg* msg, str* dest)
1128 {
1129         name_addr_t nameaddr;
1130
1131         if (!parse_nameaddr(dest, &nameaddr)) {
1132                 return set_dst_uri(msg, &nameaddr.uri);
1133         } else {
1134                 /* it is just URI, pass it through */
1135                 return set_dst_uri(msg, dest);
1136         }
1137 }
1138
1139
1140 static int attr_destination(struct sip_msg* msg, char* p1, char* p2)
1141 {
1142         avp_t* avp;
1143         avp_value_t val;
1144
1145         if ((avp = search_avp(((fparam_t*)p1)->v.avp, &val, NULL))) {
1146                 if (avp->flags & AVP_VAL_STR) {
1147                         if (set_destination(msg, &val.s)) {
1148                                 LOG(L_ERR, "ERROR: avp_destination: Can't set dst uri\n");
1149                                 return -1;
1150                         };
1151                         /* dst_uri changed, so it makes sense to re-use the current uri
1152                          * for forking */
1153                         ruri_mark_new(); /* re-use uri for serial forking */
1154                         return 1;
1155                 } else {
1156                         ERR("avp_destination:AVP has numeric value\n");
1157                         return -1;
1158                 }
1159         }
1160         return -1;
1161 }
1162
1163
1164 static int xlset_destination(struct sip_msg* msg, char* format, char* p2)
1165 {
1166         str val;
1167
1168         if (xl_printstr(msg, (xl_elog_t*) format, &val.s, &val.len) > 0) {
1169                 DBG("Setting dest to: '%.*s'\n", val.len, val.s);
1170                 if (set_destination(msg, &val) == 0) {
1171                         return 1;
1172                 }
1173         }
1174
1175         return -1;
1176 }
1177
1178
1179 static int attr_hdr_body2attrs(struct sip_msg* m, char* header_, char* prefix_)
1180 {
1181         char name_buf[50];
1182         str *prefix = (str*) prefix_;
1183         struct hdr_name *header = (void*) header_;
1184         struct hdr_field *hf;
1185         str s, name, val;
1186         int_str name2, val2;
1187         int val_type, arr;
1188         if (header->kind == HDR_STR) {
1189                 if (parse_headers(m, HDR_EOH_F, 0) == -1) {
1190                         LOG(L_ERR, "ERROR: attr_hdr_body2attrs: Error while parsing message\n");
1191                         return -1;
1192                 }
1193
1194                 for (hf=m->headers; hf; hf=hf->next) {
1195                         if ( (header->name.s.len == hf->name.len)
1196                                         && (!strncasecmp(header->name.s.s, hf->name.s, hf->name.len)) ) {
1197                                 break;
1198                         }
1199                 }
1200         }
1201         else {
1202                 if (parse_headers(m, header->name.n, 0) == -1) {
1203                         LOG(L_ERR, "ERROR: attr_hdr_body2attrs: Error while parsing message\n");
1204                         return -1;
1205                 }
1206                 switch (header->name.n) {
1207                         //      HDR_xxx:
1208                         default:
1209                                 hf = NULL;
1210                                 break;
1211                 }
1212         }
1213         if (!hf || !hf->body.len)
1214                 return 1;
1215
1216         // parse body of hf
1217         s = hf->body;
1218         name_buf[0] = '\0';
1219         while (s.len) {
1220                 trim_leading(&s);
1221                 name.s = s.s;
1222                 while ( s.len &&
1223                                 ( (s.s[0] >= 'a' && s.s[0] <= 'z') ||
1224                                         (s.s[0] >= 'A' && s.s[0] <= 'Z') ||
1225                                         (s.s[0] >= '0' && s.s[0] <= '9') ||
1226                                         s.s[0] == '_' || s.s[0] == '-'
1227                                 ) ) {
1228                         s.s++;
1229                         s.len--;
1230                 }
1231                 if (s.s == name.s)
1232                         break;
1233                 name.len = s.s - name.s;
1234                 trim_leading(&s);
1235                 if (!s.len)
1236                         break;
1237                 if (s.s[0] == '=') {
1238                         s.s++;
1239                         s.len--;
1240                         arr = -1;
1241
1242                         while (s.len) {
1243                                 trim_leading(&s);
1244                                 val_type = 0;
1245                                 if (!s.len)
1246                                         break;
1247                                 if (s.s[0] == '"') {
1248                                         s.s++;
1249                                         s.len--;
1250                                         val.s = s.s;
1251
1252                                         s.s = q_memchr(s.s, '\"', s.len);
1253                                         if (!s.s)
1254                                                 break;
1255                                         val.len = s.s - val.s;
1256                                         val_type = AVP_VAL_STR;
1257                                         s.s++;
1258                                         s.len -= s.s - val.s;
1259                                 }
1260                                 else {
1261                                         int r;
1262                                         val.s = s.s;
1263                                         if (s.s[0] == '+' || s.s[0] == '-') {
1264                                                 s.s++;
1265                                                 s.len--;
1266                                         }
1267                                         val2.n = 0; r = 0;
1268                                         while (s.len) {
1269                                                 if (s.s[0] == header->field_delimiter || (header->array_delimiter && header->array_delimiter == s.s[0]))
1270                                                         goto token_end;
1271                                                 switch (s.s[0]) {
1272                                                         case ' ':
1273                                                         case '\t':
1274                                                         case '\n':
1275                                                         case '\r':
1276                                                                 goto token_end;
1277                                                 }
1278                                                 if (!val_type && s.s[0] >= '0' && s.s[0]<= '9') {
1279                                                         r++;
1280                                                         val2.n *= 10;
1281                                                         val2.n += s.s[0] - '0';
1282                                                         // overflow detection ???
1283                                                 }
1284                                                 else {
1285                                                         val_type = AVP_VAL_STR;
1286                                                 }
1287                                                 s.s++;
1288                                                 s.len--;
1289                                         }
1290 token_end:
1291                                         if (r == 0) val_type = AVP_VAL_STR;
1292                                         if (!val_type && val.s[0] == '-') {
1293                                                 val2.n = -val2.n;
1294                                         }
1295                                         val.len = s.s - val.s;
1296                                 }
1297                                 trim_leading(&s);
1298                                 if (arr >= 0 || (s.len && header->array_delimiter && header->array_delimiter == s.s[0])) {
1299                                         arr++;
1300                                         if (arr == 100)
1301                                                 LOG(L_ERR, "ERROR: avp index out of limit\n");
1302                                 }
1303                                 if (val.len && arr < 100) {
1304                                         if (prefix != NULL || arr >= 0) {
1305                                                 if ((prefix?prefix->len:0)+name.len+1+((arr>=0)?3/*#99*/:0) > sizeof(name_buf)) {
1306                                                         if (arr <= 0)
1307                                                                 LOG(L_ERR, "ERROR: avp name too long\n");
1308                                                         goto cont;
1309                                                 }
1310                                                 name2.s.len = 0;
1311                                                 name2.s.s = name_buf;
1312                                                 if (prefix != NULL) {
1313                                                         if (name_buf[0] == '\0') {
1314                                                                 memcpy(&name_buf[0], prefix->s, prefix->len);
1315                                                         }
1316                                                         name2.s.len += prefix->len;
1317                                                 }
1318                                                 if (arr <= 0) {
1319                                                         memcpy(&name_buf[name2.s.len], name.s, name.len);
1320                                                 }
1321                                                 name2.s.len += name.len;
1322                                                 if (arr >= 0) {
1323                                                         name_buf[name2.s.len] = '#';
1324                                                         name2.s.len++;
1325                                                         if (arr >= 10) {
1326                                                                 name_buf[name2.s.len] = '0'+ (arr / 10);
1327                                                                 name2.s.len++;
1328                                                         }
1329                                                         name_buf[name2.s.len] = '0'+ (arr % 10);
1330                                                         name2.s.len++;
1331                                                 }
1332                                         }
1333                                         else {
1334                                                 name2.s.s = name.s;
1335                                                 name2.s.len = name.len;
1336                                         }
1337                                         if ( ((val_type & AVP_VAL_STR) && (header->val_types & VAL_TYPE_STR)) ||
1338                                                         ((val_type & AVP_VAL_STR) == 0 && (header->val_types & VAL_TYPE_INT))  ) {
1339                                                 if (val_type) {
1340                                                         val2.s.s = val.s;
1341                                                         val2.s.len = val.len;
1342                                                         DBG("DEBUG: attr_hdr_body2attrs: adding avp '%.*s', sval: '%.*s'\n", name2.s.len, (char*) name2.s.s, val.len, val.s);
1343                                                 } else {
1344                                                         DBG("DEBUG: attr_hdr_body2attrs: adding avp '%.*s', ival: '%d'\n", name2.s.len, (char*) name2.s.s, val2.n);
1345                                                 }
1346                                                 if ( add_avp(AVP_NAME_STR | val_type, name2, val2)!=0) {
1347                                                         LOG(L_ERR, "ERROR: attr_hdr_body2attrs: add_avp failed\n");
1348                                                         return 1;
1349                                                 }
1350                                         }
1351                                 }
1352 cont:
1353                                 if (s.len && header->array_delimiter && header->array_delimiter == s.s[0]) {
1354                                         s.s++;
1355                                         s.len--;
1356                                 }
1357                                 else {
1358                                         break;
1359                                 }
1360                         };
1361                 }
1362                 if (s.len && s.s[0] == header->field_delimiter) {
1363                         s.s++;
1364                         s.len--;
1365                 }
1366                 else {
1367                         break;
1368                 }
1369         }
1370         return 1;
1371 }
1372
1373
1374 static int attr_hdr_body2attrs2(struct sip_msg* msg, char* header_, char* prefix_)
1375 {
1376         return attr_hdr_body2attrs(msg, header_, prefix_);
1377 }
1378
1379
1380 static int attr_hdr_body2attrs_fixup(void **param, int param_no)
1381 {
1382         char *c, *params;
1383         hdr_name_t *h;
1384         int n;
1385         str *s;
1386         if(param_no == 1) {
1387                 c = *param;
1388                 if(*c == '#') {
1389                         LOG(L_ERR, "attr_hdr_body2attrs_fixup: header name is not "
1390                                                 "valid '%s'\n", c);
1391                         return E_CFG;
1392                 } else {
1393                         params = strchr(c, PARAM_DELIM);
1394                         if(params)
1395                                 n = params - c;
1396                         else
1397                                 n = strlen(c);
1398                         if(n == 0) {
1399                                 LOG(L_ERR, "attr_hdr_body2attrs_fixup: header name is empty\n");
1400                                 return E_CFG;
1401                         }
1402                         h = pkg_malloc(sizeof(hdr_name_t) + n + 1);
1403                         if(!h) {
1404                                 LOG(L_ERR, "attr_hdr_body2attrs_fixup: out of memory\n");
1405                                 return E_OUT_OF_MEM;
1406                         }
1407                         h->kind = HDR_STR;
1408                         h->name.s.len = n;
1409                         h->name.s.s = (char *)h + sizeof(hdr_name_t);
1410                         memcpy(h->name.s.s, c, n + 1);
1411                 }
1412                 if(params) {
1413                         h->val_types = 0;
1414                         while(*params) {
1415                                 switch(*params) {
1416                                         case 'i':
1417                                         case 'I':
1418                                                 h->val_types = VAL_TYPE_INT;
1419                                                 break;
1420                                         case 's':
1421                                         case 'S':
1422                                                 h->val_types = VAL_TYPE_STR;
1423                                                 break;
1424                                         case PARAM_DELIM:
1425                                                 break;
1426                                         default:
1427                                                 LOG(L_ERR, "attr_hdr_body2attrs_fixup: bad field param "
1428                                                                 "modifier near '%s'\n",
1429                                                                 params);
1430                                                 return E_CFG;
1431                                 }
1432                                 params++;
1433                         }
1434                         if(!h->val_types) {
1435                                 LOG(L_ERR, "attr_hdr_body2attrs_fixup: no field param modifier "
1436                                                 "specified\n");
1437                                 return E_CFG;
1438                         }
1439                 } else {
1440                         h->val_types = VAL_TYPE_INT | VAL_TYPE_STR;
1441                 }
1442                 pkg_free(*param);
1443                 h->field_delimiter = ',';
1444                 h->array_delimiter = '\0';
1445
1446                 *param = h;
1447         } else if(param_no == 2) {
1448                 n = strlen(*param);
1449                 if(n == 0) {
1450                         s = NULL;
1451                 } else {
1452                         s = pkg_malloc(sizeof(str) + n + 1);
1453                         if(!s) {
1454                                 LOG(L_ERR, "attr_hdr_body2attrs_fixup: out of memory\n");
1455                                 return E_OUT_OF_MEM;
1456                         }
1457                         s->len = n;
1458                         s->s = (char *)s + sizeof(str);
1459                         memcpy(s->s, *param, n + 1);
1460                 }
1461                 pkg_free(*param);
1462                 *param = s;
1463         }
1464         return 0;
1465 }
1466
1467 static int attr_hdr_body2attrs2_fixup(void** param, int param_no)
1468 {
1469         struct hdr_name *h;
1470         int res = attr_hdr_body2attrs_fixup(param, param_no);
1471         if (res == 0 && param_no == 1) {
1472                 h = *param;
1473                 h->field_delimiter = ';';
1474                 h->array_delimiter = ',';
1475         }
1476         return res;
1477 }
1478
1479
1480 static int avpgroup_fixup(void** param, int param_no)
1481 {
1482         unsigned long flags;
1483         char* s;
1484
1485         if (param_no == 1) {
1486                 /* Determine the track and class of attributes to be loaded */
1487                 s = (char*)*param;
1488                 flags = 0;
1489                 if (*s != '$' || (strlen(s) != 3 && strlen(s) != 2)) {
1490                         ERR("Invalid parameter value, $xy expected\n");
1491                         return -1;
1492                 }
1493                 switch((s[1] << 8) + s[2]) {
1494                         case 0x4655: /* $fu */
1495                         case 0x6675:
1496                         case 0x4675:
1497                         case 0x6655:
1498                                 flags = AVP_TRACK_FROM | AVP_CLASS_USER;
1499                                 break;
1500
1501                         case 0x4652: /* $fr */
1502                         case 0x6672:
1503                         case 0x4672:
1504                         case 0x6652:
1505                                 flags = AVP_TRACK_FROM | AVP_CLASS_URI;
1506                                 break;
1507
1508                         case 0x5455: /* $tu */
1509                         case 0x7475:
1510                         case 0x5475:
1511                         case 0x7455:
1512                                 flags = AVP_TRACK_TO | AVP_CLASS_USER;
1513                                 break;
1514
1515                         case 0x5452: /* $tr */
1516                         case 0x7472:
1517                         case 0x5472:
1518                         case 0x7452:
1519                                 flags = AVP_TRACK_TO | AVP_CLASS_URI;
1520                                 break;
1521
1522                         case 0x4644: /* $fd */
1523                         case 0x6664:
1524                         case 0x4664:
1525                         case 0x6644:
1526                                 flags = AVP_TRACK_FROM | AVP_CLASS_DOMAIN;
1527                                 break;
1528
1529                         case 0x5444: /* $td */
1530                         case 0x7464:
1531                         case 0x5464:
1532                         case 0x7444:
1533                                 flags = AVP_TRACK_TO | AVP_CLASS_DOMAIN;
1534                                 break;
1535
1536                         case 0x6700: /* $td */
1537                         case 0x4700:
1538                                 flags = AVP_CLASS_GLOBAL;
1539                                 break;
1540
1541                         default:
1542                                 ERR("Invalid parameter value: '%s'\n", s);
1543                                 return -1;
1544                 }
1545
1546                 pkg_free(*param);
1547                 *param = (void*)flags;
1548                 return 1;
1549         }
1550         return 0;
1551 }
1552
1553
1554 static int select_attr_fixup(str* res, select_t* s, struct sip_msg* msg)
1555 {
1556         avp_ident_t *avp_ident;
1557
1558 #define SEL_PARAM_IDX   1
1559
1560         if (! msg) { /* fixup call */
1561                 str attr_name;
1562
1563                 if (s->params[SEL_PARAM_IDX].type != SEL_PARAM_STR) {
1564                         ERR("attribute name expected.\n");
1565                         return -1;
1566                 }
1567
1568                 attr_name = s->params[SEL_PARAM_IDX].v.s;
1569                 DEBUG("fix up for attribute '%.*s'\n", STR_FMT(&attr_name));
1570
1571                 if (! (avp_ident = pkg_malloc(sizeof(avp_ident_t)))) {
1572                         ERR("out of mem; requested: %d.\n", (int)sizeof(avp_ident_t));
1573                         return -1;
1574                 }
1575                 memset(avp_ident, 0, sizeof(avp_ident_t));
1576
1577                 /* skip leading `$' */
1578                 if ((1 < attr_name.len) && (attr_name.s[0] == '$')) {
1579                         attr_name.len --;
1580                         attr_name.s ++;
1581                 }
1582                 if (parse_avp_ident(&attr_name, avp_ident) < 0) {
1583                         ERR("failed to parse attribute name: `%.*s'.\n", STR_FMT(&attr_name));
1584                         pkg_free(avp_ident);
1585                         return -1;
1586                 }
1587                 s->params[SEL_PARAM_IDX].v.p = avp_ident;
1588                 s->params[SEL_PARAM_IDX].type = SEL_PARAM_PTR;
1589         } else { /* run time call */
1590                 avp_t *ret;
1591                 avp_value_t val;
1592
1593 #ifdef EXTRA_DEBUG
1594                 assert(s->params[SEL_PARAM_IDX].type == SEL_PARAM_PTR);
1595 #endif
1596                 avp_ident = s->params[SEL_PARAM_IDX].v.p;
1597                 ret = search_first_avp(avp_ident->flags, avp_ident->name, &val, NULL);
1598                 if (ret && ret->flags & AVP_VAL_STR)
1599                         *res = val.s;
1600         }
1601
1602         return 0;
1603
1604 #undef SEL_PARAM_IDX
1605 }
1606
1607 SELECT_F(select_any_nameaddr)
1608         ABSTRACT_F(select_attr);
1609
1610         select_row_t sel_declaration[] = {
1611                 { NULL, SEL_PARAM_STR, STR_STATIC_INIT("avp"), select_attr, SEL_PARAM_EXPECTED},
1612                 { NULL, SEL_PARAM_STR, STR_STATIC_INIT("attr"), select_attr, SEL_PARAM_EXPECTED},
1613                 { NULL, SEL_PARAM_STR, STR_STATIC_INIT("attribute"), select_attr, SEL_PARAM_EXPECTED},
1614                 { select_attr, SEL_PARAM_STR, STR_NULL, select_attr_fixup, FIXUP_CALL | CONSUME_NEXT_STR},
1615
1616                 { select_attr_fixup, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED},
1617
1618                 { NULL, SEL_PARAM_INT, STR_NULL, NULL, 0}
1619         };
1620
1621 static int mod_init()
1622 {
1623         DBG("%s - initializing\n", exports.name);
1624         return register_select_table(sel_declaration);
1625 }