textopsx: enable usage of msg_apply_changes() for sip replies
[sip-router] / modules / textopsx / textopsx.c
1 /**
2  *
3  * Copyright (C) 2001-2003 FhG Fokus
4  *
5  * This file is part of ser, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fnmatch.h>
31
32 #include "../../sr_module.h"
33 #include "../../dprint.h"
34 #include "../../data_lump.h"
35 #include "../../msg_translator.h"
36 #include "../../tcp_options.h"
37 #include "../../mod_fix.h"
38 #include "../../parser/parse_hname2.h"
39 #include "../../select.h"
40 #include "../../select_buf.h"
41
42
43 #include "api.h"
44
45 MODULE_VERSION
46
47 static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2);
48
49 static int change_reply_status_f(sip_msg_t*, char*, char*);
50 static int change_reply_status_fixup(void** param, int param_no);
51
52 static int w_keep_hf_f(sip_msg_t*, char*, char*);
53
54 static int w_fnmatch2_f(sip_msg_t*, char*, char*);
55 static int w_fnmatch3_f(sip_msg_t*, char*, char*, char*);
56 static int fixup_fnmatch(void** param, int param_no);
57
58 static int w_remove_body_f(struct sip_msg*, char*, char *);
59
60 static int incexc_hf_value_f(struct sip_msg* msg, char* , char *);
61 static int include_hf_value_fixup(void**, int);
62 static int exclude_hf_value_fixup(void**, int);
63 static int hf_value_exists_fixup(void**, int);
64
65 static int insupddel_hf_value_f(struct sip_msg* msg, char* _hname, char* _val);
66 static int append_hf_value_fixup(void** param, int param_no);
67 static int insert_hf_value_fixup(void** param, int param_no);
68 static int remove_hf_value_fixup(void** param, int param_no);
69 static int assign_hf_value_fixup(void** param, int param_no);
70 static int remove_hf_value2_fixup(void** param, int param_no);
71 static int assign_hf_value2_fixup(void** param, int param_no);
72
73 static int bind_textopsx(textopsx_api_t *tob);
74
75 static int mod_init(void);
76
77 extern select_row_t sel_declaration[];
78
79 /* cfg functions */
80 static cmd_export_t cmds[] = {
81         {"msg_apply_changes",    (cmd_function)msg_apply_changes_f,     0,
82                 0, REQUEST_ROUTE|ONREPLY_ROUTE },
83         {"change_reply_status",  change_reply_status_f,                 2,
84                 change_reply_status_fixup, ONREPLY_ROUTE },
85         {"remove_body",          (cmd_function)w_remove_body_f,         0,
86                 0, ANY_ROUTE },
87         {"keep_hf",              (cmd_function)w_keep_hf_f,             1,
88                 fixup_regexp_null, ANY_ROUTE },
89         {"fnmatch",              (cmd_function)w_fnmatch2_f,            2,
90                 fixup_fnmatch, ANY_ROUTE },
91         {"fnmatch",              (cmd_function)w_fnmatch3_f,            3,
92                 fixup_fnmatch, ANY_ROUTE },
93
94         {"append_hf_value",        insupddel_hf_value_f,         2, append_hf_value_fixup,
95                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
96         {"insert_hf_value",        insupddel_hf_value_f,         2, insert_hf_value_fixup,
97                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
98         {"remove_hf_value",        insupddel_hf_value_f,         1, remove_hf_value_fixup,
99                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
100         {"assign_hf_value",        insupddel_hf_value_f,         2, assign_hf_value_fixup,
101                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
102         {"remove_hf_value2",       insupddel_hf_value_f,         1, remove_hf_value2_fixup,
103                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
104         {"assign_hf_value2",       insupddel_hf_value_f,         2, assign_hf_value2_fixup,
105                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
106         {"include_hf_value", incexc_hf_value_f,      2, include_hf_value_fixup,
107                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
108         {"exclude_hf_value", incexc_hf_value_f,      2, exclude_hf_value_fixup,
109                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
110         {"hf_value_exists",  incexc_hf_value_f,      2, hf_value_exists_fixup,
111                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
112
113         {"bind_textopsx",        (cmd_function)bind_textopsx,           1,
114                 0, ANY_ROUTE },
115
116
117         {0,0,0,0,0}
118 };
119
120 /* module exports structure */
121 struct module_exports exports= {
122         "textopsx",
123         cmds, /* cfg functions */
124         0, /* RPC methods */
125         0, /* cfg parameters */
126         mod_init, /* initialization function */
127         0, /* response function */
128         0, /* destroy function */
129         0, /* on_cancel function */
130         0  /* per-child init function */
131 };
132
133
134 /**
135  * init module function
136  */
137 static int mod_init(void)
138 {
139 #ifdef USE_TCP
140         tcp_set_clone_rcvbuf(1);
141 #endif
142         register_select_table(sel_declaration);
143         return 0;
144 }
145
146 /**
147  *
148  */
149 static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2)
150 {
151         struct dest_info dst;
152         str obuf;
153         sip_msg_t tmp;
154
155         if(msg->first_line.type!=SIP_REPLY && get_route_type()!=REQUEST_ROUTE)
156         {
157                 LM_ERR("invalid usage - not in request route\n");
158                 return -1;
159         }
160
161         init_dest_info(&dst);
162         dst.proto = PROTO_UDP;
163         if(msg->first_line.type == SIP_REPLY) {
164                 obuf.s = generate_res_buf_from_sip_res(msg,
165                                 (unsigned int*)&obuf.len, BUILD_NO_VIA1_UPDATE);
166         } else {
167                 obuf.s = build_req_buf_from_sip_req(msg,
168                                 (unsigned int*)&obuf.len, &dst,
169                                 BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE);
170         }
171         if(obuf.s == NULL)
172         {
173                 LM_ERR("couldn't update msg buffer content\n");
174                 return -1;
175         }
176         if(obuf.len>=BUF_SIZE)
177         {
178                 LM_ERR("new buffer overflow (%d)\n", obuf.len);
179                 pkg_free(obuf.s);
180                 return -1;
181         }
182         /* temporary copy */
183         memcpy(&tmp, msg, sizeof(sip_msg_t));
184
185         /* reset dst uri and path vector to avoid freeing - restored later */
186         if(msg->dst_uri.s!=NULL)
187         {
188                 msg->dst_uri.s = NULL;
189                 msg->dst_uri.len = 0;
190         }
191         if(msg->path_vec.s!=NULL)
192         {
193                 msg->path_vec.s = NULL;
194                 msg->path_vec.len = 0;
195         }
196
197         /* free old msg structure */
198         free_sip_msg(msg);
199         memset(msg, 0, sizeof(sip_msg_t));
200
201         /* restore msg fields */
202         msg->buf                = tmp.buf;
203         msg->id                 = tmp.id;
204         msg->rcv                = tmp.rcv;
205         msg->set_global_address = tmp.set_global_address;
206         msg->set_global_port    = tmp.set_global_port;
207         msg->flags              = tmp.flags;
208         msg->msg_flags          = tmp.msg_flags;
209         msg->hash_index         = tmp.hash_index;
210         msg->force_send_socket  = tmp.force_send_socket;
211         msg->fwd_send_flags     = tmp.fwd_send_flags;
212         msg->rpl_send_flags     = tmp.rpl_send_flags;
213         msg->dst_uri            = tmp.dst_uri;
214         msg->path_vec           = tmp.path_vec;
215
216         memcpy(msg->buf, obuf.s, obuf.len);
217         msg->len = obuf.len;
218         msg->buf[msg->len] = '\0';
219
220         /* free new buffer - copied in the static buffer from old sip_msg_t */
221         pkg_free(obuf.s);
222
223         /* reparse the message */
224         LM_DBG("SIP message content updated - reparsing\n");
225         if (parse_msg(msg->buf, msg->len, msg)!=0){
226                 LM_ERR("parsing new sip message failed\n");
227                 return -1;
228         }
229
230         return 1;
231 }
232
233
234 /**
235  *
236  */
237 static int change_reply_status_fixup(void** param, int param_no)
238 {
239         if (param_no == 1) {
240                 return fixup_var_int_12(param, param_no);
241         } else if (param_no == 2)
242                 return fixup_var_pve_str_12(param, param_no);
243         else
244                 return 0;
245 }
246
247 /**
248  *
249  */
250 static int change_reply_status_f(struct sip_msg* msg, char* _code, char* _reason)
251 {
252         int     code;
253         str     reason;
254         struct lump     *l;
255         char    *ch;
256
257         if (get_int_fparam(&code, msg, (fparam_t*)_code)
258                 || get_str_fparam(&reason, msg, (fparam_t*)_reason)
259                 || (reason.len == 0)
260         ) {
261                 LOG(L_ERR, "ERROR: textops: cannot get parameter\n");
262                 return -1;
263         }
264
265         if ((code < 100) || (code > 699)) {
266                 LOG(L_ERR, "ERROR: textops: wrong status code: %d\n",
267                                 code);
268                 return -1;
269         }
270
271         if (((code < 300) || (msg->REPLY_STATUS < 300))
272                 && (code/100 != msg->REPLY_STATUS/100)
273         ) {
274                 LOG(L_ERR, "ERROR: textops: the class of provisional or "
275                         "positive final replies cannot be changed\n");
276                 return -1;
277         }
278
279         /* rewrite the status code directly in the message buffer */
280         msg->first_line.u.reply.statuscode = code;
281         msg->first_line.u.reply.status.s[2] = code % 10 + '0'; code /= 10;
282         msg->first_line.u.reply.status.s[1] = code % 10 + '0'; code /= 10;
283         msg->first_line.u.reply.status.s[0] = code + '0';
284
285         l = del_lump(msg,
286                 msg->first_line.u.reply.reason.s - msg->buf,
287                 msg->first_line.u.reply.reason.len,
288                 0);
289         if (!l) {
290                 LOG(L_ERR, "ERROR: textops(): Failed to add del lump\n");
291                 return -1;
292         }
293         /* clone the reason phrase, the lumps need to be pkg allocated */
294         ch = (char *)pkg_malloc(reason.len);
295         if (!ch) {
296                 LOG(L_ERR, "ERROR: textops: Not enough memory\n");
297                 return -1;
298         }
299         memcpy(ch, reason.s, reason.len);
300         if (insert_new_lump_after(l, ch, reason.len, 0)==0){
301                 LOG(L_ERR, "ERROR: textops: failed to add new lump: %.*s\n",
302                         reason.len, ch);
303                 pkg_free(ch);
304                 return -1;
305         }
306
307         return 1;
308 }
309
310
311 /**
312  *
313  */
314 static int w_remove_body_f(struct sip_msg *msg, char *p1, char *p2)
315 {
316         str body = {0,0};
317
318         body.len = 0;
319         body.s = get_body(msg);
320         if (body.s==0)
321         {
322                 LM_DBG("no body in the message\n");
323                 return 1;
324         }
325         body.len = msg->buf + msg->len - body.s;
326         if (body.len<=0)
327         {
328                 LM_DBG("empty body in the message\n");
329                 return 1;
330         }
331         if(del_lump(msg, body.s - msg->buf, body.len, 0) == 0)
332         {
333                 LM_ERR("cannot remove body\n");
334                 return -1;
335         }
336         return 1;
337 }
338
339
340 /**
341  *
342  */
343 static int w_keep_hf_f(struct sip_msg* msg, char* key, char* foo)
344 {
345         struct hdr_field *hf;
346         regex_t *re;
347         regmatch_t pmatch;
348         char c;
349         struct lump* l;
350
351         re = (regex_t*)key;
352
353         /* we need to be sure we have seen all HFs */
354         parse_headers(msg, HDR_EOH_F, 0);
355         for (hf=msg->headers; hf; hf=hf->next)
356         {
357                 switch(hf->type) {
358                         case HDR_FROM_T:
359                         case HDR_TO_T:
360                         case HDR_CALLID_T:
361                         case HDR_CSEQ_T:
362                         case HDR_VIA_T:
363                         case HDR_VIA2_T:
364                         case HDR_CONTACT_T:
365                         case HDR_CONTENTLENGTH_T:
366                         case HDR_CONTENTTYPE_T:
367                         case HDR_ROUTE_T:
368                         case HDR_RECORDROUTE_T:
369                         case HDR_MAXFORWARDS_T:
370                                 continue;
371                         default:
372                                 ;
373                 }
374
375                 c = hf->name.s[hf->name.len];
376                 hf->name.s[hf->name.len] = '\0';
377                 if (regexec(re, hf->name.s, 1, &pmatch, 0)!=0)
378                 {
379                         /* no match => remove */
380                         hf->name.s[hf->name.len] = c;
381                         l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
382                         if (l==0)
383                         {
384                                 LM_ERR("cannot remove header\n");
385                                 return -1;
386                         }
387                 } else {
388                         hf->name.s[hf->name.len] = c;
389                 }
390         }
391
392         return -1;
393 }
394
395 /**
396  *
397  */
398 static int w_fnmatch(str *val, str *match, str *flags)
399 {
400         int i;
401         i = 0;
402 #ifdef FNM_CASEFOLD
403         if(flags && (flags->s[0]=='i' || flags->s[0]=='I'))
404                 i = FNM_CASEFOLD;
405 #endif
406         if(fnmatch(match->s, val->s, i)==0)
407                 return 0;
408         return -1;
409 }
410
411 /**
412  *
413  */
414 static int w_fnmatch2_f(sip_msg_t *msg, char *val, char *match)
415 {
416         str sval;
417         str smatch;
418         if(get_str_fparam(&sval, msg, (fparam_t*)val)<0
419                         || get_str_fparam(&smatch, msg, (fparam_t*)match)<0)
420         {
421                 LM_ERR("invalid parameters");
422                 return -1;
423         }
424         if(w_fnmatch(&sval, &smatch, NULL)<0)
425                 return -1;
426         return 1;
427 }
428
429 /**
430  *
431  */
432 static int w_fnmatch3_f(sip_msg_t *msg, char *val, char *match, char *flags)
433 {
434         str sval;
435         str smatch;
436         str sflags;
437         if(get_str_fparam(&sval, msg, (fparam_t*)val)<0
438                         || get_str_fparam(&smatch, msg, (fparam_t*)match)<0
439                         || get_str_fparam(&sflags, msg, (fparam_t*)flags)<0)
440         {
441                 LM_ERR("invalid parameters");
442                 return -1;
443         }
444         if(w_fnmatch(&sval, &smatch, &sflags)<0)
445                 return -1;
446         return 1;
447 }
448
449 /**
450  *
451  */
452 static int fixup_fnmatch(void** param, int param_no)
453 {
454         if (param_no == 1) {
455                 return fixup_var_pve_12(param, param_no);
456         } else if (param_no == 2) {
457                 return fixup_var_pve_12(param, param_no);
458         } else if (param_no == 3) {
459                 return fixup_var_pve_12(param, param_no);
460         } else {
461                 return 0;
462         }
463
464 }
465
466 /*
467  * Function to load the textops api.
468  */
469 static int bind_textopsx(textopsx_api_t *tob){
470         if(tob==NULL){
471                 LM_WARN("textopsx_binds: Cannot load textopsx API into a NULL pointer\n");
472                 return -1;
473         }
474         tob->msg_apply_changes = msg_apply_changes_f;
475         return 0;
476 }
477
478
479 /**
480  * functions operating on header value
481  */
482 #define HNF_ALL 0x01
483 #define HNF_IDX 0x02
484
485 #define MAX_HF_VALUE_STACK 10
486
487 enum {hnoInsert, hnoAppend, hnoAssign, hnoRemove, hnoInclude, hnoExclude, hnoIsIncluded, hnoGetValue, hnoGetValueUri, hnoGetValueName, hnoRemove2, hnoAssign2, hnoGetValue2};
488
489 struct hname_data {
490         int oper;
491         int htype;
492         str hname;
493         int flags;
494         int idx;
495         str param;
496 };
497
498 #define is_space(_p) ((_p) == '\t' || (_p) == '\n' || (_p) == '\r' || (_p) == ' ')
499
500 #define eat_spaces(_p) \
501         while( is_space(*(_p)) ){\
502         (_p)++;}
503
504 #define is_alphanum(_p) (((_p) >= 'a' && (_p) <= 'z') || ((_p) >= 'A' && (_p) <= 'Z') || ((_p) >= '0' && (_p) <= '9') || (_p) == '_' || (_p) == '-')
505
506 #define eat_while_alphanum(_p) \
507         while ( is_alphanum(*(_p)) ) {\
508                 (_p)++; }
509
510 static int fixup_hvalue_param(void** param, int param_no) {
511         return fixup_spve_null(param, 1);
512 }
513
514 static int eval_hvalue_param(sip_msg_t *msg, gparam_t *val, str *s) {
515         if(fixup_get_svalue(msg, val, s)<0) {
516                 LM_ERR("could not get string param value\n");
517                 return E_UNSPEC;
518         }
519         return 1;
520 }
521
522 /* parse:  hname [ ([] | [*] | [number]) ] [ "." param ] */
523 static int fixup_hname_param(char *hname, struct hname_data** h) {
524         struct hdr_field hdr;
525         char *savep, savec;
526
527         *h = pkg_malloc(sizeof(**h));
528         if (!*h) return E_OUT_OF_MEM;
529         memset(*h, 0, sizeof(**h));
530
531         memset(&hdr, 0, sizeof(hdr));
532         eat_spaces(hname);
533         (*h)->hname.s = hname;
534         savep = hname;
535         eat_while_alphanum(hname);
536         (*h)->hname.len = hname - (*h)->hname.s;
537         savec = *hname;
538         *hname = ':';
539         parse_hname2((*h)->hname.s, (*h)->hname.s+(*h)->hname.len+3, &hdr);
540         *hname = savec;
541
542         if (hdr.type == HDR_ERROR_T) goto err;
543         (*h)->htype = hdr.type;
544
545         eat_spaces(hname);
546         savep = hname;
547         if (*hname == '[') {
548                 hname++;
549                 eat_spaces(hname);
550                 savep = hname;
551                 (*h)->flags |= HNF_IDX;
552                 if (*hname == '*') {
553                         (*h)->flags |= HNF_ALL;
554                         hname++;
555                 }
556                 else if (*hname != ']') {
557                         char* c;
558                         (*h)->idx = strtol(hname, &c, 10);
559                         if (hname == c) goto err;
560                         hname = c;
561                 }
562                 eat_spaces(hname);
563                 savep = hname;
564                 if (*hname != ']') goto err;
565                 hname++;
566         }
567         eat_spaces(hname);
568         savep = hname;
569         if (*hname == '.') {
570                 hname++;
571                 eat_spaces(hname);
572                 savep = hname;
573                 (*h)->param.s = hname;
574                 eat_while_alphanum(hname);
575                 (*h)->param.len = hname-(*h)->param.s;
576                 if ((*h)->param.len == 0) goto err;
577         }
578         else {
579                 (*h)->param.s = hname;
580         }
581         savep = hname;
582         if (*hname != '\0') goto err;
583         (*h)->hname.s[(*h)->hname.len] = '\0';
584         (*h)->param.s[(*h)->param.len] = '\0';
585         return 0;
586 err:
587         pkg_free(*h);
588         LOG(L_ERR, "ERROR: textops: cannot parse header near '%s'\n", savep);
589         return E_CFG;
590 }
591
592 static int fixup_hname_str(void** param, int param_no) {
593         if (param_no == 1) {
594                 struct hname_data* h;
595                 int res = fixup_hname_param(*param, &h);
596                 if (res < 0) return res;
597                 *param = h;
598         }
599         else if (param_no == 2) {
600                 return fixup_hvalue_param(param, param_no);
601         }
602         return 0;
603 }
604
605
606 static int find_next_hf(struct sip_msg* msg, struct hname_data* hname, struct hdr_field** hf) {
607         if (!*hf) {
608                 if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
609                         LOG(L_ERR, "ERROR: textops: find_next_hf: Error while parsing message\n");
610                         return -1;
611                 }
612                 *hf = msg->headers;
613         }
614         else {
615                 *hf = (*hf)->next;
616         }
617         for (; *hf; *hf = (*hf)->next) {
618                 if (hname->htype == HDR_OTHER_T) {
619                         if ((*hf)->name.len==hname->hname.len && strncasecmp((*hf)->name.s, hname->hname.s, (*hf)->name.len)==0)
620                                 return 1;
621                 }
622                 else if (hname->htype == (*hf)->type) {
623                         return 1;
624                 }
625         }
626         return 0;
627 }
628
629 static int find_next_value(char** start, char* end, str* val, str* lump_val) {
630         int quoted = 0;
631         lump_val->s = *start;
632         while (*start < end && is_space(**start) ) (*start)++;
633         val->s = *start;
634         while ( *start < end && (**start != ',' || quoted) ) {
635                 if (**start == '\"' && (!quoted || (*start)[-1]!='\\') )
636                         quoted = ~quoted;
637                 (*start)++;
638         }
639         val->len = *start - val->s;
640         while (val->len > 0 && is_space(val->s[val->len-1])) val->len--;
641 /* we cannot automatically strip quotes!!! an example why: "name" <sip:ssss>;param="bar" 
642         if (val->len >= 2 && val->s[0] == '\"' && val->s[val->len-1] == '\"') {
643                 val->s++;
644                 val->len -= 2;
645         }
646 */
647         while (*start < end && **start != ',') (*start)++;
648         if (*start < end) {
649                 (*start)++;
650         }
651         lump_val->len = *start - lump_val->s;
652         return (*start < end);
653 }
654
655 static void adjust_lump_val_for_delete(struct hdr_field* hf, str* lump_val) {
656         if ( lump_val->s+lump_val->len == hf->body.s+hf->body.len ) {
657                 if (lump_val->s > hf->body.s) {
658                 /* in case if is it last value in header save position of last delimiter to remove it with rightmost value */
659                         lump_val->s--;
660                         lump_val->len++;
661                 }
662         }
663 }
664
665 static int find_hf_value_idx(struct sip_msg* msg, struct hname_data* hname, struct hdr_field** hf, str* val, str* lump_val) {
666         int res;
667         char *p;
668         if ( hname->flags & HNF_ALL || hname->idx == 0) return -1;
669         *hf = 0;
670         if (hname->idx > 0) {
671                 int idx;
672                 idx = hname->idx;
673                 do {
674                         res = find_next_hf(msg, hname, hf);
675                         if (res < 0) return -1;
676                         if (*hf) {
677                                 if (val) {
678                                         lump_val->len = 0;
679                                         p = (*hf)->body.s;
680                                         do {
681                                                 res = find_next_value(&p, (*hf)->body.s+(*hf)->body.len, val, lump_val);
682                                                 idx--;
683                                         } while (res && idx);
684                                 }
685                                 else {
686                                         idx--;
687                                 }
688                         }
689                 } while (*hf && idx);
690         }
691         else if (hname->idx < 0) {  /* search from the bottom */
692                 struct hf_value_stack {
693                         str val, lump_val;
694                         struct hdr_field* hf;
695                 } stack[MAX_HF_VALUE_STACK];
696                 int stack_pos, stack_num;
697
698                 if ( -hname->idx > MAX_HF_VALUE_STACK ) return -1;
699                 stack_pos = stack_num = 0;
700                 do {
701                         res = find_next_hf(msg, hname, hf);
702                         if (res < 0) return -1;
703                         if (*hf) {
704                                 stack[stack_pos].lump_val.len = 0;
705                                 p = (*hf)->body.s;
706                                 do {
707                                         stack[stack_pos].hf = *hf;
708                                         if (val)
709                                                 res = find_next_value(&p, (*hf)->body.s+(*hf)->body.len, &stack[stack_pos].val, &stack[stack_pos].lump_val);
710                                         else
711                                                 res = 0;
712                                         stack_pos++;
713                                         if (stack_pos >= MAX_HF_VALUE_STACK)
714                                                 stack_pos = 0;
715                                         if (stack_num < MAX_HF_VALUE_STACK)
716                                                 stack_num++;
717
718                                 } while (res);
719                         }
720                 } while (*hf);
721
722                 if (-hname->idx <= stack_num) {
723                         stack_pos += hname->idx;
724                         if (stack_pos < 0)
725                                 stack_pos += MAX_HF_VALUE_STACK;
726                         *hf = stack[stack_pos].hf;
727                         if (val) {
728                                 *val = stack[stack_pos].val;
729                                 *lump_val = stack[stack_pos].lump_val;
730                         }
731                 }
732                 else {
733                         *hf = 0;
734                 }
735         }
736         else
737                 return -1;
738         return *hf?1:0;
739 }
740
741 static int find_hf_value_param(struct hname_data* hname, str* param_area, str* value, str* lump_upd, str* lump_del) {
742         int i, j, found;
743
744         i = 0;
745         while (1) {
746                 lump_del->s = param_area->s + i;
747                 for (; i < param_area->len && is_space(param_area->s[i]); i++);
748                 if (i < param_area->len && param_area->s[i] == ';') {   /* found a param ? */
749                         i++;
750                         for (; i < param_area->len && is_space(param_area->s[i]); i++);
751                         j = i;
752                         for (; i < param_area->len && !is_space(param_area->s[i]) && param_area->s[i]!='=' && param_area->s[i]!=';'; i++);
753
754                         found = hname->param.len == i-j && !strncasecmp(hname->param.s, param_area->s+j, i-j);
755                         lump_upd->s = param_area->s+i;
756                         value->s = param_area->s+i;
757                         value->len = 0;
758                         for (; i < param_area->len && is_space(param_area->s[i]); i++);
759                         if (i < param_area->len && param_area->s[i]=='=') {
760                                 i++;
761                                 for (; i < param_area->len && is_space(param_area->s[i]); i++);
762                                 value->s = param_area->s+i;
763                                 if (i < param_area->len) {
764                                         if (param_area->s[i]=='\"') {
765                                                 i++;
766                                                 value->s++;
767                                                 for (; i<param_area->len; i++) {
768                                                         if (param_area->s[i]=='\"') {
769                                                                 i++;
770                                                                 break;
771                                                         }
772                                                         value->len++;
773                                                 }
774                                         }
775                                         else {
776                                                 for (; i<param_area->len && !is_space(param_area->s[i]) && param_area->s[i]!=';'; i++, value->len++);
777                                         }
778                                 }
779                         }
780                         if (found) {
781                                 lump_del->len = param_area->s+i - lump_del->s;
782                                 lump_upd->len = param_area->s+i - lump_upd->s;
783                                 return 1;
784                         }
785                 }
786                 else { /* not found, return last correct position, should be end of param area */
787                         lump_del->len = 0;
788                         return 0;
789                 }
790         }
791 }
792
793 /* parse:  something param_name=param_value something [ "," something param_name="param_value" ....]
794  * 'something' is required by Authenticate
795  */
796 static int find_hf_value2_param(struct hname_data* hname, str* param_area, str* value, str* lump_upd, str* lump_del, char* delim) {
797         int i, j, k, found, comma_flag;
798
799         i = 0;
800         *delim = 0;
801         lump_del->len = 0;
802         while (i < param_area->len) {
803
804                 lump_del->s = param_area->s + i;
805                 while (i<param_area->len && is_space(param_area->s[i])) i++;
806                 comma_flag = i < param_area->len && param_area->s[i] == ',';
807                 if (comma_flag) i++;
808                 while (i<param_area->len && is_space(param_area->s[i])) i++;
809
810                 if (i < param_area->len && is_alphanum(param_area->s[i])) {     /* found a param name ? */
811                         j = i;
812                         if (!*delim) *delim = ' ';
813                         while (i<param_area->len && is_alphanum(param_area->s[i])) i++;
814
815                         k = i;
816                         while (i<param_area->len && is_space(param_area->s[i])) i++;
817                         lump_upd->s = param_area->s + i;
818                         if (i < param_area->len && param_area->s[i] == '=') {   /* if equal then it's the param */
819                                 *delim = ',';
820                                 i++;
821                                 found = hname->param.len == k-j && !strncasecmp(hname->param.s, param_area->s+j, k-j);
822                                 while (i<param_area->len && is_space(param_area->s[i])) i++;
823
824                                 value->s = param_area->s+i;
825                                 value->len = 0;
826                                 if (i < param_area->len) {
827                                         if (param_area->s[i]=='\"') {
828                                                 i++;
829                                                 value->s++;
830                                                 for (; i<param_area->len; i++) {
831                                                         if (param_area->s[i]=='\"') {
832                                                                 i++;
833                                                                 break;
834                                                         }
835                                                         value->len++;
836                                                 }
837                                         }
838                                         else {
839                                                 for (; i<param_area->len && !is_space(param_area->s[i]) && param_area->s[i]!=','; i++, value->len++);
840                                         }
841                                 }
842                                 if (found) {
843                                         lump_upd->len = param_area->s+i - lump_upd->s;
844                                         lump_del->len = param_area->s+i - lump_del->s;
845
846                                         while (i<param_area->len && is_space(param_area->s[i])) i++;
847
848                                         if (!comma_flag && i < param_area->len && param_area->s[i]==',') {
849                                                 i++;
850                                                 lump_del->len = param_area->s+i - lump_del->s;
851                                         }
852                                         return 1;
853                                 }
854                         }
855                         while (i<param_area->len && is_space(param_area->s[i])) i++;
856                 }
857                 else {
858                         while (i<param_area->len && !is_space(param_area->s[i]) && !param_area->s[i]!=',') i++;
859                 }
860         }
861         lump_del->s = param_area->s + i;
862         return 0;
863 }
864
865 static int insert_header_lump(struct sip_msg* msg, char* msg_position, int lump_before, str* hname, str *val) {
866         struct lump* anchor;
867         char *s;
868         int len;
869
870         anchor = anchor_lump(msg, msg_position - msg->buf, 0, 0);
871         if (anchor == 0) {
872                 LOG(L_ERR, "ERROR: textops: insert_header_lump(): Can't get anchor\n");
873                 return -1;
874         }
875
876         len=hname->len+2+val->len+2;
877
878         s = (char*)pkg_malloc(len);
879         if (!s) {
880                 LOG(L_ERR, "ERROR: textops: insert_header_lump(): not enough memory\n");
881                 return -1;
882         }
883
884         memcpy(s, hname->s, hname->len);
885         s[hname->len] = ':';
886         s[hname->len+1] = ' ';
887         memcpy(s+hname->len+2, val->s, val->len);
888         s[hname->len+2+val->len] = '\r';
889         s[hname->len+2+val->len+1] = '\n';
890
891         if ( (lump_before?insert_new_lump_before(anchor, s, len, 0):insert_new_lump_after(anchor, s, len, 0)) == 0) {
892                 LOG(L_ERR, "ERROR: textops: insert_header_lump(): Can't insert lump\n");
893                 pkg_free(s);
894                 return -1;
895         }
896         return 1;
897 }
898
899 static int insert_value_lump(struct sip_msg* msg, struct hdr_field* hf, char* msg_position, int lump_before, str *val) {
900         struct lump* anchor;
901         char *s;
902         int len;
903
904         anchor = anchor_lump(msg, msg_position - msg->buf, 0, 0);
905         if (anchor == 0) {
906                 LOG(L_ERR, "ERROR: textops: insert_value_lump(): Can't get anchor\n");
907                 return -1;
908         }
909
910         len=val->len+1;
911
912         s = (char*)pkg_malloc(len);
913         if (!s) {
914                 LOG(L_ERR, "ERROR: textops: insert_value_lump(): not enough memory\n");
915                 return -1;
916         }
917
918         if (!hf) {
919                 memcpy(s, val->s, val->len);
920                 len--;
921         }
922         else if (msg_position == hf->body.s+hf->body.len) {
923                 s[0] = ',';
924                 memcpy(s+1, val->s, val->len);
925         }
926         else {
927                 memcpy(s, val->s, val->len);
928                 s[val->len] = ',';
929         }
930         if ( (lump_before?insert_new_lump_before(anchor, s, len, 0):insert_new_lump_after(anchor, s, len, 0)) == 0) {
931                 LOG(L_ERR, "ERROR: textops: insert_value_lump(): Can't insert lump\n");
932                 pkg_free(s);
933                 return -1;
934         }
935         return 1;
936 }
937
938 static int delete_value_lump(struct sip_msg* msg, struct hdr_field* hf, str *val) {
939         struct lump* l;
940         /* TODO: check already existing lumps */
941         if (hf && val->s == hf->body.s && val->len == hf->body.len)     /* check if remove whole haeder? */
942                 l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
943         else
944                 l=del_lump(msg, val->s-msg->buf, val->len, 0);
945         if (l==0) {
946                 LOG(L_ERR, "ERROR: textops: delete_value_lump: not enough memory\n");
947                 return -1;
948         }
949         return 1;
950 }
951
952 static int incexc_hf_value_str_f(struct sip_msg* msg, char* _hname, str* _pval) {
953         struct hname_data* hname = (void*) _hname;
954         struct hdr_field* hf, *lump_hf;
955         str val, hval1, hval2;
956         char *p;
957         int res;
958
959         val = *_pval;
960         if (!val.len) return -1;
961         hf = 0;
962         lump_hf = 0;
963         while (1) {
964                 if (find_next_hf(msg, hname, &hf) < 0) return -1;
965                 if (!hf) break;
966                 hval2.len = 0;
967                 p = hf->body.s;
968                 do {
969                         res = find_next_value(&p, hf->body.s+hf->body.len, &hval1, &hval2);
970                         if (hval1.len && val.len == hval1.len && strncasecmp(val.s, hval1.s, val.len) == 0) {
971                                 switch (hname->oper) {
972                                         case hnoIsIncluded:
973                                         case hnoInclude:
974                                                 return 1;
975                                         case hnoExclude:
976                                                 adjust_lump_val_for_delete(hf, &hval2);
977                                                 delete_value_lump(msg, hf, &hval2);
978                                         default:
979                                                 break;
980                                 }
981                         }
982                 } while (res);
983                 switch (hname->oper) {
984                         case hnoInclude:
985                                 if (!lump_hf) {
986                                         lump_hf = hf;
987                                 }
988                                 break;
989                         default:
990                                 break;
991                 }
992         }
993         switch (hname->oper) {
994                 case hnoIsIncluded:
995                         return -1;
996                 case hnoInclude:
997                         if (lump_hf)
998                                 return insert_value_lump(msg, lump_hf, lump_hf->body.s+lump_hf->body.len, 1, &val);
999                         else
1000                                 return insert_header_lump(msg, msg->unparsed, 1, &hname->hname, &val);
1001                 default:
1002                         return 1;
1003         }
1004 }
1005
1006 static int incexc_hf_value_f(struct sip_msg* msg, char* _hname, char* _val)
1007 {
1008         str val;
1009         int res;
1010         
1011         res = eval_hvalue_param(msg, (void*) _val, &val);
1012         
1013         if (res < 0) return res;
1014         if (!val.len) return -1;
1015
1016         return incexc_hf_value_str_f(msg, _hname, &val);
1017 }
1018
1019 #define INCEXC_HF_VALUE_FIXUP(_func,_oper) \
1020 static int _func (void** param, int param_no) {\
1021         char* p = *param; \
1022         int res=fixup_hname_str(param, param_no); \
1023         if (res < 0) return res; \
1024         if (param_no == 1) {\
1025                 if ( ((struct hname_data*)*param)->flags & HNF_IDX || ((struct hname_data*)*param)->param.len ) { \
1026                         LOG(L_ERR, "ERROR: textops: neither index nor param may be specified in '%s'\n", p);\
1027                         return E_CFG;\
1028                 }\
1029                 ((struct hname_data*)*param)->oper = _oper;\
1030         }\
1031         return 0;\
1032 }
1033
1034 INCEXC_HF_VALUE_FIXUP(include_hf_value_fixup, hnoInclude)
1035 INCEXC_HF_VALUE_FIXUP(exclude_hf_value_fixup, hnoExclude)
1036 INCEXC_HF_VALUE_FIXUP(hf_value_exists_fixup, hnoIsIncluded)
1037
1038 static void get_uri_and_skip_until_params(str *param_area, str *name, str *uri) {
1039         int i, quoted, uri_pos, uri_done;
1040
1041         name->len = 0;
1042         uri->len = 0;
1043         uri_done = 0;
1044         name->s = param_area->s;
1045         for (i=0; i<param_area->len && param_area->s[i]!=';'; ) {       /* [ *(token LSW)/quoted-string ] "<" addr-spec ">" | addr-spec */
1046                 /* skip name */
1047                 for (quoted=0, uri_pos=i; i<param_area->len; i++) {
1048                         if (!quoted) {
1049                                 if (param_area->s[i] == '\"') {
1050                                         quoted = 1;
1051                                         uri_pos = -1;
1052                                 }
1053                                 else if (param_area->s[i] == '<' || param_area->s[i] == ';' || is_space(param_area->s[i])) break;
1054                         }
1055                         else if (param_area->s[i] == '\"' && param_area->s[i-1] != '\\') quoted = 0;
1056                 }
1057                 if (!name->len)
1058                         name->len = param_area->s+i-name->s;
1059                 if (uri_pos >= 0 && !uri_done) {
1060                         uri->s = param_area->s+uri_pos;
1061                         uri->len = param_area->s+i-uri->s;
1062                 }
1063                 /* skip uri */
1064                 while (i<param_area->len && is_space(param_area->s[i])) i++;
1065                 if (i<param_area->len && param_area->s[i]=='<') {
1066                         uri->s = param_area->s+i;
1067                         uri->len = 0;
1068                         for (quoted=0; i<param_area->len; i++) {
1069                                 if (!quoted) {
1070                                         if (param_area->s[i] == '\"') quoted = 1;
1071                                         else if (param_area->s[i] == '>') {
1072                                                 uri->len = param_area->s+i-uri->s+1;
1073                                                 uri_done = 1;
1074                                                 break;
1075                                         }
1076                                 }
1077                                 else if (param_area->s[i] == '\"' && param_area->s[i-1] != '\\') quoted = 0;
1078                         }
1079                 }
1080         }
1081         param_area->s+= i;
1082         param_area->len-= i;
1083         if (uri->s == name->s)
1084                 name->len = 0;
1085 }
1086
1087 static int assign_hf_do_lumping(struct sip_msg* msg,struct hdr_field* hf, struct hname_data* hname, str* value, int upd_del_fl, str* lump_upd, str* lump_del, char delim) {
1088         int len, i;
1089         char *s;
1090         struct lump* anchor;
1091
1092         if (upd_del_fl) {
1093                 len = value?lump_upd->len:lump_del->len;
1094                 if (len > 0) {
1095                         if (!del_lump(msg, (value?lump_upd->s:lump_del->s)-msg->buf, len, 0)) {
1096                                 LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: not enough memory\n");
1097                                 return -1;
1098                         }
1099                 }
1100                 if (value && value->len) {
1101                         anchor = anchor_lump(msg, lump_upd->s - msg->buf, 0, 0);
1102                         if (anchor == 0) {
1103                                 LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: Can't get anchor\n");
1104                                 return -1;
1105                         }
1106
1107                         len = 1+value->len;
1108                         s = pkg_malloc(len);
1109                         if (!s) {
1110                                 LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: not enough memory\n");
1111                                 return -1;
1112                         }
1113                         s[0]='=';
1114                         memcpy(s+1, value->s, value->len);
1115                         if ( (insert_new_lump_before(anchor, s, len, 0)) == 0) {
1116                                 LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: Can't insert lump\n");
1117                                 pkg_free(s);
1118                                 return -1;
1119                         }
1120                 }
1121         }
1122         else {
1123                 if (!value) return -1;
1124
1125                 anchor = anchor_lump(msg, lump_del->s - msg->buf, 0, 0);
1126                 if (anchor == 0) {
1127                         LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: Can't get anchor\n");
1128                         return -1;
1129                 }
1130
1131                 len = 1+hname->param.len+(value->len?value->len+1:0);
1132                 s = pkg_malloc(len);
1133                 if (!s) {
1134                         LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: not enough memory\n");
1135                         return -1;
1136                 }
1137                 if (delim) {
1138                         s[0] = delim;
1139                         i = 1;
1140                 }
1141                 else {
1142                         i = 0;
1143                         len--;
1144                 }
1145                 memcpy(s+i, hname->param.s, hname->param.len);
1146                 if (value->len) {
1147                         s[hname->param.len+i]='=';
1148                         memcpy(s+i+hname->param.len+1, value->s, value->len);
1149                 }
1150
1151                 if ( (insert_new_lump_before(anchor, s, len, 0)) == 0) {
1152                         LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: Can't insert lump\n");
1153                         pkg_free(s);
1154                         return -1;
1155                 }
1156         }
1157         return 1;
1158 }
1159
1160
1161 static int assign_hf_process_params(struct sip_msg* msg, struct hdr_field* hf, struct hname_data* hname, str* value, str* value_area) {
1162         int r, r2, res=0;
1163         str param_area, lump_upd, lump_del, dummy_val, dummy_name, dummy_uri;
1164         param_area = *value_area;
1165         get_uri_and_skip_until_params(&param_area, &dummy_name, &dummy_uri);
1166         do {
1167                 r = find_hf_value_param(hname, &param_area, &dummy_val, &lump_upd, &lump_del);
1168                 r2 = assign_hf_do_lumping(msg, hf, hname, value, r, &lump_upd, &lump_del, ';');
1169                 if (res == 0)
1170                         res = r2;
1171                 if (r && !value) {   /* remove all parameters */
1172                         param_area.len -= lump_del.s+lump_del.len-param_area.s;
1173                         param_area.s = lump_del.s+lump_del.len;
1174                 }
1175         } while (!value && r);
1176         return res;
1177 }
1178
1179 static int assign_hf_process2_params(struct sip_msg* msg, struct hdr_field* hf, struct hname_data* hname, str* value) {
1180         int r, r2, res = 0;
1181         str param_area, lump_upd, lump_del, dummy_val;
1182         char delim;
1183
1184         param_area = hf->body;
1185
1186         do {
1187                 r = find_hf_value2_param(hname, &param_area, &dummy_val, &lump_upd, &lump_del, &delim);
1188                 r2 = assign_hf_do_lumping(msg, hf, hname, value, r, &lump_upd, &lump_del, delim);
1189                 if (res == 0)
1190                         res = r2;
1191                 if (r && !value) {   /* remove all parameters */
1192                         param_area.len -= lump_del.s+lump_del.len-param_area.s;
1193                         param_area.s = lump_del.s+lump_del.len;
1194                 }
1195         } while (!value && r);
1196         return res;
1197
1198 }
1199
1200 static int insupddel_hf_value_f(struct sip_msg* msg, char* _hname, char* _val) {
1201         struct hname_data* hname = (void*) _hname;
1202         struct hdr_field* hf;
1203         str val, hval1, hval2;
1204         int res;
1205
1206         if (_val) {
1207                 res = eval_hvalue_param(msg, (void*) _val, &val);
1208                 if (res < 0) return res;
1209         }
1210         switch (hname->oper) {
1211                 case hnoAppend:
1212                         if ((hname->flags & HNF_IDX) == 0) {
1213                                 if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
1214                                         LOG(L_ERR, "ERROR: textops: Error while parsing message\n");
1215                                         return -1;
1216                                 }
1217                                 return insert_header_lump(msg, msg->unparsed, 1, &hname->hname, &val);
1218                         }
1219                         else {
1220                                 res = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
1221                                 if (res < 0) return res;
1222                                 if (hf) {
1223                                         return insert_value_lump(msg, hf, hval2.s+hval2.len,
1224                                                         res /* insert after, except it is last value in header */, &val);
1225                                 }
1226                                 else {
1227                                         return insert_header_lump(msg, msg->unparsed, 1, &hname->hname, &val);
1228                                 }
1229                         }
1230                 case hnoInsert:
1231                         /* if !HNF_IDX is possible parse only until first hname header
1232                          * but not trivial for HDR_OTHER_T header, not implemented */
1233                         res = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
1234                         if (res < 0) return res;
1235                         if (hf && (hname->flags & HNF_IDX) == 0) {
1236                                 return insert_header_lump(msg, hf->name.s, 1, &hname->hname, &val);
1237                         }
1238                         else if (!hf && hname->idx == 1) {
1239                                 return insert_header_lump(msg, msg->unparsed, 1, &hname->hname, &val);
1240                         }
1241                         else if (hf) {
1242                                 return insert_value_lump(msg, hf, hval2.s, 1, &val);
1243                         }
1244                         else
1245                                 return -1;
1246
1247                 case hnoRemove:
1248                 case hnoAssign:
1249                         if (hname->flags & HNF_ALL) {
1250                                 struct hdr_field* hf = 0;
1251                                 int fl = -1;
1252                                 do {
1253                                         res = find_next_hf(msg, hname, &hf);
1254                                         if (res < 0) return res;
1255                                         if (hf) {
1256                                                 if (!hname->param.len) {
1257                                                         fl = 1;
1258                                                         delete_value_lump(msg, hf, &hf->body);
1259                                                 }
1260                                                 else {
1261                                                         char *p;
1262                                                         hval2.len = 0;
1263                                                         p = hf->body.s;
1264                                                         do {
1265                                                                 res = find_next_value(&p, hf->body.s+hf->body.len, &hval1, &hval2);
1266                                                                 if (assign_hf_process_params(msg, hf, hname, _val?&val:0, &hval1) > 0)
1267                                                                         fl = 1;
1268                                                         } while (res);
1269                                                 }
1270                                         }
1271                                 } while (hf);
1272                                 return fl;
1273                         }
1274                         else {
1275                                 res = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
1276                                 if (res < 0) return res;
1277                                 if (hf) {
1278                                         if (!hname->param.len) {
1279                                                 if (hname->oper == hnoRemove) {
1280                                                         adjust_lump_val_for_delete(hf, &hval2);
1281                                                         return delete_value_lump(msg, hf, &hval2);
1282                                                 }
1283                                                 else {
1284                                                         res = delete_value_lump(msg, 0 /* delete only value part */, &hval1);
1285                                                         if (res < 0) return res;
1286                                                         if (val.len) {
1287                                                                 return insert_value_lump(msg, 0 /* do not add delims */, hval1.s, 1, &val);
1288                                                         }
1289                                                         return 1;
1290                                                 }
1291                                         }
1292                                         else {
1293                                                 return assign_hf_process_params(msg, hf, hname, _val?&val:0, &hval1);
1294                                         }
1295                                 }
1296                         }
1297                         break;
1298                 case hnoRemove2:
1299                 case hnoAssign2:
1300                         if (hname->flags & HNF_ALL) {
1301                                 struct hdr_field* hf = 0;
1302                                 int fl = -1;
1303                                 do {
1304                                         res = find_next_hf(msg, hname, &hf);
1305                                         if (res < 0) return res;
1306                                         if (hf) {
1307                                                 if (!hname->param.len) {  /* the same as hnoRemove/hnoAssign */
1308                                                         fl = 1;
1309                                                         delete_value_lump(msg, hf, &hf->body);
1310                                                 }
1311                                                 else {
1312
1313                                                         if (assign_hf_process2_params(msg, hf, hname, _val?&val:0) > 0)
1314                                                                 fl = 1;
1315                                                 }
1316                                         }
1317                                 } while (hf);
1318                                 return fl;
1319                         }
1320                         else {
1321                                 res = find_hf_value_idx(msg, hname, &hf, 0, 0);
1322                                 if (res < 0) return res;
1323                                 if (hf) {
1324                                         if (!hname->param.len) {
1325                                                 if (hname->oper == hnoRemove2) {
1326                                                         return delete_value_lump(msg, hf, &hf->body);
1327                                                 }
1328                                                 else {
1329                                                         res = delete_value_lump(msg, 0 /* delete only value part */, &hf->body);
1330                                                         if (res < 0) return res;
1331                                                         if (val.len) {
1332                                                                 return insert_value_lump(msg, 0 /* do not add delims */, hf->body.s, 1, &val);
1333                                                         }
1334                                                         return 1;
1335                                                 }
1336                                         }
1337                                         else {
1338                                                 return assign_hf_process2_params(msg, hf, hname, _val?&val:0);
1339                                         }
1340                                 }
1341                         }
1342                         break;
1343         }
1344         return -1;
1345 }
1346
1347 static int append_hf_value_fixup(void** param, int param_no) {
1348         int res=fixup_hname_str(param, param_no);
1349         if (res < 0) return res;
1350         if (param_no == 1) {
1351                 if ( ((struct hname_data*)*param)->flags & HNF_ALL ) {
1352                         LOG(L_ERR, "ERROR: textops: asterisk not supported\n");
1353                         return E_CFG;
1354                 } else if ( (((struct hname_data*)*param)->flags & HNF_IDX) == 0 || !((struct hname_data*)*param)->idx ) {
1355                         ((struct hname_data*)*param)->idx = -1;
1356                 }
1357                 if (((struct hname_data*)*param)->idx < -MAX_HF_VALUE_STACK) {
1358                         LOG(L_ERR, "ERROR: textops: index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
1359                         return E_CFG;
1360                 }
1361                 if ( ((struct hname_data*)*param)->param.len ) {
1362                         LOG(L_ERR, "ERROR: textops: param not supported\n");
1363                         return E_CFG;
1364                 }
1365                 ((struct hname_data*)*param)->oper = hnoAppend;
1366         }
1367         return 0;
1368 }
1369
1370 static int insert_hf_value_fixup(void** param, int param_no) {
1371         int res=fixup_hname_str(param, param_no);
1372         if (res < 0) return res;
1373         if (param_no == 1) {
1374                 if ( ((struct hname_data*)*param)->flags & HNF_ALL ) {
1375                         LOG(L_ERR, "ERROR: textops: asterisk not supported\n");
1376                         return E_CFG;
1377                 } else if ( (((struct hname_data*)*param)->flags & HNF_IDX) == 0 || !((struct hname_data*)*param)->idx ) {
1378                         ((struct hname_data*)*param)->idx = 1;
1379                 }
1380                 if (((struct hname_data*)*param)->idx < -MAX_HF_VALUE_STACK) {
1381                         LOG(L_ERR, "ERROR: textops: index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
1382                         return E_CFG;
1383                 }
1384                 if ( ((struct hname_data*)*param)->param.len ) {
1385                         LOG(L_ERR, "ERROR: textops: param not supported\n");
1386                         return E_CFG;
1387                 }
1388                 ((struct hname_data*)*param)->oper = hnoInsert;
1389         }
1390         return 0;
1391 }
1392
1393 static int remove_hf_value_fixup(void** param, int param_no) {
1394         int res=fixup_hname_str(param, param_no);
1395         if (res < 0) return res;
1396         if (param_no == 1) {
1397                 if ( (((struct hname_data*)*param)->flags & HNF_IDX) == 0 || !((struct hname_data*)*param)->idx ) {
1398                         ((struct hname_data*)*param)->idx = 1;
1399                         ((struct hname_data*)*param)->flags |= HNF_IDX;
1400                 }
1401                 if (((struct hname_data*)*param)->idx < -MAX_HF_VALUE_STACK) {
1402                         LOG(L_ERR, "ERROR: textops: index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
1403                         return E_CFG;
1404                 }
1405                 ((struct hname_data*)*param)->oper = hnoRemove;
1406         }
1407         return 0;
1408 }
1409
1410 static int assign_hf_value_fixup(void** param, int param_no) {
1411         int res=fixup_hname_str(param, param_no);
1412         if (res < 0) return res;
1413         if (param_no == 1) {
1414                 if ( (((struct hname_data*)*param)->flags & HNF_ALL) && !((struct hname_data*)*param)->param.len) {
1415                         LOG(L_ERR, "ERROR: textops: asterisk not supported without param\n");
1416                         return E_CFG;
1417                 } else if ( (((struct hname_data*)*param)->flags & HNF_IDX) == 0 || !((struct hname_data*)*param)->idx ) {
1418                         ((struct hname_data*)*param)->idx = 1;
1419                         ((struct hname_data*)*param)->flags |= HNF_IDX;
1420                 }
1421                 if (((struct hname_data*)*param)->idx < -MAX_HF_VALUE_STACK) {
1422                         LOG(L_ERR, "ERROR: textops: index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
1423                         return E_CFG;
1424                 }
1425                 ((struct hname_data*)*param)->oper = hnoAssign;
1426         }
1427         return 0;
1428 }
1429
1430 static int remove_hf_value2_fixup(void** param, int param_no) {
1431         int res=remove_hf_value_fixup(param, param_no);
1432         if (res < 0) return res;
1433         if (param_no == 1) {
1434                 ((struct hname_data*)*param)->oper = hnoRemove2;
1435         }
1436         return 0;
1437 }
1438
1439 static int assign_hf_value2_fixup(void** param, int param_no) {
1440         int res=assign_hf_value_fixup(param, param_no);
1441         if (res < 0) return res;
1442         if (param_no == 1) {
1443                 ((struct hname_data*)*param)->oper = hnoAssign2;
1444         }
1445         return 0;
1446 }
1447
1448
1449 /* select implementation */
1450 static int sel_hf_value(str* res, select_t* s, struct sip_msg* msg) {  /* dummy */
1451         return 0;
1452 }
1453
1454 #define _ALLOC_INC_SIZE 1024
1455
1456 static int sel_hf_value_name(str* res, select_t* s, struct sip_msg* msg) {
1457         struct hname_data* hname;
1458         struct hdr_field* hf;
1459         str val, hval1, hval2, huri, dummy_name;
1460         int r;
1461         if (!msg) {
1462                 struct hdr_field hdr;
1463                 char buf[50];
1464                 int i, n;
1465
1466                 if (s->params[1].type == SEL_PARAM_STR) {
1467                         hname = pkg_malloc(sizeof(*hname));
1468                         if (!hname) return E_OUT_OF_MEM;
1469                         memset(hname, 0, sizeof(*hname));
1470
1471                         for (i=s->params[1].v.s.len-1; i>0; i--) {
1472                                 if (s->params[1].v.s.s[i]=='_')
1473                                         s->params[1].v.s.s[i]='-';
1474                         }
1475                         i = snprintf(buf, sizeof(buf)-1, "%.*s: X\n", s->params[1].v.s.len, s->params[1].v.s.s);
1476                         buf[i] = 0;
1477
1478                         hname->hname = s->params[1].v.s;
1479                         parse_hname2(buf, buf+i, &hdr);
1480
1481                         if (hdr.type == HDR_ERROR_T) return E_CFG;
1482                         hname->htype = hdr.type;
1483
1484                         s->params[1].v.p = hname;
1485                         s->params[1].type = SEL_PARAM_PTR;
1486                 }
1487                 else {
1488                         hname = s->params[1].v.p;
1489                 }
1490                 n = s->param_offset[select_level+1] - s->param_offset[select_level];  /* number of values before NESTED */
1491                 if (n > 2 && s->params[2].type == SEL_PARAM_INT) {
1492                         hname->idx = s->params[2].v.i;
1493                         hname->flags |= HNF_IDX;
1494                         if (hname->idx < -MAX_HF_VALUE_STACK) {
1495                                 LOG(L_ERR, "ERROR: textops: index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
1496                                 return E_CFG;
1497                         }
1498                         if (hname->idx == 0)
1499                                 hname->idx = 1;
1500                         i = 3;
1501                 }
1502                 else {
1503                         i = 2;
1504                         hname->idx = 1;
1505                 }
1506                 if (n > i && s->params[i].type == SEL_PARAM_STR) {
1507                         hname->param = s->params[i].v.s;
1508                         for (i=hname->param.len-1; i>0; i--) {
1509                                 if (hname->param.s[i]=='_')
1510                                         hname->param.s[i]='-';
1511                         }
1512
1513                 }
1514                 s->params[1].v.p = hname;
1515                 s->params[1].type = SEL_PARAM_PTR;
1516                 hname->oper = hnoGetValue;
1517
1518                 return 0;
1519         }
1520
1521         res->len = 0;
1522         res->s = 0;
1523         hname = s->params[1].v.p;
1524
1525         switch (hname->oper) {
1526                 case hnoGetValueUri:
1527                         if (hname->flags & HNF_ALL || (hname->flags & HNF_IDX) == 0) {
1528                                 char *buf = NULL;
1529                                 int buf_len = 0;
1530                                 
1531                                 hf = 0;
1532                                 do {
1533                                         r = find_next_hf(msg, hname, &hf);
1534                                         if (r < 0) break;
1535                                         if (hf) {
1536                                                 char *p;
1537                                                 str huri;
1538                                                 hval2.len = 0;
1539                                                 p = hf->body.s;
1540                                                 do {
1541                                                         r = find_next_value(&p, hf->body.s+hf->body.len, &hval1, &hval2);
1542                                                         get_uri_and_skip_until_params(&hval1, &dummy_name, &huri);
1543                                                         if (huri.len) {
1544                                                         /* TODO: normalize uri, lowercase except quoted params, add/strip < > */
1545                                                                 if (*huri.s == '<') {
1546                                                                         huri.s++;
1547                                                                         huri.len -= 2;
1548                                                                 }
1549                                                         }                                                       
1550                                                         if (res->len == 0) {  
1551                                                                 *res = huri; /* first value, if is also last value then we don't need any buffer */
1552                                                         }
1553                                                         else {
1554                                                                 if (buf) {
1555                                                                         if (res->len+huri.len+1 > buf_len) {
1556                                                                                 buf_len = res->len+huri.len+1+_ALLOC_INC_SIZE;
1557                                                                                 res->s = pkg_realloc(buf, buf_len);
1558                                                                                 if (!res->s) {
1559                                                                                         pkg_free(buf);
1560                                                                                         LOG(L_ERR, "ERROR: textops: cannot realloc buffer\n");
1561                                                                                         res->len = 0;
1562                                                                                         return E_OUT_OF_MEM;
1563                                                                                 }
1564                                                                                 buf = res->s;
1565                                                                         }
1566                                                                 }
1567                                                                 else {
1568                                                                         /* 2nd value */
1569                                                                         buf_len = res->len+huri.len+1+_ALLOC_INC_SIZE;
1570                                                                         buf = pkg_malloc(buf_len);
1571                                                                         if (!buf) { 
1572                                                                                 LOG(L_ERR, "ERROR: testops: out of memory\n");
1573                                                                                 res->len = 0;
1574                                                                                 return E_OUT_OF_MEM;
1575                                                                         }
1576                                                                         /* copy 1st value */
1577                                                                         memcpy(buf, res->s, res->len);                                                          
1578                                                                         res->s = buf;
1579                                                                 }
1580                                                                 res->s[res->len] = ',';
1581                                                                 res->len++;
1582                                                                 if (huri.len) {
1583                                                                         memcpy(res->s+res->len, huri.s, huri.len);
1584                                                                         res->len += huri.len;
1585                                                                 }
1586                                                         }
1587                                                 
1588                                                 } while (r);
1589                                         }
1590                                 } while (hf);
1591                                 if (buf) {
1592                                         res->s = get_static_buffer(res->len);
1593                                         if (!res->s) {
1594                                                 pkg_free(buf);
1595                                                 res->len = 0;
1596                                                 LOG(L_ERR, "ERROR: testops: cannot allocate static buffer\n");
1597                                                 return E_OUT_OF_MEM;
1598                                         }
1599                                         memcpy(res->s, buf, res->len);
1600                                         pkg_free(buf);
1601                                 }
1602                         }
1603                         else {
1604                                 r = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
1605                                 if (r > 0) {
1606                                         get_uri_and_skip_until_params(&hval1, &dummy_name, res);
1607                                         if (res->len && *res->s == '<') {
1608                                                 res->s++;       /* strip < & > */
1609                                                 res->len-=2;
1610                                         }
1611                                 }
1612                         }
1613                         break;
1614                 case hnoGetValueName:
1615                         if ((hname->flags & HNF_ALL) == 0) {
1616                                 r = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
1617                                 if (r > 0) {
1618                                         get_uri_and_skip_until_params(&hval1, res, &dummy_name);
1619                                         if (res->len >= 2 && res->s[0] == '\"' && res->s[res->len-1]=='\"' ) {
1620                                                 res->s++;       /* strip quotes */
1621                                                 res->len-=2;
1622                                         }
1623                                 }
1624                         }
1625                         break;
1626                 case hnoGetValue:
1627                         if (hname->flags & HNF_ALL || (hname->flags & HNF_IDX) == 0) {
1628                                 char *buf = NULL;
1629                                 int buf_len = 0;
1630
1631                                 hf = 0;
1632                                 do {
1633                                         r = find_next_hf(msg, hname, &hf);
1634                                         
1635                                         if (r < 0) break;
1636                                         if (hf) {
1637                                                 char *p;
1638                                                 hval2.len = 0;
1639                                                 p = hf->body.s;
1640                                                 do {
1641                                                         r = find_next_value(&p, hf->body.s+hf->body.len, &hval1, &hval2);
1642                                                         if (res->len == 0) {  
1643                                                                 *res = hval1; /* first value, if is also last value then we don't need any buffer */
1644                                                         }
1645                                                         else {
1646                                                                 if (buf) {
1647                                                                         if (res->len+hval1.len+1 > buf_len) {
1648                                                                                 buf_len = res->len+hval1.len+1+_ALLOC_INC_SIZE;
1649                                                                                 res->s = pkg_realloc(buf, buf_len);
1650                                                                                 if (!res->s) {
1651                                                                                         pkg_free(buf);
1652                                                                                         LOG(L_ERR, "ERROR: textops: cannot realloc buffer\n");
1653                                                                                         res->len = 0;
1654                                                                                         return E_OUT_OF_MEM;
1655                                                                                 }
1656                                                                                 buf = res->s;
1657                                                                         }
1658                                                                 }
1659                                                                 else {
1660                                                                         /* 2nd value */
1661                                                                         buf_len = res->len+hval1.len+1+_ALLOC_INC_SIZE;
1662                                                                         buf = pkg_malloc(buf_len);
1663                                                                         if (!buf) { 
1664                                                                                 LOG(L_ERR, "ERROR: testops: out of memory\n");
1665                                                                                 res->len = 0;
1666                                                                                 return E_OUT_OF_MEM;
1667                                                                         }
1668                                                                         /* copy 1st value */
1669                                                                         memcpy(buf, res->s, res->len);                                                          
1670                                                                         res->s = buf;
1671                                                                 }
1672                                                                 res->s[res->len] = ',';
1673                                                                 res->len++;
1674                                                                 if (hval1.len) {
1675                                                                         memcpy(res->s+res->len, hval1.s, hval1.len);
1676                                                                         res->len += hval1.len;
1677                                                                 }
1678                                                         }
1679                                                 } while (r);
1680                                         }
1681                                 } while (hf);
1682                                 if (buf) {
1683                                         res->s = get_static_buffer(res->len);
1684                                         if (!res->s) {
1685                                                 pkg_free(buf);
1686                                                 res->len = 0;
1687                                                 LOG(L_ERR, "ERROR: testops: cannot allocate static buffer\n");
1688                                                 return E_OUT_OF_MEM;
1689                                         }
1690                                         memcpy(res->s, buf, res->len);
1691                                         pkg_free(buf);
1692                                 }
1693                         }
1694                         else {
1695                                 r = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
1696                                 if (r > 0) {
1697                                         if (hname->param.len) {
1698                                                 str d1, d2;
1699                                                 get_uri_and_skip_until_params(&hval1, &dummy_name, &huri);
1700                                                 if (find_hf_value_param(hname, &hval1, &val, &d1, &d2)) {
1701                                                         *res = val;
1702                                                 }
1703                                         }
1704                                         else {
1705                                                 *res = hval1;
1706                                         }
1707                                 }
1708                         }
1709                         break;
1710                 case hnoGetValue2:
1711                         r = find_hf_value_idx(msg, hname, &hf, 0, 0);
1712                         if (r > 0) {
1713                                 if (hname->param.len) {
1714                                         str d1, d2;
1715                                         char c;
1716                                         if (find_hf_value2_param(hname, &hf->body, &val, &d1, &d2, &c)) {
1717                                                 *res = val;
1718                                         }
1719                                 }
1720                                 else {
1721                                         *res = hf->body;
1722                                 }
1723                         }
1724                         break;
1725                 default:
1726                         break;
1727         }
1728         return 0;
1729 }
1730
1731 static int sel_hf_value_name_param_name(str* res, select_t* s, struct sip_msg* msg) {
1732         return sel_hf_value_name(res, s, msg);
1733 }
1734
1735 static int sel_hf_value_name_param_name2(str* res, select_t* s, struct sip_msg* msg) {
1736         if (!msg) { /* eliminate "param" level */
1737                 int n;
1738                 n = s->param_offset[select_level+1] - s->param_offset[select_level];
1739                 s->params[n-2] = s->params[n-1];
1740         }
1741         return sel_hf_value_name(res, s, msg);
1742 }
1743
1744 static int sel_hf_value_name_uri(str* res, select_t* s, struct sip_msg* msg) {
1745         int r;
1746         r = sel_hf_value_name(res, s, msg);
1747         if (!msg && r==0) {
1748                 ((struct hname_data*) s->params[1].v.p)->oper = hnoGetValueUri;
1749         }
1750         return r;
1751 }
1752
1753 static int sel_hf_value_name_name(str* res, select_t* s, struct sip_msg* msg) {
1754         int r;
1755         r = sel_hf_value_name(res, s, msg);
1756         if (!msg && r==0) {
1757                 ((struct hname_data*) s->params[1].v.p)->oper = hnoGetValueName;
1758         }
1759         return r;
1760 }
1761
1762 static int sel_hf_value_exists(str* res, select_t* s, struct sip_msg* msg) {  /* dummy */
1763         return 0;
1764 }
1765
1766 static int sel_hf_value_exists_param(str* res, select_t* s, struct sip_msg* msg) {
1767         static char ret_val[] = "01";
1768     int r;
1769
1770         if (!msg) {
1771                 r = sel_hf_value_name(res, s, msg);
1772                 if (r == 0)
1773                         ((struct hname_data*) s->params[1].v.p)->oper = hnoIsIncluded;
1774                 return r;
1775         }
1776         r = incexc_hf_value_str_f(msg, s->params[1].v.p, &s->params[2].v.s);
1777         res->s = &ret_val[r > 0];
1778         res->len = 1;
1779
1780         return 0;
1781 }
1782
1783 static int sel_hf_value2(str* res, select_t* s, struct sip_msg* msg) {  /* dummy */
1784         return 0;
1785 }
1786
1787 static int sel_hf_value2_name(str* res, select_t* s, struct sip_msg* msg) {
1788         int r;
1789         r = sel_hf_value_name(res, s, msg);
1790         if (!msg && r==0) {
1791                 ((struct hname_data*) s->params[1].v.p)->oper = hnoGetValue2;
1792         }
1793         return r;
1794 }
1795
1796 static int sel_hf_value2_name_param_name(str* res, select_t* s, struct sip_msg* msg) {
1797         return sel_hf_value2_name(res, s, msg);
1798 }
1799
1800 SELECT_F(select_any_nameaddr)
1801 SELECT_F(select_any_uri)
1802 SELECT_F(select_anyheader_params)
1803
1804 select_row_t sel_declaration[] = {
1805         { NULL, SEL_PARAM_STR, STR_STATIC_INIT("hf_value"), sel_hf_value, SEL_PARAM_EXPECTED},
1806
1807         { sel_hf_value, SEL_PARAM_STR, STR_NULL, sel_hf_value_name, CONSUME_NEXT_INT | OPTIONAL | FIXUP_CALL},
1808         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("param"), sel_hf_value_name_param_name2, CONSUME_NEXT_STR | FIXUP_CALL},
1809         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("p"), sel_hf_value_name_param_name2, CONSUME_NEXT_STR | FIXUP_CALL},
1810         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("uri"), sel_hf_value_name_uri, FIXUP_CALL},
1811         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("name"), sel_hf_value_name_name, FIXUP_CALL},
1812         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED | CONSUME_NEXT_STR}, /* it duplicates param,p,name,... */
1813         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_anyheader_params, NESTED},
1814
1815         { sel_hf_value_name_uri, SEL_PARAM_INT, STR_NULL, select_any_uri, NESTED},
1816         { sel_hf_value_name, SEL_PARAM_STR, STR_NULL, sel_hf_value_name_param_name, FIXUP_CALL},
1817
1818         { NULL, SEL_PARAM_STR, STR_STATIC_INIT("hf_value_exists"), sel_hf_value_exists, CONSUME_NEXT_STR | SEL_PARAM_EXPECTED},
1819         { sel_hf_value_exists, SEL_PARAM_STR, STR_NULL, sel_hf_value_exists_param, FIXUP_CALL},
1820
1821         { NULL, SEL_PARAM_STR, STR_STATIC_INIT("hf_value2"), sel_hf_value2, SEL_PARAM_EXPECTED},
1822         { sel_hf_value2, SEL_PARAM_STR, STR_NULL, sel_hf_value2_name, CONSUME_NEXT_INT | OPTIONAL | FIXUP_CALL},
1823         { sel_hf_value2_name, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_anyheader_params, NESTED},
1824         { sel_hf_value2_name, SEL_PARAM_STR, STR_NULL, sel_hf_value2_name_param_name, FIXUP_CALL},
1825         { sel_hf_value2_name_param_name, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED},
1826         { sel_hf_value2_name_param_name, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_any_uri, NESTED},
1827
1828         { NULL, SEL_PARAM_INT, STR_NULL, NULL, 0}
1829 };