modules_s/textops/textops.c

00001 /*$Id$
00002  *
00003  * Example ser module, it implements the following commands:
00004  * search_append("key", "txt") - insert a "txt" after "key"
00005  * replace("txt1", "txt2") - replaces txt1 with txt2 (txt1 can be a re)
00006  * search("txt") - searches for txt (txt can be a regular expression)
00007  * append_to_reply("txt") - appends txt to the reply?
00008  * append_hf("P-foo: bar\r\n");
00009  *
00010  *
00011  *
00012  * Copyright (C) 2001-2003 FhG Fokus
00013  *
00014  * This file is part of ser, a free SIP server.
00015  *
00016  * ser is free software; you can redistribute it and/or modify
00017  * it under the terms of the GNU General Public License as published by
00018  * the Free Software Foundation; either version 2 of the License, or
00019  * (at your option) any later version
00020  *
00021  * For a license to use the ser software under conditions
00022  * other than those described here, or to purchase support for this
00023  * software, please contact iptel.org by e-mail at the following addresses:
00024  *    info@iptel.org
00025  *
00026  * ser is distributed in the hope that it will be useful,
00027  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00028  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00029  * GNU General Public License for more details.
00030  *
00031  * You should have received a copy of the GNU General Public License
00032  * along with this program; if not, write to the Free Software
00033  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00034  *
00035  *
00036  * History:
00037  * -------
00038  *  2003-02-28  scratchpad compatibility abandoned (jiri)
00039  *  2003-01-29: - rewriting actions (replace, search_append) now begin
00040  *                at the second line -- previously, they could affect
00041  *                first line too, which resulted in wrong calculation of
00042  *                forwarded requests and an error consequently
00043  *              - replace_all introduced
00044  *  2003-01-28  scratchpad removed (jiri)
00045  *  2003-01-18  append_urihf introduced (jiri)
00046  *  2003-03-10  module export interface updated to the new format (andrei)
00047  *  2003-03-16  flags export parameter added (janakj)
00048  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
00049  *  2003-04-97  actions permitted to be used from failure/reply routes (jiri)
00050  *  2003-04-21  remove_hf and is_present_hf introduced (jiri)
00051  *  2003-08-19  subst added (support for sed like res:s/re/repl/flags) (andrei)
00052  *  2003-08-20  subst_uri added (like above for uris) (andrei)
00053  *  2003-09-11  updated to new build_lump_rpl() interface (bogdan)
00054  *  2003-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan)
00055  *  2004-05-09: append_time introduced (jiri)
00056  *  2004-07-06  subst_user added (like subst_uri but only for user) (sobomax)
00057  *  2004-11-12  subst_user changes (old serdev mails) (andrei)
00058  *  2006-02-23  xl_lib formating, multi-value support (tma)
00059  *  2006-08-30  added static buffer support (tma)
00060  */
00061 
00062 
00063 #include "../../comp_defs.h"
00064 #include "../../action.h"
00065 #include "../../sr_module.h"
00066 #include "../../dprint.h"
00067 #include "../../data_lump.h"
00068 #include "../../data_lump_rpl.h"
00069 #include "../../error.h"
00070 #include "../../mem/mem.h"
00071 #include "../../re.h"
00072 #include "../../parser/parse_uri.h"
00073 #include "../../parser/parse_hname2.h"
00074 #include "../../onsend.h"
00075 #include "../../ut.h"
00076 #include "../../select.h"
00077 #include "../xlog/xl_lib.h"
00078 #include "../../script_cb.h"
00079 #include "../../select_buf.h"
00080 #include "../../ser_time.h"
00081 #include "../../dset.h"
00082 #include <stdio.h>
00083 #include <stdlib.h>
00084 #include <string.h>
00085 #include <sys/types.h> /* for regex */
00086 #include <regex.h>
00087 #include <time.h>
00088 #include <sys/time.h>
00089 
00090 MODULE_VERSION
00091 
00092 /* RFC822-conforming dates format:
00093 
00094    %a -- abbreviated week of day name (locale), %d day of month
00095    as decimal number, %b abbreviated month name (locale), %Y
00096    year with century, %T time in 24h notation
00097 */
00098 #define TIME_FORMAT "Date: %a, %d %b %Y %H:%M:%S GMT"
00099 #define MAX_TIME 64
00100 
00101 static int xlbuf_size = 4096;
00102 
00103 
00104 static int search_f(struct sip_msg*, char*, char*);
00105 static int replace_f(struct sip_msg*, char*, char*);
00106 static int subst_f(struct sip_msg*, char*, char*);
00107 static int subst_uri_f(struct sip_msg*, char*, char*);
00108 static int subst_user_f(struct sip_msg*, char*, char*);
00109 static int remove_hf_f(struct sip_msg* msg, char* str_hf, char* foo);
00110 static int remove_hf_re_f(struct sip_msg* msg, char* str_hf, char* foo);
00111 static int is_present_hf_f(struct sip_msg* msg, char* str_hf, char* foo);
00112 static int replace_all_f(struct sip_msg* msg, char* key, char* str);
00113 static int search_append_f(struct sip_msg*, char*, char*);
00114 static int append_to_reply_f(struct sip_msg* msg, char* key, char* str);
00115 static int append_hf(struct sip_msg* msg, char* str1, char* str2);
00116 static int append_urihf(struct sip_msg* msg, char* str1, char* str2);
00117 static int append_time_f(struct sip_msg* msg, char* , char *);
00118 
00119 static int incexc_hf_value_f(struct sip_msg* msg, char* , char *);
00120 static int include_hf_value_fixup(void**, int);
00121 static int exclude_hf_value_fixup(void**, int);
00122 static int hf_value_exists_fixup(void**, int);
00123 
00124 static int insupddel_hf_value_f(struct sip_msg* msg, char* _hname, char* _val);
00125 static int append_hf_value_fixup(void** param, int param_no);
00126 static int insert_hf_value_fixup(void** param, int param_no);
00127 static int remove_hf_value_fixup(void** param, int param_no);
00128 static int assign_hf_value_fixup(void** param, int param_no);
00129 static int remove_hf_value2_fixup(void** param, int param_no);
00130 static int assign_hf_value2_fixup(void** param, int param_no);
00131 static int fixup_xlstr(void** param, int param_no);
00132 static int fixup_regex_xlstr(void** param, int param_no);
00133 
00134 static int fixup_substre(void**, int);
00135 
00136 extern select_row_t sel_declaration[];
00137 
00138 static int mod_init(void);
00139 
00140 
00141 static cmd_export_t cmds[]={
00142         {"search",           search_f,          1, fixup_regex_1,
00143                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|ONSEND_ROUTE},
00144         {"search_append",    search_append_f,   2, fixup_regex_xlstr,
00145                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE},
00146         {"replace",          replace_f,         2, fixup_regex_xlstr,
00147                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE},
00148         {"replace_all",      replace_all_f,     2, fixup_regex_xlstr,
00149                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE},
00150         {"append_to_reply",  append_to_reply_f, 1, fixup_xlstr,
00151                         REQUEST_ROUTE},
00152         {"append_hf",        append_hf,         1, fixup_xlstr,
00153                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE | BRANCH_ROUTE},
00154         {"append_urihf",     append_urihf,      2, fixup_xlstr,
00155                         REQUEST_ROUTE|FAILURE_ROUTE},
00156         /* obsolete: use remove_hf_value(), does not support compact headers */
00157         {"remove_hf",        remove_hf_f,         1, fixup_var_str_1,
00158                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE},
00159         {"remove_hf_re",     remove_hf_re_f,      1, fixup_regex_12,
00160                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE},
00161         /* obsolete: use @msg.HFNAME, , does not support compact headers */
00162         {"is_present_hf",        is_present_hf_f,         1, fixup_var_str_1,
00163                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE},
00164         {"subst",            subst_f,             1, fixup_substre,
00165                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE},
00166         {"subst_uri",            subst_uri_f,     1, fixup_substre,
00167                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE},
00168         {"subst_user",           subst_user_f,    1, fixup_substre,
00169                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE},
00170         {"append_time",         append_time_f,          0, 0,
00171                         REQUEST_ROUTE },
00172 
00173 
00174         {"append_hf_value",        insupddel_hf_value_f,         2, append_hf_value_fixup,
00175                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00176         {"insert_hf_value",        insupddel_hf_value_f,         2, insert_hf_value_fixup,
00177                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00178         {"remove_hf_value",        insupddel_hf_value_f,         1, remove_hf_value_fixup,
00179                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00180         {"assign_hf_value",        insupddel_hf_value_f,         2, assign_hf_value_fixup,
00181                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00182         {"remove_hf_value2",       insupddel_hf_value_f,         1, remove_hf_value2_fixup,
00183                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00184         {"assign_hf_value2",       insupddel_hf_value_f,         2, assign_hf_value2_fixup,
00185                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00186         {"include_hf_value", incexc_hf_value_f,      2, include_hf_value_fixup,
00187                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00188         {"exclude_hf_value", incexc_hf_value_f,      2, exclude_hf_value_fixup,
00189                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00190         {"hf_value_exists",  incexc_hf_value_f,      2, hf_value_exists_fixup,
00191                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00192 
00193         {0,0,0,0,0}
00194 };
00195 
00196 static param_export_t params[]={
00197         {"xlbuf_size", PARAM_INT, &xlbuf_size},
00198 
00199         {0,0,0}
00200         }; /* no params */
00201 
00202 struct module_exports exports= {
00203         "textops",
00204         cmds,
00205         0,        /* RPC methods */
00206         params,
00207         mod_init, /* module initialization function */
00208         0, /* response function */
00209         0, /* destroy function */
00210         0, /* on_cancel function */
00211         0, /* per-child init function */
00212 };
00213 
00214 static int mod_init(void)
00215 {
00216         DBG("%s - initializing\n", exports.name);
00217         register_select_table(sel_declaration);
00218         return 0;
00219 }
00220 
00221 struct xlstr {
00222         str s;
00223         xl_elog_t* xlfmt;
00224 };
00225 
00226 static xl_print_log_f* xl_print = NULL;
00227 static xl_parse_format_f* xl_parse = NULL;
00228 
00229 #define NO_SCRIPT -1
00230 
00231 static int fixup_xlstr(void** param, int param_no) {
00232         struct xlstr* s;
00233         s = pkg_malloc(sizeof(*s));
00234         if (!s) return E_OUT_OF_MEM;
00235         s->s.s = *param;
00236         s->s.len = strlen(s->s.s);
00237         s->xlfmt = 0;
00238         if (strchr(s->s.s, '%')) {
00239                 if (!xl_print) {
00240                         xl_print=(xl_print_log_f*)find_export("xprint", NO_SCRIPT, 0);
00241                         if (!xl_print) {
00242                                 LOG(L_CRIT,"ERROR: textops: cannot find \"xprint\", is module xlog loaded?\n");
00243                                 return E_UNSPEC;
00244                         }
00245                 }
00246 
00247                 if (!xl_parse) {
00248                         xl_parse=(xl_parse_format_f*)find_export("xparse", NO_SCRIPT, 0);
00249                         if (!xl_parse) {
00250                                 LOG(L_CRIT,"ERROR: textops: cannot find \"xparse\", is module xlog loaded?\n");
00251                                 return E_UNSPEC;
00252                         }
00253                 }
00254                 if(xl_parse(s->s.s, &s->xlfmt) < 0) {
00255                         LOG(L_ERR, "ERROR: textops: wrong format '%s'\n", s->s.s);
00256                         return E_UNSPEC;
00257                 }
00258         }
00259         *param = s;
00260         return 0;
00261 }
00262 
00263 static int eval_xlstr(struct sip_msg* msg, struct xlstr* val, str* s) {
00264         static char *xlbuf = NULL;
00265         if (val) {
00266                 if (val->xlfmt) {
00267                         if (!xlbuf) {
00268                                 xlbuf = pkg_malloc(xlbuf_size);
00269                                 if (!xlbuf) {
00270                                         LOG(L_ERR, "ERROR: out of memory\n");
00271                                         return E_OUT_OF_MEM;
00272                                 }
00273                         }
00274                         s->len = xlbuf_size-1;
00275                         if (xl_print(msg, val->xlfmt, xlbuf, &s->len) < 0) {
00276                                 LOG(L_ERR, "ERROR: textops: eval_xlstr: Error while formating result '%.*s'\n", val->s.len, val->s.s);
00277                                 s->len = 0;
00278                                 return E_UNSPEC;
00279                         }
00280                         s->s = xlbuf;
00281                 }
00282                 else {
00283                         *s = val->s;
00284                 }
00285         }
00286         else
00287                 s->len = 0;
00288         return 1;
00289 }
00290 
00291 static int fixup_regex_xlstr(void** param, int param_no) {
00292         if (param_no == 1)
00293                 return fixup_regex_1(param, param_no);
00294         else if (param_no == 2)
00295                 return fixup_xlstr(param, param_no);
00296         else
00297                 return 0;
00298 }
00299 
00300 static char *get_header(struct sip_msg *msg)
00301 {
00302         return SIP_MSG_START(msg)+msg->first_line.len;
00303 }
00304 
00305 static int search_f(struct sip_msg* msg, char* key, char* str2)
00306 {
00307         /*we registered only 1 param, so we ignore str2*/
00308         regmatch_t pmatch;
00309         char* buf;
00310         struct onsend_info* snd_inf;
00311 
00312         if ((snd_inf=get_onsend_info())!=0)
00313                 buf=snd_inf->buf;
00314         else
00315                 buf=msg->buf;
00316 
00317         if (regexec(((fparam_t*)key)->v.regex, buf, 1, &pmatch, 0)!=0) return -1;
00318         return 1;
00319 }
00320 
00321 static int search_append_f(struct sip_msg* msg, char* key, char* _str)
00322 {
00323         struct lump* l;
00324         regmatch_t pmatch;
00325         str str;
00326         char* s;
00327         char *begin;
00328         int off;
00329 
00330         begin=get_header(msg); /* msg->orig/buf previously .. uri problems */
00331         off=begin-msg->buf;
00332 
00333         if (regexec(((fparam_t*)key)->v.regex, begin, 1, &pmatch, 0)!=0) return -1;
00334         if (pmatch.rm_so!=-1){
00335                 if (eval_xlstr(msg, (void*) _str, &str) < 0) return -1;
00336 
00337                 if ((l=anchor_lump(msg, off+pmatch.rm_eo, 0, 0))==0)
00338                         return -1;
00339                 s=pkg_malloc(str.len);
00340                 if (s==0){
00341                         LOG(L_ERR, "ERROR: search_append_f: mem. allocation failure\n");
00342                         return -1;
00343                 }
00344                 memcpy(s, str.s, str.len);
00345                 if (insert_new_lump_after(l, s, str.len, 0)==0){
00346                         LOG(L_ERR, "ERROR: could not insert new lump\n");
00347                         pkg_free(s);
00348                         return -1;
00349                 }
00350                 return 1;
00351         }
00352         return -1;
00353 }
00354 
00355 
00356 static int replace_all_f(struct sip_msg* msg, char* key, char* _str)
00357 {
00358         struct lump* l;
00359         regmatch_t pmatch;
00360         char* s;
00361         str str;
00362         char* begin;
00363         int off;
00364         int ret;
00365         int eflags;
00366 
00367         /* we need to be sure we have seen all HFs */
00368         parse_headers(msg, HDR_EOH_F, 0);
00369 
00370         begin=get_header(msg); /* msg->orig previously .. uri problems */
00371         ret=-1; /* pessimist: we will not find any */
00372         eflags=0; /* match ^ at the beginning of the string*/
00373 
00374         if (eval_xlstr(msg, (void*) _str, &str) < 0) return -1;
00375         while (begin<msg->buf+msg->len
00376                                 && regexec(((fparam_t*)key)->v.regex, begin, 1, &pmatch, eflags)==0) {
00377                 off=begin-msg->buf;
00378                 /* change eflags, not to match any more at string start */
00379                 eflags|=REG_NOTBOL;
00380                 if (pmatch.rm_so==-1){
00381                         LOG(L_ERR, "ERROR: replace_all_f: offset unknown\n");
00382                         return -1;
00383                 }
00384                 if ((l=del_lump(msg, pmatch.rm_so+off,
00385                                                 pmatch.rm_eo-pmatch.rm_so, 0))==0) {
00386                         LOG(L_ERR, "ERROR: replace_all_f: del_lump failed\n");
00387                         return -1;
00388                 }
00389                 s=pkg_malloc(str.len);
00390                 if (s==0){
00391                         LOG(L_ERR, "ERROR: replace_all_f: mem. allocation failure\n");
00392                         return -1;
00393                 }
00394                 memcpy(s, str.s, str.len);
00395                 if (insert_new_lump_after(l, s, str.len, 0)==0){
00396                         LOG(L_ERR, "ERROR: could not insert new lump\n");
00397                         pkg_free(s);
00398                         return -1;
00399                 }
00400                 /* new cycle */
00401                 begin=begin+pmatch.rm_eo;
00402                 ret=1;
00403         } /* while found ... */
00404         return ret;
00405 }
00406 
00407 static int replace_f(struct sip_msg* msg, char* key, char* _str)
00408 {
00409         struct lump* l;
00410         regmatch_t pmatch;
00411         char* s;
00412         str str;
00413         char* begin;
00414         int off;
00415 
00416         /* we need to be sure we have seen all HFs */
00417         parse_headers(msg, HDR_EOH_F, 0);
00418 
00419         begin=get_header(msg); /* msg->orig previously .. uri problems */
00420 
00421         if (regexec(((fparam_t*)key)->v.regex, begin, 1, &pmatch, 0)!=0) return -1;
00422         off=begin-msg->buf;
00423 
00424         if (pmatch.rm_so!=-1){
00425                 if (eval_xlstr(msg, (void*) _str, &str) < 0) return -1;
00426 
00427                 if ((l=del_lump(msg, pmatch.rm_so+off,
00428                                                 pmatch.rm_eo-pmatch.rm_so, 0))==0)
00429                         return -1;
00430                 s=pkg_malloc(str.len);
00431                 if (s==0){
00432                         LOG(L_ERR, "ERROR: replace_f: mem. allocation failure\n");
00433                         return -1;
00434                 }
00435                 memcpy(s, str.s, str.len);
00436                 if (insert_new_lump_after(l, s, str.len, 0)==0){
00437                         LOG(L_ERR, "ERROR: could not insert new lump\n");
00438                         pkg_free(s);
00439                         return -1;
00440                 }
00441 
00442                 return 1;
00443         }
00444         return -1;
00445 }
00446 
00447 
00448 
00449 /* sed-perl style re: s/regular expression/replacement/flags */
00450 static int subst_f(struct sip_msg* msg, char*  subst, char* ignored)
00451 {
00452         struct lump* l;
00453         struct replace_lst* lst;
00454         struct replace_lst* rpl;
00455         char* begin;
00456         struct subst_expr* se;
00457         int off;
00458         int ret;
00459         int nmatches;
00460 
00461         se=(struct subst_expr*)subst;
00462         begin=get_header(msg);  /* start after first line to avoid replacing
00463                                                            the uri */
00464         off=begin-msg->buf;
00465         ret=-1;
00466         if ((lst=subst_run(se, begin, msg, &nmatches))==0)
00467                 goto error; /* not found */
00468         for (rpl=lst; rpl; rpl=rpl->next){
00469                 DBG(" %s: subst_f: replacing at offset %d [%.*s] with [%.*s]\n",
00470                                 exports.name, rpl->offset+off,
00471                                 rpl->size, rpl->offset+off+msg->buf,
00472                                 rpl->rpl.len, rpl->rpl.s);
00473                 if ((l=del_lump(msg, rpl->offset+off, rpl->size, 0))==0)
00474                         goto error;
00475                 /* hack to avoid re-copying rpl, possible because both
00476                  * replace_lst & lumps use pkg_malloc */
00477                 if (insert_new_lump_after(l, rpl->rpl.s, rpl->rpl.len, 0)==0){
00478                         LOG(L_ERR, "ERROR: %s: subst_f: could not insert new lump\n",
00479                                         exports.name);
00480                         goto error;
00481                 }
00482                 /* hack continued: set rpl.s to 0 so that replace_lst_free will
00483                  * not free it */
00484                 rpl->rpl.s=0;
00485                 rpl->rpl.len=0;
00486         }
00487         ret=1;
00488 error:
00489         DBG("subst_f: lst was %p\n", lst);
00490         if (lst) replace_lst_free(lst);
00491         if (nmatches<0)
00492                 LOG(L_ERR, "ERROR: %s: subst_run failed\n", exports.name);
00493         return ret;
00494 }
00495 
00496 
00497 
00498 /* sed-perl style re: s/regular expression/replacement/flags, like
00499  *  subst but works on the message uri */
00500 static int subst_uri_f(struct sip_msg* msg, char*  subst, char* ignored)
00501 {
00502         char* tmp;
00503         int len;
00504         char c;
00505         struct subst_expr* se;
00506         str* result;
00507 
00508         se=(struct subst_expr*)subst;
00509         if (msg->new_uri.s){
00510                 len=msg->new_uri.len;
00511                 tmp=msg->new_uri.s;
00512         }else{
00513                 tmp=msg->first_line.u.request.uri.s;
00514                 len     =msg->first_line.u.request.uri.len;
00515         };
00516         /* ugly hack: 0 s[len], and restore it afterward
00517          * (our re functions require 0 term strings), we can do this
00518          * because we always alloc len+1 (new_uri) and for first_line, the
00519          * message will always be > uri.len */
00520         c=tmp[len];
00521         tmp[len]=0;
00522         result=subst_str(tmp, msg, se, 0); /* pkg malloc'ed result */
00523         tmp[len]=c;
00524         if (result){
00525                 DBG("%s: subst_uri_f: match - old uri= [%.*s], new uri= [%.*s]\n",
00526                                 exports.name, len, tmp,
00527                                 (result->len)?result->len:0,(result->s)?result->s:"");
00528                 if (msg->new_uri.s) pkg_free(msg->new_uri.s);
00529                 msg->new_uri=*result;
00530                 msg->parsed_uri_ok=0; /* reset "use cached parsed uri" flag */
00531                 ruri_mark_new();
00532                 pkg_free(result); /* free str* pointer */
00533                 return 1; /* success */
00534         }
00535         return -1; /* false, no subst. made */
00536 }
00537 
00538 
00539 
00540 /* sed-perl style re: s/regular expression/replacement/flags, like
00541  *  subst but works on the user part of the uri */
00542 static int subst_user_f(struct sip_msg* msg, char*  subst, char* ignored)
00543 {
00544         int rval;
00545         str* result;
00546         struct subst_expr* se;
00547         struct action act;
00548         str user;
00549         char c;
00550         int nmatches;
00551         struct run_act_ctx ra_ctx;
00552 
00553         c=0;
00554         if (parse_sip_msg_uri(msg)<0){
00555                 return -1; /* error, bad uri */
00556         }
00557         if (msg->parsed_uri.user.s==0){
00558                 /* no user in uri */
00559                 user.s="";
00560                 user.len=0;
00561         }else{
00562                 user=msg->parsed_uri.user;
00563                 c=user.s[user.len];
00564                 user.s[user.len]=0;
00565         }
00566         se=(struct subst_expr*)subst;
00567         result=subst_str(user.s, msg, se, &nmatches);/* pkg malloc'ed result */
00568         if (c)  user.s[user.len]=c;
00569         if (result == NULL) {
00570                 if (nmatches<0)
00571                         LOG(L_ERR, "subst_user(): subst_str() failed\n");
00572                 return -1;
00573         }
00574         /* result->s[result->len] = '\0';  --subst_str returns 0-term strings */
00575         memset(&act, 0, sizeof(act)); /* be on the safe side */
00576         act.type = SET_USER_T;
00577         act.val[0].type = STRING_ST;
00578         act.val[0].u.string = result->s;
00579         init_run_actions_ctx(&ra_ctx);
00580         rval = do_action(&ra_ctx, &act, msg);
00581         if (result->s) pkg_free(result->s); /* SET_USER_T doesn't consume s */
00582         pkg_free(result);
00583         return rval;
00584 }
00585 
00586 
00587 static inline int remove_hf(struct sip_msg* msg, char* p1, int by_re)
00588 {
00589         struct hdr_field *hf;
00590         struct lump* l;
00591         int cnt;
00592         str hfn;
00593         regex_t regexp;
00594         regmatch_t matches;
00595         char bkup;
00596         int no_match;
00597 
00598         if (by_re) {
00599                 if (get_regex_fparam(&regexp, msg, (fparam_t*)p1) < 0) {
00600                         ERR("remove_hf: Error while obtaining parameter value\n");
00601                         return -1;
00602                 }
00603         } else {
00604                 if (get_str_fparam(&hfn, msg, (fparam_t*)p1) < 0) {
00605                         ERR("remove_hf: Error while obtaining parameter value\n");
00606                         return -1;
00607                 }
00608         }
00609 
00610         cnt=0;
00611         /* we need to be sure we have seen all HFs */
00612         parse_headers(msg, HDR_EOH_F, 0);
00613         for (hf=msg->headers; hf; hf=hf->next) {
00614                 if (by_re) {
00615                         /* 0-term. it for regexp run; should always be a safe op. */
00616                         bkup = hf->name.s[hf->name.len];
00617                         hf->name.s[hf->name.len] = 0;
00618                         no_match = regexec(&regexp, hf->name.s, /*# matches */1, &matches, 
00619                                         /*flags*/0);
00620                         hf->name.s[hf->name.len] = bkup;
00621                         if (no_match)
00622                                 continue;
00623                 } else {
00624                         if (hf->name.len!=hfn.len)
00625                                 continue;
00626                         if (strncasecmp(hf->name.s, hfn.s, hf->name.len)!=0)
00627                                 continue;
00628                 }
00629                 l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
00630                 if (l==0) {
00631                         ERR("no memory\n");
00632                         return -1;
00633                 }
00634                 cnt++;
00635         }
00636         return cnt==0 ? -1 : 1;
00637 }
00638 
00639 static int remove_hf_f(struct sip_msg* msg, char* p1, char* foo)
00640 {
00641         return remove_hf(msg, p1, /*use string comparison*/0);
00642 }
00643 
00644 static int remove_hf_re_f(struct sip_msg* msg, char* p1, char* foo)
00645 {
00646         return remove_hf(msg, p1, /*use regexp comparison*/1);
00647 }
00648 
00649 static int is_present_hf_f(struct sip_msg* msg, char* p1, char* foo)
00650 {
00651         struct hdr_field *hf;
00652         str hfn;
00653 
00654         if (get_str_fparam(&hfn, msg, (fparam_t*)p1) < 0) {
00655             ERR("is_present_hf: Error while obtaining parameter value\n");
00656             return -1;
00657         }
00658 
00659         /* we need to be sure we have seen all HFs */
00660         parse_headers(msg, HDR_EOH_F, 0);
00661         for (hf=msg->headers; hf; hf=hf->next) {
00662                 if (hf->name.len!=hfn.len)
00663                         continue;
00664                 if (strncasecmp(hf->name.s, hfn.s, hf->name.len)!=0)
00665                         continue;
00666                 return 1;
00667         }
00668         return -1;
00669 }
00670 
00671 static int fixup_substre(void** param, int param_no)
00672 {
00673         struct subst_expr* se;
00674         str subst;
00675 
00676         DBG("%s module -- fixing %s\n", exports.name, (char*)(*param));
00677         if (param_no!=1) return 0;
00678         subst.s=*param;
00679         subst.len=strlen(*param);
00680         se=subst_parser(&subst);
00681         if (se==0){
00682                 LOG(L_ERR, "ERROR: %s: bad subst. re %s\n", exports.name,
00683                                 (char*)*param);
00684                 return E_BAD_RE;
00685         }
00686         /* free string */
00687         pkg_free(*param);
00688         /* replace it with the compiled subst. re */
00689         *param=se;
00690         return 0;
00691 }
00692 
00693 
00694 static int append_time_f(struct sip_msg* msg, char* p1, char *p2)
00695 {
00696 
00697 
00698         size_t len;
00699         char time_str[MAX_TIME];
00700         time_t now;
00701         struct tm *bd_time;
00702 
00703         now=ser_time(0);
00704 
00705         bd_time=gmtime(&now);
00706         if (bd_time==NULL) {
00707                 LOG(L_ERR, "ERROR: append_time: gmtime failed\n");
00708                 return -1;
00709         }
00710 
00711         len=strftime(time_str, MAX_TIME, TIME_FORMAT, bd_time);
00712         if (len>MAX_TIME-2 || len==0) {
00713                 LOG(L_ERR, "ERROR: append_time: unexpected time length\n");
00714                 return -1;
00715         }
00716 
00717         time_str[len]='\r';
00718         time_str[len+1]='\n';
00719 
00720 
00721         if (add_lump_rpl(msg, time_str, len+2, LUMP_RPL_HDR)==0)
00722         {
00723                 LOG(L_ERR, "ERROR: append_time: unable to add lump\n");
00724                 return -1;
00725         }
00726 
00727         return 1;
00728 }
00729 
00730 static int append_to_reply_f(struct sip_msg* msg, char* _str, char* dummy)
00731 {
00732         str str;
00733         if (eval_xlstr(msg, (void*) _str, &str) < 0) return -1;
00734 
00735         if ( add_lump_rpl( msg, str.s, str.len, LUMP_RPL_HDR)==0 )
00736         {
00737                 LOG(L_ERR,"ERROR:append_to_reply : unable to add lump_rl\n");
00738                 return -1;
00739         }
00740 
00741         return 1;
00742 }
00743 
00744 
00745 /* add str1 to end of header or str1.r-uri.str2 */
00746 
00747 static int append_hf_helper(struct sip_msg* msg, struct xlstr *_str1, struct xlstr *_str2)
00748 {
00749         struct lump* anchor;
00750         char *s;
00751         str str1, str2;
00752         int len;
00753 
00754         if (eval_xlstr(msg, _str1, &str1) < 0) return -1;
00755         if (_str2) {
00756                 if (eval_xlstr(msg, _str2, &str2) < 0) return -1;
00757         }
00758 
00759         if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
00760                 LOG(L_ERR, "append_hf(): Error while parsing message\n");
00761                 return -1;
00762         }
00763 
00764         anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
00765         if (anchor == 0) {
00766                 LOG(L_ERR, "append_hf(): Can't get anchor\n");
00767                 return -1;
00768         }
00769 
00770         len=str1.len;
00771         if (_str2) len+= str2.len + REQ_LINE(msg).uri.len;
00772 
00773         s = (char*)pkg_malloc(len);
00774         if (!s) {
00775                 LOG(L_ERR, "append_hf(): No memory left\n");
00776                 return -1;
00777         }
00778 
00779         memcpy(s, str1.s, str1.len);
00780         if (_str2) {
00781                 memcpy(s+str1.len, REQ_LINE(msg).uri.s, REQ_LINE(msg).uri.len);
00782                 memcpy(s+str1.len+REQ_LINE(msg).uri.len, str2.s, str2.len );
00783         }
00784 
00785         if (insert_new_lump_before(anchor, s, len, 0) == 0) {
00786                 LOG(L_ERR, "append_hf(): Can't insert lump\n");
00787                 pkg_free(s);
00788                 return -1;
00789         }
00790         return 1;
00791 }
00792 
00793 static int append_hf(struct sip_msg *msg, char *str1, char *str2 )
00794 {
00795         return append_hf_helper(msg, (struct xlstr *) str1, (struct xlstr *) 0);
00796 }
00797 
00798 static int append_urihf(struct sip_msg *msg, char *str1, char *str2 )
00799 {
00800         return append_hf_helper(msg, (struct xlstr *) str1, (struct xlstr *) str2);
00801 }
00802 
00803 #define HNF_ALL 0x01
00804 #define HNF_IDX 0x02
00805 
00806 #define MAX_HF_VALUE_STACK 10
00807 
00808 enum {hnoInsert, hnoAppend, hnoAssign, hnoRemove, hnoInclude, hnoExclude, hnoIsIncluded, hnoGetValue, hnoGetValueUri, hnoGetValueName, hnoRemove2, hnoAssign2, hnoGetValue2};
00809 
00810 struct hname_data {
00811         int oper;
00812         int htype;
00813         str hname;
00814         int flags;
00815         int idx;
00816         str param;
00817 };
00818 
00819 #define is_space(_p) ((_p) == '\t' || (_p) == '\n' || (_p) == '\r' || (_p) == ' ')
00820 
00821 #define eat_spaces(_p) \
00822         while( is_space(*(_p)) ){\
00823         (_p)++;}
00824 
00825 #define is_alphanum(_p) (((_p) >= 'a' && (_p) <= 'z') || ((_p) >= 'A' && (_p) <= 'Z') || ((_p) >= '0' && (_p) <= '9') || (_p) == '_' || (_p) == '-')
00826 
00827 #define eat_while_alphanum(_p) \
00828         while ( is_alphanum(*(_p)) ) {\
00829                 (_p)++; }
00830 
00831 /* parse:  hname [ ([] | [*] | [number]) ] [ "." param ] */
00832 static int fixup_hname_param(char *hname, struct hname_data** h) {
00833         struct hdr_field hdr;
00834         char *savep, savec;
00835 
00836         *h = pkg_malloc(sizeof(**h));
00837         if (!*h) return E_OUT_OF_MEM;
00838         memset(*h, 0, sizeof(**h));
00839 
00840         memset(&hdr, 0, sizeof(hdr));
00841         eat_spaces(hname);
00842         (*h)->hname.s = hname;
00843         savep = hname;
00844         eat_while_alphanum(hname);
00845         (*h)->hname.len = hname - (*h)->hname.s;
00846         savec = *hname;
00847         *hname = ':';
00848         parse_hname2((*h)->hname.s, (*h)->hname.s+(*h)->hname.len+3, &hdr);
00849         *hname = savec;
00850 
00851         if (hdr.type == HDR_ERROR_T) goto err;
00852         (*h)->htype = hdr.type;
00853 
00854         eat_spaces(hname);
00855         savep = hname;
00856         if (*hname == '[') {
00857                 hname++;
00858                 eat_spaces(hname);
00859                 savep = hname;
00860                 (*h)->flags |= HNF_IDX;
00861                 if (*hname == '*') {
00862                         (*h)->flags |= HNF_ALL;
00863                         hname++;
00864                 }
00865                 else if (*hname != ']') {
00866                         char* c;
00867                         (*h)->idx = strtol(hname, &c, 10);
00868                         if (hname == c) goto err;
00869                         hname = c;
00870                 }
00871                 eat_spaces(hname);
00872                 savep = hname;
00873                 if (*hname != ']') goto err;
00874                 hname++;
00875         }
00876         eat_spaces(hname);
00877         savep = hname;
00878         if (*hname == '.') {
00879                 hname++;
00880                 eat_spaces(hname);
00881                 savep = hname;
00882                 (*h)->param.s = hname;
00883                 eat_while_alphanum(hname);
00884                 (*h)->param.len = hname-(*h)->param.s;
00885                 if ((*h)->param.len == 0) goto err;
00886         }
00887         else {
00888                 (*h)->param.s = hname;
00889         }
00890         savep = hname;
00891         if (*hname != '\0') goto err;
00892         (*h)->hname.s[(*h)->hname.len] = '\0';
00893         (*h)->param.s[(*h)->param.len] = '\0';
00894         return 0;
00895 err:
00896         pkg_free(*h);
00897         LOG(L_ERR, "ERROR: textops: cannot parse header near '%s'\n", savep);
00898         return E_CFG;
00899 }
00900 
00901 static int fixup_hname_str(void** param, int param_no) {
00902         if (param_no == 1) {
00903                 struct hname_data* h;
00904                 int res = fixup_hname_param(*param, &h);
00905                 if (res < 0) return res;
00906                 *param = h;
00907         }
00908         else if (param_no == 2) {
00909                 return fixup_xlstr(param, param_no);
00910         }
00911         return 0;
00912 }
00913 
00914 static int find_next_hf(struct sip_msg* msg, struct hname_data* hname, struct hdr_field** hf) {
00915         if (!*hf) {
00916                 if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
00917                         LOG(L_ERR, "ERROR: textops: find_next_hf: Error while parsing message\n");
00918                         return -1;
00919                 }
00920                 *hf = msg->headers;
00921         }
00922         else {
00923                 *hf = (*hf)->next;
00924         }
00925         for (; *hf; *hf = (*hf)->next) {
00926                 if (hname->htype == HDR_OTHER_T) {
00927                         if ((*hf)->name.len==hname->hname.len && strncasecmp((*hf)->name.s, hname->hname.s, (*hf)->name.len)==0)
00928                                 return 1;
00929                 }
00930                 else if (hname->htype == (*hf)->type) {
00931                         return 1;
00932                 }
00933         }
00934         return 0;
00935 }
00936 
00937 static int find_next_value(char** start, char* end, str* val, str* lump_val) {
00938         int quoted = 0;
00939         lump_val->s = *start;
00940         while (*start < end && is_space(**start) ) (*start)++;
00941         val->s = *start;
00942         while ( *start < end && (**start != ',' || quoted) ) {
00943                 if (**start == '\"' && (!quoted || (*start)[-1]!='\\') )
00944                         quoted = ~quoted;
00945                 (*start)++;
00946         }
00947         val->len = *start - val->s;
00948         while (val->len > 0 && is_space(val->s[val->len-1])) val->len--;
00949 /* we cannot automatically strip quotes!!! an example why: "name" <sip:ssss>;param="bar" 
00950         if (val->len >= 2 && val->s[0] == '\"' && val->s[val->len-1] == '\"') {
00951                 val->s++;
00952                 val->len -= 2;
00953         }
00954 */
00955         while (*start < end && **start != ',') (*start)++;
00956         if (*start < end) {
00957                 (*start)++;
00958         }
00959         lump_val->len = *start - lump_val->s;
00960         return (*start < end);
00961 }
00962 
00963 static void adjust_lump_val_for_delete(struct hdr_field* hf, str* lump_val) {
00964         if ( lump_val->s+lump_val->len == hf->body.s+hf->body.len ) {
00965                 if (lump_val->s > hf->body.s) {
00966                 /* in case if is it last value in header save position of last delimiter to remove it with rightmost value */
00967                         lump_val->s--;
00968                         lump_val->len++;
00969                 }
00970         }
00971 }
00972 
00973 static int find_hf_value_idx(struct sip_msg* msg, struct hname_data* hname, struct hdr_field** hf, str* val, str* lump_val) {
00974         int res;
00975         char *p;
00976         if ( hname->flags & HNF_ALL || hname->idx == 0) return -1;
00977         *hf = 0;
00978         if (hname->idx > 0) {
00979                 int idx;
00980                 idx = hname->idx;
00981                 do {
00982                         res = find_next_hf(msg, hname, hf);
00983                         if (res < 0) return -1;
00984                         if (*hf) {
00985                                 if (val) {
00986                                         lump_val->len = 0;
00987                                         p = (*hf)->body.s;
00988                                         do {
00989                                                 res = find_next_value(&p, (*hf)->body.s+(*hf)->body.len, val, lump_val);
00990                                                 idx--;
00991                                         } while (res && idx);
00992                                 }
00993                                 else {
00994                                         idx--;
00995                                 }
00996                         }
00997                 } while (*hf && idx);
00998         }
00999         else if (hname->idx < 0) {  /* search from the bottom */
01000                 struct hf_value_stack {
01001                         str val, lump_val;
01002                         struct hdr_field* hf;
01003                 } stack[MAX_HF_VALUE_STACK];
01004                 int stack_pos, stack_num;
01005 
01006                 if ( -hname->idx > MAX_HF_VALUE_STACK ) return -1;
01007                 stack_pos = stack_num = 0;
01008                 do {
01009                         res = find_next_hf(msg, hname, hf);
01010                         if (res < 0) return -1;
01011                         if (*hf) {
01012                                 stack[stack_pos].lump_val.len = 0;
01013                                 p = (*hf)->body.s;
01014                                 do {
01015                                         stack[stack_pos].hf = *hf;
01016                                         if (val)
01017                                                 res = find_next_value(&p, (*hf)->body.s+(*hf)->body.len, &stack[stack_pos].val, &stack[stack_pos].lump_val);
01018                                         else
01019                                                 res = 0;
01020                                         stack_pos++;
01021                                         if (stack_pos >= MAX_HF_VALUE_STACK)
01022                                                 stack_pos = 0;
01023                                         if (stack_num < MAX_HF_VALUE_STACK)
01024                                                 stack_num++;
01025 
01026                                 } while (res);
01027                         }
01028                 } while (*hf);
01029 
01030                 if (-hname->idx <= stack_num) {
01031                         stack_pos += hname->idx;
01032                         if (stack_pos < 0)
01033                                 stack_pos += MAX_HF_VALUE_STACK;
01034                         *hf = stack[stack_pos].hf;
01035                         if (val) {
01036                                 *val = stack[stack_pos].val;
01037                                 *lump_val = stack[stack_pos].lump_val;
01038                         }
01039                 }
01040                 else {
01041                         *hf = 0;
01042                 }
01043         }
01044         else
01045                 return -1;
01046         return *hf?1:0;
01047 }
01048 
01049 static int find_hf_value_param(struct hname_data* hname, str* param_area, str* value, str* lump_upd, str* lump_del) {
01050         int i, j, found;
01051 
01052         i = 0;
01053         while (1) {
01054                 lump_del->s = param_area->s + i;
01055                 for (; i < param_area->len && is_space(param_area->s[i]); i++);
01056                 if (i < param_area->len && param_area->s[i] == ';') {   /* found a param ? */
01057                         i++;
01058                         for (; i < param_area->len && is_space(param_area->s[i]); i++);
01059                         j = i;
01060                         for (; i < param_area->len && !is_space(param_area->s[i]) && param_area->s[i]!='=' && param_area->s[i]!=';'; i++);
01061 
01062                         found = hname->param.len == i-j && !strncasecmp(hname->param.s, param_area->s+j, i-j);
01063                         lump_upd->s = param_area->s+i;
01064                         value->s = param_area->s+i;
01065                         value->len = 0;
01066                         for (; i < param_area->len && is_space(param_area->s[i]); i++);
01067                         if (i < param_area->len && param_area->s[i]=='=') {
01068                                 i++;
01069                                 for (; i < param_area->len && is_space(param_area->s[i]); i++);
01070                                 value->s = param_area->s+i;
01071                                 if (i < param_area->len) {
01072                                         if (param_area->s[i]=='\"') {
01073                                                 i++;
01074                                                 value->s++;
01075                                                 for (; i<param_area->len; i++) {
01076                                                         if (param_area->s[i]=='\"') {
01077                                                                 i++;
01078                                                                 break;
01079                                                         }
01080                                                         value->len++;
01081                                                 }
01082                                         }
01083                                         else {
01084                                                 for (; i<param_area->len && !is_space(param_area->s[i]) && param_area->s[i]!=';'; i++, value->len++);
01085                                         }
01086                                 }
01087                         }
01088                         if (found) {
01089                                 lump_del->len = param_area->s+i - lump_del->s;
01090                                 lump_upd->len = param_area->s+i - lump_upd->s;
01091                                 return 1;
01092                         }
01093                 }
01094                 else { /* not found, return last correct position, should be end of param area */
01095                         lump_del->len = 0;
01096                         return 0;
01097                 }
01098         }
01099 }
01100 
01101 /* parse:  something param_name=param_value something [ "," something param_name="param_value" ....]
01102  * 'something' is required by Authenticate
01103  */
01104 static int find_hf_value2_param(struct hname_data* hname, str* param_area, str* value, str* lump_upd, str* lump_del, char* delim) {
01105         int i, j, k, found, comma_flag;
01106 
01107         i = 0;
01108         *delim = 0;
01109         lump_del->len = 0;
01110         while (i < param_area->len) {
01111 
01112                 lump_del->s = param_area->s + i;
01113                 while (i<param_area->len && is_space(param_area->s[i])) i++;
01114                 comma_flag = i < param_area->len && param_area->s[i] == ',';
01115                 if (comma_flag) i++;
01116                 while (i<param_area->len && is_space(param_area->s[i])) i++;
01117 
01118                 if (i < param_area->len && is_alphanum(param_area->s[i])) {     /* found a param name ? */
01119                         j = i;
01120                         if (!*delim) *delim = ' ';
01121                         while (i<param_area->len && is_alphanum(param_area->s[i])) i++;
01122 
01123                         k = i;
01124                         while (i<param_area->len && is_space(param_area->s[i])) i++;
01125                         lump_upd->s = param_area->s + i;
01126                         if (i < param_area->len && param_area->s[i] == '=') {   /* if equal then it's the param */
01127                                 *delim = ',';
01128                                 i++;
01129                                 found = hname->param.len == k-j && !strncasecmp(hname->param.s, param_area->s+j, k-j);
01130                                 while (i<param_area->len && is_space(param_area->s[i])) i++;
01131 
01132                                 value->s = param_area->s+i;
01133                                 value->len = 0;
01134                                 if (i < param_area->len) {
01135                                         if (param_area->s[i]=='\"') {
01136                                                 i++;
01137                                                 value->s++;
01138                                                 for (; i<param_area->len; i++) {
01139                                                         if (param_area->s[i]=='\"') {
01140                                                                 i++;
01141                                                                 break;
01142                                                         }
01143                                                         value->len++;
01144                                                 }
01145                                         }
01146                                         else {
01147                                                 for (; i<param_area->len && !is_space(param_area->s[i]) && param_area->s[i]!=','; i++, value->len++);
01148                                         }
01149                                 }
01150                                 if (found) {
01151                                         lump_upd->len = param_area->s+i - lump_upd->s;
01152                                         lump_del->len = param_area->s+i - lump_del->s;
01153 
01154                                         while (i<param_area->len && is_space(param_area->s[i])) i++;
01155 
01156                                         if (!comma_flag && i < param_area->len && param_area->s[i]==',') {
01157                                                 i++;
01158                                                 lump_del->len = param_area->s+i - lump_del->s;
01159                                         }
01160                                         return 1;
01161                                 }
01162                         }
01163                         while (i<param_area->len && is_space(param_area->s[i])) i++;
01164                 }
01165                 else {
01166                         while (i<param_area->len && !is_space(param_area->s[i]) && !param_area->s[i]!=',') i++;
01167                 }
01168         }
01169         lump_del->s = param_area->s + i;
01170         return 0;
01171 }
01172 
01173 static int insert_header_lump(struct sip_msg* msg, char* msg_position, int lump_before, str* hname, str *val) {
01174         struct lump* anchor;
01175         char *s;
01176         int len;
01177 
01178         anchor = anchor_lump(msg, msg_position - msg->buf, 0, 0);
01179         if (anchor == 0) {
01180                 LOG(L_ERR, "ERROR: textops: insert_header_lump(): Can't get anchor\n");
01181                 return -1;
01182         }
01183 
01184         len=hname->len+2+val->len+2;
01185 
01186         s = (char*)pkg_malloc(len);
01187         if (!s) {
01188                 LOG(L_ERR, "ERROR: textops: insert_header_lump(): not enough memory\n");
01189                 return -1;
01190         }
01191 
01192         memcpy(s, hname->s, hname->len);
01193         s[hname->len] = ':';
01194         s[hname->len+1] = ' ';
01195         memcpy(s+hname->len+2, val->s, val->len);
01196         s[hname->len+2+val->len] = '\r';
01197         s[hname->len+2+val->len+1] = '\n';
01198 
01199         if ( (lump_before?insert_new_lump_before(anchor, s, len, 0):insert_new_lump_after(anchor, s, len, 0)) == 0) {
01200                 LOG(L_ERR, "ERROR: textops: insert_header_lump(): Can't insert lump\n");
01201                 pkg_free(s);
01202                 return -1;
01203         }
01204         return 1;
01205 }
01206 
01207 static int insert_value_lump(struct sip_msg* msg, struct hdr_field* hf, char* msg_position, int lump_before, str *val) {
01208         struct lump* anchor;
01209         char *s;
01210         int len;
01211 
01212         anchor = anchor_lump(msg, msg_position - msg->buf, 0, 0);
01213         if (anchor == 0) {
01214                 LOG(L_ERR, "ERROR: textops: insert_value_lump(): Can't get anchor\n");
01215                 return -1;
01216         }
01217 
01218         len=val->len+1;
01219 
01220         s = (char*)pkg_malloc(len);
01221         if (!s) {
01222                 LOG(L_ERR, "ERROR: textops: insert_value_lump(): not enough memory\n");
01223                 return -1;
01224         }
01225 
01226         if (!hf) {
01227                 memcpy(s, val->s, val->len);
01228                 len--;
01229         }
01230         else if (msg_position == hf->body.s+hf->body.len) {
01231                 s[0] = ',';
01232                 memcpy(s+1, val->s, val->len);
01233         }
01234         else {
01235                 memcpy(s, val->s, val->len);
01236                 s[val->len] = ',';
01237         }
01238         if ( (lump_before?insert_new_lump_before(anchor, s, len, 0):insert_new_lump_after(anchor, s, len, 0)) == 0) {
01239                 LOG(L_ERR, "ERROR: textops: insert_value_lump(): Can't insert lump\n");
01240                 pkg_free(s);
01241                 return -1;
01242         }
01243         return 1;
01244 }
01245 
01246 static int delete_value_lump(struct sip_msg* msg, struct hdr_field* hf, str *val) {
01247         struct lump* l;
01248         /* TODO: check already existing lumps */
01249         if (hf && val->s == hf->body.s && val->len == hf->body.len)     /* check if remove whole haeder? */
01250                 l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
01251         else
01252                 l=del_lump(msg, val->s-msg->buf, val->len, 0);
01253         if (l==0) {
01254                 LOG(L_ERR, "ERROR: textops: delete_value_lump: not enough memory\n");
01255                 return -1;
01256         }
01257         return 1;
01258 }
01259 
01260 static int incexc_hf_value_f(struct sip_msg* msg, char* _hname, char* _val) {
01261         struct hname_data* hname = (void*) _hname;
01262         struct hdr_field* hf, *lump_hf;
01263         str val, hval1, hval2;
01264         char *p;
01265         int res = eval_xlstr(msg, (void*) _val, &val);
01266         if (res < 0) return res;
01267         if (!val.len) return -1;
01268         hf = 0;
01269         lump_hf = 0;
01270         while (1) {
01271                 if (find_next_hf(msg, hname, &hf) < 0) return -1;
01272                 if (!hf) break;
01273                 hval2.len = 0;
01274                 p = hf->body.s;
01275                 do {
01276                         res = find_next_value(&p, hf->body.s+hf->body.len, &hval1, &hval2);
01277                         if (hval1.len && val.len == hval1.len && strncasecmp(val.s, hval1.s, val.len) == 0) {
01278                                 switch (hname->oper) {
01279                                         case hnoIsIncluded:
01280                                         case hnoInclude:
01281                                                 return 1;
01282                                         case hnoExclude:
01283                                                 adjust_lump_val_for_delete(hf, &hval2);
01284                                                 delete_value_lump(msg, hf, &hval2);
01285                                         default:
01286                                                 break;
01287                                 }
01288                         }
01289                 } while (res);
01290                 switch (hname->oper) {
01291                         case hnoInclude:
01292                                 if (!lump_hf) {
01293                                         lump_hf = hf;
01294                                 }
01295                                 break;
01296                         default:
01297                                 break;
01298                 }
01299         }
01300         switch (hname->oper) {
01301                 case hnoIsIncluded:
01302                         return -1;
01303                 case hnoInclude:
01304                         if (lump_hf)
01305                                 return insert_value_lump(msg, lump_hf, lump_hf->body.s+lump_hf->body.len, 1, &val);
01306                         else
01307                                 return insert_header_lump(msg, msg->unparsed, 1, &hname->hname, &val);
01308                 default:
01309                         return 1;
01310         }
01311 }
01312 
01313 #define INCEXC_HF_VALUE_FIXUP(_func,_oper) \
01314 static int _func (void** param, int param_no) {\
01315         char* p = *param; \
01316         int res=fixup_hname_str(param, param_no); \
01317         if (res < 0) return res; \
01318         if (param_no == 1) {\
01319                 if ( ((struct hname_data*)*param)->flags & HNF_IDX || ((struct hname_data*)*param)->param.len ) { \
01320                         LOG(L_ERR, "ERROR: textops: neither index nor param may be specified in '%s'\n", p);\
01321                         return E_CFG;\
01322                 }\
01323                 ((struct hname_data*)*param)->oper = _oper;\
01324         }\
01325         return 0;\
01326 }
01327 
01328 INCEXC_HF_VALUE_FIXUP(include_hf_value_fixup, hnoInclude)
01329 INCEXC_HF_VALUE_FIXUP(exclude_hf_value_fixup, hnoExclude)
01330 INCEXC_HF_VALUE_FIXUP(hf_value_exists_fixup, hnoIsIncluded)
01331 
01332 static void get_uri_and_skip_until_params(str *param_area, str *name, str *uri) {
01333         int i, quoted, uri_pos, uri_done;
01334 
01335         name->len = 0;
01336         uri->len = 0;
01337         uri_done = 0;
01338         name->s = param_area->s;
01339         for (i=0; i<param_area->len && param_area->s[i]!=';'; ) {       /* [ *(token LSW)/quoted-string ] "<" addr-spec ">" | addr-spec */
01340                 /* skip name */
01341                 for (quoted=0, uri_pos=i; i<param_area->len; i++) {
01342                         if (!quoted) {
01343                                 if (param_area->s[i] == '\"') {
01344                                         quoted = 1;
01345                                         uri_pos = -1;
01346                                 }
01347                                 else if (param_area->s[i] == '<' || param_area->s[i] == ';' || is_space(param_area->s[i])) break;
01348                         }
01349                         else if (param_area->s[i] == '\"' && param_area->s[i-1] != '\\') quoted = 0;
01350                 }
01351                 if (!name->len)
01352                         name->len = param_area->s+i-name->s;
01353                 if (uri_pos >= 0 && !uri_done) {
01354                         uri->s = param_area->s+uri_pos;
01355                         uri->len = param_area->s+i-uri->s;
01356                 }
01357                 /* skip uri */
01358                 while (i<param_area->len && is_space(param_area->s[i])) i++;
01359                 if (i<param_area->len && param_area->s[i]=='<') {
01360                         uri->s = param_area->s+i;
01361                         uri->len = 0;
01362                         for (quoted=0; i<param_area->len; i++) {
01363                                 if (!quoted) {
01364                                         if (param_area->s[i] == '\"') quoted = 1;
01365                                         else if (param_area->s[i] == '>') {
01366                                                 uri->len = param_area->s+i-uri->s+1;
01367                                                 uri_done = 1;
01368                                                 break;
01369                                         }
01370                                 }
01371                                 else if (param_area->s[i] == '\"' && param_area->s[i-1] != '\\') quoted = 0;
01372                         }
01373                 }
01374         }
01375         param_area->s+= i;
01376         param_area->len-= i;
01377         if (uri->s == name->s)
01378                 name->len = 0;
01379 }
01380 
01381 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) {
01382         int len, i;
01383         char *s;
01384         struct lump* anchor;
01385 
01386         if (upd_del_fl) {
01387                 len = value?lump_upd->len:lump_del->len;
01388                 if (len > 0) {
01389                         if (!del_lump(msg, (value?lump_upd->s:lump_del->s)-msg->buf, len, 0)) {
01390                                 LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: not enough memory\n");
01391                                 return -1;
01392                         }
01393                 }
01394                 if (value && value->len) {
01395                         anchor = anchor_lump(msg, lump_upd->s - msg->buf, 0, 0);
01396                         if (anchor == 0) {
01397                                 LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: Can't get anchor\n");
01398                                 return -1;
01399                         }
01400 
01401                         len = 1+value->len;
01402                         s = pkg_malloc(len);
01403                         if (!s) {
01404                                 LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: not enough memory\n");
01405                                 return -1;
01406                         }
01407                         s[0]='=';
01408                         memcpy(s+1, value->s, value->len);
01409                         if ( (insert_new_lump_before(anchor, s, len, 0)) == 0) {
01410                                 LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: Can't insert lump\n");
01411                                 pkg_free(s);
01412                                 return -1;
01413                         }
01414                 }
01415         }
01416         else {
01417                 if (!value) return -1;
01418 
01419                 anchor = anchor_lump(msg, lump_del->s - msg->buf, 0, 0);
01420                 if (anchor == 0) {
01421                         LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: Can't get anchor\n");
01422                         return -1;
01423                 }
01424 
01425                 len = 1+hname->param.len+(value->len?value->len+1:0);
01426                 s = pkg_malloc(len);
01427                 if (!s) {
01428                         LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: not enough memory\n");
01429                         return -1;
01430                 }
01431                 if (delim) {
01432                         s[0] = delim;
01433                         i = 1;
01434                 }
01435                 else {
01436                         i = 0;
01437                         len--;
01438                 }
01439                 memcpy(s+i, hname->param.s, hname->param.len);
01440                 if (value->len) {
01441                         s[hname->param.len+i]='=';
01442                         memcpy(s+i+hname->param.len+1, value->s, value->len);
01443                 }
01444 
01445                 if ( (insert_new_lump_before(anchor, s, len, 0)) == 0) {
01446                         LOG(L_ERR, "ERROR: textops: assign_hf_do_lumping: Can't insert lump\n");
01447                         pkg_free(s);
01448                         return -1;
01449                 }
01450         }
01451         return 1;
01452 }
01453 
01454 
01455 static int assign_hf_process_params(struct sip_msg* msg, struct hdr_field* hf, struct hname_data* hname, str* value, str* value_area) {
01456         int r, r2, res=0;
01457         str param_area, lump_upd, lump_del, dummy_val, dummy_name, dummy_uri;
01458         param_area = *value_area;
01459         get_uri_and_skip_until_params(&param_area, &dummy_name, &dummy_uri);
01460         do {
01461                 r = find_hf_value_param(hname, &param_area, &dummy_val, &lump_upd, &lump_del);
01462                 r2 = assign_hf_do_lumping(msg, hf, hname, value, r, &lump_upd, &lump_del, ';');
01463                 if (res == 0)
01464                         res = r2;
01465                 if (r && !value) {   /* remove all parameters */
01466                         param_area.len -= lump_del.s+lump_del.len-param_area.s;
01467                         param_area.s = lump_del.s+lump_del.len;
01468                 }
01469         } while (!value && r);
01470         return res;
01471 }
01472 
01473 static int assign_hf_process2_params(struct sip_msg* msg, struct hdr_field* hf, struct hname_data* hname, str* value) {
01474         int r, r2, res = 0;
01475         str param_area, lump_upd, lump_del, dummy_val;
01476         char delim;
01477 
01478         param_area = hf->body;
01479 
01480         do {
01481                 r = find_hf_value2_param(hname, &param_area, &dummy_val, &lump_upd, &lump_del, &delim);
01482                 r2 = assign_hf_do_lumping(msg, hf, hname, value, r, &lump_upd, &lump_del, delim);
01483                 if (res == 0)
01484                         res = r2;
01485                 if (r && !value) {   /* remove all parameters */
01486                         param_area.len -= lump_del.s+lump_del.len-param_area.s;
01487                         param_area.s = lump_del.s+lump_del.len;
01488                 }
01489         } while (!value && r);
01490         return res;
01491 
01492 }
01493 
01494 static int insupddel_hf_value_f(struct sip_msg* msg, char* _hname, char* _val) {
01495         struct hname_data* hname = (void*) _hname;
01496         struct hdr_field* hf;
01497         str val, hval1, hval2;
01498         int res;
01499 
01500         if (_val) {
01501                 res = eval_xlstr(msg, (void*) _val, &val);
01502                 if (res < 0) return res;
01503         }
01504         switch (hname->oper) {
01505                 case hnoAppend:
01506                         if ((hname->flags & HNF_IDX) == 0) {
01507                                 if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
01508                                         LOG(L_ERR, "ERROR: textops: Error while parsing message\n");
01509                                         return -1;
01510                                 }
01511                                 return insert_header_lump(msg, msg->unparsed, 1, &hname->hname, &val);
01512                         }
01513                         else {
01514                                 res = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
01515                                 if (res < 0) return res;
01516                                 if (hf) {
01517                                         return insert_value_lump(msg, hf, hval2.s+hval2.len, res /* insert after, except it is last value in header */, &val);
01518                                 }
01519                                 else {
01520                                         return insert_header_lump(msg, msg->unparsed, 1, &hname->hname, &val);
01521                                 }
01522                         }
01523                 case hnoInsert:
01524                         /* if !HNF_IDX is possible parse only until first hname header but not trivial for HDR_OTHER_T header, not implemented */
01525                         res = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
01526                         if (res < 0) return res;
01527                         if (hf && (hname->flags & HNF_IDX) == 0) {
01528                                 return insert_header_lump(msg, hf->name.s, 1, &hname->hname, &val);
01529                         }
01530                         else if (!hf && hname->idx == 1) {
01531                                 return insert_header_lump(msg, msg->unparsed, 1, &hname->hname, &val);
01532                         }
01533                         else if (hf) {
01534                                 return insert_value_lump(msg, hf, hval2.s, 1, &val);
01535                         }
01536                         else
01537                                 return -1;
01538 
01539                 case hnoRemove:
01540                 case hnoAssign:
01541                         if (hname->flags & HNF_ALL) {
01542                                 struct hdr_field* hf = 0;
01543                                 int fl = -1;
01544                                 do {
01545                                         res = find_next_hf(msg, hname, &hf);
01546                                         if (res < 0) return res;
01547                                         if (hf) {
01548                                                 if (!hname->param.len) {
01549                                                         fl = 1;
01550                                                         delete_value_lump(msg, hf, &hf->body);
01551                                                 }
01552                                                 else {
01553                                                         char *p;
01554                                                         hval2.len = 0;
01555                                                         p = hf->body.s;
01556                                                         do {
01557                                                                 res = find_next_value(&p, hf->body.s+hf->body.len, &hval1, &hval2);
01558                                                                 if (assign_hf_process_params(msg, hf, hname, _val?&val:0, &hval1) > 0)
01559                                                                         fl = 1;
01560                                                         } while (res);
01561                                                 }
01562                                         }
01563                                 } while (hf);
01564                                 return fl;
01565                         }
01566                         else {
01567                                 res = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
01568                                 if (res < 0) return res;
01569                                 if (hf) {
01570                                         if (!hname->param.len) {
01571                                                 if (hname->oper == hnoRemove) {
01572                                                         adjust_lump_val_for_delete(hf, &hval2);
01573                                                         return delete_value_lump(msg, hf, &hval2);
01574                                                 }
01575                                                 else {
01576                                                         res = delete_value_lump(msg, 0 /* delete only value part */, &hval1);
01577                                                         if (res < 0) return res;
01578                                                         if (val.len) {
01579                                                                 return insert_value_lump(msg, 0 /* do not add delims */, hval1.s, 1, &val);
01580                                                         }
01581                                                         return 1;
01582                                                 }
01583                                         }
01584                                         else {
01585                                                 return assign_hf_process_params(msg, hf, hname, _val?&val:0, &hval1);
01586                                         }
01587                                 }
01588                         }
01589                         break;
01590                 case hnoRemove2:
01591                 case hnoAssign2:
01592                         if (hname->flags & HNF_ALL) {
01593                                 struct hdr_field* hf = 0;
01594                                 int fl = -1;
01595                                 do {
01596                                         res = find_next_hf(msg, hname, &hf);
01597                                         if (res < 0) return res;
01598                                         if (hf) {
01599                                                 if (!hname->param.len) {  /* the same as hnoRemove/hnoAssign */
01600                                                         fl = 1;
01601                                                         delete_value_lump(msg, hf, &hf->body);
01602                                                 }
01603                                                 else {
01604 
01605                                                         if (assign_hf_process2_params(msg, hf, hname, _val?&val:0) > 0)
01606                                                                 fl = 1;
01607                                                 }
01608                                         }
01609                                 } while (hf);
01610                                 return fl;
01611                         }
01612                         else {
01613                                 res = find_hf_value_idx(msg, hname, &hf, 0, 0);
01614                                 if (res < 0) return res;
01615                                 if (hf) {
01616                                         if (!hname->param.len) {
01617                                                 if (hname->oper == hnoRemove2) {
01618                                                         return delete_value_lump(msg, hf, &hf->body);
01619                                                 }
01620                                                 else {
01621                                                         res = delete_value_lump(msg, 0 /* delete only value part */, &hf->body);
01622                                                         if (res < 0) return res;
01623                                                         if (val.len) {
01624                                                                 return insert_value_lump(msg, 0 /* do not add delims */, hf->body.s, 1, &val);
01625                                                         }
01626                                                         return 1;
01627                                                 }
01628                                         }
01629                                         else {
01630                                                 return assign_hf_process2_params(msg, hf, hname, _val?&val:0);
01631                                         }
01632                                 }
01633                         }
01634                         break;
01635         }
01636         return -1;
01637 }
01638 
01639 static int append_hf_value_fixup(void** param, int param_no) {
01640         int res=fixup_hname_str(param, param_no);
01641         if (res < 0) return res;
01642         if (param_no == 1) {
01643                 if ( ((struct hname_data*)*param)->flags & HNF_ALL ) {
01644                         LOG(L_ERR, "ERROR: textops: asterisk not supported\n");
01645                         return E_CFG;
01646                 } else if ( (((struct hname_data*)*param)->flags & HNF_IDX) == 0 || !((struct hname_data*)*param)->idx ) {
01647                         ((struct hname_data*)*param)->idx = -1;
01648                 }
01649                 if (((struct hname_data*)*param)->idx < -MAX_HF_VALUE_STACK) {
01650                         LOG(L_ERR, "ERROR: textops: index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
01651                         return E_CFG;
01652                 }
01653                 if ( ((struct hname_data*)*param)->param.len ) {
01654                         LOG(L_ERR, "ERROR: textops: param not supported\n");
01655                         return E_CFG;
01656                 }
01657                 ((struct hname_data*)*param)->oper = hnoAppend;
01658         }
01659         return 0;
01660 }
01661 
01662 static int insert_hf_value_fixup(void** param, int param_no) {
01663         int res=fixup_hname_str(param, param_no);
01664         if (res < 0) return res;
01665         if (param_no == 1) {
01666                 if ( ((struct hname_data*)*param)->flags & HNF_ALL ) {
01667                         LOG(L_ERR, "ERROR: textops: asterisk not supported\n");
01668                         return E_CFG;
01669                 } else if ( (((struct hname_data*)*param)->flags & HNF_IDX) == 0 || !((struct hname_data*)*param)->idx ) {
01670                         ((struct hname_data*)*param)->idx = 1;
01671                 }
01672                 if (((struct hname_data*)*param)->idx < -MAX_HF_VALUE_STACK) {
01673                         LOG(L_ERR, "ERROR: textops: index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
01674                         return E_CFG;
01675                 }
01676                 if ( ((struct hname_data*)*param)->param.len ) {
01677                         LOG(L_ERR, "ERROR: textops: param not supported\n");
01678                         return E_CFG;
01679                 }
01680                 ((struct hname_data*)*param)->oper = hnoInsert;
01681         }
01682         return 0;
01683 }
01684 
01685 static int remove_hf_value_fixup(void** param, int param_no) {
01686         int res=fixup_hname_str(param, param_no);
01687         if (res < 0) return res;
01688         if (param_no == 1) {
01689                 if ( (((struct hname_data*)*param)->flags & HNF_IDX) == 0 || !((struct hname_data*)*param)->idx ) {
01690                         ((struct hname_data*)*param)->idx = 1;
01691                         ((struct hname_data*)*param)->flags |= HNF_IDX;
01692                 }
01693                 if (((struct hname_data*)*param)->idx < -MAX_HF_VALUE_STACK) {
01694                         LOG(L_ERR, "ERROR: textops: index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
01695                         return E_CFG;
01696                 }
01697                 ((struct hname_data*)*param)->oper = hnoRemove;
01698         }
01699         return 0;
01700 }
01701 
01702 static int assign_hf_value_fixup(void** param, int param_no) {
01703         int res=fixup_hname_str(param, param_no);
01704         if (res < 0) return res;
01705         if (param_no == 1) {
01706                 if ( (((struct hname_data*)*param)->flags & HNF_ALL) && !((struct hname_data*)*param)->param.len) {
01707                         LOG(L_ERR, "ERROR: textops: asterisk not supported without param\n");
01708                         return E_CFG;
01709                 } else if ( (((struct hname_data*)*param)->flags & HNF_IDX) == 0 || !((struct hname_data*)*param)->idx ) {
01710                         ((struct hname_data*)*param)->idx = 1;
01711                         ((struct hname_data*)*param)->flags |= HNF_IDX;
01712                 }
01713                 if (((struct hname_data*)*param)->idx < -MAX_HF_VALUE_STACK) {
01714                         LOG(L_ERR, "ERROR: textops: index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
01715                         return E_CFG;
01716                 }
01717                 ((struct hname_data*)*param)->oper = hnoAssign;
01718         }
01719         return 0;
01720 }
01721 
01722 static int remove_hf_value2_fixup(void** param, int param_no) {
01723         int res=remove_hf_value_fixup(param, param_no);
01724         if (res < 0) return res;
01725         if (param_no == 1) {
01726                 ((struct hname_data*)*param)->oper = hnoRemove2;
01727         }
01728         return 0;
01729 }
01730 
01731 static int assign_hf_value2_fixup(void** param, int param_no) {
01732         int res=assign_hf_value_fixup(param, param_no);
01733         if (res < 0) return res;
01734         if (param_no == 1) {
01735                 ((struct hname_data*)*param)->oper = hnoAssign2;
01736         }
01737         return 0;
01738 }
01739 
01740 static int sel_hf_value(str* res, select_t* s, struct sip_msg* msg) {  /* dummy */
01741         return 0;
01742 }
01743 
01744 #define _ALLOC_INC_SIZE 1024
01745 
01746 static int sel_hf_value_name(str* res, select_t* s, struct sip_msg* msg) {
01747         struct hname_data* hname;
01748         struct hdr_field* hf;
01749         str val, hval1, hval2, huri, dummy_name;
01750         int r;
01751         if (!msg) {
01752                 struct hdr_field hdr;
01753                 char buf[50];
01754                 int i, n;
01755 
01756                 if (s->params[1].type == SEL_PARAM_STR) {
01757                         hname = pkg_malloc(sizeof(*hname));
01758                         if (!hname) return E_OUT_OF_MEM;
01759                         memset(hname, 0, sizeof(*hname));
01760 
01761                         for (i=s->params[1].v.s.len-1; i>0; i--) {
01762                                 if (s->params[1].v.s.s[i]=='_')
01763                                         s->params[1].v.s.s[i]='-';
01764                         }
01765                         i = snprintf(buf, sizeof(buf)-1, "%.*s: X\n", s->params[1].v.s.len, s->params[1].v.s.s);
01766                         buf[i] = 0;
01767 
01768                         hname->hname = s->params[1].v.s;
01769                         parse_hname2(buf, buf+i, &hdr);
01770 
01771                         if (hdr.type == HDR_ERROR_T) return E_CFG;
01772                         hname->htype = hdr.type;
01773 
01774                         s->params[1].v.p = hname;
01775                         s->params[1].type = SEL_PARAM_PTR;
01776                 }
01777                 else {
01778                         hname = s->params[1].v.p;
01779                 }
01780                 n = s->param_offset[select_level+1] - s->param_offset[select_level];  /* number of values before NESTED */
01781                 if (n > 2 && s->params[2].type == SEL_PARAM_INT) {
01782                         hname->idx = s->params[2].v.i;
01783                         hname->flags |= HNF_IDX;
01784                         if (hname->idx < -MAX_HF_VALUE_STACK) {
01785                                 LOG(L_ERR, "ERROR: textops: index cannot be lower than %d\n", -MAX_HF_VALUE_STACK);
01786                                 return E_CFG;
01787                         }
01788                         if (hname->idx == 0)
01789                                 hname->idx = 1;
01790                         i = 3;
01791                 }
01792                 else {
01793                         i = 2;
01794                         hname->idx = 1;
01795                 }
01796                 if (n > i && s->params[i].type == SEL_PARAM_STR) {
01797                         hname->param = s->params[i].v.s;
01798                         for (i=hname->param.len-1; i>0; i--) {
01799                                 if (hname->param.s[i]=='_')
01800                                         hname->param.s[i]='-';
01801                         }
01802 
01803                 }
01804                 s->params[1].v.p = hname;
01805                 s->params[1].type = SEL_PARAM_PTR;
01806                 hname->oper = hnoGetValue;
01807 
01808                 return 0;
01809         }
01810 
01811         res->len = 0;
01812         res->s = 0;
01813         hname = s->params[1].v.p;
01814 
01815         switch (hname->oper) {
01816                 case hnoGetValueUri:
01817                         if (hname->flags & HNF_ALL || (hname->flags & HNF_IDX) == 0) {
01818                                 char *buf = NULL;
01819                                 int buf_len = 0;
01820                                 
01821                                 hf = 0;
01822                                 do {
01823                                         r = find_next_hf(msg, hname, &hf);
01824                                         if (r < 0) break;
01825                                         if (hf) {
01826                                                 char *p;
01827                                                 str huri;
01828                                                 hval2.len = 0;
01829                                                 p = hf->body.s;
01830                                                 do {
01831                                                         r = find_next_value(&p, hf->body.s+hf->body.len, &hval1, &hval2);
01832                                                         get_uri_and_skip_until_params(&hval1, &dummy_name, &huri);
01833                                                         if (huri.len) {
01834                                                         /* TODO: normalize uri, lowercase except quoted params, add/strip < > */
01835                                                                 if (*huri.s == '<') {
01836                                                                         huri.s++;
01837                                                                         huri.len -= 2;
01838                                                                 }
01839                                                         }                                                       
01840                                                         if (res->len == 0) {  
01841                                                                 *res = huri; /* first value, if is also last value then we don't need any buffer */
01842                                                         }
01843                                                         else {
01844                                                                 if (buf) {
01845                                                                         if (res->len+huri.len+1 > buf_len) {
01846                                                                                 buf_len = res->len+huri.len+1+_ALLOC_INC_SIZE;
01847                                                                                 res->s = pkg_realloc(buf, buf_len);
01848                                                                                 if (!res->s) {
01849                                                                                         pkg_free(buf);
01850                                                                                         LOG(L_ERR, "ERROR: textops: cannot realloc buffer\n");
01851                                                                                         res->len = 0;
01852                                                                                         return E_OUT_OF_MEM;
01853                                                                                 }
01854                                                                                 buf = res->s;
01855                                                                         }
01856                                                                 }
01857                                                                 else {
01858                                                                         /* 2nd value */
01859                                                                         buf_len = res->len+huri.len+1+_ALLOC_INC_SIZE;
01860                                                                         buf = pkg_malloc(buf_len);
01861                                                                         if (!buf) { 
01862                                                                                 LOG(L_ERR, "ERROR: testops: out of memory\n");
01863                                                                                 res->len = 0;
01864                                                                                 return E_OUT_OF_MEM;
01865                                                                         }
01866                                                                         /* copy 1st value */
01867                                                                         memcpy(buf, res->s, res->len);                                                          
01868                                                                         res->s = buf;
01869                                                                 }
01870                                                                 res->s[res->len] = ',';
01871                                                                 res->len++;
01872                                                                 if (huri.len) {
01873                                                                         memcpy(res->s+res->len, huri.s, huri.len);
01874                                                                         res->len += huri.len;
01875                                                                 }
01876                                                         }
01877                                                 
01878                                                 } while (r);
01879                                         }
01880                                 } while (hf);
01881                                 if (buf) {
01882                                         res->s = get_static_buffer(res->len);
01883                                         if (!res->s) {
01884                                                 pkg_free(buf);
01885                                                 res->len = 0;
01886                                                 LOG(L_ERR, "ERROR: testops: cannot allocate static buffer\n");
01887                                                 return E_OUT_OF_MEM;
01888                                         }
01889                                         memcpy(res->s, buf, res->len);
01890                                         pkg_free(buf);
01891                                 }
01892                         }
01893                         else {
01894                                 r = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
01895                                 if (r > 0) {
01896                                         get_uri_and_skip_until_params(&hval1, &dummy_name, res);
01897                                         if (res->len && *res->s == '<') {
01898                                                 res->s++;       /* strip < & > */
01899                                                 res->len-=2;
01900                                         }
01901                                 }
01902                         }
01903                         break;
01904                 case hnoGetValueName:
01905                         if ((hname->flags & HNF_ALL) == 0) {
01906                                 r = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
01907                                 if (r > 0) {
01908                                         get_uri_and_skip_until_params(&hval1, res, &dummy_name);
01909                                         if (res->len >= 2 && res->s[0] == '\"' && res->s[res->len-1]=='\"' ) {
01910                                                 res->s++;       /* strip quotes */
01911                                                 res->len-=2;
01912                                         }
01913                                 }
01914                         }
01915                         break;
01916                 case hnoGetValue:
01917                         if (hname->flags & HNF_ALL || (hname->flags & HNF_IDX) == 0) {
01918                                 char *buf = NULL;
01919                                 int buf_len = 0;
01920 
01921                                 hf = 0;
01922                                 do {
01923                                         r = find_next_hf(msg, hname, &hf);
01924                                         
01925                                         if (r < 0) break;
01926                                         if (hf) {
01927                                                 char *p;
01928                                                 hval2.len = 0;
01929                                                 p = hf->body.s;
01930                                                 do {
01931                                                         r = find_next_value(&p, hf->body.s+hf->body.len, &hval1, &hval2);
01932                                                         if (res->len == 0) {  
01933                                                                 *res = hval1; /* first value, if is also last value then we don't need any buffer */
01934                                                         }
01935                                                         else {
01936                                                                 if (buf) {
01937                                                                         if (res->len+hval1.len+1 > buf_len) {
01938                                                                                 buf_len = res->len+hval1.len+1+_ALLOC_INC_SIZE;
01939                                                                                 res->s = pkg_realloc(buf, buf_len);
01940                                                                                 if (!res->s) {
01941                                                                                         pkg_free(buf);
01942                                                                                         LOG(L_ERR, "ERROR: textops: cannot realloc buffer\n");
01943                                                                                         res->len = 0;
01944                                                                                         return E_OUT_OF_MEM;
01945                                                                                 }
01946                                                                                 buf = res->s;
01947                                                                         }
01948                                                                 }
01949                                                                 else {
01950                                                                         /* 2nd value */
01951                                                                         buf_len = res->len+hval1.len+1+_ALLOC_INC_SIZE;
01952                                                                         buf = pkg_malloc(buf_len);
01953                                                                         if (!buf) { 
01954                                                                                 LOG(L_ERR, "ERROR: testops: out of memory\n");
01955                                                                                 res->len = 0;
01956                                                                                 return E_OUT_OF_MEM;
01957                                                                         }
01958                                                                         /* copy 1st value */
01959                                                                         memcpy(buf, res->s, res->len);                                                          
01960                                                                         res->s = buf;
01961                                                                 }
01962                                                                 res->s[res->len] = ',';
01963                                                                 res->len++;
01964                                                                 if (hval1.len) {
01965                                                                         memcpy(res->s+res->len, hval1.s, hval1.len);
01966                                                                         res->len += hval1.len;
01967                                                                 }
01968                                                         }
01969                                                 } while (r);
01970                                         }
01971                                 } while (hf);
01972                                 if (buf) {
01973                                         res->s = get_static_buffer(res->len);
01974                                         if (!res->s) {
01975                                                 pkg_free(buf);
01976                                                 res->len = 0;
01977                                                 LOG(L_ERR, "ERROR: testops: cannot allocate static buffer\n");
01978                                                 return E_OUT_OF_MEM;
01979                                         }
01980                                         memcpy(res->s, buf, res->len);
01981                                         pkg_free(buf);
01982                                 }
01983                         }
01984                         else {
01985                                 r = find_hf_value_idx(msg, hname, &hf, &hval1, &hval2);
01986                                 if (r > 0) {
01987                                         if (hname->param.len) {
01988                                                 str d1, d2;
01989                                                 get_uri_and_skip_until_params(&hval1, &dummy_name, &huri);
01990                                                 if (find_hf_value_param(hname, &hval1, &val, &d1, &d2)) {
01991                                                         *res = val;
01992                                                 }
01993                                         }
01994                                         else {
01995                                                 *res = hval1;
01996                                         }
01997                                 }
01998                         }
01999                         break;
02000                 case hnoGetValue2:
02001                         r = find_hf_value_idx(msg, hname, &hf, 0, 0);
02002                         if (r > 0) {
02003                                 if (hname->param.len) {
02004                                         str d1, d2;
02005                                         char c;
02006                                         if (find_hf_value2_param(hname, &hf->body, &val, &d1, &d2, &c)) {
02007                                                 *res = val;
02008                                         }
02009                                 }
02010                                 else {
02011                                         *res = hf->body;
02012                                 }
02013                         }
02014                         break;
02015                 default:
02016                         break;
02017         }
02018         return 0;
02019 }
02020 
02021 static int sel_hf_value_name_param_name(str* res, select_t* s, struct sip_msg* msg) {
02022         return sel_hf_value_name(res, s, msg);
02023 }
02024 
02025 static int sel_hf_value_name_param_name2(str* res, select_t* s, struct sip_msg* msg) {
02026         if (!msg) { /* eliminate "param" level */
02027                 int n;
02028                 n = s->param_offset[select_level+1] - s->param_offset[select_level];
02029                 s->params[n-2] = s->params[n-1];
02030         }
02031         return sel_hf_value_name(res, s, msg);
02032 }
02033 
02034 static int sel_hf_value_name_uri(str* res, select_t* s, struct sip_msg* msg) {
02035         int r;
02036         r = sel_hf_value_name(res, s, msg);
02037         if (!msg && r==0) {
02038                 ((struct hname_data*) s->params[1].v.p)->oper = hnoGetValueUri;
02039         }
02040         return r;
02041 }
02042 
02043 static int sel_hf_value_name_name(str* res, select_t* s, struct sip_msg* msg) {
02044         int r;
02045         r = sel_hf_value_name(res, s, msg);
02046         if (!msg && r==0) {
02047                 ((struct hname_data*) s->params[1].v.p)->oper = hnoGetValueName;
02048         }
02049         return r;
02050 }
02051 
02052 static int sel_hf_value_exists(str* res, select_t* s, struct sip_msg* msg) {  /* dummy */
02053         return 0;
02054 }
02055 
02056 static int sel_hf_value_exists_param(str* res, select_t* s, struct sip_msg* msg) {
02057         static char ret_val[] = "01";
02058         struct xlstr xlstr;
02059         int r;
02060 
02061         if (!msg) {
02062                 r = sel_hf_value_name(res, s, msg);
02063                 if (r == 0)
02064                         ((struct hname_data*) s->params[1].v.p)->oper = hnoIsIncluded;
02065                 return r;
02066         }
02067         xlstr.s = s->params[2].v.s;
02068         xlstr.xlfmt = 0;
02069         r = incexc_hf_value_f(msg, s->params[1].v.p, (void*) &xlstr);
02070         res->s = &ret_val[r > 0];
02071         res->len = 1;
02072 
02073         return 0;
02074 }
02075 
02076 static int sel_hf_value2(str* res, select_t* s, struct sip_msg* msg) {  /* dummy */
02077         return 0;
02078 }
02079 
02080 static int sel_hf_value2_name(str* res, select_t* s, struct sip_msg* msg) {
02081         int r;
02082         r = sel_hf_value_name(res, s, msg);
02083         if (!msg && r==0) {
02084                 ((struct hname_data*) s->params[1].v.p)->oper = hnoGetValue2;
02085         }
02086         return r;
02087 }
02088 
02089 static int sel_hf_value2_name_param_name(str* res, select_t* s, struct sip_msg* msg) {
02090         return sel_hf_value2_name(res, s, msg);
02091 }
02092 
02093 SELECT_F(select_any_nameaddr)
02094 SELECT_F(select_any_uri)
02095 SELECT_F(select_anyheader_params)
02096 
02097 select_row_t sel_declaration[] = {
02098         { NULL, SEL_PARAM_STR, STR_STATIC_INIT("hf_value"), sel_hf_value, SEL_PARAM_EXPECTED},
02099 
02100         { sel_hf_value, SEL_PARAM_STR, STR_NULL, sel_hf_value_name, CONSUME_NEXT_INT | OPTIONAL | FIXUP_CALL},
02101         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("param"), sel_hf_value_name_param_name2, CONSUME_NEXT_STR | FIXUP_CALL},
02102         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("p"), sel_hf_value_name_param_name2, CONSUME_NEXT_STR | FIXUP_CALL},
02103         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("uri"), sel_hf_value_name_uri, FIXUP_CALL},
02104         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("name"), sel_hf_value_name_name, FIXUP_CALL},
02105         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED | CONSUME_NEXT_STR}, /* it duplicates param,p,name,... */
02106         { sel_hf_value_name, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_anyheader_params, NESTED},
02107 
02108         { sel_hf_value_name_uri, SEL_PARAM_INT, STR_NULL, select_any_uri, NESTED},
02109         { sel_hf_value_name, SEL_PARAM_STR, STR_NULL, sel_hf_value_name_param_name, FIXUP_CALL},
02110 
02111         { NULL, SEL_PARAM_STR, STR_STATIC_INIT("hf_value_exists"), sel_hf_value_exists, CONSUME_NEXT_STR | SEL_PARAM_EXPECTED},
02112         { sel_hf_value_exists, SEL_PARAM_STR, STR_NULL, sel_hf_value_exists_param, FIXUP_CALL},
02113 
02114         { NULL, SEL_PARAM_STR, STR_STATIC_INIT("hf_value2"), sel_hf_value2, SEL_PARAM_EXPECTED},
02115         { sel_hf_value2, SEL_PARAM_STR, STR_NULL, sel_hf_value2_name, CONSUME_NEXT_INT | OPTIONAL | FIXUP_CALL},
02116         { sel_hf_value2_name, SEL_PARAM_STR, STR_STATIC_INIT("params"), select_anyheader_params, NESTED},
02117         { sel_hf_value2_name, SEL_PARAM_STR, STR_NULL, sel_hf_value2_name_param_name, FIXUP_CALL},
02118         { sel_hf_value2_name_param_name, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED},
02119         { sel_hf_value2_name_param_name, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_any_uri, NESTED},
02120 
02121         { NULL, SEL_PARAM_INT, STR_NULL, NULL, 0}
02122 };