317abb600289b68c869956b77788ebb31080c485
[sip-router] / src / modules / textopsx / textopsx.c
1 /**
2  *
3  * Copyright (C) 2001-2003 FhG Fokus
4  *
5  * This file is part of Kamailio, a free SIP server.
6  *
7  * ser is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version
11  *
12  * For a license to use the ser software under conditions
13  * other than those described here, or to purchase support for this
14  * software, please contact iptel.org by e-mail at the following addresses:
15  *    info@iptel.org
16  *
17  * ser is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
25  */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fnmatch.h>
31
32 #include "../../core/sr_module.h"
33 #include "../../core/dprint.h"
34 #include "../../core/data_lump.h"
35 #include "../../core/msg_translator.h"
36 #include "../../core/tcp_options.h"
37 #include "../../core/mod_fix.h"
38 #include "../../core/parser/parse_hname2.h"
39 #include "../../core/select.h"
40 #include "../../core/select_buf.h"
41 #include "../../core/kemi.h"
42
43
44 #include "api.h"
45
46 MODULE_VERSION
47
48 static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2);
49
50 static int change_reply_status_f(sip_msg_t *, char *, char *);
51 static int change_reply_status_fixup(void **param, int param_no);
52
53 static int w_keep_hf_f(sip_msg_t *, char *, char *);
54
55 static int w_fnmatch2_f(sip_msg_t *, char *, char *);
56 static int w_fnmatch3_f(sip_msg_t *, char *, char *, char *);
57 static int fixup_fnmatch(void **param, int param_no);
58
59 static int w_remove_body_f(struct sip_msg *, char *, char *);
60
61 static int incexc_hf_value_f(struct sip_msg *msg, char *, char *);
62 static int include_hf_value_fixup(void **, int);
63 static int exclude_hf_value_fixup(void **, int);
64 static int hf_value_exists_fixup(void **, int);
65
66 static int insupddel_hf_value_f(struct sip_msg *msg, char *_hname, char *_val);
67 static int append_hf_value_fixup(void **param, int param_no);
68 static int insert_hf_value_fixup(void **param, int param_no);
69 static int remove_hf_value_fixup(void **param, int param_no);
70 static int assign_hf_value_fixup(void **param, int param_no);
71 static int remove_hf_value2_fixup(void **param, int param_no);
72 static int assign_hf_value2_fixup(void **param, int param_no);
73
74 static int bind_textopsx(textopsx_api_t *tob);
75
76 static int mod_init(void);
77
78 extern select_row_t sel_declaration[];
79
80 /* cfg functions */
81 /* clag-format off */
82 static cmd_export_t cmds[] = {
83         {"msg_apply_changes", (cmd_function)msg_apply_changes_f, 0, 0, 0,
84                         REQUEST_ROUTE | ONREPLY_ROUTE},
85         {"change_reply_status", change_reply_status_f, 2,
86                         change_reply_status_fixup, 0, ONREPLY_ROUTE},
87         {"remove_body", (cmd_function)w_remove_body_f, 0, 0, 0, ANY_ROUTE},
88         {"keep_hf", (cmd_function)w_keep_hf_f, 0, fixup_regexp_null, 0, ANY_ROUTE},
89         {"keep_hf", (cmd_function)w_keep_hf_f, 1, fixup_regexp_null, 0, ANY_ROUTE},
90         {"fnmatch", (cmd_function)w_fnmatch2_f, 2, fixup_fnmatch, 0, ANY_ROUTE},
91         {"fnmatch", (cmd_function)w_fnmatch3_f, 3, fixup_fnmatch, 0, ANY_ROUTE},
92         {"append_hf_value", insupddel_hf_value_f, 2, append_hf_value_fixup, 0,
93                         REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
94         {"insert_hf_value", insupddel_hf_value_f, 2, insert_hf_value_fixup, 0,
95                         REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
96         {"remove_hf_value", insupddel_hf_value_f, 1, remove_hf_value_fixup, 0,
97                         REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
98         {"assign_hf_value", insupddel_hf_value_f, 2, assign_hf_value_fixup, 0,
99                         REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
100         {"remove_hf_value2", insupddel_hf_value_f, 1, remove_hf_value2_fixup, 0,
101                         REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
102         {"assign_hf_value2", insupddel_hf_value_f, 2, assign_hf_value2_fixup, 0,
103                         REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
104         {"include_hf_value", incexc_hf_value_f, 2, include_hf_value_fixup, 0,
105                         REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
106         {"exclude_hf_value", incexc_hf_value_f, 2, exclude_hf_value_fixup, 0,
107                         REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
108         {"hf_value_exists", incexc_hf_value_f, 2, hf_value_exists_fixup, 0,
109                         REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
110
111         {"bind_textopsx", (cmd_function)bind_textopsx, 1, 0, 0, ANY_ROUTE},
112
113         {0, 0, 0, 0, 0, 0}
114 };
115
116 /* module exports structure */
117 struct module_exports exports = {
118         "textopsx",             /* module name */
119         DEFAULT_DLFLAGS,        /* dlopen flags */
120         cmds,                   /* exported cfg functions */
121         0,                              /* exported cfg parameters */
122         0,                              /* exported RPC methods */
123         0,                              /* exported pseudo-variables */
124         0,                              /* response handling function */
125         mod_init,               /* module init function */
126         0,                              /* per-child init function */
127         0,                              /* destroy function */
128 };
129 /* clag-format on */
130
131
132 /**
133  * init module function
134  */
135 static int mod_init(void)
136 {
137 #ifdef USE_TCP
138         tcp_set_clone_rcvbuf(1);
139 #endif
140         register_select_table(sel_declaration);
141         return 0;
142 }
143
144 /**
145  *
146  */
147 static int ki_msg_update_buffer(sip_msg_t *msg, str *obuf)
148 {
149         if(obuf==NULL || obuf->s==NULL || obuf->len<=0) {
150                 LM_ERR("invalid buffer parameter\n");
151                 return -1;
152         }
153
154         if(obuf->len >= BUF_SIZE) {
155                 LM_ERR("new buffer is too large (%d)\n", obuf->len);
156                 return -1;
157         }
158
159         return sip_msg_update_buffer(msg, obuf);
160 }
161
162 /**
163  *
164  */
165 static int ki_msg_set_buffer(sip_msg_t *msg, str *obuf)
166 {
167         if(msg->first_line.type != SIP_REPLY && get_route_type() != REQUEST_ROUTE) {
168                 LM_ERR("invalid usage - not in request route or a reply\n");
169                 return -1;
170         }
171
172         return ki_msg_update_buffer(msg, obuf);
173 }
174
175 /**
176  *
177  */
178 static int ki_msg_apply_changes(sip_msg_t *msg)
179 {
180         return sip_msg_apply_changes(msg);
181 }
182
183 /**
184  *
185  */
186 static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2)
187 {
188         return sip_msg_apply_changes(msg);
189 }
190
191 /**
192  *
193  */
194 static int change_reply_status_fixup(void **param, int param_no)
195 {
196         if(param_no == 1) {
197                 return fixup_var_int_12(param, param_no);
198         } else if(param_no == 2)
199                 return fixup_var_pve_str_12(param, param_no);
200         else
201                 return 0;
202 }
203
204 /**
205  *
206  */
207 static int ki_change_reply_status(sip_msg_t *msg, int code, str *reason)
208 {
209         struct lump *l;
210         char *ch;
211
212         if(reason==NULL || (reason->len<=0)) {
213                 LM_ERR("invalid reason parameter\n");
214                 return -1;
215         }
216
217         if((code < 100) || (code > 699)) {
218                 LM_ERR("wrong status code: %d\n", code);
219                 return -1;
220         }
221
222         if(((code < 300) || (msg->REPLY_STATUS < 300))
223                         && (code / 100 != msg->REPLY_STATUS / 100)) {
224                 LM_ERR("the class of provisional or "
225                                    "positive final replies cannot be changed\n");
226                 return -1;
227         }
228
229         /* rewrite the status code directly in the message buffer */
230         msg->first_line.u.reply.statuscode = code;
231         msg->first_line.u.reply.status.s[2] = code % 10 + '0';
232         code /= 10;
233         msg->first_line.u.reply.status.s[1] = code % 10 + '0';
234         code /= 10;
235         msg->first_line.u.reply.status.s[0] = code + '0';
236
237         l = del_lump(msg, msg->first_line.u.reply.reason.s - msg->buf,
238                         msg->first_line.u.reply.reason.len, 0);
239         if(!l) {
240                 LM_ERR("Failed to add del lump\n");
241                 return -1;
242         }
243         /* clone the reason phrase, the lumps need to be pkg allocated */
244         ch = (char *)pkg_malloc(reason->len);
245         if(!ch) {
246                 LM_ERR("Not enough memory\n");
247                 return -1;
248         }
249         memcpy(ch, reason->s, reason->len);
250         if(insert_new_lump_after(l, ch, reason->len, 0) == 0) {
251                 LM_ERR("failed to add new lump: %.*s\n", reason->len, ch);
252                 pkg_free(ch);
253                 return -1;
254         }
255
256         return 1;
257 }
258
259
260 /**
261  *
262  */
263 static int change_reply_status_f(
264                 struct sip_msg *msg, char *_code, char *_reason)
265 {
266         int code;
267         str reason;
268
269         if(get_int_fparam(&code, msg, (fparam_t *)_code)
270                         || get_str_fparam(&reason, msg, (fparam_t *)_reason)) {
271                 LM_ERR("cannot get parameters\n");
272                 return -1;
273         }
274         return ki_change_reply_status(msg, code, &reason);
275 }
276
277
278 /**
279  *
280  */
281 static int ki_remove_body(struct sip_msg *msg)
282 {
283         str body = {0, 0};
284
285         body.len = 0;
286         body.s = get_body(msg);
287         if(body.s == 0) {
288                 LM_DBG("no body in the message\n");
289                 return 1;
290         }
291         body.len = msg->buf + msg->len - body.s;
292         if(body.len <= 0) {
293                 LM_DBG("empty body in the message\n");
294                 return 1;
295         }
296         if(del_lump(msg, body.s - msg->buf, body.len, 0) == 0) {
297                 LM_ERR("cannot remove body\n");
298                 return -1;
299         }
300         return 1;
301 }
302
303
304 /**
305  *
306  */
307 static int w_remove_body_f(struct sip_msg *msg, char *p1, char *p2)
308 {
309         return ki_remove_body(msg);
310 }
311
312
313 /**
314  *
315  */
316 static int keep_hf_helper(sip_msg_t *msg, regex_t *re)
317 {
318         struct hdr_field *hf;
319         regmatch_t pmatch;
320         char c;
321         struct lump *l;
322
323         /* we need to be sure we have seen all HFs */
324         if(parse_headers(msg, HDR_EOH_F, 0) == -1) {
325                 LM_ERR("Error while parsing message\n");
326                 return -1;
327         }
328         for(hf = msg->headers; hf; hf = hf->next) {
329                 switch(hf->type) {
330                         case HDR_FROM_T:
331                         case HDR_TO_T:
332                         case HDR_CALLID_T:
333                         case HDR_CSEQ_T:
334                         case HDR_VIA_T:
335                         case HDR_VIA2_T:
336                         case HDR_CONTACT_T:
337                         case HDR_CONTENTLENGTH_T:
338                         case HDR_CONTENTTYPE_T:
339                         case HDR_ROUTE_T:
340                         case HDR_RECORDROUTE_T:
341                         case HDR_MAXFORWARDS_T:
342                                 continue;
343                         default:;
344                 }
345
346                 if(re == NULL) {
347                         /* no regex to match => remove all */
348                         l = del_lump(msg, hf->name.s - msg->buf, hf->len, 0);
349                         if(l == 0) {
350                                 LM_ERR("cannot remove header [%.*s]\n", hf->name.len,
351                                                 hf->name.s);
352                                 return -1;
353                         }
354                 } else {
355                         c = hf->name.s[hf->name.len];
356                         hf->name.s[hf->name.len] = '\0';
357                         if(regexec(re, hf->name.s, 1, &pmatch, 0) != 0) {
358                                 /* no match => remove */
359                                 hf->name.s[hf->name.len] = c;
360                                 l = del_lump(msg, hf->name.s - msg->buf, hf->len, 0);
361                                 if(l == 0) {
362                                         LM_ERR("cannot remove header [%.*s]\n", hf->name.len,
363                                                         hf->name.s);
364                                         return -1;
365                                 }
366                         } else {
367                                 hf->name.s[hf->name.len] = c;
368                         }
369                 }
370         }
371
372         return -1;
373 }
374
375
376 /**
377  *
378  */
379 static int w_keep_hf_f(struct sip_msg *msg, char *key, char *foo)
380 {
381         regex_t *re;
382
383         if(key) {
384                 re = (regex_t *)key;
385         } else {
386                 re = NULL;
387         }
388         return keep_hf_helper(msg, re);
389 }
390
391
392 /**
393  *
394  */
395 static int ki_keep_hf(sip_msg_t *msg)
396 {
397         return keep_hf_helper(msg, NULL);
398 }
399
400
401 /**
402  *
403  */
404 static int ki_keep_hf_re(sip_msg_t *msg, str *sre)
405 {
406         regex_t re;
407         int ret;
408
409         if(sre==NULL || sre->len<=0)
410                 return keep_hf_helper(msg, NULL);
411
412         memset(&re, 0, sizeof(regex_t));
413         if (regcomp(&re, sre->s, REG_EXTENDED|REG_ICASE|REG_NEWLINE)!=0) {
414                 LM_ERR("failed to compile regex: %.*s\n", sre->len, sre->s);
415                 return -1;
416         }
417         ret = keep_hf_helper(msg, &re);
418         regfree(&re);
419         return ret;
420 }
421
422
423 /**
424  *
425  */
426 static int w_fnmatch_ex(str *val, str *match, str *flags)
427 {
428         int i;
429         i = 0;
430 #ifdef FNM_CASEFOLD
431         if(flags && (flags->s[0] == 'i' || flags->s[0] == 'I'))
432                 i = FNM_CASEFOLD;
433 #endif
434         if(fnmatch(match->s, val->s, i) == 0)
435                 return 0;
436         return -1;
437 }
438
439 /**
440  *
441  */
442 static int w_fnmatch2_f(sip_msg_t *msg, char *val, char *match)
443 {
444         str sval;
445         str smatch;
446         if(get_str_fparam(&sval, msg, (fparam_t *)val) < 0
447                         || get_str_fparam(&smatch, msg, (fparam_t *)match) < 0) {
448                 LM_ERR("invalid parameters");
449                 return -1;
450         }
451         if(w_fnmatch_ex(&sval, &smatch, NULL) < 0)
452                 return -1;
453         return 1;
454 }
455
456 /**
457  *
458  */
459 static int w_fnmatch3_f(sip_msg_t *msg, char *val, char *match, char *flags)
460 {
461         str sval;
462         str smatch;
463         str sflags;
464         if(get_str_fparam(&sval, msg, (fparam_t *)val) < 0
465                         || get_str_fparam(&smatch, msg, (fparam_t *)match) < 0
466                         || get_str_fparam(&sflags, msg, (fparam_t *)flags) < 0) {
467                 LM_ERR("invalid parameters");
468                 return -1;
469         }
470         if(w_fnmatch_ex(&sval, &smatch, &sflags) < 0)
471                 return -1;
472         return 1;
473 }
474
475 /**
476  *
477  */
478 static int ki_fnmatch(sip_msg_t *msg, str *val, str *match)
479 {
480         return w_fnmatch_ex(val, match, NULL);
481 }
482
483 /**
484  *
485  */
486 static int ki_fnmatch_ex(sip_msg_t *msg, str *val, str *match, str *flags)
487 {
488         return w_fnmatch_ex(val, match, flags);
489 }
490
491 /**
492  *
493  */
494 static int fixup_fnmatch(void **param, int param_no)
495 {
496         if(param_no == 1) {
497                 return fixup_var_pve_12(param, param_no);
498         } else if(param_no == 2) {
499                 return fixup_var_pve_12(param, param_no);
500         } else if(param_no == 3) {
501                 return fixup_var_pve_12(param, param_no);
502         } else {
503                 return 0;
504         }
505 }
506
507 /*
508  * Function to load the textops api.
509  */
510 static int bind_textopsx(textopsx_api_t *tob)
511 {
512         if(tob == NULL) {
513                 LM_WARN("textopsx_binds: Cannot load textopsx API into a NULL "
514                                 "pointer\n");
515                 return -1;
516         }
517         tob->msg_apply_changes = msg_apply_changes_f;
518         return 0;
519 }
520
521
522 /**
523  * functions operating on header value
524  */
525 #define HNF_ALL 0x01
526 #define HNF_IDX 0x02
527
528 #define MAX_HF_VALUE_STACK 10
529
530 enum
531 {
532         hnoInsert,
533         hnoAppend,
534         hnoAssign,
535         hnoRemove,
536         hnoInclude,
537         hnoExclude,
538         hnoIsIncluded,
539         hnoGetValue,
540         hnoGetValueUri,
541         hnoGetValueName,
542         hnoRemove2,
543         hnoAssign2,
544         hnoGetValue2
545 };
546
547 struct hname_data
548 {
549         int oper;
550         int htype;
551         str hname;
552         int flags;
553         int idx;
554         str param;
555 };
556
557 #define is_space(_p) \
558         ((_p) == '\t' || (_p) == '\n' || (_p) == '\r' || (_p) == ' ')
559
560 #define eat_spaces(_p)       \
561         while(is_space(*(_p))) { \
562                 (_p)++;              \
563         }
564
565 #define is_alphanum(_p)                                           \
566         (((_p) >= 'a' && (_p) <= 'z') || ((_p) >= 'A' && (_p) <= 'Z') \
567                         || ((_p) >= '0' && (_p) <= '9') || (_p) == '_' || (_p) == '-')
568
569 #define eat_while_alphanum(_p)  \
570         while(is_alphanum(*(_p))) { \
571                 (_p)++;                 \
572         }
573
574 static int fixup_hvalue_param(void **param, int param_no)
575 {
576         return fixup_spve_null(param, 1);
577 }
578
579 static int eval_hvalue_param(sip_msg_t *msg, gparam_t *val, str *s)
580 {
581         if(fixup_get_svalue(msg, val, s) < 0) {
582                 LM_ERR("could not get string param value\n");
583                 return E_UNSPEC;
584         }
585         return 1;
586 }
587
588 /* parse:  hname [ ([] | [*] | [number]) ] [ "." param ] */
589 static int fixup_hname_param(char *hname, struct hname_data **h)
590 {
591         struct hdr_field hdr;
592         char *savep, savec;
593
594         *h = pkg_malloc(sizeof(**h));
595         if(!*h)
596                 return E_OUT_OF_MEM;
597         memset(*h, 0, sizeof(**h));
598
599         memset(&hdr, 0, sizeof(hdr));
600         eat_spaces(hname);
601         (*h)->hname.s = hname;
602         savep = hname;
603         eat_while_alphanum(hname);
604         (*h)->hname.len = hname - (*h)->hname.s;
605         savec = *hname;
606         *hname = ':';
607         parse_hname2_short(
608                         (*h)->hname.s, (*h)->hname.s + (*h)->hname.len + 1, &hdr);
609         *hname = savec;
610
611         if(hdr.type == HDR_ERROR_T)
612                 goto err;
613         (*h)->htype = hdr.type;
614
615         eat_spaces(hname);
616         savep = hname;
617         if(*hname == '[') {
618                 hname++;
619                 eat_spaces(hname);
620                 savep = hname;
621                 (*h)->flags |= HNF_IDX;
622                 if(*hname == '*') {
623                         (*h)->flags |= HNF_ALL;
624                         hname++;
625                 } else if(*hname != ']') {
626                         char *c;
627                         (*h)->idx = strtol(hname, &c, 10);
628                         if(hname == c)
629                                 goto err;
630                         hname = c;
631                 }
632                 eat_spaces(hname);
633                 savep = hname;
634                 if(*hname != ']')
635                         goto err;
636                 hname++;
637         }
638         eat_spaces(hname);
639         savep = hname;
640         if(*hname == '.') {
641                 hname++;
642                 eat_spaces(hname);
643                 savep = hname;
644                 (*h)->param.s = hname;
645                 eat_while_alphanum(hname);
646                 (*h)->param.len = hname - (*h)->param.s;
647                 if((*h)->param.len == 0)
648                         goto err;
649         } else {
650                 (*h)->param.s = hname;
651         }
652         savep = hname;
653         if(*hname != '\0')
654                 goto err;
655         (*h)->hname.s[(*h)->hname.len] = '\0';
656         (*h)->param.s[(*h)->param.len] = '\0';
657         return 0;
658 err:
659         pkg_free(*h);
660         LM_ERR("cannot parse header near '%s'\n", savep);
661         return E_CFG;
662 }
663
664 static int fixup_hname_str(void **param, int param_no)
665 {
666         if(param_no == 1) {
667                 struct hname_data *h;
668                 int res = fixup_hname_param(*param, &h);
669                 if(res < 0)
670                         return res;
671                 *param = h;
672         } else if(param_no == 2) {
673                 return fixup_hvalue_param(param, param_no);
674         }
675         return 0;
676 }
677
678 static int fixup_free_hname_str(void **param, int param_no)
679 {
680         if(param_no == 1) {
681                 struct hname_data *h;
682                 h = (struct hname_data *)(*param);
683                 pkg_free(h);
684                 return 0;
685         } else if(param_no == 2) {
686                 return fixup_free_spve_null(param, 1);
687         }
688         return 0;
689 }
690
691 static int find_next_hf(
692                 struct sip_msg *msg, struct hname_data *hname, struct hdr_field **hf)
693 {
694         if(!*hf) {
695                 if(parse_headers(msg, HDR_EOH_F, 0) == -1) {
696                         LM_ERR("Error while parsing message\n");
697                         return -1;
698                 }
699                 *hf = msg->headers;
700         } else {
701                 *hf = (*hf)->next;
702         }
703         for(; *hf; *hf = (*hf)->next) {
704                 if(hname->htype == HDR_OTHER_T) {
705                         if((*hf)->name.len == hname->hname.len
706                                         && strncasecmp(
707                                                            (*hf)->name.s, hname->hname.s, (*hf)->name.len)
708                                                            == 0)
709                                 return 1;
710                 } else if(hname->htype == (*hf)->type) {
711                         return 1;
712                 }
713         }
714         return 0;
715 }
716
717 static int find_next_value(char **start, char *end, str *val, str *lump_val)
718 {
719         int quoted = 0;
720         lump_val->s = *start;
721         while(*start < end && is_space(**start))
722                 (*start)++;
723         val->s = *start;
724         while(*start < end && (**start != ',' || quoted)) {
725                 if(**start == '\"' && (!quoted || (*start)[-1] != '\\'))
726                         quoted = ~quoted;
727                 (*start)++;
728         }
729         val->len = *start - val->s;
730         while(val->len > 0 && is_space(val->s[val->len - 1]))
731                 val->len--;
732         /* we cannot automatically strip quotes!!! an example why: "name" <sip:ssss>;param="bar"
733         if (val->len >= 2 && val->s[0] == '\"' && val->s[val->len-1] == '\"') {
734                 val->s++;
735                 val->len -= 2;
736         }
737 */
738         while(*start < end && **start != ',')
739                 (*start)++;
740         if(*start < end) {
741                 (*start)++;
742         }
743         lump_val->len = *start - lump_val->s;
744         return (*start < end);
745 }
746
747 static void adjust_lump_val_for_delete(struct hdr_field *hf, str *lump_val)
748 {
749         if(lump_val->s + lump_val->len == hf->body.s + hf->body.len) {
750                 if(lump_val->s > hf->body.s) {
751                         /* in case if is it last value in header save position of last delimiter to remove it with rightmost value */
752                         lump_val->s--;
753                         lump_val->len++;
754                 }
755         }
756 }
757
758 static int find_hf_value_idx(struct sip_msg *msg, struct hname_data *hname,
759                 struct hdr_field **hf, str *val, str *lump_val)
760 {
761         int res;
762         char *p;
763         if(hname->flags & HNF_ALL || hname->idx == 0)
764                 return -1;
765         *hf = 0;
766         if(hname->idx > 0) {
767                 int idx;
768                 idx = hname->idx;
769                 do {
770                         res = find_next_hf(msg, hname, hf);
771                         if(res < 0)
772                                 return -1;
773                         if(*hf) {
774                                 if(val) {
775                                         lump_val->len = 0;
776                                         p = (*hf)->body.s;
777                                         do {
778                                                 res = find_next_value(&p,
779                                                                 (*hf)->body.s + (*hf)->body.len, val, lump_val);
780                                                 idx--;
781                                         } while(res && idx);
782                                 } else {
783                                         idx--;
784                                 }
785                         }
786                 } while(*hf && idx);
787         } else if(hname->idx < 0) { /* search from the bottom */
788                 struct hf_value_stack
789                 {
790                         str val, lump_val;
791                         struct hdr_field *hf;
792                 } stack[MAX_HF_VALUE_STACK];
793                 int stack_pos, stack_num;
794
795                 if(-hname->idx > MAX_HF_VALUE_STACK)
796                         return -1;
797                 stack_pos = stack_num = 0;
798                 do {
799                         res = find_next_hf(msg, hname, hf);
800                         if(res < 0)
801                                 return -1;
802                         if(*hf) {
803                                 stack[stack_pos].lump_val.len = 0;
804                                 p = (*hf)->body.s;
805                                 do {
806                                         stack[stack_pos].hf = *hf;
807                                         if(val)
808                                                 res = find_next_value(&p,
809                                                                 (*hf)->body.s + (*hf)->body.len,
810                                                                 &stack[stack_pos].val,
811                                                                 &stack[stack_pos].lump_val);
812                                         else
813                                                 res = 0;
814                                         stack_pos++;
815                                         if(stack_pos >= MAX_HF_VALUE_STACK)
816                                                 stack_pos = 0;
817                                         if(stack_num < MAX_HF_VALUE_STACK)
818                                                 stack_num++;
819
820                                 } while(res);
821                         }
822                 } while(*hf);
823
824                 if(-hname->idx <= stack_num) {
825                         stack_pos += hname->idx;
826                         if(stack_pos < 0)
827                                 stack_pos += MAX_HF_VALUE_STACK;
828                         *hf = stack[stack_pos].hf;
829                         if(val) {
830                                 *val = stack[stack_pos].val;
831                                 *lump_val = stack[stack_pos].lump_val;
832                         }
833                 } else {
834                         *hf = 0;
835                 }
836         } else
837                 return -1;
838         return *hf ? 1 : 0;
839 }
840
841 static int find_hf_value_param(struct hname_data *hname, str *param_area,
842                 str *value, str *lump_upd, str *lump_del)
843 {
844         int i, j, found;
845
846         i = 0;
847         while(1) {
848                 lump_del->s = param_area->s + i;
849                 for(; i < param_area->len && is_space(param_area->s[i]); i++)
850                         ;
851                 if(i < param_area->len
852                                 && param_area->s[i] == ';') { /* found a param ? */
853                         i++;
854                         for(; i < param_area->len && is_space(param_area->s[i]); i++)
855                                 ;
856                         j = i;
857                         for(; i < param_area->len && !is_space(param_area->s[i])
858                                         && param_area->s[i] != '=' && param_area->s[i] != ';';
859                                         i++)
860                                 ;
861
862                         found = hname->param.len == i - j
863                                         && !strncasecmp(hname->param.s, param_area->s + j, i - j);
864                         lump_upd->s = param_area->s + i;
865                         value->s = param_area->s + i;
866                         value->len = 0;
867                         for(; i < param_area->len && is_space(param_area->s[i]); i++)
868                                 ;
869                         if(i < param_area->len && param_area->s[i] == '=') {
870                                 i++;
871                                 for(; i < param_area->len && is_space(param_area->s[i]); i++)
872                                         ;
873                                 value->s = param_area->s + i;
874                                 if(i < param_area->len) {
875                                         if(param_area->s[i] == '\"') {
876                                                 i++;
877                                                 value->s++;
878                                                 for(; i < param_area->len; i++) {
879                                                         if(param_area->s[i] == '\"') {
880                                                                 i++;
881                                                                 break;
882                                                         }
883                                                         value->len++;
884                                                 }
885                                         } else {
886                                                 for(; i < param_area->len && !is_space(param_area->s[i])
887                                                                 && param_area->s[i] != ';';
888                                                                 i++, value->len++)
889                                                         ;
890                                         }
891                                 }
892                         }
893                         if(found) {
894                                 lump_del->len = param_area->s + i - lump_del->s;
895                                 lump_upd->len = param_area->s + i - lump_upd->s;
896                                 return 1;
897                         }
898                 } else { /* not found, return last correct position, should be end of param area */
899                         lump_del->len = 0;
900                         return 0;
901                 }
902         }
903 }
904
905 /* parse:  something param_name=param_value something [ "," something param_name="param_value" ....]
906  * 'something' is required by Authenticate
907  */
908 static int find_hf_value2_param(struct hname_data *hname, str *param_area,
909                 str *value, str *lump_upd, str *lump_del, char *delim)
910 {
911         int i, j, k, found, comma_flag;
912
913         i = 0;
914         *delim = 0;
915         lump_del->len = 0;
916         while(i < param_area->len) {
917
918                 lump_del->s = param_area->s + i;
919                 while(i < param_area->len && is_space(param_area->s[i]))
920                         i++;
921                 comma_flag = i < param_area->len && param_area->s[i] == ',';
922                 if(comma_flag)
923                         i++;
924                 while(i < param_area->len && is_space(param_area->s[i]))
925                         i++;
926
927                 if(i < param_area->len
928                                 && is_alphanum(param_area->s[i])) { /* found a param name ? */
929                         j = i;
930                         if(!*delim)
931                                 *delim = ' ';
932                         while(i < param_area->len && is_alphanum(param_area->s[i]))
933                                 i++;
934
935                         k = i;
936                         while(i < param_area->len && is_space(param_area->s[i]))
937                                 i++;
938                         lump_upd->s = param_area->s + i;
939                         if(i < param_area->len
940                                         && param_area->s[i]
941                                                            == '=') { /* if equal then it's the param */
942                                 *delim = ',';
943                                 i++;
944                                 found = hname->param.len == k - j
945                                                 && !strncasecmp(
946                                                                    hname->param.s, param_area->s + j, k - j);
947                                 while(i < param_area->len && is_space(param_area->s[i]))
948                                         i++;
949
950                                 value->s = param_area->s + i;
951                                 value->len = 0;
952                                 if(i < param_area->len) {
953                                         if(param_area->s[i] == '\"') {
954                                                 i++;
955                                                 value->s++;
956                                                 for(; i < param_area->len; i++) {
957                                                         if(param_area->s[i] == '\"') {
958                                                                 i++;
959                                                                 break;
960                                                         }
961                                                         value->len++;
962                                                 }
963                                         } else {
964                                                 for(; i < param_area->len && !is_space(param_area->s[i])
965                                                                 && param_area->s[i] != ',';
966                                                                 i++, value->len++)
967                                                         ;
968                                         }
969                                 }
970                                 if(found) {
971                                         lump_upd->len = param_area->s + i - lump_upd->s;
972                                         lump_del->len = param_area->s + i - lump_del->s;
973
974                                         while(i < param_area->len && is_space(param_area->s[i]))
975                                                 i++;
976
977                                         if(!comma_flag && i < param_area->len
978                                                         && param_area->s[i] == ',') {
979                                                 i++;
980                                                 lump_del->len = param_area->s + i - lump_del->s;
981                                         }
982                                         return 1;
983                                 }
984                         }
985                         while(i < param_area->len && is_space(param_area->s[i]))
986                                 i++;
987                 } else {
988                         while(i < param_area->len && !is_space(param_area->s[i])
989                                         && !(param_area->s[i] != ','))
990                                 i++;
991                 }
992         }
993         lump_del->s = param_area->s + i;
994         return 0;
995 }
996
997 static int insert_header_lump(struct sip_msg *msg, char *msg_position,
998                 int lump_before, str *hname, str *val)
999 {
1000         struct lump *anchor;
1001         char *s;
1002         int len;
1003
1004         anchor = anchor_lump(msg, msg_position - msg->buf, 0, 0);
1005         if(anchor == 0) {
1006                 LM_ERR("Can't get anchor\n");
1007                 return -1;
1008         }
1009
1010         len = hname->len + 2 + val->len + 2;
1011
1012         s = (char *)pkg_malloc(len);
1013         if(!s) {
1014                 LM_ERR("not enough memory\n");
1015                 return -1;
1016         }
1017
1018         memcpy(s, hname->s, hname->len);
1019         s[hname->len] = ':';
1020         s[hname->len + 1] = ' ';
1021         memcpy(s + hname->len + 2, val->s, val->len);
1022         s[hname->len + 2 + val->len] = '\r';
1023         s[hname->len + 2 + val->len + 1] = '\n';
1024
1025         if((lump_before ? insert_new_lump_before(anchor, s, len, 0)
1026                                         : insert_new_lump_after(anchor, s, len, 0))
1027                         == 0) {
1028                 LM_ERR("Can't insert lump\n");
1029                 pkg_free(s);
1030                 return -1;
1031         }
1032         return 1;
1033 }
1034
1035 static int insert_value_lump(struct sip_msg *msg, struct hdr_field *hf,
1036                 char *msg_position, int lump_before, str *val)
1037 {
1038         struct lump *anchor;
1039         char *s;
1040         int len;
1041
1042         anchor = anchor_lump(msg, msg_position - msg->buf, 0, 0);
1043         if(anchor == 0) {
1044                 LM_ERR("Can't get anchor\n");
1045                 return -1;
1046         }
1047
1048         len = val->len + 1;
1049
1050         s = (char *)pkg_malloc(len);
1051         if(!s) {
1052                 LM_ERR("not enough memory\n");
1053                 return -1;
1054         }
1055
1056         if(!hf) {
1057                 memcpy(s, val->s, val->len);
1058                 len--;
1059         } else if(msg_position == hf->body.s + hf->body.len) {
1060                 s[0] = ',';
1061                 memcpy(s + 1, val->s, val->len);
1062         } else {
1063                 memcpy(s, val->s, val->len);
1064                 s[val->len] = ',';
1065         }
1066         if((lump_before ? insert_new_lump_before(anchor, s, len, 0)
1067                                         : insert_new_lump_after(anchor, s, len, 0))
1068                         == 0) {
1069                 LM_ERR("Can't insert lump\n");
1070                 pkg_free(s);
1071                 return -1;
1072         }
1073         return 1;
1074 }
1075
1076 static int delete_value_lump(
1077                 struct sip_msg *msg, struct hdr_field *hf, str *val)
1078 {
1079         struct lump *l;
1080         /* TODO: check already existing lumps */
1081         if(hf && val->s == hf->body.s
1082                         && val->len == hf->body.len) /* check if remove whole haeder? */
1083                 l = del_lump(msg, hf->name.s - msg->buf, hf->len, 0);
1084         else
1085                 l = del_lump(msg, val->s - msg->buf, val->len, 0);
1086         if(l == 0) {
1087                 LM_ERR("not enough memory\n");
1088                 return -1;
1089         }
1090         return 1;
1091 }
1092
1093 static int ki_modify_hf(sip_msg_t *msg, str *hexp, str *val,
1094         fixup_function fixf, cmd_function cmdf)
1095 {
1096         int ret;
1097         char *s1 = NULL;
1098         char *s2 = NULL;
1099         void *p1 = NULL;
1100         void *p2 = NULL;
1101
1102         s1 = as_asciiz(hexp);
1103         p1 = s1;
1104         if(fixf(&p1, 1)!=0) {
1105                 LM_ERR("failed to fix first parameter\n");
1106                 p1 = NULL;
1107                 goto error;
1108         }
1109         if(val && val->s!=0 && val->len>0) {
1110                 s2 = as_asciiz(val);
1111                 p2 = s2;
1112                 if(fixf(&p2, 2)!=0) {
1113                         LM_ERR("failed to fix second parameter\n");
1114                         p2 = NULL;
1115                         goto error;
1116                 }
1117         }
1118
1119         ret = cmdf(msg, (char*)p1, (char*)p2);
1120
1121         if(p2!=NULL) fixup_free_hname_str(&p2, 2);
1122         fixup_free_hname_str(&p1, 1);
1123         if(s2!=NULL) pkg_free(s2);
1124         pkg_free(s1);
1125         return ret;
1126
1127 error:
1128         if(p1!=NULL) fixup_free_hname_str(&p1, 1);
1129         if(s2!=NULL) pkg_free(s2);
1130         if(s1!=NULL) pkg_free(s1);
1131         return -1;
1132 }
1133
1134 static int incexc_hf_value_str_f(struct sip_msg *msg, char *_hname, str *_pval)
1135 {
1136         struct hname_data *hname = (void *)_hname;
1137         struct hdr_field *hf, *lump_hf;
1138         str val, hval1, hval2;
1139         char *p;
1140         int res;
1141
1142         val = *_pval;
1143         if(!val.len)
1144                 return -1;
1145         hf = 0;
1146         lump_hf = 0;
1147         while(1) {
1148                 if(find_next_hf(msg, hname, &hf) < 0)
1149                         return -1;
1150                 if(!hf)
1151                         break;
1152                 hval2.len = 0;
1153                 p = hf->body.s;
1154                 do {
1155                         res = find_next_value(
1156                                         &p, hf->body.s + hf->body.len, &hval1, &hval2);
1157                         if(hval1.len && val.len == hval1.len
1158                                         && strncasecmp(val.s, hval1.s, val.len) == 0) {
1159                                 switch(hname->oper) {
1160                                         case hnoIsIncluded:
1161                                         case hnoInclude:
1162                                                 return 1;
1163                                         case hnoExclude:
1164                                                 adjust_lump_val_for_delete(hf, &hval2);
1165                                                 delete_value_lump(msg, hf, &hval2);
1166                                         default:
1167                                                 break;
1168                                 }
1169                         }
1170                 } while(res);
1171                 switch(hname->oper) {
1172                         case hnoInclude:
1173                                 if(!lump_hf) {
1174                                         lump_hf = hf;
1175                                 }
1176                                 break;
1177                         default:
1178                                 break;
1179                 }
1180         }
1181         switch(hname->oper) {
1182                 case hnoIsIncluded:
1183                         return -1;
1184                 case hnoInclude:
1185                         if(lump_hf)
1186                                 return insert_value_lump(msg, lump_hf,
1187                                                 lump_hf->body.s + lump_hf->body.len, 1, &val);
1188                         else
1189                                 return insert_header_lump(
1190                                                 msg, msg->unparsed, 1, &hname->hname, &val);
1191                 default:
1192                         return 1;
1193         }
1194 }
1195
1196 static int incexc_hf_value_f(struct sip_msg *msg, char *_hname, char *_val)
1197 {
1198         str val;
1199         int res;
1200
1201         res = eval_hvalue_param(msg, (void *)_val, &val);
1202
1203         if(res < 0)
1204                 return res;
1205         if(!val.len)
1206                 return -1;
1207
1208         return incexc_hf_value_str_f(msg, _hname, &val);
1209 }
1210
1211 #define INCEXC_HF_VALUE_FIXUP(_func, _oper)                                  \
1212         static int _func(void **param, int param_no)                             \
1213         {                                                                        \
1214                 char *p = *param;                                                    \
1215                 int res = fixup_hname_str(param, param_no);                          \
1216                 if(res < 0)                                                          \
1217                         return res;                                                      \
1218                 if(param_no == 1) {                                                  \
1219                         if(((struct hname_data *)*param)->flags & HNF_IDX                \
1220                                         || ((struct hname_data *)*param)->param.len) {           \
1221                                 LM_ERR("neither index nor param may be specified in '%s'\n", \
1222                                                 p);                                                  \
1223                                 return E_CFG;                                                \
1224                         }                                                                \
1225                         ((struct hname_data *)*param)->oper = _oper;                     \
1226                 }                                                                    \
1227                 return 0;                                                            \
1228         }
1229
1230 INCEXC_HF_VALUE_FIXUP(include_hf_value_fixup, hnoInclude)
1231 INCEXC_HF_VALUE_FIXUP(exclude_hf_value_fixup, hnoExclude)
1232 INCEXC_HF_VALUE_FIXUP(hf_value_exists_fixup, hnoIsIncluded)
1233
1234 static int ki_include_hf_value(sip_msg_t *msg, str *hexp, str *val)
1235 {
1236         return ki_modify_hf(msg, hexp, val, include_hf_value_fixup,
1237                         incexc_hf_value_f);
1238 }
1239
1240 static int ki_exclude_hf_value(sip_msg_t *msg, str *hexp, str *val)
1241 {
1242         return ki_modify_hf(msg, hexp, val, exclude_hf_value_fixup,
1243                         incexc_hf_value_f);
1244 }
1245
1246 static int ki_hf_value_exists(sip_msg_t *msg, str *hexp, str *val)
1247 {
1248         return ki_modify_hf(msg, hexp, val, hf_value_exists_fixup,
1249                         incexc_hf_value_f);
1250 }
1251
1252 static void get_uri_and_skip_until_params(str *param_area, str *name, str *uri)
1253 {
1254         int i, quoted, uri_pos, uri_done;
1255
1256         name->len = 0;
1257         uri->len = 0;
1258         uri->s = 0;
1259         uri_done = 0;
1260         name->s = param_area->s;
1261         for(i = 0; i < param_area->len && param_area->s[i] != ';';) {
1262                 /* [ *(token LSW)/quoted-string ] "<" addr-spec ">" | addr-spec */
1263                 /* skip name */
1264                 for(quoted = 0, uri_pos = i; i < param_area->len; i++) {
1265                         if(!quoted) {
1266                                 if(param_area->s[i] == '\"') {
1267                                         quoted = 1;
1268                                         uri_pos = -1;
1269                                 } else if(param_area->s[i] == '<' || param_area->s[i] == ';'
1270                                                   || is_space(param_area->s[i]))
1271                                         break;
1272                         } else if(param_area->s[i] == '\"' && param_area->s[i - 1] != '\\')
1273                                 quoted = 0;
1274                 }
1275                 if(!name->len)
1276                         name->len = param_area->s + i - name->s;
1277                 if(uri_pos >= 0 && !uri_done) {
1278                         uri->s = param_area->s + uri_pos;
1279                         uri->len = param_area->s + i - uri->s;
1280                 }
1281                 /* skip uri */
1282                 while(i < param_area->len && is_space(param_area->s[i]))
1283                         i++;
1284                 if(i < param_area->len && param_area->s[i] == '<') {
1285                         uri->s = param_area->s + i;
1286                         uri->len = 0;
1287                         for(quoted = 0; i < param_area->len; i++) {
1288                                 if(!quoted) {
1289                                         if(param_area->s[i] == '\"')
1290                                                 quoted = 1;
1291                                         else if(param_area->s[i] == '>') {
1292                                                 uri->len = param_area->s + i - uri->s + 1;
1293                                                 uri_done = 1;
1294                                                 break;
1295                                         }
1296                                 } else if(param_area->s[i] == '\"'
1297                                                   && param_area->s[i - 1] != '\\')
1298                                         quoted = 0;
1299                         }
1300                 }
1301         }
1302         param_area->s += i;
1303         param_area->len -= i;
1304         if(uri->s == name->s)
1305                 name->len = 0;
1306 }
1307
1308 static int assign_hf_do_lumping(struct sip_msg *msg, struct hdr_field *hf,
1309                 struct hname_data *hname, str *value, int upd_del_fl, str *lump_upd,
1310                 str *lump_del, char delim)
1311 {
1312         int len, i;
1313         char *s;
1314         struct lump *anchor;
1315
1316         if(upd_del_fl) {
1317                 len = value ? lump_upd->len : lump_del->len;
1318                 if(len > 0) {
1319                         if(!del_lump(msg, (value ? lump_upd->s : lump_del->s) - msg->buf,
1320                                            len, 0)) {
1321                                 LM_ERR("not enough memory\n");
1322                                 return -1;
1323                         }
1324                 }
1325                 if(value && value->len) {
1326                         anchor = anchor_lump(msg, lump_upd->s - msg->buf, 0, 0);
1327                         if(anchor == 0) {
1328                                 LM_ERR("Can't get anchor\n");
1329                                 return -1;
1330                         }
1331
1332                         len = 1 + value->len;
1333                         s = pkg_malloc(len);
1334                         if(!s) {
1335                                 LM_ERR("not enough memory\n");
1336                                 return -1;
1337                         }
1338                         s[0] = '=';
1339                         memcpy(s + 1, value->s, value->len);
1340                         if((insert_new_lump_before(anchor, s, len, 0)) == 0) {
1341                                 LM_ERR("Can't insert lump\n");
1342                                 pkg_free(s);
1343                                 return -1;
1344                         }
1345                 }
1346         } else {
1347                 if(!value)
1348                         return -1;
1349
1350                 anchor = anchor_lump(msg, lump_del->s - msg->buf, 0, 0);
1351                 if(anchor == 0) {
1352                         LM_ERR("Can't get anchor\n");
1353                         return -1;
1354                 }
1355
1356                 len = 1 + hname->param.len + (value->len ? value->len + 1 : 0);
1357                 s = pkg_malloc(len);
1358                 if(!s) {
1359                         LM_ERR("not enough memory\n");
1360                         return -1;
1361                 }
1362                 if(delim) {
1363                         s[0] = delim;
1364                         i = 1;
1365                 } else {
1366                         i = 0;
1367                         len--;
1368                 }
1369                 memcpy(s + i, hname->param.s, hname->param.len);
1370                 if(value->len) {
1371                         s[hname->param.len + i] = '=';
1372                         memcpy(s + i + hname->param.len + 1, value->s, value->len);
1373                 }
1374
1375                 if((insert_new_lump_before(anchor, s, len, 0)) == 0) {
1376                         LM_ERR("Can't insert lump\n");
1377                         pkg_free(s);
1378                         return -1;
1379                 }
1380         }
1381         return 1;
1382 }
1383
1384
1385 static int assign_hf_process_params(struct sip_msg *msg, struct hdr_field *hf,
1386                 struct hname_data *hname, str *value, str *value_area)
1387 {
1388         int r, r2, res = 0;
1389         str param_area, lump_upd, lump_del, dummy_val, dummy_name, dummy_uri;
1390         param_area = *value_area;
1391         get_uri_and_skip_until_params(&param_area, &dummy_name, &dummy_uri);
1392         do {
1393                 r = find_hf_value_param(
1394                                 hname, &param_area, &dummy_val, &lump_upd, &lump_del);
1395                 r2 = assign_hf_do_lumping(
1396                                 msg, hf, hname, value, r, &lump_upd, &lump_del, ';');
1397                 if(res == 0)
1398                         res = r2;
1399                 if(r && !value) { /* remove all parameters */
1400                         param_area.len -= lump_del.s + lump_del.len - param_area.s;
1401                         param_area.s = lump_del.s + lump_del.len;
1402                 }
1403         } while(!value && r);
1404         return res;
1405 }
1406
1407 static int assign_hf_process2_params(struct sip_msg *msg, struct hdr_field *hf,
1408                 struct hname_data *hname, str *value)
1409 {
1410         int r, r2, res = 0;
1411         str param_area, lump_upd, lump_del, dummy_val;
1412         char delim;
1413
1414         param_area = hf->body;
1415
1416         do {
1417                 r = find_hf_value2_param(
1418                                 hname, &param_area, &dummy_val, &lump_upd, &lump_del, &delim);
1419                 r2 = assign_hf_do_lumping(
1420                                 msg, hf, hname, value, r, &lump_upd, &lump_del, delim);
1421                 if(res == 0)
1422                         res = r2;
1423                 if(r && !value) { /* remove all parameters */
1424                         param_area.len -= lump_del.s + lump_del.len - param_area.s;
1425                         param_area.s = lump_del.s + lump_del.len;
1426                 }
1427         } while(!value && r);
1428         return res;
1429 }
1430
1431 static int insupddel_hf_value_f(struct sip_msg *msg, char *_hname, char *_val)
1432 {
1433         struct hname_data *hname = (void *)_hname;
1434         struct hdr_field *hf;
1435         str val = {0};
1436         str hval1, hval2;
1437         int res;
1438
1439         if(_val) {
1440                 res = eval_hvalue_param(msg, (void *)_val, &val);
1441                 if(res < 0)
1442                         return res;
1443         }
1444         switch(hname->oper) {
1445                 case hnoAppend:
1446                         if((hname->flags & HNF_IDX) == 0) {
1447                                 if(parse_headers(msg, HDR_EOH_F, 0) == -1) {
1448                                         LM_ERR("Error while parsing message\n");
1449                                         return -1;
1450                                 }
1451                                 return insert_header_lump(
1452                                                 msg, msg->unparsed, 1, &hname->hname, &val);
1453                         } else {
1454                                 res = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
1455                                 if(res < 0)
1456                                         return res;
1457                                 if(hf) {
1458                                         return insert_value_lump(msg, hf, hval2.s + hval2.len,
1459                                                         res /* insert after, except it is last value in header */
1460                                                         ,
1461                                                         &val);
1462                                 } else {
1463                                         return insert_header_lump(
1464                                                         msg, msg->unparsed, 1, &hname->hname, &val);
1465                                 }
1466                         }
1467                 case hnoInsert:
1468                         /* if !HNF_IDX is possible parse only until first hname header
1469                          * but not trivial for HDR_OTHER_T header, not implemented */
1470                         res = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
1471                         if(res < 0)
1472                                 return res;
1473                         if(hf && (hname->flags & HNF_IDX) == 0) {
1474                                 return insert_header_lump(
1475                                                 msg, hf->name.s, 1, &hname->hname, &val);
1476                         } else if(!hf && hname->idx == 1) {
1477                                 return insert_header_lump(
1478                                                 msg, msg->unparsed, 1, &hname->hname, &val);
1479                         } else if(hf) {
1480                                 return insert_value_lump(msg, hf, hval2.s, 1, &val);
1481                         } else
1482                                 return -1;
1483
1484                 case hnoRemove:
1485                 case hnoAssign:
1486                         if(hname->flags & HNF_ALL) {
1487                                 struct hdr_field *hf = 0;
1488                                 int fl = -1;
1489                                 do {
1490                                         res = find_next_hf(msg, hname, &hf);
1491                                         if(res < 0)
1492                                                 return res;
1493                                         if(hf) {
1494                                                 if(!hname->param.len) {
1495                                                         fl = 1;
1496                                                         delete_value_lump(msg, hf, &hf->body);
1497                                                 } else {
1498                                                         char *p;
1499                                                         hval2.len = 0;
1500                                                         p = hf->body.s;
1501                                                         do {
1502                                                                 res = find_next_value(&p,
1503                                                                                 hf->body.s + hf->body.len, &hval1,
1504                                                                                 &hval2);
1505                                                                 if(assign_hf_process_params(msg, hf, hname,
1506                                                                                    _val ? &val : 0, &hval1)
1507                                                                                 > 0)
1508                                                                         fl = 1;
1509                                                         } while(res);
1510                                                 }
1511                                         }
1512                                 } while(hf);
1513                                 return fl;
1514                         } else {
1515                                 res = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
1516                                 if(res < 0)
1517                                         return res;
1518                                 if(hf) {
1519                                         if(!hname->param.len) {
1520                                                 if(hname->oper == hnoRemove) {
1521                                                         adjust_lump_val_for_delete(hf, &hval2);
1522                                                         return delete_value_lump(msg, hf, &hval2);
1523                                                 } else {
1524                                                         res = delete_value_lump(msg,
1525                                                                         0 /* delete only value part */, &hval1);
1526                                                         if(res < 0)
1527                                                                 return res;
1528                                                         if(val.len) {
1529                                                                 return insert_value_lump(msg,
1530                                                                                 0 /* do not add delims */, hval1.s, 1,
1531                                                                                 &val);
1532                                                         }
1533                                                         return 1;
1534                                                 }
1535                                         } else {
1536                                                 return assign_hf_process_params(
1537                                                                 msg, hf, hname, _val ? &val : 0, &hval1);
1538                                         }
1539                                 }
1540                         }
1541                         break;
1542                 case hnoRemove2:
1543                 case hnoAssign2:
1544                         if(hname->flags & HNF_ALL) {
1545                                 struct hdr_field *hf = 0;
1546                                 int fl = -1;
1547                                 do {
1548                                         res = find_next_hf(msg, hname, &hf);
1549                                         if(res < 0)
1550                                                 return res;
1551                                         if(hf) {
1552                                                 if(!hname->param.len) { /* the same as hnoRemove/hnoAssign */
1553                                                         fl = 1;
1554                                                         delete_value_lump(msg, hf, &hf->body);
1555                                                 } else {
1556
1557                                                         if(assign_hf_process2_params(
1558                                                                            msg, hf, hname, _val ? &val : 0)
1559                                                                         > 0)
1560                                                                 fl = 1;
1561                                                 }
1562                                         }
1563                                 } while(hf);
1564                                 return fl;
1565                         } else {
1566                                 res = find_hf_value_idx(msg, hname, &hf, 0, 0);
1567                                 if(res < 0)
1568                                         return res;
1569                                 if(hf) {
1570                                         if(!hname->param.len) {
1571                                                 if(hname->oper == hnoRemove2) {
1572                                                         return delete_value_lump(msg, hf, &hf->body);
1573                                                 } else {
1574                                                         res = delete_value_lump(msg,
1575                                                                         0 /* delete only value part */, &hf->body);
1576                                                         if(res < 0)
1577                                                                 return res;
1578                                                         if(val.len) {
1579                                                                 return insert_value_lump(msg,
1580                                                                                 0 /* do not add delims */, hf->body.s,
1581                                                                                 1, &val);
1582                                                         }
1583                                                         return 1;
1584                                                 }
1585                                         } else {
1586                                                 return assign_hf_process2_params(
1587                                                                 msg, hf, hname, _val ? &val : 0);
1588                                         }
1589                                 }
1590                         }
1591                         break;
1592         }
1593         return -1;
1594 }
1595
1596 static int append_hf_value_fixup(void **param, int param_no)
1597 {
1598         int res = fixup_hname_str(param, param_no);
1599         if(res < 0)
1600                 return res;
1601         if(param_no == 1) {
1602                 if(((struct hname_data *)*param)->flags & HNF_ALL) {
1603                         LM_ERR("asterisk not supported\n");
1604                         return E_CFG;
1605                 } else if((((struct hname_data *)*param)->flags & HNF_IDX) == 0
1606                                   || !((struct hname_data *)*param)->idx) {
1607                         ((struct hname_data *)*param)->idx = -1;
1608                 }
1609                 if(((struct hname_data *)*param)->idx < -MAX_HF_VALUE_STACK) {
1610                         LM_ERR("index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
1611                         return E_CFG;
1612                 }
1613                 if(((struct hname_data *)*param)->param.len) {
1614                         LM_ERR("param not supported\n");
1615                         return E_CFG;
1616                 }
1617                 ((struct hname_data *)*param)->oper = hnoAppend;
1618         }
1619         return 0;
1620 }
1621
1622 static int ki_append_hf_value(sip_msg_t *msg, str *hexp, str *val)
1623 {
1624         return ki_modify_hf(msg, hexp, val, append_hf_value_fixup,
1625                         insupddel_hf_value_f);
1626 }
1627
1628 static int insert_hf_value_fixup(void **param, int param_no)
1629 {
1630         int res = fixup_hname_str(param, param_no);
1631         if(res < 0)
1632                 return res;
1633         if(param_no == 1) {
1634                 if(((struct hname_data *)*param)->flags & HNF_ALL) {
1635                         LM_ERR("asterisk not supported\n");
1636                         return E_CFG;
1637                 } else if((((struct hname_data *)*param)->flags & HNF_IDX) == 0
1638                                   || !((struct hname_data *)*param)->idx) {
1639                         ((struct hname_data *)*param)->idx = 1;
1640                 }
1641                 if(((struct hname_data *)*param)->idx < -MAX_HF_VALUE_STACK) {
1642                         LM_ERR("index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
1643                         return E_CFG;
1644                 }
1645                 if(((struct hname_data *)*param)->param.len) {
1646                         LM_ERR("param not supported\n");
1647                         return E_CFG;
1648                 }
1649                 ((struct hname_data *)*param)->oper = hnoInsert;
1650         }
1651         return 0;
1652 }
1653
1654 static int ki_insert_hf_value(sip_msg_t *msg, str *hexp, str *val)
1655 {
1656         return ki_modify_hf(msg, hexp, val, insert_hf_value_fixup,
1657                         insupddel_hf_value_f);
1658 }
1659
1660 static int remove_hf_value_fixup(void **param, int param_no)
1661 {
1662         int res = fixup_hname_str(param, param_no);
1663         if(res < 0)
1664                 return res;
1665         if(param_no == 1) {
1666                 if((((struct hname_data *)*param)->flags & HNF_IDX) == 0
1667                                 || !((struct hname_data *)*param)->idx) {
1668                         ((struct hname_data *)*param)->idx = 1;
1669                         ((struct hname_data *)*param)->flags |= HNF_IDX;
1670                 }
1671                 if(((struct hname_data *)*param)->idx < -MAX_HF_VALUE_STACK) {
1672                         LM_ERR("index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
1673                         return E_CFG;
1674                 }
1675                 ((struct hname_data *)*param)->oper = hnoRemove;
1676         }
1677         return 0;
1678 }
1679
1680 static int ki_remove_hf_value(sip_msg_t *msg, str *hexp)
1681 {
1682         return ki_modify_hf(msg, hexp, NULL, remove_hf_value_fixup,
1683                         insupddel_hf_value_f);
1684 }
1685
1686 static int assign_hf_value_fixup(void **param, int param_no)
1687 {
1688         int res = fixup_hname_str(param, param_no);
1689         if(res < 0)
1690                 return res;
1691         if(param_no == 1) {
1692                 if((((struct hname_data *)*param)->flags & HNF_ALL)
1693                                 && !((struct hname_data *)*param)->param.len) {
1694                         LM_ERR("asterisk not supported without param\n");
1695                         return E_CFG;
1696                 } else if((((struct hname_data *)*param)->flags & HNF_IDX) == 0
1697                                   || !((struct hname_data *)*param)->idx) {
1698                         ((struct hname_data *)*param)->idx = 1;
1699                         ((struct hname_data *)*param)->flags |= HNF_IDX;
1700                 }
1701                 if(((struct hname_data *)*param)->idx < -MAX_HF_VALUE_STACK) {
1702                         LM_ERR("index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
1703                         return E_CFG;
1704                 }
1705                 ((struct hname_data *)*param)->oper = hnoAssign;
1706         }
1707         return 0;
1708 }
1709
1710 static int ki_assign_hf_value(sip_msg_t *msg, str *hexp, str *val)
1711 {
1712         return ki_modify_hf(msg, hexp, val, assign_hf_value_fixup,
1713                         insupddel_hf_value_f);
1714 }
1715
1716 static int remove_hf_value2_fixup(void **param, int param_no)
1717 {
1718         int res = remove_hf_value_fixup(param, param_no);
1719         if(res < 0)
1720                 return res;
1721         if(param_no == 1) {
1722                 ((struct hname_data *)*param)->oper = hnoRemove2;
1723         }
1724         return 0;
1725 }
1726
1727 static int ki_remove_hf_value2(sip_msg_t *msg, str *hexp, str *val)
1728 {
1729         return ki_modify_hf(msg, hexp, val, remove_hf_value2_fixup,
1730                         insupddel_hf_value_f);
1731 }
1732
1733 static int assign_hf_value2_fixup(void **param, int param_no)
1734 {
1735         int res = assign_hf_value_fixup(param, param_no);
1736         if(res < 0)
1737                 return res;
1738         if(param_no == 1) {
1739                 ((struct hname_data *)*param)->oper = hnoAssign2;
1740         }
1741         return 0;
1742 }
1743
1744 static int ki_assign_hf_value2(sip_msg_t *msg, str *hexp, str *val)
1745 {
1746         return ki_modify_hf(msg, hexp, val, assign_hf_value2_fixup,
1747                         insupddel_hf_value_f);
1748 }
1749
1750 /* select implementation */
1751 static int sel_hf_value(str *res, select_t *s, struct sip_msg *msg)
1752 { /* dummy */
1753         return 0;
1754 }
1755
1756 #define _ALLOC_INC_SIZE 1024
1757
1758 static int sel_hf_value_name(str *res, select_t *s, struct sip_msg *msg)
1759 {
1760         struct hname_data *hname;
1761         struct hdr_field *hf;
1762         str val, hval1, hval2, huri, dummy_name;
1763         int r;
1764         if(!msg) {
1765                 struct hdr_field hdr;
1766                 char buf[50];
1767                 int i, n;
1768
1769                 if(s->params[1].type == SEL_PARAM_STR) {
1770                         hname = pkg_malloc(sizeof(*hname));
1771                         if(!hname)
1772                                 return E_OUT_OF_MEM;
1773                         memset(hname, 0, sizeof(*hname));
1774
1775                         for(i = s->params[1].v.s.len - 1; i > 0; i--) {
1776                                 if(s->params[1].v.s.s[i] == '_')
1777                                         s->params[1].v.s.s[i] = '-';
1778                         }
1779                         i = snprintf(buf, sizeof(buf) - 1, "%.*s: X\n",
1780                                         s->params[1].v.s.len, s->params[1].v.s.s);
1781                         buf[i] = 0;
1782
1783                         hname->hname = s->params[1].v.s;
1784                         parse_hname2(buf, buf + i, &hdr);
1785
1786                         if(hdr.type == HDR_ERROR_T) {
1787                                 pkg_free(hname);
1788                                 return E_CFG;
1789                         }
1790                         hname->htype = hdr.type;
1791
1792                         s->params[1].v.p = hname;
1793                         s->params[1].type = SEL_PARAM_PTR;
1794                 } else {
1795                         hname = s->params[1].v.p;
1796                 }
1797                 n = s->param_offset[select_level + 1]
1798                         - s->param_offset
1799                                           [select_level]; /* number of values before NESTED */
1800                 if(n > 2 && s->params[2].type == SEL_PARAM_INT) {
1801                         hname->idx = s->params[2].v.i;
1802                         hname->flags |= HNF_IDX;
1803                         if(hname->idx < -MAX_HF_VALUE_STACK) {
1804                                 LM_ERR("index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
1805                                 return E_CFG;
1806                         }
1807                         if(hname->idx == 0)
1808                                 hname->idx = 1;
1809                         i = 3;
1810                 } else {
1811                         i = 2;
1812                         hname->idx = 1;
1813                 }
1814                 if(n > i && s->params[i].type == SEL_PARAM_STR) {
1815                         hname->param = s->params[i].v.s;
1816                         for(i = hname->param.len - 1; i > 0; i--) {
1817                                 if(hname->param.s[i] == '_')
1818                                         hname->param.s[i] = '-';
1819                         }
1820                 }
1821                 s->params[1].v.p = hname;
1822                 s->params[1].type = SEL_PARAM_PTR;
1823                 hname->oper = hnoGetValue;
1824
1825                 return 0;
1826         }
1827
1828         res->len = 0;
1829         res->s = 0;
1830         hname = s->params[1].v.p;
1831
1832         switch(hname->oper) {
1833                 case hnoGetValueUri:
1834                         if(hname->flags & HNF_ALL || (hname->flags & HNF_IDX) == 0) {
1835                                 char *buf = NULL;
1836                                 int buf_len = 0;
1837
1838                                 hf = 0;
1839                                 do {
1840                                         r = find_next_hf(msg, hname, &hf);
1841                                         if(r < 0)
1842                                                 break;
1843                                         if(hf) {
1844                                                 char *p;
1845                                                 str huri;
1846                                                 hval2.len = 0;
1847                                                 p = hf->body.s;
1848                                                 do {
1849                                                         r = find_next_value(&p, hf->body.s + hf->body.len,
1850                                                                         &hval1, &hval2);
1851                                                         get_uri_and_skip_until_params(
1852                                                                         &hval1, &dummy_name, &huri);
1853                                                         if(huri.len) {
1854                                                                 /* TODO: normalize uri, lowercase except quoted params, add/strip < > */
1855                                                                 if(*huri.s == '<') {
1856                                                                         huri.s++;
1857                                                                         huri.len -= 2;
1858                                                                 }
1859                                                         }
1860                                                         if(res->len == 0) {
1861                                                                 *res = huri; /* first value, if is also last value then we don't need any buffer */
1862                                                         } else {
1863                                                                 if(buf) {
1864                                                                         if(res->len + huri.len + 1 > buf_len) {
1865                                                                                 buf_len = res->len + huri.len + 1
1866                                                                                                   + _ALLOC_INC_SIZE;
1867                                                                                 res->s = pkg_realloc(buf, buf_len);
1868                                                                                 if(!res->s) {
1869                                                                                         pkg_free(buf);
1870                                                                                         LM_ERR("cannot realloc buffer\n");
1871                                                                                         res->len = 0;
1872                                                                                         return E_OUT_OF_MEM;
1873                                                                                 }
1874                                                                                 buf = res->s;
1875                                                                         }
1876                                                                 } else {
1877                                                                         /* 2nd value */
1878                                                                         buf_len = res->len + huri.len + 1
1879                                                                                           + _ALLOC_INC_SIZE;
1880                                                                         buf = pkg_malloc(buf_len);
1881                                                                         if(!buf) {
1882                                                                                 LM_ERR("out of memory\n");
1883                                                                                 res->len = 0;
1884                                                                                 return E_OUT_OF_MEM;
1885                                                                         }
1886                                                                         /* copy 1st value */
1887                                                                         memcpy(buf, res->s, res->len);
1888                                                                         res->s = buf;
1889                                                                 }
1890                                                                 res->s[res->len] = ',';
1891                                                                 res->len++;
1892                                                                 if(huri.len) {
1893                                                                         memcpy(res->s + res->len, huri.s, huri.len);
1894                                                                         res->len += huri.len;
1895                                                                 }
1896                                                         }
1897
1898                                                 } while(r);
1899                                         }
1900                                 } while(hf);
1901                                 if(buf) {
1902                                         res->s = get_static_buffer(res->len);
1903                                         if(!res->s) {
1904                                                 pkg_free(buf);
1905                                                 res->len = 0;
1906                                                 LM_ERR("cannot allocate static buffer\n");
1907                                                 return E_OUT_OF_MEM;
1908                                         }
1909                                         memcpy(res->s, buf, res->len);
1910                                         pkg_free(buf);
1911                                 }
1912                         } else {
1913                                 r = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
1914                                 if(r > 0) {
1915                                         get_uri_and_skip_until_params(&hval1, &dummy_name, res);
1916                                         if(res->len && *res->s == '<') {
1917                                                 res->s++; /* strip < & > */
1918                                                 res->len -= 2;
1919                                         }
1920                                 }
1921                         }
1922                         break;
1923                 case hnoGetValueName:
1924                         if((hname->flags & HNF_ALL) == 0) {
1925                                 r = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
1926                                 if(r > 0) {
1927                                         get_uri_and_skip_until_params(&hval1, res, &dummy_name);
1928                                         if(res->len >= 2 && res->s[0] == '\"'
1929                                                         && res->s[res->len - 1] == '\"') {
1930                                                 res->s++; /* strip quotes */
1931                                                 res->len -= 2;
1932                                         }
1933                                 }
1934                         }
1935                         break;
1936                 case hnoGetValue:
1937                         if(hname->flags & HNF_ALL || (hname->flags & HNF_IDX) == 0) {
1938                                 char *buf = NULL;
1939                                 int buf_len = 0;
1940
1941                                 hf = 0;
1942                                 do {
1943                                         r = find_next_hf(msg, hname, &hf);
1944
1945                                         if(r < 0)
1946                                                 break;
1947                                         if(hf) {
1948                                                 char *p;
1949                                                 hval2.len = 0;
1950                                                 p = hf->body.s;
1951                                                 do {
1952                                                         r = find_next_value(&p, hf->body.s + hf->body.len,
1953                                                                         &hval1, &hval2);
1954                                                         if(res->len == 0) {
1955                                                                 *res = hval1; /* first value, if is also last value then we don't need any buffer */
1956                                                         } else {
1957                                                                 if(buf) {
1958                                                                         if(res->len + hval1.len + 1 > buf_len) {
1959                                                                                 buf_len = res->len + hval1.len + 1
1960                                                                                                   + _ALLOC_INC_SIZE;
1961                                                                                 res->s = pkg_realloc(buf, buf_len);
1962                                                                                 if(!res->s) {
1963                                                                                         pkg_free(buf);
1964                                                                                         LM_ERR("cannot realloc buffer\n");
1965                                                                                         res->len = 0;
1966                                                                                         return E_OUT_OF_MEM;
1967                                                                                 }
1968                                                                                 buf = res->s;
1969                                                                         }
1970                                                                 } else {
1971                                                                         /* 2nd value */
1972                                                                         buf_len = res->len + hval1.len + 1
1973                                                                                           + _ALLOC_INC_SIZE;
1974                                                                         buf = pkg_malloc(buf_len);
1975                                                                         if(!buf) {
1976                                                                                 LM_ERR("out of memory\n");
1977                                                                                 res->len = 0;
1978                                                                                 return E_OUT_OF_MEM;
1979                                                                         }
1980                                                                         /* copy 1st value */
1981                                                                         memcpy(buf, res->s, res->len);
1982                                                                         res->s = buf;
1983                                                                 }
1984                                                                 res->s[res->len] = ',';
1985                                                                 res->len++;
1986                                                                 if(hval1.len) {
1987                                                                         memcpy(res->s + res->len, hval1.s,
1988                                                                                         hval1.len);
1989                                                                         res->len += hval1.len;
1990                                                                 }
1991                                                         }
1992                                                 } while(r);
1993                                         }
1994                                 } while(hf);
1995                                 if(buf) {
1996                                         res->s = get_static_buffer(res->len);
1997                                         if(!res->s) {
1998                                                 pkg_free(buf);
1999                                                 res->len = 0;
2000                                                 LM_ERR("cannot allocate static buffer\n");
2001                                                 return E_OUT_OF_MEM;
2002                                         }
2003                                         memcpy(res->s, buf, res->len);
2004                                         pkg_free(buf);
2005                                 }
2006                         } else {
2007                                 r = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
2008                                 if(r > 0) {
2009                                         if(hname->param.len) {
2010                                                 str d1, d2;
2011                                                 get_uri_and_skip_until_params(
2012                                                                 &hval1, &dummy_name, &huri);
2013                                                 if(find_hf_value_param(hname, &hval1, &val, &d1, &d2)) {
2014                                                         *res = val;
2015                                                 }
2016                                         } else {
2017                                                 *res = hval1;
2018                                         }
2019                                 }
2020                         }
2021                         break;
2022                 case hnoGetValue2:
2023                         r = find_hf_value_idx(msg, hname, &hf, 0, 0);
2024                         if(r > 0) {
2025                                 if(hname->param.len) {
2026                                         str d1, d2;
2027                                         char c;
2028                                         if(find_hf_value2_param(
2029                                                            hname, &hf->body, &val, &d1, &d2, &c)) {
2030                                                 *res = val;
2031                                         }
2032                                 } else {
2033                                         *res = hf->body;
2034                                 }
2035                         }
2036                         break;
2037                 default:
2038                         break;
2039         }
2040         return 0;
2041 }
2042
2043 static int sel_hf_value_name_param_name(
2044                 str *res, select_t *s, struct sip_msg *msg)
2045 {
2046         return sel_hf_value_name(res, s, msg);
2047 }
2048
2049 static int sel_hf_value_name_param_name2(
2050                 str *res, select_t *s, struct sip_msg *msg)
2051 {
2052         if(!msg) { /* eliminate "param" level */
2053                 int n;
2054                 n = s->param_offset[select_level + 1] - s->param_offset[select_level];
2055                 s->params[n - 2] = s->params[n - 1];
2056         }
2057         return sel_hf_value_name(res, s, msg);
2058 }
2059
2060 static int sel_hf_value_name_uri(str *res, select_t *s, struct sip_msg *msg)
2061 {
2062         int r;
2063         r = sel_hf_value_name(res, s, msg);
2064         if(!msg && r == 0) {
2065                 ((struct hname_data *)s->params[1].v.p)->oper = hnoGetValueUri;
2066         }
2067         return r;
2068 }
2069
2070 static int sel_hf_value_name_name(str *res, select_t *s, struct sip_msg *msg)
2071 {
2072         int r;
2073         r = sel_hf_value_name(res, s, msg);
2074         if(!msg && r == 0) {
2075                 ((struct hname_data *)s->params[1].v.p)->oper = hnoGetValueName;
2076         }
2077         return r;
2078 }
2079
2080 static int sel_hf_value_exists(str *res, select_t *s, struct sip_msg *msg)
2081 { /* dummy */
2082         return 0;
2083 }
2084
2085 static int sel_hf_value_exists_param(str *res, select_t *s, struct sip_msg *msg)
2086 {
2087         static char ret_val[] = "01";
2088         int r;
2089
2090         if(!msg) {
2091                 r = sel_hf_value_name(res, s, msg);
2092                 if(r == 0)
2093                         ((struct hname_data *)s->params[1].v.p)->oper = hnoIsIncluded;
2094                 return r;
2095         }
2096         r = incexc_hf_value_str_f(msg, s->params[1].v.p, &s->params[2].v.s);
2097         res->s = &ret_val[r > 0];
2098         res->len = 1;
2099
2100         return 0;
2101 }
2102
2103 static int sel_hf_value2(str *res, select_t *s, struct sip_msg *msg)
2104 { /* dummy */
2105         return 0;
2106 }
2107
2108 static int sel_hf_value2_name(str *res, select_t *s, struct sip_msg *msg)
2109 {
2110         int r;
2111         r = sel_hf_value_name(res, s, msg);
2112         if(!msg && r == 0) {
2113                 ((struct hname_data *)s->params[1].v.p)->oper = hnoGetValue2;
2114         }
2115         return r;
2116 }
2117
2118 static int sel_hf_value2_name_param_name(
2119                 str *res, select_t *s, struct sip_msg *msg)
2120 {
2121         return sel_hf_value2_name(res, s, msg);
2122 }
2123
2124 SELECT_F(select_any_nameaddr)
2125 SELECT_F(select_any_uri)
2126 SELECT_F(select_anyheader_params)
2127
2128 select_row_t sel_declaration[] = {
2129                 {NULL, SEL_PARAM_STR, STR_STATIC_INIT("hf_value"), sel_hf_value,
2130                                 SEL_PARAM_EXPECTED},
2131
2132                 {sel_hf_value, SEL_PARAM_STR, STR_NULL, sel_hf_value_name,
2133                                 CONSUME_NEXT_INT | OPTIONAL | FIXUP_CALL},
2134                 {sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("param"),
2135                                 sel_hf_value_name_param_name2, CONSUME_NEXT_STR | FIXUP_CALL},
2136                 {sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("p"),
2137                                 sel_hf_value_name_param_name2, CONSUME_NEXT_STR | FIXUP_CALL},
2138                 {sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("uri"),
2139                                 sel_hf_value_name_uri, FIXUP_CALL},
2140                 {sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("name"),
2141                                 sel_hf_value_name_name, FIXUP_CALL},
2142                 {sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"),
2143                                 select_any_nameaddr,
2144                                 NESTED | CONSUME_NEXT_STR}, /* it duplicates param,p,name,... */
2145                 {sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("params"),
2146                                 select_anyheader_params, NESTED},
2147
2148                 {sel_hf_value_name_uri, SEL_PARAM_INT, STR_NULL, select_any_uri,
2149                                 NESTED},
2150                 {sel_hf_value_name, SEL_PARAM_STR, STR_NULL,
2151                                 sel_hf_value_name_param_name, FIXUP_CALL},
2152
2153                 {NULL, SEL_PARAM_STR, STR_STATIC_INIT("hf_value_exists"),
2154                                 sel_hf_value_exists, CONSUME_NEXT_STR | SEL_PARAM_EXPECTED},
2155                 {sel_hf_value_exists, SEL_PARAM_STR, STR_NULL,
2156                                 sel_hf_value_exists_param, FIXUP_CALL},
2157
2158                 {NULL, SEL_PARAM_STR, STR_STATIC_INIT("hf_value2"), sel_hf_value2,
2159                                 SEL_PARAM_EXPECTED},
2160                 {sel_hf_value2, SEL_PARAM_STR, STR_NULL, sel_hf_value2_name,
2161                                 CONSUME_NEXT_INT | OPTIONAL | FIXUP_CALL},
2162                 {sel_hf_value2_name, SEL_PARAM_STR, STR_STATIC_INIT("params"),
2163                                 select_anyheader_params, NESTED},
2164                 {sel_hf_value2_name, SEL_PARAM_STR, STR_NULL,
2165                                 sel_hf_value2_name_param_name, FIXUP_CALL},
2166                 {sel_hf_value2_name_param_name, SEL_PARAM_STR,
2167                                 STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED},
2168                 {sel_hf_value2_name_param_name, SEL_PARAM_STR, STR_STATIC_INIT("uri"),
2169                                 select_any_uri, NESTED},
2170
2171                 {NULL, SEL_PARAM_INT, STR_NULL, NULL, 0}
2172 };
2173
2174 /**
2175  *
2176  */
2177 /* clang-format off */
2178 static sr_kemi_t sr_kemi_textopsx_exports[] = {
2179         { str_init("textopsx"), str_init("msg_apply_changes"),
2180                 SR_KEMIP_INT, ki_msg_apply_changes,
2181                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
2182                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2183         },
2184         { str_init("textopsx"), str_init("msg_set_buffer"),
2185                 SR_KEMIP_INT, ki_msg_set_buffer,
2186                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2187                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2188         },
2189         { str_init("textopsx"), str_init("change_reply_status"),
2190                 SR_KEMIP_INT, ki_change_reply_status,
2191                 { SR_KEMIP_INT, SR_KEMIP_STR, SR_KEMIP_NONE,
2192                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2193         },
2194         { str_init("textopsx"), str_init("remove_body"),
2195                 SR_KEMIP_INT, ki_remove_body,
2196                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
2197                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2198         },
2199         { str_init("textopsx"), str_init("keep_hf"),
2200                 SR_KEMIP_INT, ki_keep_hf,
2201                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
2202                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2203         },
2204         { str_init("textopsx"), str_init("keep_hf_re"),
2205                 SR_KEMIP_INT, ki_keep_hf_re,
2206                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2207                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2208         },
2209         { str_init("textopsx"), str_init("fnmatch"),
2210                 SR_KEMIP_INT, ki_fnmatch,
2211                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2212                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2213         },
2214         { str_init("textopsx"), str_init("fnmatch_ex"),
2215                 SR_KEMIP_INT, ki_fnmatch_ex,
2216                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
2217                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2218         },
2219         { str_init("textopsx"), str_init("append_hf_value"),
2220                 SR_KEMIP_INT, ki_append_hf_value,
2221                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2222                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2223         },
2224         { str_init("textopsx"), str_init("insert_hf_value"),
2225                 SR_KEMIP_INT, ki_insert_hf_value,
2226                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2227                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2228         },
2229         { str_init("textopsx"), str_init("assign_hf_value"),
2230                 SR_KEMIP_INT, ki_assign_hf_value,
2231                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2232                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2233         },
2234         { str_init("textopsx"), str_init("assign_hf_value2"),
2235                 SR_KEMIP_INT, ki_assign_hf_value2,
2236                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2237                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2238         },
2239         { str_init("textopsx"), str_init("remove_hf_value"),
2240                 SR_KEMIP_INT, ki_remove_hf_value,
2241                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2242                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2243         },
2244         { str_init("textopsx"), str_init("remove_hf_value2"),
2245                 SR_KEMIP_INT, ki_remove_hf_value2,
2246                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2247                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2248         },
2249         { str_init("textopsx"), str_init("include_hf_value"),
2250                 SR_KEMIP_INT, ki_include_hf_value,
2251                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2252                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2253         },
2254         { str_init("textopsx"), str_init("exclude_hf_value"),
2255                 SR_KEMIP_INT, ki_exclude_hf_value,
2256                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2257                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2258         },
2259         { str_init("textopsx"), str_init("hf_value_exists"),
2260                 SR_KEMIP_INT, ki_hf_value_exists,
2261                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2262                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2263         },
2264
2265         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
2266 };
2267 /* clang-format on */
2268
2269 /**
2270  *
2271  */
2272 int mod_register(char *path, int *dlflags, void *p1, void *p2)
2273 {
2274         sr_kemi_modules_add(sr_kemi_textopsx_exports);
2275         return 0;
2276 }