avpops: converted to the new module interface
[sip-router] / src / modules / avpops / avpops.c
1 /*
2  * Copyright (C) 2004-2006 Voice Sistem SRL
3  *
4  * This file is part of Kamailio.
5  *
6  * Kamailio is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  */
21
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h> /* for regex */
27 #include <regex.h>
28
29 #include "../../core/mem/shm_mem.h"
30 #include "../../core/mem/mem.h"
31 #include "../../core/parser/parse_hname2.h"
32 #include "../../core/sr_module.h"
33 #include "../../core/str.h"
34 #include "../../core/dprint.h"
35 #include "../../core/error.h"
36 #include "../../core/ut.h"
37 #include "avpops_parse.h"
38 #include "avpops_impl.h"
39 #include "avpops_db.h"
40
41
42 MODULE_VERSION
43
44 /* modules param variables */
45 static str db_url          = {NULL, 0};  /* database url */
46 static str db_table        = {NULL, 0};  /* table */
47 static int use_domain      = 0;  /* if domain should be use for avp matching */
48 static str uuid_col        = str_init("uuid");
49 static str attribute_col   = str_init("attribute");
50 static str value_col       = str_init("value");
51 static str type_col        = str_init("type");
52 static str username_col    = str_init("username");
53 static str domain_col      = str_init("domain");
54 static str* db_columns[6] = {&uuid_col, &attribute_col, &value_col, &type_col, &username_col, &domain_col};
55
56
57 static int avpops_init(void);
58 static int avpops_child_init(int rank);
59
60 static int fixup_db_load_avp(void** param, int param_no);
61 static int fixup_db_delete_avp(void** param, int param_no);
62 static int fixup_db_store_avp(void** param, int param_no);
63 static int fixup_db_query_avp(void** param, int param_no);
64 static int fixup_delete_avp(void** param, int param_no);
65 static int fixup_copy_avp(void** param, int param_no);
66 static int fixup_pushto_avp(void** param, int param_no);
67 static int fixup_check_avp(void** param, int param_no);
68 static int fixup_op_avp(void** param, int param_no);
69 static int fixup_subst(void** param, int param_no);
70 static int fixup_is_avp_set(void** param, int param_no);
71
72 static int w_print_avps(struct sip_msg* msg, char* foo, char *bar);
73 static int w_dbload_avps(struct sip_msg* msg, char* source, char* param);
74 static int w_dbdelete_avps(struct sip_msg* msg, char* source, char* param);
75 static int w_dbstore_avps(struct sip_msg* msg, char* source, char* param);
76 static int w_dbquery1_avps(struct sip_msg* msg, char* query, char* param);
77 static int w_dbquery2_avps(struct sip_msg* msg, char* query, char* dest);
78 static int w_delete_avps(struct sip_msg* msg, char* param, char *foo);
79 static int w_copy_avps(struct sip_msg* msg, char* param, char *check);
80 static int w_pushto_avps(struct sip_msg* msg, char* destination, char *param);
81 static int w_check_avps(struct sip_msg* msg, char* param, char *check);
82 static int w_op_avps(struct sip_msg* msg, char* param, char *op);
83 static int w_subst(struct sip_msg* msg, char* src, char *subst);
84 static int w_is_avp_set(struct sip_msg* msg, char* param, char *foo);
85
86 /*! \brief
87  * Exported functions
88  */
89 static cmd_export_t cmds[] = {
90         {"avp_print", (cmd_function)w_print_avps, 0, 0, 0,
91                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
92         {"avp_db_load", (cmd_function)w_dbload_avps,  2, fixup_db_load_avp, 0,
93                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
94         {"avp_db_delete", (cmd_function)w_dbdelete_avps, 2, fixup_db_delete_avp, 0,
95                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
96         {"avp_db_store", (cmd_function)w_dbstore_avps,  2, fixup_db_store_avp, 0,
97                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
98         {"avp_db_query", (cmd_function)w_dbquery1_avps, 1, fixup_db_query_avp, 0,
99                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
100         {"avp_db_query", (cmd_function)w_dbquery2_avps, 2, fixup_db_query_avp, 0,
101                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
102         {"avp_delete", (cmd_function)w_delete_avps, 1, fixup_delete_avp, 0,
103                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
104         {"avp_copy",   (cmd_function)w_copy_avps,  2,  fixup_copy_avp, 0,
105                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
106         {"avp_pushto", (cmd_function)w_pushto_avps, 2, fixup_pushto_avp, 0,
107                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
108         {"avp_check",  (cmd_function)w_check_avps, 2, fixup_check_avp, 0,
109                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
110         {"avp_op",     (cmd_function)w_op_avps, 2, fixup_op_avp, 0,
111                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
112         {"avp_subst",  (cmd_function)w_subst,   2, fixup_subst, 0,
113                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
114         {"is_avp_set", (cmd_function)w_is_avp_set, 1, fixup_is_avp_set, 0,
115                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
116         {0, 0, 0, 0, 0, 0}
117 };
118
119
120 /*! \brief
121  * Exported parameters
122  */
123 static param_export_t params[] = {
124         {"db_url",            PARAM_STR, &db_url        },
125         {"avp_table",         PARAM_STR, &db_table      },
126         {"use_domain",        INT_PARAM, &use_domain      },
127         {"uuid_column",       PARAM_STR, &uuid_col      },
128         {"attribute_column",  PARAM_STR, &attribute_col },
129         {"value_column",      PARAM_STR, &value_col     },
130         {"type_column",       PARAM_STR, &type_col      },
131         {"username_column",   PARAM_STR, &username_col  },
132         {"domain_column",     PARAM_STR, &domain_col    },
133         {"db_scheme",         PARAM_STRING|USE_FUNC_PARAM, (void*)avp_add_db_scheme },
134         {0, 0, 0}
135 };
136
137
138 struct module_exports exports = {
139         "avpops",
140         DEFAULT_DLFLAGS,        /* dlopen flags */
141         cmds,                   /* Exported functions */
142         params,                 /* Exported parameters */
143         0,                      /* exported RPC methods */
144         0,                      /* exported pseudo-variables */
145         0,                      /* response handling function */
146         avpops_init,            /* Module initialization function */
147         avpops_child_init,      /* per-child init function */
148         0                       /* module destroy function */
149 };
150
151
152 static int avpops_init(void)
153 {
154         /* if DB_URL defined -> bind to a DB module */
155         if (db_url.s && db_url.len>0)
156         {
157                 /* check AVP_TABLE param */
158                 if (!db_table.s || db_table.len<=0)
159                 {
160                         LM_CRIT("\"AVP_DB\" present but \"AVP_TABLE\" found empty\n");
161                         goto error;
162                 }
163                 /* bind to the DB module */
164                 if (avpops_db_bind(&db_url)<0)
165                         goto error;
166         }
167
168         init_store_avps(db_columns);
169
170         return 0;
171 error:
172         return -1;
173 }
174
175
176 static int avpops_child_init(int rank)
177 {
178         /* init DB only if enabled */
179         if (db_url.s==0)
180                 return 0;
181         /* skip main process and TCP manager process */
182         if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
183                 return 0;
184         /* init DB connection */
185         return avpops_db_init(&db_url, &db_table, db_columns);
186 }
187
188
189 static int fixup_db_avp(void** param, int param_no, int allow_scheme)
190 {
191         struct fis_param *sp;
192         struct db_param  *dbp;
193         int flags;
194         str s;
195         char *p;
196
197         flags=0;
198         if (db_url.s==0)
199         {
200                 LM_ERR("you have to configure a db_url for using avp_db_xxx functions\n");
201                 return E_UNSPEC;
202         }
203
204         s.s = (char*)*param;
205         if (param_no==1)
206         {
207                 /* prepare the fis_param structure */
208                 sp = (struct fis_param*)pkg_malloc(sizeof(struct fis_param));
209                 if (sp==0) {
210                         LM_ERR("no more pkg mem!\n");
211                         return E_OUT_OF_MEM;
212                 }
213                 memset(sp, 0, sizeof(struct fis_param));
214
215                 if ( (p=strchr(s.s,'/'))!=0)
216                 {
217                         *(p++) = 0;
218                         /* check for extra flags/params */
219                         if (!strcasecmp("domain",p)) {
220                                 flags|=AVPOPS_FLAG_DOMAIN0;
221                         } else if (!strcasecmp("username",p)) {
222                                 flags|=AVPOPS_FLAG_USER0;
223                         } else if (!strcasecmp("uri",p)) {
224                                 flags|=AVPOPS_FLAG_URI0;
225                         } else if (!strcasecmp("uuid",p)) {
226                                 flags|=AVPOPS_FLAG_UUID0;
227                         } else {
228                                 LM_ERR("unknown flag <%s>\n",p);
229                                 pkg_free(sp);
230                                 return E_UNSPEC;
231                         }
232                 }
233                 if (*s.s!='$')
234                 {
235                         /* is a constant string -> use it as uuid*/
236                         sp->opd = ((flags==0)?AVPOPS_FLAG_UUID0:flags)|AVPOPS_VAL_STR;
237                         sp->u.s.s = (char*)pkg_malloc(strlen(s.s)+1);
238                         if (sp->u.s.s==0) {
239                                 LM_ERR("no more pkg mem!!\n");
240                                 pkg_free(sp);
241                                 return E_OUT_OF_MEM;
242                         }
243                         sp->u.s.len = strlen(s.s);
244                         strcpy(sp->u.s.s, s.s);
245                 } else {
246                         /* is a variable $xxxxx */
247                         s.len = strlen(s.s);
248                         sp->u.sval = pv_cache_get(&s);
249                         if (sp->u.sval==0 || sp->u.sval->type==PVT_NULL || sp->u.sval->type==PVT_EMPTY)
250                         {
251                                 LM_ERR("bad param 1; "
252                                         "expected : $pseudo-variable or int/str value\n");
253                                 pkg_free(sp);
254                                 return E_UNSPEC;
255                         }
256                         
257                         if(sp->u.sval->type==PVT_RURI || sp->u.sval->type==PVT_FROM
258                                         || sp->u.sval->type==PVT_TO || sp->u.sval->type==PVT_OURI)
259                         {
260                                 sp->opd = ((flags==0)?AVPOPS_FLAG_URI0:flags)|AVPOPS_VAL_PVAR;
261                         } else {
262                                 sp->opd = ((flags==0)?AVPOPS_FLAG_UUID0:flags)|AVPOPS_VAL_PVAR;
263                         }
264                 }
265                 *param=(void*)sp;
266         } else if (param_no==2) {
267                 /* compose the db_param structure */
268                 dbp = (struct db_param*)pkg_malloc(sizeof(struct db_param));
269                 if (dbp==0)
270                 {
271                         LM_ERR("no more pkg mem!!!\n");
272                         return E_OUT_OF_MEM;
273                 }
274                 memset( dbp, 0, sizeof(struct db_param));
275                 if ( parse_avp_db( s.s, dbp, allow_scheme)!=0 )
276                 {
277                         LM_ERR("parse failed\n");
278                         pkg_free(dbp);
279                         return E_UNSPEC;
280                 }
281                 *param=(void*)dbp;
282         }
283
284         return 0;
285 }
286
287
288 static int fixup_db_load_avp(void** param, int param_no)
289 {
290         return fixup_db_avp( param, param_no, 1/*allow scheme*/);
291 }
292
293 static int fixup_db_delete_avp(void** param, int param_no)
294 {
295         return fixup_db_avp( param, param_no, 0/*no scheme*/);
296 }
297
298
299 static int fixup_db_store_avp(void** param, int param_no)
300 {
301         return fixup_db_avp( param, param_no, 0/*no scheme*/);
302 }
303
304 static int fixup_db_query_avp(void** param, int param_no)
305 {
306         pv_elem_t *model = NULL;
307         pvname_list_t *anlist = NULL;
308         str s;
309
310         if (db_url.s==0)
311         {
312                 LM_ERR("you have to configure db_url for using avp_db_query function\n");
313                 return E_UNSPEC;
314         }
315
316         s.s = (char*)(*param);
317         if (param_no==1)
318         {
319                 if(s.s==NULL)
320                 {
321                         LM_ERR("null format in P%d\n",
322                                         param_no);
323                         return E_UNSPEC;
324                 }
325                 s.len = strlen(s.s);
326                 if(pv_parse_format(&s, &model)<0)
327                 {
328                         LM_ERR("wrong format[%s]\n", s.s);
329                         return E_UNSPEC;
330                 }
331                         
332                 *param = (void*)model;
333                 return 0;
334         } else if(param_no==2) {
335                 if(s.s==NULL)
336                 {
337                         LM_ERR("null format in P%d\n", param_no);
338                         return E_UNSPEC;
339                 }
340                                 s.len = strlen(s.s);
341
342                 anlist = parse_pvname_list(&s, PVT_AVP);
343                 if(anlist==NULL)
344                 {
345                         LM_ERR("bad format in P%d [%s]\n", param_no, s.s);
346                         return E_UNSPEC;
347                 }
348                 *param = (void*)anlist;
349                 return 0;
350         }
351
352         return 0;
353 }
354
355
356 static int fixup_delete_avp(void** param, int param_no)
357 {
358         struct fis_param *ap=NULL;
359         char *p;
360         char *s;
361         unsigned int flags;
362         str s0;
363
364         s = (char*)(*param);
365         if (param_no==1) {
366                 /* attribute name / alias */
367                 if ( (p=strchr(s,'/'))!=0 )
368                         *(p++)=0;
369                 
370                 if(*s=='$')
371                 {
372                         /* is variable */
373                         ap = avpops_parse_pvar(s);
374                         if (ap==0)
375                         {
376                                 LM_ERR("unable to get"
377                                         " pseudo-variable in param \n");
378                                 return E_UNSPEC;
379                         }
380                         if (ap->u.sval->type!=PVT_AVP)
381                         {
382                                 LM_ERR("bad param; expected : $avp(name)\n");
383                                 pkg_free(ap);
384                                 return E_UNSPEC;
385                         }
386                         ap->opd|=AVPOPS_VAL_PVAR;
387                         ap->type = AVPOPS_VAL_PVAR;
388                 } else {
389                         if(strlen(s)<1)
390                         {
391                                 LM_ERR("bad param - expected : $avp(name), *, s or i value\n");
392                                 return E_UNSPEC;
393                         }
394                         ap = (struct fis_param*)pkg_malloc(sizeof(struct fis_param));
395                         if (ap==0)
396                         {
397                                 LM_ERR(" no more pkg mem\n");
398                                 return E_OUT_OF_MEM;
399                         }
400                         memset(ap, 0, sizeof(struct fis_param));
401                         ap->opd|=AVPOPS_VAL_NONE;
402                         switch(*s) {
403                                 case 's': case 'S':
404                                         ap->opd = AVPOPS_VAL_NONE|AVPOPS_VAL_STR;
405                                 break;
406                                 case 'i': case 'I':
407                                         ap->opd = AVPOPS_VAL_NONE|AVPOPS_VAL_INT;
408                                 break;
409                                 case '*': case 'a': case 'A':
410                                         ap->opd = AVPOPS_VAL_NONE;
411                                 break;
412                                 default:
413                                         LM_ERR(" bad param - expected : *, s or i AVP flag\n");
414                                         pkg_free(ap);
415                                         return E_UNSPEC;
416                         }
417                         /* flags */
418                         flags = 0;
419                         if(*(s+1)!='\0')
420                         {
421                                 s0.s = s+1;
422                                 s0.len = strlen(s0.s);
423                                 if(str2int(&s0, &flags)!=0)
424                                 {
425                                         LM_ERR("bad avp flags\n");
426                                         pkg_free(ap);
427                                         return E_UNSPEC;
428                                 }
429                         }
430                         ap->type = AVPOPS_VAL_INT;
431                         ap->u.n = flags<<8;
432                 }
433
434                 /* flags */
435                 for( ; p&&*p ; p++ )
436                 {
437                         switch (*p)
438                         {
439                                 case 'g':
440                                 case 'G':
441                                         ap->ops|=AVPOPS_FLAG_ALL;
442                                         break;
443                                 default:
444                                         LM_ERR(" bad flag <%c>\n",*p);
445                                         if(ap!=NULL)
446                                                 pkg_free(ap);
447                                         return E_UNSPEC;
448                         }
449                 }
450                 /* force some flags: if no avp name is given, force "all" flag */
451                 if (ap->opd&AVPOPS_VAL_NONE)
452                         ap->ops |= AVPOPS_FLAG_ALL;
453
454                 *param=(void*)ap;
455         }
456
457         return 0;
458 }
459
460 static int fixup_copy_avp(void** param, int param_no)
461 {
462         struct fis_param *ap;
463         char *s;
464         char *p;
465
466         s = (char*)*param;
467         ap = 0;
468         p = 0;
469
470         if (param_no==2)
471         {
472                 /* avp / flags */
473                 if ( (p=strchr(s,'/'))!=0 )
474                         *(p++)=0;
475         }
476
477         ap = avpops_parse_pvar(s);
478         if (ap==0)
479         {
480                 LM_ERR("unable to get pseudo-variable in P%d\n", param_no);
481                 return E_OUT_OF_MEM;
482         }
483
484         /* attr name is mandatory */
485         if (ap->u.sval->type!=PVT_AVP)
486         {
487                 LM_ERR("you must specify only AVP as parameter\n");
488                 pkg_free(ap);
489                 return E_UNSPEC;
490         }
491
492         if (param_no==2)
493         {
494                 /* flags */
495                 for( ; p&&*p ; p++ )
496                 {
497                         switch (*p) {
498                                 case 'g':
499                                 case 'G':
500                                         ap->ops|=AVPOPS_FLAG_ALL;
501                                         break;
502                                 case 'd':
503                                 case 'D':
504                                         ap->ops|=AVPOPS_FLAG_DELETE;
505                                         break;
506                                 case 'n':
507                                 case 'N':
508                                         ap->ops|=AVPOPS_FLAG_CASTN;
509                                         break;
510                                 case 's':
511                                 case 'S':
512                                         ap->ops|=AVPOPS_FLAG_CASTS;
513                                         break;
514                                 default:
515                                         LM_ERR("bad flag <%c>\n",*p);
516                                         pkg_free(ap);
517                                         return E_UNSPEC;
518                         }
519                 }
520         }
521
522         *param=(void*)ap;
523         return 0;
524 }
525
526 static int fixup_pushto_avp(void** param, int param_no)
527 {
528         struct fis_param *ap;
529         char *s;
530         char *p;
531
532         s = (char*)*param;
533         ap = 0;
534
535         if (param_no==1)
536         {
537                 if ( *s!='$')
538                 {
539                         LM_ERR("bad param 1; expected : $ru $du ...\n");
540                         return E_UNSPEC;
541                 }
542                 /* compose the param structure */
543
544                 if ( (p=strchr(s,'/'))!=0 )
545                         *(p++)=0;
546                 ap = avpops_parse_pvar(s);
547                 if (ap==0)
548                 {
549                         LM_ERR("unable to get pseudo-variable in param 1\n");
550                         return E_OUT_OF_MEM;
551                 }
552
553                 switch(ap->u.sval->type) {
554                         case PVT_RURI:
555                                 ap->opd = AVPOPS_VAL_NONE|AVPOPS_USE_RURI;
556                                 if ( p && !(
557                                         (!strcasecmp("username",p)
558                                                         && (ap->opd|=AVPOPS_FLAG_USER0)) ||
559                                         (!strcasecmp("domain",p)
560                                                         && (ap->opd|=AVPOPS_FLAG_DOMAIN0)) ))
561                                 {
562                                         LM_ERR("unknown ruri flag \"%s\"!\n",p);
563                                         pkg_free(ap);
564                                         return E_UNSPEC;
565                                 }
566                         break;
567                         case PVT_DSTURI:
568                                 if ( p!=0 )
569                                 {
570                                         LM_ERR("unknown duri flag \"%s\"!\n",p);
571                                         pkg_free(ap);
572                                         return E_UNSPEC;
573                                 }
574                                 ap->opd = AVPOPS_VAL_NONE|AVPOPS_USE_DURI;
575                         break;
576                         case PVT_HDR:
577                                 /* what's the hdr destination ? request or reply? */
578                                 LM_ERR("push to header  is obsoleted - use append_hf() "
579                                                 "or append_to_reply() from textops module!\n");
580                                 pkg_free(ap);
581                                 return E_UNSPEC;
582                         break;
583                         case PVT_BRANCH:
584                                 if ( p!=0 )
585                                 {
586                                         LM_ERR("unknown branch flag \"%s\"!\n",p);
587                                         pkg_free(ap);
588                                         return E_UNSPEC;
589                                 }
590                                 ap->opd = AVPOPS_VAL_NONE|AVPOPS_USE_BRANCH;
591                         break;
592                         default:
593                                 LM_ERR("unsupported destination \"%s\"; "
594                                                 "expected $ru,$du,$br\n",s);
595                                 pkg_free(ap);
596                                 return E_UNSPEC;
597                 }
598         } else if (param_no==2) {
599                 /* attribute name*/
600                 if ( *s!='$')
601                 {
602                         LM_ERR("bad param 2; expected: $pseudo-variable ...\n");
603                         return E_UNSPEC;
604                 }
605                 /* compose the param structure */
606
607                 if ( (p=strchr(s,'/'))!=0 )
608                         *(p++)=0;
609                 ap = avpops_parse_pvar(s);
610                 if (ap==0)
611                 {
612                         LM_ERR("unable to get pseudo-variable in param 2\n");
613                         return E_OUT_OF_MEM;
614                 }
615                 if (ap->u.sval->type==PVT_NULL)
616                 {
617                         LM_ERR("bad param 2; expected : $pseudo-variable ...\n");
618                         pkg_free(ap);
619                         return E_UNSPEC;
620                 }
621                 ap->opd |= AVPOPS_VAL_PVAR;
622
623                 /* flags */
624                 for( ; p&&*p ; p++ )
625                 {
626                         switch (*p) {
627                                 case 'g':
628                                 case 'G':
629                                         ap->ops|=AVPOPS_FLAG_ALL;
630                                         break;
631                                 default:
632                                         LM_ERR("bad flag <%c>\n",*p);
633                                         pkg_free(ap);
634                                         return E_UNSPEC;
635                         }
636                 }
637         }
638
639         *param=(void*)ap;
640         return 0;
641 }
642
643 static int fixup_check_avp(void** param, int param_no)
644 {
645         struct fis_param *ap;
646         regex_t* re;
647         char *s;
648
649         s = (char*)*param;
650         ap = 0;
651
652         if (param_no==1)
653         {
654                 ap = avpops_parse_pvar(s);
655                 if (ap==0)
656                 {
657                         LM_ERR("unable to get pseudo-variable in param 1\n");
658                         return E_OUT_OF_MEM;
659                 }
660                 /* attr name is mandatory */
661                 if (ap->u.sval->type==PVT_NULL)
662                 {
663                         LM_ERR("null pseudo-variable in param 1\n");
664                         pkg_free(ap);
665                         return E_UNSPEC;
666                 }
667         } else if (param_no==2) {
668                 if ( (ap=parse_check_value(s))==0 )
669                 {
670                         LM_ERR("failed to parse checked value \n");
671                         return E_UNSPEC;
672                 }
673                 /* if REGEXP op -> compile the expresion */
674                 if (ap->ops&AVPOPS_OP_RE)
675                 {
676                         if ( (ap->opd&AVPOPS_VAL_STR)!=0 )
677                         {
678                                 re = (regex_t*) pkg_malloc(sizeof(regex_t));
679                                 if (re==0)
680                                 {
681                                         LM_ERR("no more pkg mem\n");
682                                         pkg_free(ap);
683                                         return E_OUT_OF_MEM;
684                                 }
685                                 LM_DBG("compiling regexp <%.*s>\n", ap->u.s.len, ap->u.s.s);
686                                 if (regcomp(re, ap->u.s.s,REG_EXTENDED|REG_ICASE|REG_NEWLINE))
687                                 {
688                                         LM_ERR("bad re <%.*s>\n", ap->u.s.len, ap->u.s.s);
689                                         pkg_free(re);
690                                         pkg_free(ap);
691                                         return E_BAD_RE;
692                                 }
693                                 ap->u.s.s = (char*)re;
694                         }
695                 } else if (ap->ops&AVPOPS_OP_FM) {
696                         if ( !( ap->opd&AVPOPS_VAL_PVAR ||
697                         (!(ap->opd&AVPOPS_VAL_PVAR) && ap->opd&AVPOPS_VAL_STR) ) )
698                         {
699                                 LM_ERR("fast_match operation requires string value or "
700                                                 "avp name/alias (%d/%d)\n",     ap->opd, ap->ops);
701                                 pkg_free(ap);
702                                 return E_UNSPEC;
703                         }
704                 }
705         }
706
707         *param=(void*)ap;
708         return 0;
709 }
710
711 static int fixup_subst(void** param, int param_no)
712 {
713         struct subst_expr* se;
714         str subst;
715         struct fis_param *ap;
716         struct fis_param **av;
717         char *s;
718         char *p;
719         
720         if (param_no==1) {
721                 s = (char*)*param;
722                 ap = 0;
723                 p = 0;
724                 av = (struct fis_param**)pkg_malloc(2*sizeof(struct fis_param*));
725                 if(av==NULL)
726                 {
727                         LM_ERR("no more pkg memory\n");
728                         return E_UNSPEC;                        
729                 }
730                 memset(av, 0, 2*sizeof(struct fis_param*));
731
732                 /* avp src / avp dst /flags */
733                 if ( (p=strchr(s,'/'))!=0 )
734                         *(p++)=0;
735                 ap = avpops_parse_pvar(s);
736                 if (ap==0)
737                 {
738                         LM_ERR("unable to get pseudo-variable in param 2 [%s]\n", s);
739                         pkg_free(av);
740                         return E_OUT_OF_MEM;
741                 }
742                 if (ap->u.sval->type!=PVT_AVP)
743                 {
744                         LM_ERR("bad attribute name <%s>\n", (char*)*param);
745                         pkg_free(av);
746                         pkg_free(ap);
747                         return E_UNSPEC;
748                 }
749                 /* attr name is mandatory */
750                 if (ap->opd&AVPOPS_VAL_NONE)
751                 {
752                         LM_ERR("you must specify a name for the AVP\n");
753                         pkg_free(av);
754                         pkg_free(ap);
755                         return E_UNSPEC;
756                 }
757                 av[0] = ap;
758                 if(p==0 || *p=='\0')
759                 {
760                         *param=(void*)av;
761                         return 0;
762                 }
763                 ap = 0;
764                 
765                 /* dst || flags */
766                 s = p;
767                 if(*s==PV_MARKER)
768                 {
769                         if ( (p=strchr(s,'/'))!=0 )
770                                 *(p++)=0;
771                         if(p==0 || (p!=0 && p-s>1))
772                         {
773                                 ap = avpops_parse_pvar(s);
774                                 if (ap==0)
775                                 {
776                                         LM_ERR("unable to get pseudo-variable in param 2 [%s]\n",s);
777                                         pkg_free(av);
778                                         return E_OUT_OF_MEM;
779                                 }
780                         
781                                 if (ap->u.sval->type!=PVT_AVP)
782                                 {
783                                         LM_ERR("bad attribute name <%s>!\n", s);
784                                         pkg_free(av);
785                                         pkg_free(ap);
786                                         return E_UNSPEC;
787                                 }
788                                 /* attr name is mandatory */
789                                 if (ap->opd&AVPOPS_VAL_NONE)
790                                 {
791                                         LM_ERR("you must specify a name for the AVP!\n");
792                                         pkg_free(av);
793                                         pkg_free(ap);
794                                         return E_UNSPEC;
795                                 }
796                                 av[1] = ap;
797                         }
798                         if(p==0 || *p=='\0')
799                         {
800                                 *param=(void*)av;
801                                 return 0;
802                         }
803                 }
804                 
805                 /* flags */
806                 for( ; p&&*p ; p++ )
807                 {
808                         switch (*p) {
809                                 case 'g':
810                                 case 'G':
811                                         av[0]->ops|=AVPOPS_FLAG_ALL;
812                                         break;
813                                 case 'd':
814                                 case 'D':
815                                         av[0]->ops|=AVPOPS_FLAG_DELETE;
816                                         break;
817                                 default:
818                                         LM_ERR("bad flag <%c>\n",*p);
819                                         pkg_free(av[0]);
820                                         if(av[1]) pkg_free(av[1]);
821                                         pkg_free(av);
822                                         return E_UNSPEC;
823                         }
824                 }
825                 *param=(void*)av;
826         } else if (param_no==2) {
827                 LM_DBG("%s fixing %s\n", exports.name, (char*)(*param));
828                 subst.s=*param;
829                 subst.len=strlen(*param);
830                 se=subst_parser(&subst);
831                 if (se==0){
832                         LM_ERR("%s: bad subst re %s\n",exports.name, (char*)*param);
833                         return E_BAD_RE;
834                 }
835                 /* don't free string -- needed for specifiers */
836                 /* pkg_free(*param); */
837                 /* replace it with the compiled subst. re */
838                 *param=se;
839         }
840
841         return 0;
842 }
843
844 static int fixup_op_avp(void** param, int param_no)
845 {
846         struct fis_param *ap;
847         struct fis_param **av;
848         char *s;
849         char *p;
850
851         s = (char*)*param;
852         ap = 0;
853
854         if (param_no==1)
855         {
856                 av = (struct fis_param**)pkg_malloc(2*sizeof(struct fis_param*));
857                 if(av==NULL)
858                 {
859                         LM_ERR("no more pkg memory\n");
860                         return E_UNSPEC;                        
861                 }
862                 memset(av, 0, 2*sizeof(struct fis_param*));
863                 /* avp src / avp dst */
864                 if ( (p=strchr(s,'/'))!=0 )
865                         *(p++)=0;
866
867                 av[0] = avpops_parse_pvar(s);
868                 if (av[0]==0)
869                 {
870                         LM_ERR("unable to get pseudo-variable in param 1\n");
871                         pkg_free(av);
872                         return E_OUT_OF_MEM;
873                 }
874                 if (av[0]->u.sval->type!=PVT_AVP)
875                 {
876                         LM_ERR("bad attribute name <%s>\n", (char*)*param);
877                         pkg_free(av[0]);
878                         pkg_free(av);
879                         return E_UNSPEC;
880                 }
881                 if(p==0 || *p=='\0')
882                 {
883                         *param=(void*)av;
884                         return 0;
885                 }
886                 
887                 s = p;
888                 ap = avpops_parse_pvar(s);
889                 if (ap==0)
890                 {
891                         LM_ERR("unable to get pseudo-variable in param 1 (2)\n");
892                         pkg_free(av[0]);
893                         pkg_free(av);
894                         return E_OUT_OF_MEM;
895                 }
896                 if (ap->u.sval->type!=PVT_AVP)
897                 {
898                         LM_ERR("bad attribute name/alias <%s>!\n", s);
899                         pkg_free(ap);
900                         pkg_free(av[0]);
901                         pkg_free(av);
902                         return E_UNSPEC;
903                 }
904                 av[1] = ap;
905                 *param=(void*)av;
906                 return 0;
907         } else if (param_no==2) {
908                 if ( (ap=parse_op_value(s))==0 )
909                 {
910                         LM_ERR("failed to parse the value \n");
911                         return E_UNSPEC;
912                 }
913                 /* only integer values or avps */
914                 if ( (ap->opd&AVPOPS_VAL_STR)!=0 && (ap->opd&AVPOPS_VAL_PVAR)==0)
915                 {
916                         LM_ERR("operations requires integer values\n");
917                         pkg_free(ap);
918                         return E_UNSPEC;
919                 }
920                 *param=(void*)ap;
921                 return 0;
922         }
923         return -1;
924 }
925
926 static int fixup_is_avp_set(void** param, int param_no)
927 {
928         struct fis_param *ap;
929         char *p;
930         char *s;
931         
932         s = (char*)(*param);
933         if (param_no==1) {
934                 /* attribute name | alias / flags */
935                 if ( (p=strchr(s,'/'))!=0 )
936                         *(p++)=0;
937                 
938                 ap = avpops_parse_pvar(s);
939                 if (ap==0)
940                 {
941                         LM_ERR("unable to get pseudo-variable in param\n");
942                         return E_OUT_OF_MEM;
943                 }
944                 
945                 if (ap->u.sval->type!=PVT_AVP)
946                 {
947                         LM_ERR("bad attribute name <%s>\n", (char*)*param);
948                         pkg_free(ap);
949                         return E_UNSPEC;
950                 }
951                 if(p==0 || *p=='\0')
952                         ap->ops|=AVPOPS_FLAG_ALL;
953
954                 /* flags */
955                 for( ; p&&*p ; p++ )
956                 {
957                         switch (*p) {
958                                 case 'e':
959                                 case 'E':
960                                         ap->ops|=AVPOPS_FLAG_EMPTY;
961                                         break;
962                                 case 'n':
963                                 case 'N':
964                                         if(ap->ops&AVPOPS_FLAG_CASTS)
965                                         {
966                                                 LM_ERR("invalid flag combination <%c> and 's|S'\n",*p);
967                                                 pkg_free(ap);
968                                                 return E_UNSPEC;
969                                         }
970                                         ap->ops|=AVPOPS_FLAG_CASTN;
971                                         break;
972                                 case 's':
973                                 case 'S':
974                                         if(ap->ops&AVPOPS_FLAG_CASTN)
975                                         {
976                                                 LM_ERR("invalid flag combination <%c> and 'n|N'\n",*p);
977                                                 pkg_free(ap);
978                                                 return E_UNSPEC;
979                                         }
980                                         ap->ops|=AVPOPS_FLAG_CASTS;
981                                         break;
982                                 default:
983                                         LM_ERR("bad flag <%c>\n",*p);
984                                         pkg_free(ap);
985                                         return E_UNSPEC;
986                         }
987                 }
988                 
989                 *param=(void*)ap;
990         }
991
992         return 0;
993 }
994
995 static int w_dbload_avps(struct sip_msg* msg, char* source, char* param)
996 {
997         return ops_dbload_avps ( msg, (struct fis_param*)source,
998                                                                 (struct db_param*)param, use_domain);
999 }
1000
1001 static int w_dbdelete_avps(struct sip_msg* msg, char* source, char* param)
1002 {
1003         return ops_dbdelete_avps ( msg, (struct fis_param*)source,
1004                                                                 (struct db_param*)param, use_domain);
1005 }
1006
1007 static int w_dbstore_avps(struct sip_msg* msg, char* source, char* param)
1008 {
1009         return ops_dbstore_avps ( msg, (struct fis_param*)source,
1010                                                                 (struct db_param*)param, use_domain);
1011 }
1012
1013 static int w_dbquery1_avps(struct sip_msg* msg, char* query, char* param)
1014 {
1015         return ops_dbquery_avps ( msg, (pv_elem_t*)query, 0);
1016 }
1017
1018 static int w_dbquery2_avps(struct sip_msg* msg, char* query, char* dest)
1019 {
1020         return ops_dbquery_avps ( msg, (pv_elem_t*)query, (pvname_list_t*)dest);
1021 }
1022
1023 static int w_delete_avps(struct sip_msg* msg, char* param, char* foo)
1024 {
1025         return ops_delete_avp ( msg, (struct fis_param*)param);
1026 }
1027
1028 static int w_copy_avps(struct sip_msg* msg, char* name1, char *name2)
1029 {
1030         return ops_copy_avp ( msg, (struct fis_param*)name1,
1031                                                                 (struct fis_param*)name2);
1032 }
1033
1034 static int w_pushto_avps(struct sip_msg* msg, char* destination, char *param)
1035 {
1036         return ops_pushto_avp ( msg, (struct fis_param*)destination,
1037                                                                 (struct fis_param*)param);
1038 }
1039
1040 static int w_check_avps(struct sip_msg* msg, char* param, char *check)
1041 {
1042         return ops_check_avp ( msg, (struct fis_param*)param,
1043                                                                 (struct fis_param*)check);
1044 }
1045
1046 static int w_op_avps(struct sip_msg* msg, char* param, char *op)
1047 {
1048         return ops_op_avp ( msg, (struct fis_param**)param,
1049                                                                 (struct fis_param*)op);
1050 }
1051
1052 static int w_subst(struct sip_msg* msg, char* src, char *subst)
1053 {
1054         return ops_subst(msg, (struct fis_param**)src, (struct subst_expr*)subst);
1055 }
1056
1057 static int w_is_avp_set(struct sip_msg* msg, char* param, char *op)
1058 {
1059         return ops_is_avp_set(msg, (struct fis_param*)param);
1060 }
1061
1062 static int w_print_avps(struct sip_msg* msg, char* foo, char *bar)
1063 {
1064         return ops_print_avp();
1065 }
1066